summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp')
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp1929
1 files changed, 1929 insertions, 0 deletions
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 00000000000..19eef06d3d1
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,1929 @@
+//===-- 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/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 "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()
+{
+ m_infos.reserve(20);
+}
+
+DWARFDebugInfoEntry::Attributes::~Attributes()
+{
+}
+
+
+uint32_t
+DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const
+{
+ std::vector<Info>::const_iterator end = m_infos.end();
+ std::vector<Info>::const_iterator beg = m_infos.begin();
+ std::vector<Info>::const_iterator pos;
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->attr == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT_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) != UINT_MAX;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
+{
+ uint32_t attr_index = FindAttributeIndex(attr);
+ if (attr_index != UINT_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));
+ dw_offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+}
+
+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;
+}
+
+
+//----------------------------------------------------------------------
+// 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,
+ uint32_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();
+ uint32_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;
+
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ if (abbrCode)
+ {
+ m_abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbrCode);
+
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+
+ bool isCompileUnitTag = 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 = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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
+ {
+die_extract_indirect_form:
+ 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_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 :
+ {
+// const char *s =
+ debug_info_data.GetCStr(&offset);
+// switch (attr)
+// {
+// case DW_AT_name: m_name = s; break;
+// case DW_AT_MIPS_linkage_name: m_linkage_name = s; break;
+// default: break;
+// }
+ }
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ case DW_FORM_ref_addr :
+ form_size = cu_addr_size;
+ 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 :
+// switch (attr)
+// {
+// case DW_AT_name:
+// m_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+// case DW_AT_MIPS_linkage_name:
+// m_linkage_name = debug_str_data.PeekCStr(debug_info_data.GetU32(&offset));
+// break;
+//
+// default:
+ form_size = 4;
+// break;
+// }
+ break;
+
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ // case DW_FORM_APPLE_db_str:
+ 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);
+ goto die_extract_indirect_form;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ }
+ else
+ {
+ m_abbrevDecl = NULL;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendDependentDIES()
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendDependentDIES
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const bool add_children,
+ DWARFDIECollection& dependent_dies
+) const
+{
+ // Add this object's DIE offset
+ // The line below is the only place that should add a die to the
+ // dependent_dies collection as we have to be careful of recursion!
+ if ( !dependent_dies.Insert(this) )
+ return false; // This DIE already exists in the collection, nothing to do!
+
+ //DEBUG_PRINTF(" dependent_dies.Insert(0x%8.8x)\n", GetOffset());///
+
+ if (m_abbrevDecl)
+ {
+ // Keep adding parent DIE offsets as long as the offsets do not
+ // already exist in the collection
+ const DWARFDebugInfoEntry* die = GetParent();
+ while ( die && die->AppendDependentDIES(dwarf2Data, cu, false, dependent_dies) )
+ die = die->GetParent();
+
+ bool add_non_subprogram_children = false;
+ bool add_children_override = false;
+
+ if (!add_children)
+ {
+ switch (m_abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break;
+ case DW_TAG_class_type: add_non_subprogram_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: add_children_override = true; break;
+ case DW_TAG_member: break;
+ case DW_TAG_pointer_type: break;
+ case DW_TAG_reference_type: break;
+ case DW_TAG_compile_unit: break;
+ case DW_TAG_string_type: break;
+ case DW_TAG_structure_type: add_non_subprogram_children = true; break;
+ case DW_TAG_subroutine_type: add_children_override = true; break;
+ case DW_TAG_typedef: break;
+ case DW_TAG_union_type: add_non_subprogram_children = true; break;
+ case DW_TAG_unspecified_parameters: break;
+ case DW_TAG_variant: break;
+ case DW_TAG_common_block: break;
+ case DW_TAG_common_inclusion: break;
+ case DW_TAG_inheritance: break;
+ case DW_TAG_inlined_subroutine: break;
+ case DW_TAG_module: 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: 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: add_children_override = 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: 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: 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;
+ }
+ }
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_offset_t offset = GetOffset();
+ debug_info_data.Skip_LEB128(&offset); // Skip abbreviation code
+
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+
+ switch (attr)
+ {
+ // All cases that use refer to another DIE should use this case
+ // without
+ // having to check the FORM of the attribute to tell if it refers to another
+ // DIE
+ case DW_AT_abstract_origin:
+ case DW_AT_import:
+ case DW_AT_discr:
+ case DW_AT_containing_type:
+ case DW_AT_base_types:
+ case DW_AT_friend:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_common_reference:
+ case DW_AT_default_value:
+ {
+ form_value.ExtractValue(debug_info_data, &offset, cu);
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* ref_die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (ref_die)
+ ref_die->AppendDependentDIES(dwarf2Data, cu_sp_ptr.get(), true, dependent_dies);
+ }
+ break;
+
+ default:
+ if (attr != DW_AT_sibling)
+ {
+ switch (form_value.Form())
+ {
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+// Log::WarningVerbose("DWARFDebugInfoEntry::AppendDependentDIES() -- check on this item %s: attr = %s form = %s",
+// DW_TAG_value_to_name(m_abbrevDecl->Tag()),
+// DW_AT_value_to_name(attr),
+// DW_FORM_value_to_name(form));
+ break;
+ }
+ }
+ form_value.SkipValue(debug_info_data, &offset, cu);
+ break;
+ }
+ }
+
+ if (m_abbrevDecl->HasChildren())
+ {
+ const DWARFDebugInfoEntry* child;
+ for (child = GetFirstChild(); child != NULL; child = child->GetSibling())
+ {
+ bool add = add_children || add_children_override;
+
+ if (!add)
+ {
+ if (add_non_subprogram_children)
+ {
+ // add_non_subprogram_children is used for classes and structs
+ // that may contain children that are the member variables that
+ // may have functions as children and whom may add the class or
+ // struct by adding their parent. We don't want to add any
+ // functions though since they may have been optimized out. But
+ // we do need to watch for declarations and keep them.
+ if (child->Tag() == DW_TAG_subprogram)
+ {
+ // Check if this subprogram TAG had a DW_AT_declaration attribute set to 1.
+ // If so we need to include this DIE so that we always have a complete view
+ // of a class definition so debuggers can track down any weak symbols that
+ // may not have had weak definition entries.
+ if (child->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_declaration, 0) == 1)
+ add = true;
+ }
+ else
+ {
+ // Add all other items inside a class/struct
+ add = true;
+ }
+ }
+ else
+ {
+ // We don't need to add this child, only add it if it's a NULL tag
+ add = child->IsNULL();
+ }
+ }
+
+ if (add)
+ child->AppendDependentDIES(dwarf2Data, cu, true, dependent_dies);
+ }
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------
+// 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 = UINT_MAX;
+ uint32_t b_name_index = UINT_MAX;
+ if (is_decl_index != UINT_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 != UINT_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 != UINT_MAX && b_name_index != UINT_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 = DW_INVALID_ADDRESS;
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ std::vector<dw_offset_t> die_offsets;
+ if (m_abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ uint32_t offset = m_offset;
+
+ if (!debug_info_data.ValidOffset(offset))
+ return false;
+
+ // Skip the abbreviation code
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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:
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_high_pc:
+ hi_pc = form_value.Unsigned();
+ 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.AddOffset(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:
+ 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, NULL);
+ }
+ 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)
+ {
+ Address base_address(cu->GetBaseAddress(), dwarf2Data->GetObjectFile()->GetSectionList());
+ frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ size_t numRanges = ranges.Size();
+
+ if (numRanges == 0)
+ {
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ if (hi_pc != DW_INVALID_ADDRESS)
+ ranges.AddRange(lo_pc, hi_pc);
+ else
+ ranges.AddRange(lo_pc, lo_pc);
+ }
+ }
+
+ if (ranges.Size() == 0 || (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.Size() > 0;
+}
+
+//----------------------------------------------------------------------
+// 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();
+ uint32_t offset = m_offset;
+ bool english = s->GetFlags().IsSet (DWARFDebugInfo::eDumpFlag_EnglishyNames);
+
+ 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)
+ {
+ if (m_abbrevDecl)
+ {
+ if (english)
+ s->PutCString(DW_TAG_value_to_englishy_name(m_abbrevDecl->Tag()));
+ else
+ s->PutCString(DW_TAG_value_to_name(m_abbrevDecl->Tag()));
+ s->Printf( " [%u] %c\n", abbrCode, m_abbrevDecl->HasChildren() ? '*':' ');
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ m_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");
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// 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,
+ uint32_t* offset_ptr,
+ Stream *s,
+ dw_attr_t attr,
+ dw_form_t form
+)
+{
+ bool verbose = s->GetVerbose();
+ bool show_form = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_ShowForm);
+ bool english = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_EnglishyNames);
+ const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL;
+ if (verbose)
+ s->Offset(*offset_ptr);
+ else
+ s->Printf( " ");
+ s->Indent();
+
+ if (english)
+ s->PutCString(DW_AT_value_to_englishy_name(attr));
+ else
+ s->PutCString(DW_AT_value_to_name(attr));
+
+ if (show_form)
+ {
+ s->Printf( "[%s", english ? DW_FORM_value_to_englishy_name(form) : 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]", english ? DW_FORM_value_to_englishy_name(form_value.Form()) : 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.8x", 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);
+ uint32_t ranges_offset = form_value.Unsigned();
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ 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,
+ DWARFDebugInfoEntry::Attributes& attributes
+) const
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t offset = GetOffset();
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ const uint32_t num_attributes = m_abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ DWARFFormValue form_value;
+ for (i=0; i<num_attributes; ++i)
+ {
+ m_abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form);
+ attributes.Append(cu, offset, attr, form);
+ 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, attributes);
+ }
+ 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(), attributes);
+ }
+ }
+ }
+ else
+ {
+ assert(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
+{
+ if (m_abbrevDecl)
+ {
+ uint32_t attr_idx = m_abbrevDecl->FindAttributeIndex(attr);
+
+ if (attr_idx != DW_INVALID_INDEX)
+ {
+ uint32_t offset = GetOffset();
+
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ // Skip the abbreviation code so we are at the data for the attributes
+ debug_info_data.Skip_LEB128(&offset);
+
+ uint32_t idx=0;
+ while (idx<attr_idx)
+ DWARFFormValue::SkipValue(m_abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetForm(m_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;
+}
+
+//----------------------------------------------------------------------
+// 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
+ dw_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());
+ 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 (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;
+ 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_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 uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_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 uint32_t die_offset,
+ Stream *s
+)
+{
+ DWARFDebugInfoEntry die;
+ uint32_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();
+
+ 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;
+}
+
+//----------------------------------------------------------------------
+// BuildAddressRangeTable
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_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->InsertRange(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_abbrevDecl)
+ {
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ if (tag == DW_TAG_subprogram)
+ {
+ dw_addr_t hi_pc = DW_INVALID_ADDRESS;
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_INVALID_ADDRESS)
+ {
+ // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16llx - 0x%16.16llx)\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY
+ debug_aranges->InsertRange(GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// 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_abbrevDecl)
+ {
+ bool check_children = false;
+ bool match_addr_range = false;
+ dw_tag_t tag = m_abbrevDecl->Tag();
+ // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address);
+ switch (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, DW_INVALID_ADDRESS);
+ if (lo_pc != DW_INVALID_ADDRESS)
+ {
+ dw_addr_t hi_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS);
+ if (hi_pc != DW_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 (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 subtroutines so we must always search
+ // if there is no valid high and low PC
+ check_children = (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.AddOffset(cu->GetBaseAddress());
+ if (ranges.Lookup(address))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (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;
+}
+
+
+bool
+DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b)
+{
+ return a.GetOffset() < b.GetOffset();
+}
+
OpenPOWER on IntegriCloud