summaryrefslogtreecommitdiff
path: root/usr/src/tools/ctf/dwarf/common/dwarf_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/tools/ctf/dwarf/common/dwarf_util.c')
-rw-r--r--usr/src/tools/ctf/dwarf/common/dwarf_util.c470
1 files changed, 317 insertions, 153 deletions
diff --git a/usr/src/tools/ctf/dwarf/common/dwarf_util.c b/usr/src/tools/ctf/dwarf/common/dwarf_util.c
index df217e3628..01e0dd755d 100644
--- a/usr/src/tools/ctf/dwarf/common/dwarf_util.c
+++ b/usr/src/tools/ctf/dwarf/common/dwarf_util.c
@@ -1,6 +1,6 @@
/*
-
- Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of version 2.1 of the GNU Lesser General Public License
@@ -19,10 +19,10 @@
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
USA.
- Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
Mountain View, CA 94043, or:
http://www.sgi.com
@@ -32,6 +32,13 @@
http://oss.sgi.com/projects/GenInfo/NoticeExplan
*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
@@ -51,8 +58,9 @@
*/
Dwarf_Unsigned
_dwarf_get_size_of_val(Dwarf_Debug dbg,
- Dwarf_Unsigned form,
- Dwarf_Small * val_ptr, int v_length_size)
+ Dwarf_Unsigned form,
+ Dwarf_Half address_size,
+ Dwarf_Small * val_ptr, int v_length_size)
{
Dwarf_Unsigned length = 0;
Dwarf_Word leb128_length = 0;
@@ -61,98 +69,153 @@ _dwarf_get_size_of_val(Dwarf_Debug dbg,
switch (form) {
- default: /* Handles form = 0. */
- return (form);
+ default: /* Handles form = 0. */
+ return (form);
case DW_FORM_addr:
- return (dbg->de_pointer_size);
-
+ if(address_size) {
+ return address_size;
+ }
+ /* This should never happen, address_size should be set. */
+ return (dbg->de_pointer_size);
+
+ /* DWARF2 was wrong on the size of the attribute for
+ DW_FORM_ref_addr. We assume compilers are using the
+ corrected DWARF3 text (for 32bit pointer target objects pointer and
+ offsets are the same size anyway). */
case DW_FORM_ref_addr:
- return (v_length_size);
+ return (v_length_size);
case DW_FORM_block1:
- return (*(Dwarf_Small *) val_ptr + 1);
+ return (*(Dwarf_Small *) val_ptr + 1);
case DW_FORM_block2:
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- val_ptr, sizeof(Dwarf_Half));
- return (ret_value + sizeof(Dwarf_Half));
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_Half));
+ return (ret_value + sizeof(Dwarf_Half));
case DW_FORM_block4:
- READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
- val_ptr, sizeof(Dwarf_ufixed));
- return (ret_value + sizeof(Dwarf_ufixed));
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_ufixed));
+ return (ret_value + sizeof(Dwarf_ufixed));
case DW_FORM_data1:
- return (1);
+ return (1);
case DW_FORM_data2:
- return (2);
+ return (2);
case DW_FORM_data4:
- return (4);
+ return (4);
case DW_FORM_data8:
- return (8);
+ return (8);
case DW_FORM_string:
- return (strlen((char *) val_ptr) + 1);
+ return (strlen((char *) val_ptr) + 1);
case DW_FORM_block:
- length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
- return (length + leb128_length);
+ case DW_FORM_exprloc:
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (length + leb128_length);
+ case DW_FORM_flag_present:
+ return (0);
case DW_FORM_flag:
- return (1);
+ return (1);
+
+ case DW_FORM_sec_offset:
+ /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */
+ return (v_length_size);
case DW_FORM_ref_udata:
- _dwarf_decode_u_leb128(val_ptr, &leb128_length);
- return (leb128_length);
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
case DW_FORM_indirect:
- {
- Dwarf_Word indir_len = 0;
-
- form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
- if (form_indirect == DW_FORM_indirect) {
- return (0); /* We are in big trouble: The true form
- of DW_FORM_indirect is
- DW_FORM_indirect? Nonsense. Should
- never happen. */
- }
- return (indir_len + _dwarf_get_size_of_val(dbg,
- form_indirect,
- val_ptr +
- indir_len,
- v_length_size));
- }
+ {
+ Dwarf_Word indir_len = 0;
+
+ form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
+ if (form_indirect == DW_FORM_indirect) {
+ return (0); /* We are in big trouble: The true form
+ of DW_FORM_indirect is
+ DW_FORM_indirect? Nonsense. Should
+ never happen. */
+ }
+ return (indir_len + _dwarf_get_size_of_val(dbg,
+ form_indirect,
+ address_size,
+ val_ptr + indir_len,
+ v_length_size));
+ }
case DW_FORM_ref1:
- return (1);
+ return (1);
case DW_FORM_ref2:
- return (2);
+ return (2);
case DW_FORM_ref4:
- return (4);
+ return (4);
case DW_FORM_ref8:
- return (8);
+ return (8);
case DW_FORM_sdata:
- _dwarf_decode_s_leb128(val_ptr, &leb128_length);
- return (leb128_length);
+ _dwarf_decode_s_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
case DW_FORM_strp:
- return (v_length_size);
+ return (v_length_size);
case DW_FORM_udata:
- _dwarf_decode_u_leb128(val_ptr, &leb128_length);
- return (leb128_length);
+ _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
}
}
+/* We allow an arbitrary number of HT_MULTIPLE entries
+ before resizing. It seems up to 20 or 30
+ would work nearly as well.
+ We could have a different resize multiple than 'resize now'
+ test multiple, but for now we don't do that.
+*/
+#define HT_MULTIPLE 8
+
+/* Copy the old entries, updating each to be in
+ a new list. Don't delete anything. Leave the
+ htin with stale data. */
+static void
+copy_abbrev_table_to_new_table(Dwarf_Hash_Table htin,
+ Dwarf_Hash_Table htout)
+{
+ Dwarf_Hash_Table_Entry entry_in = htin->tb_entries;
+ unsigned entry_in_count = htin->tb_table_entry_count;
+ Dwarf_Hash_Table_Entry entry_out = htout->tb_entries;
+ unsigned entry_out_count = htout->tb_table_entry_count;
+ unsigned k = 0;
+ for ( ; k < entry_in_count; ++k,++entry_in) {
+ Dwarf_Abbrev_List listent = entry_in->at_head;
+ Dwarf_Abbrev_List nextlistent = 0;
+
+ for ( ; listent ; listent = nextlistent) {
+ unsigned newtmp = listent->ab_code;
+ unsigned newhash = newtmp%entry_out_count;
+ Dwarf_Hash_Table_Entry e;
+ nextlistent = listent->ab_next;
+ e = entry_out+newhash;
+ /* Move_entry_to_new_hash. This reverses the
+ order of the entries, effectively, but
+ that does not seem significant. */
+ listent->ab_next = e->at_head;
+ e->at_head = listent;
+
+ htout->tb_total_abbrev_count++;
+ }
+ }
+}
/*
This function returns a pointer to a Dwarf_Abbrev_List_s
@@ -175,77 +238,131 @@ _dwarf_get_size_of_val(Dwarf_Debug dbg,
hash table contains both a head pointer and a tail pointer
for each entry.
+ While the lists can move and entries can be moved between
+ lists on reallocation, any given Dwarf_Abbrev_list entry
+ never moves once allocated, so the pointer is safe to return.
+
Returns NULL on error.
*/
Dwarf_Abbrev_List
-_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Word code)
+_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code)
{
Dwarf_Debug dbg = cu_context->cc_dbg;
- Dwarf_Hash_Table hash_table = cu_context->cc_abbrev_hash_table;
- Dwarf_Word hash_num;
- Dwarf_Abbrev_List hash_abbrev_list;
- Dwarf_Abbrev_List abbrev_list;
- Dwarf_Byte_Ptr abbrev_ptr;
- Dwarf_Half abbrev_code, abbrev_tag;
- Dwarf_Half attr_name, attr_form;
-
- hash_num = code % ABBREV_HASH_TABLE_SIZE;
- for (hash_abbrev_list = hash_table[hash_num].at_head;
- hash_abbrev_list != NULL && hash_abbrev_list->ab_code != code;
- hash_abbrev_list = hash_abbrev_list->ab_next);
- if (hash_abbrev_list != NULL)
- return (hash_abbrev_list);
+ Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table;
+ Dwarf_Hash_Table_Entry entry_base = 0;
+ Dwarf_Hash_Table_Entry entry_cur = 0;
+ Dwarf_Word hash_num = 0;
+ Dwarf_Unsigned abbrev_code = 0;
+ Dwarf_Unsigned abbrev_tag = 0;
+ Dwarf_Unsigned attr_name = 0;
+ Dwarf_Unsigned attr_form = 0;
+
+ Dwarf_Abbrev_List hash_abbrev_entry = 0;
+
+ Dwarf_Abbrev_List inner_list_entry = 0;
+ Dwarf_Hash_Table_Entry inner_hash_entry = 0;
+
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ unsigned hashable_val;
+
+ if ( !hash_table_base->tb_entries ) {
+ hash_table_base->tb_table_entry_count = HT_MULTIPLE;
+ hash_table_base->tb_total_abbrev_count= 0;
+ hash_table_base->tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ hash_table_base->tb_table_entry_count);
+ if(! hash_table_base->tb_entries) {
+ return NULL;
+ }
+
+ } else if (hash_table_base->tb_total_abbrev_count >
+ ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) {
+ struct Dwarf_Hash_Table_s newht;
+ /* Effectively multiplies by >= HT_MULTIPLE */
+ newht.tb_table_entry_count = hash_table_base->tb_total_abbrev_count;
+ newht.tb_total_abbrev_count = 0;
+ newht.tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ newht.tb_table_entry_count);
+
+ if(! newht.tb_entries) {
+ return NULL;
+ }
+ /* Copy the existing entries to the new table,
+ rehashing each.
+ */
+ copy_abbrev_table_to_new_table(hash_table_base, &newht);
+ /* Dealloc only the entries hash table array, not the lists
+ of things pointed to by a hash table entry array. */
+ dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+ hash_table_base->tb_entries = 0;
+ /* Now overwrite the existing table descriptor with
+ the new, newly valid, contents. */
+ *hash_table_base = newht;
+ } /* Else is ok as is, add entry */
+
+
+ hashable_val = code;
+ hash_num = hashable_val %
+ hash_table_base->tb_table_entry_count;
+ entry_base = hash_table_base->tb_entries;
+ entry_cur = entry_base + hash_num;
+
+ /* Determine if the 'code' is the list of synonyms already. */
+ for (hash_abbrev_entry = entry_cur->at_head;
+ hash_abbrev_entry != NULL && hash_abbrev_entry->ab_code != code;
+ hash_abbrev_entry = hash_abbrev_entry->ab_next);
+ if (hash_abbrev_entry != NULL) {
+ /* This returns a pointer to an abbrev list entry, not
+ the list itself. */
+ return (hash_abbrev_entry);
+ }
abbrev_ptr = cu_context->cc_last_abbrev_ptr != NULL ?
- cu_context->cc_last_abbrev_ptr :
- dbg->de_debug_abbrev + cu_context->cc_abbrev_offset;
+ cu_context->cc_last_abbrev_ptr :
+ dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset;
/* End of abbrev's for this cu, since abbrev code is 0. */
if (*abbrev_ptr == 0) {
- return (NULL);
+ return (NULL);
}
do {
- Dwarf_Unsigned utmp;
-
- DECODE_LEB128_UWORD(abbrev_ptr, utmp)
- abbrev_code = (Dwarf_Half) utmp;
- DECODE_LEB128_UWORD(abbrev_ptr, utmp)
- abbrev_tag = (Dwarf_Half) utmp;
-
- abbrev_list = (Dwarf_Abbrev_List)
- _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
- if (abbrev_list == NULL)
- return (NULL);
-
- hash_num = abbrev_code % ABBREV_HASH_TABLE_SIZE;
- if (hash_table[hash_num].at_head == NULL) {
- hash_table[hash_num].at_head =
- hash_table[hash_num].at_tail = abbrev_list;
- } else {
- hash_table[hash_num].at_tail->ab_next = abbrev_list;
- hash_table[hash_num].at_tail = abbrev_list;
- }
-
- abbrev_list->ab_code = abbrev_code;
- abbrev_list->ab_tag = abbrev_tag;
-
- abbrev_list->ab_has_child = *(abbrev_ptr++);
- abbrev_list->ab_abbrev_ptr = abbrev_ptr;
-
- do {
- Dwarf_Unsigned utmp3;
-
- DECODE_LEB128_UWORD(abbrev_ptr, utmp3)
- attr_name = (Dwarf_Half) utmp3;
- DECODE_LEB128_UWORD(abbrev_ptr, utmp3)
- attr_form = (Dwarf_Half) utmp3;
- } while (attr_name != 0 && attr_form != 0);
+ unsigned new_hashable_val;
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code);
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag);
+
+ inner_list_entry = (Dwarf_Abbrev_List)
+ _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
+ if (inner_list_entry == NULL)
+ return (NULL);
+
+ new_hashable_val = abbrev_code;
+ hash_num = new_hashable_val %
+ hash_table_base->tb_table_entry_count;
+ inner_hash_entry = entry_base + hash_num;
+ /* Move_entry_to_new_hash */
+ inner_list_entry->ab_next = inner_hash_entry->at_head;
+ inner_hash_entry->at_head = inner_list_entry;
+
+ hash_table_base->tb_total_abbrev_count++;
+
+ inner_list_entry->ab_code = abbrev_code;
+ inner_list_entry->ab_tag = abbrev_tag;
+ inner_list_entry->ab_has_child = *(abbrev_ptr++);
+ inner_list_entry->ab_abbrev_ptr = abbrev_ptr;
+
+ /* Cycle thru the abbrev content, ignoring the content except
+ to find the end of the content. */
+ do {
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_name);
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_form);
+ } while (attr_name != 0 && attr_form != 0);
} while (*abbrev_ptr != 0 && abbrev_code != code);
cu_context->cc_last_abbrev_ptr = abbrev_ptr;
- return (abbrev_code == code ? abbrev_list : NULL);
+ return (abbrev_code == code ? inner_list_entry : NULL);
}
@@ -261,13 +378,13 @@ _dwarf_string_valid(void *startptr, void *endptr)
char *end = endptr;
while (start < end) {
- if (*start == 0) {
- return 1; /* OK! */
- }
- ++start;
- ++end;
+ if (*start == 0) {
+ return 1; /* OK! */
+ }
+ ++start;
+ ++end;
}
- return 0; /* FAIL! bad string! */
+ return 0; /* FAIL! bad string! */
}
/*
@@ -283,28 +400,28 @@ _dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len)
unsigned char *src = (unsigned char *) s2;
if (len == 4) {
- targ[3] = src[0];
- targ[2] = src[1];
- targ[1] = src[2];
- targ[0] = src[3];
+ targ[3] = src[0];
+ targ[2] = src[1];
+ targ[1] = src[2];
+ targ[0] = src[3];
} else if (len == 8) {
- targ[7] = src[0];
- targ[6] = src[1];
- targ[5] = src[2];
- targ[4] = src[3];
- targ[3] = src[4];
- targ[2] = src[5];
- targ[1] = src[6];
- targ[0] = src[7];
+ targ[7] = src[0];
+ targ[6] = src[1];
+ targ[5] = src[2];
+ targ[4] = src[3];
+ targ[3] = src[4];
+ targ[2] = src[5];
+ targ[1] = src[6];
+ targ[0] = src[7];
} else if (len == 2) {
- targ[1] = src[0];
- targ[0] = src[1];
+ targ[1] = src[0];
+ targ[0] = src[1];
}
/* should NOT get below here: is not the intended use */
else if (len == 1) {
- targ[0] = src[0];
+ targ[0] = src[0];
} else {
- memcpy(s1, s2, len);
+ memcpy(s1, s2, len);
}
return orig_s1;
@@ -326,31 +443,31 @@ _dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset)
int local_length_size = 0;
int local_extension_size = 0;
Dwarf_Unsigned length = 0;
- Dwarf_Small *cuptr = dbg->de_debug_info + offset;
+ Dwarf_Small *cuptr = dbg->de_debug_info.dss_data + offset;
READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
- cuptr, local_length_size, local_extension_size);
+ cuptr, local_length_size, local_extension_size);
- return local_extension_size + /* initial extesion, if present
- */
- local_length_size + /* Size of cu length field. */
- sizeof(Dwarf_Half) + /* Size of version stamp field. */
- local_length_size + /* Size of abbrev offset field. */
- sizeof(Dwarf_Small); /* Size of address size field. */
+ return local_extension_size + /* initial extesion, if present
+ */
+ local_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ local_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
}
/*
- Pretend we know nothing about the CU
- and just roughly compute the result.
+ Pretend we know nothing about the CU
+ and just roughly compute the result.
*/
Dwarf_Unsigned
_dwarf_length_of_cu_header_simple(Dwarf_Debug dbg)
{
- return dbg->de_length_size + /* Size of cu length field. */
- sizeof(Dwarf_Half) + /* Size of version stamp field. */
- dbg->de_length_size + /* Size of abbrev offset field. */
- sizeof(Dwarf_Small); /* Size of address size field. */
+ return dbg->de_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ dbg->de_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
}
/* Now that we delay loading .debug_info, we need to do the
@@ -362,22 +479,69 @@ _dwarf_length_of_cu_header_simple(Dwarf_Debug dbg)
int
_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error)
{
- int res;
+ int res = DW_DLV_ERROR;
- /* Testing de_debug_info allows us to avoid testing
- de_debug_abbrev. One test instead of 2. .debug_info is useless
+ /* Testing de_debug_info.dss_data allows us to avoid testing
+ de_debug_abbrev.dss_data.
+ One test instead of 2. .debug_info is useless
without .debug_abbrev. */
- if (dbg->de_debug_info) {
- return DW_DLV_OK;
+ if (dbg->de_debug_info.dss_data) {
+ return DW_DLV_OK;
}
- res = _dwarf_load_section(dbg, dbg->de_debug_abbrev_index,
- &dbg->de_debug_abbrev, error);
+ res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error);
if (res != DW_DLV_OK) {
- return res;
+ return res;
}
- res = _dwarf_load_section(dbg, dbg->de_debug_info_index,
- &dbg->de_debug_info, error);
+ res = _dwarf_load_section(dbg, &dbg->de_debug_info, error);
return res;
}
+void
+_dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,Dwarf_Hash_Table hash_table)
+{
+ /* A Hash Table is an array with tb_table_entry_count struct
+ Dwarf_Hash_Table_s entries in the array. */
+ int hashnum = 0;
+ for (; hashnum < hash_table->tb_table_entry_count; ++hashnum) {
+ struct Dwarf_Abbrev_List_s *abbrev = 0;
+ struct Dwarf_Abbrev_List_s *nextabbrev = 0;
+ struct Dwarf_Hash_Table_Entry_s *tb = &hash_table->tb_entries[hashnum];
+
+ abbrev = tb->at_head;
+ for (; abbrev; abbrev = nextabbrev) {
+ nextabbrev = abbrev->ab_next;
+ dwarf_dealloc(dbg, abbrev, DW_DLA_ABBREV_LIST);
+ }
+ }
+ /* Frees all the entries at once: an array. */
+ dwarf_dealloc(dbg,hash_table->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+}
+
+/*
+ If no die provided the size value returned might be wrong.
+ If different compilation units have different address sizes
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the Elf offset size != address_size
+ (for example if address_size = 4 but recorded in elf64 object)
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the die pointer is non-NULL (in which case it must point to
+ a valid DIE) this will return the correct size.
+*/
+int
+_dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die)
+{
+ Dwarf_CU_Context context = 0;
+ Dwarf_Half addrsize = 0;
+ if(!die) {
+ return dbg->de_pointer_size;
+ }
+ context = die->di_cu_context;
+ addrsize = context->cc_address_size;
+ return addrsize;
+}
+
+
+