diff options
Diffstat (limited to 'source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp')
| -rw-r--r-- | source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 2317 |
1 files changed, 2317 insertions, 0 deletions
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp new file mode 100644 index 000000000000..03c12e366f92 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -0,0 +1,2317 @@ +//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugInfoEntry.h" + +#include <assert.h> + +#include <algorithm> + +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/ObjectFile.h" + +#include "DWARFCompileUnit.h" +#include "SymbolFileDWARF.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "DWARFDeclContext.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "DWARFLocationDescription.h" +#include "DWARFLocationList.h" +#include "DWARFDebugRanges.h" + +using namespace lldb_private; +using namespace std; +extern int g_verbose; + + + +DWARFDebugInfoEntry::Attributes::Attributes() : + m_infos() +{ +} + +DWARFDebugInfoEntry::Attributes::~Attributes() +{ +} + + +uint32_t +DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const +{ + collection::const_iterator end = m_infos.end(); + collection::const_iterator beg = m_infos.begin(); + collection::const_iterator pos; + for (pos = beg; pos != end; ++pos) + { + if (pos->attr == attr) + return std::distance(beg, pos); + } + return UINT32_MAX; +} + +void +DWARFDebugInfoEntry::Attributes::Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form) +{ + Info info = { cu, attr_die_offset, attr, form }; + m_infos.push_back(info); +} + +bool +DWARFDebugInfoEntry::Attributes::ContainsAttribute(dw_attr_t attr) const +{ + return FindAttributeIndex(attr) != UINT32_MAX; +} + +bool +DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr) +{ + uint32_t attr_index = FindAttributeIndex(attr); + if (attr_index != UINT32_MAX) + { + m_infos.erase(m_infos.begin() + attr_index); + return true; + } + return false; +} + +bool +DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const +{ + form_value.SetForm(FormAtIndex(i)); + lldb::offset_t offset = DIEOffsetAtIndex(i); + return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i)); +} + +uint64_t +DWARFDebugInfoEntry::Attributes::FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const +{ + const uint32_t attr_idx = FindAttributeIndex (attr); + if (attr_idx != UINT32_MAX) + return FormValueAsUnsignedAtIndex (dwarf2Data, attr_idx, fail_value); + return fail_value; +} + +uint64_t +DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const +{ + DWARFFormValue form_value; + if (ExtractFormValueAtIndex(dwarf2Data, i, form_value)) + return form_value.Reference(CompileUnitAtIndex(i)); + return fail_value; +} + + + +bool +DWARFDebugInfoEntry::FastExtract +( + const DataExtractor& debug_info_data, + const DWARFCompileUnit* cu, + const uint8_t *fixed_form_sizes, + lldb::offset_t *offset_ptr +) +{ + m_offset = *offset_ptr; + m_parent_idx = 0; + m_sibling_idx = 0; + m_empty_children = false; + const uint64_t abbr_idx = debug_info_data.GetULEB128 (offset_ptr); + assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + m_abbr_idx = abbr_idx; + + //assert (fixed_form_sizes); // For best performance this should be specified! + + if (m_abbr_idx) + { + lldb::offset_t offset = *offset_ptr; + + const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(m_abbr_idx); + + if (abbrevDecl == NULL) + { + cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid abbreviation code %u, please file a bug and attach the file at the start of this error message", + m_offset, + (unsigned)abbr_idx); + // WE can't parse anymore if the DWARF is borked... + *offset_ptr = UINT32_MAX; + return false; + } + m_tag = abbrevDecl->Tag(); + m_has_children = abbrevDecl->HasChildren(); + // Skip all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + register uint32_t i; + register dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + form = abbrevDecl->GetFormByIndexUnchecked(i); + + const uint8_t fixed_skip_size = fixed_form_sizes [form]; + if (fixed_skip_size) + offset += fixed_skip_size; + else + { + bool form_is_indirect = false; + do + { + form_is_indirect = false; + register uint32_t form_size = 0; + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_exprloc : + case DW_FORM_block : form_size = debug_info_data.GetULEB128 (&offset); break; + case DW_FORM_block1 : form_size = debug_info_data.GetU8_unchecked (&offset); break; + case DW_FORM_block2 : form_size = debug_info_data.GetU16_unchecked (&offset);break; + case DW_FORM_block4 : form_size = debug_info_data.GetU32_unchecked (&offset);break; + + // Inlined NULL terminated C-strings + case DW_FORM_string : + debug_info_data.GetCStr (&offset); + break; + + // Compile unit address sized values + case DW_FORM_addr : + form_size = cu->GetAddressByteSize(); + break; + case DW_FORM_ref_addr : + if (cu->GetVersion() <= 2) + form_size = cu->GetAddressByteSize(); + else + form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + break; + + // 0 sized form + case DW_FORM_flag_present: + form_size = 0; + break; + + // 1 byte values + case DW_FORM_data1 : + case DW_FORM_flag : + case DW_FORM_ref1 : + form_size = 1; + break; + + // 2 byte values + case DW_FORM_data2 : + case DW_FORM_ref2 : + form_size = 2; + break; + + // 4 byte values + case DW_FORM_strp : + case DW_FORM_data4 : + case DW_FORM_ref4 : + form_size = 4; + break; + + // 8 byte values + case DW_FORM_data8 : + case DW_FORM_ref8 : + case DW_FORM_ref_sig8 : + form_size = 8; + break; + + // signed or unsigned LEB 128 values + case DW_FORM_sdata : + case DW_FORM_udata : + case DW_FORM_ref_udata : + debug_info_data.Skip_LEB128 (&offset); + break; + + case DW_FORM_indirect : + form_is_indirect = true; + form = debug_info_data.GetULEB128 (&offset); + break; + + case DW_FORM_sec_offset : + if (cu->GetAddressByteSize () == 4) + debug_info_data.GetU32 (offset_ptr); + else + debug_info_data.GetU64 (offset_ptr); + break; + + default: + *offset_ptr = m_offset; + return false; + } + offset += form_size; + + } while (form_is_indirect); + } + } + *offset_ptr = offset; + return true; + } + else + { + m_tag = 0; + m_has_children = false; + return true; // NULL debug tag entry + } + + return false; +} + +//---------------------------------------------------------------------- +// Extract +// +// Extract a debug info entry for a given compile unit from the +// .debug_info and .debug_abbrev data within the SymbolFileDWARF class +// starting at the given offset +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::Extract +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + lldb::offset_t *offset_ptr +) +{ + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); +// const DataExtractor& debug_str_data = dwarf2Data->get_debug_str_data(); + const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); + const uint8_t cu_addr_size = cu->GetAddressByteSize(); + lldb::offset_t offset = *offset_ptr; +// if (offset >= cu_end_offset) +// Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset); + if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset)) + { + m_offset = offset; + + const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset); + assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + m_abbr_idx = abbr_idx; + if (abbr_idx) + { + const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbr_idx); + + if (abbrevDecl) + { + m_tag = abbrevDecl->Tag(); + m_has_children = abbrevDecl->HasChildren(); + + bool isCompileUnitTag = m_tag == DW_TAG_compile_unit; + if (cu && isCompileUnitTag) + ((DWARFCompileUnit*)cu)->SetBaseAddress(0); + + // Skip all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + + if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) + { + DWARFFormValue form_value(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) + ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned()); + } + } + else + { + bool form_is_indirect = false; + do + { + form_is_indirect = false; + register uint32_t form_size = 0; + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_exprloc : + case DW_FORM_block : form_size = debug_info_data.GetULEB128(&offset); break; + case DW_FORM_block1 : form_size = debug_info_data.GetU8(&offset); break; + case DW_FORM_block2 : form_size = debug_info_data.GetU16(&offset); break; + case DW_FORM_block4 : form_size = debug_info_data.GetU32(&offset); break; + + // Inlined NULL terminated C-strings + case DW_FORM_string : debug_info_data.GetCStr(&offset); break; + + // Compile unit address sized values + case DW_FORM_addr : + form_size = cu_addr_size; + break; + case DW_FORM_ref_addr : + if (cu->GetVersion() <= 2) + form_size = cu_addr_size; + else + form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + break; + + // 0 sized form + case DW_FORM_flag_present: + form_size = 0; + break; + + // 1 byte values + case DW_FORM_data1 : + case DW_FORM_flag : + case DW_FORM_ref1 : + form_size = 1; + break; + + // 2 byte values + case DW_FORM_data2 : + case DW_FORM_ref2 : + form_size = 2; + break; + + // 4 byte values + case DW_FORM_strp : + form_size = 4; + break; + + case DW_FORM_data4 : + case DW_FORM_ref4 : + form_size = 4; + break; + + // 8 byte values + case DW_FORM_data8 : + case DW_FORM_ref8 : + case DW_FORM_ref_sig8 : + form_size = 8; + break; + + // signed or unsigned LEB 128 values + case DW_FORM_sdata : + case DW_FORM_udata : + case DW_FORM_ref_udata : + debug_info_data.Skip_LEB128(&offset); + break; + + case DW_FORM_indirect : + form = debug_info_data.GetULEB128(&offset); + form_is_indirect = true; + break; + + case DW_FORM_sec_offset : + if (cu->GetAddressByteSize () == 4) + debug_info_data.GetU32 (offset_ptr); + else + debug_info_data.GetU64 (offset_ptr); + break; + + default: + *offset_ptr = offset; + return false; + } + + offset += form_size; + } while (form_is_indirect); + } + } + *offset_ptr = offset; + return true; + } + } + else + { + m_tag = 0; + m_has_children = false; + *offset_ptr = offset; + return true; // NULL debug tag entry + } + } + + return false; +} + +//---------------------------------------------------------------------- +// DumpAncestry +// +// Dumps all of a debug information entries parents up until oldest and +// all of it's attributes to the specified stream. +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::DumpAncestry +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const DWARFDebugInfoEntry* oldest, + Stream &s, + uint32_t recurse_depth +) const +{ + const DWARFDebugInfoEntry* parent = GetParent(); + if (parent && parent != oldest) + parent->DumpAncestry(dwarf2Data, cu, oldest, s, 0); + Dump(dwarf2Data, cu, s, recurse_depth); +} + +//---------------------------------------------------------------------- +// Compare two DIE by comparing all their attributes values, and +// following all DW_FORM_ref attributes and comparing their contents as +// well (except for DW_AT_sibling attributes. +// +// DWARFDebugInfoEntry::CompareState compare_state; +// int result = DWARFDebugInfoEntry::Compare(this, 0x00017ccb, 0x0001eb2b, compare_state, false, true); +//---------------------------------------------------------------------- +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// dw_offset_t a_die_offset, +// dw_offset_t b_die_offset, +// CompareState &compare_state, +// bool compare_siblings, +// bool compare_children +//) +//{ +// if (a_die_offset == b_die_offset) +// return 0; +// +// DWARFCompileUnitSP a_cu_sp; +// DWARFCompileUnitSP b_cu_sp; +// const DWARFDebugInfoEntry* a_die = dwarf2Data->DebugInfo()->GetDIEPtr(a_die_offset, &a_cu_sp); +// const DWARFDebugInfoEntry* b_die = dwarf2Data->DebugInfo()->GetDIEPtr(b_die_offset, &b_cu_sp); +// +// return Compare(dwarf2Data, a_cu_sp.get(), a_die, b_cu_sp.get(), b_die, compare_state, compare_siblings, compare_children); +//} +// +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die, +// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die, +// CompareState &compare_state, +// bool compare_siblings, +// bool compare_children +//) +//{ +// if (a_die == b_die) +// return 0; +// +// if (!compare_state.AddTypePair(a_die->GetOffset(), b_die->GetOffset())) +// { +// // We are already comparing both of these types, so let +// // compares complete for the real result +// return 0; +// } +// +// //printf("DWARFDebugInfoEntry::Compare(0x%8.8x, 0x%8.8x)\n", a_die->GetOffset(), b_die->GetOffset()); +// +// // Do we have two valid DIEs? +// if (a_die && b_die) +// { +// // Both DIE are valid +// int result = 0; +// +// const dw_tag_t a_tag = a_die->Tag(); +// const dw_tag_t b_tag = b_die->Tag(); +// if (a_tag == 0 && b_tag == 0) +// return 0; +// +// //printf(" comparing tags: %s and %s\n", DW_TAG_value_to_name(a_tag), DW_TAG_value_to_name(b_tag)); +// +// if (a_tag < b_tag) +// return -1; +// else if (a_tag > b_tag) +// return 1; +// +// DWARFDebugInfoEntry::Attributes a_attrs; +// DWARFDebugInfoEntry::Attributes b_attrs; +// size_t a_attr_count = a_die->GetAttributes(dwarf2Data, a_cu, a_attrs); +// size_t b_attr_count = b_die->GetAttributes(dwarf2Data, b_cu, b_attrs); +// if (a_attr_count != b_attr_count) +// { +// a_attrs.RemoveAttribute(DW_AT_sibling); +// b_attrs.RemoveAttribute(DW_AT_sibling); +// } +// +// a_attr_count = a_attrs.Size(); +// b_attr_count = b_attrs.Size(); +// +// DWARFFormValue a_form_value; +// DWARFFormValue b_form_value; +// +// if (a_attr_count != b_attr_count) +// { +// uint32_t is_decl_index = a_attrs.FindAttributeIndex(DW_AT_declaration); +// uint32_t a_name_index = UINT32_MAX; +// uint32_t b_name_index = UINT32_MAX; +// if (is_decl_index != UINT32_MAX) +// { +// if (a_attr_count == 2) +// { +// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name); +// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name); +// } +// } +// else +// { +// is_decl_index = b_attrs.FindAttributeIndex(DW_AT_declaration); +// if (is_decl_index != UINT32_MAX && a_attr_count == 2) +// { +// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name); +// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name); +// } +// } +// if (a_name_index != UINT32_MAX && b_name_index != UINT32_MAX) +// { +// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, a_name_index, a_form_value) && +// b_attrs.ExtractFormValueAtIndex(dwarf2Data, b_name_index, b_form_value)) +// { +// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, &dwarf2Data->get_debug_str_data()); +// if (result == 0) +// { +// a_attr_count = b_attr_count = 0; +// compare_children = false; +// } +// } +// } +// } +// +// if (a_attr_count < b_attr_count) +// return -1; +// if (a_attr_count > b_attr_count) +// return 1; +// +// +// // The number of attributes are the same... +// if (a_attr_count > 0) +// { +// const DataExtractor* debug_str_data_ptr = &dwarf2Data->get_debug_str_data(); +// +// uint32_t i; +// for (i=0; i<a_attr_count; ++i) +// { +// const dw_attr_t a_attr = a_attrs.AttributeAtIndex(i); +// const dw_attr_t b_attr = b_attrs.AttributeAtIndex(i); +// //printf(" comparing attributes\n\t\t0x%8.8x: %s %s\t\t0x%8.8x: %s %s\n", +// // a_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(a_attrs.FormAtIndex(i)), DW_AT_value_to_name(a_attr), +// // b_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(b_attrs.FormAtIndex(i)), DW_AT_value_to_name(b_attr)); +// +// if (a_attr < b_attr) +// return -1; +// else if (a_attr > b_attr) +// return 1; +// +// switch (a_attr) +// { +// // Since we call a form of GetAttributes which inlines the +// // attributes from DW_AT_abstract_origin and DW_AT_specification +// // we don't care if their values mismatch... +// case DW_AT_abstract_origin: +// case DW_AT_specification: +// case DW_AT_sibling: +// case DW_AT_containing_type: +// //printf(" action = IGNORE\n"); +// result = 0; +// break; // ignore +// +// default: +// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, i, a_form_value) && +// b_attrs.ExtractFormValueAtIndex(dwarf2Data, i, b_form_value)) +// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, debug_str_data_ptr); +// break; +// } +// +// //printf("\t result = %i\n", result); +// +// if (result != 0) +// { +// // Attributes weren't equal, lets see if we care? +// switch (a_attr) +// { +// case DW_AT_decl_file: +// // TODO: add the ability to compare files in two different compile units +// if (a_cu == b_cu) +// { +// //printf(" action = RETURN RESULT\n"); +// return result; // Only return the compare results when the compile units are the same and the decl_file attributes can be compared +// } +// else +// { +// result = 0; +// //printf(" action = IGNORE\n"); +// } +// break; +// +// default: +// switch (a_attrs.FormAtIndex(i)) +// { +// case DW_FORM_ref1: +// case DW_FORM_ref2: +// case DW_FORM_ref4: +// case DW_FORM_ref8: +// case DW_FORM_ref_udata: +// case DW_FORM_ref_addr: +// //printf(" action = COMPARE DIEs 0x%8.8x 0x%8.8x\n", (dw_offset_t)a_form_value.Reference(a_cu), (dw_offset_t)b_form_value.Reference(b_cu)); +// // These attribute values refer to other DIEs, so lets compare those instead of their DIE offsets... +// result = Compare(dwarf2Data, a_form_value.Reference(a_cu), b_form_value.Reference(b_cu), compare_state, false, true); +// if (result != 0) +// return result; +// break; +// +// default: +// // We do care that they were different, return this result... +// //printf(" action = RETURN RESULT\n"); +// return result; +// } +// } +// } +// } +// } +// //printf(" SUCCESS\n\t\t0x%8.8x: %s\n\t\t0x%8.8x: %s\n", a_die->GetOffset(), DW_TAG_value_to_name(a_tag), b_die->GetOffset(), DW_TAG_value_to_name(b_tag)); +// +// if (compare_children) +// { +// bool a_has_children = a_die->HasChildren(); +// bool b_has_children = b_die->HasChildren(); +// if (a_has_children == b_has_children) +// { +// // Both either have kids or don't +// if (a_has_children) +// result = Compare( dwarf2Data, +// a_cu, a_die->GetFirstChild(), +// b_cu, b_die->GetFirstChild(), +// compare_state, true, compare_children); +// else +// result = 0; +// } +// else if (!a_has_children) +// result = -1; // A doesn't have kids, but B does +// else +// result = 1; // A has kids, but B doesn't +// } +// +// if (compare_siblings) +// { +// result = Compare( dwarf2Data, +// a_cu, a_die->GetSibling(), +// b_cu, b_die->GetSibling(), +// compare_state, true, compare_children); +// } +// +// return result; +// } +// +// if (a_die == NULL) +// return -1; // a_die is NULL, yet b_die is non-NULL +// else +// return 1; // a_die is non-NULL, yet b_die is NULL +// +//} +// +// +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// const DWARFCompileUnit* cu_a, +// const DWARFDebugInfoEntry* die_a, +// const DWARFCompileUnit* cu_a, +// const DWARFDebugInfoEntry* die_b, +// CompareState &compare_state +//) +//{ +//} + +//---------------------------------------------------------------------- +// GetDIENamesAndRanges +// +// Gets the valid address ranges for a given DIE by looking for a +// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges +// attributes. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetDIENamesAndRanges +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const char * &name, + const char * &mangled, + DWARFDebugRanges::RangeList& ranges, + int& decl_file, + int& decl_line, + int& decl_column, + int& call_file, + int& call_line, + int& call_column, + DWARFExpression *frame_base +) const +{ + if (dwarf2Data == NULL) + return false; + + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + std::vector<dw_offset_t> die_offsets; + bool set_frame_base_loclist_addr = false; + + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + if (!debug_info_data.ValidOffset(offset)) + return false; + + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + bool do_offset = false; + + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + DWARFFormValue form_value(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + switch (attr) + { + case DW_AT_low_pc: + lo_pc = form_value.Unsigned(); + + if (do_offset) + hi_pc += lo_pc; + do_offset = false; + break; + + case DW_AT_entry_pc: + lo_pc = form_value.Unsigned(); + break; + + case DW_AT_high_pc: + hi_pc = form_value.Unsigned(); + if (form_value.Form() != DW_FORM_addr) + { + if (lo_pc == LLDB_INVALID_ADDRESS) + do_offset = hi_pc != LLDB_INVALID_ADDRESS; + else + hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save on relocations + } + break; + + case DW_AT_ranges: + { + const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); + debug_ranges->FindRanges(form_value.Unsigned(), ranges); + // All DW_AT_ranges are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + ranges.Slide(cu->GetBaseAddress()); + } + break; + + case DW_AT_name: + if (name == NULL) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + break; + + case DW_AT_MIPS_linkage_name: + case DW_AT_linkage_name: + if (mangled == NULL) + mangled = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + break; + + case DW_AT_abstract_origin: + die_offsets.push_back(form_value.Reference(cu)); + break; + + case DW_AT_specification: + die_offsets.push_back(form_value.Reference(cu)); + break; + + case DW_AT_decl_file: + if (decl_file == 0) + decl_file = form_value.Unsigned(); + break; + + case DW_AT_decl_line: + if (decl_line == 0) + decl_line = form_value.Unsigned(); + break; + + case DW_AT_decl_column: + if (decl_column == 0) + decl_column = form_value.Unsigned(); + break; + + case DW_AT_call_file: + if (call_file == 0) + call_file = form_value.Unsigned(); + break; + + case DW_AT_call_line: + if (call_line == 0) + call_line = form_value.Unsigned(); + break; + + case DW_AT_call_column: + if (call_column == 0) + call_column = form_value.Unsigned(); + break; + + case DW_AT_frame_base: + if (frame_base) + { + if (form_value.BlockData()) + { + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + frame_base->SetOpcodeData(debug_info_data, block_offset, block_length); + } + else + { + const DataExtractor &debug_loc_data = dwarf2Data->get_debug_loc_data(); + const dw_offset_t debug_loc_offset = form_value.Unsigned(); + + size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset); + if (loc_list_length > 0) + { + frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length); + if (lo_pc != LLDB_INVALID_ADDRESS) + { + assert (lo_pc >= cu->GetBaseAddress()); + frame_base->SetLocationListSlide(lo_pc - cu->GetBaseAddress()); + } + else + { + set_frame_base_loclist_addr = true; + } + } + } + } + break; + + default: + break; + } + } + } + } + + if (ranges.IsEmpty()) + { + if (lo_pc != LLDB_INVALID_ADDRESS) + { + if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc) + ranges.Append(DWARFDebugRanges::Range (lo_pc, hi_pc - lo_pc)); + else + ranges.Append(DWARFDebugRanges::Range (lo_pc, 0)); + } + } + + if (set_frame_base_loclist_addr) + { + dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); + assert (lowest_range_pc >= cu->GetBaseAddress()); + frame_base->SetLocationListSlide (lowest_range_pc - cu->GetBaseAddress()); + } + + if (ranges.IsEmpty() || name == NULL || mangled == NULL) + { + std::vector<dw_offset_t>::const_iterator pos; + std::vector<dw_offset_t>::const_iterator end = die_offsets.end(); + for (pos = die_offsets.begin(); pos != end; ++pos) + { + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = NULL; + dw_offset_t die_offset = *pos; + if (die_offset != DW_INVALID_OFFSET) + { + die = dwarf2Data->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr); + if (die) + die->GetDIENamesAndRanges(dwarf2Data, cu_sp_ptr.get(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column); + } + } + } + return !ranges.IsEmpty(); +} + +//---------------------------------------------------------------------- +// Dump +// +// Dumps a debug information entry and all of it's attributes to the +// specified stream. +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::Dump +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + Stream &s, + uint32_t recurse_depth +) const +{ + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + lldb::offset_t offset = m_offset; + + if (debug_info_data.ValidOffset(offset)) + { + dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset); + + s.Printf("\n0x%8.8x: ", m_offset); + s.Indent(); + if (abbrCode != m_abbr_idx) + { + s.Printf( "error: DWARF has been modified\n"); + } + else if (abbrCode) + { + const DWARFAbbreviationDeclaration* abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration (abbrCode); + + if (abbrevDecl) + { + s.PutCString(DW_TAG_value_to_name(abbrevDecl->Tag())); + s.Printf( " [%u] %c\n", abbrCode, abbrevDecl->HasChildren() ? '*':' '); + + // Dump all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + + DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, form); + } + + const DWARFDebugInfoEntry* child = GetFirstChild(); + if (recurse_depth > 0 && child) + { + s.IndentMore(); + + while (child) + { + child->Dump(dwarf2Data, cu, s, recurse_depth-1); + child = child->GetSibling(); + } + s.IndentLess(); + } + } + else + s.Printf( "Abbreviation code note found in 'debug_abbrev' class for code: %u\n", abbrCode); + } + else + { + s.Printf( "NULL\n"); + } + } +} + +void +DWARFDebugInfoEntry::DumpLocation +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + Stream &s +) const +{ + const DWARFDebugInfoEntry *cu_die = cu->GetCompileUnitDIEOnly(); + const char *cu_name = NULL; + if (cu_die != NULL) + cu_name = cu_die->GetName (dwarf2Data, cu); + const char *obj_file_name = NULL; + ObjectFile *obj_file = dwarf2Data->GetObjectFile(); + if (obj_file) + obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString(); + const char *die_name = GetName (dwarf2Data, cu); + s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)", + cu->GetOffset(), + GetOffset(), + die_name ? die_name : "", + cu_name ? cu_name : "<NULL>", + obj_file_name ? obj_file_name : "<NULL>"); +} + +//---------------------------------------------------------------------- +// DumpAttribute +// +// Dumps a debug information entry attribute along with it's form. Any +// special display of attributes is done (disassemble location lists, +// show enumeration values for attributes, etc). +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::DumpAttribute +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const DataExtractor& debug_info_data, + lldb::offset_t *offset_ptr, + Stream &s, + dw_attr_t attr, + dw_form_t form +) +{ + bool verbose = s.GetVerbose(); + bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); + + const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL; + if (verbose) + s.Offset (*offset_ptr); + else + s.Printf (" "); + s.Indent(DW_AT_value_to_name(attr)); + + if (show_form) + { + s.Printf( "[%s", DW_FORM_value_to_name(form)); + } + + DWARFFormValue form_value(form); + + if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu)) + return; + + if (show_form) + { + if (form == DW_FORM_indirect) + { + s.Printf( " [%s]", DW_FORM_value_to_name(form_value.Form())); + } + + s.PutCString("] "); + } + + s.PutCString("( "); + + // Always dump form value if verbose is enabled + if (verbose) + { + form_value.Dump(s, debug_str_data, cu); + } + + + // Check to see if we have any special attribute formatters + switch (attr) + { + case DW_AT_stmt_list: + if ( verbose ) s.PutCString(" ( "); + s.Printf( "0x%8.8" PRIx64, form_value.Unsigned()); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_language: + if ( verbose ) s.PutCString(" ( "); + s.PutCString(DW_LANG_value_to_name(form_value.Unsigned())); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_encoding: + if ( verbose ) s.PutCString(" ( "); + s.PutCString(DW_ATE_value_to_name(form_value.Unsigned())); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_data_member_location: + { + const uint8_t* blockData = form_value.BlockData(); + if (blockData) + { + if (!verbose) + form_value.Dump(s, debug_str_data, cu); + + // Location description is inlined in data in the form value + DataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned()); + if ( verbose ) s.PutCString(" ( "); + print_dwarf_expression (s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false); + if ( verbose ) s.PutCString(" )"); + } + else + { + // We have a location list offset as the value that is + // the offset into the .debug_loc section that describes + // the value over it's lifetime + uint64_t debug_loc_offset = form_value.Unsigned(); + if (dwarf2Data) + { + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset); + } + else + { + if ( !verbose ) + form_value.Dump(s, NULL, cu); + } + } + } + break; + + case DW_AT_abstract_origin: + case DW_AT_specification: + { + uint64_t abstract_die_offset = form_value.Reference(cu); + form_value.Dump(s, debug_str_data, cu); + // *ostrm_ptr << HEX32 << abstract_die_offset << " ( "; + if ( verbose ) s.PutCString(" ( "); + GetName(dwarf2Data, cu, abstract_die_offset, s); + if ( verbose ) s.PutCString(" )"); + } + break; + + case DW_AT_type: + { + uint64_t type_die_offset = form_value.Reference(cu); + if (!verbose) + form_value.Dump(s, debug_str_data, cu); + s.PutCString(" ( "); + AppendTypeName(dwarf2Data, cu, type_die_offset, s); + s.PutCString(" )"); + } + break; + + case DW_AT_ranges: + { + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + lldb::offset_t ranges_offset = form_value.Unsigned(); + dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; + if (dwarf2Data) + DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), &ranges_offset, base_addr); + } + break; + + default: + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + break; + } + + s.PutCString(" )\n"); +} + +//---------------------------------------------------------------------- +// Get all attribute values for a given DIE, including following any +// specification or abstract origin attributes and including those in +// the results. Any duplicate attributes will have the first instance +// take precedence (this can happen for declaration attributes). +//---------------------------------------------------------------------- +size_t +DWARFDebugInfoEntry::GetAttributes +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const uint8_t *fixed_form_sizes, + DWARFDebugInfoEntry::Attributes& attributes, + uint32_t curr_depth +) const +{ + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + if (fixed_form_sizes == NULL) + fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize()); + + const uint32_t num_attributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + DWARFFormValue form_value; + for (i=0; i<num_attributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form); + + // If we are tracking down DW_AT_specification or DW_AT_abstract_origin + // attributes, the depth will be non-zero. We need to omit certain + // attributes that don't make sense. + switch (attr) + { + case DW_AT_sibling: + case DW_AT_declaration: + if (curr_depth > 0) + { + // This attribute doesn't make sense when combined with + // the DIE that references this DIE. We know a DIE is + // referencing this DIE because curr_depth is not zero + break; + } + // Fall through... + default: + attributes.Append(cu, offset, attr, form); + break; + } + + if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) + { + form_value.SetForm(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + const DWARFDebugInfoEntry* die = NULL; + dw_offset_t die_offset = form_value.Reference(cu); + if (cu->ContainsDIEOffset(die_offset)) + { + die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset); + if (die) + die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes, curr_depth + 1); + } + else + { + DWARFCompileUnitSP cu_sp_ptr; + die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr); + if (die) + die->GetAttributes(dwarf2Data, cu_sp_ptr.get(), fixed_form_sizes, attributes, curr_depth + 1); + } + } + } + else + { + const uint8_t fixed_skip_size = fixed_form_sizes [form]; + if (fixed_skip_size) + offset += fixed_skip_size; + else + DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu); + } + } + } + else + { + attributes.Clear(); + } + return attributes.Size(); + +} + +//---------------------------------------------------------------------- +// GetAttributeValue +// +// Get the value of an attribute and return the .debug_info offset of the +// attribute if it was properly extracted into form_value, or zero +// if we fail since an offset of zero is invalid for an attribute (it +// would be a compile unit header). +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugInfoEntry::GetAttributeValue +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DWARFFormValue& form_value, + dw_offset_t* end_attr_offset_ptr +) const +{ + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); + + if (attr_idx != DW_INVALID_INDEX) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + uint32_t idx=0; + while (idx<attr_idx) + DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu); + + const dw_offset_t attr_offset = offset; + form_value.SetForm(abbrevDecl->GetFormByIndex(idx)); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + if (end_attr_offset_ptr) + *end_attr_offset_ptr = offset; + return attr_offset; + } + } + } + + return 0; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsString +// +// Get the value of an attribute as a string return it. The resulting +// pointer to the string data exists within the supplied SymbolFileDWARF +// and will only be available as long as the SymbolFileDWARF is still around +// and it's content doesn't change. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetAttributeValueAsString +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + const char* fail_value) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.AsCString(&dwarf2Data->get_debug_str_data()); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsUnsigned +// +// Get the value of an attribute as unsigned and return it. +//---------------------------------------------------------------------- +uint64_t +DWARFDebugInfoEntry::GetAttributeValueAsUnsigned +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Unsigned(); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsSigned +// +// Get the value of an attribute a signed value and return it. +//---------------------------------------------------------------------- +int64_t +DWARFDebugInfoEntry::GetAttributeValueAsSigned +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + int64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Signed(); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsReference +// +// Get the value of an attribute as reference and fix up and compile +// unit relative offsets as needed. +//---------------------------------------------------------------------- +uint64_t +DWARFDebugInfoEntry::GetAttributeValueAsReference +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Reference(cu); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeHighPC +// +// Get the hi_pc, adding hi_pc to lo_pc when specified +// as an <offset-from-low-pc>. +// +// Returns the hi_pc or fail_value. +//---------------------------------------------------------------------- +dw_addr_t +DWARFDebugInfoEntry::GetAttributeHighPC +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t lo_pc, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value)) + { + dw_addr_t hi_pc = form_value.Unsigned(); + if (form_value.Form() != DW_FORM_addr) + hi_pc += lo_pc; // DWARF4 can specify the hi_pc as an <offset-from-lowpc> + return hi_pc; + } + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeAddressRange +// +// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified +// as an <offset-from-low-pc>. +// +// Returns true or sets lo_pc and hi_pc to fail_value. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetAttributeAddressRange +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t& lo_pc, + dw_addr_t& hi_pc, + uint64_t fail_value +) const +{ + lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, fail_value); + if (lo_pc != fail_value) + { + hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, fail_value); + if (hi_pc != fail_value) + return true; + } + lo_pc = fail_value; + hi_pc = fail_value; + return false; +} +//---------------------------------------------------------------------- +// GetAttributeValueAsLocation +// +// Get the value of an attribute as reference and fix up and compile +// unit relative offsets as needed. +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugInfoEntry::GetAttributeValueAsLocation +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DataExtractor& location_data, + uint32_t &block_size +) const +{ + block_size = 0; + DWARFFormValue form_value; + + // Empty out data in case we don't find anything + location_data.Clear(); + dw_offset_t end_addr_offset = DW_INVALID_OFFSET; + const dw_offset_t attr_offset = GetAttributeValue(dwarf2Data, cu, attr, form_value, &end_addr_offset); + if (attr_offset) + { + const uint8_t* blockData = form_value.BlockData(); + if (blockData) + { + // We have an inlined location list in the .debug_info section + const DataExtractor& debug_info = dwarf2Data->get_debug_info_data(); + dw_offset_t block_offset = blockData - debug_info.GetDataStart(); + block_size = (end_addr_offset - attr_offset) - form_value.Unsigned(); + location_data.SetData(debug_info, block_offset, block_size); + } + else + { + // We have a location list offset as the value that is + // the offset into the .debug_loc section that describes + // the value over it's lifetime + lldb::offset_t debug_loc_offset = form_value.Unsigned(); + if (dwarf2Data) + { + assert(dwarf2Data->get_debug_loc_data().GetAddressByteSize() == cu->GetAddressByteSize()); + return DWARFLocationList::Extract(dwarf2Data->get_debug_loc_data(), &debug_loc_offset, location_data); + } + } + } + return attr_offset; +} + +//---------------------------------------------------------------------- +// GetName +// +// Get value of the DW_AT_name attribute and return it if one exists, +// else return NULL. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + return form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else + { + if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) + { + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + if (die) + return die->GetName(dwarf2Data, cu_sp_ptr.get()); + } + } + return NULL; +} + + +//---------------------------------------------------------------------- +// GetMangledName +// +// Get value of the DW_AT_MIPS_linkage_name attribute and return it if +// one exists, else return the value of the DW_AT_name attribute +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetMangledName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + bool substitute_name_allowed +) const +{ + const char* name = NULL; + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + + if (substitute_name_allowed && name == NULL) + { + if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + } + return name; +} + + +//---------------------------------------------------------------------- +// GetPubname +// +// Get value the name for a DIE as it should appear for a +// .debug_pubnames or .debug_pubtypes section. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetPubname +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu +) const +{ + const char* name = NULL; + if (!dwarf2Data) + return name; + + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) + { + // The specification DIE may be in another compile unit so we need + // to get a die and its compile unit. + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + if (die) + return die->GetPubname(dwarf2Data, cu_sp_ptr.get()); + } + return name; +} + + +//---------------------------------------------------------------------- +// GetName +// +// Get value of the DW_AT_name attribute for a debug information entry +// that exists at offset "die_offset" and place that value into the +// supplied stream object. If the DIE is a NULL object "NULL" is placed +// into the stream, and if no DW_AT_name attribute exists for the DIE +// then nothing is printed. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + Stream &s +) +{ + if (dwarf2Data == NULL) + { + s.PutCString("NULL"); + return false; + } + + DWARFDebugInfoEntry die; + lldb::offset_t offset = die_offset; + if (die.Extract(dwarf2Data, cu, &offset)) + { + if (die.IsNULL()) + { + s.PutCString("NULL"); + return true; + } + else + { + DWARFFormValue form_value; + if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + { + const char* name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + if (name) + { + s.PutCString(name); + return true; + } + } + } + } + return false; +} + +//---------------------------------------------------------------------- +// AppendTypeName +// +// Follows the type name definition down through all needed tags to +// end up with a fully qualified type name and dump the results to +// the supplied stream. This is used to show the name of types given +// a type identifier. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::AppendTypeName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + Stream &s +) +{ + if (dwarf2Data == NULL) + { + s.PutCString("NULL"); + return false; + } + + DWARFDebugInfoEntry die; + lldb::offset_t offset = die_offset; + if (die.Extract(dwarf2Data, cu, &offset)) + { + if (die.IsNULL()) + { + s.PutCString("NULL"); + return true; + } + else + { + const char* name = die.GetPubname(dwarf2Data, cu); + // if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + // name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + if (name) + s.PutCString(name); + else + { + bool result = true; + const DWARFAbbreviationDeclaration* abbrevDecl = die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl == NULL) + return false; + + switch (abbrevDecl->Tag()) + { + case DW_TAG_array_type: break; // print out a "[]" after printing the full type of the element below + case DW_TAG_base_type: s.PutCString("base "); break; + case DW_TAG_class_type: s.PutCString("class "); break; + case DW_TAG_const_type: s.PutCString("const "); break; + case DW_TAG_enumeration_type: s.PutCString("enum "); break; + case DW_TAG_file_type: s.PutCString("file "); break; + case DW_TAG_interface_type: s.PutCString("interface "); break; + case DW_TAG_packed_type: s.PutCString("packed "); break; + case DW_TAG_pointer_type: break; // print out a '*' after printing the full type below + case DW_TAG_ptr_to_member_type: break; // print out a '*' after printing the full type below + case DW_TAG_reference_type: break; // print out a '&' after printing the full type below + case DW_TAG_restrict_type: s.PutCString("restrict "); break; + case DW_TAG_set_type: s.PutCString("set "); break; + case DW_TAG_shared_type: s.PutCString("shared "); break; + case DW_TAG_string_type: s.PutCString("string "); break; + case DW_TAG_structure_type: s.PutCString("struct "); break; + case DW_TAG_subrange_type: s.PutCString("subrange "); break; + case DW_TAG_subroutine_type: s.PutCString("function "); break; + case DW_TAG_thrown_type: s.PutCString("thrown "); break; + case DW_TAG_union_type: s.PutCString("union "); break; + case DW_TAG_unspecified_type: s.PutCString("unspecified "); break; + case DW_TAG_volatile_type: s.PutCString("volatile "); break; + default: + return false; + } + + // Follow the DW_AT_type if possible + DWARFFormValue form_value; + if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value)) + { + uint64_t next_die_offset = form_value.Reference(cu); + result = AppendTypeName(dwarf2Data, cu, next_die_offset, s); + } + + switch (abbrevDecl->Tag()) + { + case DW_TAG_array_type: s.PutCString("[]"); break; + case DW_TAG_pointer_type: s.PutChar('*'); break; + case DW_TAG_ptr_to_member_type: s.PutChar('*'); break; + case DW_TAG_reference_type: s.PutChar('&'); break; + default: + break; + } + return result; + } + } + } + return false; +} + +bool +DWARFDebugInfoEntry::Contains (const DWARFDebugInfoEntry *die) const +{ + if (die) + { + const dw_offset_t die_offset = die->GetOffset(); + if (die_offset > GetOffset()) + { + const DWARFDebugInfoEntry *sibling = GetSibling(); + assert (sibling); // TODO: take this out + if (sibling) + return die_offset < sibling->GetOffset(); + } + } + return false; +} + +//---------------------------------------------------------------------- +// BuildAddressRangeTable +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::BuildAddressRangeTable +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges +) const +{ + if (m_tag) + { + if (m_tag == DW_TAG_subprogram) + { + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) + { + /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc); + debug_aranges->AppendRange (cu->GetOffset(), lo_pc, hi_pc); + } + } + + + const DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + child->BuildAddressRangeTable(dwarf2Data, cu, debug_aranges); + child = child->GetSibling(); + } + } +} + +//---------------------------------------------------------------------- +// BuildFunctionAddressRangeTable +// +// This function is very similar to the BuildAddressRangeTable function +// except that the actual DIE offset for the function is placed in the +// table instead of the compile unit offset (which is the way the +// standard .debug_aranges section does it). +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::BuildFunctionAddressRangeTable +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges +) const +{ + if (m_tag) + { + if (m_tag == DW_TAG_subprogram) + { + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) + { + // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY + debug_aranges->AppendRange (GetOffset(), lo_pc, hi_pc); + } + } + + const DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges); + child = child->GetSibling(); + } + } +} + +void +DWARFDebugInfoEntry::GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDIECollection &decl_context_dies) const +{ + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + if (parent_decl_ctx_die && parent_decl_ctx_die != this) + { + decl_context_dies.Append(parent_decl_ctx_die); + parent_decl_ctx_die->GetDeclContextDIEs (dwarf2Data, cu, decl_context_dies); + } +} + +void +DWARFDebugInfoEntry::GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDeclContext &dwarf_decl_ctx) const +{ + const dw_tag_t tag = Tag(); + if (tag != DW_TAG_compile_unit) + { + dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu)); + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + if (parent_decl_ctx_die && parent_decl_ctx_die != this) + { + if (parent_decl_ctx_die->Tag() != DW_TAG_compile_unit) + parent_decl_ctx_die->GetDWARFDeclContext (dwarf2Data, cu, dwarf_decl_ctx); + } + } +} + + +bool +DWARFDebugInfoEntry::MatchesDWARFDeclContext (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDeclContext &dwarf_decl_ctx) const +{ + + DWARFDeclContext this_dwarf_decl_ctx; + GetDWARFDeclContext (dwarf2Data, cu, this_dwarf_decl_ctx); + return this_dwarf_decl_ctx == dwarf_decl_ctx; +} + +const DWARFDebugInfoEntry * +DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu) const +{ + DWARFDebugInfoEntry::Attributes attributes; + GetAttributes(dwarf2Data, cu, NULL, attributes); + return GetParentDeclContextDIE (dwarf2Data, cu, attributes); +} + +const DWARFDebugInfoEntry * +DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes) const +{ + const DWARFDebugInfoEntry * die = this; + + while (die != NULL) + { + // If this is the original DIE that we are searching for a declaration + // for, then don't look in the cache as we don't want our own decl + // context to be our decl context... + if (die != this) + { + switch (die->Tag()) + { + case DW_TAG_compile_unit: + case DW_TAG_namespace: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + return die; + + default: + break; + } + } + + dw_offset_t die_offset; + + die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_specification, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + const DWARFDebugInfoEntry *spec_die = cu->GetDIEPtr (die_offset); + if (spec_die) + { + const DWARFDebugInfoEntry *spec_die_decl_ctx_die = spec_die->GetParentDeclContextDIE (dwarf2Data, cu); + if (spec_die_decl_ctx_die) + return spec_die_decl_ctx_die; + } + } + + die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_abstract_origin, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + const DWARFDebugInfoEntry *abs_die = cu->GetDIEPtr (die_offset); + if (abs_die) + { + const DWARFDebugInfoEntry *abs_die_decl_ctx_die = abs_die->GetParentDeclContextDIE (dwarf2Data, cu); + if (abs_die_decl_ctx_die) + return abs_die_decl_ctx_die; + } + } + + die = die->GetParent(); + } + return NULL; +} + + +const char * +DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + std::string &storage) const +{ + DWARFDebugInfoEntry::Attributes attributes; + GetAttributes(dwarf2Data, cu, NULL, attributes); + return GetQualifiedName (dwarf2Data, cu, attributes, storage); +} + +const char* +DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes, + std::string &storage) const +{ + + const char *name = GetName (dwarf2Data, cu); + + if (name) + { + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + storage.clear(); + // TODO: change this to get the correct decl context parent.... + while (parent_decl_ctx_die) + { + const dw_tag_t parent_tag = parent_decl_ctx_die->Tag(); + switch (parent_tag) + { + case DW_TAG_namespace: + { + const char *namespace_name = parent_decl_ctx_die->GetName (dwarf2Data, cu); + if (namespace_name) + { + storage.insert (0, "::"); + storage.insert (0, namespace_name); + } + else + { + storage.insert (0, "(anonymous namespace)::"); + } + parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu); + } + break; + + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + { + const char *class_union_struct_name = parent_decl_ctx_die->GetName (dwarf2Data, cu); + + if (class_union_struct_name) + { + storage.insert (0, "::"); + storage.insert (0, class_union_struct_name); + } + parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu); + } + break; + + default: + parent_decl_ctx_die = NULL; + break; + } + } + + if (storage.empty()) + storage.append ("::"); + + storage.append (name); + } + if (storage.empty()) + return NULL; + return storage.c_str(); +} + + +//---------------------------------------------------------------------- +// LookupAddress +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::LookupAddress +( + const dw_addr_t address, + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die +) +{ + bool found_address = false; + if (m_tag) + { + bool check_children = false; + bool match_addr_range = false; + // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address); + switch (m_tag) + { + case DW_TAG_array_type : break; + case DW_TAG_class_type : check_children = true; break; + case DW_TAG_entry_point : break; + case DW_TAG_enumeration_type : break; + case DW_TAG_formal_parameter : break; + case DW_TAG_imported_declaration : break; + case DW_TAG_label : break; + case DW_TAG_lexical_block : check_children = true; match_addr_range = true; break; + case DW_TAG_member : break; + case DW_TAG_pointer_type : break; + case DW_TAG_reference_type : break; + case DW_TAG_compile_unit : match_addr_range = true; break; + case DW_TAG_string_type : break; + case DW_TAG_structure_type : check_children = true; break; + case DW_TAG_subroutine_type : break; + case DW_TAG_typedef : break; + case DW_TAG_union_type : break; + case DW_TAG_unspecified_parameters : break; + case DW_TAG_variant : break; + case DW_TAG_common_block : check_children = true; break; + case DW_TAG_common_inclusion : break; + case DW_TAG_inheritance : break; + case DW_TAG_inlined_subroutine : check_children = true; match_addr_range = true; break; + case DW_TAG_module : match_addr_range = true; break; + case DW_TAG_ptr_to_member_type : break; + case DW_TAG_set_type : break; + case DW_TAG_subrange_type : break; + case DW_TAG_with_stmt : break; + case DW_TAG_access_declaration : break; + case DW_TAG_base_type : break; + case DW_TAG_catch_block : match_addr_range = true; break; + case DW_TAG_const_type : break; + case DW_TAG_constant : break; + case DW_TAG_enumerator : break; + case DW_TAG_file_type : break; + case DW_TAG_friend : break; + case DW_TAG_namelist : break; + case DW_TAG_namelist_item : break; + case DW_TAG_packed_type : break; + case DW_TAG_subprogram : match_addr_range = true; break; + case DW_TAG_template_type_parameter : break; + case DW_TAG_template_value_parameter : break; + case DW_TAG_thrown_type : break; + case DW_TAG_try_block : match_addr_range = true; break; + case DW_TAG_variant_part : break; + case DW_TAG_variable : break; + case DW_TAG_volatile_type : break; + case DW_TAG_dwarf_procedure : break; + case DW_TAG_restrict_type : break; + case DW_TAG_interface_type : break; + case DW_TAG_namespace : check_children = true; break; + case DW_TAG_imported_module : break; + case DW_TAG_unspecified_type : break; + case DW_TAG_partial_unit : break; + case DW_TAG_imported_unit : break; + case DW_TAG_shared_type : break; + default: break; + } + + if (match_addr_range) + { + dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (lo_pc != LLDB_INVALID_ADDRESS) + { + dw_addr_t hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, LLDB_INVALID_ADDRESS); + if (hi_pc != LLDB_INVALID_ADDRESS) + { + // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc); + if ((lo_pc <= address) && (address < hi_pc)) + { + found_address = true; + // puts("***MATCH***"); + switch (m_tag) + { + case DW_TAG_compile_unit: // File + check_children = ((function_die != NULL) || (block_die != NULL)); + break; + + case DW_TAG_subprogram: // Function + if (function_die) + *function_die = this; + check_children = (block_die != NULL); + break; + + case DW_TAG_inlined_subroutine: // Inlined Function + case DW_TAG_lexical_block: // Block { } in code + if (block_die) + { + *block_die = this; + check_children = true; + } + break; + + default: + check_children = true; + break; + } + } + } + else + { // compile units may not have a valid high/low pc when there + // are address gaps in subroutines so we must always search + // if there is no valid high and low PC + check_children = (m_tag == DW_TAG_compile_unit) && ((function_die != NULL) || (block_die != NULL)); + } + } + else + { + dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET); + if (debug_ranges_offset != DW_INVALID_OFFSET) + { + DWARFDebugRanges::RangeList ranges; + DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); + debug_ranges->FindRanges(debug_ranges_offset, ranges); + // All DW_AT_ranges are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + ranges.Slide (cu->GetBaseAddress()); + if (ranges.FindEntryThatContains(address)) + { + found_address = true; + // puts("***MATCH***"); + switch (m_tag) + { + case DW_TAG_compile_unit: // File + check_children = ((function_die != NULL) || (block_die != NULL)); + break; + + case DW_TAG_subprogram: // Function + if (function_die) + *function_die = this; + check_children = (block_die != NULL); + break; + + case DW_TAG_inlined_subroutine: // Inlined Function + case DW_TAG_lexical_block: // Block { } in code + if (block_die) + { + *block_die = this; + check_children = true; + } + break; + + default: + check_children = true; + break; + } + } + else + { + check_children = false; + } + } + } + } + + + if (check_children) + { + // printf("checking children\n"); + DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + if (child->LookupAddress(address, dwarf2Data, cu, function_die, block_die)) + return true; + child = child->GetSibling(); + } + } + } + return found_address; +} + +const DWARFAbbreviationDeclaration* +DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit *cu, + lldb::offset_t &offset) const +{ + if (dwarf2Data) + { + offset = GetOffset(); + + const DWARFAbbreviationDeclaration* abbrev_decl = cu->GetAbbreviations()->GetAbbreviationDeclaration (m_abbr_idx); + if (abbrev_decl) + { + // Make sure the abbreviation code still matches. If it doesn't and + // the DWARF data was mmap'ed, the backing file might have been modified + // which is bad news. + const uint64_t abbrev_code = dwarf2Data->get_debug_info_data().GetULEB128 (&offset); + + if (abbrev_decl->Code() == abbrev_code) + return abbrev_decl; + + dwarf2Data->GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("0x%8.8x: the DWARF debug information has been modified (abbrev code was %u, and is now %u)", + GetOffset(), + (uint32_t)abbrev_decl->Code(), + (uint32_t)abbrev_code); + } + } + offset = DW_INVALID_OFFSET; + return NULL; +} + + +bool +DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b) +{ + return a.GetOffset() < b.GetOffset(); +} + +void +DWARFDebugInfoEntry::DumpDIECollection (Stream &strm, DWARFDebugInfoEntry::collection &die_collection) +{ + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = die_collection.end(); + strm.PutCString("\noffset parent sibling child\n"); + strm.PutCString("-------- -------- -------- --------\n"); + for (pos = die_collection.begin(); pos != end; ++pos) + { + const DWARFDebugInfoEntry& die_ref = *pos; + const DWARFDebugInfoEntry* p = die_ref.GetParent(); + const DWARFDebugInfoEntry* s = die_ref.GetSibling(); + const DWARFDebugInfoEntry* c = die_ref.GetFirstChild(); + strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n", + die_ref.GetOffset(), + p ? p->GetOffset() : 0, + s ? s->GetOffset() : 0, + c ? c->GetOffset() : 0, + die_ref.Tag(), + DW_TAG_value_to_name(die_ref.Tag()), + die_ref.HasChildren() ? " *" : ""); + } +} + + |
