diff options
Diffstat (limited to 'usr/src/tools/ctf/dwarf/common/dwarf_util.c')
-rw-r--r-- | usr/src/tools/ctf/dwarf/common/dwarf_util.c | 470 |
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; +} + + + |