/* This function returns a pointer to a Dwarf_Abbrev_List_s struct for the abbrev with the given code. It puts the struct on the appropriate hash table. It also adds all the abbrev between the last abbrev added and this one to the hash table. In other words, the .debug_abbrev section is scanned sequentially from the top for an abbrev with the given code. All intervening abbrevs are also put into the hash table. This function hashes the given code, and checks the chain at that hash table entry to see if a Dwarf_Abbrev_List_s with the given code exists. If yes, it returns a pointer to that struct. Otherwise, it scans the .debug_abbrev section from the last byte scanned for that CU till either an abbrev with the given code is found, or an abbrev code of 0 is read. It puts Dwarf_Abbrev_List_s entries for all abbrev's read till that point into the hash table. The 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. See also dwarf_get_abbrev() in dwarf_abbrev.c. Returns NULL on error. */ int _dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code, Dwarf_Abbrev_List *list_out, Dwarf_Error *error) { Dwarf_Debug dbg = cu_context->cc_dbg; 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; Dwarf_Byte_Ptr end_abbrev_ptr = 0; unsigned hashable_val = 0; 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 = (struct Dwarf_Hash_Table_Entry_s *)_dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE_ENTRY, hash_table_base->tb_table_entry_count); if (!hash_table_base->tb_entries) { return DW_DLV_NO_ENTRY; } } 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 = (struct Dwarf_Hash_Table_Entry_s *)_dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE_ENTRY, newht.tb_table_entry_count); if (!newht.tb_entries) { return DW_DLV_NO_ENTRY; } /* 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->abl_code != code; hash_abbrev_entry = hash_abbrev_entry->abl_next); if (hash_abbrev_entry != NULL) { /* This returns a pointer to an abbrev list entry, not the list itself. */ *list_out = hash_abbrev_entry; return DW_DLV_OK; } if (cu_context->cc_last_abbrev_ptr) { abbrev_ptr = cu_context->cc_last_abbrev_ptr; end_abbrev_ptr = cu_context->cc_last_abbrev_endptr; } else { /* This is ok because cc_abbrev_offset includes DWP offset if appropriate. */ abbrev_ptr = dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset; if (cu_context->cc_dwp_offsets.pcu_type) { /* In a DWP the abbrevs for this context are known quite precisely. */ Dwarf_Unsigned size = 0; /* Ignore the offset returned. Already in cc_abbrev_offset. */ _dwarf_get_dwp_extra_offset(&cu_context->cc_dwp_offsets, DW_SECT_ABBREV,&size); /* ASSERT: size != 0 */ end_abbrev_ptr = abbrev_ptr + size; } else { end_abbrev_ptr = abbrev_ptr + dbg->de_debug_abbrev.dss_size; } } /* End of abbrev's as we are past the end entirely. This can happen. */ if (abbrev_ptr > end_abbrev_ptr) { return DW_DLV_NO_ENTRY; } /* End of abbrev's for this cu, since abbrev code is 0. */ if (*abbrev_ptr == 0) { return DW_DLV_NO_ENTRY; } do { unsigned new_hashable_val = 0; Dwarf_Off abb_goff = 0; Dwarf_Unsigned atcount = 0; abb_goff = abbrev_ptr - dbg->de_debug_abbrev.dss_data; 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) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return DW_DLV_ERROR; } 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->abl_next = inner_hash_entry->at_head; inner_hash_entry->at_head = inner_list_entry; hash_table_base->tb_total_abbrev_count++; inner_list_entry->abl_code = abbrev_code; inner_list_entry->abl_tag = abbrev_tag; inner_list_entry->abl_has_child = *(abbrev_ptr++); inner_list_entry->abl_abbrev_ptr = abbrev_ptr; inner_list_entry->abl_goffset = abb_goff; hash_table_base->tb_total_abbrev_count++; /* 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); if (!_dwarf_valid_form_we_know(dbg,attr_form,attr_name)) { _dwarf_error(dbg,error,DW_DLE_UNKNOWN_FORM); return DW_DLV_ERROR; } atcount++; } while (attr_name != 0 && attr_form != 0); /* We counted one too high, by counting the NUL byte pair at end of list. So decrement. */ inner_list_entry->abl_count = atcount-1; /* We may have fallen off the end of content, that is not a botch in the section, as there is no rule that the last abbrev need have abbrev_code of 0. */ } while ((abbrev_ptr < end_abbrev_ptr) && *abbrev_ptr != 0 && abbrev_code != code); cu_context->cc_last_abbrev_ptr = abbrev_ptr; cu_context->cc_last_abbrev_endptr = end_abbrev_ptr; if(abbrev_code == code) { *list_out = inner_list_entry; return DW_DLV_OK; } return DW_DLV_NO_ENTRY; }
/* This function returns a pointer to a Dwarf_Abbrev_List_s struct for the abbrev with the given code. It puts the struct on the appropriate hash table. It also adds all the abbrev between the last abbrev added and this one to the hash table. In other words, the .debug_abbrev section is scanned sequentially from the top for an abbrev with the given code. All intervening abbrevs are also put into the hash table. This function hashes the given code, and checks the chain at that hash table entry to see if a Dwarf_Abbrev_List_s with the given code exists. If yes, it returns a pointer to that struct. Otherwise, it scans the .debug_abbrev section from the last byte scanned for that CU till either an abbrev with the given code is found, or an abbrev code of 0 is read. It puts Dwarf_Abbrev_List_s entries for all abbrev's read till that point into the hash table. The 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_Unsigned code) { Dwarf_Debug dbg = cu_context->cc_dbg; 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.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); } do { 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 ? inner_list_entry : NULL); }