diff options
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/DWARF')
43 files changed, 17584 insertions, 0 deletions
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp new file mode 100644 index 00000000000..989e49452fb --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -0,0 +1,211 @@ +//===-- DWARFAbbreviationDeclaration.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFAbbreviationDeclaration.h" + +#include "lldb/Core/dwarf.h" + +#include "DWARFFormValue.h" + +using namespace lldb_private; + +DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() : + m_code (InvalidCode), + m_tag (0), + m_has_children (0), + m_attributes() +{ +} + +DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children) : + m_code (InvalidCode), + m_tag (tag), + m_has_children (has_children), + m_attributes() +{ +} + +bool +DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, uint32_t* offset_ptr) +{ + return Extract(data, offset_ptr, data.GetULEB128(offset_ptr)); +} + +bool +DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, uint32_t* offset_ptr, dw_uleb128_t code) +{ + m_code = code; + m_attributes.clear(); + if (m_code) + { + m_tag = data.GetULEB128(offset_ptr); + m_has_children = data.GetU8(offset_ptr); + + while (data.ValidOffset(*offset_ptr)) + { + dw_attr_t attr = data.GetULEB128(offset_ptr); + dw_form_t form = data.GetULEB128(offset_ptr); + + if (attr && form) + m_attributes.push_back(DWARFAttribute(attr, form)); + else + break; + } + + return m_tag != 0; + } + else + { + m_tag = 0; + m_has_children = 0; + } + + return false; +} + + +void +DWARFAbbreviationDeclaration::Dump(Stream *s) const +{ +// *ostrm_ptr << std::setfill(' ') << std::dec << '[' << std::setw(3) << std::right << m_code << ']' << ' ' << std::setw(30) << std::left << DW_TAG_value_to_name(m_tag) << DW_CHILDREN_value_to_name(m_has_children) << std::endl; +// +// DWARFAttribute::const_iterator pos; +// +// for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos) +// *ostrm_ptr << " " << std::setw(29) << std::left << DW_AT_value_to_name(pos->attr()) << ' ' << DW_FORM_value_to_name(pos->form()) << std::endl; +// +// *ostrm_ptr << std::endl; +} + + + +bool +DWARFAbbreviationDeclaration::IsValid() +{ + return m_code != 0 && m_tag != 0; +} + + +void +DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx) +{ + m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely. + m_tag = abbr_decl.Tag(); + m_has_children = abbr_decl.HasChildren(); + + const DWARFAttribute::collection& attributes = abbr_decl.Attributes(); + const uint32_t num_abbr_decl_attributes = attributes.size(); + + dw_attr_t attr; + dw_form_t form; + uint32_t i; + + for (i = 0; i < num_abbr_decl_attributes; ++i) + { + attributes[i].get(attr, form); + switch (attr) + { + case DW_AT_location: + case DW_AT_frame_base: + // Only add these if they are location expressions (have a single + // value) and not location lists (have a lists of location + // expressions which are only valid over specific address ranges) + if (DWARFFormValue::IsBlockForm(form)) + m_attributes.push_back(DWARFAttribute(attr, form)); + break; + + case DW_AT_low_pc: + case DW_AT_high_pc: + case DW_AT_ranges: + case DW_AT_entry_pc: + // Don't add these attributes + if (i >= idx) + break; + // Fall through and add attribute + default: + // Add anything that isn't address related + m_attributes.push_back(DWARFAttribute(attr, form)); + break; + } + } +} + +void +DWARFAbbreviationDeclaration::CopyChangingStringToStrp( + const DWARFAbbreviationDeclaration& abbr_decl, + const DataExtractor& debug_info_data, + dw_offset_t debug_info_offset, + const DWARFCompileUnit* cu, + const uint32_t strp_min_len +) +{ + m_code = InvalidCode; + m_tag = abbr_decl.Tag(); + m_has_children = abbr_decl.HasChildren(); + + const DWARFAttribute::collection& attributes = abbr_decl.Attributes(); + const uint32_t num_abbr_decl_attributes = attributes.size(); + + dw_attr_t attr; + dw_form_t form; + uint32_t i; + dw_offset_t offset = debug_info_offset; + + for (i = 0; i < num_abbr_decl_attributes; ++i) + { + attributes[i].get(attr, form); + dw_offset_t attr_offset = offset; + DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu); + + if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len)) + m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp)); + else + m_attributes.push_back(DWARFAttribute(attr, form)); + } +} + + +uint32_t +DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const +{ + uint32_t i; + const uint32_t kNumAttributes = m_attributes.size(); + for (i = 0; i < kNumAttributes; ++i) + { + if (m_attributes[i].get_attr() == attr) + return i; + } + return DW_INVALID_INDEX; +} + + +bool +DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& rhs) const +{ + return Tag() == rhs.Tag() + && HasChildren() == rhs.HasChildren() + && Attributes() == rhs.Attributes(); +} + +#if 0 +DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const +{ + out_buff.Append32_as_ULEB128(Code()); + out_buff.Append32_as_ULEB128(Tag()); + out_buff.Append8(HasChildren()); + const uint32_t kNumAttributes = m_attributes.size(); + for (uint32_t i = 0; i < kNumAttributes; ++i) + { + out_buff.Append32_as_ULEB128(m_attributes[i].attr()); + out_buff.Append32_as_ULEB128(m_attributes[i].form()); + } + out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128) + out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128) +} +#endif // 0 diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h new file mode 100644 index 00000000000..7959f264dfe --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -0,0 +1,77 @@ +//===-- DWARFAbbreviationDeclaration.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFAbbreviationDeclaration_h_ +#define liblldb_DWARFAbbreviationDeclaration_h_ + +#include "SymbolFileDWARF.h" +#include "DWARFAttribute.h" + +class DWARFCompileUnit; + +class DWARFAbbreviationDeclaration +{ +public: + enum { InvalidCode = 0 }; + DWARFAbbreviationDeclaration(); + + // For hand crafting an abbreviation declaration + DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children); + void AddAttribute(const DWARFAttribute& attr) + { + m_attributes.push_back(attr); + } + + dw_uleb128_t Code() const { return m_code; } + void SetCode(dw_uleb128_t code) { m_code = code; } + dw_tag_t Tag() const { return m_tag; } + bool HasChildren() const { return m_has_children; } + uint32_t NumAttributes() const { return m_attributes.size(); } + dw_attr_t GetAttrByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_attr() : 0; } + dw_form_t GetFormByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_form() : 0; } + bool GetAttrAndFormByIndex(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const + { + if (m_attributes.size() > idx) + { + m_attributes[idx].get(attr, form); + return true; + } + attr = form = 0; + return false; + } + + // idx is assumed to be valid when calling GetAttrAndFormByIndexUnchecked() + void GetAttrAndFormByIndexUnchecked(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const + { + m_attributes[idx].get(attr, form); + } + void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx); + void CopyChangingStringToStrp( + const DWARFAbbreviationDeclaration& abbr_decl, + const lldb_private::DataExtractor& debug_info_data, + dw_offset_t debug_info_offset, + const DWARFCompileUnit* cu, + const uint32_t strp_min_len); + uint32_t FindAttributeIndex(dw_attr_t attr) const; + bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr); + bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr, dw_uleb128_t code); +// void Append(BinaryStreamBuf& out_buff) const; + bool IsValid(); + void Dump(lldb_private::Stream *s) const; + bool operator == (const DWARFAbbreviationDeclaration& rhs) const; +// DWARFAttribute::collection& Attributes() { return m_attributes; } + const DWARFAttribute::collection& Attributes() const { return m_attributes; } +protected: + dw_uleb128_t m_code; + dw_tag_t m_tag; + uint8_t m_has_children; + DWARFAttribute::collection m_attributes; +}; + +#endif // liblldb_DWARFAbbreviationDeclaration_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h new file mode 100644 index 00000000000..0b44926cba0 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -0,0 +1,45 @@ +//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFAttribute_h_ +#define liblldb_DWARFAttribute_h_ + +#include "DWARFDefines.h" +#include <vector> + +class DWARFAttribute +{ +public: + DWARFAttribute(dw_attr_t attr, dw_form_t form) : + m_attr_form ( attr << 16 | form ) + { + } + + void set(dw_attr_t attr, dw_form_t form) { m_attr_form = (attr << 16) | form; } + void set_attr(dw_attr_t attr) { m_attr_form = (m_attr_form & 0x0000ffffu) | (attr << 16); } + void set_form(dw_form_t form) { m_attr_form = (m_attr_form & 0xffff0000u) | form; } + dw_attr_t get_attr() const { return m_attr_form >> 16; } + dw_form_t get_form() const { return m_attr_form; } + void get(dw_attr_t& attr, dw_form_t& form) const + { + register uint32_t attr_form = m_attr_form; + attr = attr_form >> 16; + form = attr_form; + } + bool operator == (const DWARFAttribute& rhs) const { return m_attr_form == rhs.m_attr_form; } + typedef std::vector<DWARFAttribute> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + +protected: + uint32_t m_attr_form; // Upper 16 bits is attribute, lower 16 bits is form +}; + + +#endif // liblldb_DWARFAttribute_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp new file mode 100644 index 00000000000..e7f92c6eff2 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -0,0 +1,770 @@ +//===-- DWARFCompileUnit.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFCompileUnit.h" + +#include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" + +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARF.h" + +using namespace lldb_private; +using namespace std; + +extern int g_verbose; + +DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* m_dwarf2Data) : + m_dwarf2Data ( m_dwarf2Data ), + m_offset ( DW_INVALID_OFFSET ), + m_length ( 0 ), + m_version ( 0 ), + m_abbrevs ( NULL ), + m_addr_size ( DWARFCompileUnit::GetDefaultAddressSize() ), + m_base_addr ( 0 ), + m_die_array (), + m_aranges_ap (), + m_user_data ( NULL ) +{ +} + +void +DWARFCompileUnit::Clear() +{ + m_offset = DW_INVALID_OFFSET; + m_length = 0; + m_version = 0; + m_abbrevs = NULL; + m_addr_size = DWARFCompileUnit::GetDefaultAddressSize(); + m_base_addr = 0; + m_die_array.clear(); + m_aranges_ap.reset(); + m_user_data = NULL; +} + +bool +DWARFCompileUnit::Extract(const DataExtractor &debug_info, uint32_t* offset_ptr) +{ + Clear(); + + m_offset = *offset_ptr; + + if (debug_info.ValidOffset(*offset_ptr)) + { + dw_offset_t abbr_offset; + const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev(); + m_length = debug_info.GetU32(offset_ptr); + m_version = debug_info.GetU16(offset_ptr); + abbr_offset = debug_info.GetU32(offset_ptr); + m_addr_size = debug_info.GetU8 (offset_ptr); + + bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset); + bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); + + if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr != NULL) + { + m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); + return true; + } + + // reset the offset to where we tried to parse from if anything went wrong + *offset_ptr = m_offset; + } + + return false; +} + + +dw_offset_t +DWARFCompileUnit::Extract(dw_offset_t offset, const DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs) +{ + Clear(); + + m_offset = offset; + + if (debug_info_data.ValidOffset(offset)) + { + m_length = debug_info_data.GetU32(&offset); + m_version = debug_info_data.GetU16(&offset); + bool abbrevs_OK = debug_info_data.GetU32(&offset) == abbrevs->GetOffset(); + m_abbrevs = abbrevs; + m_addr_size = debug_info_data.GetU8 (&offset); + + bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); + + if (version_OK && addr_size_OK && abbrevs_OK && debug_info_data.ValidOffset(offset)) + return offset; + } + return DW_INVALID_OFFSET; +} + +void +DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die) +{ + if (m_die_array.size() > 1) + { + // std::vectors never get any smaller when resized to a smaller size, + // or when clear() or erase() are called, the size will report that it + // is smaller, but the memory allocated remains intact (call capacity() + // to see this). So we need to create a temporary vector and swap the + // contents which will cause just the internal pointers to be swapped + // so that when "tmp_array" goes out of scope, it will destroy the + // contents. + + // Save at least the compile unit DIE + DWARFDebugInfoEntry::collection tmp_array; + m_die_array.swap(tmp_array); + if (keep_compile_unit_die) + m_die_array.push_back(tmp_array.front()); + } +} + +//---------------------------------------------------------------------- +// ParseCompileUnitDIEsIfNeeded +// +// Parses a compile unit and indexes its DIEs if it already hasn't been +// done. +//---------------------------------------------------------------------- +size_t +DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only) +{ + const size_t initial_die_array_size = m_die_array.size(); + if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) + return 0; // Already parsed + + Timer scoped_timer (__PRETTY_FUNCTION__, + "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", + m_offset, + cu_die_only); + + // Set the offset to that of the first DIE + uint32_t offset = GetFirstDIEOffset(); + const dw_offset_t next_cu_offset = GetNextCompileUnitOffset(); + DWARFDebugInfoEntry die; + // Keep a flat array of the DIE for binary lookup by DIE offset + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); +// if (log) +// log->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x", +// cu->GetOffset(), +// cu->GetLength(), +// cu->GetVersion(), +// cu->GetAbbrevOffset(), +// cu->GetAddressByteSize()); + + uint32_t depth = 0; + // We are in our compile unit, parse starting at the offset + // we were told to parse + while (die.Extract(m_dwarf2Data, this, &offset)) + { + if (log) + log->Printf("0x%8.8x: %*.*s%s%s", + die.GetOffset(), + depth * 2, depth * 2, "", + DW_TAG_value_to_name (die.Tag()), + die.HasChildren() ? " *" : ""); + if (cu_die_only) + { + AddDIE(die); + return 1; + } + else if (depth == 0 && initial_die_array_size == 1) + { + // Don't append the CU die as we already did that + } + else + { + AddDIE(die); + } + + const DWARFAbbreviationDeclaration* abbrDecl = die.GetAbbreviationDeclarationPtr(); + if (abbrDecl) + { + // Normal DIE + if (abbrDecl->HasChildren()) + ++depth; + } + else + { + // NULL DIE. + if (depth > 0) + --depth; + else + break; // We are done with this compile unit! + } + + assert(offset <= next_cu_offset); + } + SetDIERelations(); + return m_die_array.size(); +} + + +dw_offset_t +DWARFCompileUnit::GetAbbrevOffset() const +{ + return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; +} + + + +bool +DWARFCompileUnit::Verify(Stream *s) const +{ + const DataExtractor& debug_info = m_dwarf2Data->get_debug_info_data(); + bool valid_offset = debug_info.ValidOffset(m_offset); + bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset()); + bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); + bool verbose = s->GetVerbose(); + if (valid_offset && length_OK && version_OK && addr_size_OK && abbr_offset_OK) + { + if (verbose) + s->Printf(" 0x%8.8x: OK\n", m_offset); + return true; + } + else + { + s->Printf(" 0x%8.8x: ", m_offset); + + m_dwarf2Data->get_debug_info_data().Dump (s, m_offset, lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, 0); + s->EOL(); + if (valid_offset) + { + if (!length_OK) + s->Printf(" The length (0x%8.8x) for this compile unit is too large for the .debug_info provided.\n", m_length); + if (!version_OK) + s->Printf(" The 16 bit compile unit header version is not supported.\n"); + if (!abbr_offset_OK) + s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) is not valid.\n", GetAbbrevOffset()); + if (!addr_size_OK) + s->Printf(" The address size is unsupported: 0x%2.2x\n", m_addr_size); + } + else + s->Printf(" The start offset of the compile unit header in the .debug_info is invalid.\n"); + } + return false; +} + + +void +DWARFCompileUnit::Dump(Stream *s) const +{ + s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at {0x%8.8x})\n", + m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset()); +} + + +static uint8_t g_default_addr_size = 4; + +uint8_t +DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu) +{ + if (cu) + return cu->GetAddressByteSize(); + return DWARFCompileUnit::GetDefaultAddressSize(); +} + +uint8_t +DWARFCompileUnit::GetDefaultAddressSize() +{ + return g_default_addr_size; +} + +void +DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size) +{ + g_default_addr_size = addr_size; +} + +bool +DWARFCompileUnit::LookupAddress +( + const dw_addr_t address, + DWARFDebugInfoEntry** function_die_handle, + DWARFDebugInfoEntry** block_die_handle +) +{ + bool success = false; + + if (function_die_handle != NULL && DIE()) + { + if (m_aranges_ap.get() == NULL) + { + m_aranges_ap.reset(new DWARFDebugAranges()); + m_die_array.front().BuildFunctionAddressRangeTable(m_dwarf2Data, this, m_aranges_ap.get()); + } + + // Re-check the aranges auto pointer contents in case it was created above + if (m_aranges_ap.get() != NULL) + { + *function_die_handle = GetDIEPtr(m_aranges_ap->FindAddress(address)); + if (*function_die_handle != NULL) + { + success = true; + if (block_die_handle != NULL) + { + DWARFDebugInfoEntry* child = (*function_die_handle)->GetFirstChild(); + while (child) + { + if (child->LookupAddress(address, m_dwarf2Data, this, NULL, block_die_handle)) + break; + child = child->GetSibling(); + } + } + } + } + } + return success; +} + +//---------------------------------------------------------------------- +// SetDIERelations() +// +// We read in all of the DIE entries into our flat list of DIE entries +// and now we need to go back through all of them and set the parent, +// sibling and child pointers for quick DIE navigation. +//---------------------------------------------------------------------- +void +DWARFCompileUnit::SetDIERelations() +{ +#if 0 + // Compute average bytes per DIE + // + // We can figure out what the average number of bytes per DIE is + // to help us pre-allocate the correct number of m_die_array + // entries so we don't end up doing a lot of memory copies as we + // are creating our DIE array when parsing + // + // Enable this code by changing "#if 0" above to "#if 1" and running + // the dsymutil or dwarfdump with a bunch of dwarf files and see what + // the running average ends up being in the stdout log. + static size_t g_total_cu_debug_info_size = 0; + static size_t g_total_num_dies = 0; + static size_t g_min_bytes_per_die = UINT_MAX; + static size_t g_max_bytes_per_die = 0; + const size_t num_dies = m_die_array.size(); + const size_t cu_debug_info_size = GetDebugInfoSize(); + const size_t bytes_per_die = cu_debug_info_size / num_dies; + if (g_min_bytes_per_die > bytes_per_die) + g_min_bytes_per_die = bytes_per_die; + if (g_max_bytes_per_die < bytes_per_die) + g_max_bytes_per_die = bytes_per_die; + if (g_total_cu_debug_info_size == 0) + { + cout << " min max avg" << endl + << "n dies cu size bpd bpd bpd bpd" << endl + << "------ -------- --- === === ===" << endl; + } + g_total_cu_debug_info_size += cu_debug_info_size; + g_total_num_dies += num_dies; + const size_t avg_bytes_per_die = g_total_cu_debug_info_size / g_total_num_dies; + cout + << DECIMAL_WIDTH(6) << num_dies << ' ' + << DECIMAL_WIDTH(8) << cu_debug_info_size << ' ' + << DECIMAL_WIDTH(3) << bytes_per_die << ' ' + << DECIMAL_WIDTH(3) << g_min_bytes_per_die << ' ' + << DECIMAL_WIDTH(3) << g_max_bytes_per_die << ' ' + << DECIMAL_WIDTH(3) << avg_bytes_per_die + << endl; +#endif + if (m_die_array.empty()) + return; + DWARFDebugInfoEntry* die_array_begin = &m_die_array.front(); + DWARFDebugInfoEntry* die_array_end = &m_die_array.back(); + DWARFDebugInfoEntry* curr_die; + // We purposely are skipping the last element in the array in the loop below + // so that we can always have a valid next item + for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) + { + // Since our loop doesn't include the last element, we can always + // safely access the next die in the array. + DWARFDebugInfoEntry* next_die = curr_die + 1; + + const DWARFAbbreviationDeclaration* curr_die_abbrev = curr_die->GetAbbreviationDeclarationPtr(); + + if (curr_die_abbrev) + { + // Normal DIE + if (curr_die_abbrev->HasChildren()) + next_die->SetParent(curr_die); + else + curr_die->SetSibling(next_die); + } + else + { + // NULL DIE that terminates a sibling chain + DWARFDebugInfoEntry* parent = curr_die->GetParent(); + if (parent) + parent->SetSibling(next_die); + } + } + + // Since we skipped the last element, we need to fix it up! + if (die_array_begin < die_array_end) + curr_die->SetParent(die_array_begin); + +#if 0 + // The code below will dump the DIE relations in case any modification + // is done to the above code. This dump can be used in a diff to make + // sure that no functionality is lost. + { + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + puts("offset parent sibling child"); + puts("-------- -------- -------- --------"); + for (pos = m_die_array.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(); + printf("%.8x: %.8x %.8x %.8x\n", die_ref.GetOffset(), + p ? p->GetOffset() : 0, + s ? s->GetOffset() : 0, + c ? c->GetOffset() : 0); + } + } +#endif + +} +//---------------------------------------------------------------------- +// Compare function DWARFDebugAranges::Range structures +//---------------------------------------------------------------------- +static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2) +{ + return die1.GetOffset() < die2.GetOffset(); +} + +//---------------------------------------------------------------------- +// GetDIEPtr() +// +// Get the DIE (Debug Information Entry) with the specified offset. +//---------------------------------------------------------------------- +DWARFDebugInfoEntry* +DWARFCompileUnit::GetDIEPtr(dw_offset_t die_offset) +{ + if (die_offset != DW_INVALID_OFFSET) + { + ExtractDIEsIfNeeded (false); + DWARFDebugInfoEntry compare_die; + compare_die.SetOffset(die_offset); + DWARFDebugInfoEntry::iterator end = m_die_array.end(); + DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset); + if (pos != end) + { + if (die_offset == (*pos).GetOffset()) + return &(*pos); + } + } + return NULL; // Not found in any compile units +} + +//---------------------------------------------------------------------- +// GetDIEPtrContainingOffset() +// +// Get the DIE (Debug Information Entry) that contains the specified +// .debug_info offset. +//---------------------------------------------------------------------- +const DWARFDebugInfoEntry* +DWARFCompileUnit::GetDIEPtrContainingOffset(dw_offset_t die_offset) +{ + if (die_offset != DW_INVALID_OFFSET) + { + ExtractDIEsIfNeeded (false); + DWARFDebugInfoEntry compare_die; + compare_die.SetOffset(die_offset); + DWARFDebugInfoEntry::iterator end = m_die_array.end(); + DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset); + if (pos != end) + { + if (die_offset >= (*pos).GetOffset()) + { + DWARFDebugInfoEntry::iterator next = pos + 1; + if (next != end) + { + if (die_offset < (*next).GetOffset()) + return &(*pos); + } + } + } + } + return NULL; // Not found in any compile units +} + + + +size_t +DWARFCompileUnit::AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& dies, uint32_t depth) const +{ + size_t old_size = dies.Size(); + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + for (pos = m_die_array.begin(); pos != end; ++pos) + { + if (pos->Tag() == tag) + dies.Insert(&(*pos)); + } + + // Return the number of DIEs added to the collection + return dies.Size() - old_size; +} + +void +DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx) +{ + m_global_die_indexes.push_back (die_idx); +} + + +void +DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die) +{ + // Indexes to all file level global and static variables + m_global_die_indexes; + + if (m_die_array.empty()) + return; + + const DWARFDebugInfoEntry* first_die = &m_die_array[0]; + const DWARFDebugInfoEntry* end = first_die + m_die_array.size(); + if (first_die <= die && die < end) + m_global_die_indexes.push_back (die - first_die); +} + + +void +DWARFCompileUnit::Index +( + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die +) +{ + + const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data(); + + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator begin = m_die_array.begin(); + DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); + for (pos = begin; pos != end; ++pos) + { + const DWARFDebugInfoEntry &die = *pos; + + const dw_tag_t tag = die.Tag(); + + switch (tag) + { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_string_type: + case DW_TAG_subroutine_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_typedef: + case DW_TAG_namespace: + case DW_TAG_variable: + break; + + default: + continue; + } + + DWARFDebugInfoEntry::Attributes attributes; + const char *name = NULL; + const char *mangled = NULL; + bool is_variable = false; + bool is_declaration = false; + bool is_artificial = false; + bool has_address = false; + bool has_location = false; + bool is_global_or_static_variable = false; + const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, attributes); + if (num_attributes > 0) + { + uint32_t i; + + dw_tag_t tag = die.Tag(); + + is_variable = tag == DW_TAG_variable; + + for (i=0; i<num_attributes; ++i) + { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + switch (attr) + { + case DW_AT_name: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + name = form_value.AsCString(debug_str); + break; + + case DW_AT_declaration: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + is_declaration = form_value.Unsigned() != 0; + break; + + case DW_AT_artificial: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + is_artificial = form_value.Unsigned() != 0; + break; + + case DW_AT_MIPS_linkage_name: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + mangled = form_value.AsCString(debug_str); + break; + + case DW_AT_low_pc: + case DW_AT_ranges: + case DW_AT_entry_pc: + has_address = true; + break; + + case DW_AT_location: + has_location = true; + if (tag == DW_TAG_variable) + { + const DWARFDebugInfoEntry* parent_die = die.GetParent(); + while ( parent_die != NULL ) + { + switch (parent_die->Tag()) + { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + // Even if this is a function level static, we don't add it. We could theoretically + // add these if we wanted to by introspecting into the DW_AT_location and seeing + // if the location describes a hard coded address, but we dont want the performance + // penalty of that right now. + is_global_or_static_variable = false; +// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) +// { +// // If we have valid block data, then we have location expression bytes +// // that are fixed (not a location list). +// const uint8_t *block_data = form_value.BlockData(); +// if (block_data) +// { +// uint32_t block_length = form_value.Unsigned(); +// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) +// { +// if (block_data[0] == DW_OP_addr) +// add_die = true; +// } +// } +// } + parent_die = NULL; // Terminate the while loop. + break; + + case DW_TAG_compile_unit: + is_global_or_static_variable = true; + parent_die = NULL; // Terminate the while loop. + break; + + default: + parent_die = parent_die->GetParent(); // Keep going in the while loop. + break; + } + } + } + break; + } + } + } + + switch (tag) + { + case DW_TAG_subprogram: + if (has_address) + { + if (name && name[0]) + { + if ((name[0] == '-' || name[0] == '+') && name[1] == '[') + { + int name_len = strlen (name); + // Objective C methods must have at least: + // "-[" or "+[" prefix + // One character for a class name + // One character for the space between the class name + // One character for the method name + // "]" suffix + if (name_len >= 6 && name[name_len - 1] == ']') + { + const char *method_name = strchr (name, ' '); + if (method_name) + { + // Skip the space + ++method_name; + // Extract the objective C basename and add it to the + // accelerator tables + size_t method_name_len = name_len - (method_name - name) - 1; + ConstString method_const_str (method_name, method_name_len); + name_to_function_die.Append(method_const_str.AsCString(), die.GetOffset()); + } + } + } + name_to_function_die.Append(ConstString(name).AsCString(), die.GetOffset()); + } + if (mangled && mangled[0]) + name_to_function_die.Append(ConstString(mangled).AsCString(), die.GetOffset()); + } + break; + + case DW_TAG_inlined_subroutine: + if (has_address) + { + if (name && name[0]) + name_to_inlined_die.Append(ConstString(name).AsCString(), die.GetOffset()); + if (mangled && mangled[0]) + name_to_inlined_die.Append(ConstString(mangled).AsCString(), die.GetOffset()); + } + break; + + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_string_type: + case DW_TAG_subroutine_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_typedef: + case DW_TAG_namespace: + if (name && is_declaration == false) + { + name_to_type_die.Append(ConstString(name).AsCString(), die.GetOffset()); + } + break; + + case DW_TAG_variable: + if (name && has_location && is_global_or_static_variable) + { + AddGlobalDIEByIndex (std::distance (begin, pos)); + name_to_global_die.Append(ConstString(name).AsCString(), die.GetOffset()); + } + break; + + default: + continue; + } + } +} + + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h new file mode 100644 index 00000000000..44bbbfe5ba4 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -0,0 +1,168 @@ +//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFCompileUnit_h_ +#define SymbolFileDWARF_DWARFCompileUnit_h_ + +#include "SymbolFileDWARF.h" +#include "DWARFDebugInfoEntry.h" + +class DWARFCompileUnit +{ +public: + DWARFCompileUnit(SymbolFileDWARF* dwarf2Data); + + bool Extract(const lldb_private::DataExtractor &debug_info, uint32_t* offset_ptr); + dw_offset_t Extract(dw_offset_t offset, const lldb_private::DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs); + size_t ExtractDIEsIfNeeded (bool cu_die_only); + bool LookupAddress( + const dw_addr_t address, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die); + + size_t AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& matching_dies, uint32_t depth = UINT_MAX) const; + void Clear(); + bool Verify(lldb_private::Stream *s) const; + void Dump(lldb_private::Stream *s) const; + dw_offset_t GetOffset() const { return m_offset; } + uint32_t Size() const { return 11; /* Size in bytes of the compile unit header */ } + bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); } + dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); } + dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + 4; } + size_t GetDebugInfoSize() const { return m_length + 4 - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ } + uint32_t GetLength() const { return m_length; } + uint16_t GetVersion() const { return m_version; } + const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; } + dw_offset_t GetAbbrevOffset() const; + uint8_t GetAddressByteSize() const { return m_addr_size; } + dw_addr_t GetBaseAddress() const { return m_base_addr; } + void ClearDIEs(bool keep_compile_unit_die); + + void + SetBaseAddress(dw_addr_t base_addr) + { + m_base_addr = base_addr; + } + + void + SetDIERelations(); + + const DWARFDebugInfoEntry* + GetCompileUnitDIEOnly() + { + ExtractDIEsIfNeeded (true); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } + + const DWARFDebugInfoEntry* + DIE() + { + ExtractDIEsIfNeeded (false); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } + + void + AddDIE(DWARFDebugInfoEntry& die) + { + // The average bytes per DIE entry has been seen to be + // around 14-20 so lets pre-reserve the needed memory for + // our DIE entries accordingly. Search forward for "Compute + // average bytes per DIE" to see #if'ed out code that does + // that determination. + + // Only reserve the memory if we are adding children of + // the main compile unit DIE. The compile unit DIE is always + // the first entry, so if our size is 1, then we are adding + // the first compile unit child DIE and should reserve + // the memory. + if (m_die_array.empty()) + m_die_array.reserve(GetDebugInfoSize() / 14); + m_die_array.push_back(die); + } + + DWARFDebugInfoEntry* + GetDIEPtr (dw_offset_t die_offset); + + const DWARFDebugInfoEntry* + GetDIEPtrContainingOffset (dw_offset_t die_offset); + + static uint8_t + GetAddressByteSize(const DWARFCompileUnit* cu); + + static uint8_t + GetDefaultAddressSize(); + static void + SetDefaultAddressSize(uint8_t addr_size); + + void * + GetUserData() const + { + return m_user_data; + } + + void + SetUserData(void *d) + { + m_user_data = d; + } + + + void + AddGlobalDIEByIndex (uint32_t die_idx); + + void + AddGlobal (const DWARFDebugInfoEntry* die); + + size_t + GetNumGlobals () const + { + return m_global_die_indexes.size(); + } + + const DWARFDebugInfoEntry * + GetGlobalDIEAtIndex (uint32_t idx) + { + if (idx < m_global_die_indexes.size()) + { + uint32_t die_idx = m_global_die_indexes[idx]; + if (die_idx < m_die_array.size()) + return &m_die_array[die_idx]; + } + return NULL; + } + + void + Index (lldb_private::UniqueCStringMap<dw_offset_t>& name_to_function_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_inlined_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_global_die, + lldb_private::UniqueCStringMap<dw_offset_t>& name_to_type_die); + +protected: + SymbolFileDWARF* m_dwarf2Data; + dw_offset_t m_offset; + uint32_t m_length; + uint16_t m_version; + const DWARFAbbreviationDeclarationSet* + m_abbrevs; + uint8_t m_addr_size; + dw_addr_t m_base_addr; + DWARFDebugInfoEntry::collection + m_die_array; // The compile unit debug information entry item + std::auto_ptr<DWARFDebugAranges> m_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs + std::vector<uint32_t> m_global_die_indexes; // Indexes to all file level global and static variables + void * m_user_data; +private: + DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit); +}; + +#endif // SymbolFileDWARF_DWARFCompileUnit_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp new file mode 100644 index 00000000000..60aac74ad86 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp @@ -0,0 +1,56 @@ +//===-- DWARFDIECollection.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDIECollection.h" + +#include <algorithm> + +#include "lldb/Core/Stream.h" + +#include "DWARFDebugInfoEntry.h" + +using namespace lldb_private; +using namespace std; + +bool +DWARFDIECollection::Insert(const DWARFDebugInfoEntry *die) +{ + iterator end_pos = m_dies.end(); + iterator insert_pos = upper_bound(m_dies.begin(), end_pos, die); + if (insert_pos != end_pos && (*insert_pos == die)) + return false; + m_dies.insert(insert_pos, die); + return true; +} + +const DWARFDebugInfoEntry * +DWARFDIECollection::GetDIEPtrAtIndex(uint32_t idx) const +{ + if (idx < m_dies.size()) + return m_dies[idx]; + return NULL; +} + + +size_t +DWARFDIECollection::Size() const +{ + return m_dies.size(); +} + +void +DWARFDIECollection::Dump(Stream *s, const char* title) const +{ + if (title && title[0] != '\0') + s->Printf( "%s\n", title); + const_iterator end_pos = m_dies.end(); + const_iterator pos; + for (pos = m_dies.begin(); pos != end_pos; ++pos) + s->Printf( "0x%8.8x\n", (*pos)->GetOffset()); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h new file mode 100644 index 00000000000..c374a148c6c --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h @@ -0,0 +1,48 @@ +//===-- DWARFDIECollection.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDIECollection_h_ +#define SymbolFileDWARF_DWARFDIECollection_h_ + +#include "SymbolFileDWARF.h" +#include <vector> + +class DWARFDIECollection +{ +public: + DWARFDIECollection() : + m_dies() + { + } + ~DWARFDIECollection() + { + } + + void + Dump(lldb_private::Stream *s, const char* title) const; + + const DWARFDebugInfoEntry* + GetDIEPtrAtIndex(uint32_t idx) const; + + bool + Insert(const DWARFDebugInfoEntry *die); + + size_t + Size() const; + +protected: + typedef std::vector<const DWARFDebugInfoEntry *> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + collection m_dies; // Ordered list of die offsets +}; + + +#endif // SymbolFileDWARF_DWARFDIECollection_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp new file mode 100644 index 00000000000..af6fc8e93e7 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp @@ -0,0 +1,202 @@ +//===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugAbbrev.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Stream.h" + +using namespace lldb; +using namespace lldb_private; +using namespace std; + +//---------------------------------------------------------------------- +// DWARFAbbreviationDeclarationSet::Clear() +//---------------------------------------------------------------------- +void +DWARFAbbreviationDeclarationSet::Clear() +{ + m_idx_offset = 0; + m_decls.clear(); +} + + +//---------------------------------------------------------------------- +// DWARFAbbreviationDeclarationSet::Extract() +//---------------------------------------------------------------------- +bool +DWARFAbbreviationDeclarationSet::Extract(const DataExtractor& data, uint32_t* offset_ptr) +{ + const uint32_t begin_offset = *offset_ptr; + m_offset = begin_offset; + Clear(); + DWARFAbbreviationDeclaration abbrevDeclaration; + dw_uleb128_t prev_abbr_code = 0; + while (abbrevDeclaration.Extract(data, offset_ptr)) + { + m_decls.push_back(abbrevDeclaration); + if (m_idx_offset == 0) + m_idx_offset = abbrevDeclaration.Code(); + else + { + if (prev_abbr_code + 1 != abbrevDeclaration.Code()) + m_idx_offset = UINT_MAX; // Out of order indexes, we can't do O(1) lookups... + } + prev_abbr_code = abbrevDeclaration.Code(); + } + return begin_offset != *offset_ptr; +} + + +//---------------------------------------------------------------------- +// DWARFAbbreviationDeclarationSet::Dump() +//---------------------------------------------------------------------- +void +DWARFAbbreviationDeclarationSet::Dump(Stream *s) const +{ + std::for_each (m_decls.begin(), m_decls.end(), bind2nd(std::mem_fun_ref(&DWARFAbbreviationDeclaration::Dump),s)); +} + + +//---------------------------------------------------------------------- +// DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration() +//---------------------------------------------------------------------- +const DWARFAbbreviationDeclaration* +DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const +{ + if (m_idx_offset == UINT_MAX) + { + DWARFAbbreviationDeclarationCollConstIter pos; + DWARFAbbreviationDeclarationCollConstIter end = m_decls.end(); + for (pos = m_decls.begin(); pos != end; ++pos) + { + if (pos->Code() == abbrCode) + return &(*pos); + } + } + else + { + uint32_t idx = abbrCode - m_idx_offset; + if (idx < m_decls.size()) + return &m_decls[idx]; + } + return NULL; +} + +//---------------------------------------------------------------------- +// DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential() +// +// Append an abbreviation declaration with a sequential code for O(n) +// lookups. Handy when creating an DWARFAbbreviationDeclarationSet. +//---------------------------------------------------------------------- +dw_uleb128_t +DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl) +{ + // Get the next abbreviation code based on our current array size + dw_uleb128_t code = m_decls.size()+1; + + // Push the new declaration on the back + m_decls.push_back(abbrevDecl); + + // Update the code for this new declaration + m_decls.back().SetCode(code); + + return code; // return the new abbreviation code! +} + + +//---------------------------------------------------------------------- +// Encode +// +// Encode the abbreviation table onto the end of the buffer provided +// into a byte represenation as would be found in a ".debug_abbrev" +// debug information section. +//---------------------------------------------------------------------- +//void +//DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) const +//{ +// DWARFAbbreviationDeclarationCollConstIter pos; +// DWARFAbbreviationDeclarationCollConstIter end = m_decls.end(); +// for (pos = m_decls.begin(); pos != end; ++pos) +// pos->Append(debug_abbrev_buf); +// debug_abbrev_buf.Append8(0); +//} + + +//---------------------------------------------------------------------- +// DWARFDebugAbbrev constructor +//---------------------------------------------------------------------- +DWARFDebugAbbrev::DWARFDebugAbbrev() : + m_abbrevCollMap(), + m_prev_abbr_offset_pos(m_abbrevCollMap.end()) +{ +} + + +//---------------------------------------------------------------------- +// DWARFDebugAbbrev::Parse() +//---------------------------------------------------------------------- +void +DWARFDebugAbbrev::Parse(const DataExtractor& data) +{ + uint32_t offset = 0; + + while (data.ValidOffset(offset)) + { + uint32_t initial_cu_offset = offset; + DWARFAbbreviationDeclarationSet abbrevDeclSet; + + if (abbrevDeclSet.Extract(data, &offset)) + m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet; + else + break; + } + m_prev_abbr_offset_pos = m_abbrevCollMap.end(); +} + +//---------------------------------------------------------------------- +// DWARFDebugAbbrev::Dump() +//---------------------------------------------------------------------- +void +DWARFDebugAbbrev::Dump(Stream *s) const +{ + if (m_abbrevCollMap.empty()) + { + s->PutCString("< EMPTY >\n"); + return; + } + + DWARFAbbreviationDeclarationCollMapConstIter pos; + for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos) + { + s->Printf("Abbrev table for offset: 0x%8.8x\n", pos->first); + pos->second.Dump(s); + } +} + + +//---------------------------------------------------------------------- +// DWARFDebugAbbrev::GetAbbreviationDeclarationSet() +//---------------------------------------------------------------------- +const DWARFAbbreviationDeclarationSet* +DWARFDebugAbbrev::GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const +{ + DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end(); + DWARFAbbreviationDeclarationCollMapConstIter pos; + if (m_prev_abbr_offset_pos != end && m_prev_abbr_offset_pos->first == cu_abbr_offset) + return &(m_prev_abbr_offset_pos->second); + else + { + pos = m_abbrevCollMap.find(cu_abbr_offset); + m_prev_abbr_offset_pos = pos; + } + + if (pos != m_abbrevCollMap.end()); + return &(pos->second); + return NULL; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h new file mode 100644 index 00000000000..3185d9895a3 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h @@ -0,0 +1,74 @@ +//===-- DWARFDebugAbbrev.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugAbbrev_h_ +#define SymbolFileDWARF_DWARFDebugAbbrev_h_ + +#include <list> +#include <map> + +#include "lldb/lldb-private.h" + +#include "DWARFDefines.h" +#include "DWARFAbbreviationDeclaration.h" + +typedef std::vector<DWARFAbbreviationDeclaration> DWARFAbbreviationDeclarationColl; +typedef DWARFAbbreviationDeclarationColl::iterator DWARFAbbreviationDeclarationCollIter; +typedef DWARFAbbreviationDeclarationColl::const_iterator DWARFAbbreviationDeclarationCollConstIter; + + +class DWARFAbbreviationDeclarationSet +{ +public: + DWARFAbbreviationDeclarationSet() : + m_offset(DW_INVALID_OFFSET), + m_idx_offset(0), + m_decls() + { + } + + DWARFAbbreviationDeclarationSet(dw_offset_t offset, uint32_t idx_offset) : + m_offset(offset), + m_idx_offset(idx_offset), + m_decls() + { + } + + void Clear(); + dw_offset_t GetOffset() const { return m_offset; } + void Dump(lldb_private::Stream *s) const; + bool Extract(const lldb_private::DataExtractor& data, uint32_t* offset_ptr); + //void Encode(BinaryStreamBuf& debug_abbrev_buf) const; + dw_uleb128_t AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl); + + const DWARFAbbreviationDeclaration* GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const; +private: + dw_offset_t m_offset; + uint32_t m_idx_offset; + std::vector<DWARFAbbreviationDeclaration> m_decls; +}; + +typedef std::map<dw_offset_t, DWARFAbbreviationDeclarationSet> DWARFAbbreviationDeclarationCollMap; +typedef DWARFAbbreviationDeclarationCollMap::iterator DWARFAbbreviationDeclarationCollMapIter; +typedef DWARFAbbreviationDeclarationCollMap::const_iterator DWARFAbbreviationDeclarationCollMapConstIter; + + +class DWARFDebugAbbrev +{ +public: + DWARFDebugAbbrev(); + const DWARFAbbreviationDeclarationSet* GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const; + void Dump(lldb_private::Stream *s) const; + void Parse(const lldb_private::DataExtractor& data); +protected: + DWARFAbbreviationDeclarationCollMap m_abbrevCollMap; + mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos; +}; + +#endif // SymbolFileDWARF_DWARFDebugAbbrev_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp new file mode 100644 index 00000000000..57ef6ba4eb4 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -0,0 +1,274 @@ +//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugArangeSet.h" + +#include <assert.h> +#include "lldb/Core/Stream.h" +#include "SymbolFileDWARF.h" + +using namespace lldb_private; + +DWARFDebugArangeSet::DWARFDebugArangeSet() : + m_offset(DW_INVALID_OFFSET), + m_header(), + m_arange_descriptors() +{ + m_header.length = 0; + m_header.version = 0; + m_header.cu_offset = 0; + m_header.addr_size = 0; + m_header.seg_size = 0; +} + +void +DWARFDebugArangeSet::Clear() +{ + m_offset = DW_INVALID_OFFSET; + m_header.length = 0; + m_header.version = 0; + m_header.cu_offset = 0; + m_header.addr_size = 0; + m_header.seg_size = 0; + m_arange_descriptors.clear(); +} + +void +DWARFDebugArangeSet::SetHeader +( + uint16_t version, + uint32_t cu_offset, + uint8_t addr_size, + uint8_t seg_size +) +{ + m_header.version = version; + m_header.cu_offset = cu_offset; + m_header.addr_size = addr_size; + m_header.seg_size = seg_size; +} + +void +DWARFDebugArangeSet::Compact() +{ + if (m_arange_descriptors.empty()) + return; + + // Iterate through all arange descriptors and combine any ranges that + // overlap or have matching boundaries. The m_arange_descriptors are assumed + // to be in ascending order after being built by adding descriptors + // using the AddDescriptor method. + uint32_t i = 0; + while (i + 1 < m_arange_descriptors.size()) + { + if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i+1].address) + { + // The current range ends at or exceeds the start of the next address range. + // Compute the max end address between the two and use that to make the new + // length. + const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i+1].end_address()); + m_arange_descriptors[i].length = max_end_addr - m_arange_descriptors[i].address; + // Now remove the next entry as it was just combined with the previous one. + m_arange_descriptors.erase(m_arange_descriptors.begin()+i+1); + } + else + { + // Discontiguous address range, just proceed to the next one. + ++i; + } + } +} +//---------------------------------------------------------------------- +// Compare function DWARFDebugArangeSet::Descriptor structures +//---------------------------------------------------------------------- +static bool DescriptorLessThan (const DWARFDebugArangeSet::Descriptor& range1, const DWARFDebugArangeSet::Descriptor& range2) +{ + return range1.address < range2.address; +} + +//---------------------------------------------------------------------- +// Add a range descriptor and keep things sorted so we can easily +// compact the ranges before being saved or used. +//---------------------------------------------------------------------- +void +DWARFDebugArangeSet::AddDescriptor(const DWARFDebugArangeSet::Descriptor& range) +{ + if (m_arange_descriptors.empty()) + { + m_arange_descriptors.push_back(range); + return; + } + + DescriptorIter end = m_arange_descriptors.end(); + DescriptorIter pos = lower_bound(m_arange_descriptors.begin(), end, range, DescriptorLessThan); + const dw_addr_t range_end_addr = range.end_address(); + if (pos != end) + { + const dw_addr_t found_end_addr = pos->end_address(); + if (range.address < pos->address) + { + if (range_end_addr < pos->address) + { + // Non-contiguous entries, add this one before the found entry + m_arange_descriptors.insert(pos, range); + } + else if (range_end_addr == pos->address) + { + // The top end of 'range' is the lower end of the entry + // pointed to by 'pos'. We can combine range with the + // entry we found by setting the starting address and + // increasing the length since they don't overlap. + pos->address = range.address; + pos->length += range.length; + } + else + { + // We can combine these two and make sure the largest end + // address is used to make end address. + pos->address = range.address; + pos->length = std::max(found_end_addr, range_end_addr) - pos->address; + } + } + else if (range.address == pos->address) + { + pos->length = std::max(pos->length, range.length); + } + } + else + { + // NOTE: 'pos' points to entry past the end which is ok for insert, + // don't use otherwise!!! + const dw_addr_t max_addr = m_arange_descriptors.back().end_address(); + if (max_addr < range.address) + { + // Non-contiguous entries, add this one before the found entry + m_arange_descriptors.insert(pos, range); + } + else if (max_addr == range.address) + { + m_arange_descriptors.back().length += range.length; + } + else + { + m_arange_descriptors.back().length = std::max(max_addr, range_end_addr) - m_arange_descriptors.back().address; + } + } +} + +bool +DWARFDebugArangeSet::Extract(const DataExtractor &data, uint32_t* offset_ptr) +{ + if (data.ValidOffset(*offset_ptr)) + { + m_arange_descriptors.clear(); + m_offset = *offset_ptr; + + // 7.20 Address Range Table + // + // Each set of entries in the table of address ranges contained in + // the .debug_aranges section begins with a header consisting of: a + // 4-byte length containing the length of the set of entries for this + // compilation unit, not including the length field itself; a 2-byte + // version identifier containing the value 2 for DWARF Version 2; a + // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer + // containing the size in bytes of an address (or the offset portion of + // an address for segmented addressing) on the target system; and a + // 1-byte unsigned integer containing the size in bytes of a segment + // descriptor on the target system. This header is followed by a series + // of tuples. Each tuple consists of an address and a length, each in + // the size appropriate for an address on the target architecture. + m_header.length = data.GetU32(offset_ptr); + m_header.version = data.GetU16(offset_ptr); + m_header.cu_offset = data.GetU32(offset_ptr); + m_header.addr_size = data.GetU8(offset_ptr); + m_header.seg_size = data.GetU8(offset_ptr); + + + // The first tuple following the header in each set begins at an offset + // that is a multiple of the size of a single tuple (that is, twice the + // size of an address). The header is padded, if necessary, to the + // appropriate boundary. + const uint32_t header_size = *offset_ptr - m_offset; + const uint32_t tuple_size = m_header.addr_size << 1; + uint32_t first_tuple_offset = 0; + while (first_tuple_offset < header_size) + first_tuple_offset += tuple_size; + + *offset_ptr = m_offset + first_tuple_offset; + + Descriptor arangeDescriptor; + + assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length)); + assert(sizeof(arangeDescriptor.address) >= m_header.addr_size); + + while (data.ValidOffset(*offset_ptr)) + { + arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size); + arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); + + // Each set of tuples is terminated by a 0 for the address and 0 + // for the length. + if (arangeDescriptor.address || arangeDescriptor.length) + m_arange_descriptors.push_back(arangeDescriptor); + else + break; // We are done if we get a zero address and length + } + + return !m_arange_descriptors.empty(); + } + return false; +} + + +dw_offset_t +DWARFDebugArangeSet::GetOffsetOfNextEntry() const +{ + return m_offset + m_header.length + 4; +} + + +void +DWARFDebugArangeSet::Dump(Stream *s) const +{ + s->Printf("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n", + m_header.length ,m_header.version, m_header.cu_offset, m_header.addr_size, m_header.seg_size); + + const uint32_t hex_width = m_header.addr_size * 2; + DescriptorConstIter pos; + DescriptorConstIter end = m_arange_descriptors.end(); + for (pos = m_arange_descriptors.begin(); pos != end; ++pos) + s->Printf("[0x%*.*llx - 0x%*.*llx)\n", + hex_width, hex_width, pos->address, + hex_width, hex_width, pos->end_address()); +} + + +class DescriptorContainsAddress +{ +public: + DescriptorContainsAddress (dw_addr_t address) : m_address(address) {} + bool operator() (const DWARFDebugArangeSet::Descriptor& desc) const + { + return (m_address >= desc.address) && (m_address < (desc.address + desc.length)); + } + private: + const dw_addr_t m_address; +}; + +dw_offset_t +DWARFDebugArangeSet::FindAddress(dw_addr_t address) const +{ + DescriptorConstIter end = m_arange_descriptors.end(); + DescriptorConstIter pos = std::find_if( m_arange_descriptors.begin(), end, // Range + DescriptorContainsAddress(address));// Predicate + if (pos != end) + return m_header.cu_offset; + + return DW_INVALID_OFFSET; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h new file mode 100644 index 00000000000..fc1e391aeb4 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h @@ -0,0 +1,70 @@ +//===-- DWARFDebugArangeSet.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugArangeSet_h_ +#define SymbolFileDWARF_DWARFDebugArangeSet_h_ + +#include "SymbolFileDWARF.h" +#include <vector> + +class SymbolFileDWARF; + +class DWARFDebugArangeSet +{ +public: + typedef struct HeaderTag + { + uint32_t length; // The total length of the entries for that set, not including the length field itself. + uint16_t version; // The DWARF version number + uint32_t cu_offset; // The offset from the beginning of the .debug_info section of the compilation unit entry referenced by the table. + uint8_t addr_size; // The size in bytes of an address on the target architecture. For segmented addressing, this is the size of the offset portion of the address + uint8_t seg_size; // The size in bytes of a segment descriptor on the target architecture. If the target system uses a flat address space, this value is 0. + } Header; + + typedef struct DescriptorTag + { + dw_addr_t address; + dw_addr_t length; + dw_addr_t end_address() const { return address + length; } + } Descriptor; + + + DWARFDebugArangeSet(); + void Clear(); + void SetOffset(uint32_t offset) { m_offset = offset; } + void SetHeader(uint16_t version, uint32_t cu_offset, uint8_t addr_size, uint8_t seg_size); + void AddDescriptor(const DWARFDebugArangeSet::Descriptor& range); + void Compact(); + bool Extract(const lldb_private::DataExtractor &data, uint32_t* offset_ptr); + void Dump(lldb_private::Stream *s) const; + dw_offset_t GetCompileUnitDIEOffset() const { return m_header.cu_offset; } + dw_offset_t GetOffsetOfNextEntry() const; + dw_offset_t FindAddress(dw_addr_t address) const; + uint32_t NumDescriptors() const { return m_arange_descriptors.size(); } + const Header& GetHeader() const { return m_header; } + const Descriptor* GetDescriptor(uint32_t i) const + { + if (i < m_arange_descriptors.size()) + return &m_arange_descriptors[i]; + return NULL; + } + + +protected: + typedef std::vector<Descriptor> DescriptorColl; + typedef DescriptorColl::iterator DescriptorIter; + typedef DescriptorColl::const_iterator DescriptorConstIter; + + + uint32_t m_offset; + Header m_header; + DescriptorColl m_arange_descriptors; +}; + +#endif // SymbolFileDWARF_DWARFDebugArangeSet_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp new file mode 100644 index 00000000000..a3213e080c3 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -0,0 +1,343 @@ +//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugAranges.h" + +#include <assert.h> + +#include <algorithm> + +#include "lldb/Core/Stream.h" + +#include "SymbolFileDWARF.h" +#include "DWARFDebugInfo.h" +#include "DWARFCompileUnit.h" + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Constructor +//---------------------------------------------------------------------- +DWARFDebugAranges::DWARFDebugAranges() : + m_aranges() +{ +} + + +//---------------------------------------------------------------------- +// Compare function DWARFDebugAranges::Range structures +//---------------------------------------------------------------------- +static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2) +{ +// printf("RangeLessThan -- 0x%8.8x < 0x%8.8x ? %d\n", range1.lo_pc, range1.lo_pc, range1.lo_pc < range2.lo_pc); + return range1.lo_pc < range2.lo_pc; +} + +//---------------------------------------------------------------------- +// CountArangeDescriptors +//---------------------------------------------------------------------- +class CountArangeDescriptors +{ +public: + CountArangeDescriptors (uint32_t& count_ref) : count(count_ref) + { +// printf("constructor CountArangeDescriptors()\n"); + } + void operator() (const DWARFDebugArangeSet& set) + { + count += set.NumDescriptors(); + } + uint32_t& count; +}; + +//---------------------------------------------------------------------- +// AddArangeDescriptors +//---------------------------------------------------------------------- +class AddArangeDescriptors +{ +public: + AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(ranges) {} + void operator() (const DWARFDebugArangeSet& set) + { + const DWARFDebugArangeSet::Descriptor* arange_desc_ptr; + DWARFDebugAranges::Range range; + range.offset = set.GetCompileUnitDIEOffset(); + + for (uint32_t i=0; arange_desc_ptr = set.GetDescriptor(i); ++i) + { + range.lo_pc = arange_desc_ptr->address; + range.hi_pc = arange_desc_ptr->address + arange_desc_ptr->length; + + // Insert each item in increasing address order so binary searching + // can later be done! + DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan); + range_collection.insert(insert_pos, range); + } + } + DWARFDebugAranges::RangeColl& range_collection; +}; + +//---------------------------------------------------------------------- +// PrintRange +//---------------------------------------------------------------------- +static void PrintRange(const DWARFDebugAranges::Range& range) +{ + // Cast the address values in case the address type is compiled as 32 bit + printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (uint64_t)range.lo_pc, (uint64_t)range.hi_pc); +} + +//---------------------------------------------------------------------- +// Extract +//---------------------------------------------------------------------- +bool +DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data) +{ + if (debug_aranges_data.ValidOffset(0)) + { + uint32_t offset = 0; + + typedef std::vector<DWARFDebugArangeSet> SetCollection; + typedef SetCollection::const_iterator SetCollectionIter; + SetCollection sets; + + DWARFDebugArangeSet set; + Range range; + while (set.Extract(debug_aranges_data, &offset)) + sets.push_back(set); + + uint32_t count = 0; + + for_each(sets.begin(), sets.end(), CountArangeDescriptors(count)); + + if (count > 0) + { + m_aranges.reserve(count); + AddArangeDescriptors range_adder(m_aranges); + for_each(sets.begin(), sets.end(), range_adder); + } + + // puts("\n\nDWARFDebugAranges list is:\n"); + // for_each(m_aranges.begin(), m_aranges.end(), PrintRange); + } + return false; +} + +//---------------------------------------------------------------------- +// Generate +//---------------------------------------------------------------------- +bool +DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data) +{ + Clear(); + DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); + if (debug_info) + { + uint32_t cu_idx = 0; + const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); + for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); + if (cu) + cu->DIE()->BuildAddressRangeTable(dwarf2Data, cu, this); + } + } + return !IsEmpty(); +} + + +void +DWARFDebugAranges::Print() const +{ + puts("\n\nDWARFDebugAranges address range list is:\n"); + for_each(m_aranges.begin(), m_aranges.end(), PrintRange); +} + + +void +DWARFDebugAranges::Range::Dump(Stream *s) const +{ + s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc); +} + +//---------------------------------------------------------------------- +// Dump +//---------------------------------------------------------------------- +void +DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s) +{ + const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data(); + if (debug_aranges_data.ValidOffset(0)) + { + uint32_t offset = 0; + + DWARFDebugArangeSet set; + while (set.Extract(debug_aranges_data, &offset)) + set.Dump(s); + } + else + s->PutCString("< EMPTY >\n"); +} + + +//---------------------------------------------------------------------- +// AppendDebugRanges +//---------------------------------------------------------------------- +//void +//DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const +//{ +// if (!m_aranges.empty()) +// { +// RangeCollIterator end = m_aranges.end(); +// RangeCollIterator pos; +// RangeCollIterator lo_pos = end; +// for (pos = m_aranges.begin(); pos != end; ++pos) +// { +// if (lo_pos == end) +// lo_pos = pos; +// +// RangeCollIterator next = pos + 1; +// if (next != end) +// { +// // Check to see if we can combine two consecutive ranges? +// if (pos->hi_pc == next->lo_pc) +// continue; // We can combine them! +// } +// +// if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS) +// { +// debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size); +// debug_ranges.AppendMax64(pos->hi_pc, addr_size); +// } +// else +// { +// assert(lo_pos->lo_pc >= cu_base_addr); +// assert(pos->hi_pc >= cu_base_addr); +// debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size); +// debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size); +// } +// +// // Reset the low part of the next address range +// lo_pos = end; +// } +// } +// // Terminate the .debug_ranges with two zero addresses +// debug_ranges.AppendMax64(0, addr_size); +// debug_ranges.AppendMax64(0, addr_size); +// +//} +// +//---------------------------------------------------------------------- +// ArangeSetContainsAddress +//---------------------------------------------------------------------- +class ArangeSetContainsAddress +{ +public: + ArangeSetContainsAddress (dw_addr_t the_address) : address(the_address), offset(DW_INVALID_OFFSET) {} + bool operator() (const DWARFDebugArangeSet& set) + { + offset = set.FindAddress(address); + return (offset != DW_INVALID_OFFSET); + } + const dw_addr_t address; + dw_offset_t offset; +}; + + +//---------------------------------------------------------------------- +// InsertRange +//---------------------------------------------------------------------- +void +DWARFDebugAranges::InsertRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) +{ + // Insert each item in increasing address order so binary searching + // can later be done! + DWARFDebugAranges::Range range(low_pc, high_pc, offset); + InsertRange(range); +} + +//---------------------------------------------------------------------- +// InsertRange +//---------------------------------------------------------------------- +void +DWARFDebugAranges::InsertRange(const DWARFDebugAranges::Range& range) +{ + // Insert each item in increasing address order so binary searching + // can later be done! + RangeColl::iterator insert_pos = lower_bound(m_aranges.begin(), m_aranges.end(), range, RangeLessThan); + m_aranges.insert(insert_pos, range); +} + + +//---------------------------------------------------------------------- +// FindAddress +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugAranges::FindAddress(dw_addr_t address) const +{ + if ( !m_aranges.empty() ) + { + DWARFDebugAranges::Range range(address); + DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); + DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); + DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan); + + if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc)) + { + // printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); + return pos->offset; + } + else if (pos != begin) + { + --pos; + if ((pos->lo_pc <= address) && (address < pos->hi_pc)) + { + // printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); + return (*pos).offset; + } + } + } + return DW_INVALID_OFFSET; +} + +//---------------------------------------------------------------------- +// AllRangesAreContiguous +//---------------------------------------------------------------------- +bool +DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const +{ + if (m_aranges.empty()) + return false; + + DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); + DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); + DWARFDebugAranges::RangeCollIterator pos; + dw_addr_t next_addr = 0; + + for (pos = begin; pos != end; ++pos) + { + if ((pos != begin) && (pos->lo_pc != next_addr)) + return false; + next_addr = pos->hi_pc; + } + lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid + hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid + return true; +} + +bool +DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const +{ + if (m_aranges.empty()) + return false; + + lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid + hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid + return true; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h new file mode 100644 index 00000000000..f3db949bf26 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -0,0 +1,98 @@ +//===-- DWARFDebugAranges.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugAranges_h_ +#define SymbolFileDWARF_DWARFDebugAranges_h_ + +#include "DWARFDebugArangeSet.h" +#include <list> + +class SymbolFileDWARF; + +class DWARFDebugAranges +{ +public: + struct Range + { + Range( + dw_addr_t _lo_pc = DW_INVALID_ADDRESS, + dw_addr_t _hi_pc = DW_INVALID_ADDRESS, + dw_offset_t _offset = DW_INVALID_OFFSET) : + lo_pc(_lo_pc), + hi_pc(_hi_pc), + offset(_offset) + { + } + + void Clear() + { + lo_pc = hi_pc = DW_INVALID_ADDRESS; + offset = DW_INVALID_OFFSET; + } + + bool ValidRange() const + { + return hi_pc > lo_pc; + } + + bool Contains(const Range& range) const + { + return lo_pc <= range.lo_pc && range.hi_pc <= hi_pc; + } + + void Dump(lldb_private::Stream *s) const; + dw_addr_t lo_pc; // Start of address range + dw_addr_t hi_pc; // End of address range (not including this address) + dw_offset_t offset; // Offset of the compile unit or die + }; + + DWARFDebugAranges(); + + void Clear() { m_aranges.clear(); } + bool AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const; + bool GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const; + bool Extract(const lldb_private::DataExtractor &debug_aranges_data); + bool Generate(SymbolFileDWARF* dwarf2Data); + void InsertRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc); + void InsertRange(const DWARFDebugAranges::Range& range); + const Range* RangeAtIndex(uint32_t idx) const + { + if (idx < m_aranges.size()) + return &m_aranges[idx]; + return NULL; + } + void Print() const; + dw_offset_t FindAddress(dw_addr_t address) const; + bool IsEmpty() const { return m_aranges.empty(); } + void Dump(lldb_private::Stream *s); + uint32_t NumRanges() const + { + return m_aranges.size(); + } + + dw_offset_t OffsetAtIndex(uint32_t idx) const + { + if (idx < m_aranges.size()) + return m_aranges[idx].offset; + return DW_INVALID_OFFSET; + } +// void AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const; + + static void Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s); + + typedef std::vector<Range> RangeColl; + typedef RangeColl::const_iterator RangeCollIterator; + +protected: + + RangeColl m_aranges; +}; + + +#endif // SymbolFileDWARF_DWARFDebugAranges_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp new file mode 100644 index 00000000000..fcb0ccf1189 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -0,0 +1,1206 @@ +//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileDWARF.h" + +#include <algorithm> +#include <set> + +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Stream.h" + +#include "DWARFDebugInfo.h" +#include "DWARFCompileUnit.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFFormValue.h" + +using namespace lldb_private; +using namespace std; + +//---------------------------------------------------------------------- +// Constructor +//---------------------------------------------------------------------- +DWARFDebugInfo::DWARFDebugInfo() : + m_dwarf2Data(NULL), + m_compile_units() +{ +} + +//---------------------------------------------------------------------- +// SetDwarfData +//---------------------------------------------------------------------- +void +DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data) +{ + m_dwarf2Data = dwarf2Data; + m_compile_units.clear(); +} + +//---------------------------------------------------------------------- +// BuildDIEAddressRangeTable +//---------------------------------------------------------------------- +bool +DWARFDebugInfo::BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges) +{ + const uint32_t num_compile_units = GetNumCompileUnits(); + uint32_t idx; + for (idx = 0; idx < num_compile_units; ++idx) + { + DWARFCompileUnit* cu = GetCompileUnitAtIndex (idx); + if (cu) + { + cu->DIE()->BuildFunctionAddressRangeTable(m_dwarf2Data, cu, debug_aranges); + } + } + return !debug_aranges->IsEmpty(); +} + +//---------------------------------------------------------------------- +// LookupAddress +//---------------------------------------------------------------------- +bool +DWARFDebugInfo::LookupAddress +( + const dw_addr_t address, + const dw_offset_t hint_die_offset, + DWARFCompileUnitSP& cu_sp, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die +) +{ + + if (hint_die_offset != DW_INVALID_OFFSET) + cu_sp = GetCompileUnit(hint_die_offset); + else + { + // Get a non const version of the address ranges + DWARFDebugAranges* debug_aranges = ((SymbolFileDWARF*)m_dwarf2Data)->DebugAranges(); + + if (debug_aranges != NULL) + { + // If we have an empty address ranges section, lets build a sorted + // table ourselves by going through all of the debug information so we + // can do quick subsequent searches. + + if (debug_aranges->IsEmpty()) + { + const uint32_t num_compile_units = GetNumCompileUnits(); + uint32_t idx; + for (idx = 0; idx < num_compile_units; ++idx) + { + DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); + if (cu) + cu->DIE()->BuildAddressRangeTable(m_dwarf2Data, cu, debug_aranges); + } + } + cu_sp = GetCompileUnit(debug_aranges->FindAddress(address)); + } + } + + if (cu_sp.get()) + { + if (cu_sp->LookupAddress(address, function_die, block_die)) + return true; + cu_sp.reset(); + } + else + { + // The hint_die_offset may have been a pointer to the actual item that + // we are looking for + DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp); + if (die_ptr) + { + if (cu_sp.get()) + { + if (function_die || block_die) + return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die); + + // We only wanted the compile unit that contained this address + return true; + } + } + } + return false; +} + + +void +DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() +{ + if (m_compile_units.empty()) + { + if (m_dwarf2Data != NULL) + { + uint32_t offset = 0; + const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data(); + while (debug_info_data.ValidOffset(offset)) + { + DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data)); + // Out of memory? + if (cu_sp.get() == NULL) + break; + + if (cu_sp->Extract(debug_info_data, &offset) == false) + break; + + m_compile_units.push_back(cu_sp); + + offset = cu_sp->GetNextCompileUnitOffset(); + } + } + } +} + +uint32_t +DWARFDebugInfo::GetNumCompileUnits() +{ + ParseCompileUnitHeadersIfNeeded(); + return m_compile_units.size(); +} + +DWARFCompileUnit* +DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) +{ + DWARFCompileUnit* cu = NULL; + if (idx < GetNumCompileUnits()) + cu = m_compile_units[idx].get(); + return cu; +} + +static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b) +{ + return a->GetOffset() < b->GetOffset(); +} + + +static int +CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem) +{ + const dw_offset_t key_cu_offset = *(dw_offset_t*) key; + const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset(); + if (key_cu_offset < cu_offset) + return -1; + if (key_cu_offset > cu_offset) + return 1; + return 0; +} + +DWARFCompileUnitSP +DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr) +{ + DWARFCompileUnitSP cu_sp; + uint32_t cu_idx = DW_INVALID_INDEX; + if (cu_offset != DW_INVALID_OFFSET) + { + ParseCompileUnitHeadersIfNeeded(); + + DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset); + if (match) + { + cu_sp = *match; + cu_idx = match - &m_compile_units[0]; + } + } + if (idx_ptr) + *idx_ptr = cu_idx; + return cu_sp; +} + +DWARFCompileUnitSP +DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset) +{ + DWARFCompileUnitSP cu_sp; + if (die_offset != DW_INVALID_OFFSET) + { + ParseCompileUnitHeadersIfNeeded(); + + CompileUnitColl::const_iterator end_pos = m_compile_units.end(); + CompileUnitColl::const_iterator pos; + + for (pos = m_compile_units.begin(); pos != end_pos; ++pos) + { + dw_offset_t cu_start_offset = (*pos)->GetOffset(); + dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset(); + if (cu_start_offset <= die_offset && die_offset < cu_end_offset) + { + cu_sp = *pos; + break; + } + } + } + return cu_sp; +} + +//---------------------------------------------------------------------- +// Compare function DWARFDebugAranges::Range structures +//---------------------------------------------------------------------- +static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2) +{ + return die1.GetOffset() < die2.GetOffset(); +} + + +//---------------------------------------------------------------------- +// GetDIE() +// +// Get the DIE (Debug Information Entry) with the specified offset. +//---------------------------------------------------------------------- +DWARFDebugInfoEntry* +DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr) +{ + DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset)); + if (cu_sp_ptr) + *cu_sp_ptr = cu_sp; + if (cu_sp.get()) + return cu_sp->GetDIEPtr(die_offset); + return NULL; // Not found in any compile units +} + +const DWARFDebugInfoEntry* +DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr) +{ + DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset)); + if (cu_sp_ptr) + *cu_sp_ptr = cu_sp; + if (cu_sp.get()) + return cu_sp->GetDIEPtrContainingOffset(die_offset); + + return NULL; // Not found in any compile units + +} + +//---------------------------------------------------------------------- +// DWARFDebugInfo_ParseCallback +// +// A callback function for the static DWARFDebugInfo::Parse() function +// that gets parses all compile units and DIE's into an internate +// representation for further modification. +//---------------------------------------------------------------------- + +static dw_offset_t +DWARFDebugInfo_ParseCallback +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnitSP& cu_sp, + DWARFDebugInfoEntry* die, + const dw_offset_t next_offset, + const uint32_t curr_depth, + void* userData +) +{ + DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData; + DWARFCompileUnit* cu = cu_sp.get(); + if (die) + { + cu->AddDIE(*die); + } + else if (cu) + { + debug_info->AddCompileUnit(cu_sp); + } + + // Just return the current offset to parse the next CU or DIE entry + return next_offset; +} + +//---------------------------------------------------------------------- +// AddCompileUnit +//---------------------------------------------------------------------- +void +DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu) +{ + m_compile_units.push_back(cu); +} + +/* +void +DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die) +{ + m_die_array.push_back(die); +} +*/ + + + + +//---------------------------------------------------------------------- +// Parse +// +// Parses the .debug_info section and uses the .debug_abbrev section +// and various other sections in the SymbolFileDWARF class and calls the +// supplied callback function each time a compile unit header, or debug +// information entry is successfully parsed. This function can be used +// for different tasks such as parsing the file contents into a +// structured data, dumping, verifying and much more. +//---------------------------------------------------------------------- +void +DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData) +{ + if (dwarf2Data) + { + uint32_t offset = 0; + uint32_t depth = 0; + DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data)); + if (cu.get() == NULL) + return; + DWARFDebugInfoEntry die; + + while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset)) + { + const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); + + depth = 0; + // Call the callback funtion with no DIE pointer for the compile unit + // and get the offset that we are to continue to parse from + offset = callback(dwarf2Data, cu, NULL, offset, depth, userData); + + // Make sure we are within our compile unit + if (offset < next_cu_offset) + { + // We are in our compile unit, parse starting at the offset + // we were told to parse + bool done = false; + while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) + { + // Call the callback funtion with DIE pointer that falls within the compile unit + offset = callback(dwarf2Data, cu, &die, offset, depth, userData); + + if (die.IsNULL()) + { + if (depth) + --depth; + else + done = true; // We are done with this compile unit! + } + else if (die.HasChildren()) + ++depth; + } + } + + // Make sure the offset returned is valid, and if not stop parsing. + // Returning DW_INVALID_OFFSET from this callback is a good way to end + // all parsing + if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) + break; + + // See if during the callback anyone retained a copy of the compile + // unit other than ourselves and if so, let whomever did own the object + // and create a new one for our own use! + if (!cu.unique()) + cu.reset(new DWARFCompileUnit(dwarf2Data)); + + + // Make sure we start on a propper + offset = next_cu_offset; + } + } +} + +/* +typedef struct AddressRangeTag +{ + dw_addr_t lo_pc; + dw_addr_t hi_pc; + dw_offset_t die_offset; +} AddressRange; +*/ +struct DIERange +{ + DIERange() : + range(), + lo_die_offset(), + hi_die_offset() + { + } + + DWARFDebugAranges::Range range; + dw_offset_t lo_die_offset; + dw_offset_t hi_die_offset; +}; + +typedef struct DwarfStat +{ + DwarfStat() : count(0), byte_size(0) {} + uint32_t count; + uint32_t byte_size; +} DwarfStat; + +typedef map<dw_attr_t, DwarfStat> DwarfAttrStatMap; + +typedef struct DIEStat +{ + DIEStat() : count(0), byte_size(0), attr_stats() {} + uint32_t count; + uint32_t byte_size; + DwarfAttrStatMap attr_stats; +} DIEStat; + +typedef map<dw_tag_t, DIEStat> DIEStatMap; +struct VerifyInfo +{ + VerifyInfo(Stream* the_strm) : + strm(the_strm), + die_ranges(), + addr_range_errors(0), + sibling_errors(0), + die_stats() + { + } + + Stream* strm; + vector<DIERange> die_ranges; + uint32_t addr_range_errors; + uint32_t sibling_errors; + DIEStatMap die_stats; + + DISALLOW_COPY_AND_ASSIGN(VerifyInfo); + +}; + + +//---------------------------------------------------------------------- +// VerifyCallback +// +// A callback function for the static DWARFDebugInfo::Parse() function +// that gets called each time a compile unit header or debug information +// entry is successfully parsed. +// +// This function will verify the DWARF information is well formed by +// making sure that any DW_TAG_compile_unit tags that have valid address +// ranges (DW_AT_low_pc and DW_AT_high_pc) have no gaps in the address +// ranges of it contained DW_TAG_subprogram tags. Also the sibling chain +// and relationships are verified to make sure nothing gets hosed up +// when dead stripping occurs. +//---------------------------------------------------------------------- + +static dw_offset_t +VerifyCallback +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnitSP& cu_sp, + DWARFDebugInfoEntry* die, + const dw_offset_t next_offset, + const uint32_t curr_depth, + void* userData +) +{ + VerifyInfo* verifyInfo = (VerifyInfo*)userData; + + const DWARFCompileUnit* cu = cu_sp.get(); + Stream *s = verifyInfo->strm; + bool verbose = s->GetVerbose(); + if (die) + { + // die->Dump(dwarf2Data, cu, f); + const DWARFAbbreviationDeclaration* abbrevDecl = die->GetAbbreviationDeclarationPtr(); + // We have a DIE entry + if (abbrevDecl) + { + const dw_offset_t die_offset = die->GetOffset(); + const dw_offset_t sibling = die->GetAttributeValueAsReference(dwarf2Data, cu, DW_AT_sibling, DW_INVALID_OFFSET); + + if (sibling != DW_INVALID_OFFSET) + { + if (sibling <= next_offset) + { + if (verifyInfo->sibling_errors++ == 0) + s->Printf("ERROR\n"); + s->Printf(" 0x%8.8x: sibling attribyte (0x%8.8x) in this die is not valid: it is less than this DIE or some of its contents.\n", die->GetOffset(), sibling); + } + else if (sibling > verifyInfo->die_ranges.back().hi_die_offset) + { + if (verifyInfo->sibling_errors++ == 0) + s->Printf("ERROR\n"); + s->Printf(" 0x%8.8x: sibling attribute (0x%8.8x) in this DIE is not valid: it is greater than the end of the parent scope.\n", die->GetOffset(), sibling); + } + } + + if ((die_offset < verifyInfo->die_ranges.back().lo_die_offset) || (die_offset >= verifyInfo->die_ranges.back().hi_die_offset)) + { + if (verifyInfo->sibling_errors++ == 0) + s->Printf("ERROR\n"); + s->Printf(" 0x%8.8x: DIE offset is not within the parent DIE range {0x%8.8x}: (0x%8.8x - 0x%8.8x)\n", + die->GetOffset(), + verifyInfo->die_ranges.back().range.offset, + verifyInfo->die_ranges.back().lo_die_offset, + verifyInfo->die_ranges.back().hi_die_offset); + + } + + dw_tag_t tag = abbrevDecl->Tag(); + + // Keep some stats on this DWARF file + verifyInfo->die_stats[tag].count++; + verifyInfo->die_stats[tag].byte_size += (next_offset - die->GetOffset()); + + if (verbose) + { + DIEStat& tag_stat = verifyInfo->die_stats[tag]; + + const DataExtractor& debug_info = dwarf2Data->get_debug_info_data(); + + dw_offset_t offset = die->GetOffset(); + // Skip the abbreviation code so we are at the data for the attributes + debug_info.Skip_LEB128(&offset); + + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + dw_attr_t attr; + dw_form_t form; + for (uint32_t idx = 0; idx < numAttributes; ++idx) + { + dw_offset_t start_offset = offset; + abbrevDecl->GetAttrAndFormByIndexUnchecked(idx, attr, form); + DWARFFormValue::SkipValue(form, debug_info, &offset, cu); + + if (tag_stat.attr_stats.find(attr) == tag_stat.attr_stats.end()) + { + tag_stat.attr_stats[attr].count = 0; + tag_stat.attr_stats[attr].byte_size = 0; + } + + tag_stat.attr_stats[attr].count++; + tag_stat.attr_stats[attr].byte_size += offset - start_offset; + } + } + + DWARFDebugAranges::Range range; + range.offset = die->GetOffset(); + + switch (tag) + { + case DW_TAG_compile_unit: + // Check for previous subroutines that were within a previous + // + // VerifyAddressRangesForCU(verifyInfo); + // Remember which compile unit we are dealing with so we can verify + // the address ranges within it (if any) are contiguous. The DWARF + // spec states that if a compile unit TAG has high and low PC + // attributes, there must be no gaps in the address ranges of it's + // contained subtroutines. If there are gaps, the high and low PC + // must not be in the DW_TAG_compile_unit's attributes. Errors like + // this can crop up when optimized code is dead stripped and the debug + // information isn't properly fixed up for output. + range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS); + if (range.lo_pc != DW_INVALID_ADDRESS) + { + range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS); + if (s->GetVerbose()) + { + s->Printf("\n CU "); + range.Dump(s); + } + } + else + { + range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_entry_pc, DW_INVALID_ADDRESS); + } + break; + + case DW_TAG_subprogram: + // If the DW_TAG_compile_unit that contained this function had a + // valid address range, add all of the valid subroutine address + // ranges to a collection of addresses which will be sorted + // and verified right before the next DW_TAG_compile_unit is + // processed to make sure that there are no gaps in the address + // range. + range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS); + if (range.lo_pc != DW_INVALID_ADDRESS) + { + range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS); + if (range.hi_pc != DW_INVALID_ADDRESS) + { + range.offset = die->GetOffset(); + bool valid = range.ValidRange(); + if (!valid || s->GetVerbose()) + { + s->Printf("\n FUNC "); + range.Dump(s); + if (!valid) + { + ++verifyInfo->addr_range_errors; + s->Printf(" ERROR: Invalid address range for function."); + } + } + + // Only add to our subroutine ranges if our compile unit has a valid address range + // if (valid && verifyInfo->die_ranges.size() >= 2 && verifyInfo->die_ranges[1].range.ValidRange()) + // verifyInfo->subroutine_ranges.InsertRange(range); + } + } + break; + + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + { + range.lo_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, DW_INVALID_ADDRESS); + if (range.lo_pc != DW_INVALID_ADDRESS) + { + range.hi_pc = die->GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_high_pc, DW_INVALID_ADDRESS); + if (range.hi_pc != DW_INVALID_ADDRESS) + { + range.offset = die->GetOffset(); + bool valid = range.ValidRange(); + if (!valid || s->GetVerbose()) + { + s->Printf("\n BLCK "); + range.Dump(s); + if (!valid) + { + ++verifyInfo->addr_range_errors; + s->Printf(" ERROR: Invalid address range for block or inlined subroutine."); + } + } + } + } + } + break; + } + + if (range.ValidRange() && verifyInfo->die_ranges.back().range.ValidRange()) + { + if (!verifyInfo->die_ranges.back().range.Contains(range)) + { + ++verifyInfo->addr_range_errors; + s->Printf("\n "); + range.Dump(s); + s->Printf(" ERROR: Range is not in parent"); + verifyInfo->die_ranges.back().range.Dump(s); + } + } + + if (die->HasChildren()) + { + // Keep tabs on the valid address ranges for the current item to make + // sure that it all fits (make sure the sibling offsets got fixed up + // correctly if any functions were dead stripped). + DIERange die_range; + die_range.range = range; + die_range.lo_die_offset = next_offset; + die_range.hi_die_offset = sibling; + if (die_range.hi_die_offset == DW_INVALID_OFFSET) + die_range.hi_die_offset = verifyInfo->die_ranges.back().hi_die_offset; + verifyInfo->die_ranges.push_back(die_range); + } + } + else + { + // NULL entry + verifyInfo->die_ranges.pop_back(); + } + } + else + { + // cu->Dump(ostrm_ptr); // Dump the compile unit for the DIE + // We have a new comile unit header + verifyInfo->die_ranges.clear(); + DIERange die_range; + die_range.range.offset = cu->GetOffset(); + die_range.lo_die_offset = next_offset; + die_range.hi_die_offset = cu->GetNextCompileUnitOffset(); + verifyInfo->die_ranges.push_back(die_range); + } + + // Just return the current offset to parse the next CU or DIE entry + return next_offset; +} + + +class CompareDIEStatSizes +{ +public: + bool operator() (const DIEStatMap::const_iterator& pos1, const DIEStatMap::const_iterator& pos2) const + { + return pos1->second.byte_size <= pos2->second.byte_size; + } +}; + +class CompareAttrDIEStatSizes +{ +public: + bool operator() (const DwarfAttrStatMap::const_iterator& pos1, const DwarfAttrStatMap::const_iterator& pos2) const + { + return pos1->second.byte_size <= pos2->second.byte_size; + } +}; + +//---------------------------------------------------------------------- +// Verify +// +// Verifies the DWARF information is valid. +//---------------------------------------------------------------------- +void +DWARFDebugInfo::Verify(Stream *s, SymbolFileDWARF* dwarf2Data) +{ + s->Printf("Verifying Compile Unit Header chain....."); + VerifyInfo verifyInfo(s); + verifyInfo.addr_range_errors = 0; + verifyInfo.sibling_errors = 0; + + bool verbose = s->GetVerbose(); + + uint32_t offset = 0; + if (verbose) + s->EOL(); +// vector<dw_offset_t> valid_cu_offsets; + DWARFCompileUnit cu (dwarf2Data); + bool success = true; + while ( success && dwarf2Data->get_debug_info_data().ValidOffset(offset+cu.Size()) ) + { + success = cu.Extract (dwarf2Data->get_debug_info_data(), &offset); + if (!success) + s->Printf("ERROR\n"); + // else + // valid_cu_offsets.push_back(cu.GetOffset()); + + cu.Verify(verifyInfo.strm); + offset = cu.GetNextCompileUnitOffset(); + } + + if (success) + s->Printf("OK\n"); + + s->Printf("Verifying address ranges and siblings..."); + if (verbose) + s->EOL(); + DWARFDebugInfo::Parse(dwarf2Data, VerifyCallback, &verifyInfo); + +// VerifyAddressRangesForCU(&verifyInfo); + + if (verifyInfo.addr_range_errors > 0) + s->Printf("\nERRORS - %u error(s) were found.\n", verifyInfo.addr_range_errors); + else + s->Printf("OK\n"); + + uint32_t total_category_sizes[kNumTagCategories] = {0}; + uint32_t total_category_count[kNumTagCategories] = {0}; + uint32_t total_die_count = 0; + uint32_t total_die_size = 0; + + typedef set<DIEStatMap::const_iterator, CompareDIEStatSizes> DIEStatBySizeMap; + + s->PutCString( "\n" + "DWARF Statistics\n" + "Count Size Size % Tag\n" + "-------- -------- -------- -------------------------------------------\n"); + DIEStatBySizeMap statBySizeMap; + DIEStatMap::const_iterator pos; + DIEStatMap::const_iterator end_pos = verifyInfo.die_stats.end(); + for (pos = verifyInfo.die_stats.begin(); pos != end_pos; ++pos) + { + const uint32_t die_count = pos->second.count; + const uint32_t die_size = pos->second.byte_size; + + statBySizeMap.insert(pos); + total_die_count += die_count; + total_die_size += die_size; + DW_TAG_CategoryEnum category = get_tag_category(pos->first); + total_category_sizes[category] += die_size; + total_category_count[category] += die_count; + } + + float total_die_size_float = total_die_size; + + DIEStatBySizeMap::const_reverse_iterator size_pos; + DIEStatBySizeMap::const_reverse_iterator size_pos_end = statBySizeMap.rend(); + float percentage; + for (size_pos = statBySizeMap.rbegin(); size_pos != size_pos_end; ++size_pos) + { + pos = *size_pos; + + const DIEStat& tag_stat = pos->second; + + const uint32_t die_count = tag_stat.count; + const uint32_t die_size = tag_stat.byte_size; + percentage = ((float)die_size/total_die_size_float)*100.0; + s->Printf("%7u %8u %2.2f%% %s\n", die_count, die_size, percentage, DW_TAG_value_to_name(pos->first)); + + const DwarfAttrStatMap& attr_stats = tag_stat.attr_stats; + if (!attr_stats.empty()) + { + typedef set<DwarfAttrStatMap::const_iterator, CompareAttrDIEStatSizes> DwarfAttrStatBySizeMap; + DwarfAttrStatBySizeMap attrStatBySizeMap; + DwarfAttrStatMap::const_iterator attr_stat_pos; + DwarfAttrStatMap::const_iterator attr_stat_pos_end = attr_stats.end(); + for (attr_stat_pos = attr_stats.begin(); attr_stat_pos != attr_stat_pos_end; ++attr_stat_pos) + { + attrStatBySizeMap.insert(attr_stat_pos); + } + + DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos; + DwarfAttrStatBySizeMap::const_reverse_iterator attr_size_pos_end = attrStatBySizeMap.rend(); + for (attr_size_pos = attrStatBySizeMap.rbegin(); attr_size_pos != attr_size_pos_end; ++attr_size_pos) + { + attr_stat_pos = *attr_size_pos; + percentage = ((float)attr_stat_pos->second.byte_size/die_size)*100.0; + s->Printf("%7u %8u %2.2f%% %s\n", attr_stat_pos->second.count, attr_stat_pos->second.byte_size, percentage, DW_AT_value_to_name(attr_stat_pos->first)); + } + s->EOL(); + } + } + + s->Printf("-------- -------- -------- -------------------------------------------\n"); + s->Printf("%7u %8u 100.00% Total for all DIEs\n", total_die_count, total_die_size); + + float total_category_percentages[kNumTagCategories] = + { + ((float)total_category_sizes[TagCategoryVariable]/total_die_size_float)*100.0, + ((float)total_category_sizes[TagCategoryType]/total_die_size_float)*100.0, + ((float)total_category_sizes[TagCategoryProgram]/total_die_size_float)*100.0 + }; + + s->EOL(); + s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryVariable], total_category_sizes[TagCategoryVariable], total_category_percentages[TagCategoryVariable], "Total for variable related DIEs"); + s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryType], total_category_sizes[TagCategoryType], total_category_percentages[TagCategoryType], "Total for type related DIEs"); + s->Printf("%7u %8u %2.2f%% %s\n", total_category_count[TagCategoryProgram], total_category_sizes[TagCategoryProgram], total_category_percentages[TagCategoryProgram], "Total for program related DIEs"); + s->Printf("\n\n"); +} + +typedef struct DumpInfo +{ + DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) : + strm(init_strm), + die_offset(off), + recurse_depth(depth), + found_depth(UINT_MAX), + found_die(false), + ancestors() + { + } + Stream* strm; + const uint32_t die_offset; + const uint32_t recurse_depth; + uint32_t found_depth; + bool found_die; + std::vector<DWARFDebugInfoEntry> ancestors; + + DISALLOW_COPY_AND_ASSIGN(DumpInfo); +} DumpInfo; + +//---------------------------------------------------------------------- +// DumpCallback +// +// A callback function for the static DWARFDebugInfo::Parse() function +// that gets called each time a compile unit header or debug information +// entry is successfully parsed. +// +// This function dump DWARF information and obey recurse depth and +// wether a single DIE is to be dumped (or all of the data). +//---------------------------------------------------------------------- +static dw_offset_t DumpCallback +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnitSP& cu_sp, + DWARFDebugInfoEntry* die, + const dw_offset_t next_offset, + const uint32_t curr_depth, + void* userData +) +{ + DumpInfo* dumpInfo = (DumpInfo*)userData; + + const DWARFCompileUnit* cu = cu_sp.get(); + + Stream *s = dumpInfo->strm; + bool show_parents = s->GetFlags().IsSet(DWARFDebugInfo::eDumpFlag_ShowAncestors); + + if (die) + { + // Are we dumping everything? + if (dumpInfo->die_offset == DW_INVALID_OFFSET) + { + // Yes we are dumping everything. Obey our recurse level though + if (curr_depth < dumpInfo->recurse_depth) + die->Dump(dwarf2Data, cu, s, 0); + } + else + { + // We are dumping a specific DIE entry by offset + if (dumpInfo->die_offset == die->GetOffset()) + { + // We found the DIE we were looking for, dump it! + if (show_parents) + { + s->SetIndentLevel(0); + const uint32_t num_ancestors = dumpInfo->ancestors.size(); + if (num_ancestors > 0) + { + for (uint32_t i=0; i<num_ancestors-1; ++i) + { + dumpInfo->ancestors[i].Dump(dwarf2Data, cu, s, 0); + s->IndentMore(); + } + } + } + + dumpInfo->found_depth = curr_depth; + + die->Dump(dwarf2Data, cu, s, 0); + + // Note that we found the DIE we were looking for + dumpInfo->found_die = true; + + // Since we are dumping a single DIE, if there are no children we are done! + if (!die->HasChildren() || dumpInfo->recurse_depth == 0) + return DW_INVALID_OFFSET; // Return an invalid address to end parsing + } + else if (dumpInfo->found_die) + { + // Are we done with all the children? + if (curr_depth <= dumpInfo->found_depth) + return DW_INVALID_OFFSET; + + // We have already found our DIE and are printing it's children. Obey + // our recurse depth and return an invalid offset if we get done + // dumping all the the children + if (dumpInfo->recurse_depth == UINT_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) + die->Dump(dwarf2Data, cu, s, 0); + } + else if (dumpInfo->die_offset > die->GetOffset()) + { + if (show_parents) + dumpInfo->ancestors.back() = *die; + } + } + + // Keep up with our indent level + if (die->IsNULL()) + { + if (show_parents) + dumpInfo->ancestors.pop_back(); + + if (curr_depth <= 1) + return cu->GetNextCompileUnitOffset(); + else + s->IndentLess(); + } + else if (die->HasChildren()) + { + if (show_parents) + { + DWARFDebugInfoEntry null_die; + dumpInfo->ancestors.push_back(null_die); + } + s->IndentMore(); + } + } + else + { + if (cu == NULL) + s->PutCString("NULL - cu"); + // We have a compile unit, reset our indent level to zero just in case + s->SetIndentLevel(0); + + // See if we are dumping everything? + if (dumpInfo->die_offset == DW_INVALID_OFFSET) + { + // We are dumping everything + cu->Dump(s); + return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit + } + else + { + if (show_parents) + { + dumpInfo->ancestors.clear(); + dumpInfo->ancestors.resize(1); + } + + // We are dumping only a single DIE possibly with it's children and + // we must find it's compile unit before we can dump it properly + if (dumpInfo->die_offset < cu->GetFirstDIEOffset()) + { + // Not found, maybe the DIE offset provided wasn't correct? + // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl; + return DW_INVALID_OFFSET; + } + else + { + // See if the DIE is in this compile unit? + if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) + { + // This DIE is in this compile unit! + if (s->GetVerbose()) + cu->Dump(s); // Dump the compile unit for the DIE in verbose mode + + return next_offset; + // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE... + // return dumpInfo->die_offset; + } + else + { + // Skip to the next compile unit as the DIE isn't in the current one! + return cu->GetNextCompileUnitOffset(); + } + } + } + } + + // Just return the current offset to parse the next CU or DIE entry + return next_offset; +} + +//---------------------------------------------------------------------- +// Dump +// +// Dump the information in the .debug_info section to the specified +// ostream. If die_offset is valid, a single DIE will be dumped. If the +// die_offset is invalid, all the DWARF information will be dumped. Both +// cases will obey a "recurse_depth" or how deep to traverse into the +// children of each DIE entry. A recurse_depth of zero will dump all +// compile unit headers. A recurse_depth of 1 will dump all compile unit +// headers and the DW_TAG_compile unit tags. A depth of 2 will also +// dump all types and functions. +//---------------------------------------------------------------------- +void +DWARFDebugInfo::Dump +( + Stream *s, + SymbolFileDWARF* dwarf2Data, + const uint32_t die_offset, + const uint32_t recurse_depth +) +{ + DumpInfo dumpInfo(s, die_offset, recurse_depth); + s->PutCString(".debug_info contents"); + if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) + { + if (die_offset == DW_INVALID_OFFSET) + s->PutCString(":\n"); + else + { + s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); + if (recurse_depth != UINT_MAX) + s->Printf(" recursing %u levels deep.", recurse_depth); + s->EOL(); + } + } + else + { + s->PutCString(": < EMPTY >\n"); + return; + } + DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); +} + + +//---------------------------------------------------------------------- +// Dump +// +// Dump the contents of this DWARFDebugInfo object as has been parsed +// and/or modified after it has been parsed. +//---------------------------------------------------------------------- +void +DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth) +{ + DumpInfo dumpInfo(s, die_offset, recurse_depth); + + s->PutCString("Dumping .debug_info section from internal representation\n"); + + CompileUnitColl::const_iterator pos; + uint32_t curr_depth = 0; + ParseCompileUnitHeadersIfNeeded(); + for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) + { + const DWARFCompileUnitSP& cu_sp = *pos; + DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo); + cu_sp->DIE()->Dump(m_dwarf2Data, cu_sp.get(), s, recurse_depth); + } +} + + +//---------------------------------------------------------------------- +// FindCallbackString +// +// A callback function for the static DWARFDebugInfo::Parse() function +// that gets called each time a compile unit header or debug information +// entry is successfully parsed. +// +// This function will find the die_offset of any items whose DW_AT_name +// matches the given string +//---------------------------------------------------------------------- +typedef struct FindCallbackStringInfoTag +{ + const char* name; + bool ignore_case; + RegularExpression* regex; + vector<dw_offset_t>& die_offsets; +} FindCallbackStringInfo; + +static dw_offset_t FindCallbackString +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnitSP& cu_sp, + DWARFDebugInfoEntry* die, + const dw_offset_t next_offset, + const uint32_t curr_depth, + void* userData +) +{ + FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData; + const DWARFCompileUnit* cu = cu_sp.get(); + + if (die) + { + const char* die_name = die->GetName(dwarf2Data, cu); + if (die_name) + { + if (info->regex) + { + if (info->regex->Execute(die_name)) + info->die_offsets.push_back(die->GetOffset()); + } + else + { + if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0) + info->die_offsets.push_back(die->GetOffset()); + } + } + } + + // Just return the current offset to parse the next CU or DIE entry + return next_offset; +} + +//---------------------------------------------------------------------- +// Find +// +// Finds all DIE that have a specific DW_AT_name attribute by manually +// searching through the debug information (not using the +// .debug_pubnames section). The string must match the entire name +// and case sensitive searches are an option. +//---------------------------------------------------------------------- +bool +DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const +{ + die_offsets.clear(); + if (name && name[0]) + { + FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets }; + DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); + } + return !die_offsets.empty(); +} + +//---------------------------------------------------------------------- +// Find +// +// Finds all DIE that have a specific DW_AT_name attribute by manually +// searching through the debug information (not using the +// .debug_pubnames section). The string must match the supplied regular +// expression. +//---------------------------------------------------------------------- +bool +DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const +{ + die_offsets.clear(); + FindCallbackStringInfo info = { NULL, false, &re, die_offsets }; + DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info); + return !die_offsets.empty(); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h new file mode 100644 index 00000000000..f506a3de6e0 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -0,0 +1,86 @@ +//===-- DWARFDebugInfo.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugInfo_h_ +#define SymbolFileDWARF_DWARFDebugInfo_h_ + +#include <vector> +#include <map> + +#include "lldb/lldb-private.h" +#include "lldb/lldb-private.h" +#include "SymbolFileDWARF.h" + +typedef std::multimap<const char*, dw_offset_t, CStringCompareFunctionObject> CStringToDIEMap; +typedef CStringToDIEMap::iterator CStringToDIEMapIter; +typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter; + +typedef lldb::SharedPtr<DWARFCompileUnit>::Type DWARFCompileUnitSP; + +class DWARFDebugInfo +{ +public: + typedef dw_offset_t (*Callback)( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnitSP& cu_shared_ptr, + DWARFDebugInfoEntry* die, + const dw_offset_t next_offset, + const uint32_t depth, + void* userData); + + DWARFDebugInfo(); + void SetDwarfData(SymbolFileDWARF* dwarf2Data); + bool BuildFunctionAddressRangeTable(DWARFDebugAranges* debug_aranges); + + bool LookupAddress( + const dw_addr_t address, + const dw_offset_t cu_offset, // Can be valid (find in .debug_aranges), or DW_INVALID_OFFSET if we need to search manually + DWARFCompileUnitSP& cu_shared_ptr, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die); + + void AddCompileUnit(DWARFCompileUnitSP& cu); + uint32_t GetNumCompileUnits(); + DWARFCompileUnit* GetCompileUnitAtIndex(uint32_t idx); + DWARFCompileUnitSP GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr = NULL); + DWARFCompileUnitSP GetCompileUnitContainingDIE(dw_offset_t die_offset); + + DWARFDebugInfoEntry* GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr); + const DWARFDebugInfoEntry* GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr); + + void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth); + static void Parse(SymbolFileDWARF* parser, Callback callback, void* userData); + static void Verify(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data); + static void Dump(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data, const uint32_t die_offset, const uint32_t recurse_depth); + bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const; + bool Find(lldb_private::RegularExpression& re, std::vector<dw_offset_t>& die_offsets) const; + + enum + { + eDumpFlag_Verbose = (1<<0), // Verbose dumping + eDumpFlag_ShowForm = (1<<1), // Show the DW_form type + eDumpFlag_EnglishyNames = (1<<2), // Show the DW_TAG, DW_AT and DW_FORM types in more englishy names instead of as DWARF definitions values + eDumpFlag_ShowAncestors = (1<<3) // Show all parent DIEs when dumping single DIEs + }; + + +protected: + SymbolFileDWARF* m_dwarf2Data; + typedef std::vector<DWARFCompileUnitSP> CompileUnitColl; + + CompileUnitColl m_compile_units; + +private: + // All parsing needs to be done partially any managed by this class as accessors are called. + void ParseCompileUnitHeadersIfNeeded(); + + DISALLOW_COPY_AND_ASSIGN (DWARFDebugInfo); +}; + +#endif // SymbolFileDWARF_DWARFDebugInfo_h_ 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(); +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h new file mode 100644 index 00000000000..8340acc427e --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -0,0 +1,320 @@ +//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugInfoEntry_h_ +#define liblldb_DWARFDebugInfoEntry_h_ + +#include "SymbolFileDWARF.h" +#include "DWARFAbbreviationDeclaration.h" +#include "DWARFDebugRanges.h" +#include <vector> +#include <map> +#include <set> + +typedef std::map<const DWARFDebugInfoEntry*, dw_addr_t> DIEToAddressMap; +typedef DIEToAddressMap::iterator DIEToAddressMapIter; +typedef DIEToAddressMap::const_iterator DIEToAddressMapConstIter; + +typedef std::map<dw_addr_t, const DWARFDebugInfoEntry*> AddressToDIEMap; +typedef AddressToDIEMap::iterator AddressToDIEMapIter; +typedef AddressToDIEMap::const_iterator AddressToDIEMapConstIter; + + +typedef std::map<dw_offset_t, dw_offset_t> DIEToDIEMap; +typedef DIEToDIEMap::iterator DIEToDIEMapIter; +typedef DIEToDIEMap::const_iterator DIEToDIEMapConstIter; + +typedef std::map<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMap; +typedef UInt32ToDIEMap::iterator UInt32ToDIEMapIter; +typedef UInt32ToDIEMap::const_iterator UInt32ToDIEMapConstIter; + +typedef std::multimap<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMMap; +typedef UInt32ToDIEMMap::iterator UInt32ToDIEMMapIter; +typedef UInt32ToDIEMMap::const_iterator UInt32ToDIEMMapConstIter; + +class DWARFDebugInfoEntry +{ +public: + typedef std::vector<DWARFDebugInfoEntry> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + typedef std::vector<dw_offset_t> offset_collection; + typedef offset_collection::iterator offset_collection_iterator; + typedef offset_collection::const_iterator offset_collection_const_iterator; + + class Attributes + { + public: + Attributes(); + ~Attributes(); + + void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form); + const DWARFCompileUnit * CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; } + dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; } + dw_attr_t AttributeAtIndex(uint32_t i) const { return m_infos[i].attr; } + dw_attr_t FormAtIndex(uint32_t i) const { return m_infos[i].form; } + bool ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const; + uint64_t FormValueAsUnsignedAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const; + uint32_t FindAttributeIndex(dw_attr_t attr) const; + bool ContainsAttribute(dw_attr_t attr) const; + bool RemoveAttribute(dw_attr_t attr); + void Clear() { m_infos.clear(); } + uint32_t Size() const { return m_infos.size(); } + + protected: + struct Info + { + const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in case we have DW_FORM_ref_addr values + dw_offset_t die_offset; + dw_attr_t attr; + dw_form_t form; + }; + std::vector<Info> m_infos; + }; + + struct CompareState + { + CompareState() : + die_offset_pairs() + { + assert(sizeof(dw_offset_t)*2 == sizeof(uint64_t)); + } + + bool AddTypePair(dw_offset_t a, dw_offset_t b) + { + uint64_t a_b_offsets = (uint64_t)a << 32 | (uint64_t)b; + // Return true if this type was inserted, false otherwise + return die_offset_pairs.insert(a_b_offsets).second; + } + std::set< uint64_t > die_offset_pairs; + }; + + DWARFDebugInfoEntry(): + m_offset (DW_INVALID_OFFSET), + m_parent_idx (0), + m_sibling_idx (0), + m_abbrevDecl (NULL), + m_user_data (NULL) + { + } + + + void BuildAddressRangeTable( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges) const; + + void BuildFunctionAddressRangeTable( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges) const; + + bool Extract( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_offset_t* offset_ptr); + + bool LookupAddress( + const dw_addr_t address, + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die); + + size_t GetAttributes( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugInfoEntry::Attributes& attrs) const; + + dw_offset_t GetAttributeValue( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DWARFFormValue& formValue, + dw_offset_t* end_attr_offset_ptr = NULL) const; + + const char* GetAttributeValueAsString( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + const char* fail_value) const; + + uint64_t GetAttributeValueAsUnsigned( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value) const; + + uint64_t GetAttributeValueAsReference( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value) const; + + int64_t GetAttributeValueAsSigned( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + int64_t fail_value) const; + + dw_offset_t GetAttributeValueAsLocation( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + lldb_private::DataExtractor& data, + uint32_t &block_size) const; + + const char* GetName( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu) const; + + const char* GetMangledName( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + bool substitute_name_allowed = true) const; + + const char* GetPubname( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu) const; + + static bool GetName( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + lldb_private::Stream *s); + + static bool AppendTypeName( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + lldb_private::Stream *s); + + static int Compare( + SymbolFileDWARF* dwarf2Data, + dw_offset_t a_die_offset, + dw_offset_t b_die_offset, + CompareState &compare_state, + bool compare_siblings, + bool compare_children); + + static int 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); + + static bool OffsetLessThan ( + const DWARFDebugInfoEntry& a, + const DWARFDebugInfoEntry& b); + + bool AppendDependentDIES( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const bool add_children, + DWARFDIECollection& die_offsets) const; + + void Dump( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + lldb_private::Stream *s, + uint32_t recurse_depth) const; + + void DumpAncestry( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const DWARFDebugInfoEntry* oldest, + lldb_private::Stream *s, + uint32_t recurse_depth) const; + + static void DumpAttribute( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const lldb_private::DataExtractor& debug_info_data, + uint32_t* offset_ptr, + lldb_private::Stream *s, + dw_attr_t attr, + dw_form_t form); + + bool GetDIENamesAndRanges( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const char * &name, + const char * &mangled, + DWARFDebugRanges::RangeList& rangeList, + int& decl_file, + int& decl_line, + int& decl_column, + int& call_file, + int& call_line, + int& call_column, + lldb_private::DWARFExpression *frame_base = NULL) const; + + + dw_tag_t Tag() const { return m_abbrevDecl ? m_abbrevDecl->Tag() : 0; } + bool IsNULL() const { return m_abbrevDecl == NULL; } + dw_offset_t GetOffset() const { return m_offset; } + void SetOffset(dw_offset_t offset) { m_offset = offset; } + uint32_t NumAttributes() const { return m_abbrevDecl ? m_abbrevDecl->NumAttributes() : 0; } + bool HasChildren() const { return m_abbrevDecl != NULL && m_abbrevDecl->HasChildren(); } + + // We know we are kept in a vector of contiguous entries, so we know + // our parent will be some index behind "this". + DWARFDebugInfoEntry* GetParent() { return m_parent_idx > 0 ? this - m_parent_idx : NULL; } + const DWARFDebugInfoEntry* GetParent() const { return m_parent_idx > 0 ? this - m_parent_idx : NULL; } + // We know we are kept in a vector of contiguous entries, so we know + // our sibling will be some index after "this". + DWARFDebugInfoEntry* GetSibling() { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; } + const DWARFDebugInfoEntry* GetSibling() const { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; } + // We know we are kept in a vector of contiguous entries, so we know + // we don't need to store our child pointer, if we have a child it will + // be the next entry in the list... + DWARFDebugInfoEntry* GetFirstChild() { return HasChildren() ? this + 1 : NULL; } + const DWARFDebugInfoEntry* GetFirstChild() const { return HasChildren() ? this + 1 : NULL; } + + void + SetParent (DWARFDebugInfoEntry* parent) + { + if (parent) + { + // We know we are kept in a vector of contiguous entries, so we know + // our parent will be some index behind "this". + m_parent_idx = this - parent; + } + else + m_parent_idx = 0; + } + void + SetSibling (DWARFDebugInfoEntry* sibling) + { + if (sibling) + { + // We know we are kept in a vector of contiguous entries, so we know + // our sibling will be some index after "this". + m_sibling_idx = sibling - this; + sibling->SetParent(GetParent()); + } + else + m_sibling_idx = 0; + } + const DWARFAbbreviationDeclaration* GetAbbreviationDeclarationPtr() const { return m_abbrevDecl; } + + void * GetUserData() const { return m_user_data; } + void SetUserData(void *d) const { m_user_data = d; } +protected: + dw_offset_t m_offset; // Offset within the .debug_info of the start of this entry + uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. If zero this die has no parent + uint32_t m_sibling_idx; // How many to add to "this" to get the sibling. + const DWARFAbbreviationDeclaration* m_abbrevDecl; + mutable void * m_user_data; // Flags for use by the parsers +}; + +#endif // liblldb_DWARFDebugInfoEntry_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp new file mode 100644 index 00000000000..2b3f39b24f3 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -0,0 +1,1410 @@ +//===-- DWARFDebugLine.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugLine.h" + +//#define ENABLE_DEBUG_PRINTF // DO NOT LEAVE THIS DEFINED: DEBUG ONLY!!! +#include <assert.h> + +#include "lldb/Core/FileSpecList.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Timer.h" + +#include "SymbolFileDWARF.h" +#include "LogChannelDWARF.h" + +using namespace lldb_private; +using namespace std; + +//---------------------------------------------------------------------- +// Parse +// +// Parse all information in the debug_line_data into an internal +// representation. +//---------------------------------------------------------------------- +void +DWARFDebugLine::Parse(const DataExtractor& debug_line_data) +{ + m_lineTableMap.clear(); + dw_offset_t offset = 0; + LineTable::shared_ptr line_table_sp(new LineTable); + while (debug_line_data.ValidOffset(offset)) + { + const uint32_t debug_line_offset = offset; + + if (line_table_sp.get() == NULL) + break; + + if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get())) + { + // Make sure we don't don't loop infinitely + if (offset <= debug_line_offset) + break; + //DEBUG_PRINTF("m_lineTableMap[0x%8.8x] = line_table_sp\n", debug_line_offset); + m_lineTableMap[debug_line_offset] = line_table_sp; + line_table_sp.reset(new LineTable); + } + else + ++offset; // Try next byte in line table + } +} + +void +DWARFDebugLine::ParseIfNeeded(const DataExtractor& debug_line_data) +{ + if (m_lineTableMap.empty()) + Parse(debug_line_data); +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::GetLineTable +//---------------------------------------------------------------------- +DWARFDebugLine::LineTable::shared_ptr +DWARFDebugLine::GetLineTable(const dw_offset_t offset) const +{ + DWARFDebugLine::LineTable::shared_ptr line_table_shared_ptr; + LineTableConstIter pos = m_lineTableMap.find(offset); + if (pos != m_lineTableMap.end()) + line_table_shared_ptr = pos->second; + return line_table_shared_ptr; +} + + +//---------------------------------------------------------------------- +// DumpStateToFile +//---------------------------------------------------------------------- +static void +DumpStateToFile (dw_offset_t offset, const DWARFDebugLine::State& state, void* userData) +{ + Log *log = (Log *)userData; + if (state.row == DWARFDebugLine::State::StartParsingLineTable) + { + // If the row is zero we are being called with the prologue only + state.prologue->Dump (log); + log->PutCString ("Address Line Column File"); + log->PutCString ("------------------ ------ ------ ------"); + } + else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) + { + // Done parsing line table + } + else + { + log->Printf( "0x%16.16llx %6u %6u %6u%s\n", state.address, state.line, state.column, state.file, state.end_sequence ? " END" : ""); + } +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::DumpLineTableRows +//---------------------------------------------------------------------- +bool +DWARFDebugLine::DumpLineTableRows(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset) +{ + const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data(); + + if (debug_line_offset == DW_INVALID_OFFSET) + { + // Dump line table to a single file only + debug_line_offset = 0; + while (debug_line_data.ValidOffset(debug_line_offset)) + debug_line_offset = DumpStatementTable (log, debug_line_data, debug_line_offset); + } + else + { + // Dump line table to a single file only + DumpStatementTable (log, debug_line_data, debug_line_offset); + } + return false; +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::DumpStatementTable +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugLine::DumpStatementTable(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset) +{ + if (debug_line_data.ValidOffset(debug_line_offset)) + { + uint32_t offset = debug_line_offset; + log->Printf( "----------------------------------------------------------------------\n" + "debug_line[0x%8.8x]\n" + "----------------------------------------------------------------------\n", debug_line_offset); + + if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log)) + return offset; + else + return debug_line_offset + 1; // Skip to next byte in .debug_line section + } + + return DW_INVALID_OFFSET; +} + + +//---------------------------------------------------------------------- +// DumpOpcodes +//---------------------------------------------------------------------- +bool +DWARFDebugLine::DumpOpcodes(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset, uint32_t dump_flags) +{ + const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data(); + + if (debug_line_data.GetByteSize() == 0) + { + log->Printf( "< EMPTY >\n"); + return false; + } + + if (debug_line_offset == DW_INVALID_OFFSET) + { + // Dump line table to a single file only + debug_line_offset = 0; + while (debug_line_data.ValidOffset(debug_line_offset)) + debug_line_offset = DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags); + } + else + { + // Dump line table to a single file only + DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags); + } + return false; +} + +//---------------------------------------------------------------------- +// DumpStatementOpcodes +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugLine::DumpStatementOpcodes(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset, uint32_t flags) +{ + uint32_t offset = debug_line_offset; + if (debug_line_data.ValidOffset(offset)) + { + Prologue prologue; + + if (ParsePrologue(debug_line_data, &offset, &prologue)) + { + log->PutCString ("----------------------------------------------------------------------"); + log->Printf ("debug_line[0x%8.8x]", debug_line_offset); + log->PutCString ("----------------------------------------------------------------------\n"); + prologue.Dump (log); + } + else + { + offset = debug_line_offset; + log->Printf( "0x%8.8x: skipping pad byte %2.2x", offset, debug_line_data.GetU8(&offset)); + return offset; + } + + Row row(prologue.default_is_stmt); + const dw_offset_t end_offset = debug_line_offset + prologue.total_length + sizeof(prologue.total_length); + + assert(debug_line_data.ValidOffset(end_offset-1)); + + while (offset < end_offset) + { + const uint32_t op_offset = offset; + uint8_t opcode = debug_line_data.GetU8(&offset); + switch (opcode) + { + case 0: // Extended Opcodes always start with a zero opcode followed by + { // a uleb128 length so you can skip ones you don't know about + + dw_offset_t ext_offset = offset; + dw_uleb128_t len = debug_line_data.GetULEB128(&offset); + dw_offset_t arg_size = len - (offset - ext_offset); + uint8_t sub_opcode = debug_line_data.GetU8(&offset); +// if (verbose) +// log->Printf( "Extended: <%u> %2.2x ", len, sub_opcode); + + switch (sub_opcode) + { + case DW_LNE_end_sequence : + log->Printf( "0x%8.8x: DW_LNE_end_sequence", op_offset); + row.Dump(log); + row.Reset(prologue.default_is_stmt); + break; + + case DW_LNE_set_address : + { + row.address = debug_line_data.GetMaxU64(&offset, arg_size); + log->Printf( "0x%8.8x: DW_LNE_set_address (0x%llx)", op_offset, row.address); + } + break; + + case DW_LNE_define_file: + { + FileNameEntry fileEntry; + fileEntry.name = debug_line_data.GetCStr(&offset); + fileEntry.dir_idx = debug_line_data.GetULEB128(&offset); + fileEntry.mod_time = debug_line_data.GetULEB128(&offset); + fileEntry.length = debug_line_data.GetULEB128(&offset); + log->Printf( "0x%8.8x: DW_LNE_define_file('%s', dir=%i, mod_time=0x%8.8x, length=%i )", + op_offset, + fileEntry.name.c_str(), + fileEntry.dir_idx, + fileEntry.mod_time, + fileEntry.length); + prologue.file_names.push_back(fileEntry); + } + break; + + default: + log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode); + // Length doesn't include the zero opcode byte or the length itself, but + // it does include the sub_opcode, so we have to adjust for that below + offset += arg_size; + break; + } + } + break; + + // Standard Opcodes + case DW_LNS_copy: + log->Printf( "0x%8.8x: DW_LNS_copy", op_offset); + row.Dump (log); + break; + + case DW_LNS_advance_pc: + { + dw_uleb128_t addr_offset_n = debug_line_data.GetULEB128(&offset); + dw_uleb128_t addr_offset = addr_offset_n * prologue.min_inst_length; + log->Printf( "0x%8.8x: DW_LNS_advance_pc (0x%llx)", op_offset, addr_offset); + row.address += addr_offset; + } + break; + + case DW_LNS_advance_line: + { + dw_sleb128_t line_offset = debug_line_data.GetSLEB128(&offset); + log->Printf( "0x%8.8x: DW_LNS_advance_line (%i)", op_offset, line_offset); + row.line += line_offset; + } + break; + + case DW_LNS_set_file: + row.file = debug_line_data.GetULEB128(&offset); + log->Printf( "0x%8.8x: DW_LNS_set_file (%u)", op_offset, row.file); + break; + + case DW_LNS_set_column: + row.column = debug_line_data.GetULEB128(&offset); + log->Printf( "0x%8.8x: DW_LNS_set_column (%u)", op_offset, row.column); + break; + + case DW_LNS_negate_stmt: + row.is_stmt = !row.is_stmt; + log->Printf( "0x%8.8x: DW_LNS_negate_stmt", op_offset); + break; + + case DW_LNS_set_basic_block: + row.basic_block = true; + log->Printf( "0x%8.8x: DW_LNS_set_basic_block", op_offset); + break; + + case DW_LNS_const_add_pc: + { + uint8_t adjust_opcode = 255 - prologue.opcode_base; + dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length; + log->Printf( "0x%8.8x: DW_LNS_const_add_pc (0x%8.8llx)", op_offset, addr_offset); + row.address += addr_offset; + } + break; + + case DW_LNS_fixed_advance_pc: + { + uint16_t pc_offset = debug_line_data.GetU16(&offset); + log->Printf( "0x%8.8x: DW_LNS_fixed_advance_pc (0x%4.4x)", op_offset, pc_offset); + row.address += pc_offset; + } + break; + + case DW_LNS_set_prologue_end: + row.prologue_end = true; + log->Printf( "0x%8.8x: DW_LNS_set_prologue_end", op_offset); + break; + + case DW_LNS_set_epilogue_begin: + row.epilogue_begin = true; + log->Printf( "0x%8.8x: DW_LNS_set_epilogue_begin", op_offset); + break; + + case DW_LNS_set_isa: + row.isa = debug_line_data.GetULEB128(&offset); + log->Printf( "0x%8.8x: DW_LNS_set_isa (%u)", op_offset, row.isa); + break; + + // Special Opcodes + default: + if (opcode < prologue.opcode_base) + { + // We have an opcode that this parser doesn't know about, skip + // the number of ULEB128 numbers that is says to skip in the + // prologue's standard_opcode_lengths array + uint8_t n = prologue.standard_opcode_lengths[opcode-1]; + log->Printf( "0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n); + while (n > 0) + { + debug_line_data.GetULEB128(&offset); + --n; + } + } + else + { + uint8_t adjust_opcode = opcode - prologue.opcode_base; + dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length; + int32_t line_offset = prologue.line_base + (adjust_opcode % prologue.line_range); + log->Printf("0x%8.8x: address += 0x%llx, line += %i\n", op_offset, (uint64_t)addr_offset, line_offset); + row.address += addr_offset; + row.line += line_offset; + row.Dump (log); + } + break; + } + } + return end_offset; + } + return DW_INVALID_OFFSET; +} + + + + +//---------------------------------------------------------------------- +// Parse +// +// Parse the entire line table contents calling callback each time a +// new prologue is parsed and every time a new row is to be added to +// the line table. +//---------------------------------------------------------------------- +void +DWARFDebugLine::Parse(const DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData) +{ + uint32_t offset = 0; + if (debug_line_data.ValidOffset(offset)) + { + if (!ParseStatementTable(debug_line_data, &offset, callback, userData)) + ++offset; // Skip to next byte in .debug_line section + } +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::ParsePrologue +//---------------------------------------------------------------------- +bool +DWARFDebugLine::ParsePrologue(const DataExtractor& debug_line_data, dw_offset_t* offset_ptr, Prologue* prologue) +{ +// const uint32_t prologue_offset = *offset_ptr; + + //DEBUG_PRINTF("0x%8.8x: ParsePrologue()\n", *offset_ptr); + + prologue->Clear(); + uint32_t i; + const char * s; + prologue->total_length = debug_line_data.GetU32(offset_ptr); + prologue->version = debug_line_data.GetU16(offset_ptr); + if (prologue->version != 2) + return false; + + prologue->prologue_length = debug_line_data.GetU32(offset_ptr); + const dw_offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr; + prologue->min_inst_length = debug_line_data.GetU8(offset_ptr); + prologue->default_is_stmt = debug_line_data.GetU8(offset_ptr); + prologue->line_base = debug_line_data.GetU8(offset_ptr); + prologue->line_range = debug_line_data.GetU8(offset_ptr); + prologue->opcode_base = debug_line_data.GetU8(offset_ptr); + + prologue->standard_opcode_lengths.reserve(prologue->opcode_base-1); + + for (i=1; i<prologue->opcode_base; ++i) + { + uint8_t op_len = debug_line_data.GetU8(offset_ptr); + prologue->standard_opcode_lengths.push_back(op_len); + } + + while (*offset_ptr < end_prologue_offset) + { + s = debug_line_data.GetCStr(offset_ptr); + if (s && s[0]) + prologue->include_directories.push_back(s); + else + break; + } + + while (*offset_ptr < end_prologue_offset) + { + const char* name = debug_line_data.GetCStr( offset_ptr ); + if (name && name[0]) + { + FileNameEntry fileEntry; + fileEntry.name = name; + fileEntry.dir_idx = debug_line_data.GetULEB128( offset_ptr ); + fileEntry.mod_time = debug_line_data.GetULEB128( offset_ptr ); + fileEntry.length = debug_line_data.GetULEB128( offset_ptr ); + prologue->file_names.push_back(fileEntry); + } + else + break; + } + + assert(*offset_ptr == end_prologue_offset); + return end_prologue_offset; +} + +bool +DWARFDebugLine::ParseSupportFiles(const DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files) +{ + uint32_t offset = stmt_list + 4; // Skip the total length + const char * s; + uint32_t version = debug_line_data.GetU16(&offset); + if (version != 2) + return false; + + const dw_offset_t end_prologue_offset = debug_line_data.GetU32(&offset) + offset; + // Skip instruction length, default is stmt, line base, line range and + // opcode base, and all opcode lengths + offset += 4; + const uint8_t opcode_base = debug_line_data.GetU8(&offset); + offset += opcode_base - 1; + std::vector<std::string> include_directories; + include_directories.push_back(""); // Directory at index zero doesn't exist + while (offset < end_prologue_offset) + { + s = debug_line_data.GetCStr(&offset); + if (s && s[0]) + include_directories.push_back(s); + else + break; + } + std::string fullpath; + while (offset < end_prologue_offset) + { + const char* path = debug_line_data.GetCStr( &offset ); + if (path && path[0]) + { + uint32_t dir_idx = debug_line_data.GetULEB128( &offset ); + debug_line_data.Skip_LEB128(&offset); // Skip mod_time + debug_line_data.Skip_LEB128(&offset); // Skip length + + if (path[0] == '/') + { + // The path starts with a directory delimiter, so we are done. + fullpath = path; + } + else + { + if (dir_idx > 0 && dir_idx < include_directories.size()) + { + if (cu_comp_dir && include_directories[dir_idx][0] != '/') + { + fullpath = cu_comp_dir; + + if (*fullpath.rbegin() != '/') + fullpath += '/'; + fullpath += include_directories[dir_idx]; + + } + else + fullpath = include_directories[dir_idx]; + } + else if (cu_comp_dir && cu_comp_dir[0]) + { + fullpath = cu_comp_dir; + } + + if (!fullpath.empty()) + { + if (*fullpath.rbegin() != '/') + fullpath += '/'; + } + fullpath += path; + } + FileSpec file_spec(fullpath.c_str()); + support_files.Append(file_spec); + } + } + + assert(offset == end_prologue_offset); + return end_prologue_offset; +} + +//---------------------------------------------------------------------- +// ParseStatementTable +// +// Parse a single line table (prologue and all rows) and call the +// callback function once for the prologue (row in state will be zero) +// and each time a row is to be added to the line table. +//---------------------------------------------------------------------- +bool +DWARFDebugLine::ParseStatementTable +( + const DataExtractor& debug_line_data, + dw_offset_t* offset_ptr, + DWARFDebugLine::State::Callback callback, + void* userData +) +{ + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_LINE); + Prologue::shared_ptr prologue(new Prologue()); + + + const dw_offset_t debug_line_offset = *offset_ptr; + + Timer scoped_timer (__PRETTY_FUNCTION__, + "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])", + debug_line_offset); + + if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get())) + { + if (log) + log->Error ("failed to parse DWARF line table prologue"); + // Restore our offset and return false to indicate failure! + *offset_ptr = debug_line_offset; + return false; + } + + if (log) + prologue->Dump (log); + + const dw_offset_t end_offset = debug_line_offset + prologue->total_length + sizeof(prologue->total_length); + + assert(debug_line_data.ValidOffset(end_offset-1)); + + State state(prologue, log, callback, userData); + + while (*offset_ptr < end_offset) + { + //DEBUG_PRINTF("0x%8.8x: ", *offset_ptr); + uint8_t opcode = debug_line_data.GetU8(offset_ptr); + + if (opcode == 0) + { + // Extended Opcodes always start with a zero opcode followed by + // a uleb128 length so you can skip ones you don't know about + dw_offset_t ext_offset = *offset_ptr; + dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr); + dw_offset_t arg_size = len - (*offset_ptr - ext_offset); + + //DEBUG_PRINTF("Extended: <%2u> ", len); + uint8_t sub_opcode = debug_line_data.GetU8(offset_ptr); + switch (sub_opcode) + { + case DW_LNE_end_sequence: + // Set the end_sequence register of the state machine to true and + // append a row to the matrix using the current values of the + // state-machine registers. Then reset the registers to the initial + // values specified above. Every statement program sequence must end + // with a DW_LNE_end_sequence instruction which creates a row whose + // address is that of the byte after the last target machine instruction + // of the sequence. + state.end_sequence = true; + state.AppendRowToMatrix(*offset_ptr); + state.Reset(); + break; + + case DW_LNE_set_address: + // Takes a single relocatable address as an operand. The size of the + // operand is the size appropriate to hold an address on the target + // machine. Set the address register to the value given by the + // relocatable address. All of the other statement program opcodes + // that affect the address register add a delta to it. This instruction + // stores a relocatable value into it instead. + state.address = debug_line_data.GetAddress(offset_ptr); + break; + + case DW_LNE_define_file: + // Takes 4 arguments. The first is a null terminated string containing + // a source file name. The second is an unsigned LEB128 number representing + // the directory index of the directory in which the file was found. The + // third is an unsigned LEB128 number representing the time of last + // modification of the file. The fourth is an unsigned LEB128 number + // representing the length in bytes of the file. The time and length + // fields may contain LEB128(0) if the information is not available. + // + // The directory index represents an entry in the include_directories + // section of the statement program prologue. The index is LEB128(0) + // if the file was found in the current directory of the compilation, + // LEB128(1) if it was found in the first directory in the + // include_directories section, and so on. The directory index is + // ignored for file names that represent full path names. + // + // The files are numbered, starting at 1, in the order in which they + // appear; the names in the prologue come before names defined by + // the DW_LNE_define_file instruction. These numbers are used in the + // the file register of the state machine. + { + FileNameEntry fileEntry; + fileEntry.name = debug_line_data.GetCStr(offset_ptr); + fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr); + fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr); + fileEntry.length = debug_line_data.GetULEB128(offset_ptr); + state.prologue->file_names.push_back(fileEntry); + } + break; + + default: + // Length doesn't include the zero opcode byte or the length itself, but + // it does include the sub_opcode, so we have to adjust for that below + (*offset_ptr) += arg_size; + break; + } + } + else if (opcode < prologue->opcode_base) + { + switch (opcode) + { + // Standard Opcodes + case DW_LNS_copy: + // Takes no arguments. Append a row to the matrix using the + // current values of the state-machine registers. Then set + // the basic_block register to false. + state.AppendRowToMatrix(*offset_ptr); + break; + + case DW_LNS_advance_pc: + // Takes a single unsigned LEB128 operand, multiplies it by the + // min_inst_length field of the prologue, and adds the + // result to the address register of the state machine. + state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length; + break; + + case DW_LNS_advance_line: + // Takes a single signed LEB128 operand and adds that value to + // the line register of the state machine. + state.line += debug_line_data.GetSLEB128(offset_ptr); + break; + + case DW_LNS_set_file: + // Takes a single unsigned LEB128 operand and stores it in the file + // register of the state machine. + state.file = debug_line_data.GetULEB128(offset_ptr); + break; + + case DW_LNS_set_column: + // Takes a single unsigned LEB128 operand and stores it in the + // column register of the state machine. + state.column = debug_line_data.GetULEB128(offset_ptr); + break; + + case DW_LNS_negate_stmt: + // Takes no arguments. Set the is_stmt register of the state + // machine to the logical negation of its current value. + state.is_stmt = !state.is_stmt; + break; + + case DW_LNS_set_basic_block: + // Takes no arguments. Set the basic_block register of the + // state machine to true + state.basic_block = true; + break; + + case DW_LNS_const_add_pc: + // Takes no arguments. Add to the address register of the state + // machine the address increment value corresponding to special + // opcode 255. The motivation for DW_LNS_const_add_pc is this: + // when the statement program needs to advance the address by a + // small amount, it can use a single special opcode, which occupies + // a single byte. When it needs to advance the address by up to + // twice the range of the last special opcode, it can use + // DW_LNS_const_add_pc followed by a special opcode, for a total + // of two bytes. Only if it needs to advance the address by more + // than twice that range will it need to use both DW_LNS_advance_pc + // and a special opcode, requiring three or more bytes. + { + uint8_t adjust_opcode = 255 - prologue->opcode_base; + dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length; + state.address += addr_offset; + } + break; + + case DW_LNS_fixed_advance_pc: + // Takes a single uhalf operand. Add to the address register of + // the state machine the value of the (unencoded) operand. This + // is the only extended opcode that takes an argument that is not + // a variable length number. The motivation for DW_LNS_fixed_advance_pc + // is this: existing assemblers cannot emit DW_LNS_advance_pc or + // special opcodes because they cannot encode LEB128 numbers or + // judge when the computation of a special opcode overflows and + // requires the use of DW_LNS_advance_pc. Such assemblers, however, + // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. + state.address += debug_line_data.GetU16(offset_ptr); + break; + + case DW_LNS_set_prologue_end: + // Takes no arguments. Set the prologue_end register of the + // state machine to true + state.prologue_end = true; + break; + + case DW_LNS_set_epilogue_begin: + // Takes no arguments. Set the basic_block register of the + // state machine to true + state.epilogue_begin = true; + break; + + case DW_LNS_set_isa: + // Takes a single unsigned LEB128 operand and stores it in the + // column register of the state machine. + state.isa = debug_line_data.GetULEB128(offset_ptr); + break; + + default: + // Handle any unknown standard opcodes here. We know the lengths + // of such opcodes because they are specified in the prologue + // as a multiple of LEB128 operands for each opcode. + { + uint8_t i; + assert (opcode - 1 < prologue->standard_opcode_lengths.size()); + const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1]; + for (i=0; i<opcode_length; ++i) + debug_line_data.Skip_LEB128(offset_ptr); + } + break; + } + } + else + { + // Special Opcodes + + // A special opcode value is chosen based on the amount that needs + // to be added to the line and address registers. The maximum line + // increment for a special opcode is the value of the line_base + // field in the header, plus the value of the line_range field, + // minus 1 (line base + line range - 1). If the desired line + // increment is greater than the maximum line increment, a standard + // opcode must be used instead of a special opcode. The “address + // advance” is calculated by dividing the desired address increment + // by the minimum_instruction_length field from the header. The + // special opcode is then calculated using the following formula: + // + // opcode = (desired line increment - line_base) + (line_range * address advance) + opcode_base + // + // If the resulting opcode is greater than 255, a standard opcode + // must be used instead. + // + // To decode a special opcode, subtract the opcode_base from the + // opcode itself to give the adjusted opcode. The amount to + // increment the address register is the result of the adjusted + // opcode divided by the line_range multiplied by the + // minimum_instruction_length field from the header. That is: + // + // address increment = (adjusted opcode / line_range) * minimim_instruction_length + // + // The amount to increment the line register is the line_base plus + // the result of the adjusted opcode modulo the line_range. That is: + // + // line increment = line_base + (adjusted opcode % line_range) + + uint8_t adjust_opcode = opcode - prologue->opcode_base; + dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length; + int32_t line_offset = prologue->line_base + (adjust_opcode % prologue->line_range); + state.line += line_offset; + state.address += addr_offset; + state.AppendRowToMatrix(*offset_ptr); + } + } + + state.Finalize( *offset_ptr ); + + return end_offset; +} + + +//---------------------------------------------------------------------- +// ParseStatementTableCallback +//---------------------------------------------------------------------- +static void +ParseStatementTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData) +{ + DWARFDebugLine::LineTable* line_table = (DWARFDebugLine::LineTable*)userData; + if (state.row == DWARFDebugLine::State::StartParsingLineTable) + { + // Just started parsing the line table, so lets keep a reference to + // the prologue using the supplied shared pointer + line_table->prologue = state.prologue; + } + else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) + { + // Done parsing line table, nothing to do for the cleanup + } + else + { + // We have a new row, lets append it + line_table->AppendRow(state); + } +} + +//---------------------------------------------------------------------- +// ParseStatementTable +// +// Parse a line table at offset and populate the LineTable class with +// the prologue and all rows. +//---------------------------------------------------------------------- +bool +DWARFDebugLine::ParseStatementTable(const DataExtractor& debug_line_data, uint32_t* offset_ptr, LineTable* line_table) +{ + return ParseStatementTable(debug_line_data, offset_ptr, ParseStatementTableCallback, line_table); +} + + +inline bool +DWARFDebugLine::Prologue::IsValid() const +{ + return SymbolFileDWARF::SupportedVersion(version); +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::Prologue::Dump +//---------------------------------------------------------------------- +void +DWARFDebugLine::Prologue::Dump(Log *log) +{ + uint32_t i; + + log->Printf( "Line table prologue:"); + log->Printf( " total_length: 0x%8.8x", total_length); + log->Printf( " version: %u", version); + log->Printf( "prologue_length: 0x%8.8x", prologue_length); + log->Printf( "min_inst_length: %u", min_inst_length); + log->Printf( "default_is_stmt: %u", default_is_stmt); + log->Printf( " line_base: %i", line_base); + log->Printf( " line_range: %u", line_range); + log->Printf( " opcode_base: %u", opcode_base); + + for (i=0; i<standard_opcode_lengths.size(); ++i) + { + log->Printf( "standard_opcode_lengths[%s] = %u", DW_LNS_value_to_name(i+1), standard_opcode_lengths[i]); + } + + if (!include_directories.empty()) + { + for (i=0; i<include_directories.size(); ++i) + { + log->Printf( "include_directories[%3u] = '%s'", i+1, include_directories[i].c_str()); + } + } + + if (!file_names.empty()) + { + log->PutCString (" Dir Mod Time File Len File Name"); + log->PutCString (" ---- ---------- ---------- ---------------------------"); + for (i=0; i<file_names.size(); ++i) + { + const FileNameEntry& fileEntry = file_names[i]; + log->Printf ("file_names[%3u] %4u 0x%8.8x 0x%8.8x %s", + i+1, + fileEntry.dir_idx, + fileEntry.mod_time, + fileEntry.length, + fileEntry.name.c_str()); + } + } +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::ParsePrologue::Append +// +// Append the contents of the prologue to the binary stream buffer +//---------------------------------------------------------------------- +//void +//DWARFDebugLine::Prologue::Append(BinaryStreamBuf& buff) const +//{ +// uint32_t i; +// +// buff.Append32(total_length); +// buff.Append16(version); +// buff.Append32(prologue_length); +// buff.Append8(min_inst_length); +// buff.Append8(default_is_stmt); +// buff.Append8(line_base); +// buff.Append8(line_range); +// buff.Append8(opcode_base); +// +// for (i=0; i<standard_opcode_lengths.size(); ++i) +// buff.Append8(standard_opcode_lengths[i]); +// +// for (i=0; i<include_directories.size(); ++i) +// buff.AppendCStr(include_directories[i].c_str()); +// buff.Append8(0); // Terminate the include directory section with empty string +// +// for (i=0; i<file_names.size(); ++i) +// { +// buff.AppendCStr(file_names[i].name.c_str()); +// buff.Append32_as_ULEB128(file_names[i].dir_idx); +// buff.Append32_as_ULEB128(file_names[i].mod_time); +// buff.Append32_as_ULEB128(file_names[i].length); +// } +// buff.Append8(0); // Terminate the file names section with empty string +//} + + +bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, std::string& path, std::string& directory) const +{ + uint32_t idx = file_idx - 1; // File indexes are 1 based... + if (idx < file_names.size()) + { + path = file_names[idx].name; + uint32_t dir_idx = file_names[idx].dir_idx - 1; + if (dir_idx < include_directories.size()) + directory = include_directories[dir_idx]; + else + directory.clear(); + return true; + } + return false; +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::LineTable::Dump +//---------------------------------------------------------------------- +void +DWARFDebugLine::LineTable::Dump(Log *log) const +{ + if (prologue.get()) + prologue->Dump (log); + + if (!rows.empty()) + { + log->PutCString ("Address Line Column File ISA Flags"); + log->PutCString ("------------------ ------ ------ ------ --- -------------"); + Row::const_iterator pos = rows.begin(); + Row::const_iterator end = rows.end(); + while (pos != end) + { + (*pos).Dump (log); + ++pos; + } + } +} + + +void +DWARFDebugLine::LineTable::AppendRow(const DWARFDebugLine::Row& state) +{ + rows.push_back(state); +} + + + +//---------------------------------------------------------------------- +// Compare function for the binary search in DWARFDebugLine::LineTable::LookupAddress() +//---------------------------------------------------------------------- +static bool FindMatchingAddress (const DWARFDebugLine::Row& row1, const DWARFDebugLine::Row& row2) +{ + return row1.address < row2.address; +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::LineTable::LookupAddress +//---------------------------------------------------------------------- +uint32_t +DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const +{ + uint32_t index = UINT_MAX; + if (!rows.empty()) + { + // Use the lower_bound algorithm to perform a binary search since we know + // that our line table data is ordered by address. + DWARFDebugLine::Row row; + row.address = address; + Row::const_iterator begin_pos = rows.begin(); + Row::const_iterator end_pos = rows.end(); + Row::const_iterator pos = lower_bound(begin_pos, end_pos, row, FindMatchingAddress); + if (pos == end_pos) + { + if (address < cu_high_pc) + return rows.size()-1; + } + else + { + // Rely on fact that we are using a std::vector and we can do + // pointer arithmetic to find the row index (which will be one less + // that what we found since it will find the first position after + // the current address) since std::vector iterators are just + // pointers to the container type. + index = pos - begin_pos; + if (pos->address > address) + { + if (index > 0) + --index; + else + index = UINT_MAX; + } + } + } + return index; // Failed to find address +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::Row::Row +//---------------------------------------------------------------------- +DWARFDebugLine::Row::Row(bool default_is_stmt) : + address(0), + line(1), + column(0), + file(1), + is_stmt(default_is_stmt), + basic_block(false), + end_sequence(false), + prologue_end(false), + epilogue_begin(false), + isa(0) +{ +} + +//---------------------------------------------------------------------- +// Called after a row is appended to the matrix +//---------------------------------------------------------------------- +void +DWARFDebugLine::Row::PostAppend() +{ + basic_block = false; + prologue_end = false; + epilogue_begin = false; +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::Row::Reset +//---------------------------------------------------------------------- +void +DWARFDebugLine::Row::Reset(bool default_is_stmt) +{ + address = 0; + line = 1; + column = 0; + file = 1; + is_stmt = default_is_stmt; + basic_block = false; + end_sequence = false; + prologue_end = false; + epilogue_begin = false; + isa = 0; +} +//---------------------------------------------------------------------- +// DWARFDebugLine::Row::Dump +//---------------------------------------------------------------------- +void +DWARFDebugLine::Row::Dump(Log *log) const +{ + log->Printf( "0x%16.16llx %6u %6u %6u %3u %s%s%s%s%s", + address, + line, + column, + file, + isa, + is_stmt ? " is_stmt" : "", + basic_block ? " basic_block" : "", + prologue_end ? " prologue_end" : "", + epilogue_begin ? " epilogue_begin" : "", + end_sequence ? " end_sequence" : ""); +} + +//---------------------------------------------------------------------- +// Compare function LineTable structures +//---------------------------------------------------------------------- +static bool AddressLessThan (const DWARFDebugLine::Row& a, const DWARFDebugLine::Row& b) +{ + return a.address < b.address; +} + + + +// Insert a row at the correct address if the addresses can be out of +// order which can only happen when we are linking a line table that +// may have had it's contents rearranged. +void +DWARFDebugLine::Row::Insert(Row::collection& state_coll, const Row& state) +{ + // If we don't have anything yet, or if the address of the last state in our + // line table is less than the current one, just append the current state + if (state_coll.empty() || AddressLessThan(state_coll.back(), state)) + { + state_coll.push_back(state); + } + else + { + // Do a binary search for the correct entry + pair<Row::iterator, Row::iterator> range(equal_range(state_coll.begin(), state_coll.end(), state, AddressLessThan)); + + // If the addresses are equal, we can safely replace the previous entry + // with the current one if the one it is replacing is an end_sequence entry. + // We currently always place an extra end sequence when ever we exit a valid + // address range for a function in case the functions get rearranged by + // optmimizations or by order specifications. These extra end sequences will + // disappear by getting replaced with valid consecutive entries within a + // compile unit if there are no gaps. + if (range.first == range.second) + { + state_coll.insert(range.first, state); + } + else + { + if ((distance(range.first, range.second) == 1) && range.first->end_sequence == true) + { + *range.first = state; + } + else + { + state_coll.insert(range.second, state); + } + } + } +} + +void +DWARFDebugLine::Row::Dump(Log *log, const Row::collection& state_coll) +{ + std::for_each (state_coll.begin(), state_coll.end(), bind2nd(std::mem_fun_ref(&Row::Dump),log)); +} + + +//---------------------------------------------------------------------- +// DWARFDebugLine::State::State +//---------------------------------------------------------------------- +DWARFDebugLine::State::State(Prologue::shared_ptr& p, Log *l, DWARFDebugLine::State::Callback cb, void* userData) : + Row (p->default_is_stmt), + prologue (p), + log (l), + callback (cb), + callbackUserData (userData), + row (StartParsingLineTable) +{ + // Call the callback with the initial row state of zero for the prologue + if (callback) + callback(0, *this, callbackUserData); +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::State::Reset +//---------------------------------------------------------------------- +void +DWARFDebugLine::State::Reset() +{ + Row::Reset(prologue->default_is_stmt); +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::State::AppendRowToMatrix +//---------------------------------------------------------------------- +void +DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset) +{ + // Each time we are to add an entry into the line table matrix + // call the callback funtion so that someone can do something with + // the current state of the state machine (like build a line table + // or dump the line table!) + if (log) + { + if (row == 0) + { + log->PutCString ("Address Line Column File ISA Flags"); + log->PutCString ("------------------ ------ ------ ------ --- -------------"); + } + Dump (log); + } + + ++row; // Increase the row number before we call our callback for a real row + if (callback) + callback(offset, *this, callbackUserData); + PostAppend(); +} + +//---------------------------------------------------------------------- +// DWARFDebugLine::State::Finalize +//---------------------------------------------------------------------- +void +DWARFDebugLine::State::Finalize(dw_offset_t offset) +{ + // Call the callback with a special row state when we are done parsing a + // line table + row = DoneParsingLineTable; + if (callback) + callback(offset, *this, callbackUserData); +} + +//void +//DWARFDebugLine::AppendLineTableData +//( +// const DWARFDebugLine::Prologue* prologue, +// const DWARFDebugLine::Row::collection& state_coll, +// const uint32_t addr_size, +// BinaryStreamBuf &debug_line_data +//) +//{ +// if (state_coll.empty()) +// { +// // We have no entries, just make an empty line table +// debug_line_data.Append8(0); +// debug_line_data.Append8(1); +// debug_line_data.Append8(DW_LNE_end_sequence); +// } +// else +// { +// DWARFDebugLine::Row::const_iterator pos; +// Row::const_iterator end = state_coll.end(); +// bool default_is_stmt = prologue->default_is_stmt; +// const DWARFDebugLine::Row reset_state(default_is_stmt); +// const DWARFDebugLine::Row* prev_state = &reset_state; +// const int32_t max_line_increment_for_special_opcode = prologue->MaxLineIncrementForSpecialOpcode(); +// for (pos = state_coll.begin(); pos != end; ++pos) +// { +// const DWARFDebugLine::Row& curr_state = *pos; +// int32_t line_increment = 0; +// dw_addr_t addr_offset = curr_state.address - prev_state->address; +// dw_addr_t addr_advance = (addr_offset) / prologue->min_inst_length; +// line_increment = (int32_t)(curr_state.line - prev_state->line); +// +// // If our previous state was the reset state, then let's emit the +// // address to keep GDB's DWARF parser happy. If we don't start each +// // sequence with a DW_LNE_set_address opcode, the line table won't +// // get slid properly in GDB. +// +// if (prev_state == &reset_state) +// { +// debug_line_data.Append8(0); // Extended opcode +// debug_line_data.Append32_as_ULEB128(addr_size + 1); // Length of opcode bytes +// debug_line_data.Append8(DW_LNE_set_address); +// debug_line_data.AppendMax64(curr_state.address, addr_size); +// addr_advance = 0; +// } +// +// if (prev_state->file != curr_state.file) +// { +// debug_line_data.Append8(DW_LNS_set_file); +// debug_line_data.Append32_as_ULEB128(curr_state.file); +// } +// +// if (prev_state->column != curr_state.column) +// { +// debug_line_data.Append8(DW_LNS_set_column); +// debug_line_data.Append32_as_ULEB128(curr_state.column); +// } +// +// // Don't do anything fancy if we are at the end of a sequence +// // as we don't want to push any extra rows since the DW_LNE_end_sequence +// // will push a row itself! +// if (curr_state.end_sequence) +// { +// if (line_increment != 0) +// { +// debug_line_data.Append8(DW_LNS_advance_line); +// debug_line_data.Append32_as_SLEB128(line_increment); +// } +// +// if (addr_advance > 0) +// { +// debug_line_data.Append8(DW_LNS_advance_pc); +// debug_line_data.Append32_as_ULEB128(addr_advance); +// } +// +// // Now push the end sequence on! +// debug_line_data.Append8(0); +// debug_line_data.Append8(1); +// debug_line_data.Append8(DW_LNE_end_sequence); +// +// prev_state = &reset_state; +// } +// else +// { +// if (line_increment || addr_advance) +// { +// if (line_increment > max_line_increment_for_special_opcode) +// { +// debug_line_data.Append8(DW_LNS_advance_line); +// debug_line_data.Append32_as_SLEB128(line_increment); +// line_increment = 0; +// } +// +// uint32_t special_opcode = (line_increment >= prologue->line_base) ? ((line_increment - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256; +// if (special_opcode > 255) +// { +// // Both the address and line won't fit in one special opcode +// // check to see if just the line advance will? +// uint32_t special_opcode_line = ((line_increment >= prologue->line_base) && (line_increment != 0)) ? +// ((line_increment - prologue->line_base) + prologue->opcode_base) : 256; +// +// +// if (special_opcode_line > 255) +// { +// // Nope, the line advance won't fit by itself, check the address increment by itself +// uint32_t special_opcode_addr = addr_advance ? +// ((0 - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256; +// +// if (special_opcode_addr > 255) +// { +// // Neither the address nor the line will fit in a +// // special opcode, we must manually enter both then +// // do a DW_LNS_copy to push a row (special opcode +// // automatically imply a new row is pushed) +// if (line_increment != 0) +// { +// debug_line_data.Append8(DW_LNS_advance_line); +// debug_line_data.Append32_as_SLEB128(line_increment); +// } +// +// if (addr_advance > 0) +// { +// debug_line_data.Append8(DW_LNS_advance_pc); +// debug_line_data.Append32_as_ULEB128(addr_advance); +// } +// +// // Now push a row onto the line table manually +// debug_line_data.Append8(DW_LNS_copy); +// +// } +// else +// { +// // The address increment alone will fit into a special opcode +// // so modify our line change, then issue a special opcode +// // for the address increment and it will push a row into the +// // line table +// if (line_increment != 0) +// { +// debug_line_data.Append8(DW_LNS_advance_line); +// debug_line_data.Append32_as_SLEB128(line_increment); +// } +// +// // Advance of line and address will fit into a single byte special opcode +// // and this will also push a row onto the line table +// debug_line_data.Append8(special_opcode_addr); +// } +// } +// else +// { +// // The line change alone will fit into a special opcode +// // so modify our address increment first, then issue a +// // special opcode for the line change and it will push +// // a row into the line table +// if (addr_advance > 0) +// { +// debug_line_data.Append8(DW_LNS_advance_pc); +// debug_line_data.Append32_as_ULEB128(addr_advance); +// } +// +// // Advance of line and address will fit into a single byte special opcode +// // and this will also push a row onto the line table +// debug_line_data.Append8(special_opcode_line); +// } +// } +// else +// { +// // Advance of line and address will fit into a single byte special opcode +// // and this will also push a row onto the line table +// debug_line_data.Append8(special_opcode); +// } +// } +// prev_state = &curr_state; +// } +// } +// } +//} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h new file mode 100644 index 00000000000..57b2f159661 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -0,0 +1,225 @@ +//===-- DWARFDebugLine.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugLine_h_ +#define liblldb_DWARFDebugLine_h_ + +#include <map> +#include <vector> +#include <string> + +#include "lldb/lldb-private.h" + +#include "DWARFDefines.h" + +class SymbolFileDWARF; +class DWARFDebugInfoEntry; + +//---------------------------------------------------------------------- +// DWARFDebugLine +//---------------------------------------------------------------------- +class DWARFDebugLine +{ +public: + //------------------------------------------------------------------ + // FileNameEntry + //------------------------------------------------------------------ + struct FileNameEntry + { + FileNameEntry() : + name(), + dir_idx(0), + mod_time(0), + length(0) + { + } + + std::string name; + dw_sleb128_t dir_idx; + dw_sleb128_t mod_time; + dw_sleb128_t length; + + }; + + //------------------------------------------------------------------ + // Prologue + //------------------------------------------------------------------ + struct Prologue + { + + Prologue() : + total_length(0), + version(0), + prologue_length(0), + min_inst_length(0), + default_is_stmt(0), + line_base(0), + line_range(0), + opcode_base(0), + standard_opcode_lengths(), + include_directories(), + file_names() + { + } + + typedef lldb::SharedPtr<Prologue>::Type shared_ptr; + + uint32_t total_length; // The size in bytes of the statement information for this compilation unit (not including the total_length field itself). + uint16_t version; // Version identifier for the statement information format. + uint32_t prologue_length;// The number of bytes following the prologue_length field to the beginning of the first byte of the statement program itself. + uint8_t min_inst_length;// The size in bytes of the smallest target machine instruction. Statement program opcodes that alter the address register first multiply their operands by this value. + uint8_t default_is_stmt;// The initial value of theis_stmtregister. + int8_t line_base; // This parameter affects the meaning of the special opcodes. See below. + uint8_t line_range; // This parameter affects the meaning of the special opcodes. See below. + uint8_t opcode_base; // The number assigned to the first special opcode. + std::vector<uint8_t> standard_opcode_lengths; + std::vector<std::string> include_directories; + std::vector<FileNameEntry> file_names; + + // Length of the prologue in bytes + uint32_t Length() const { return prologue_length + sizeof(total_length) + sizeof(version) + sizeof(prologue_length); } + // Length of the line table data in bytes (not including the prologue) + uint32_t StatementTableLength() const { return total_length + sizeof(total_length) - Length(); } + int32_t MaxLineIncrementForSpecialOpcode() const { return line_base + (int8_t)line_range - 1; }; + bool IsValid() const; +// void Append(BinaryStreamBuf& buff) const; + void Dump (lldb_private::Log *log); + void Clear() + { + total_length = version = prologue_length = min_inst_length = line_base = line_range = opcode_base = 0; + line_base = 0; + standard_opcode_lengths.clear(); + include_directories.clear(); + file_names.clear(); + } + bool GetFile(uint32_t file_idx, std::string& file, std::string& dir) const; + + }; + + // Standard .debug_line state machine structure + struct Row + { + typedef std::vector<Row> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + Row(bool default_is_stmt = false); + virtual ~Row() {} + void PostAppend (); + void Reset(bool default_is_stmt); + void Dump(lldb_private::Log *log) const; + static void Insert(Row::collection& state_coll, const Row& state); + static void Dump(lldb_private::Log *log, const Row::collection& state_coll); + + dw_addr_t address; // The program-counter value corresponding to a machine instruction generated by the compiler. + uint32_t line; // An unsigned integer indicating a source line number. Lines are numbered beginning at 1. The compiler may emit the value 0 in cases where an instruction cannot be attributed to any source line. + uint16_t column; // An unsigned integer indicating a column number within a source line. Columns are numbered beginning at 1. The value 0 is reserved to indicate that a statement begins at the ‘‘left edge’’ of the line. + uint16_t file; // An unsigned integer indicating the identity of the source file corresponding to a machine instruction. + uint8_t is_stmt:1, // A boolean indicating that the current instruction is the beginning of a statement. + basic_block:1, // A boolean indicating that the current instruction is the beginning of a basic block. + end_sequence:1, // A boolean indicating that the current address is that of the first byte after the end of a sequence of target machine instructions. + prologue_end:1, // A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an entry breakpoint of a function. + epilogue_begin:1;// A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an exit breakpoint of a function. + uint32_t isa; // An unsigned integer whose value encodes the applicable instruction set architecture for the current instruction. + }; + + + //------------------------------------------------------------------ + // LineTable + //------------------------------------------------------------------ + struct LineTable + { + typedef lldb::SharedPtr<LineTable>::Type shared_ptr; + + LineTable() : + prologue(), + rows() + { + } + + void AppendRow(const DWARFDebugLine::Row& state); + void Clear() + { + prologue.reset(); + rows.clear(); + } + + uint32_t LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const; + void Dump(lldb_private::Log *log) const; + + Prologue::shared_ptr prologue; + Row::collection rows; + }; + + //------------------------------------------------------------------ + // State + //------------------------------------------------------------------ + struct State : public Row + { + typedef void (*Callback)(dw_offset_t offset, const State& state, void* userData); + + // Special row codes used when calling the callback + enum + { + StartParsingLineTable = 0, + DoneParsingLineTable = -1 + }; + + State (Prologue::shared_ptr& prologue_sp, + lldb_private::Log *log, + Callback callback, + void* userData); + + void + AppendRowToMatrix (dw_offset_t offset); + + void + Finalize (dw_offset_t offset); + + void + Reset (); + + Prologue::shared_ptr prologue; + lldb_private::Log *log; + Callback callback; // Callback funcation that gets called each time an entry it to be added to the matrix + void* callbackUserData; + int row; // The row number that starts at zero for the prologue, and increases for each row added to the matrix + private: + DISALLOW_COPY_AND_ASSIGN (State); + }; + + static bool DumpOpcodes(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET, uint32_t dump_flags = 0); // If line_offset is invalid, dump everything + static bool DumpLineTableRows(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET); // If line_offset is invalid, dump everything + static bool ParseSupportFiles(const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files); + static bool ParsePrologue(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, Prologue* prologue); + static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, State::Callback callback, void* userData); + static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset); + static dw_offset_t DumpStatementOpcodes(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset, uint32_t flags); + static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, uint32_t* offset_ptr, LineTable* line_table); + static void Parse(const lldb_private::DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData); +// static void AppendLineTableData(const DWARFDebugLine::Prologue* prologue, const DWARFDebugLine::Row::collection& state_coll, const uint32_t addr_size, BinaryStreamBuf &debug_line_data); + + DWARFDebugLine() : + m_lineTableMap() + { + } + + void Parse(const lldb_private::DataExtractor& debug_line_data); + void ParseIfNeeded(const lldb_private::DataExtractor& debug_line_data); + LineTable::shared_ptr GetLineTable(const dw_offset_t offset) const; + +protected: + typedef std::map<dw_offset_t, LineTable::shared_ptr> LineTableMap; + typedef LineTableMap::iterator LineTableIter; + typedef LineTableMap::const_iterator LineTableConstIter; + + LineTableMap m_lineTableMap; +}; + +#endif // liblldb_DWARFDebugLine_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp new file mode 100644 index 00000000000..0501da8fe40 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp @@ -0,0 +1,48 @@ +//===-- DWARFDebugMacinfo.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugMacinfo.h" + +#include "DWARFDebugMacinfoEntry.h" +#include "SymbolFileDWARF.h" + +#include "lldb/Core/Stream.h" + +using namespace lldb_private; +using namespace std; + +DWARFDebugMacinfo::DWARFDebugMacinfo() +{ +} + +DWARFDebugMacinfo::~DWARFDebugMacinfo() +{ +} + +void +DWARFDebugMacinfo::Dump(Stream *s, const DataExtractor& macinfo_data, dw_offset_t offset) +{ + DWARFDebugMacinfoEntry maninfo_entry; + if (macinfo_data.GetByteSize() == 0) + { + s->PutCString("< EMPTY >\n"); + return; + } + if (offset == DW_INVALID_OFFSET) + { + offset = 0; + while (maninfo_entry.Extract(macinfo_data, &offset)) + maninfo_entry.Dump(s); + } + else + { + if (maninfo_entry.Extract(macinfo_data, &offset)) + maninfo_entry.Dump(s); + } +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h new file mode 100644 index 00000000000..e420a5be84e --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h @@ -0,0 +1,29 @@ +//===-- DWARFDebugMacinfo.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugLine_h_ +#define SymbolFileDWARF_DWARFDebugLine_h_ + +#include "SymbolFileDWARF.h" + +class DWARFDebugMacinfo +{ +public: + DWARFDebugMacinfo(); + + ~DWARFDebugMacinfo(); + + static void + Dump (lldb_private::Stream *s, + const lldb_private::DataExtractor& macinfo_data, + dw_offset_t offset = DW_INVALID_OFFSET); +}; + + +#endif // SymbolFileDWARF_DWARFDebugLine_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp new file mode 100644 index 00000000000..c07cec45c2a --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp @@ -0,0 +1,132 @@ +//===-- DWARFDebugMacinfoEntry.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugMacinfoEntry.h" + +#include "lldb/Core/Stream.h" + +using namespace lldb_private; +using namespace std; + +DWARFDebugMacinfoEntry::DWARFDebugMacinfoEntry() : + m_type_code(0), + m_line(0), + m_op2() +{ + m_op2.cstr = NULL; +} + +DWARFDebugMacinfoEntry::~DWARFDebugMacinfoEntry() +{ +} + +const char* +DWARFDebugMacinfoEntry::GetCString() const +{ + switch (m_type_code) + { + case 0: + case DW_MACINFO_start_file: + case DW_MACINFO_end_file: + return NULL; + default: + break; + } + return m_op2.cstr; +} + + + +void +DWARFDebugMacinfoEntry::Dump(Stream *s) const +{ + if (m_type_code) + { + s->PutCString(DW_MACINFO_value_to_name(m_type_code)); + + switch (m_type_code) + { + case DW_MACINFO_define: + s->Printf(" line:%u #define %s\n", (uint32_t)m_line, m_op2.cstr); + break; + + case DW_MACINFO_undef: + s->Printf(" line:%u #undef %s\n", (uint32_t)m_line, m_op2.cstr); + break; + + default: + s->Printf(" line:%u str: '%s'\n", (uint32_t)m_line, m_op2.cstr); + break; + + case DW_MACINFO_start_file: + s->Printf(" line:%u file index: '%s'\n", (uint32_t)m_line, (uint32_t)m_op2.file_idx); + break; + + case DW_MACINFO_end_file: + break; + } + } + else + { + s->PutCString(" END\n"); + } +} + + +bool +DWARFDebugMacinfoEntry::Extract(const DataExtractor& mac_info_data, dw_offset_t* offset_ptr) +{ + if (mac_info_data.ValidOffset(*offset_ptr)) + { + m_type_code = mac_info_data.GetU8(offset_ptr); + + switch (m_type_code) + { + + case DW_MACINFO_define: + case DW_MACINFO_undef: + // 2 operands: + // Arg 1: operand encodes the line number of the source line on which + // the relevant defining or undefining pre-processor directives + // appeared. + m_line = mac_info_data.GetULEB128(offset_ptr); + // Arg 2: define string + m_op2.cstr = mac_info_data.GetCStr(offset_ptr); + break; + + case DW_MACINFO_start_file: + // 2 operands: + // Op 1: line number of the source line on which the inclusion + // pre-processor directive occurred. + m_line = mac_info_data.GetULEB128(offset_ptr); + // Op 2: a source file name index to a file number in the statement + // information table for the relevant compilation unit. + m_op2.file_idx = mac_info_data.GetULEB128(offset_ptr); + break; + + case 0: // End of list + case DW_MACINFO_end_file: + // No operands + m_line = DW_INVALID_OFFSET; + m_op2.cstr = NULL; + break; + default: + // Vendor specific entries always have a ULEB128 and a string + m_line = mac_info_data.GetULEB128(offset_ptr); + m_op2.cstr = mac_info_data.GetCStr(offset_ptr); + break; + } + return true; + } + else + m_type_code = 0; + + return false; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h new file mode 100644 index 00000000000..85dd6254833 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h @@ -0,0 +1,57 @@ +//===-- DWARFDebugMacinfoEntry.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugMacinfoEntry_h_ +#define SymbolFileDWARF_DWARFDebugMacinfoEntry_h_ + +#include "SymbolFileDWARF.h" + +class DWARFDebugMacinfoEntry +{ +public: + DWARFDebugMacinfoEntry(); + + ~DWARFDebugMacinfoEntry(); + + uint8_t + TypeCode() const + { + return m_type_code; + } + + uint8_t + GetLineNumber() const + { + return m_line; + } + + void + Dump(lldb_private::Stream *s) const; + + const char* + GetCString() const; + + bool + Extract(const lldb_private::DataExtractor& mac_info_data, + dw_offset_t* offset_ptr); + +protected: + +private: + uint8_t m_type_code; + dw_uleb128_t m_line; + union + { + dw_uleb128_t file_idx; + const char* cstr; + } m_op2; +}; + + +#endif // SymbolFileDWARF_DWARFDebugMacinfoEntry_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp new file mode 100644 index 00000000000..93ecaed72c6 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp @@ -0,0 +1,297 @@ +//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugPubnames.h" + +#include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" + +#include "DWARFDebugInfo.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "DWARFCompileUnit.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARF.h" + + +using namespace lldb_private; + +DWARFDebugPubnames::DWARFDebugPubnames() : + m_sets() +{ +} + +bool +DWARFDebugPubnames::Extract(const DataExtractor& data) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "DWARFDebugPubnames::Extract (byte_size = %zu)", + data.GetByteSize()); + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES); + if (log) + log->Printf("DWARFDebugPubnames::Extract (byte_size = %zu)", data.GetByteSize()); + + if (data.ValidOffset(0)) + { + uint32_t offset = 0; + + DWARFDebugPubnamesSet set; + while (data.ValidOffset(offset)) + { + if (set.Extract(data, &offset)) + { + m_sets.push_back(set); + offset = set.GetOffsetOfNextEntry(); + } + else + break; + } + if (log) + Dump (log); + return true; + } + return false; +} + + +bool +DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "DWARFDebugPubnames::GeneratePubnames (data = %p)", + dwarf2Data); + + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES); + if (log) + log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); + + m_sets.clear(); + DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); + if (debug_info) + { + + const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data(); + + uint32_t cu_idx = 0; + const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); + for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + + DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); + + bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; + + DWARFDIECollection dies; + const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) + + cu->AppendDIEsWithTag (DW_TAG_variable, dies); + + dw_offset_t cu_offset = cu->GetOffset(); + DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); + + size_t die_idx; + for (die_idx = 0; die_idx < die_count; ++die_idx) + { + const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); + DWARFDebugInfoEntry::Attributes attributes; + const char *name = NULL; + const char *mangled = NULL; + bool add_die = false; + bool is_variable = false; + const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, attributes); + if (num_attributes > 0) + { + uint32_t i; + + dw_tag_t tag = die->Tag(); + + is_variable = tag == DW_TAG_variable; + + for (i=0; i<num_attributes; ++i) + { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + switch (attr) + { + case DW_AT_name: + if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) + name = form_value.AsCString(debug_str); + break; + + case DW_AT_MIPS_linkage_name: + if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) + mangled = form_value.AsCString(debug_str); + break; + + case DW_AT_low_pc: + case DW_AT_ranges: + case DW_AT_entry_pc: + if (tag == DW_TAG_subprogram) + add_die = true; + break; + + case DW_AT_location: + if (tag == DW_TAG_variable) + { + const DWARFDebugInfoEntry* parent_die = die->GetParent(); + while ( parent_die != NULL ) + { + switch (parent_die->Tag()) + { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + // Even if this is a function level static, we don't add it. We could theoretically + // add these if we wanted to by introspecting into the DW_AT_location and seeing + // if the location describes a hard coded address, but we dont want the performance + // penalty of that right now. + add_die = false; +// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) +// { +// // If we have valid block data, then we have location expression bytes +// // that are fixed (not a location list). +// const uint8_t *block_data = form_value.BlockData(); +// if (block_data) +// { +// uint32_t block_length = form_value.Unsigned(); +// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) +// { +// if (block_data[0] == DW_OP_addr) +// add_die = true; +// } +// } +// } + parent_die = NULL; // Terminate the while loop. + break; + + case DW_TAG_compile_unit: + add_die = true; + parent_die = NULL; // Terminate the while loop. + break; + + default: + parent_die = parent_die->GetParent(); // Keep going in the while loop. + break; + } + } + } + break; + } + } + } + + if (add_die && (name || mangled)) + { + if (is_variable) + cu->AddGlobal(die); + pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name); + } + } + + if (pubnames_set.NumDescriptors() > 0) + { + m_sets.push_back(pubnames_set); + } + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed + if (clear_dies) + cu->ClearDIEs (true); + } + } + if (m_sets.empty()) + return false; + if (log) + Dump (log); + return true; +} + +bool +DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data) +{ + m_sets.clear(); + DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); + if (debug_info) + { + uint32_t cu_idx = 0; + const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); + for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFDIECollection dies; + const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies); + dw_offset_t cu_offset = cu->GetOffset(); + DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); + + size_t die_idx; + for (die_idx = 0; die_idx < die_count; ++die_idx) + { + const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); + const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL); + + if (name) + { + pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name); + } + } + + if (pubnames_set.NumDescriptors() > 0) + { + m_sets.push_back(pubnames_set); + } + } + } + return !m_sets.empty(); +} + +void +DWARFDebugPubnames::Dump(Log *s) const +{ + if (m_sets.empty()) + s->PutCString("< EMPTY >\n"); + else + { + const_iterator pos; + const_iterator end = m_sets.end(); + + for (pos = m_sets.begin(); pos != end; ++pos) + (*pos).Dump(s); + } +} + +bool +DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const +{ + const_iterator pos; + const_iterator end = m_sets.end(); + + die_offsets.clear(); + + for (pos = m_sets.begin(); pos != end; ++pos) + { + (*pos).Find(name, ignore_case, die_offsets); + } + + return !die_offsets.empty(); +} + +bool +DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const +{ + const_iterator pos; + const_iterator end = m_sets.end(); + + die_offsets.clear(); + + for (pos = m_sets.begin(); pos != end; ++pos) + { + (*pos).Find(regex, die_offsets); + } + + return !die_offsets.empty(); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h new file mode 100644 index 00000000000..7d09bf3b55a --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h @@ -0,0 +1,38 @@ +//===-- DWARFDebugPubnames.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugPubnames_h_ +#define SymbolFileDWARF_DWARFDebugPubnames_h_ + +#include "SymbolFileDWARF.h" + +#include <list> + +#include "DWARFDebugPubnamesSet.h" + +class DWARFDebugPubnames +{ +public: + DWARFDebugPubnames(); + bool Extract(const lldb_private::DataExtractor& data); + bool GeneratePubnames(SymbolFileDWARF* dwarf2Data); + bool GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data); + + void Dump(lldb_private::Log *s) const; + bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const; + bool Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const; +protected: + typedef std::list<DWARFDebugPubnamesSet> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + collection m_sets; +}; + +#endif // SymbolFileDWARF_DWARFDebugPubnames_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp new file mode 100644 index 00000000000..0421ced55d4 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp @@ -0,0 +1,166 @@ +//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugPubnamesSet.h" + +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Log.h" + +#include "SymbolFileDWARF.h" + +using namespace lldb_private; + +DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() : + m_offset(DW_INVALID_OFFSET), + m_header(), + m_descriptors(), + m_name_to_descriptor_index() +{ +} + +DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t cu_die_length) : + m_offset(debug_aranges_offset), + m_header(), + m_descriptors(), + m_name_to_descriptor_index() +{ + m_header.length = 10; // set the length to only include the header right for now + m_header.version = 2; // The DWARF version number + m_header.die_offset = cu_die_offset;// compile unit .debug_info offset + m_header.die_length = cu_die_length;// compile unit .debug_info length +} + +void +DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, const char* name) +{ + if (name && name[0]) + { + // Adjust our header length + m_header.length += strlen(name) + 1 + sizeof(dw_offset_t); + Descriptor pubnameDesc(cu_rel_offset, name); + m_descriptors.push_back(pubnameDesc); + } +} + +void +DWARFDebugPubnamesSet::Clear() +{ + m_offset = DW_INVALID_OFFSET; + m_header.length = 10; + m_header.version = 2; + m_header.die_offset = DW_INVALID_OFFSET; + m_header.die_length = 0; + m_descriptors.clear(); +} + + +//---------------------------------------------------------------------- +// InitNameIndexes +//---------------------------------------------------------------------- +void +DWARFDebugPubnamesSet::InitNameIndexes() const +{ + // Create the name index vector to be able to quickly search by name + const size_t count = m_descriptors.size(); + for (uint32_t idx = 0; idx < count; ++idx) + { + const char* name = m_descriptors[idx].name.c_str(); + if (name && name[0]) + m_name_to_descriptor_index.insert(cstr_to_index_mmap::value_type(name, idx)); + } +} + + +bool +DWARFDebugPubnamesSet::Extract(const DataExtractor& data, uint32_t* offset_ptr) +{ + if (data.ValidOffset(*offset_ptr)) + { + m_descriptors.clear(); + m_offset = *offset_ptr; + m_header.length = data.GetU32(offset_ptr); + m_header.version = data.GetU16(offset_ptr); + m_header.die_offset = data.GetU32(offset_ptr); + m_header.die_length = data.GetU32(offset_ptr); + + Descriptor pubnameDesc; + while (data.ValidOffset(*offset_ptr)) + { + pubnameDesc.offset = data.GetU32(offset_ptr); + + if (pubnameDesc.offset) + { + const char* name = data.GetCStr(offset_ptr); + if (name && name[0]) + { + pubnameDesc.name = name; + m_descriptors.push_back(pubnameDesc); + } + } + else + break; // We are done if we get a zero 4 byte offset + } + + return !m_descriptors.empty(); + } + return false; +} + +dw_offset_t +DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const +{ + return m_offset + m_header.length + 4; +} + +void +DWARFDebugPubnamesSet::Dump(Log *log) const +{ + log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, die_offset = 0x%8.8x, die_length = 0x%8.8x", + m_header.length, + m_header.version, + m_header.die_offset, + m_header.die_length); + + bool verbose = log->GetVerbose(); + + DescriptorConstIter pos; + DescriptorConstIter end = m_descriptors.end(); + for (pos = m_descriptors.begin(); pos != end; ++pos) + { + if (verbose) + log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, m_header.die_offset, pos->offset + m_header.die_offset, pos->name.c_str()); + else + log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, pos->name.c_str()); + } +} + + +void +DWARFDebugPubnamesSet::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const +{ + if (!m_descriptors.empty() && m_name_to_descriptor_index.empty()) + InitNameIndexes(); + + std::pair<cstr_to_index_mmap::const_iterator, cstr_to_index_mmap::const_iterator> range(m_name_to_descriptor_index.equal_range(name)); + for (cstr_to_index_mmap::const_iterator pos = range.first; pos != range.second; ++pos) + die_offset_coll.push_back(m_header.die_offset + m_descriptors[(*pos).second].offset); +} + +void +DWARFDebugPubnamesSet::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offset_coll) const +{ + DescriptorConstIter pos; + DescriptorConstIter end = m_descriptors.end(); + for (pos = m_descriptors.begin(); pos != end; ++pos) + { + if ( regex.Execute(pos->name.c_str()) ) + die_offset_coll.push_back(m_header.die_offset + pos->offset); + } +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h new file mode 100644 index 00000000000..0597e368e1f --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h @@ -0,0 +1,91 @@ +//===-- DWARFDebugPubnamesSet.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugPubnamesSet_h_ +#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_ + +#include "SymbolFileDWARF.h" +#include <string> +#include <vector> +#include <ext/hash_map> + +class DWARFDebugPubnamesSet +{ +public: + struct Header + { + uint32_t length; // length of the set of entries for this compilation unit, not including the length field itself + uint16_t version; // The DWARF version number + uint32_t die_offset; // compile unit .debug_info offset + uint32_t die_length; // compile unit .debug_info length + Header() : + length(10), + version(2), + die_offset(DW_INVALID_OFFSET), + die_length(0) + { + } + }; + + struct Descriptor + { + Descriptor() : + offset(), + name() + { + } + + Descriptor(dw_offset_t the_offset, const char *the_name) : + offset(the_offset), + name(the_name ? the_name : "") + { + } + + dw_offset_t offset; + std::string name; + }; + + DWARFDebugPubnamesSet(); + DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t die_length); + dw_offset_t GetOffset() const { return m_offset; } + void SetOffset(dw_offset_t offset) { m_offset = offset; } + DWARFDebugPubnamesSet::Header& GetHeader() { return m_header; } + const DWARFDebugPubnamesSet::Header& GetHeader() const { return m_header; } + const DWARFDebugPubnamesSet::Descriptor* GetDescriptor(uint32_t i) const + { + if (i < m_descriptors.size()) + return &m_descriptors[i]; + return NULL; + } + uint32_t NumDescriptors() const { return m_descriptors.size(); } + void AddDescriptor(dw_offset_t cu_rel_offset, const char* name); + void Clear(); + bool Extract(const lldb_private::DataExtractor& debug_pubnames_data, uint32_t* offset_ptr); + void Dump(lldb_private::Log *s) const; + void InitNameIndexes() const; + void Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const; + void Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const; + dw_offset_t GetOffsetOfNextEntry() const; + + + +protected: + typedef std::vector<Descriptor> DescriptorColl; + typedef DescriptorColl::iterator DescriptorIter; + typedef DescriptorColl::const_iterator DescriptorConstIter; + + + dw_offset_t m_offset; + Header m_header; + typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap; + DescriptorColl m_descriptors; + mutable cstr_to_index_mmap m_name_to_descriptor_index; +}; + +#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp new file mode 100644 index 00000000000..62da22855f7 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -0,0 +1,275 @@ +//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugRanges.h" +#include "SymbolFileDWARF.h" +#include "lldb/Core/Stream.h" +#include <assert.h> + +using namespace lldb_private; +using namespace std; + +DWARFDebugRanges::DWARFDebugRanges() : + m_range_map() +{ +} + +DWARFDebugRanges::~DWARFDebugRanges() +{ +} + +void +DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data) +{ + RangeList range_list; + dw_offset_t offset = 0; + dw_offset_t debug_ranges_offset = offset; + while (range_list.Extract(dwarf2Data, &offset)) + { + m_range_map[debug_ranges_offset] = range_list; + debug_ranges_offset = offset; + } +} + +bool +DWARFDebugRanges::RangeList::AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr) +{ + if (lo_addr <= hi_addr) + { + Range range(lo_addr, hi_addr); + ranges.push_back(range); + return true; + } + return false; +} + +const DWARFDebugRanges::Range* +DWARFDebugRanges::RangeList::Lookup(dw_addr_t offset) const +{ + Range::const_iterator pos = ranges.begin(); + Range::const_iterator end_pos = ranges.end(); + for (pos = ranges.begin(); pos != end_pos; ++pos) + { + if (pos->begin_offset <= offset && offset < pos->end_offset) + { + return &(*pos); + } + } + return NULL; +} + +size_t +DWARFDebugRanges::RangeList::Size() const +{ + return ranges.size(); +} + +void +DWARFDebugRanges::RangeList::AddOffset(dw_addr_t offset) +{ + if (!ranges.empty()) + { + Range::iterator pos = ranges.begin(); + Range::iterator end_pos = ranges.end(); + for (pos = ranges.begin(); pos != end_pos; ++pos) + { + // assert for unsigned overflows + assert (~pos->begin_offset >= offset); + assert (~pos->end_offset >= offset); + pos->begin_offset += offset; + pos->end_offset += offset; + } + } +} + +void +DWARFDebugRanges::RangeList::SubtractOffset(dw_addr_t offset) +{ + if (!ranges.empty()) + { + Range::iterator pos = ranges.begin(); + Range::iterator end_pos = ranges.end(); + for (pos = ranges.begin(); pos != end_pos; ++pos) + { + assert (pos->begin_offset >= offset); + assert (pos->end_offset >= offset); + pos->begin_offset -= offset; + pos->end_offset -= offset; + } + } +} + + +const DWARFDebugRanges::Range* +DWARFDebugRanges::RangeList::RangeAtIndex(size_t i) const +{ + if (i < ranges.size()) + return &ranges[i]; + return NULL; +} + +bool +DWARFDebugRanges::RangeList::Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr) +{ + Clear(); + uint32_t range_offset = *offset_ptr; + const DataExtractor& debug_ranges_data = dwarf2Data->get_debug_ranges_data(); + uint32_t addr_size = debug_ranges_data.GetAddressByteSize(); + + while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) + { + dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + if (!begin && !end) + { + // End of range list + break; + } + // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits + // of ones + switch (addr_size) + { + case 2: + if (begin == 0xFFFFull) + begin = DW_INVALID_ADDRESS; + break; + + case 4: + if (begin == 0xFFFFFFFFull) + begin = DW_INVALID_ADDRESS; + break; + + case 8: + break; + + default: + assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size."); + break; + } + + // Filter out empty ranges + if (begin != end) + ranges.push_back(Range(begin, end)); + } + + // Make sure we consumed at least something + return range_offset != *offset_ptr; +} + + +dw_addr_t +DWARFDebugRanges::RangeList::LowestAddress(const dw_addr_t cu_base_addr) const +{ + dw_addr_t addr = DW_INVALID_ADDRESS; + dw_addr_t curr_base_addr = cu_base_addr; + if (!ranges.empty()) + { + Range::const_iterator pos = ranges.begin(); + Range::const_iterator end_pos = ranges.end(); + for (pos = ranges.begin(); pos != end_pos; ++pos) + { + if (pos->begin_offset == DW_INVALID_ADDRESS) + curr_base_addr = pos->end_offset; + else if (curr_base_addr != DW_INVALID_ADDRESS) + { + dw_addr_t curr_addr = curr_base_addr + pos->begin_offset; + if (addr > curr_addr) + addr = curr_addr; + } + } + } + return addr; +} + +dw_addr_t +DWARFDebugRanges::RangeList::HighestAddress(const dw_addr_t cu_base_addr) const +{ + dw_addr_t addr = 0; + dw_addr_t curr_base_addr = cu_base_addr; + if (!ranges.empty()) + { + Range::const_iterator pos = ranges.begin(); + Range::const_iterator end_pos = ranges.end(); + for (pos = ranges.begin(); pos != end_pos; ++pos) + { + if (pos->begin_offset == DW_INVALID_ADDRESS) + curr_base_addr = pos->end_offset; + else if (curr_base_addr != DW_INVALID_ADDRESS) + { + dw_addr_t curr_addr = curr_base_addr + pos->end_offset; + if (addr < curr_addr) + addr = curr_addr; + } + } + } + if (addr != 0) + return addr; + return DW_INVALID_ADDRESS; +} + + +void +DWARFDebugRanges::Dump(Stream *s, const DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr) +{ + uint32_t addr_size = s->GetAddressByteSize(); + bool verbose = s->GetVerbose(); + + dw_addr_t base_addr = cu_base_addr; + while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) + { + dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); + // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits + // of ones + if (begin == 0xFFFFFFFFull && addr_size == 4) + begin = DW_INVALID_ADDRESS; + + s->Indent(); + if (verbose) + { + s->AddressRange(begin, end, sizeof (dw_addr_t), " offsets = "); + } + + + if (begin == 0 && end == 0) + { + s->PutCString(" End"); + break; + } + else if (begin == DW_INVALID_ADDRESS) + { + // A base address selection entry + base_addr = end; + s->Address(base_addr, sizeof (dw_addr_t), " Base address = "); + } + else + { + // Convert from offset to an address + dw_addr_t begin_addr = begin + base_addr; + dw_addr_t end_addr = end + base_addr; + + s->AddressRange(begin_addr, end_addr, sizeof (dw_addr_t), verbose ? " ==> addrs = " : NULL); + } + } +} + +bool +DWARFDebugRanges::FindRanges(dw_offset_t debug_ranges_offset, RangeList& range_list) const +{ + range_map_const_iterator pos = m_range_map.find(debug_ranges_offset); + if (pos != m_range_map.end()) + { + range_list = pos->second; + return true; + } + return false; +} + + + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h new file mode 100644 index 00000000000..607c3c24a3e --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -0,0 +1,89 @@ +//===-- DWARFDebugRanges.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDebugRanges_h_ +#define liblldb_DWARFDebugRanges_h_ + +#include "SymbolFileDWARF.h" +#include <map> +#include <vector> + + +class DWARFDebugRanges +{ +public: + + //------------------------------------------------------------------ + // Address range + //------------------------------------------------------------------ + struct Range + { + Range(dw_addr_t begin = DW_INVALID_ADDRESS, dw_addr_t end = DW_INVALID_ADDRESS) : + begin_offset(begin), + end_offset(end) + { + } + + void Clear() + { + begin_offset = DW_INVALID_ADDRESS; + end_offset = DW_INVALID_ADDRESS; + } + + dw_addr_t begin_offset; + dw_addr_t end_offset; + + typedef std::vector<Range> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + }; + + //------------------------------------------------------------------ + // Collection of ranges + //------------------------------------------------------------------ + struct RangeList + { + RangeList() : + ranges() + { + } + + bool Extract(SymbolFileDWARF* dwarf2Data, uint32_t* offset_ptr); + bool AddRange(dw_addr_t lo_addr, dw_addr_t hi_addr); + void Clear() + { + ranges.clear(); + } + + dw_addr_t LowestAddress(const dw_addr_t base_addr) const; + dw_addr_t HighestAddress(const dw_addr_t base_addr) const; + void AddOffset(dw_addr_t offset); + void SubtractOffset(dw_addr_t offset); + size_t Size() const; + const Range* RangeAtIndex(size_t i) const; + const Range* Lookup(dw_addr_t offset) const; + Range::collection ranges; + }; + + DWARFDebugRanges(); + ~DWARFDebugRanges(); + void Extract(SymbolFileDWARF* dwarf2Data); + static void Dump(lldb_private::Stream *s, const lldb_private::DataExtractor& debug_ranges_data, uint32_t* offset_ptr, dw_addr_t cu_base_addr); + bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const; + +protected: + typedef std::map<dw_offset_t, RangeList> range_map; + typedef range_map::iterator range_map_iterator; + typedef range_map::const_iterator range_map_const_iterator; + range_map m_range_map; +}; + + +#endif // liblldb_DWARFDebugRanges_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c new file mode 100644 index 00000000000..fe487f9b792 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.c @@ -0,0 +1,2224 @@ +//===-- DWARFDefines.c ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDefines.h" +#include <stdio.h> + +#define DW_TAG_PREFIX "TAG_" +#define DW_AT_PREFIX " AT_" +#define DW_FORM_PREFIX "FORM_" + +/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */ + +const char * +DW_TAG_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0000: return DW_TAG_PREFIX "NULL"; + case 0x0001: return DW_TAG_PREFIX "array_type"; + case 0x0002: return DW_TAG_PREFIX "class_type"; + case 0x0003: return DW_TAG_PREFIX "entry_point"; + case 0x0004: return DW_TAG_PREFIX "enumeration_type"; + case 0x0005: return DW_TAG_PREFIX "formal_parameter"; + case 0x0008: return DW_TAG_PREFIX "imported_declaration"; + case 0x000a: return DW_TAG_PREFIX "label"; + case 0x000b: return DW_TAG_PREFIX "lexical_block"; + case 0x000d: return DW_TAG_PREFIX "member"; + case 0x000f: return DW_TAG_PREFIX "pointer_type"; + case 0x0010: return DW_TAG_PREFIX "reference_type"; + case 0x0011: return DW_TAG_PREFIX "compile_unit"; + case 0x0012: return DW_TAG_PREFIX "string_type"; + case 0x0013: return DW_TAG_PREFIX "structure_type"; + case 0x0015: return DW_TAG_PREFIX "subroutine_type"; + case 0x0016: return DW_TAG_PREFIX "typedef"; + case 0x0017: return DW_TAG_PREFIX "union_type"; + case 0x0018: return DW_TAG_PREFIX "unspecified_parameters"; + case 0x0019: return DW_TAG_PREFIX "variant"; + case 0x001a: return DW_TAG_PREFIX "common_block"; + case 0x001b: return DW_TAG_PREFIX "common_inclusion"; + case 0x001c: return DW_TAG_PREFIX "inheritance"; + case 0x001d: return DW_TAG_PREFIX "inlined_subroutine"; + case 0x001e: return DW_TAG_PREFIX "module"; + case 0x001f: return DW_TAG_PREFIX "ptr_to_member_type"; + case 0x0020: return DW_TAG_PREFIX "set_type"; + case 0x0021: return DW_TAG_PREFIX "subrange_type"; + case 0x0022: return DW_TAG_PREFIX "with_stmt"; + case 0x0023: return DW_TAG_PREFIX "access_declaration"; + case 0x0024: return DW_TAG_PREFIX "base_type"; + case 0x0025: return DW_TAG_PREFIX "catch_block"; + case 0x0026: return DW_TAG_PREFIX "const_type"; + case 0x0027: return DW_TAG_PREFIX "constant"; + case 0x0028: return DW_TAG_PREFIX "enumerator"; + case 0x0029: return DW_TAG_PREFIX "file_type"; + case 0x002a: return DW_TAG_PREFIX "friend"; + case 0x002b: return DW_TAG_PREFIX "namelist"; + case 0x002c: return DW_TAG_PREFIX "namelist_item"; + case 0x002d: return DW_TAG_PREFIX "packed_type"; + case 0x002e: return DW_TAG_PREFIX "subprogram"; + case 0x002f: return DW_TAG_PREFIX "template_type_parameter"; + case 0x0030: return DW_TAG_PREFIX "template_value_parameter"; + case 0x0031: return DW_TAG_PREFIX "thrown_type"; + case 0x0032: return DW_TAG_PREFIX "try_block"; + case 0x0033: return DW_TAG_PREFIX "variant_part"; + case 0x0034: return DW_TAG_PREFIX "variable"; + case 0x0035: return DW_TAG_PREFIX "volatile_type"; + case 0x0036: return DW_TAG_PREFIX "dwarf_procedure"; + case 0x0037: return DW_TAG_PREFIX "restrict_type"; + case 0x0038: return DW_TAG_PREFIX "interface_type"; + case 0x0039: return DW_TAG_PREFIX "namespace"; + case 0x003a: return DW_TAG_PREFIX "imported_module"; + case 0x003b: return DW_TAG_PREFIX "unspecified_type"; + case 0x003c: return DW_TAG_PREFIX "partial_unit"; + case 0x003d: return DW_TAG_PREFIX "imported_unit"; +// case 0x003d: return DW_TAG_PREFIX "condition"; + case 0x0040: return DW_TAG_PREFIX "shared_type"; + case 0x4080: return DW_TAG_PREFIX "lo_user"; + case 0xffff: return DW_TAG_PREFIX "hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_TAG_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0001: return "array type"; + case 0x0002: return "class type"; + case 0x0003: return "entry point"; + case 0x0004: return "enumeration type"; + case 0x0005: return "formal parameter"; + case 0x0008: return "imported declaration"; + case 0x000a: return "label"; + case 0x000b: return "lexical block"; + case 0x000d: return "member"; + case 0x000f: return "pointer type"; + case 0x0010: return "reference type"; + case 0x0011: return "file"; + case 0x0012: return "string type"; + case 0x0013: return "structure type"; + case 0x0015: return "subroutine type"; + case 0x0016: return "typedef"; + case 0x0017: return "union type"; + case 0x0018: return "unspecified parameters"; + case 0x0019: return "variant"; + case 0x001a: return "common block"; + case 0x001b: return "common inclusion"; + case 0x001c: return "inheritance"; + case 0x001d: return "inlined subroutine"; + case 0x001e: return "module"; + case 0x001f: return "ptr to member type"; + case 0x0020: return "set type"; + case 0x0021: return "subrange type"; + case 0x0022: return "with stmt"; + case 0x0023: return "access declaration"; + case 0x0024: return "base type"; + case 0x0025: return "catch block"; + case 0x0026: return "const type"; + case 0x0027: return "constant"; + case 0x0028: return "enumerator"; + case 0x0029: return "file type"; + case 0x002a: return "friend"; + case 0x002b: return "namelist"; + case 0x002c: return "namelist item"; + case 0x002d: return "packed type"; + case 0x002e: return "function"; + case 0x002f: return "template type parameter"; + case 0x0030: return "template value parameter"; + case 0x0031: return "thrown type"; + case 0x0032: return "try block"; + case 0x0033: return "variant part"; + case 0x0034: return "variable"; + case 0x0035: return "volatile type"; + case 0x0036: return "dwarf procedure"; + case 0x0037: return "restrict type"; + case 0x0038: return "interface type"; + case 0x0039: return "namespace"; + case 0x003a: return "imported module"; + case 0x003b: return "unspecified type"; + case 0x003c: return "partial unit"; + case 0x003d: return "imported unit"; +// case 0x003d: return "condition"; + case 0x0040: return "shared type"; + case 0x4080: return "lo user"; + case 0xffff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_TAG_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0001: return 0; + case 0x0002: return 0; + case 0x0003: return 0; + case 0x0004: return 0; + case 0x0005: return 0; + case 0x0008: return 0; + case 0x000a: return 0; + case 0x000b: return 0; + case 0x000d: return 0; + case 0x000f: return 0; + case 0x0010: return 0; + case 0x0011: return 0; + case 0x0012: return 0; + case 0x0013: return 0; + case 0x0015: return 0; + case 0x0016: return 0; + case 0x0017: return 0; + case 0x0018: return 0; + case 0x0019: return 0; + case 0x001a: return 0; + case 0x001b: return 0; + case 0x001c: return 0; + case 0x001d: return 0; + case 0x001e: return 0; + case 0x001f: return 0; + case 0x0020: return 0; + case 0x0021: return 0; + case 0x0022: return 0; + case 0x0023: return 0; + case 0x0024: return 0; + case 0x0025: return 0; + case 0x0026: return 0; + case 0x0027: return 0; + case 0x0028: return 0; + case 0x0029: return 0; + case 0x002a: return 0; + case 0x002b: return 0; + case 0x002c: return 0; + case 0x002d: return 0; + case 0x002e: return 0; + case 0x002f: return 0; + case 0x0030: return 0; + case 0x0031: return 0; + case 0x0032: return 0; + case 0x0033: return 0; + case 0x0034: return 0; + case 0x0035: return 0; + case 0x0036: return DRC_DWARFv3; + case 0x0037: return DRC_DWARFv3; + case 0x0038: return DRC_DWARFv3; + case 0x0039: return DRC_DWARFv3; + case 0x003a: return DRC_DWARFv3; + case 0x003b: return DRC_DWARFv3; + case 0x003c: return DRC_DWARFv3; + case 0x003d: return DRC_DWARFv3; +// case 0x003d: return DRC_DWARFv3; + case 0x0040: return DRC_DWARFv3; + case 0x4080: return 0; + case 0xffff: return 0; + default: return 0; + } +} + +/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */ + +const char * +DW_CHILDREN_value_to_name (uint8_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_CHILDREN_no"; + case 0x1: return "DW_CHILDREN_yes"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_CHILDREN_value_to_englishy_name (uint8_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "no"; + case 0x1: return "yes"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CHILDREN constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_CHILDREN_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + default: return 0; + } +} + +/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */ + +const char * +DW_AT_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0001: return DW_AT_PREFIX "sibling"; + case 0x0002: return DW_AT_PREFIX "location"; + case 0x0003: return DW_AT_PREFIX "name"; + case 0x0009: return DW_AT_PREFIX "ordering"; + case 0x000b: return DW_AT_PREFIX "byte_size"; + case 0x000c: return DW_AT_PREFIX "bit_offset"; + case 0x000d: return DW_AT_PREFIX "bit_size"; + case 0x0010: return DW_AT_PREFIX "stmt_list"; + case 0x0011: return DW_AT_PREFIX "low_pc"; + case 0x0012: return DW_AT_PREFIX "high_pc"; + case 0x0013: return DW_AT_PREFIX "language"; + case 0x0015: return DW_AT_PREFIX "discr"; + case 0x0016: return DW_AT_PREFIX "discr_value"; + case 0x0017: return DW_AT_PREFIX "visibility"; + case 0x0018: return DW_AT_PREFIX "import"; + case 0x0019: return DW_AT_PREFIX "string_length"; + case 0x001a: return DW_AT_PREFIX "common_reference"; + case 0x001b: return DW_AT_PREFIX "comp_dir"; + case 0x001c: return DW_AT_PREFIX "const_value"; + case 0x001d: return DW_AT_PREFIX "containing_type"; + case 0x001e: return DW_AT_PREFIX "default_value"; + case 0x0020: return DW_AT_PREFIX "inline"; + case 0x0021: return DW_AT_PREFIX "is_optional"; + case 0x0022: return DW_AT_PREFIX "lower_bound"; + case 0x0025: return DW_AT_PREFIX "producer"; + case 0x0027: return DW_AT_PREFIX "prototyped"; + case 0x002a: return DW_AT_PREFIX "return_addr"; + case 0x002c: return DW_AT_PREFIX "start_scope"; + case 0x002e: return DW_AT_PREFIX "bit_stride"; + case 0x002f: return DW_AT_PREFIX "upper_bound"; + case 0x0031: return DW_AT_PREFIX "abstract_origin"; + case 0x0032: return DW_AT_PREFIX "accessibility"; + case 0x0033: return DW_AT_PREFIX "address_class"; + case 0x0034: return DW_AT_PREFIX "artificial"; + case 0x0035: return DW_AT_PREFIX "base_types"; + case 0x0036: return DW_AT_PREFIX "calling_convention"; + case 0x0037: return DW_AT_PREFIX "count"; + case 0x0038: return DW_AT_PREFIX "data_member_location"; + case 0x0039: return DW_AT_PREFIX "decl_column"; + case 0x003a: return DW_AT_PREFIX "decl_file"; + case 0x003b: return DW_AT_PREFIX "decl_line"; + case 0x003c: return DW_AT_PREFIX "declaration"; + case 0x003d: return DW_AT_PREFIX "discr_list"; + case 0x003e: return DW_AT_PREFIX "encoding"; + case 0x003f: return DW_AT_PREFIX "external"; + case 0x0040: return DW_AT_PREFIX "frame_base"; + case 0x0041: return DW_AT_PREFIX "friend"; + case 0x0042: return DW_AT_PREFIX "identifier_case"; + case 0x0043: return DW_AT_PREFIX "macro_info"; + case 0x0044: return DW_AT_PREFIX "namelist_item"; + case 0x0045: return DW_AT_PREFIX "priority"; + case 0x0046: return DW_AT_PREFIX "segment"; + case 0x0047: return DW_AT_PREFIX "specification"; + case 0x0048: return DW_AT_PREFIX "static_link"; + case 0x0049: return DW_AT_PREFIX "type"; + case 0x004a: return DW_AT_PREFIX "use_location"; + case 0x004b: return DW_AT_PREFIX "variable_parameter"; + case 0x004c: return DW_AT_PREFIX "virtuality"; + case 0x004d: return DW_AT_PREFIX "vtable_elem_location"; + case 0x004e: return DW_AT_PREFIX "allocated"; + case 0x004f: return DW_AT_PREFIX "associated"; + case 0x0050: return DW_AT_PREFIX "data_location"; + case 0x0051: return DW_AT_PREFIX "byte_stride"; + case 0x0052: return DW_AT_PREFIX "entry_pc"; + case 0x0053: return DW_AT_PREFIX "use_UTF8"; + case 0x0054: return DW_AT_PREFIX "extension"; + case 0x0055: return DW_AT_PREFIX "ranges"; + case 0x0056: return DW_AT_PREFIX "trampoline"; + case 0x0057: return DW_AT_PREFIX "call_column"; + case 0x0058: return DW_AT_PREFIX "call_file"; + case 0x0059: return DW_AT_PREFIX "call_line"; + case 0x005a: return DW_AT_PREFIX "description"; + case 0x005b: return DW_AT_PREFIX "binary_scale"; + case 0x005c: return DW_AT_PREFIX "decimal_scale"; + case 0x005d: return DW_AT_PREFIX "small"; + case 0x005e: return DW_AT_PREFIX "decimal_sign"; + case 0x005f: return DW_AT_PREFIX "digit_count"; + case 0x0060: return DW_AT_PREFIX "picture_string"; + case 0x0061: return DW_AT_PREFIX "mutable"; + case 0x0062: return DW_AT_PREFIX "threads_scaled"; + case 0x0063: return DW_AT_PREFIX "explicit"; + case 0x0064: return DW_AT_PREFIX "object_pointer"; + case 0x0065: return DW_AT_PREFIX "endianity"; + case 0x0066: return DW_AT_PREFIX "elemental"; + case 0x0067: return DW_AT_PREFIX "pure"; + case 0x0068: return DW_AT_PREFIX "recursive"; + case 0x2000: return DW_AT_PREFIX "lo_user"; + case 0x3fff: return DW_AT_PREFIX "hi_user"; + case 0x2001: return DW_AT_PREFIX "MIPS_fde"; + case 0x2002: return DW_AT_PREFIX "MIPS_loop_begin"; + case 0x2003: return DW_AT_PREFIX "MIPS_tail_loop_begin"; + case 0x2004: return DW_AT_PREFIX "MIPS_epilog_begin"; + case 0x2005: return DW_AT_PREFIX "MIPS_loop_unroll_factor"; + case 0x2006: return DW_AT_PREFIX "MIPS_software_pipeline_depth"; + case 0x2007: return DW_AT_PREFIX "MIPS_linkage_name"; + case 0x2008: return DW_AT_PREFIX "MIPS_stride"; + case 0x2009: return DW_AT_PREFIX "MIPS_abstract_name"; + case 0x200a: return DW_AT_PREFIX "MIPS_clone_origin"; + case 0x200b: return DW_AT_PREFIX "MIPS_has_inlines"; + case 0x2101: return DW_AT_PREFIX "sf_names"; + case 0x2102: return DW_AT_PREFIX "src_info"; + case 0x2103: return DW_AT_PREFIX "mac_info"; + case 0x2104: return DW_AT_PREFIX "src_coords"; + case 0x2105: return DW_AT_PREFIX "body_begin"; + case 0x2106: return DW_AT_PREFIX "body_end"; + case 0x2107: return DW_AT_PREFIX "GNU_vector"; + case 0x2501: return DW_AT_PREFIX "APPLE_repository_file"; + case 0x2502: return DW_AT_PREFIX "APPLE_repository_type"; + case 0x2503: return DW_AT_PREFIX "APPLE_repository_name"; + case 0x2504: return DW_AT_PREFIX "APPLE_repository_specification"; + case 0x2505: return DW_AT_PREFIX "APPLE_repository_import"; + case 0x2506: return DW_AT_PREFIX "APPLE_repository_abstract_origin"; + case DW_AT_APPLE_flags: return DW_AT_PREFIX "APPLE_flags"; + case DW_AT_APPLE_optimized: return DW_AT_PREFIX "APPLE_optimized"; + case DW_AT_APPLE_isa: return DW_AT_PREFIX "APPLE_isa"; + case DW_AT_APPLE_block: return DW_AT_PREFIX "APPLE_block"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_AT_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0001: return "sibling"; + case 0x0002: return "location"; + case 0x0003: return "name"; + case 0x0009: return "ordering"; + case 0x000b: return "byte size"; + case 0x000c: return "bit offset"; + case 0x000d: return "bit size"; + case 0x0010: return "stmt list"; + case 0x0011: return "low pc"; + case 0x0012: return "high pc"; + case 0x0013: return "language"; + case 0x0015: return "discr"; + case 0x0016: return "discr value"; + case 0x0017: return "visibility"; + case 0x0018: return "import"; + case 0x0019: return "string length"; + case 0x001a: return "common reference"; + case 0x001b: return "comp dir"; + case 0x001c: return "const value"; + case 0x001d: return "containing type"; + case 0x001e: return "default value"; + case 0x0020: return "inline"; + case 0x0021: return "is optional"; + case 0x0022: return "lower bound"; + case 0x0025: return "producer"; + case 0x0027: return "prototyped"; + case 0x002a: return "return addr"; + case 0x002c: return "start scope"; + case 0x002e: return "bit stride"; + case 0x002f: return "upper bound"; + case 0x0031: return "abstract origin"; + case 0x0032: return "accessibility"; + case 0x0033: return "address class"; + case 0x0034: return "artificial"; + case 0x0035: return "base types"; + case 0x0036: return "calling convention"; + case 0x0037: return "count"; + case 0x0038: return "data member location"; + case 0x0039: return "decl column"; + case 0x003a: return "decl file"; + case 0x003b: return "decl line"; + case 0x003c: return "declaration"; + case 0x003d: return "discr list"; + case 0x003e: return "encoding"; + case 0x003f: return "external"; + case 0x0040: return "frame base"; + case 0x0041: return "friend"; + case 0x0042: return "identifier case"; + case 0x0043: return "macro info"; + case 0x0044: return "namelist item"; + case 0x0045: return "priority"; + case 0x0046: return "segment"; + case 0x0047: return "specification"; + case 0x0048: return "static link"; + case 0x0049: return "type"; + case 0x004a: return "use location"; + case 0x004b: return "variable parameter"; + case 0x004c: return "virtuality"; + case 0x004d: return "vtable elem location"; + case 0x004e: return "allocated"; + case 0x004f: return "associated"; + case 0x0050: return "data location"; + case 0x0051: return "byte stride"; + case 0x0052: return "entry pc"; + case 0x0053: return "use UTF8"; + case 0x0054: return "extension"; + case 0x0055: return "ranges"; + case 0x0056: return "trampoline"; + case 0x0057: return "call column"; + case 0x0058: return "call file"; + case 0x0059: return "call line"; + case 0x005a: return "description"; + case 0x005b: return "binary scale"; + case 0x005c: return "decimal scale"; + case 0x005d: return "small"; + case 0x005e: return "decimal sign"; + case 0x005f: return "digit count"; + case 0x0060: return "picture string"; + case 0x0061: return "mutable"; + case 0x0062: return "threads scaled"; + case 0x0063: return "explicit"; + case 0x0064: return "object pointer"; + case 0x0065: return "endianity"; + case 0x0066: return "elemental"; + case 0x0067: return "pure"; + case 0x0068: return "recursive"; + case 0x2000: return "lo user"; + case 0x3fff: return "hi user"; + case 0x2001: return "MIPS fde"; + case 0x2002: return "MIPS loop begin"; + case 0x2003: return "MIPS tail loop begin"; + case 0x2004: return "MIPS epilog begin"; + case 0x2005: return "MIPS loop unroll factor"; + case 0x2006: return "MIPS software pipeline depth"; + case 0x2007: return "MIPS linkage name"; + case 0x2008: return "MIPS stride"; + case 0x2009: return "MIPS abstract name"; + case 0x200a: return "MIPS clone origin"; + case 0x200b: return "MIPS has inlines"; + case 0x2101: return "source file names"; + case 0x2102: return "source info"; + case 0x2103: return "macro info"; + case 0x2104: return "source coordinates"; + case 0x2105: return "body begin"; + case 0x2106: return "body end"; + case 0x2107: return "GNU vector"; + case 0x2501: return "repository file"; + case 0x2502: return "repository type"; + case 0x2503: return "repository name"; + case 0x2504: return "repository specification"; + case 0x2505: return "repository import"; + case 0x2506: return "repository abstract origin"; + case DW_AT_APPLE_flags: return "Apple gcc compiler flags"; + case DW_AT_APPLE_optimized: return "APPLE optimized"; + case DW_AT_APPLE_isa: return "APPLE instruction set architecture"; + case DW_AT_APPLE_block: return "APPLE block"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_AT_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0001: return DRC_REFERENCE; + case 0x0002: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x0003: return DRC_STRING; + case 0x0009: return DRC_CONSTANT; + case 0x000b: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x000c: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x000d: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x0010: return DRC_LINEPTR; + case 0x0011: return DRC_ADDRESS; + case 0x0012: return DRC_ADDRESS; + case 0x0013: return DRC_CONSTANT; + case 0x0015: return DRC_REFERENCE; + case 0x0016: return DRC_CONSTANT; + case 0x0017: return DRC_CONSTANT; + case 0x0018: return DRC_REFERENCE; + case 0x0019: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x001a: return DRC_REFERENCE; + case 0x001b: return DRC_STRING; + case 0x001c: return DRC_BLOCK | DRC_CONSTANT | DRC_STRING; + case 0x001d: return DRC_REFERENCE; + case 0x001e: return DRC_REFERENCE; + case 0x0020: return DRC_CONSTANT; + case 0x0021: return DRC_FLAG; + case 0x0022: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x0025: return DRC_STRING; + case 0x0027: return DRC_FLAG; + case 0x002a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x002c: return DRC_CONSTANT; + case 0x002e: return DRC_CONSTANT; + case 0x002f: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x0031: return DRC_REFERENCE; + case 0x0032: return DRC_CONSTANT; + case 0x0033: return DRC_CONSTANT; + case 0x0034: return DRC_FLAG; + case 0x0035: return DRC_REFERENCE; + case 0x0036: return DRC_CONSTANT; + case 0x0037: return DRC_BLOCK | DRC_CONSTANT | DRC_REFERENCE; + case 0x0038: return DRC_BLOCK | DRC_CONSTANT | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x0039: return DRC_CONSTANT; + case 0x003a: return DRC_CONSTANT; + case 0x003b: return DRC_CONSTANT; + case 0x003c: return DRC_FLAG; + case 0x003d: return DRC_BLOCK; + case 0x003e: return DRC_CONSTANT; + case 0x003f: return DRC_FLAG; + case 0x0040: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x0041: return DRC_REFERENCE; + case 0x0042: return DRC_CONSTANT; + case 0x0043: return DRC_MACPTR; + case 0x0044: return DRC_BLOCK; + case 0x0045: return DRC_REFERENCE; + case 0x0046: return DRC_BLOCK | DRC_CONSTANT; + case 0x0047: return DRC_REFERENCE; + case 0x0048: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x0049: return DRC_REFERENCE; + case 0x004a: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x004b: return DRC_FLAG; + case 0x004c: return DRC_CONSTANT; + case 0x004d: return DRC_BLOCK | DRC_LOCEXPR | DRC_LOCLISTPTR; + case 0x004e: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE; + case 0x004f: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE; + case 0x0050: return DRC_BLOCK | DRC_DWARFv3; + case 0x0051: return DRC_BLOCK | DRC_CONSTANT | DRC_DWARFv3 | DRC_REFERENCE; + case 0x0052: return DRC_ADDRESS | DRC_DWARFv3; + case 0x0053: return DRC_DWARFv3 | DRC_FLAG; + case 0x0054: return DRC_DWARFv3 | DRC_REFERENCE; + case 0x0055: return DRC_DWARFv3 | DRC_RANGELISTPTR; + case 0x0056: return DRC_ADDRESS | DRC_DWARFv3 | DRC_FLAG | DRC_REFERENCE | DRC_STRING; + case 0x0057: return DRC_CONSTANT | DRC_DWARFv3; + case 0x0058: return DRC_CONSTANT | DRC_DWARFv3; + case 0x0059: return DRC_CONSTANT | DRC_DWARFv3; + case 0x005a: return DRC_DWARFv3 | DRC_STRING; + case 0x005b: return DRC_CONSTANT | DRC_DWARFv3; + case 0x005c: return DRC_CONSTANT | DRC_DWARFv3; + case 0x005d: return DRC_DWARFv3 | DRC_REFERENCE; + case 0x005e: return DRC_CONSTANT | DRC_DWARFv3; + case 0x005f: return DRC_CONSTANT | DRC_DWARFv3; + case 0x0060: return DRC_DWARFv3 | DRC_STRING; + case 0x0061: return DRC_DWARFv3 | DRC_FLAG; + case 0x0062: return DRC_DWARFv3 | DRC_FLAG; + case 0x0063: return DRC_DWARFv3 | DRC_FLAG; + case 0x0064: return DRC_DWARFv3 | DRC_REFERENCE; + case 0x0065: return DRC_0x65 | DRC_CONSTANT | DRC_DWARFv3; + case 0x0066: return DRC_DWARFv3 | DRC_FLAG; + case 0x0067: return DRC_DWARFv3 | DRC_FLAG; + case 0x0068: return DRC_DWARFv3 | DRC_FLAG; + case 0x2000: return 0; + case 0x3fff: return 0; + case 0x2001: return DRC_VENDOR_MIPS; + case 0x2002: return DRC_VENDOR_MIPS; + case 0x2003: return DRC_VENDOR_MIPS; + case 0x2004: return DRC_VENDOR_MIPS; + case 0x2005: return DRC_VENDOR_MIPS; + case 0x2006: return DRC_VENDOR_MIPS; + case 0x2007: return DRC_STRING | DRC_VENDOR_MIPS; + case 0x2008: return DRC_VENDOR_MIPS; + case 0x2009: return DRC_VENDOR_MIPS; + case 0x200a: return DRC_VENDOR_MIPS; + case 0x200b: return DRC_VENDOR_MIPS; + default: return 0; + } +} + +/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */ + +const char * +DW_FORM_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return DW_FORM_PREFIX "addr"; + case 0x03: return DW_FORM_PREFIX "block2"; + case 0x04: return DW_FORM_PREFIX "block4"; + case 0x05: return DW_FORM_PREFIX "data2"; + case 0x06: return DW_FORM_PREFIX "data4"; + case 0x07: return DW_FORM_PREFIX "data8"; + case 0x08: return DW_FORM_PREFIX "string"; + case 0x09: return DW_FORM_PREFIX "block"; + case 0x0a: return DW_FORM_PREFIX "block1"; + case 0x0b: return DW_FORM_PREFIX "data1"; + case 0x0c: return DW_FORM_PREFIX "flag"; + case 0x0d: return DW_FORM_PREFIX "sdata"; + case 0x0e: return DW_FORM_PREFIX "strp"; + case 0x0f: return DW_FORM_PREFIX "udata"; + case 0x10: return DW_FORM_PREFIX "ref_addr"; + case 0x11: return DW_FORM_PREFIX "ref1"; + case 0x12: return DW_FORM_PREFIX "ref2"; + case 0x13: return DW_FORM_PREFIX "ref4"; + case 0x14: return DW_FORM_PREFIX "ref8"; + case 0x15: return DW_FORM_PREFIX "ref_udata"; + case 0x16: return DW_FORM_PREFIX "indirect"; +// case DW_FORM_APPLE_db_str: return DW_FORM_PREFIX "APPLE_db_str"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_FORM_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "addr"; + case 0x03: return "block2"; + case 0x04: return "block4"; + case 0x05: return "data2"; + case 0x06: return "data4"; + case 0x07: return "data8"; + case 0x08: return "string"; + case 0x09: return "block"; + case 0x0a: return "block1"; + case 0x0b: return "data1"; + case 0x0c: return "flag"; + case 0x0d: return "sdata"; + case 0x0e: return "strp"; + case 0x0f: return "udata"; + case 0x10: return "ref addr"; + case 0x11: return "ref1"; + case 0x12: return "ref2"; + case 0x13: return "ref4"; + case 0x14: return "ref8"; + case 0x15: return "ref udata"; + case 0x16: return "indirect"; +// case DW_FORM_APPLE_db_str: return "repository str"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_FORM_value_to_class (uint32_t val) +{ + switch (val) { + case 0x01: return DRC_ADDRESS; + case 0x03: return DRC_BLOCK | DRC_LOCEXPR; + case 0x04: return DRC_BLOCK | DRC_LOCEXPR; + case 0x05: return DRC_CONSTANT; + case 0x06: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR; + case 0x07: return DRC_CONSTANT | DRC_LINEPTR | DRC_LOCLISTPTR | DRC_MACPTR | DRC_RANGELISTPTR; + case 0x08: return DRC_STRING; + case 0x09: return DRC_BLOCK | DRC_LOCEXPR; + case 0x0a: return DRC_BLOCK | DRC_LOCEXPR; + case 0x0b: return DRC_CONSTANT; + case 0x0c: return DRC_FLAG; + case 0x0d: return DRC_CONSTANT; + case 0x0e: return DRC_STRING; + case 0x0f: return DRC_CONSTANT; + case 0x10: return DRC_REFERENCE; + case 0x11: return DRC_REFERENCE; + case 0x12: return DRC_REFERENCE; + case 0x13: return DRC_REFERENCE; + case 0x14: return DRC_REFERENCE; + case 0x15: return DRC_REFERENCE; + case 0x16: return DRC_INDIRECT_SPECIAL; + default: return 0; + } +} + +/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */ + +const char * +DW_OP_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x03: return "DW_OP_addr"; + case 0x06: return "DW_OP_deref"; + case 0x08: return "DW_OP_const1u"; + case 0x09: return "DW_OP_const1s"; + case 0x0a: return "DW_OP_const2u"; + case 0x0b: return "DW_OP_const2s"; + case 0x0c: return "DW_OP_const4u"; + case 0x0d: return "DW_OP_const4s"; + case 0x0e: return "DW_OP_const8u"; + case 0x0f: return "DW_OP_const8s"; + case 0x10: return "DW_OP_constu"; + case 0x11: return "DW_OP_consts"; + case 0x12: return "DW_OP_dup"; + case 0x13: return "DW_OP_drop"; + case 0x14: return "DW_OP_over"; + case 0x15: return "DW_OP_pick"; + case 0x16: return "DW_OP_swap"; + case 0x17: return "DW_OP_rot"; + case 0x18: return "DW_OP_xderef"; + case 0x19: return "DW_OP_abs"; + case 0x1a: return "DW_OP_and"; + case 0x1b: return "DW_OP_div"; + case 0x1c: return "DW_OP_minus"; + case 0x1d: return "DW_OP_mod"; + case 0x1e: return "DW_OP_mul"; + case 0x1f: return "DW_OP_neg"; + case 0x20: return "DW_OP_not"; + case 0x21: return "DW_OP_or"; + case 0x22: return "DW_OP_plus"; + case 0x23: return "DW_OP_plus_uconst"; + case 0x24: return "DW_OP_shl"; + case 0x25: return "DW_OP_shr"; + case 0x26: return "DW_OP_shra"; + case 0x27: return "DW_OP_xor"; + case 0x2f: return "DW_OP_skip"; + case 0x28: return "DW_OP_bra"; + case 0x29: return "DW_OP_eq"; + case 0x2a: return "DW_OP_ge"; + case 0x2b: return "DW_OP_gt"; + case 0x2c: return "DW_OP_le"; + case 0x2d: return "DW_OP_lt"; + case 0x2e: return "DW_OP_ne"; + case 0x30: return "DW_OP_lit0"; + case 0x31: return "DW_OP_lit1"; + case 0x32: return "DW_OP_lit2"; + case 0x33: return "DW_OP_lit3"; + case 0x34: return "DW_OP_lit4"; + case 0x35: return "DW_OP_lit5"; + case 0x36: return "DW_OP_lit6"; + case 0x37: return "DW_OP_lit7"; + case 0x38: return "DW_OP_lit8"; + case 0x39: return "DW_OP_lit9"; + case 0x3a: return "DW_OP_lit10"; + case 0x3b: return "DW_OP_lit11"; + case 0x3c: return "DW_OP_lit12"; + case 0x3d: return "DW_OP_lit13"; + case 0x3e: return "DW_OP_lit14"; + case 0x3f: return "DW_OP_lit15"; + case 0x40: return "DW_OP_lit16"; + case 0x41: return "DW_OP_lit17"; + case 0x42: return "DW_OP_lit18"; + case 0x43: return "DW_OP_lit19"; + case 0x44: return "DW_OP_lit20"; + case 0x45: return "DW_OP_lit21"; + case 0x46: return "DW_OP_lit22"; + case 0x47: return "DW_OP_lit23"; + case 0x48: return "DW_OP_lit24"; + case 0x49: return "DW_OP_lit25"; + case 0x4a: return "DW_OP_lit26"; + case 0x4b: return "DW_OP_lit27"; + case 0x4c: return "DW_OP_lit28"; + case 0x4d: return "DW_OP_lit29"; + case 0x4e: return "DW_OP_lit30"; + case 0x4f: return "DW_OP_lit31"; + case 0x50: return "DW_OP_reg0"; + case 0x51: return "DW_OP_reg1"; + case 0x52: return "DW_OP_reg2"; + case 0x53: return "DW_OP_reg3"; + case 0x54: return "DW_OP_reg4"; + case 0x55: return "DW_OP_reg5"; + case 0x56: return "DW_OP_reg6"; + case 0x57: return "DW_OP_reg7"; + case 0x58: return "DW_OP_reg8"; + case 0x59: return "DW_OP_reg9"; + case 0x5a: return "DW_OP_reg10"; + case 0x5b: return "DW_OP_reg11"; + case 0x5c: return "DW_OP_reg12"; + case 0x5d: return "DW_OP_reg13"; + case 0x5e: return "DW_OP_reg14"; + case 0x5f: return "DW_OP_reg15"; + case 0x60: return "DW_OP_reg16"; + case 0x61: return "DW_OP_reg17"; + case 0x62: return "DW_OP_reg18"; + case 0x63: return "DW_OP_reg19"; + case 0x64: return "DW_OP_reg20"; + case 0x65: return "DW_OP_reg21"; + case 0x66: return "DW_OP_reg22"; + case 0x67: return "DW_OP_reg23"; + case 0x68: return "DW_OP_reg24"; + case 0x69: return "DW_OP_reg25"; + case 0x6a: return "DW_OP_reg26"; + case 0x6b: return "DW_OP_reg27"; + case 0x6c: return "DW_OP_reg28"; + case 0x6d: return "DW_OP_reg29"; + case 0x6e: return "DW_OP_reg30"; + case 0x6f: return "DW_OP_reg31"; + case 0x70: return "DW_OP_breg0"; + case 0x71: return "DW_OP_breg1"; + case 0x72: return "DW_OP_breg2"; + case 0x73: return "DW_OP_breg3"; + case 0x74: return "DW_OP_breg4"; + case 0x75: return "DW_OP_breg5"; + case 0x76: return "DW_OP_breg6"; + case 0x77: return "DW_OP_breg7"; + case 0x78: return "DW_OP_breg8"; + case 0x79: return "DW_OP_breg9"; + case 0x7a: return "DW_OP_breg10"; + case 0x7b: return "DW_OP_breg11"; + case 0x7c: return "DW_OP_breg12"; + case 0x7d: return "DW_OP_breg13"; + case 0x7e: return "DW_OP_breg14"; + case 0x7f: return "DW_OP_breg15"; + case 0x80: return "DW_OP_breg16"; + case 0x81: return "DW_OP_breg17"; + case 0x82: return "DW_OP_breg18"; + case 0x83: return "DW_OP_breg19"; + case 0x84: return "DW_OP_breg20"; + case 0x85: return "DW_OP_breg21"; + case 0x86: return "DW_OP_breg22"; + case 0x87: return "DW_OP_breg23"; + case 0x88: return "DW_OP_breg24"; + case 0x89: return "DW_OP_breg25"; + case 0x8a: return "DW_OP_breg26"; + case 0x8b: return "DW_OP_breg27"; + case 0x8c: return "DW_OP_breg28"; + case 0x8d: return "DW_OP_breg29"; + case 0x8e: return "DW_OP_breg30"; + case 0x8f: return "DW_OP_breg31"; + case 0x90: return "DW_OP_regx"; + case 0x91: return "DW_OP_fbreg"; + case 0x92: return "DW_OP_bregx"; + case 0x93: return "DW_OP_piece"; + case 0x94: return "DW_OP_deref_size"; + case 0x95: return "DW_OP_xderef_size"; + case 0x96: return "DW_OP_nop"; + case 0x97: return "DW_OP_push_object_address"; + case 0x98: return "DW_OP_call2"; + case 0x99: return "DW_OP_call4"; + case 0x9a: return "DW_OP_call_ref"; + case 0xf0: return "DW_OP_APPLE_uninit"; + case 0xe0: return "DW_OP_lo_user"; + case 0xff: return "DW_OP_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_OP_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x03: return "addr"; + case 0x06: return "deref"; + case 0x08: return "const1u"; + case 0x09: return "const1s"; + case 0x0a: return "const2u"; + case 0x0b: return "const2s"; + case 0x0c: return "const4u"; + case 0x0d: return "const4s"; + case 0x0e: return "const8u"; + case 0x0f: return "const8s"; + case 0x10: return "constu"; + case 0x11: return "consts"; + case 0x12: return "dup"; + case 0x13: return "drop"; + case 0x14: return "over"; + case 0x15: return "pick"; + case 0x16: return "swap"; + case 0x17: return "rot"; + case 0x18: return "xderef"; + case 0x19: return "abs"; + case 0x1a: return "and"; + case 0x1b: return "div"; + case 0x1c: return "minus"; + case 0x1d: return "mod"; + case 0x1e: return "mul"; + case 0x1f: return "neg"; + case 0x20: return "not"; + case 0x21: return "or"; + case 0x22: return "plus"; + case 0x23: return "plus uconst"; + case 0x24: return "shl"; + case 0x25: return "shr"; + case 0x26: return "shra"; + case 0x27: return "xor"; + case 0x2f: return "skip"; + case 0x28: return "bra"; + case 0x29: return "eq"; + case 0x2a: return "ge"; + case 0x2b: return "gt"; + case 0x2c: return "le"; + case 0x2d: return "lt"; + case 0x2e: return "ne"; + case 0x30: return "lit0"; + case 0x31: return "lit1"; + case 0x32: return "lit2"; + case 0x33: return "lit3"; + case 0x34: return "lit4"; + case 0x35: return "lit5"; + case 0x36: return "lit6"; + case 0x37: return "lit7"; + case 0x38: return "lit8"; + case 0x39: return "lit9"; + case 0x3a: return "lit10"; + case 0x3b: return "lit11"; + case 0x3c: return "lit12"; + case 0x3d: return "lit13"; + case 0x3e: return "lit14"; + case 0x3f: return "lit15"; + case 0x40: return "lit16"; + case 0x41: return "lit17"; + case 0x42: return "lit18"; + case 0x43: return "lit19"; + case 0x44: return "lit20"; + case 0x45: return "lit21"; + case 0x46: return "lit22"; + case 0x47: return "lit23"; + case 0x48: return "lit24"; + case 0x49: return "lit25"; + case 0x4a: return "lit26"; + case 0x4b: return "lit27"; + case 0x4c: return "lit28"; + case 0x4d: return "lit29"; + case 0x4e: return "lit30"; + case 0x4f: return "lit31"; + case 0x50: return "reg0"; + case 0x51: return "reg1"; + case 0x52: return "reg2"; + case 0x53: return "reg3"; + case 0x54: return "reg4"; + case 0x55: return "reg5"; + case 0x56: return "reg6"; + case 0x57: return "reg7"; + case 0x58: return "reg8"; + case 0x59: return "reg9"; + case 0x5a: return "reg10"; + case 0x5b: return "reg11"; + case 0x5c: return "reg12"; + case 0x5d: return "reg13"; + case 0x5e: return "reg14"; + case 0x5f: return "reg15"; + case 0x60: return "reg16"; + case 0x61: return "reg17"; + case 0x62: return "reg18"; + case 0x63: return "reg19"; + case 0x64: return "reg20"; + case 0x65: return "reg21"; + case 0x66: return "reg22"; + case 0x67: return "reg23"; + case 0x68: return "reg24"; + case 0x69: return "reg25"; + case 0x6a: return "reg26"; + case 0x6b: return "reg27"; + case 0x6c: return "reg28"; + case 0x6d: return "reg29"; + case 0x6e: return "reg30"; + case 0x6f: return "reg31"; + case 0x70: return "breg0"; + case 0x71: return "breg1"; + case 0x72: return "breg2"; + case 0x73: return "breg3"; + case 0x74: return "breg4"; + case 0x75: return "breg5"; + case 0x76: return "breg6"; + case 0x77: return "breg7"; + case 0x78: return "breg8"; + case 0x79: return "breg9"; + case 0x7a: return "breg10"; + case 0x7b: return "breg11"; + case 0x7c: return "breg12"; + case 0x7d: return "breg13"; + case 0x7e: return "breg14"; + case 0x7f: return "breg15"; + case 0x80: return "breg16"; + case 0x81: return "breg17"; + case 0x82: return "breg18"; + case 0x83: return "breg19"; + case 0x84: return "breg20"; + case 0x85: return "breg21"; + case 0x86: return "breg22"; + case 0x87: return "breg23"; + case 0x88: return "breg24"; + case 0x89: return "breg25"; + case 0x8a: return "breg26"; + case 0x8b: return "breg27"; + case 0x8c: return "breg28"; + case 0x8d: return "breg29"; + case 0x8e: return "breg30"; + case 0x8f: return "breg31"; + case 0x90: return "regx"; + case 0x91: return "fbreg"; + case 0x92: return "bregx"; + case 0x93: return "piece"; + case 0x94: return "deref size"; + case 0x95: return "xderef size"; + case 0x96: return "nop"; + case 0x97: return "push object address"; + case 0x98: return "call2"; + case 0x99: return "call4"; + case 0x9a: return "call ref"; + case 0xf0: return "uninitialized"; + case 0xe0: return "lo user"; + case 0xff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_OP_value_to_class (uint32_t val) +{ + switch (val) { + case 0x03: return DRC_ONEOPERAND; + case 0x06: return DRC_ZEROOPERANDS; + case 0x08: return DRC_ONEOPERAND; + case 0x09: return DRC_ONEOPERAND; + case 0x0a: return DRC_ONEOPERAND; + case 0x0b: return DRC_ONEOPERAND; + case 0x0c: return DRC_ONEOPERAND; + case 0x0d: return DRC_ONEOPERAND; + case 0x0e: return DRC_ONEOPERAND; + case 0x0f: return DRC_ONEOPERAND; + case 0x10: return DRC_ONEOPERAND; + case 0x11: return DRC_ONEOPERAND; + case 0x12: return DRC_ZEROOPERANDS; + case 0x13: return DRC_ZEROOPERANDS; + case 0x14: return DRC_ZEROOPERANDS; + case 0x15: return DRC_ONEOPERAND; + case 0x16: return DRC_ZEROOPERANDS; + case 0x17: return DRC_ZEROOPERANDS; + case 0x18: return DRC_ZEROOPERANDS; + case 0x19: return DRC_ZEROOPERANDS; + case 0x1a: return DRC_ZEROOPERANDS; + case 0x1b: return DRC_ZEROOPERANDS; + case 0x1c: return DRC_ZEROOPERANDS; + case 0x1d: return DRC_ZEROOPERANDS; + case 0x1e: return DRC_ZEROOPERANDS; + case 0x1f: return DRC_ZEROOPERANDS; + case 0x20: return DRC_ZEROOPERANDS; + case 0x21: return DRC_ZEROOPERANDS; + case 0x22: return DRC_ZEROOPERANDS; + case 0x23: return DRC_ONEOPERAND; + case 0x24: return DRC_ZEROOPERANDS; + case 0x25: return DRC_ZEROOPERANDS; + case 0x26: return DRC_ZEROOPERANDS; + case 0x27: return DRC_ZEROOPERANDS; + case 0x2f: return DRC_ONEOPERAND; + case 0x28: return DRC_ONEOPERAND; + case 0x29: return DRC_ZEROOPERANDS; + case 0x2a: return DRC_ZEROOPERANDS; + case 0x2b: return DRC_ZEROOPERANDS; + case 0x2c: return DRC_ZEROOPERANDS; + case 0x2d: return DRC_ZEROOPERANDS; + case 0x2e: return DRC_ZEROOPERANDS; + case 0x30: return DRC_ZEROOPERANDS; + case 0x31: return DRC_ZEROOPERANDS; + case 0x32: return DRC_ZEROOPERANDS; + case 0x33: return DRC_ZEROOPERANDS; + case 0x34: return DRC_ZEROOPERANDS; + case 0x35: return DRC_ZEROOPERANDS; + case 0x36: return DRC_ZEROOPERANDS; + case 0x37: return DRC_ZEROOPERANDS; + case 0x38: return DRC_ZEROOPERANDS; + case 0x39: return DRC_ZEROOPERANDS; + case 0x3a: return DRC_ZEROOPERANDS; + case 0x3b: return DRC_ZEROOPERANDS; + case 0x3c: return DRC_ZEROOPERANDS; + case 0x3d: return DRC_ZEROOPERANDS; + case 0x3e: return DRC_ZEROOPERANDS; + case 0x3f: return DRC_ZEROOPERANDS; + case 0x40: return DRC_ZEROOPERANDS; + case 0x41: return DRC_ZEROOPERANDS; + case 0x42: return DRC_ZEROOPERANDS; + case 0x43: return DRC_ZEROOPERANDS; + case 0x44: return DRC_ZEROOPERANDS; + case 0x45: return DRC_ZEROOPERANDS; + case 0x46: return DRC_ZEROOPERANDS; + case 0x47: return DRC_ZEROOPERANDS; + case 0x48: return DRC_ZEROOPERANDS; + case 0x49: return DRC_ZEROOPERANDS; + case 0x4a: return DRC_ZEROOPERANDS; + case 0x4b: return DRC_ZEROOPERANDS; + case 0x4c: return DRC_ZEROOPERANDS; + case 0x4d: return DRC_ZEROOPERANDS; + case 0x4e: return DRC_ZEROOPERANDS; + case 0x4f: return DRC_ZEROOPERANDS; + case 0x50: return DRC_ZEROOPERANDS; + case 0x51: return DRC_ZEROOPERANDS; + case 0x52: return DRC_ZEROOPERANDS; + case 0x53: return DRC_ZEROOPERANDS; + case 0x54: return DRC_ZEROOPERANDS; + case 0x55: return DRC_ZEROOPERANDS; + case 0x56: return DRC_ZEROOPERANDS; + case 0x57: return DRC_ZEROOPERANDS; + case 0x58: return DRC_ZEROOPERANDS; + case 0x59: return DRC_ZEROOPERANDS; + case 0x5a: return DRC_ZEROOPERANDS; + case 0x5b: return DRC_ZEROOPERANDS; + case 0x5c: return DRC_ZEROOPERANDS; + case 0x5d: return DRC_ZEROOPERANDS; + case 0x5e: return DRC_ZEROOPERANDS; + case 0x5f: return DRC_ZEROOPERANDS; + case 0x60: return DRC_ZEROOPERANDS; + case 0x61: return DRC_ZEROOPERANDS; + case 0x62: return DRC_ZEROOPERANDS; + case 0x63: return DRC_ZEROOPERANDS; + case 0x64: return DRC_ZEROOPERANDS; + case 0x65: return DRC_ZEROOPERANDS; + case 0x66: return DRC_ZEROOPERANDS; + case 0x67: return DRC_ZEROOPERANDS; + case 0x68: return DRC_ZEROOPERANDS; + case 0x69: return DRC_ZEROOPERANDS; + case 0x6a: return DRC_ZEROOPERANDS; + case 0x6b: return DRC_ZEROOPERANDS; + case 0x6c: return DRC_ZEROOPERANDS; + case 0x6d: return DRC_ZEROOPERANDS; + case 0x6e: return DRC_ZEROOPERANDS; + case 0x6f: return DRC_ZEROOPERANDS; + case 0x70: return DRC_ONEOPERAND; + case 0x71: return DRC_ONEOPERAND; + case 0x72: return DRC_ONEOPERAND; + case 0x73: return DRC_ONEOPERAND; + case 0x74: return DRC_ONEOPERAND; + case 0x75: return DRC_ONEOPERAND; + case 0x76: return DRC_ONEOPERAND; + case 0x77: return DRC_ONEOPERAND; + case 0x78: return DRC_ONEOPERAND; + case 0x79: return DRC_ONEOPERAND; + case 0x7a: return DRC_ONEOPERAND; + case 0x7b: return DRC_ONEOPERAND; + case 0x7c: return DRC_ONEOPERAND; + case 0x7d: return DRC_ONEOPERAND; + case 0x7e: return DRC_ONEOPERAND; + case 0x7f: return DRC_ONEOPERAND; + case 0x80: return DRC_ONEOPERAND; + case 0x81: return DRC_ONEOPERAND; + case 0x82: return DRC_ONEOPERAND; + case 0x83: return DRC_ONEOPERAND; + case 0x84: return DRC_ONEOPERAND; + case 0x85: return DRC_ONEOPERAND; + case 0x86: return DRC_ONEOPERAND; + case 0x87: return DRC_ONEOPERAND; + case 0x88: return DRC_ONEOPERAND; + case 0x89: return DRC_ONEOPERAND; + case 0x8a: return DRC_ONEOPERAND; + case 0x8b: return DRC_ONEOPERAND; + case 0x8c: return DRC_ONEOPERAND; + case 0x8d: return DRC_ONEOPERAND; + case 0x8e: return DRC_ONEOPERAND; + case 0x8f: return DRC_ONEOPERAND; + case 0x90: return DRC_ONEOPERAND; + case 0x91: return DRC_ONEOPERAND; + case 0x92: return DRC_TWOOPERANDS; + case 0x93: return DRC_ONEOPERAND; + case 0x94: return DRC_ONEOPERAND; + case 0x95: return DRC_ONEOPERAND; + case 0x96: return DRC_ZEROOPERANDS; + case 0x97: return DRC_DWARFv3 | DRC_ZEROOPERANDS; + case 0x98: return DRC_DWARFv3 | DRC_ONEOPERAND; + case 0x99: return DRC_DWARFv3 | DRC_ONEOPERAND; + case 0x9a: return DRC_DWARFv3 | DRC_ONEOPERAND; + case 0xf0: return DRC_ZEROOPERANDS; /* DW_OP_APPLE_uninit */ + case 0xe0: return 0; + case 0xff: return 0; + default: return 0; + } +} + +/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */ + +const char * +DW_ATE_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "DW_ATE_address"; + case 0x02: return "DW_ATE_boolean"; + case 0x03: return "DW_ATE_complex_float"; + case 0x04: return "DW_ATE_float"; + case 0x05: return "DW_ATE_signed"; + case 0x06: return "DW_ATE_signed_char"; + case 0x07: return "DW_ATE_unsigned"; + case 0x08: return "DW_ATE_unsigned_char"; + case 0x09: return "DW_ATE_imaginary_float"; + case 0x80: return "DW_ATE_lo_user"; + case 0xff: return "DW_ATE_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_ATE_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "address"; + case 0x02: return "boolean"; + case 0x03: return "complex float"; + case 0x04: return "float"; + case 0x05: return "signed"; + case 0x06: return "signed char"; + case 0x07: return "unsigned"; + case 0x08: return "unsigned char"; + case 0x09: return "imaginary float"; + case 0x80: return "lo user"; + case 0xff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_ATE_value_to_class (uint32_t val) +{ + switch (val) { + case 0x01: return 0; + case 0x02: return 0; + case 0x03: return 0; + case 0x04: return 0; + case 0x05: return 0; + case 0x06: return 0; + case 0x07: return 0; + case 0x08: return 0; + case 0x09: return DRC_DWARFv3; + case 0x80: return 0; + case 0xff: return 0; + default: return 0; + } +} + +/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */ + +const char * +DW_ACCESS_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "DW_ACCESS_public"; + case 0x2: return "DW_ACCESS_protected"; + case 0x3: return "DW_ACCESS_private"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_ACCESS_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "public"; + case 0x2: return "protected"; + case 0x3: return "private"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ACCESS constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_ACCESS_value_to_class (uint32_t val) +{ + switch (val) { + case 0x1: return 0; + case 0x2: return 0; + case 0x3: return 0; + default: return 0; + } +} + +/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */ + +const char * +DW_VIS_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "DW_VIS_local"; + case 0x2: return "DW_VIS_exported"; + case 0x3: return "DW_VIS_qualified"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_VIS_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "local"; + case 0x2: return "exported"; + case 0x3: return "qualified"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_VIS constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_VIS_value_to_class (uint32_t val) +{ + switch (val) { + case 0x1: return 0; + case 0x2: return 0; + case 0x3: return 0; + default: return 0; + } +} + +/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */ + +const char * +DW_VIRTUALITY_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_VIRTUALITY_none"; + case 0x1: return "DW_VIRTUALITY_virtual"; + case 0x2: return "DW_VIRTUALITY_pure_virtual"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_VIRTUALITY_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "none"; + case 0x1: return "virtual"; + case 0x2: return "pure virtual"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_VIRTUALITY_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + case 0x2: return 0; + default: return 0; + } +} + +/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */ + +const char * +DW_LANG_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0001: return "DW_LANG_C89"; + case 0x0002: return "DW_LANG_C"; + case 0x0003: return "DW_LANG_Ada83"; + case 0x0004: return "DW_LANG_C_plus_plus"; + case 0x0005: return "DW_LANG_Cobol74"; + case 0x0006: return "DW_LANG_Cobol85"; + case 0x0007: return "DW_LANG_Fortran77"; + case 0x0008: return "DW_LANG_Fortran90"; + case 0x0009: return "DW_LANG_Pascal83"; + case 0x000a: return "DW_LANG_Modula2"; + case 0x000b: return "DW_LANG_Java"; + case 0x000c: return "DW_LANG_C99"; + case 0x000d: return "DW_LANG_Ada95"; + case 0x000e: return "DW_LANG_Fortran95"; + case 0x000f: return "DW_LANG_PLI"; + case 0x0010: return "DW_LANG_ObjC"; + case 0x0011: return "DW_LANG_ObjC_plus_plus"; + case 0x0012: return "DW_LANG_UPC"; + case 0x0013: return "DW_LANG_D"; + case 0x8000: return "DW_LANG_lo_user"; + case 0x8001: return "DW_LANG_Mips_Assembler"; + case 0x8765: return "DW_LANG_Upc"; + case 0xffff: return "DW_LANG_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_LANG_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0001: return "C89"; + case 0x0002: return "C"; + case 0x0003: return "Ada83"; + case 0x0004: return "C++"; + case 0x0005: return "Cobol74"; + case 0x0006: return "Cobol85"; + case 0x0007: return "Fortran77"; + case 0x0008: return "Fortran90"; + case 0x0009: return "Pascal83"; + case 0x000a: return "Modula2"; + case 0x000b: return "Java"; + case 0x000c: return "C99"; + case 0x000d: return "Ada95"; + case 0x000e: return "Fortran95"; + case 0x000f: return "PLI"; + case 0x0010: return "Objective C"; + case 0x0011: return "Objective C++"; + case 0x0012: return "UPC"; + case 0x0013: return "D"; + case 0x8000: return "lo user"; + case 0x8001: return "MIPS Assembler"; + case 0x8765: return "UPC"; + case 0xffff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_LANG_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0001: return 0; + case 0x0002: return 0; + case 0x0003: return 0; + case 0x0004: return 0; + case 0x0005: return 0; + case 0x0006: return 0; + case 0x0007: return 0; + case 0x0008: return 0; + case 0x0009: return 0; + case 0x000a: return 0; + case 0x000b: return DRC_DWARFv3; + case 0x000c: return DRC_DWARFv3; + case 0x000d: return DRC_DWARFv3; + case 0x000e: return DRC_DWARFv3; + case 0x000f: return DRC_DWARFv3; + case 0x0010: return DRC_DWARFv3; + case 0x0011: return DRC_DWARFv3; + case 0x0012: return DRC_DWARFv3; + case 0x0013: return DRC_DWARFv3; + case 0x8000: return 0; + case 0x8001: return 0; + case 0x8765: return 0; + case 0xffff: return 0; + default: return 0; + } +} + +/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */ + +const char * +DW_ADDR_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_ADDR_none"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_ADDR_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "none"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ADDR constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_ADDR_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + default: return 0; + } +} + +/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */ + +const char * +DW_ID_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_ID_case_sensitive"; + case 0x1: return "DW_ID_up_case"; + case 0x2: return "DW_ID_down_case"; + case 0x3: return "DW_ID_case_insensitive"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_ID_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "case sensitive"; + case 0x1: return "up case"; + case 0x2: return "down case"; + case 0x3: return "case insensitive"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ID constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_ID_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + case 0x2: return 0; + case 0x3: return 0; + default: return 0; + } +} + +/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */ + +const char * +DW_CC_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "DW_CC_normal"; + case 0x02: return "DW_CC_program"; + case 0x03: return "DW_CC_nocall"; + case 0x40: return "DW_CC_lo_user"; + case 0xff: return "DW_CC_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_CC_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "normal"; + case 0x02: return "program"; + case 0x03: return "nocall"; + case 0x40: return "lo user"; + case 0xff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CC constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_CC_value_to_class (uint32_t val) +{ + switch (val) { + case 0x01: return 0; + case 0x02: return 0; + case 0x03: return 0; + case 0x40: return 0; + case 0xff: return 0; + default: return 0; + } +} + +/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */ + +const char * +DW_INL_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_INL_not_inlined"; + case 0x1: return "DW_INL_inlined"; + case 0x2: return "DW_INL_declared_not_inlined"; + case 0x3: return "DW_INL_declared_inlined"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_INL_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "not inlined"; + case 0x1: return "inlined"; + case 0x2: return "declared not inlined"; + case 0x3: return "declared inlined"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_INL constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_INL_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + case 0x2: return 0; + case 0x3: return 0; + default: return 0; + } +} + +/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */ + +const char * +DW_ORD_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_ORD_row_major"; + case 0x1: return "DW_ORD_col_major"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_ORD_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "row major"; + case 0x1: return "col major"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_ORD constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_ORD_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + default: return 0; + } +} + +/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */ + +const char * +DW_DSC_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "DW_DSC_label"; + case 0x1: return "DW_DSC_range"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_DSC_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x0: return "label"; + case 0x1: return "range"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_DSC_value_to_class (uint32_t val) +{ + switch (val) { + case 0x0: return 0; + case 0x1: return 0; + default: return 0; + } +} + +/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */ + +const char * +DW_LNS_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "DW_LNS_copy"; + case 0x2: return "DW_LNS_advance_pc"; + case 0x3: return "DW_LNS_advance_line"; + case 0x4: return "DW_LNS_set_file"; + case 0x5: return "DW_LNS_set_column"; + case 0x6: return "DW_LNS_negate_stmt"; + case 0x7: return "DW_LNS_set_basic_block"; + case 0x8: return "DW_LNS_const_add_pc"; + case 0x9: return "DW_LNS_fixed_advance_pc"; + case 0xa: return "DW_LNS_set_prologue_end"; + case 0xb: return "DW_LNS_set_epilogue_begin"; + case 0xc: return "DW_LNS_set_isa"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_LNS_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x1: return "copy"; + case 0x2: return "advance pc"; + case 0x3: return "advance line"; + case 0x4: return "set file"; + case 0x5: return "set column"; + case 0x6: return "negate stmt"; + case 0x7: return "set basic block"; + case 0x8: return "const add pc"; + case 0x9: return "fixed advance pc"; + case 0xa: return "set prologue end"; + case 0xb: return "set epilogue begin"; + case 0xc: return "set isa"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_LNS_value_to_class (uint32_t val) +{ + switch (val) { + case 0x1: return 0; + case 0x2: return 0; + case 0x3: return 0; + case 0x4: return 0; + case 0x5: return 0; + case 0x6: return 0; + case 0x7: return 0; + case 0x8: return 0; + case 0x9: return 0; + case 0xa: return DRC_DWARFv3; + case 0xb: return DRC_DWARFv3; + case 0xc: return DRC_DWARFv3; + default: return 0; + } +} + +/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */ + +const char * +DW_LNE_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "DW_LNE_end_sequence"; + case 0x02: return "DW_LNE_set_address"; + case 0x03: return "DW_LNE_define_file"; + case 0x80: return "DW_LNE_lo_user"; + case 0xff: return "DW_LNE_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_LNE_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "end sequence"; + case 0x02: return "set address"; + case 0x03: return "define file"; + case 0x80: return "lo user"; + case 0xff: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_LNE constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_LNE_value_to_class (uint32_t val) +{ + switch (val) { + case 0x01: return 0; + case 0x02: return 0; + case 0x03: return 0; + case 0x80: return DRC_DWARFv3; + case 0xff: return DRC_DWARFv3; + default: return 0; + } +} + +/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */ + +const char * +DW_MACINFO_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "DW_MACINFO_define"; + case 0x02: return "DW_MACINFO_undef"; + case 0x03: return "DW_MACINFO_start_file"; + case 0x04: return "DW_MACINFO_end_file"; + case 0xff: return "DW_MACINFO_vendor_ext"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_MACINFO_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x01: return "define"; + case 0x02: return "undef"; + case 0x03: return "start file"; + case 0x04: return "end file"; + case 0xff: return "vendor ext"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_MACINFO constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_MACINFO_value_to_class (uint32_t val) +{ + switch (val) { + case 0x01: return 0; + case 0x02: return 0; + case 0x03: return 0; + case 0x04: return 0; + case 0xff: return 0; + default: return 0; + } +} + +/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */ + +const char * +DW_CFA_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x40: return "DW_CFA_advance_loc"; + case 0x80: return "DW_CFA_offset"; + case 0xc0: return "DW_CFA_restore"; + case 0x00: return "DW_CFA_nop"; + case 0x01: return "DW_CFA_set_loc"; + case 0x02: return "DW_CFA_advance_loc1"; + case 0x03: return "DW_CFA_advance_loc2"; + case 0x04: return "DW_CFA_advance_loc4"; + case 0x05: return "DW_CFA_offset_extended"; + case 0x06: return "DW_CFA_restore_extended"; + case 0x07: return "DW_CFA_undefined"; + case 0x08: return "DW_CFA_same_value"; + case 0x09: return "DW_CFA_register"; + case 0x0a: return "DW_CFA_remember_state"; + case 0x0b: return "DW_CFA_restore_state"; + case 0x0c: return "DW_CFA_def_cfa"; + case 0x0d: return "DW_CFA_def_cfa_register"; + case 0x0e: return "DW_CFA_def_cfa_offset"; + case 0x0f: return "DW_CFA_def_cfa_expression"; + case 0x10: return "DW_CFA_expression"; + case 0x11: return "DW_CFA_offset_extended_sf"; + case 0x12: return "DW_CFA_def_cfa_sf"; + case 0x13: return "DW_CFA_def_cfa_offset_sf"; + case 0x1c: return "DW_CFA_lo_user"; + case 0x3f: return "DW_CFA_hi_user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_CFA_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x40: return "advance loc"; + case 0x80: return "offset"; + case 0xc0: return "restore"; + case 0x00: return "nop"; + case 0x01: return "set loc"; + case 0x02: return "advance loc1"; + case 0x03: return "advance loc2"; + case 0x04: return "advance loc4"; + case 0x05: return "offset extended"; + case 0x06: return "restore extended"; + case 0x07: return "undefined"; + case 0x08: return "same value"; + case 0x09: return "register"; + case 0x0a: return "remember state"; + case 0x0b: return "restore state"; + case 0x0c: return "def cfa"; + case 0x0d: return "def cfa register"; + case 0x0e: return "def cfa offset"; + case 0x0f: return "def cfa expression"; + case 0x10: return "expression"; + case 0x11: return "offset extended sf"; + case 0x12: return "def cfa sf"; + case 0x13: return "def cfa offset sf"; + case 0x1c: return "lo user"; + case 0x3f: return "hi user"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_CFA constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_CFA_value_to_class (uint32_t val) +{ + switch (val) { + case 0x40: return DRC_ZEROOPERANDS; + case 0x80: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET; + case 0xc0: return DRC_ZEROOPERANDS; + case 0x00: return DRC_ZEROOPERANDS; + case 0x01: return DRC_ONEOPERAND | DRC_OPERANDONE_ADDRESS; + case 0x02: return DRC_ONEOPERAND | DRC_OPERANDONE_1BYTE_DELTA; + case 0x03: return DRC_ONEOPERAND | DRC_OPERANDONE_2BYTE_DELTA; + case 0x04: return DRC_ONEOPERAND | DRC_OPERANDONE_4BYTE_DELTA; + case 0x05: return DRC_OPERANDTWO_ULEB128_OFFSET | DRC_OPERNADONE_ULEB128_REGISTER | DRC_TWOOPERANDS; + case 0x06: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER; + case 0x07: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER; + case 0x08: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER; + case 0x09: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_REGISTER | DRC_TWOOPERANDS; + case 0x0a: return DRC_ZEROOPERANDS; + case 0x0b: return DRC_ZEROOPERANDS; + case 0x0c: return DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_ULEB128_OFFSET | DRC_TWOOPERANDS; + case 0x0d: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_REGISTER; + case 0x0e: return DRC_ONEOPERAND | DRC_OPERANDONE_ULEB128_OFFSET; + case 0x0f: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_BLOCK; + case 0x10: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_BLOCK | DRC_TWOOPERANDS; + case 0x11: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS; + case 0x12: return DRC_DWARFv3 | DRC_OPERANDONE_ULEB128_REGISTER | DRC_OPERANDTWO_SLEB128_OFFSET | DRC_TWOOPERANDS; + case 0x13: return DRC_DWARFv3 | DRC_ONEOPERAND | DRC_OPERANDONE_SLEB128_OFFSET; + case 0x1c: return 0; + case 0x3f: return 0; + default: return 0; + } +} + +/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */ + +const char * +DW_GNU_EH_PE_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x00: return "DW_GNU_EH_PE_absptr"; + case 0x01: return "DW_GNU_EH_PE_uleb128"; + case 0x02: return "DW_GNU_EH_PE_udata2"; + case 0x03: return "DW_GNU_EH_PE_udata4"; + case 0x04: return "DW_GNU_EH_PE_udata8"; + case 0x09: return "DW_GNU_EH_PE_sleb128"; + case 0x0a: return "DW_GNU_EH_PE_sdata2"; + case 0x0b: return "DW_GNU_EH_PE_sdata4"; + case 0x0c: return "DW_GNU_EH_PE_sdata8"; + case 0x08: return "DW_GNU_EH_PE_signed"; + case 0x10: return "DW_GNU_EH_PE_pcrel"; + case 0x20: return "DW_GNU_EH_PE_textrel"; + case 0x30: return "DW_GNU_EH_PE_datarel"; + case 0x40: return "DW_GNU_EH_PE_funcrel"; + case 0x50: return "DW_GNU_EH_PE_aligned"; + case 0x80: return "DW_GNU_EH_PE_indirect"; + case 0xff: return "DW_GNU_EH_PE_omit"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val); + return invalid; + } +} + +const char * +DW_GNU_EH_PE_value_to_englishy_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x00: return "absptr"; + case 0x01: return "uleb128"; + case 0x02: return "udata2"; + case 0x03: return "udata4"; + case 0x04: return "udata8"; + case 0x09: return "sleb128"; + case 0x0a: return "sdata2"; + case 0x0b: return "sdata4"; + case 0x0c: return "sdata8"; + case 0x08: return "signed"; + case 0x10: return "pcrel"; + case 0x20: return "textrel"; + case 0x30: return "datarel"; + case 0x40: return "funcrel"; + case 0x50: return "aligned"; + case 0x80: return "indirect"; + case 0xff: return "omit"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_GNU_EH_PE constant: 0x%x", val); + return invalid; + } +} + +DRC_class +DW_GNU_EH_PE_value_to_class (uint32_t val) +{ + switch (val) { + case 0x00: return DRC_VENDOR_GNU; + case 0x01: return DRC_VENDOR_GNU; + case 0x02: return DRC_VENDOR_GNU; + case 0x03: return DRC_VENDOR_GNU; + case 0x04: return DRC_VENDOR_GNU; + case 0x09: return DRC_VENDOR_GNU; + case 0x0a: return DRC_VENDOR_GNU; + case 0x0b: return DRC_VENDOR_GNU; + case 0x0c: return DRC_VENDOR_GNU; + case 0x08: return DRC_VENDOR_GNU; + case 0x10: return DRC_VENDOR_GNU; + case 0x20: return DRC_VENDOR_GNU; + case 0x30: return DRC_VENDOR_GNU; + case 0x40: return DRC_VENDOR_GNU; + case 0x50: return DRC_VENDOR_GNU; + case 0x80: return DRC_VENDOR_GNU; + case 0xff: return DRC_VENDOR_GNU; + default: return 0; + } +} + +bool +is_type_tag (uint16_t tag) +{ + switch (tag) + { + case DW_TAG_array_type: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_const_type: + case DW_TAG_enumeration_type: + case DW_TAG_file_type: + case DW_TAG_interface_type: + case DW_TAG_packed_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_reference_type: + case DW_TAG_restrict_type: + case DW_TAG_set_type: + case DW_TAG_shared_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subrange_type: + case DW_TAG_subroutine_type: + case DW_TAG_thrown_type: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + case DW_TAG_volatile_type: + return true; + default: + return false; + } +} + +bool +is_pubtype_tag (uint16_t tag) +{ + switch (tag) + { + case DW_TAG_array_type: + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_file_type: + case DW_TAG_interface_type: + case DW_TAG_set_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subrange_type: + case DW_TAG_subroutine_type: + case DW_TAG_thrown_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + return true; + default: + break; + } + return false; +} + +DW_TAG_CategoryEnum +get_tag_category (uint16_t tag) +{ + switch (tag) + { + case DW_TAG_array_type : return TagCategoryType; + case DW_TAG_class_type : return TagCategoryType; + case DW_TAG_entry_point : return TagCategoryProgram; + case DW_TAG_enumeration_type : return TagCategoryType; + case DW_TAG_formal_parameter : return TagCategoryVariable; + case DW_TAG_imported_declaration : return TagCategoryProgram; + case DW_TAG_label : return TagCategoryProgram; + case DW_TAG_lexical_block : return TagCategoryProgram; + case DW_TAG_member : return TagCategoryType; + case DW_TAG_pointer_type : return TagCategoryType; + case DW_TAG_reference_type : return TagCategoryType; + case DW_TAG_compile_unit : return TagCategoryProgram; + case DW_TAG_string_type : return TagCategoryType; + case DW_TAG_structure_type : return TagCategoryType; + case DW_TAG_subroutine_type : return TagCategoryType; + case DW_TAG_typedef : return TagCategoryType; + case DW_TAG_union_type : return TagCategoryType; + case DW_TAG_unspecified_parameters : return TagCategoryVariable; + case DW_TAG_variant : return TagCategoryType; + case DW_TAG_common_block : return TagCategoryProgram; + case DW_TAG_common_inclusion : return TagCategoryProgram; + case DW_TAG_inheritance : return TagCategoryType; + case DW_TAG_inlined_subroutine : return TagCategoryProgram; + case DW_TAG_module : return TagCategoryProgram; + case DW_TAG_ptr_to_member_type : return TagCategoryType; + case DW_TAG_set_type : return TagCategoryType; + case DW_TAG_subrange_type : return TagCategoryType; + case DW_TAG_with_stmt : return TagCategoryProgram; + case DW_TAG_access_declaration : return TagCategoryProgram; + case DW_TAG_base_type : return TagCategoryType; + case DW_TAG_catch_block : return TagCategoryProgram; + case DW_TAG_const_type : return TagCategoryType; + case DW_TAG_constant : return TagCategoryVariable; + case DW_TAG_enumerator : return TagCategoryType; + case DW_TAG_file_type : return TagCategoryType; + case DW_TAG_friend : return TagCategoryType; + case DW_TAG_namelist : return TagCategoryVariable; + case DW_TAG_namelist_item : return TagCategoryVariable; + case DW_TAG_packed_type : return TagCategoryType; + case DW_TAG_subprogram : return TagCategoryProgram; + case DW_TAG_template_type_parameter : return TagCategoryType; + case DW_TAG_template_value_parameter : return TagCategoryType; + case DW_TAG_thrown_type : return TagCategoryType; + case DW_TAG_try_block : return TagCategoryProgram; + case DW_TAG_variant_part : return TagCategoryType; + case DW_TAG_variable : return TagCategoryVariable; + case DW_TAG_volatile_type : return TagCategoryType; + case DW_TAG_dwarf_procedure : return TagCategoryProgram; + case DW_TAG_restrict_type : return TagCategoryType; + case DW_TAG_interface_type : return TagCategoryType; + case DW_TAG_namespace : return TagCategoryProgram; + case DW_TAG_imported_module : return TagCategoryProgram; + case DW_TAG_unspecified_type : return TagCategoryType; + case DW_TAG_partial_unit : return TagCategoryProgram; + case DW_TAG_imported_unit : return TagCategoryProgram; + case DW_TAG_shared_type : return TagCategoryType; + default: break; + } + return TagCategoryProgram; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h new file mode 100644 index 00000000000..dafe8a7c8b4 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -0,0 +1,252 @@ +//===-- DWARFDefines.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFDefines_h_ +#define liblldb_DWARFDefines_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> +#include "lldb/Core/dwarf.h" + +/* DWARF constants generated on Wed Sep 7 16:41:50 2005 */ + +typedef uint32_t DRC_class; // Holds DRC_* class bitfields + +/* [7.5.4] Figure 16 "Tag Encodings" (pp. 125-127) in DWARFv3 draft 8 */ + + +enum DW_TAG_Category +{ + TagCategoryVariable, + TagCategoryType, + TagCategoryProgram, + kNumTagCategories +}; + +typedef enum DW_TAG_Category DW_TAG_CategoryEnum; +const char *DW_TAG_value_to_name (uint32_t val); +const char *DW_TAG_value_to_englishy_name (uint32_t val); +DRC_class DW_TAG_value_to_class (uint32_t val); +DW_TAG_CategoryEnum get_tag_category (uint16_t tag); +#define DW_TAG_MAX_NAME_LENGTH 31 + + +/* [7.5.4] Figure 17 "Child determination encodings" (p. 128) in DWARFv3 draft 8 */ + +const char *DW_CHILDREN_value_to_name (uint8_t val); +const char *DW_CHILDREN_value_to_englishy_name (uint8_t val); +DRC_class DW_CHILDREN_value_to_class (uint32_t val); +#define DW_CHILDREN_MAX_NAME_LENGTH 15 + + +/* [7.5.4] Figure 18 "Attribute encodings" (pp. 129-132) in DWARFv3 draft 8 */ + + +const char *DW_AT_value_to_name (uint32_t val); +const char *DW_AT_value_to_englishy_name (uint32_t val); +DRC_class DW_AT_value_to_class (uint32_t val); +#define DW_AT_MAX_NAME_LENGTH 34 + + +/* [7.5.4] Figure 19 "Attribute form encodings" (pp. 133-134) in DWARFv3 draft 8 */ + +const char *DW_FORM_value_to_name (uint32_t val); +const char *DW_FORM_value_to_englishy_name (uint32_t val); +DRC_class DW_FORM_value_to_class (uint32_t val); +#define DW_FORM_MAX_NAME_LENGTH 17 + + +/* [7.7.1] Figure 22 "DWARF operation encodings" (pp. 136-139) in DWARFv3 draft 8 */ + +const char *DW_OP_value_to_name (uint32_t val); +const char *DW_OP_value_to_englishy_name (uint32_t val); +DRC_class DW_OP_value_to_class (uint32_t val); +#define DW_OP_MAX_NAME_LENGTH 25 + + +/* [7.8] Figure 23 "Base type encoding values" (pp. 140-141) in DWARFv3 draft 8 */ + +const char *DW_ATE_value_to_name (uint32_t val); +const char *DW_ATE_value_to_englishy_name (uint32_t val); +DRC_class DW_ATE_value_to_class (uint32_t val); +#define DW_ATE_MAX_NAME_LENGTH 22 + + +/* [7.9] Figure 24 "Accessibility encodings" (p. 141) in DWARFv3 draft 8 */ + +const char *DW_ACCESS_value_to_name (uint32_t val); +const char *DW_ACCESS_value_to_englishy_name (uint32_t val); +DRC_class DW_ACCESS_value_to_class (uint32_t val); +#define DW_ACCESS_MAX_NAME_LENGTH 19 + + +/* [7.10] Figure 25 "Visibility encodings" (p. 142) in DWARFv3 draft 8 */ + +const char *DW_VIS_value_to_name (uint32_t val); +const char *DW_VIS_value_to_englishy_name (uint32_t val); +DRC_class DW_VIS_value_to_class (uint32_t val); +#define DW_VIS_MAX_NAME_LENGTH 16 + + +/* [7.11] Figure 26 "Virtuality encodings" (p. 142) in DWARFv3 draft 8 */ + +const char *DW_VIRTUALITY_value_to_name (uint32_t val); +const char *DW_VIRTUALITY_value_to_englishy_name (uint32_t val); +DRC_class DW_VIRTUALITY_value_to_class (uint32_t val); +#define DW_VIRTUALITY_MAX_NAME_LENGTH 26 + + +/* [7.12] Figure 27 "Language encodings" (p. 143) in DWARFv3 draft 8 */ + +const char *DW_LANG_value_to_name (uint32_t val); +const char *DW_LANG_value_to_englishy_name (uint32_t val); +DRC_class DW_LANG_value_to_class (uint32_t val); +#define DW_LANG_MAX_NAME_LENGTH 19 + + +/* [7.13], "Address Class Encodings" (p. 144) in DWARFv3 draft 8 */ + +const char *DW_ADDR_value_to_name (uint32_t val); +const char *DW_ADDR_value_to_englishy_name (uint32_t val); +DRC_class DW_ADDR_value_to_class (uint32_t val); +#define DW_ADDR_MAX_NAME_LENGTH 12 + + +/* [7.14] Figure 28 "Identifier case encodings" (p. 144) in DWARFv3 draft 8 */ + +const char *DW_ID_value_to_name (uint32_t val); +const char *DW_ID_value_to_englishy_name (uint32_t val); +DRC_class DW_ID_value_to_class (uint32_t val); +#define DW_ID_MAX_NAME_LENGTH 22 + + +/* [7.15] Figure 29 "Calling convention encodings" (p. 144) in DWARFv3 draft 8 */ + +const char *DW_CC_value_to_name (uint32_t val); +const char *DW_CC_value_to_englishy_name (uint32_t val); +DRC_class DW_CC_value_to_class (uint32_t val); +#define DW_CC_MAX_NAME_LENGTH 13 + + +/* [7.16] Figure 30 "Inline encodings" (p. 145) in DWARFv3 draft 8 */ + +const char *DW_INL_value_to_name (uint32_t val); +const char *DW_INL_value_to_englishy_name (uint32_t val); +DRC_class DW_INL_value_to_class (uint32_t val); +#define DW_INL_MAX_NAME_LENGTH 27 + + +/* [7.17] Figure 31 "Ordering encodings" (p. 145) in DWARFv3 draft 8 */ + +const char *DW_ORD_value_to_name (uint32_t val); +const char *DW_ORD_value_to_englishy_name (uint32_t val); +DRC_class DW_ORD_value_to_class (uint32_t val); +#define DW_ORD_MAX_NAME_LENGTH 16 + + +/* [7.18] Figure 32 "Discriminant descriptor encodings" (p. 146) in DWARFv3 draft 8 */ + +const char *DW_DSC_value_to_name (uint32_t val); +const char *DW_DSC_value_to_englishy_name (uint32_t val); +DRC_class DW_DSC_value_to_class (uint32_t val); +#define DW_DSC_MAX_NAME_LENGTH 12 + + +/* [7.21] Figure 33 "Line Number Standard Opcode Encodings" (pp. 148-149) in DWARFv3 draft 8 */ + +const char *DW_LNS_value_to_name (uint32_t val); +const char *DW_LNS_value_to_englishy_name (uint32_t val); +DRC_class DW_LNS_value_to_class (uint32_t val); +#define DW_LNS_MAX_NAME_LENGTH 25 + + +/* [7.21] Figure 34 "Line Number Extended Opcode Encodings" (p. 149) in DWARFv3 draft 8 */ + +const char *DW_LNE_value_to_name (uint32_t val); +const char *DW_LNE_value_to_englishy_name (uint32_t val); +DRC_class DW_LNE_value_to_class (uint32_t val); +#define DW_LNE_MAX_NAME_LENGTH 19 + + +/* [7.22] Figure 35 "Macinfo Type Encodings" (p. 150) in DWARFv3 draft 8 */ + +const char *DW_MACINFO_value_to_name (uint32_t val); +const char *DW_MACINFO_value_to_englishy_name (uint32_t val); +DRC_class DW_MACINFO_value_to_class (uint32_t val); +#define DW_MACINFO_MAX_NAME_LENGTH 21 + + +/* [7.23] Figure 36 "Call frame instruction encodings" (pp. 151-152) in DWARFv3 draft 8 */ + +const char *DW_CFA_value_to_name (uint32_t val); +const char *DW_CFA_value_to_englishy_name (uint32_t val); +DRC_class DW_CFA_value_to_class (uint32_t val); +#define DW_CFA_MAX_NAME_LENGTH 25 + + +/* FSF exception handling Pointer-Encoding constants (CFI augmentation) -- "DW_EH_PE_..." in the FSF sources */ + +const char *DW_GNU_EH_PE_value_to_name (uint32_t val); +const char *DW_GNU_EH_PE_value_to_englishy_name (uint32_t val); +DRC_class DW_GNU_EH_PE_value_to_class (uint32_t val); +#define DW_GNU_EH_PE_MAX_NAME_LENGTH 21 + + +/* These DRC are entirely our own construction, + although they are derived from various comments in the DWARF standard. + Most of these are not useful to the parser, but the DW_AT and DW_FORM + classes should prove to be usable in some fashion. */ + +#define DRC_0x65 0x1 +#define DRC_ADDRESS 0x2 +#define DRC_BLOCK 0x4 +#define DRC_CONSTANT 0x8 +#define DRC_DWARFv3 0x10 +#define DRC_FLAG 0x20 +#define DRC_INDIRECT_SPECIAL 0x40 +#define DRC_LINEPTR 0x80 +#define DRC_LOCEXPR 0x100 +#define DRC_LOCLISTPTR 0x200 +#define DRC_MACPTR 0x400 +#define DRC_ONEOPERAND 0x800 +#define DRC_OPERANDONE_1BYTE_DELTA 0x1000 +#define DRC_OPERANDONE_2BYTE_DELTA 0x2000 +#define DRC_OPERANDONE_4BYTE_DELTA 0x4000 +#define DRC_OPERANDONE_ADDRESS 0x8000 +#define DRC_OPERANDONE_BLOCK 0x10000 +#define DRC_OPERANDONE_SLEB128_OFFSET 0x20000 +#define DRC_OPERANDONE_ULEB128_OFFSET 0x40000 +#define DRC_OPERANDONE_ULEB128_REGISTER 0x80000 +#define DRC_OPERANDTWO_BLOCK 0x100000 +#define DRC_OPERANDTWO_SLEB128_OFFSET 0x200000 +#define DRC_OPERANDTWO_ULEB128_OFFSET 0x400000 +#define DRC_OPERANDTWO_ULEB128_REGISTER 0x800000 +#define DRC_OPERNADONE_ULEB128_REGISTER 0x1000000 +#define DRC_RANGELISTPTR 0x2000000 +#define DRC_REFERENCE 0x4000000 +#define DRC_STRING 0x8000000 +#define DRC_TWOOPERANDS 0x10000000 +#define DRC_VENDOR_GNU 0x20000000 +#define DRC_VENDOR_MIPS 0x40000000 +#define DRC_ZEROOPERANDS 0x80000000 + +bool is_type_tag (uint16_t tag); +bool is_pubtype_tag (uint16_t tag); + + +#ifdef __cplusplus +} +#endif + + +#endif // liblldb_DWARFDefines_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp new file mode 100644 index 00000000000..d2c137bd7df --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -0,0 +1,571 @@ +//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <assert.h> + +#include "lldb/Core/dwarf.h" +#include "lldb/Core/Stream.h" + +#include "DWARFFormValue.h" +#include "DWARFCompileUnit.h" + +class DWARFCompileUnit; + +using namespace lldb_private; + +DWARFFormValue::DWARFFormValue(dw_form_t form) : + m_form(form), + m_value() +{ +} + +bool +DWARFFormValue::ExtractValue(const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) +{ + bool indirect = false; + bool is_block = false; + m_value.data = NULL; + // Read the value for the form into value and follow and DW_FORM_indirect instances we run into + do + { + indirect = false; + switch (m_form) + { + case DW_FORM_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break; + case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); is_block = true; break; + case DW_FORM_block4: m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break; + case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break; + case DW_FORM_data4: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break; + case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr); + // Set the string value to also be the data for inlined cstr form values only + // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form + // values; + m_value.data = (uint8_t*)m_value.value.cstr; break; + case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break; + case DW_FORM_block1: m_value.value.uval = data.GetU8(offset_ptr); is_block = true; break; + case DW_FORM_data1: m_value.value.uval = data.GetU8(offset_ptr); break; + case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break; + case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break; + case DW_FORM_strp: m_value.value.uval = data.GetU32(offset_ptr); break; + // case DW_FORM_APPLE_db_str: + case DW_FORM_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break; + case DW_FORM_ref_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break; + case DW_FORM_ref1: m_value.value.uval = data.GetU8(offset_ptr); break; + case DW_FORM_ref2: m_value.value.uval = data.GetU16(offset_ptr); break; + case DW_FORM_ref4: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_ref8: m_value.value.uval = data.GetU64(offset_ptr); break; + case DW_FORM_ref_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break; + case DW_FORM_indirect: + m_form = data.GetULEB128(offset_ptr); + indirect = true; + break; + + default: + return false; + break; + } + } while (indirect); + + if (is_block) + { + m_value.data = data.PeekData(*offset_ptr, m_value.value.uval); + if (m_value.data != NULL) + { + *offset_ptr += m_value.value.uval; + } + } + + return true; +} + +bool +DWARFFormValue::SkipValue(const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const +{ + return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu); +} + +bool +DWARFFormValue::SkipValue(dw_form_t form, const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) +{ + bool indirect = false; + do + { + indirect = false; + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_block : { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); *offset_ptr += size; } return true; + case DW_FORM_block1 : { dw_uleb128_t size = debug_info_data.GetU8(offset_ptr); *offset_ptr += size; } return true; + case DW_FORM_block2 : { dw_uleb128_t size = debug_info_data.GetU16(offset_ptr); *offset_ptr += size; } return true; + case DW_FORM_block4 : { dw_uleb128_t size = debug_info_data.GetU32(offset_ptr); *offset_ptr += size; } return true; + + // Inlined NULL terminated C-strings + case DW_FORM_string : + debug_info_data.GetCStr(offset_ptr); + return true; + + // Compile unit address sized values + case DW_FORM_addr : + case DW_FORM_ref_addr : + *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + return true; + + // 1 byte values + case DW_FORM_data1 : + case DW_FORM_flag : + case DW_FORM_ref1 : + *offset_ptr += 1; + return true; + + // 2 byte values + case DW_FORM_data2 : + case DW_FORM_ref2 : + *offset_ptr += 2; + return true; + + // 4 byte values + case DW_FORM_strp : + case DW_FORM_data4 : + case DW_FORM_ref4 : + *offset_ptr += 4; + return true; + + // 8 byte values + case DW_FORM_data8 : + case DW_FORM_ref8 : + *offset_ptr += 8; + return true; + + // 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_ptr); + return true; + + case DW_FORM_indirect : + indirect = true; + form = debug_info_data.GetULEB128(offset_ptr); + break; + default: + return false; + } + } while (indirect); + return true; +} + +//bool +//DWARFFormValue::PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs) +//{ +// assert(offset != DW_INVALID_OFFSET); +//// printf("PutUnsigned(%s, 0x%8.8x, 0x%16.16llx, %d)\n", DW_FORM_value_to_name(form), offset, value, fixup_cu_relative_refs); +// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into +// switch (form) +// { +// case DW_FORM_addr: offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu)); break; +// +// case DW_FORM_flag: +// case DW_FORM_data1: offset = out_buff.Put8(offset, value); break; +// case DW_FORM_data2: offset = out_buff.Put16(offset, value); break; +// case DW_FORM_data4: offset = out_buff.Put32(offset, value); break; +// case DW_FORM_data8: offset = out_buff.Put64(offset, value); break; +//// case DW_FORM_udata: offset = out_buff.Put32_as_ULEB128(offset, value); break; +//// case DW_FORM_sdata: offset = out_buff.Put32_as_SLEB128(offset, value); break; +// case DW_FORM_strp: offset = out_buff.Put32(offset, value); break; +//// case DW_FORM_APPLE_db_str: +//// offset = out_buff.Put32_as_ULEB128(offset, value); break; +// +// case DW_FORM_ref1: +// if (fixup_cu_relative_refs) value -= cu->GetOffset(); +// offset = out_buff.Put8(offset, value); +// break; +// case DW_FORM_ref2: +// if (fixup_cu_relative_refs) value -= cu->GetOffset(); +// offset = out_buff.Put16(offset, value); +// break; +// case DW_FORM_ref4: +// if (fixup_cu_relative_refs) value -= cu->GetOffset(); +// offset = out_buff.Put32(offset, value); +// break; +// case DW_FORM_ref8: +// if (fixup_cu_relative_refs) value -= cu->GetOffset(); +// offset = out_buff.Put64(offset, value); +// break; +//// case DW_FORM_ref_udata: +//// if (fixup_cu_relative_refs) value -= cu->GetOffset(); +//// offset = out_buff.Put32_as_ULEB128(offset, value); +//// break; +// case DW_FORM_ref_addr: +// // TODO: Add support for DWARF3 if we ever start emitting DWARF3. The DW_FORM_ref_addr +// // is always the same size as an address prior to DWARF3, and with DWARF3 or later it +// // is 4 hard coded to bytes. +// offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu)); +// break; +// +// default: +// return false; +// } +// +// return true; +//} + +//bool +//DWARFFormValue::TransferValue(dw_form_t form, const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff) +//{ +// DWARFFormValue formValue(form); +// if (formValue.ExtractValue(data, offset_ptr,cu)) +// return TransferValue(formValue, cu, out_buff); +// return false; +//} + +//bool +//DWARFFormValue::TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff) +//{ +// // Read the value for the form into value and follow and DW_FORM_indirect instances we run into +// dw_form_t form = formValue.Form(); +// switch (form) +// { +// case DW_FORM_addr: +// case DW_FORM_ref_addr: +// { +// uint8_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu); +// out_buff.AppendMax64(formValue.Unsigned(), addr_size); +// } +// break; +// +// case DW_FORM_block: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break; +// case DW_FORM_block1: out_buff.Append8(formValue.Unsigned()); break; +// case DW_FORM_block2: out_buff.Append16(formValue.Unsigned()); break; +// case DW_FORM_block4: out_buff.Append32(formValue.Unsigned()); break; +// +// case DW_FORM_flag: +// case DW_FORM_data1: out_buff.Append8(formValue.Unsigned()); break; +// case DW_FORM_data2: out_buff.Append16(formValue.Unsigned()); break; +// case DW_FORM_data4: out_buff.Append32(formValue.Unsigned()); break; +// case DW_FORM_data8: out_buff.Append64(formValue.Unsigned()); break; +// case DW_FORM_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break; +// case DW_FORM_sdata: out_buff.Append32_as_SLEB128(formValue.Signed()); break; +// +// case DW_FORM_string: out_buff.AppendCStr(formValue.m_value.value.cstr); break; +// case DW_FORM_strp: out_buff.Append32(formValue.Unsigned()); break; +//// case DW_FORM_APPLE_db_str: +//// out_buff.Append32_as_ULEB128(formValue.Unsigned()); break; +// +// case DW_FORM_ref1: out_buff.Append8(formValue.Unsigned()); break; +// case DW_FORM_ref2: out_buff.Append16(formValue.Unsigned()); break; +// case DW_FORM_ref4: out_buff.Append32(formValue.Unsigned()); break; +// case DW_FORM_ref8: out_buff.Append64(formValue.Unsigned()); break; +// case DW_FORM_ref_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break; +// +// case DW_FORM_indirect: +// assert(!"DW_FORM_indirect found in DWARFFormValue::TransferValue() for an extracted form..."); +// break; +// +// default: +// Log::Error("DWARFFormValue::TransferValue() Unrecognized form: 0x%4.4x", form); +// return false; +// break; +// } +// +// const uint8_t* block_data = formValue.BlockData(); +// if (block_data) +// out_buff.AppendData(block_data, formValue.Unsigned()); +// return true; +//} + +void +DWARFFormValue::Dump(Stream *s, const DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const +{ + uint64_t uvalue = Unsigned(); + bool cu_relative_offset = false; + + bool verbose = s->GetVerbose(); + + switch (m_form) + { + case DW_FORM_addr: s->Address(uvalue, sizeof (uint64_t)); break; + case DW_FORM_flag: + case DW_FORM_data1: s->PutHex8(uvalue); break; + case DW_FORM_data2: s->PutHex16(uvalue); break; + case DW_FORM_data4: s->PutHex32(uvalue); break; + case DW_FORM_data8: s->PutHex64(uvalue); break; + case DW_FORM_string: s->QuotedCString(AsCString(NULL)); break; + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + if (uvalue > 0) + { + switch (m_form) + { + case DW_FORM_block: s->Printf("<0x%llx> ", uvalue); break; + case DW_FORM_block1: s->Printf("<0x%2.2x> ", (uint8_t)uvalue); break; + case DW_FORM_block2: s->Printf("<0x%4.4x> ", (uint16_t)uvalue); break; + case DW_FORM_block4: s->Printf("<0x%8.8x> ", (uint32_t)uvalue); break; + default: break; + } + + const uint8_t* data_ptr = m_value.data; + if (data_ptr) + { + const uint8_t* end_data_ptr = data_ptr + uvalue; // uvalue contains size of block + while (data_ptr < end_data_ptr) + { + s->Printf("%2.2x ", *data_ptr); + ++data_ptr; + } + } + else + s->PutCString("NULL"); + } + break; + + case DW_FORM_sdata: s->PutSLEB128(uvalue); break; + case DW_FORM_udata: s->PutULEB128(uvalue); break; + case DW_FORM_strp: + if (debug_str_data) + { + if (verbose) + s->Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); + + const char* dbg_str = AsCString(debug_str_data); + if (dbg_str) + s->QuotedCString(dbg_str); + } + else + { + s->PutHex32(uvalue); + } + break; + + case DW_FORM_ref_addr: + { + s->Address(uvalue, sizeof (uint64_t) * 2); + break; + } + case DW_FORM_ref1: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%2.2x", (uint8_t)uvalue); break; + case DW_FORM_ref2: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%4.4x", (uint16_t)uvalue); break; + case DW_FORM_ref4: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%4.4x", (uint32_t)uvalue); break; + case DW_FORM_ref8: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%8.8llx", uvalue); break; + case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s->Printf("cu + 0x%llx", uvalue); break; + + // All DW_FORM_indirect attributes should be resolved prior to calling this function + case DW_FORM_indirect: s->PutCString("DW_FORM_indirect"); break; + default: + s->Printf("DW_FORM(0x%4.4x)", m_form); + break; + } + + if (cu_relative_offset) + { + if (verbose) + s->PutCString(" => "); + + s->Printf("{0x%8.8x}", (uvalue + (cu ? cu->GetOffset() : 0))); + } +} + +const char* +DWARFFormValue::AsCString(const DataExtractor* debug_str_data_ptr) const +{ + if (IsInlinedCStr()) + return m_value.value.cstr; + else if (debug_str_data_ptr) + return debug_str_data_ptr->PeekCStr(m_value.value.uval); + return NULL; +} + +uint64_t +DWARFFormValue::Reference(const DWARFCompileUnit* cu) const +{ + uint64_t die_offset = m_value.value.uval; + switch (m_form) + { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + die_offset += (cu ? cu->GetOffset() : 0); + break; + + default: + break; + } + + return die_offset; +} + +//---------------------------------------------------------------------- +// Resolve any compile unit specific references so that we don't need +// the compile unit at a later time in order to work with the form +// value. +//---------------------------------------------------------------------- +bool +DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu) +{ + switch (m_form) + { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + m_value.value.uval += cu->GetOffset(); + m_form = DW_FORM_ref_addr; + return true; + break; + + default: + break; + } + + return false; +} + +const uint8_t* +DWARFFormValue::BlockData() const +{ + if (!IsInlinedCStr()) + return m_value.data; + return NULL; +} + + +bool +DWARFFormValue::IsBlockForm(const dw_form_t form) +{ + switch (form) + { + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + return true; + } + return false; +} + +bool +DWARFFormValue::IsDataForm(const dw_form_t form) +{ + switch (form) + { + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + return true; + } + return false; +} + +int +DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DataExtractor* debug_str_data_ptr) +{ + dw_form_t a_form = a_value.Form(); + dw_form_t b_form = b_value.Form(); + if (a_form < b_form) + return -1; + if (a_form > b_form) + return 1; + switch (a_form) + { + case DW_FORM_addr: + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_udata: + case DW_FORM_ref_addr: + { + uint64_t a = a_value.Unsigned(); + uint64_t b = b_value.Unsigned(); + if (a < b) + return -1; + if (a > b) + return 1; + return 0; + } + + case DW_FORM_sdata: + { + int64_t a = a_value.Signed(); + int64_t b = b_value.Signed(); + if (a < b) + return -1; + if (a > b) + return 1; + return 0; + } + + case DW_FORM_string: + case DW_FORM_strp: + { + const char *a_string = a_value.AsCString(debug_str_data_ptr); + const char *b_string = b_value.AsCString(debug_str_data_ptr); + if (a_string == b_string) + return 0; + else if (a_string && b_string) + return strcmp(a_string, b_string); + else if (a_string == NULL) + return -1; // A string is NULL, and B is valid + else + return 1; // A string valid, and B is NULL + } + + + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + { + uint64_t a_len = a_value.Unsigned(); + uint64_t b_len = b_value.Unsigned(); + if (a_len < b_len) + return -1; + if (a_len > b_len) + return 1; + // The block lengths are the same + return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned()); + } + break; + + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + { + uint64_t a = a_value.Reference(a_cu); + uint64_t b = b_value.Reference(b_cu); + if (a < b) + return -1; + if (a > b) + return 1; + return 0; + } + + case DW_FORM_indirect: + assert(!"This shouldn't happen after the form has been extracted..."); + break; + + default: + assert(!"Unhandled DW_FORM"); + break; + } + return -1; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h new file mode 100644 index 00000000000..3db63664f38 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -0,0 +1,81 @@ +//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// + +// +//===----------------------------------------------------------------------===// + + #ifndef liblldb_DWARFFormValue_h_ + #define SymbolFileDWARF_DWARFFormValue_h_ + +#include "SymbolFileDWARF.h" +#include <stddef.h> // for NULL + +class DWARFFormValue +{ +public: + typedef struct ValueTypeTag + { + ValueTypeTag() : + data(NULL), + value() + { + value.uval = 0; + } + + union + { + uint64_t uval; + int64_t sval; + const char* cstr; + } value; + const uint8_t* data; + } ValueType; + + enum + { + eValueTypeInvalid = 0, + eValueTypeUnsigned, + eValueTypeSigned, + eValueTypeCStr, + eValueTypeBlock + }; + + DWARFFormValue(dw_form_t form = 0); + dw_form_t Form() const { return m_form; } + void SetForm(dw_form_t form) { m_form = form; } + const ValueType& Value() const { return m_value; } + void Dump(lldb_private::Stream *s, const lldb_private::DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const; + bool ExtractValue(const lldb_private::DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu); + bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; } + const uint8_t* BlockData() const; + uint64_t Reference(const DWARFCompileUnit* cu) const; + bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu); + uint64_t Unsigned() const { return m_value.value.uval; } + void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; } + int64_t Signed() const { return m_value.value.sval; } + void SetSigned(int64_t sval) { m_value.value.sval = sval; } + const char* AsCString(const lldb_private::DataExtractor* debug_str_data_ptr) const; + bool SkipValue(const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const; + static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu); +// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff); +// static bool TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff); +// static bool PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs); + static bool IsBlockForm(const dw_form_t form); + static bool IsDataForm(const dw_form_t form); + + static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const lldb_private::DataExtractor* debug_str_data_ptr); +protected: + dw_form_t m_form; // Form for this value + ValueType m_value; // Contains all data for the form +}; + + +#endif // SymbolFileDWARF_DWARFFormValue_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp new file mode 100644 index 00000000000..9229c2a2d22 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp @@ -0,0 +1,172 @@ +//===-- DWARFLocationDescription.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFLocationDescription.h" +#include "DWARFDefines.h" +#include "lldb/lldb-private.h" +#include "lldb/Core/Stream.h" + + +using namespace lldb_private; + +static int print_dwarf_exp_op (Stream *s, const DataExtractor& data, uint32_t* offset_ptr, int address_size, int dwarf_ref_size); + +int +print_dwarf_expression (Stream *s, + const DataExtractor& data, + int address_size, + int dwarf_ref_size, + bool location_expression) +{ + int op_count = 0; + uint32_t offset = 0; + while (data.ValidOffset(offset)) + { + if (location_expression && op_count > 0) + { + // err (baton, "Dwarf location expressions may only have one operand!"); + return 1; + } + if (op_count > 0) + { + s->PutCString(", "); + } + if (print_dwarf_exp_op (s, data, &offset, address_size, dwarf_ref_size) == 1) + return 1; + op_count++; + } + + return 0; +} + +static int +print_dwarf_exp_op (Stream *s, + const DataExtractor& data, + uint32_t* offset_ptr, + int address_size, + int dwarf_ref_size) +{ + uint8_t opcode = data.GetU8(offset_ptr); + DRC_class opcode_class; + uint64_t uint; + int64_t sint; + + int size; + + opcode_class = DW_OP_value_to_class (opcode) & (~DRC_DWARFv3); + + s->Printf("%s ", DW_OP_value_to_englishy_name (opcode)); + + /* Does this take zero parameters? If so we can shortcut this function. */ + if (opcode_class == DRC_ZEROOPERANDS) + return 0; + + if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx) + { + uint = data.GetULEB128(offset_ptr); + sint = data.GetSLEB128(offset_ptr); + s->Printf("%llu %lli", uint, sint); + return 0; + } + if (opcode_class != DRC_ONEOPERAND) + { + s->Printf("UNKNOWN OP %u", opcode); + return 1; + } + + switch (opcode) + { + case DW_OP_addr: size = address_size; break; + case DW_OP_const1u: size = 1; break; + case DW_OP_const1s: size = -1; break; + case DW_OP_const2u: size = 2; break; + case DW_OP_const2s: size = -2; break; + case DW_OP_const4u: size = 4; break; + case DW_OP_const4s: size = -4; break; + case DW_OP_const8u: size = 8; break; + case DW_OP_const8s: size = -8; break; + case DW_OP_constu: size = 128; break; + case DW_OP_consts: size = -128; break; + case DW_OP_fbreg: size = -128; break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + size = -128; break; + case DW_OP_pick: + size = 1; break; + case DW_OP_deref_size: + size = 1; break; + case DW_OP_xderef_size: + size = 1; break; + case DW_OP_plus_uconst: + size = 128; break; + case DW_OP_skip: + size = -2; break; + case DW_OP_bra: + size = -2; break; + case DW_OP_call2: + size = 2; break; + case DW_OP_call4: + size = 4; break; + case DW_OP_call_ref: + size = dwarf_ref_size; break; + case DW_OP_piece: + size = 128; break; + case DW_OP_regx: + size = 128; break; + default: + s->Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode); + return 1; + } + + switch (size) + { + case -1: sint = (int8_t) data.GetU8(offset_ptr); s->Printf("%+lli", sint); break; + case -2: sint = (int16_t) data.GetU16(offset_ptr); s->Printf("%+lli", sint); break; + case -4: sint = (int32_t) data.GetU32(offset_ptr); s->Printf("%+lli", sint); break; + case -8: sint = (int64_t) data.GetU64(offset_ptr); s->Printf("%+lli", sint); break; + case -128: sint = data.GetSLEB128(offset_ptr); s->Printf("%+lli", sint); break; + case 1: uint = data.GetU8(offset_ptr); s->Printf("0x%2.2llx", uint); break; + case 2: uint = data.GetU16(offset_ptr); s->Printf("0x%4.4llx", uint); break; + case 4: uint = data.GetU32(offset_ptr); s->Printf("0x%8.8llx", uint); break; + case 8: uint = data.GetU64(offset_ptr); s->Printf("0x%16.16llx", uint); break; + case 128: uint = data.GetULEB128(offset_ptr); s->Printf("0x%llx", uint); break; + } + + return 0; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h new file mode 100644 index 00000000000..413a95c0f49 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h @@ -0,0 +1,24 @@ +//===-- DWARFLocationDescription.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFLocationDescription_h_ +#define SymbolFileDWARF_DWARFLocationDescription_h_ + +#include "SymbolFileDWARF.h" + +int +print_dwarf_expression (lldb_private::Stream *s, + const lldb_private::DataExtractor& data, + int address_size, + int dwarf_ref_size, + bool location_expression); + + + +#endif // SymbolFileDWARF_DWARFLocationDescription_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp new file mode 100644 index 00000000000..6a8359d3986 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp @@ -0,0 +1,89 @@ +//===-- DWARFLocationList.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFLocationList.h" + +#include "lldb/Core/Stream.h" + +#include "DWARFCompileUnit.h" +#include "DWARFDebugInfo.h" +#include "DWARFLocationDescription.h" + +using namespace lldb_private; + +dw_offset_t +DWARFLocationList::Dump(Stream *s, const DWARFCompileUnit* cu, const DataExtractor& debug_loc_data, dw_offset_t offset) +{ + uint64_t start_addr, end_addr; + uint32_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu); + s->SetAddressByteSize(DWARFCompileUnit::GetAddressByteSize(cu)); + dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; + while (debug_loc_data.ValidOffset(offset)) + { + start_addr = debug_loc_data.GetMaxU64(&offset,addr_size); + end_addr = debug_loc_data.GetMaxU64(&offset,addr_size); + + if (start_addr == 0 && end_addr == 0) + break; + + s->PutCString("\n "); + s->Indent(); + s->AddressRange(start_addr + base_addr, end_addr + base_addr, NULL, ": "); + uint32_t loc_length = debug_loc_data.GetU16(&offset); + + DataExtractor locationData(debug_loc_data, offset, loc_length); + // if ( dump_flags & DWARFDebugInfo::eDumpFlag_Verbose ) *ostrm_ptr << " ( "; + print_dwarf_expression (s, locationData, addr_size, 4, false); + offset += loc_length; + } + + return offset; +} + +bool +DWARFLocationList::Extract(const DataExtractor& debug_loc_data, dw_offset_t* offset_ptr, DataExtractor& location_list_data) +{ + // Initialize with no data just in case we don't find anything + location_list_data.Clear(); + + size_t loc_list_length = Size(debug_loc_data, *offset_ptr); + if (loc_list_length > 0) + { + location_list_data.SetData(debug_loc_data, *offset_ptr, loc_list_length); + *offset_ptr += loc_list_length; + return true; + } + + return false; +} + +size_t +DWARFLocationList::Size(const DataExtractor& debug_loc_data, dw_offset_t offset) +{ + const dw_offset_t debug_loc_offset = offset; + + while (debug_loc_data.ValidOffset(offset)) + { + dw_addr_t start_addr = debug_loc_data.GetAddress(&offset); + dw_addr_t end_addr = debug_loc_data.GetAddress(&offset); + + if (start_addr == 0 && end_addr == 0) + break; + + uint16_t loc_length = debug_loc_data.GetU16(&offset); + offset += loc_length; + } + + if (offset > debug_loc_offset) + return offset - debug_loc_offset; + return 0; +} + + + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h new file mode 100644 index 00000000000..3efd5c4492b --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h @@ -0,0 +1,34 @@ +//===-- DWARFLocationList.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DWARFLocationList_h_ +#define SymbolFileDWARF_DWARFLocationList_h_ + +#include "SymbolFileDWARF.h" + +class DWARFLocationList +{ +public: + static dw_offset_t + Dump (lldb_private::Stream *s, + const DWARFCompileUnit* cu, + const lldb_private::DataExtractor& debug_loc_data, + dw_offset_t offset); + + static bool + Extract (const lldb_private::DataExtractor& debug_loc_data, + dw_offset_t* offset_ptr, + lldb_private::DataExtractor& location_list_data); + + static size_t + Size (const lldb_private::DataExtractor& debug_loc_data, + dw_offset_t offset); + +}; +#endif // SymbolFileDWARF_DWARFLocationList_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp new file mode 100644 index 00000000000..571271b34bb --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -0,0 +1,207 @@ +//===-- LogChannelDWARF.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LogChannelDWARF.h" + +#include "lldb/Core/Args.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "SymbolFileDWARF.h" + +using namespace lldb; +using namespace lldb_private; + + +// when the one and only logging channel is abled, then this will be non NULL. +static LogChannelDWARF* g_log_channel = NULL; + +LogChannelDWARF::LogChannelDWARF () : + LogChannel () +{ +} + +LogChannelDWARF::~LogChannelDWARF () +{ +} + + +void +LogChannelDWARF::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + LogChannelDWARF::CreateInstance); +} + +void +LogChannelDWARF::Terminate() +{ + PluginManager::UnregisterPlugin (LogChannelDWARF::CreateInstance); +} + +LogChannel* +LogChannelDWARF::CreateInstance () +{ + return new LogChannelDWARF (); +} + +const char * +LogChannelDWARF::GetPluginNameStatic() +{ + static std::string g_plugin_name; + if (g_plugin_name.empty()) + { + g_plugin_name = SymbolFileDWARF::GetPluginNameStatic(); + g_plugin_name += LogChannel::GetPluginSuffix (); + } + return g_plugin_name.c_str(); +} + + +const char * +LogChannelDWARF::GetPluginDescriptionStatic() +{ + return "DWARF log channel for debugging plug-in issues."; +} + +const char * +LogChannelDWARF::GetPluginName() +{ + return GetPluginDescriptionStatic(); +} + +const char * +LogChannelDWARF::GetShortPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +LogChannelDWARF::GetPluginVersion() +{ + return 1; +} + + +void +LogChannelDWARF::GetPluginCommandHelp (const char *command, Stream *strm) +{ +} + + +Error +LogChannelDWARF::ExecutePluginCommand (Args &command, Stream *strm) +{ + Error error; + error.SetErrorStringWithFormat("No commands are supported.\n"); + return error; +} + + +Log * +LogChannelDWARF::EnablePluginLogging (Stream *strm, Args &command) +{ + return NULL; +} + + +void +LogChannelDWARF::Disable () +{ + g_log_channel = NULL; + m_log_sp.reset(); +} + +bool +LogChannelDWARF::Enable +( + StreamSP &log_stream_sp, + uint32_t log_options, + Stream *feedback_strm, // Feedback stream for argument errors etc + const Args &categories // The categories to enable within this logging stream, if empty, enable default set +) +{ + Disable (); + + m_log_sp.reset(new Log (log_stream_sp)); + g_log_channel = this; + uint32_t flag_bits = 0; + bool got_unknown_category = false; + const size_t argc = categories.GetArgumentCount(); + for (size_t i=0; i<argc; ++i) + { + const char *arg = categories.GetArgumentAtIndex(i); + + if (::strcasecmp (arg, "all") == 0 ) flag_bits |= DWARF_LOG_ALL; + else if (::strcasecmp (arg, "info") == 0 ) flag_bits |= DWARF_LOG_DEBUG_INFO; + else if (::strcasecmp (arg, "line") == 0 ) flag_bits |= DWARF_LOG_DEBUG_LINE; + else if (::strcasecmp (arg, "pubnames") == 0 ) flag_bits |= DWARF_LOG_DEBUG_PUBNAMES; + else if (::strcasecmp (arg, "pubtypes") == 0 ) flag_bits |= DWARF_LOG_DEBUG_PUBTYPES; + else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= DWARF_LOG_DEFAULT; + else + { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + if (got_unknown_category == false) + { + got_unknown_category = true; + ListCategories (feedback_strm); + } + } + } + if (flag_bits == 0) + flag_bits = DWARF_LOG_DEFAULT; + m_log_sp->GetMask().SetAllFlagBits(flag_bits); + m_log_sp->GetOptions().SetAllFlagBits(log_options); + return m_log_sp.get() != NULL; +} + +void +LogChannelDWARF::ListCategories (Stream *strm) +{ + strm->Printf("Logging categories for '%s':\n" + " all - turn on all available logging categories\n" + " info - log the parsing if .debug_info\n" + " line - log the parsing if .debug_line\n" + " pubnames - log the parsing if .debug_pubnames\n" + " pubtypes - log the parsing if .debug_pubtypes\n\n", + SymbolFileDWARF::GetPluginNameStatic()); +} + +Log * +LogChannelDWARF::GetLog () +{ + if (g_log_channel) + return g_log_channel->m_log_sp.get(); + else + return NULL; +} + +Log * +LogChannelDWARF::GetLogIfAll (uint32_t mask) +{ + Log *log = GetLog(); + if (log) + if (log->GetMask().IsSet(mask)) + return log; + return NULL; +} + + +void +LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...) +{ + if (g_log_channel) + { + LogSP log_sp(g_log_channel->m_log_sp); + va_list args; + va_start (args, format); + log_sp->VAPrintf (format, args); + va_end (args); + } +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h new file mode 100644 index 00000000000..943d1da194f --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -0,0 +1,91 @@ +//===-- LogChannelDWARF.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LogChannelDWARF_h_ +#define liblldb_LogChannelDWARF_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes + +// Project includes +#include "lldb/Core/Log.h" + +#define DWARF_LOG_VERBOSE (1u << 0) +#define DWARF_LOG_DEBUG_INFO (1u << 1) +#define DWARF_LOG_DEBUG_LINE (1u << 2) +#define DWARF_LOG_DEBUG_PUBNAMES (1u << 3) +#define DWARF_LOG_DEBUG_PUBTYPES (1u << 4) +#define DWARF_LOG_ALL (UINT32_MAX) +#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO) + +class LogChannelDWARF : public lldb_private::LogChannel +{ +public: + LogChannelDWARF (); + + virtual + ~LogChannelDWARF (); + + static void + Initialize(); + + static void + Terminate(); + + static const char * + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::LogChannel * + CreateInstance (); + + virtual const char * + GetPluginName(); + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp (const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command); + + virtual void + Disable (); + + virtual bool + Enable (lldb::StreamSP &log_stream_sp, + uint32_t log_options, + lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc + const lldb_private::Args &categories); // The categories to enable within this logging stream, if empty, enable default set + + virtual void + ListCategories (lldb_private::Stream *strm); + + static lldb_private::Log * + GetLog (); + + static lldb_private::Log * + GetLogIfAll (uint32_t mask); + + static void + LogIf (uint32_t mask, const char *format, ...); +}; + +#endif // liblldb_LogChannelDWARF_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp new file mode 100644 index 00000000000..ffee695d3ab --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -0,0 +1,3615 @@ +//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileDWARF.h" + +// Other libraries and framework includes +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclGroup.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Specifiers.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/Value.h" + +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/VariableList.h" + +#include "DWARFCompileUnit.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFDebugLine.h" +#include "DWARFDebugPubnames.h" +#include "DWARFDebugRanges.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "DWARFLocationList.h" +#include "LogChannelDWARF.h" + +#include <map> + +#define DIE_IS_BEING_PARSED ((void*)1) + +using namespace lldb; +using namespace lldb_private; + + +static const ConstString& +GetSectionNameDebugInfo() +{ + static const ConstString g_sect_name("__debug_info"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugAbbrev() +{ + static const ConstString g_sect_name ("__debug_abbrev"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugAranges() +{ + static const ConstString g_sect_name ("__debug_aranges"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugFrame() +{ + static const ConstString g_sect_name ("__debug_frame"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugLine() +{ + static const ConstString g_sect_name ("__debug_line"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugLoc() +{ + static const ConstString g_sect_name ("__debug_loc"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugMacInfo() +{ + static const ConstString g_sect_name ("__debug_macinfo"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugPubNames() +{ + static const ConstString g_sect_name ("__debug_pubnames"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugPubTypes() +{ + static const ConstString g_sect_name ("__debug_pubtypes"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugRanges() +{ + static const ConstString g_sect_name ("__debug_ranges"); + return g_sect_name; +} + +static const ConstString& +GetSectionNameDebugStr() +{ + static const ConstString g_sect_name ("__debug_str"); + return g_sect_name; +} + +static uint32_t +DwarfToClangAccessibility (uint32_t dwarf_accessibility) +{ + switch (dwarf_accessibility) + { + case DW_ACCESS_public: + return clang::AS_public; + case DW_ACCESS_private: + return clang::AS_private; + case DW_ACCESS_protected: + return clang::AS_protected; + default: + return clang::AS_none; + } +} + +void +SymbolFileDWARF::Initialize() +{ + LogChannelDWARF::Initialize(); + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +SymbolFileDWARF::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); + LogChannelDWARF::Initialize(); +} + + +const char * +SymbolFileDWARF::GetPluginNameStatic() +{ + return "symbol-file.dwarf2"; +} + +const char * +SymbolFileDWARF::GetPluginDescriptionStatic() +{ + return "DWARF and DWARF3 debug symbol file reader."; +} + + +SymbolFile* +SymbolFileDWARF::CreateInstance (ObjectFile* obj_file) +{ + return new SymbolFileDWARF(obj_file); +} + +//---------------------------------------------------------------------- +// Gets the first parent that is a lexical block, function or inlined +// subroutine, or compile unit. +//---------------------------------------------------------------------- +static const DWARFDebugInfoEntry * +GetParentSymbolContextDIE(const DWARFDebugInfoEntry *child_die) +{ + const DWARFDebugInfoEntry *die; + for (die = child_die->GetParent(); die != NULL; die = die->GetParent()) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_compile_unit: + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + return die; + } + } + return NULL; +} + + +SymbolFileDWARF::SymbolFileDWARF(ObjectFile* ofile) : + SymbolFile(ofile), + m_flags(), + m_data_debug_abbrev(), + m_data_debug_aranges(), + m_data_debug_frame(), + m_data_debug_info(), + m_data_debug_line(), + m_data_debug_loc(), + m_data_debug_macinfo(), + m_data_debug_pubnames(), + m_data_debug_pubtypes(), + m_data_debug_ranges(), + m_data_debug_str(), + m_abbr(), + m_aranges(), + m_info(), + m_line(), + m_name_to_function_die(), + m_name_to_inlined_die(), + m_name_to_global_die(), + m_name_to_type_die(), + m_indexed(false), +// m_pubnames(), +// m_pubtypes(), +// m_pubbasetypes(), + m_ranges()//, +// m_type_fixups(), +// m_indirect_fixups() +{ +} + +SymbolFileDWARF::~SymbolFileDWARF() +{ +} + +bool +SymbolFileDWARF::SupportedVersion(uint16_t version) +{ + return version == 2 || version == 3; +} + +uint32_t +SymbolFileDWARF::GetAbilities () +{ + uint32_t abilities = 0; + if (m_obj_file != NULL) + { + const Section* section = NULL; + const SectionList *section_list = m_obj_file->GetSectionList(); + if (section_list == NULL) + return 0; + + uint64_t debug_abbrev_file_size = 0; + uint64_t debug_aranges_file_size = 0; + uint64_t debug_frame_file_size = 0; + uint64_t debug_info_file_size = 0; + uint64_t debug_line_file_size = 0; + uint64_t debug_loc_file_size = 0; + uint64_t debug_macinfo_file_size = 0; + uint64_t debug_pubnames_file_size = 0; + uint64_t debug_pubtypes_file_size = 0; + uint64_t debug_ranges_file_size = 0; + uint64_t debug_str_file_size = 0; + + static ConstString g_dwarf_section_name ("__DWARF"); + + section = section_list->FindSectionByName(g_dwarf_section_name).get(); + + if (section) + section->MemoryMapSectionDataFromObjectFile(m_obj_file, m_dwarf_data); + + section = section_list->FindSectionByName (GetSectionNameDebugInfo()).get(); + if (section != NULL) + { + debug_info_file_size = section->GetByteSize(); + + section = section_list->FindSectionByName (GetSectionNameDebugAbbrev()).get(); + if (section) + debug_abbrev_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugAbbrevData); + + section = section_list->FindSectionByName (GetSectionNameDebugAranges()).get(); + if (section) + debug_aranges_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugArangesData); + + section = section_list->FindSectionByName (GetSectionNameDebugFrame()).get(); + if (section) + debug_frame_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugFrameData); + + section = section_list->FindSectionByName (GetSectionNameDebugLine()).get(); + if (section) + debug_line_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugLineData); + + section = section_list->FindSectionByName (GetSectionNameDebugLoc()).get(); + if (section) + debug_loc_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugLocData); + + section = section_list->FindSectionByName (GetSectionNameDebugMacInfo()).get(); + if (section) + debug_macinfo_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugMacInfoData); + + section = section_list->FindSectionByName (GetSectionNameDebugPubNames()).get(); + if (section) + debug_pubnames_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugPubNamesData); + + section = section_list->FindSectionByName (GetSectionNameDebugPubTypes()).get(); + if (section) + debug_pubtypes_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugPubTypesData); + + section = section_list->FindSectionByName (GetSectionNameDebugRanges()).get(); + if (section) + debug_ranges_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugRangesData); + + section = section_list->FindSectionByName (GetSectionNameDebugStr()).get(); + if (section) + debug_str_file_size = section->GetByteSize(); + else + m_flags.Set (flagsGotDebugStrData); + } + + if (debug_abbrev_file_size > 0 && debug_info_file_size > 0) + abilities |= CompileUnits | Functions | Blocks | GlobalVariables | LocalVariables | VariableTypes; + + if (debug_line_file_size > 0) + abilities |= LineTables; + + if (debug_aranges_file_size > 0) + abilities |= AddressAcceleratorTable; + + if (debug_pubnames_file_size > 0) + abilities |= FunctionAcceleratorTable; + + if (debug_pubtypes_file_size > 0) + abilities |= TypeAcceleratorTable; + + if (debug_macinfo_file_size > 0) + abilities |= MacroInformation; + + if (debug_frame_file_size > 0) + abilities |= CallFrameInformation; + } + return abilities; +} + +const DataExtractor& +SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, const ConstString §ion_name, DataExtractor &data) +{ + if (m_flags.IsClear (got_flag)) + { + m_flags.Set (got_flag); + const SectionList *section_list = m_obj_file->GetSectionList(); + if (section_list) + { + Section *section = section_list->FindSectionByName (section_name).get(); + if (section ) + { + // See if we memory mapped the DWARF segment? + if (m_dwarf_data.GetByteSize()) + { + data.SetData(m_dwarf_data, section->GetOffset (), section->GetByteSize()); + } + else + { + if (section->ReadSectionDataFromObjectFile(m_obj_file, data) == 0) + data.Clear(); + } + } + } + } + return data; +} + +const DataExtractor& +SymbolFileDWARF::get_debug_abbrev_data() +{ + return GetCachedSectionData (flagsGotDebugAbbrevData, GetSectionNameDebugAbbrev(), m_data_debug_abbrev); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_aranges_data() +{ + return GetCachedSectionData (flagsGotDebugArangesData, GetSectionNameDebugAranges(), m_data_debug_aranges); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_frame_data() +{ + return GetCachedSectionData (flagsGotDebugFrameData, GetSectionNameDebugFrame(), m_data_debug_frame); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_info_data() +{ + return GetCachedSectionData (flagsGotDebugInfoData, GetSectionNameDebugInfo(), m_data_debug_info); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_line_data() +{ + return GetCachedSectionData (flagsGotDebugLineData, GetSectionNameDebugLine(), m_data_debug_line); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_loc_data() +{ + return GetCachedSectionData (flagsGotDebugLocData, GetSectionNameDebugLoc(), m_data_debug_loc); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_macinfo_data() +{ + return GetCachedSectionData (flagsGotDebugMacInfoData, GetSectionNameDebugMacInfo(), m_data_debug_macinfo); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_pubnames_data() +{ + return GetCachedSectionData (flagsGotDebugPubNamesData, GetSectionNameDebugPubNames(), m_data_debug_pubnames); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_pubtypes_data() +{ + return GetCachedSectionData (flagsGotDebugPubTypesData, GetSectionNameDebugPubTypes(), m_data_debug_pubtypes); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_ranges_data() +{ + return GetCachedSectionData (flagsGotDebugRangesData, GetSectionNameDebugRanges(), m_data_debug_ranges); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_str_data() +{ + return GetCachedSectionData (flagsGotDebugStrData, GetSectionNameDebugStr(), m_data_debug_str); +} + + +DWARFDebugAbbrev* +SymbolFileDWARF::DebugAbbrev() +{ + if (m_abbr.get() == NULL) + { + const DataExtractor &debug_abbrev_data = get_debug_abbrev_data(); + if (debug_abbrev_data.GetByteSize() > 0) + { + m_abbr.reset(new DWARFDebugAbbrev()); + if (m_abbr.get()) + m_abbr->Parse(debug_abbrev_data); + } + } + return m_abbr.get(); +} + +const DWARFDebugAbbrev* +SymbolFileDWARF::DebugAbbrev() const +{ + return m_abbr.get(); +} + +DWARFDebugAranges* +SymbolFileDWARF::DebugAranges() +{ + if (m_aranges.get() == NULL) + { + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); + m_aranges.reset(new DWARFDebugAranges()); + if (m_aranges.get()) + { + const DataExtractor &debug_aranges_data = get_debug_aranges_data(); + if (debug_aranges_data.GetByteSize() > 0) + m_aranges->Extract(debug_aranges_data); + else + m_aranges->Generate(this); + } + } + return m_aranges.get(); +} + +const DWARFDebugAranges* +SymbolFileDWARF::DebugAranges() const +{ + return m_aranges.get(); +} + + +DWARFDebugInfo* +SymbolFileDWARF::DebugInfo() +{ + if (m_info.get() == NULL) + { + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); + if (get_debug_info_data().GetByteSize() > 0) + { + m_info.reset(new DWARFDebugInfo()); + if (m_info.get()) + { + m_info->SetDwarfData(this); + } + } + } + return m_info.get(); +} + +const DWARFDebugInfo* +SymbolFileDWARF::DebugInfo() const +{ + return m_info.get(); +} + +//DWARFDebugLine* +//SymbolFileDWARF::DebugLine() +//{ +// if (m_line.get() == NULL) +// { +// Timer scoped_timer(__PRETTY_FUNCTION__); +// const DataExtractor &debug_line_data = debug_line(); +// if (debug_line_data.GetByteSize() > 0) +// { +// m_line.reset(new DWARFDebugLine()); +// if (m_line.get()) +// m_line->Parse(debug_line_data); +// } +// } +// return m_line.get(); +//} +// +//const DWARFDebugLine* +//SymbolFileDWARF::DebugLine() const +//{ +// return m_line.get(); +//} + + +DWARFCompileUnit* +SymbolFileDWARF::GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid) +{ + DWARFDebugInfo* info = DebugInfo(); + if (info) + return info->GetCompileUnit(cu_uid).get(); + return NULL; +} + +//DWARFCompileUnit* +//SymbolFileDWARF::GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu) +//{ +// DWARFCompileUnit* cu = NULL; +// DWARFDebugInfo* info = DebugInfo(); +// if (info) +// { +// uint32_t cu_idx = 0; +// if (prev_cu != NULL) +// { +// // Find the index of the previus DWARF compile unit if one was provided +// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL) +// { +// ++cu_idx; +// if (cu == prev_cu) +// break; +// } +// } +// +// // Now find the next unparsed DWARF compile unit. We do this by checking the +// // user data in the DWARFCompileUnit class that starts as NULL, and eventually +// // holds a pointer to the CompileUnit that was created for it after it has +// // been parsed. +// while ((cu = info->GetCompileUnitAtIndex(cu_idx)) != NULL) +// { +// if (cu->GetUserData() == NULL) +// break; +// } +// } +// return cu; +//} + +DWARFDebugRanges* +SymbolFileDWARF::DebugRanges() +{ + if (m_ranges.get() == NULL) + { + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); + if (get_debug_ranges_data().GetByteSize() > 0) + { + m_ranges.reset(new DWARFDebugRanges()); + if (m_ranges.get()) + m_ranges->Extract(this); + } + } + return m_ranges.get(); +} + +const DWARFDebugRanges* +SymbolFileDWARF::DebugRanges() const +{ + return m_ranges.get(); +} +// +//DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubnames() +//{ +// if (m_pubnames.get() == NULL) +// { +// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); +// const DataExtractor &debug_pubnames_data = get_debug_pubnames_data(); +// if (debug_pubnames_data.GetByteSize() > 0) +// { +// // Pass false to indicate this is a pubnames section +// m_pubnames.reset(new DWARFDebugPubnames()); +// if (m_pubnames.get()) +// { +// // "m_pubnames->GeneratePubnames" is costly, but needed for global variables +// m_pubnames->GeneratePubnames(this); +// +//#if 0 +// StreamFile s(stdout); +// s.Printf (".debug_pubnames for %s/%s:\n", +// m_obj_file->GetModule()->GetFileSpec().GetDirectory().AsCString(), +// m_obj_file->GetModule()->GetFileSpec().GetFilename().AsCString()); +// m_pubnames->Dump (&s); +//#endif +// // "m_pubnames->Extract" is quicker, but the pubnames don't always contain what we need. +// //m_pubnames->Extract(debug_pubnames_data); +// } +// } +// } +// return m_pubnames.get(); +//} +// +//const DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubnames() const +//{ +// return m_pubnames.get(); +//} + +//DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubBaseTypes() +//{ +// if (m_pubbasetypes.get() == NULL) +// { +// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); +// // Pass false to indicate this is a pubnames section +// m_pubbasetypes.reset(new DWARFDebugPubnames()); +// if (m_pubbasetypes.get()) +// m_pubbasetypes->GeneratePubBaseTypes(this); +// } +// return m_pubbasetypes.get(); +//} +// +//const DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubBaseTypes() const +//{ +// return m_pubbasetypes.get(); +//} +// +//const DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubtypes() const +//{ +// return m_pubtypes.get(); +//} +// +//DWARFDebugPubnames* +//SymbolFileDWARF::DebugPubtypes() +//{ +// if (m_pubtypes.get() == NULL) +// { +// Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this); +// const DataExtractor &debug_pubtypes_data = get_debug_pubtypes_data(); +// if (debug_pubtypes_data.GetByteSize() > 0) +// { +// // Pass false to indicate this is a pubnames section +// m_pubtypes.reset(new DWARFDebugPubnames()); +// if (m_pubtypes.get()) +// m_pubtypes->Extract(debug_pubtypes_data); +// } +// } +// return m_pubtypes.get(); +//} +// + +bool +SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit* cu, CompUnitSP& compile_unit_sp) +{ + if (cu != NULL) + { + const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly (); + if (cu_die) + { + const char * cu_die_name = cu_die->GetName(this, cu); + const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL); + Language::Type language = (Language::Type)cu_die->GetAttributeValueAsUnsigned(this, cu, DW_AT_language, 0); + if (cu_die_name) + { + if (cu_die_name[0] == '/' || cu_comp_dir == NULL && cu_comp_dir[0]) + { + compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, cu_die_name, cu->GetOffset(), language)); + } + else + { + std::string fullpath(cu_comp_dir); + if (*fullpath.rbegin() != '/') + fullpath += '/'; + fullpath += cu_die_name; + + compile_unit_sp.reset(new CompileUnit(m_obj_file->GetModule(), cu, fullpath.c_str(), cu->GetOffset(), language)); + } + + if (compile_unit_sp.get()) + { + cu->SetUserData(compile_unit_sp.get()); + return true; + } + } + } + } + return false; +} + +#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST + +void +SymbolFileDWARF::ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die) +{ + while (die != NULL) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_base_type: + // Put all base types into the base type compile unit + fs_to_dies[base_types_fspec].Insert(die); + break; + + default: + { + uint32_t decl_file = die->GetAttributeValueAsUnsigned(this, dw_cu, DW_AT_decl_file, 0); + if (decl_file) + { + fs_to_dies[dc_cu->GetSupportFiles().GetFileSpecAtIndex(decl_file)].Insert(die); + } + else + { + // add this to the current compile unit + fs_to_dies[cu_fspec].Insert(die); + } + } + break; + } + + die = die->GetSibling(); + } +} + + + +#endif + +uint32_t +SymbolFileDWARF::GetNumCompileUnits() +{ + DWARFDebugInfo* info = DebugInfo(); + if (info) + { +#if defined LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST + uint32_t cu_idx; + FSToDIES fs_to_dies; + + FileSpec base_type_fspec("DW_TAG_base_type"); + const uint32_t num_comp_units = info->GetNumCompileUnits(); + + for (cu_idx=0; cu_idx < num_comp_units; ++cu_idx) + { + DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx); + if (cu != NULL) + { + const DWARFDebugInfoEntry *cu_die = cu->DIE(); + if (cu_die) + { + CompUnitSP dc_cu_sp; + ParseCompileUnit(cu, dc_cu_sp); + if (dc_cu_sp.get()) + { + FileSpec cu_fspec(*dc_cu_sp.get()); + + ShrinkDSYM(dc_cu_sp.get(), cu, cu_fspec, base_type_fspec, fs_to_dies, cu->DIE()->GetFirstChild()); + } + } + } + } + + Stream strm(stdout); + FSToDIES::const_iterator pos, end = fs_to_dies.end(); + for (pos = fs_to_dies.begin(); pos != end; ++pos) + { + strm << "\n\nMinimal Compile Unit: " << pos->first << ":\n"; + const DWARFDIECollection& dies = pos->second; + dies.Dump(strm, NULL); + } + return num_comp_units; +#else + return info->GetNumCompileUnits(); +#endif + } + return 0; +} + +CompUnitSP +SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) +{ + CompUnitSP comp_unit; + DWARFDebugInfo* info = DebugInfo(); + if (info) + { + DWARFCompileUnit* cu = info->GetCompileUnitAtIndex(cu_idx); + if (cu != NULL) + { + // Our symbol vendor shouldn't be asking us to add a compile unit that + // has already been added to it, which this DWARF plug-in knows as it + // stores the lldb compile unit (CompileUnit) pointer in each + // DWARFCompileUnit object when it gets added. + assert(cu->GetUserData() == NULL); + ParseCompileUnit(cu, comp_unit); + } + } + return comp_unit; +} + +static void +AddRangesToBlock +( + BlockList& blocks, + lldb::user_id_t blockID, + DWARFDebugRanges::RangeList& ranges, + addr_t block_base_addr +) +{ + ranges.SubtractOffset (block_base_addr); + size_t range_idx = 0; + const DWARFDebugRanges::Range *debug_range; + for (range_idx = 0; (debug_range = ranges.RangeAtIndex(range_idx)) != NULL; range_idx++) + { + blocks.AddRange(blockID, debug_range->begin_offset, debug_range->end_offset); + } +} + + +Function * +SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die) +{ + DWARFDebugRanges::RangeList func_ranges; + const char *name = NULL; + const char *mangled = NULL; + int decl_file = 0; + int decl_line = 0; + int decl_column = 0; + int call_file = 0; + int call_line = 0; + int call_column = 0; + DWARFExpression frame_base; + + // Parse the function prototype as a type that can then be added to concrete function instance + ParseTypes (sc, dwarf_cu, die, false, false); + //FixupTypes(); + + if (die->GetDIENamesAndRanges(this, dwarf_cu, name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column, &frame_base)) + { + // Union of all ranges in the function DIE (if the function is discontiguous) + AddressRange func_range; + lldb::addr_t lowest_func_addr = func_ranges.LowestAddress(0); + lldb::addr_t highest_func_addr = func_ranges.HighestAddress(0); + if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr) + { + func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, m_obj_file->GetSectionList()); + if (func_range.GetBaseAddress().IsValid()) + func_range.SetByteSize(highest_func_addr - lowest_func_addr); + } + + if (func_range.GetBaseAddress().IsValid()) + { + Mangled func_name; + if (mangled) + func_name.SetValue(mangled, true); + else if (name) + func_name.SetValue(name, false); + + FunctionSP func_sp; + std::auto_ptr<Declaration> decl_ap; + if (decl_file != 0 || decl_line != 0 || decl_column != 0) + decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column)); + + Type *func_type = NULL; + + if (die->GetUserData() != DIE_IS_BEING_PARSED) + func_type = (Type*)die->GetUserData(); + + assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); + + func_range.GetBaseAddress().ResolveLinkedAddress(); + + func_sp.reset(new Function (sc.comp_unit, + die->GetOffset(), // UserID is the DIE offset + die->GetOffset(), + func_name, + func_type, + func_range)); // first address range + + if (func_sp.get() != NULL) + { + func_sp->GetFrameBaseExpression() = frame_base; + sc.comp_unit->AddFunction(func_sp); + return func_sp.get(); + } + } + } + return NULL; +} + +size_t +SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) +{ + assert (sc.comp_unit); + size_t functions_added = 0; + const DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + if (dwarf_cu) + { + DWARFDIECollection function_dies; + const size_t num_funtions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies); + size_t func_idx; + for (func_idx = 0; func_idx < num_funtions; ++func_idx) + { + const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx); + if (sc.comp_unit->FindFunctionByUID (die->GetOffset()).get() == NULL) + { + if (ParseCompileUnitFunction(sc, dwarf_cu, die)) + ++functions_added; + } + } + //FixupTypes(); + } + return functions_added; +} + +bool +SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) +{ + assert (sc.comp_unit); + DWARFCompileUnit* cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + assert (cu); + const DWARFDebugInfoEntry * cu_die = cu->GetCompileUnitDIEOnly(); + + if (cu_die) + { + const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, cu, DW_AT_comp_dir, NULL); + dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, cu, DW_AT_stmt_list, DW_INVALID_OFFSET); + + // All file indexes in DWARF are one based and a file of index zero is + // supposed to be the compile unit itself. + support_files.Append (*sc.comp_unit); + + return DWARFDebugLine::ParseSupportFiles(get_debug_line_data(), cu_comp_dir, stmt_list, support_files); + } + return false; +} + +struct ParseDWARFLineTableCallbackInfo +{ + LineTable* line_table; + const SectionList *section_list; + lldb::addr_t prev_sect_file_base_addr; + lldb::addr_t curr_sect_file_base_addr; + bool is_oso_for_debug_map; + bool prev_in_final_executable; + DWARFDebugLine::Row prev_row; + SectionSP prev_section_sp; + SectionSP curr_section_sp; +}; + +//---------------------------------------------------------------------- +// ParseStatementTableCallback +//---------------------------------------------------------------------- +static void +ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData) +{ + LineTable* line_table = ((ParseDWARFLineTableCallbackInfo*)userData)->line_table; + if (state.row == DWARFDebugLine::State::StartParsingLineTable) + { + // Just started parsing the line table + } + else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) + { + // Done parsing line table, nothing to do for the cleanup + } + else + { + ParseDWARFLineTableCallbackInfo* info = (ParseDWARFLineTableCallbackInfo*)userData; + // We have a new row, lets append it + + if (info->curr_section_sp.get() == NULL || info->curr_section_sp->ContainsFileAddress(state.address) == false) + { + info->prev_section_sp = info->curr_section_sp; + info->prev_sect_file_base_addr = info->curr_sect_file_base_addr; + // If this is an end sequence entry, then we subtract one from the + // address to make sure we get an address that is not the end of + // a section. + if (state.end_sequence && state.address != 0) + info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address - 1); + else + info->curr_section_sp = info->section_list->FindSectionContainingFileAddress (state.address); + + if (info->curr_section_sp.get()) + info->curr_sect_file_base_addr = info->curr_section_sp->GetFileAddress (); + else + info->curr_sect_file_base_addr = 0; + } + if (info->curr_section_sp.get()) + { + lldb::addr_t curr_line_section_offset = state.address - info->curr_sect_file_base_addr; + // Check for the fancy section magic to determine if we + + if (info->is_oso_for_debug_map) + { + // When this is a debug map object file that contains DWARF + // (referenced from an N_OSO debug map nlist entry) we will have + // a file address in the file range for our section from the + // original .o file, and a load address in the executable that + // contains the debug map. + // + // If the sections for the file range and load range are + // different, we have a remapped section for the function and + // this address is resolved. If they are the same, then the + // function for this address didn't make it into the final + // executable. + bool curr_in_final_executable = info->curr_section_sp->GetLinkedSection () != NULL; + + // If we are doing DWARF with debug map, then we need to carefully + // add each line table entry as there may be gaps as functions + // get moved around or removed. + if (!info->prev_row.end_sequence && info->prev_section_sp.get()) + { + if (info->prev_in_final_executable) + { + bool terminate_previous_entry = false; + if (!curr_in_final_executable) + { + // Check for the case where the previous line entry + // in a function made it into the final executable, + // yet the current line entry falls in a function + // that didn't. The line table used to be contiguous + // through this address range but now it isn't. We + // need to terminate the previous line entry so + // that we can reconstruct the line range correctly + // for it and to keep the line table correct. + terminate_previous_entry = true; + } + else if (info->curr_section_sp.get() != info->prev_section_sp.get()) + { + // Check for cases where the line entries used to be + // contiguous address ranges, but now they aren't. + // This can happen when order files specify the + // ordering of the functions. + lldb::addr_t prev_line_section_offset = info->prev_row.address - info->prev_sect_file_base_addr; + Section *curr_sect = info->curr_section_sp.get(); + Section *prev_sect = info->prev_section_sp.get(); + assert (curr_sect->GetLinkedSection()); + assert (prev_sect->GetLinkedSection()); + lldb::addr_t object_file_addr_delta = state.address - info->prev_row.address; + lldb::addr_t curr_linked_file_addr = curr_sect->GetLinkedFileAddress() + curr_line_section_offset; + lldb::addr_t prev_linked_file_addr = prev_sect->GetLinkedFileAddress() + prev_line_section_offset; + lldb::addr_t linked_file_addr_delta = curr_linked_file_addr - prev_linked_file_addr; + if (object_file_addr_delta != linked_file_addr_delta) + terminate_previous_entry = true; + } + + if (terminate_previous_entry) + { + line_table->InsertLineEntry (info->prev_section_sp, + state.address - info->prev_sect_file_base_addr, + info->prev_row.line, + info->prev_row.column, + info->prev_row.file, + false, // is_stmt + false, // basic_block + false, // state.prologue_end + false, // state.epilogue_begin + true); // end_sequence); + } + } + } + + if (curr_in_final_executable) + { + line_table->InsertLineEntry (info->curr_section_sp, + curr_line_section_offset, + state.line, + state.column, + state.file, + state.is_stmt, + state.basic_block, + state.prologue_end, + state.epilogue_begin, + state.end_sequence); + info->prev_section_sp = info->curr_section_sp; + } + else + { + // If the current address didn't make it into the final + // executable, the current section will be the __text + // segment in the .o file, so we need to clear this so + // we can catch the next function that did make it into + // the final executable. + info->prev_section_sp.reset(); + info->curr_section_sp.reset(); + } + + info->prev_in_final_executable = curr_in_final_executable; + } + else + { + // We are not in an object file that contains DWARF for an + // N_OSO, this is just a normal DWARF file. The DWARF spec + // guarantees that the addresses will be in increasing order + // so, since we store line tables in file address order, we + // can always just append the line entry without needing to + // search for the correct insertion point (we don't need to + // use LineEntry::InsertLineEntry()). + line_table->AppendLineEntry (info->curr_section_sp, + curr_line_section_offset, + state.line, + state.column, + state.file, + state.is_stmt, + state.basic_block, + state.prologue_end, + state.epilogue_begin, + state.end_sequence); + } + } + + info->prev_row = state; + } +} + +bool +SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc) +{ + assert (sc.comp_unit); + if (sc.comp_unit->GetLineTable() != NULL) + return true; + + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + if (dwarf_cu) + { + const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const dw_offset_t cu_line_offset = dwarf_cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET); + if (cu_line_offset != DW_INVALID_OFFSET) + { + std::auto_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit)); + if (line_table_ap.get()) + { + ParseDWARFLineTableCallbackInfo info = { line_table_ap.get(), m_obj_file->GetSectionList(), 0, 0, m_flags.IsSet (flagsDWARFIsOSOForDebugMap), false}; + uint32_t offset = cu_line_offset; + DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info); + sc.comp_unit->SetLineTable(line_table_ap.release()); + return true; + } + } + } + return false; +} + +size_t +SymbolFileDWARF::ParseFunctionBlocks +( + const SymbolContext& sc, + lldb::user_id_t parentBlockID, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + addr_t subprogram_low_pc, + bool parse_siblings, + bool parse_children +) +{ + size_t blocks_added = 0; + while (die != NULL) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + { + DWARFDebugRanges::RangeList ranges; + const char *name = NULL; + const char *mangled_name = NULL; + BlockList& blocks = sc.function->GetBlocks(false); + + lldb::user_id_t blockID = blocks.AddChild(parentBlockID, die->GetOffset()); + int decl_file = 0; + int decl_line = 0; + int decl_column = 0; + int call_file = 0; + int call_line = 0; + int call_column = 0; + if (die->GetDIENamesAndRanges(this, dwarf_cu, name, mangled_name, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column)) + { + if (tag == DW_TAG_subprogram) + { + assert (subprogram_low_pc == LLDB_INVALID_ADDRESS); + subprogram_low_pc = ranges.LowestAddress(0); + } + + AddRangesToBlock (blocks, blockID, ranges, subprogram_low_pc); + + if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL)) + { + std::auto_ptr<Declaration> decl_ap; + if (decl_file != 0 || decl_line != 0 || decl_column != 0) + decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, decl_column)); + + std::auto_ptr<Declaration> call_ap; + if (call_file != 0 || call_line != 0 || call_column != 0) + call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file), call_line, call_column)); + + blocks.SetInlinedFunctionInfo(blockID, name, mangled_name, decl_ap.get(), call_ap.get()); + } + + ++blocks_added; + + if (parse_children && die->HasChildren()) + { + blocks_added += ParseFunctionBlocks(sc, blockID, dwarf_cu, die->GetFirstChild(), subprogram_low_pc, true, true); + } + } + } + break; + default: + break; + } + + if (parse_siblings) + die = die->GetSibling(); + else + die = NULL; + } + return blocks_added; +} + +size_t +SymbolFileDWARF::ParseChildMembers +( + const SymbolContext& sc, + TypeSP& type_sp, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + std::vector<clang::CXXBaseSpecifier *>& base_classes, + std::vector<int>& member_accessibilities, + int& default_accessibility, + bool &is_a_class +) +{ + if (parent_die == NULL) + return 0; + + TypeList* type_list = m_obj_file->GetModule()->GetTypeList(); + + size_t count = 0; + const DWARFDebugInfoEntry *die; + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_member: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + Declaration decl; + DWARFExpression location; + const char *name = NULL; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + uint32_t accessibility = clang::AS_none; + off_t member_offset = 0; + size_t byte_size = 0; + size_t bit_offset = 0; + size_t bit_size = 0; + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_bit_offset: bit_offset = form_value.Unsigned(); break; + case DW_AT_bit_size: bit_size = form_value.Unsigned(); break; + case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_data_member_location: + if (form_value.BlockData()) + { + Value initialValue(0); + Value memberOffset(0); + const DataExtractor& debug_info_data = get_debug_info_data(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + if (DWARFExpression::Evaluate(NULL, NULL, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL)) + { + member_offset = memberOffset.ResolveValue(NULL, NULL).UInt(); + } + } + break; + + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility (form_value.Unsigned()); break; + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_mutable: + case DW_AT_visibility: + default: + case DW_AT_sibling: + break; + } + } + } + + Type *member_type = ResolveTypeUID(encoding_uid); + assert(member_type); + if (accessibility == clang::AS_none) + accessibility = default_accessibility; + member_accessibilities.push_back(accessibility); + + type_list->GetClangASTContext().AddFieldToRecordType (type_sp->GetOpaqueClangQualType(), name, member_type->GetOpaqueClangQualType(), accessibility, bit_size); + } + } + break; + + case DW_TAG_subprogram: + { + is_a_class = true; + if (default_accessibility == clang::AS_none) + default_accessibility = clang::AS_private; + // TODO: implement DW_TAG_subprogram type parsing +// UserDefTypeChildInfo method_info(die->GetOffset()); +// +// FunctionSP func_sp (sc.comp_unit->FindFunctionByUID (die->GetOffset())); +// if (func_sp.get() == NULL) +// ParseCompileUnitFunction(sc, dwarf_cu, die); +// +// method_info.SetEncodingTypeUID(die->GetOffset()); +// struct_udt->AddMethod(method_info); + } + break; + + case DW_TAG_inheritance: + { + is_a_class = true; + if (default_accessibility == clang::AS_none) + default_accessibility = clang::AS_private; + // TODO: implement DW_TAG_inheritance type parsing + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + Declaration decl; + DWARFExpression location; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + uint32_t accessibility = default_accessibility; + bool is_virtual = false; + bool is_base_of_class = true; + off_t member_offset = 0; + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_data_member_location: + if (form_value.BlockData()) + { + Value initialValue(0); + Value memberOffset(0); + const DataExtractor& debug_info_data = get_debug_info_data(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + if (DWARFExpression::Evaluate(NULL, NULL, debug_info_data, NULL, NULL, block_offset, block_length, eRegisterKindDWARF, &initialValue, memberOffset, NULL)) + { + member_offset = memberOffset.ResolveValue(NULL, NULL).UInt(); + } + } + break; + + case DW_AT_accessibility: + accessibility = DwarfToClangAccessibility(form_value.Unsigned()); + break; + + case DW_AT_virtuality: is_virtual = form_value.Unsigned() != 0; break; + default: + case DW_AT_sibling: + break; + } + } + } + + Type *base_class_dctype = ResolveTypeUID(encoding_uid); + assert(base_class_dctype); + base_classes.push_back (type_list->GetClangASTContext().CreateBaseClassSpecifier (base_class_dctype->GetOpaqueClangQualType(), accessibility, is_virtual, is_base_of_class)); + assert(base_classes.back()); + } + } + break; + + default: + break; + } + } + return count; +} + + +clang::DeclContext* +SymbolFileDWARF::GetClangDeclContextForTypeUID (lldb::user_id_t type_uid) +{ + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp); + if (die) + return GetClangDeclContextForDIE (cu_sp.get(), die); + } + return NULL; +} + +Type* +SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) +{ + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, NULL); + if (type_die != NULL) + { + void *type = type_die->GetUserData(); + if (type == NULL) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp); + if (die != NULL) + { + TypeSP owning_type_sp; + TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, 0, 0)); + } + type = type_die->GetUserData(); + } + if (type != DIE_IS_BEING_PARSED) + return (Type *)type; + } + } + return NULL; +} + +CompileUnit* +SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx) +{ + // Check if the symbol vendor already knows about this compile unit? + if (cu->GetUserData() == NULL) + { + // The symbol vendor doesn't know about this compile unit, we + // need to parse and add it to the symbol vendor object. + CompUnitSP dc_cu; + ParseCompileUnit(cu, dc_cu); + if (dc_cu.get()) + { + // Figure out the compile unit index if we weren't given one + if (cu_idx == UINT_MAX) + DebugInfo()->GetCompileUnit(cu->GetOffset(), &cu_idx); + + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(dc_cu, cu_idx); + } + } + return (CompileUnit*)cu->GetUserData(); +} + +bool +SymbolFileDWARF::GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc) +{ + sc.Clear(); + // Check if the symbol vendor already knows about this compile unit? + sc.module_sp = m_obj_file->GetModule()->GetSP(); + sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX); + + sc.function = sc.comp_unit->FindFunctionByUID (func_die->GetOffset()).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, cu, func_die); + + return sc.function != NULL; +} + +uint32_t +SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) +{ + Timer scoped_timer(__PRETTY_FUNCTION__, + "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%llx }, resolve_scope = 0x%8.8x)", + so_addr.GetSection(), + so_addr.GetOffset(), + resolve_scope); + uint32_t resolved = 0; + if (resolve_scope & ( eSymbolContextCompUnit | + eSymbolContextFunction | + eSymbolContextBlock | + eSymbolContextLineEntry)) + { + lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); + + DWARFDebugAranges* debug_aranges = DebugAranges(); + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_aranges) + { + dw_offset_t cu_offset = debug_aranges->FindAddress(file_vm_addr); + if (cu_offset != DW_INVALID_OFFSET) + { + uint32_t cu_idx; + DWARFCompileUnit* cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get(); + if (cu) + { + sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx); + assert(sc.comp_unit != NULL); + resolved |= eSymbolContextCompUnit; + + if (resolve_scope & eSymbolContextLineEntry) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table == NULL) + { + if (ParseCompileUnitLineTable(sc)) + line_table = sc.comp_unit->GetLineTable(); + } + if (line_table != NULL) + { + if (so_addr.IsLinkedAddress()) + { + Address linked_addr (so_addr); + linked_addr.ResolveLinkedAddress(); + if (line_table->FindLineEntryByAddress (linked_addr, sc.line_entry)) + { + resolved |= eSymbolContextLineEntry; + } + } + else if (line_table->FindLineEntryByAddress (so_addr, sc.line_entry)) + { + resolved |= eSymbolContextLineEntry; + } + } + } + + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) + { + DWARFDebugInfoEntry *function_die = NULL; + DWARFDebugInfoEntry *block_die = NULL; + if (resolve_scope & eSymbolContextBlock) + { + cu->LookupAddress(file_vm_addr, &function_die, &block_die); + } + else + { + cu->LookupAddress(file_vm_addr, &function_die, NULL); + } + + if (function_die != NULL) + { + sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, cu, function_die); + } + + if (sc.function != NULL) + { + resolved |= eSymbolContextFunction; + + if (resolve_scope & eSymbolContextBlock) + { + BlockList& blocks = sc.function->GetBlocks(true); + + if (block_die != NULL) + sc.block = blocks.GetBlockByID(block_die->GetOffset()); + else + sc.block = blocks.GetBlockByID(function_die->GetOffset()); + if (sc.block) + resolved |= eSymbolContextBlock; + } + } + } + } + } + } + } + return resolved; +} + + + +uint32_t +SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) +{ + const uint32_t prev_size = sc_list.GetSize(); + if (resolve_scope & eSymbolContextCompUnit) + { + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + uint32_t cu_idx; + DWARFCompileUnit* cu = NULL; + + for (cu_idx = 0; (cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx) + { + CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(cu, cu_idx); + bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Compare(file_spec, *dc_cu, false) == 0; + if (check_inlines || file_spec_matches_cu_file_spec) + { + SymbolContext sc (m_obj_file->GetModule()); + sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, cu_idx); + assert(sc.comp_unit != NULL); + + uint32_t file_idx = UINT32_MAX; + + // If we are looking for inline functions only and we don't + // find it in the support files, we are done. + if (check_inlines) + { + file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec); + if (file_idx == UINT32_MAX) + continue; + } + + if (line != 0) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table != NULL && line != 0) + { + // We will have already looked up the file index if + // we are searching for inline entries. + if (!check_inlines) + file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec); + + if (file_idx != UINT32_MAX) + { + uint32_t found_line; + uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, false, &sc.line_entry); + found_line = sc.line_entry.line; + + while (line_idx != UINT_MAX) + { + sc.function = NULL; + sc.block = NULL; + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) + { + const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress(); + if (file_vm_addr != LLDB_INVALID_ADDRESS) + { + DWARFDebugInfoEntry *function_die = NULL; + DWARFDebugInfoEntry *block_die = NULL; + cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL); + + if (function_die != NULL) + { + sc.function = sc.comp_unit->FindFunctionByUID (function_die->GetOffset()).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, cu, function_die); + } + + if (sc.function != NULL) + { + BlockList& blocks = sc.function->GetBlocks(true); + + if (block_die != NULL) + sc.block = blocks.GetBlockByID(block_die->GetOffset()); + else + sc.block = blocks.GetBlockByID(function_die->GetOffset()); + } + } + } + + sc_list.Append(sc); + line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry); + } + } + } + else if (file_spec_matches_cu_file_spec && !check_inlines) + { + // only append the context if we aren't looking for inline call sites + // by file and line and if the file spec matches that of the compile unit + sc_list.Append(sc); + } + } + else if (file_spec_matches_cu_file_spec && !check_inlines) + { + // only append the context if we aren't looking for inline call sites + // by file and line and if the file spec matches that of the compile unit + sc_list.Append(sc); + } + + if (!check_inlines) + break; + } + } + } + } + return sc_list.GetSize() - prev_size; +} + +void +SymbolFileDWARF::Index () +{ + if (m_indexed) + return; + m_indexed = true; + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARF::Index (%s)", + GetObjectFile()->GetFileSpec().GetFilename().AsCString()); + + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + uint32_t cu_idx = 0; + const uint32_t num_compile_units = GetNumCompileUnits(); + for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); + + bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; + + cu->Index (m_name_to_function_die, + m_name_to_inlined_die, + m_name_to_global_die, + m_name_to_type_die); + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed + if (clear_dies) + cu->ClearDIEs (true); + } + + m_name_to_function_die.Sort(); + m_name_to_inlined_die.Sort(); + m_name_to_global_die.Sort(); + m_name_to_type_die.Sort(); + } +} + +uint32_t +SymbolFileDWARF::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables) +{ + std::vector<dw_offset_t> die_offsets; + + // If we aren't appending the results to this list, then clear the list + if (!append) + variables.Clear(); + + // Remember how many variables are in the list before we search in case + // we are appending the results to a variable list. + const uint32_t original_size = variables.GetSize(); + + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + const UniqueCStringMap<dw_offset_t>::Entry *entry; + + for (entry = m_name_to_global_die.FindFirstValueForName (name.AsCString()); + entry != NULL; + entry = m_name_to_global_die.FindNextValueForName (name.AsCString(), entry)) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp); + DWARFCompileUnit* cu = cu_sp.get(); + if (die) + { + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule()->GetSP(); + assert (sc.module_sp); + + sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX); + assert(sc.comp_unit != NULL); + + ParseVariables(sc, cu_sp.get(), die, false, false, &variables); + + if (variables.GetSize() - original_size >= max_matches) + break; + } + } + + // Return the number of variable that were appended to the list + return variables.GetSize() - original_size; +} + +uint32_t +SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) +{ + std::vector<dw_offset_t> die_offsets; + + // If we aren't appending the results to this list, then clear the list + if (!append) + variables.Clear(); + + // Remember how many variables are in the list before we search in case + // we are appending the results to a variable list. + const uint32_t original_size = variables.GetSize(); + + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + // Create the pubnames information so we can quickly lookup external symbols by name + const size_t num_entries = m_name_to_global_die.GetSize(); + for (size_t i=0; i<num_entries; i++) + { + if (!regex.Execute(m_name_to_global_die.GetCStringAtIndex (i))) + continue; + + const dw_offset_t die_offset = *m_name_to_global_die.GetValueAtIndex (i); + + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp); + DWARFCompileUnit* cu = cu_sp.get(); + if (die) + { + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule()->GetSP(); + assert (sc.module_sp); + + + sc.comp_unit = GetCompUnitForDWARFCompUnit(cu, UINT_MAX); + assert(sc.comp_unit != NULL); + + ParseVariables(sc, cu_sp.get(), die, false, false, &variables); + + if (variables.GetSize() - original_size >= max_matches) + break; + } + } + + // Return the number of variable that were appended to the list + return variables.GetSize() - original_size; +} + + +uint32_t +SymbolFileDWARF::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARF::FindFunctions (name = '%s')", + name.AsCString()); + + std::vector<dw_offset_t> die_offsets; + + // If we aren't appending the results to this list, then clear the list + if (!append) + sc_list.Clear(); + + // Remember how many sc_list are in the list before we search in case + // we are appending the results to a variable list. + uint32_t original_size = sc_list.GetSize(); + + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + const UniqueCStringMap<dw_offset_t>::Entry *entry; + + SymbolContext sc; + for (entry = m_name_to_function_die.FindFirstValueForName (name.AsCString()); + entry != NULL; + entry = m_name_to_function_die.FindNextValueForName (name.AsCString(), entry)) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (entry->value, &cu_sp); + if (die) + { + if (GetFunction (cu_sp.get(), die, sc)) + { + // We found the function, so we should find the line table + // and line table entry as well + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table == NULL) + { + if (ParseCompileUnitLineTable(sc)) + line_table = sc.comp_unit->GetLineTable(); + } + if (line_table != NULL) + line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry); + + sc_list.Append(sc); + } + } + } + + // Return the number of variable that were appended to the list + return sc_list.GetSize() - original_size; +} + + +uint32_t +SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARF::FindFunctions (regex = '%s')", + regex.GetText()); + + std::vector<dw_offset_t> die_offsets; + + // If we aren't appending the results to this list, then clear the list + if (!append) + sc_list.Clear(); + + // Remember how many sc_list are in the list before we search in case + // we are appending the results to a variable list. + uint32_t original_size = sc_list.GetSize(); + + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + // Create the pubnames information so we can quickly lookup external symbols by name + // Create the pubnames information so we can quickly lookup external symbols by name + const size_t num_entries = m_name_to_function_die.GetSize(); + SymbolContext sc; + for (size_t i=0; i<num_entries; i++) + { + if (!regex.Execute(m_name_to_function_die.GetCStringAtIndex (i))) + continue; + + const dw_offset_t die_offset = *m_name_to_function_die.GetValueAtIndex (i); + + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr (die_offset, &cu_sp); + if (die) + { + if (GetFunction (cu_sp.get(), die, sc)) + { + // We found the function, so we should find the line table + // and line table entry as well + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table == NULL) + { + if (ParseCompileUnitLineTable(sc)) + line_table = sc.comp_unit->GetLineTable(); + } + if (line_table != NULL) + line_table->FindLineEntryByAddress (sc.function->GetAddressRange().GetBaseAddress(), sc.line_entry); + + + sc_list.Append(sc); + } + } + } + + // Return the number of variable that were appended to the list + return sc_list.GetSize() - original_size; +} + +#if 0 +uint32_t +SymbolFileDWARF::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) +{ + // If we aren't appending the results to this list, then clear the list + if (!append) + types.Clear(); + + // Create the pubnames information so we can quickly lookup external symbols by name + DWARFDebugPubnames* pubtypes = DebugPubtypes(); + if (pubtypes) + { + std::vector<dw_offset_t> die_offsets; + if (!pubtypes->Find(name.AsCString(), false, die_offsets)) + { + DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes(); + if (pub_base_types && !pub_base_types->Find(name.AsCString(), false, die_offsets)) + return 0; + } + return FindTypes(die_offsets, max_matches, encoding, udt_uid, types); + } + return 0; +} + + +uint32_t +SymbolFileDWARF::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) +{ + // If we aren't appending the results to this list, then clear the list + if (!append) + types.Clear(); + + // Create the pubnames information so we can quickly lookup external symbols by name + DWARFDebugPubnames* pubtypes = DebugPubtypes(); + if (pubtypes) + { + std::vector<dw_offset_t> die_offsets; + if (!pubtypes->Find(regex, die_offsets)) + { + DWARFDebugPubnames* pub_base_types = DebugPubBaseTypes(); + if (pub_base_types && !pub_base_types->Find(regex, die_offsets)) + return 0; + } + + return FindTypes(die_offsets, max_matches, encoding, udt_uid, types); + } + + return 0; +} + + + +uint32_t +SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) +{ + // Remember how many sc_list are in the list before we search in case + // we are appending the results to a variable list. + uint32_t original_size = types.Size(); + + const uint32_t num_die_offsets = die_offsets.size(); + // Parse all of the types we found from the pubtypes matches + uint32_t i; + uint32_t num_matches = 0; + for (i = 0; i < num_die_offsets; ++i) + { + dw_offset_t die_offset = die_offsets[i]; + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp); + + assert(die != NULL); + + bool get_type_for_die = true; + if (encoding) + { + // Check if this type has already been uniqued and registers with the module? + Type* type = (Type*)die->GetUserData(); + if (type != NULL && type != DIE_IS_BEING_PARSED) + { + get_type_for_die = type->GetEncoding() == encoding; + } + else + { + dw_tag_t tag = die->Tag(); + switch (encoding) + { + case Type::address: + case Type::boolean: + case Type::complex_float: + case Type::float_type: + case Type::signed_int: + case Type::signed_char: + case Type::unsigned_int: + case Type::unsigned_char: + case Type::imaginary_float: + case Type::packed_decimal: + case Type::numeric_string: + case Type::edited_string: + case Type::signed_fixed: + case Type::unsigned_fixed: + case Type::decimal_float: + if (tag != DW_TAG_base_type) + get_type_for_die = false; + else + { + if (die->GetAttributeValueAsUnsigned(this, cu_sp.get(), DW_AT_encoding, Type::invalid) != encoding) + get_type_for_die = false; + } + break; + + case Type::indirect_const: get_type_for_die = tag == DW_TAG_const_type; break; + case Type::indirect_restrict: get_type_for_die = tag == DW_TAG_restrict_type; break; + case Type::indirect_volatile: get_type_for_die = tag == DW_TAG_volatile_type; break; + case Type::indirect_typedef: get_type_for_die = tag == DW_TAG_typedef; break; + case Type::indirect_pointer: get_type_for_die = tag == DW_TAG_pointer_type; break; + case Type::indirect_reference: get_type_for_die = tag == DW_TAG_reference_type; break; + + case Type::user_defined_type: + switch (tag) + { + case DW_TAG_array_type: + get_type_for_die = UserDefTypeArray::OwnsUserDefTypeUID(udt_uid); + break; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + get_type_for_die = UserDefTypeStruct::OwnsUserDefTypeUID(udt_uid); + break; + + case DW_TAG_enumeration_type: + get_type_for_die = UserDefTypeEnum::OwnsUserDefTypeUID(udt_uid); + break; + + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + get_type_for_die = UserDefTypeFunction::OwnsUserDefTypeUID(udt_uid); + break; + } + } + } + } + + if (get_type_for_die) + { + TypeSP owning_type_sp; + TypeSP type_sp(GetTypeForDIE(cu_sp.get(), die, owning_type_sp, NULL, 0, 0)); + + if (type_sp.get()) + { + // See if we are filtering results based on encoding? + bool add_type = (encoding == Type::invalid); + if (!add_type) + { + // We are filtering base on encoding, so lets check the resulting type encoding + add_type = (encoding == type_sp->GetEncoding()); + if (add_type) + { + // The type encoding matches, if this is a user defined type, lets + // make sure the exact user define type uid matches if one was provided + if (encoding == Type::user_defined_type && udt_uid != LLDB_INVALID_UID) + { + UserDefType* udt = type_sp->GetUserDefinedType().get(); + if (udt) + add_type = udt->UserDefinedTypeUID() == udt_uid; + } + } + } + // Add the type to our list as long as everything matched + if (add_type) + { + types.InsertUnique(type_sp); + if (++num_matches >= max_matches) + break; + } + } + } + } + + // Return the number of variable that were appended to the list + return types.Size() - original_size; +} + +#endif + + +size_t +SymbolFileDWARF::ParseChildParameters +( + const SymbolContext& sc, + TypeSP& type_sp, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + TypeList* type_list, + std::vector<void *>& function_param_types, + std::vector<clang::ParmVarDecl*>& function_param_decls +) +{ + if (parent_die == NULL) + return 0; + + size_t count = 0; + const DWARFDebugInfoEntry *die; + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + dw_tag_t tag = die->Tag(); + switch (tag) + { + case DW_TAG_formal_parameter: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + const char *name = NULL; + Declaration decl; + dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; + // one of None, Auto, Register, Extern, Static, PrivateExtern + + clang::VarDecl::StorageClass storage = clang::VarDecl::None; + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_type: param_type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_location: + // if (form_value.BlockData()) + // { + // const DataExtractor& debug_info_data = debug_info(); + // uint32_t block_length = form_value.Unsigned(); + // DataExtractor location(debug_info_data, form_value.BlockData() - debug_info_data.GetDataStart(), block_length); + // } + // else + // { + // } + // break; + case DW_AT_artificial: + case DW_AT_const_value: + case DW_AT_default_value: + case DW_AT_description: + case DW_AT_endianity: + case DW_AT_is_optional: + case DW_AT_segment: + case DW_AT_variable_parameter: + default: + case DW_AT_abstract_origin: + case DW_AT_sibling: + break; + } + } + } + Type *dc_type = ResolveTypeUID(param_type_die_offset); + if (dc_type) + { + function_param_types.push_back (dc_type->GetOpaqueClangQualType()); + + clang::ParmVarDecl *param_var_decl = type_list->GetClangASTContext().CreateParmeterDeclaration (name, dc_type->GetOpaqueClangQualType(), storage); + assert(param_var_decl); + function_param_decls.push_back(param_var_decl); + } + } + } + break; + + default: + break; + } + } + return count; +} + +size_t +SymbolFileDWARF::ParseChildEnumerators +( + const SymbolContext& sc, + TypeSP& type_sp, + void * enumerator_qual_type, + uint32_t enumerator_byte_size, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die +) +{ + if (parent_die == NULL) + return 0; + + size_t enumerators_added = 0; + const DWARFDebugInfoEntry *die; + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + const dw_tag_t tag = die->Tag(); + if (tag == DW_TAG_enumerator) + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_child_attributes > 0) + { + const char *name = NULL; + bool got_value = false; + int64_t enum_value = 0; + Declaration decl; + + uint32_t i; + for (i=0; i<num_child_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_const_value: + got_value = true; + enum_value = form_value.Unsigned(); + break; + + case DW_AT_name: + name = form_value.AsCString(&get_debug_str_data()); + break; + + case DW_AT_description: + default: + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_sibling: + break; + } + } + } + + if (name && name[0] && got_value) + { + TypeList* type_list = m_obj_file->GetModule()->GetTypeList(); + type_list->GetClangASTContext().AddEnumerationValueToEnumerationType (type_sp->GetOpaqueClangQualType(), enumerator_qual_type, decl, name, enum_value, enumerator_byte_size * 8); + ++enumerators_added; + } + } + } + } + return enumerators_added; +} + +void +SymbolFileDWARF::ParseChildArrayInfo +( + const SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + int64_t& first_index, + std::vector<uint64_t>& element_orders, + uint32_t& byte_stride, + uint32_t& bit_stride +) +{ + if (parent_die == NULL) + return; + + const DWARFDebugInfoEntry *die; + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + const dw_tag_t tag = die->Tag(); + switch (tag) + { + case DW_TAG_enumerator: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_child_attributes > 0) + { + const char *name = NULL; + bool got_value = false; + int64_t enum_value = 0; + + uint32_t i; + for (i=0; i<num_child_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_const_value: + got_value = true; + enum_value = form_value.Unsigned(); + break; + + case DW_AT_name: + name = form_value.AsCString(&get_debug_str_data()); + break; + + case DW_AT_description: + default: + case DW_AT_decl_file: + case DW_AT_decl_line: + case DW_AT_decl_column: + case DW_AT_sibling: + break; + } + } + } + } + } + break; + + case DW_TAG_subrange_type: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_child_attributes > 0) + { + const char *name = NULL; + bool got_value = false; + uint64_t byte_size = 0; + int64_t enum_value = 0; + uint64_t num_elements = 0; + uint64_t lower_bound = 0; + uint64_t upper_bound = 0; + uint32_t i; + for (i=0; i<num_child_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_const_value: + got_value = true; + enum_value = form_value.Unsigned(); + break; + + case DW_AT_name: + name = form_value.AsCString(&get_debug_str_data()); + break; + + case DW_AT_count: + num_elements = form_value.Unsigned(); + break; + + case DW_AT_bit_stride: + bit_stride = form_value.Unsigned(); + break; + + case DW_AT_byte_stride: + byte_stride = form_value.Unsigned(); + break; + + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + + case DW_AT_lower_bound: + lower_bound = form_value.Unsigned(); + break; + + case DW_AT_upper_bound: + upper_bound = form_value.Unsigned(); + break; + + default: + //printf("0x%8.8x: %-30s skipping attribute at 0x%8.8x: %s\n", die->GetOffset(), DW_TAG_value_to_name(tag), attributes.die_offsets[i], DW_AT_value_to_name(attr)); // remove this, debug only + + case DW_AT_abstract_origin: + case DW_AT_accessibility: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_sibling: + case DW_AT_threads_scaled: + case DW_AT_type: + case DW_AT_visibility: + break; + } + } + } + + if (upper_bound > lower_bound) + num_elements = upper_bound - lower_bound + 1; + + if (num_elements > 0) + element_orders.push_back (num_elements); + } + } + break; + } + } +} + +Type* +SymbolFileDWARF::GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe) +{ + if (type_die_offset != DW_INVALID_OFFSET) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* type_die = DebugInfo()->GetDIEPtr(type_die_offset, &cu_sp); + assert(type_die != NULL); + GetTypeForDIE(cu_sp.get(), type_die, owning_type_sp, child_type, idx); + // Return the uniqued type if there is one + Type* type = (Type*)type_die->GetUserData(); + if (type == DIE_IS_BEING_PARSED && safe) + return NULL; + return type; + } + return NULL; +} + +TypeSP +SymbolFileDWARF::GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, TypeSP& owning_type_sp, int32_t child_type, uint32_t idx) +{ + TypeSP type_sp; + if (die != NULL) + { + assert(cu != NULL); + Type *type_ptr = (Type *)die->GetUserData(); + if (type_ptr == NULL) + { + SymbolContext sc(GetCompUnitForDWARFCompUnit(cu)); + bool type_is_new = false; + type_sp = ParseType(sc, cu, die, type_is_new); + type_ptr = (Type *)die->GetUserData(); + if (owning_type_sp.get() == NULL) + owning_type_sp = type_sp; + } + else if (type_ptr != DIE_IS_BEING_PARSED) + { + // Grab the existing type from the master types lists + type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(type_ptr->GetID()); + } + + } + return type_sp; +} + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextForDIEOffset (dw_offset_t die_offset) +{ + if (die_offset != DW_INVALID_OFFSET) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp); + return GetClangDeclContextForDIE (cu_sp.get(), die); + } + return NULL; +} + + + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) +{ + DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die); + if (pos != m_die_to_decl_ctx.end()) + return pos->second; + + while (die != NULL) + { + switch (die->Tag()) + { + case DW_TAG_namespace: + { + const char *namespace_name = die->GetAttributeValueAsString(this, cu, DW_AT_name, NULL); + if (namespace_name) + { + TypeList* type_list = m_obj_file->GetModule()->GetTypeList(); + assert(type_list); + Declaration decl; // TODO: fill in the decl object + clang::NamespaceDecl *namespace_decl = type_list->GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (cu, die->GetParent())); + if (namespace_decl) + m_die_to_decl_ctx[die] = (clang::DeclContext*)namespace_decl; + return namespace_decl; + } + } + break; + + default: + break; + } + clang::DeclContext *decl_ctx; + decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_specification, DW_INVALID_OFFSET)); + if (decl_ctx) + return decl_ctx; + + decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET)); + if (decl_ctx) + return decl_ctx; + + die = die->GetParent(); + } + return NULL; +} + +TypeSP +SymbolFileDWARF::ParseType(const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new) +{ + TypeSP type_sp; + + uint32_t accessibility = clang::AS_none; + if (die != NULL) + { + dw_tag_t tag = die->Tag(); + if (die->GetUserData() == NULL) + { + type_is_new = true; + + bool is_forward_declaration = false; + DWARFDebugInfoEntry::Attributes attributes; + const char *type_name_cstr = NULL; + ConstString type_name_dbstr; + Type::EncodingUIDType encoding_uid_type = Type::eIsTypeWithUID; + void *clang_type = NULL; + + TypeList* type_list = m_obj_file->GetModule()->GetTypeList(); + dw_attr_t attr; + + switch (tag) + { + case DW_TAG_base_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_typedef: + case DW_TAG_const_type: + case DW_TAG_restrict_type: + case DW_TAG_volatile_type: + { + //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag)); + // Set a bit that lets us know that we are currently parsing this + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED); + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + Declaration decl; + uint32_t encoding = 0; + size_t byte_size = 0; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + + if (num_attributes > 0) + { + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(&get_debug_str_data()); + type_name_dbstr.SetCString(type_name_cstr); + break; + case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_encoding: encoding = form_value.Unsigned(); break; + case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + default: + case DW_AT_sibling: + break; + } + } + } + } + + switch (tag) + { + default: + case DW_TAG_base_type: + clang_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr, encoding, byte_size * 8); + break; + + case DW_TAG_pointer_type: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::ePointerToTypeWithUID; + break; + + case DW_TAG_reference_type: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::eLValueReferenceToTypeWithUID; + break; + + case DW_TAG_typedef: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::eTypedefToTypeWithUID; + break; + + case DW_TAG_const_type: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::eIsConstTypeWithUID; //ClangASTContext::AddConstModifier (clang_type); + break; + + case DW_TAG_restrict_type: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::eIsRestrictTypeWithUID; //ClangASTContext::AddRestrictModifier (clang_type); + break; + + case DW_TAG_volatile_type: + // The encoding_uid will be embedded into the + // Type object and will be looked up when the Type::GetOpaqueClangQualType() + encoding_uid_type = Type::eIsVolatileTypeWithUID; //ClangASTContext::AddVolatileModifier (clang_type); + break; + } + + type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, encoding_uid_type, &decl, clang_type)); + + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get()); + + +// Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false); +// if (encoding_type != NULL) +// { +// if (encoding_type != DIE_IS_BEING_PARSED) +// type_sp->SetEncodingType(encoding_type); +// else +// m_indirect_fixups.push_back(type_sp.get()); +// } + } + break; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + { + //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag)); + // Set a bit that lets us know that we are currently parsing this + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED); + + size_t byte_size = 0; + //bool struct_is_class = false; + Declaration decl; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(&get_debug_str_data()); + type_name_dbstr.SetCString(type_name_cstr); + break; + case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; break; + case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break; + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_description: + case DW_AT_start_scope: + case DW_AT_visibility: + default: + case DW_AT_sibling: + break; + } + } + } + } + + int tag_decl_kind = -1; + int default_accessibility = clang::AS_none; + if (tag == DW_TAG_structure_type) + { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = clang::AS_public; + } + else if (tag == DW_TAG_union_type) + { + tag_decl_kind = clang::TTK_Union; + default_accessibility = clang::AS_public; + } + else if (tag == DW_TAG_class_type) + { + tag_decl_kind = clang::TTK_Class; + default_accessibility = clang::AS_private; + } + + assert (tag_decl_kind != -1); + clang_type = type_list->GetClangASTContext().CreateRecordType (type_name_cstr, tag_decl_kind, GetClangDeclContextForDIE (dwarf_cu, die)); + + m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type); + type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type)); + + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get()); + +// assert(type_sp.get()); +// if (accessibility) +// type_sp->SetAccess(accessibility); +// + type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type); + if (die->HasChildren()) + { + std::vector<clang::CXXBaseSpecifier *> base_classes; + std::vector<int> member_accessibilities; + bool is_a_class = false; + ParseChildMembers(sc, type_sp, dwarf_cu, die, base_classes, member_accessibilities, default_accessibility, is_a_class); + // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we + // need to tell the clang type it is actually a class. + if (is_a_class && tag_decl_kind != clang::TTK_Class) + type_list->GetClangASTContext().SetTagTypeKind (clang_type, clang::TTK_Class); + + // Since DW_TAG_structure_type gets used for both classes + // and structures, we may need to set any DW_TAG_member + // fields to have a "private" access if none was specified. + // When we parsed the child members we tracked that actual + // accessibility value for each DW_TAG_member in the + // "member_accessibilities" array. If the value for the + // member is zero, then it was set to the "default_accessibility" + // which for structs was "public". Below we correct this + // by setting any fields to "private" that weren't correctly + // set. + if (is_a_class && !member_accessibilities.empty()) + { + // This is a class and all members that didn't have + // their access specified are private. + type_list->GetClangASTContext().SetDefaultAccessForRecordFields (clang_type, clang::AS_private, member_accessibilities.data(), member_accessibilities.size()); + } + + if (!base_classes.empty()) + { + type_list->GetClangASTContext().SetBaseClassesForClassType (clang_type, base_classes.data(), base_classes.size()); + } + } + type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type); + } + break; + + case DW_TAG_enumeration_type: + { + //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag)); + // Set a bit that lets us know that we are currently parsing this + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED); + + size_t byte_size = 0; + lldb::user_id_t encoding_uid = DW_INVALID_OFFSET; + Declaration decl; + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + uint32_t i; + + for (i=0; i<num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(&get_debug_str_data()); + type_name_dbstr.SetCString(type_name_cstr); + break; + case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; + case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break; + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_bit_stride: + case DW_AT_byte_stride: + case DW_AT_data_location: + case DW_AT_description: + case DW_AT_start_scope: + case DW_AT_visibility: + case DW_AT_specification: + case DW_AT_abstract_origin: + case DW_AT_sibling: + break; + } + } + } + + clang_type = type_list->GetClangASTContext().CreateEnumerationType(decl, type_name_cstr); + m_die_to_decl_ctx[die] = ClangASTContext::GetDeclContextForType (clang_type); + type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, byte_size, NULL, encoding_uid, Type::eIsTypeWithUID, &decl, clang_type)); + + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get()); + + if (die->HasChildren()) + { + type_list->GetClangASTContext().StartTagDeclarationDefinition (clang_type); + void *enumerator_qual_type = type_list->GetClangASTContext().GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, DW_ATE_signed, byte_size * 8); + ParseChildEnumerators(sc, type_sp, enumerator_qual_type, byte_size, dwarf_cu, die); + type_list->GetClangASTContext().CompleteTagDeclarationDefinition (clang_type); + } + } + } + break; + + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + { + //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag)); + // Set a bit that lets us know that we are currently parsing this + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED); + + const char *mangled = NULL; + dw_offset_t type_die_offset = DW_INVALID_OFFSET; + Declaration decl; + bool isVariadic = false; + bool is_inline = false; + unsigned type_quals = 0; + clang::FunctionDecl::StorageClass storage = clang::FunctionDecl::None;//, Extern, Static, PrivateExtern + + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(&get_debug_str_data()); + type_name_dbstr.SetCString(type_name_cstr); + break; + + case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; + case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break; + case DW_AT_external: + if (form_value.Unsigned()) + { + if (storage == clang::FunctionDecl::None) + storage = clang::FunctionDecl::Extern; + else + storage = clang::FunctionDecl::PrivateExtern; + } + break; + case DW_AT_inline: + is_inline = form_value.Unsigned() != 0; + break; + + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_address_class: + case DW_AT_artificial: + case DW_AT_calling_convention: + case DW_AT_data_location: + case DW_AT_elemental: + case DW_AT_entry_pc: + case DW_AT_explicit: + case DW_AT_frame_base: + case DW_AT_high_pc: + case DW_AT_low_pc: + case DW_AT_object_pointer: + case DW_AT_prototyped: + case DW_AT_pure: + case DW_AT_ranges: + case DW_AT_recursive: + case DW_AT_return_addr: + case DW_AT_segment: + case DW_AT_specification: + case DW_AT_start_scope: + case DW_AT_static_link: + case DW_AT_trampoline: + case DW_AT_visibility: + case DW_AT_virtuality: + case DW_AT_vtable_elem_location: + case DW_AT_abstract_origin: + case DW_AT_description: + case DW_AT_sibling: + break; + } + } + } + + void *return_clang_type = NULL; + Type *func_type = ResolveTypeUID(type_die_offset); + if (func_type) + return_clang_type = func_type->GetOpaqueClangQualType(); + else + return_clang_type = type_list->GetClangASTContext().GetVoidBuiltInType(); + + std::vector<void *> function_param_types; + std::vector<clang::ParmVarDecl*> function_param_decls; + + // Parse the function children for the parameters + ParseChildParameters(sc, type_sp, dwarf_cu, die, type_list, function_param_types, function_param_decls); + + clang_type = type_list->GetClangASTContext().CreateFunctionType (return_clang_type, &function_param_types[0], function_param_types.size(), isVariadic, type_quals); + if (type_name_cstr) + { + clang::FunctionDecl *function_decl = type_list->GetClangASTContext().CreateFunctionDeclaration (type_name_cstr, clang_type, storage, is_inline); + // Add the decl to our DIE to decl context map + assert (function_decl); + m_die_to_decl_ctx[die] = function_decl; + if (!function_param_decls.empty()) + type_list->GetClangASTContext().SetFunctionParameters (function_decl, function_param_decls.data(), function_param_decls.size()); + } + type_sp.reset( new Type(die->GetOffset(), this, type_name_dbstr, 0, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type)); + + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get()); + assert(type_sp.get()); + } + } + break; + + case DW_TAG_array_type: + { + //printf("0x%8.8x: %s (ParesTypes)\n", die->GetOffset(), DW_TAG_value_to_name(tag)); + // Set a bit that lets us know that we are currently parsing this + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(DIE_IS_BEING_PARSED); + + size_t byte_size = 0; + lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; + Declaration decl; + int64_t first_index = 0; + uint32_t byte_stride = 0; + uint32_t bit_stride = 0; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + + if (num_attributes > 0) + { + uint32_t i; + for (i=0; i<num_attributes; ++i) + { + attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(&get_debug_str_data()); + type_name_dbstr.SetCString(type_name_cstr); + break; + + case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; + case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break; + case DW_AT_bit_stride: bit_stride = form_value.Unsigned(); break; + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; + case DW_AT_declaration: is_forward_declaration = form_value.Unsigned() != 0; break; + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_description: + case DW_AT_ordering: + case DW_AT_start_scope: + case DW_AT_visibility: + case DW_AT_specification: + case DW_AT_abstract_origin: + case DW_AT_sibling: + break; + } + } + } + + Type *element_type = ResolveTypeUID(type_die_offset); + + if (element_type) + { + std::vector<uint64_t> element_orders; + ParseChildArrayInfo(sc, dwarf_cu, die, first_index, element_orders, byte_stride, bit_stride); + if (byte_stride == 0 && bit_stride == 0) + byte_stride = element_type->GetByteSize(); + void *array_element_type = element_type->GetOpaqueClangQualType(); + uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; + uint64_t num_elements = 0; + std::vector<uint64_t>::const_reverse_iterator pos; + std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend(); + for (pos = element_orders.rbegin(); pos != end; ++pos) + { + num_elements = *pos; + clang_type = type_list->GetClangASTContext().CreateArrayType (array_element_type, num_elements, num_elements * array_element_bit_stride); + array_element_type = clang_type; + array_element_bit_stride = array_element_bit_stride * num_elements; + } + ConstString empty_name; + type_sp.reset( new Type(die->GetOffset(), this, empty_name, array_element_bit_stride / 8, NULL, LLDB_INVALID_UID, Type::eIsTypeWithUID, &decl, clang_type)); + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(type_sp.get()); + } + } + } + break; + + default: + break; + } + + if (type_sp.get()) + { + const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); + dw_tag_t sc_parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + + SymbolContextScope * symbol_context_scope = NULL; + if (sc_parent_tag == DW_TAG_compile_unit) + { + symbol_context_scope = sc.comp_unit; + } + else if (sc.function != NULL) + { + symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset()); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } + + if (symbol_context_scope != NULL) + { + type_sp->SetSymbolContextScope(symbol_context_scope); + } + +// if (udt_sp.get()) +// { +// if (is_forward_declaration) +// udt_sp->GetFlags().Set(UserDefType::flagIsForwardDefinition); +// type_sp->SetUserDefinedType(udt_sp); +// } + + if (type_sp.unique()) + { + // We are ready to put this type into the uniqued list up at the module level + TypeSP uniqued_type_sp(m_obj_file->GetModule()->GetTypeList()->InsertUnique(type_sp)); + + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(uniqued_type_sp.get()); + + type_sp = uniqued_type_sp; + } + } + } + else + { + switch (tag) + { + case DW_TAG_base_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_typedef: + case DW_TAG_const_type: + case DW_TAG_restrict_type: + case DW_TAG_volatile_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + case DW_TAG_array_type: + { + Type *existing_type = (Type*)die->GetUserData(); + if (existing_type != DIE_IS_BEING_PARSED) + { + type_sp = m_obj_file->GetModule()->GetTypeList()->FindType(existing_type->GetID()); + } + } + break; + default: + //assert(!"invalid type tag..."); + break; + } + } + } + return type_sp; +} + +size_t +SymbolFileDWARF::ParseTypes (const SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children) +{ + size_t types_added = 0; + while (die != NULL) + { + bool type_is_new = false; + if (ParseType(sc, dwarf_cu, die, type_is_new).get()) + { + if (type_is_new) + ++types_added; + } + + if (parse_children && die->HasChildren()) + { + if (die->Tag() == DW_TAG_subprogram) + { + SymbolContext child_sc(sc); + child_sc.function = sc.comp_unit->FindFunctionByUID(die->GetOffset()).get(); + types_added += ParseTypes(child_sc, dwarf_cu, die->GetFirstChild(), true, true); + } + else + types_added += ParseTypes(sc, dwarf_cu, die->GetFirstChild(), true, true); + } + + if (parse_siblings) + die = die->GetSibling(); + else + die = NULL; + } + return types_added; +} + + +size_t +SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc) +{ + assert(sc.comp_unit && sc.function); + size_t functions_added = 0; + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + if (dwarf_cu) + { + dw_offset_t function_die_offset = sc.function->GetID(); + const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset); + if (function_die) + { + ParseFunctionBlocks(sc, Block::RootID, dwarf_cu, function_die, LLDB_INVALID_ADDRESS, false, true); + } + } + + return functions_added; +} + + +size_t +SymbolFileDWARF::ParseTypes (const SymbolContext &sc) +{ + // At least a compile unit must be valid + assert(sc.comp_unit); + size_t types_added = 0; + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + if (dwarf_cu) + { + if (sc.function) + { + dw_offset_t function_die_offset = sc.function->GetID(); + const DWARFDebugInfoEntry *func_die = dwarf_cu->GetDIEPtr(function_die_offset); + if (func_die && func_die->HasChildren()) + { + types_added = ParseTypes(sc, dwarf_cu, func_die->GetFirstChild(), true, true); + } + } + else + { + const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->DIE(); + if (dwarf_cu_die && dwarf_cu_die->HasChildren()) + { + types_added = ParseTypes(sc, dwarf_cu, dwarf_cu_die->GetFirstChild(), true, true); + } + } + } + + return types_added; +} + +size_t +SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc) +{ + if (sc.comp_unit != NULL) + { + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnitForUID(sc.comp_unit->GetID()); + + if (dwarf_cu == NULL) + return 0; + + if (sc.function) + { + const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID()); + return ParseVariables(sc, dwarf_cu, function_die->GetFirstChild(), true, true); + } + else if (sc.comp_unit) + { + uint32_t vars_added = 0; + VariableListSP variables (sc.comp_unit->GetVariableList(false)); + + if (variables.get() == NULL) + { + variables.reset(new VariableList()); + sc.comp_unit->SetVariableList(variables); + + // Index if we already haven't to make sure the compile units + // get indexed and make their global DIE index list + if (!m_indexed) + Index (); + + const size_t num_globals = dwarf_cu->GetNumGlobals(); + for (size_t idx=0; idx<num_globals; ++idx) + { + VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, dwarf_cu->GetGlobalDIEAtIndex (idx))); + if (var_sp) + { + variables->AddVariable(var_sp); + ++vars_added; + } + } + } + return vars_added; + } + } + return 0; +} + + +VariableSP +SymbolFileDWARF::ParseVariableDIE +( + const SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die +) +{ + + VariableSP var_sp; + + const dw_tag_t tag = die->Tag(); + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, attributes); + if (num_attributes > 0) + { + const char *name = NULL; + Declaration decl; + uint32_t i; + TypeSP type_sp; + Type *var_type = NULL; + DWARFExpression location; + bool is_external = false; + bool is_artificial = false; + uint32_t accessibility = clang::AS_none; + + for (i=0; i<num_attributes; ++i) + { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + switch (attr) + { + case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break; + case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break; + case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; + case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_type: var_type = GetUniquedTypeForDIEOffset(form_value.Reference(dwarf_cu), type_sp, 0, 0, false); break; + case DW_AT_external: is_external = form_value.Unsigned() != 0; break; + case DW_AT_location: + { + if (form_value.BlockData()) + { + const DataExtractor& debug_info_data = get_debug_info_data(); + + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + location.SetOpcodeData(get_debug_info_data(), block_offset, block_length, NULL); + } + else + { + const DataExtractor& debug_loc_data = 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(dwarf_cu->GetBaseAddress(), m_obj_file->GetSectionList()); + location.SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length, &base_address); + } + } + } + break; + + case DW_AT_artificial: is_artificial = form_value.Unsigned() != 0; break; + case DW_AT_accessibility: accessibility = DwarfToClangAccessibility(form_value.Unsigned()); break; + case DW_AT_const_value: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_endianity: + case DW_AT_segment: + case DW_AT_start_scope: + case DW_AT_visibility: + default: + case DW_AT_abstract_origin: + case DW_AT_sibling: + case DW_AT_specification: + break; + } + } + } + + if (location.IsValid()) + { + assert(var_type != DIE_IS_BEING_PARSED); + + ConstString var_name(name); + + ValueType scope = eValueTypeInvalid; + + const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); + dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + + if (tag == DW_TAG_formal_parameter) + scope = eValueTypeVariableArgument; + else if (is_external || parent_tag == DW_TAG_compile_unit) + scope = eValueTypeVariableGlobal; + else + scope = eValueTypeVariableLocal; + + SymbolContextScope * symbol_context_scope = NULL; + if (parent_tag == DW_TAG_compile_unit) + { + symbol_context_scope = sc.comp_unit; + } + else if (sc.function != NULL) + { + symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset()); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } + + assert(symbol_context_scope != NULL); + var_sp.reset (new Variable(die->GetOffset(), + var_name, + var_type, + scope, + symbol_context_scope, + &decl, + location, + is_external, + is_artificial)); + const_cast<DWARFDebugInfoEntry*>(die)->SetUserData(var_sp.get()); + } + } + return var_sp; +} + +size_t +SymbolFileDWARF::ParseVariables +( + const SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *orig_die, + bool parse_siblings, + bool parse_children, + VariableList* cc_variable_list +) +{ + if (orig_die == NULL) + return 0; + + size_t vars_added = 0; + const DWARFDebugInfoEntry *die = orig_die; + const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die); + dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + VariableListSP variables; + switch (parent_tag) + { + case DW_TAG_compile_unit: + if (sc.comp_unit != NULL) + { + variables = sc.comp_unit->GetVariableList(false); + if (variables.get() == NULL) + { + variables.reset(new VariableList()); + sc.comp_unit->SetVariableList(variables); + } + } + else + { + assert(!"Parent DIE was a compile unit, yet we don't have a valid compile unit in the symbol context..."); + vars_added = 0; + } + break; + + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + if (sc.function != NULL) + { + // Check to see if we already have parsed the variables for the given scope + variables = sc.function->GetBlocks(true).GetVariableList(sc_parent_die->GetOffset(), false, false); + if (variables.get() == NULL) + { + variables.reset(new VariableList()); + sc.function->GetBlocks(true).SetVariableList(sc_parent_die->GetOffset(), variables); + } + } + else + { + assert(!"Parent DIE was a function or block, yet we don't have a function in the symbol context..."); + vars_added = 0; + } + break; + + default: + assert(!"Didn't find appropriate parent DIE for variable list..."); + break; + } + + // We need to have a variable list at this point that we can add variables to + assert(variables.get()); + + while (die != NULL) + { + dw_tag_t tag = die->Tag(); + + // Check to see if we have already parsed this variable or constant? + if (die->GetUserData() == NULL) + { + // We haven't already parsed it, lets do that now. + if ((tag == DW_TAG_variable) || + (tag == DW_TAG_constant) || + (tag == DW_TAG_formal_parameter && sc.function)) + { + VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die)); + if (var_sp) + { + variables->AddVariable(var_sp); + ++vars_added; + } + } + } + + bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram); + + if (!skip_children && parse_children && die->HasChildren()) + { + vars_added += ParseVariables(sc, dwarf_cu, die->GetFirstChild(), true, true); + //vars_added += ParseVariables(sc, dwarf_cu, die->GetFirstChild(), parse_siblings, parse_children); + } + + if (parse_siblings) + die = die->GetSibling(); + else + die = NULL; + } + + if (cc_variable_list) + { + cc_variable_list->AddVariables(variables.get()); + } + + return vars_added; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +const char * +SymbolFileDWARF::GetPluginName() +{ + return "SymbolFileDWARF"; +} + +const char * +SymbolFileDWARF::GetShortPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +SymbolFileDWARF::GetPluginVersion() +{ + return 1; +} + +void +SymbolFileDWARF::GetPluginCommandHelp (const char *command, Stream *strm) +{ +} + +Error +SymbolFileDWARF::ExecutePluginCommand (Args &command, Stream *strm) +{ + Error error; + error.SetErrorString("No plug-in command are currently supported."); + return error; +} + +Log * +SymbolFileDWARF::EnablePluginLogging (Stream *strm, Args &command) +{ + return NULL; +} + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h new file mode 100644 index 00000000000..95545a4844e --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -0,0 +1,331 @@ +//===-- SymbolFileDWARF.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_SymbolFileDWARF_h_ +#define liblldb_SymbolFileDWARF_h_ + +// C Includes +// C++ Includes +#include <list> +#include <memory> +#include <map> +#include <vector> + +// Other libraries and framework includes +#include "llvm/ADT/DenseMap.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Flags.h" +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolContext.h" + +// Project includes +#include "DWARFDefines.h" + + +//---------------------------------------------------------------------- +// Forward Declarations for this DWARF plugin +//---------------------------------------------------------------------- +class DWARFAbbreviationDeclaration; +class DWARFAbbreviationDeclarationSet; +class DWARFCompileUnit; +class DWARFDebugAbbrev; +class DWARFDebugAranges; +class DWARFDebugInfo; +class DWARFDebugInfoEntry; +class DWARFDebugLine; +class DWARFDebugPubnames; +class DWARFDebugRanges; +class DWARFDIECollection; +class DWARFFormValue; + +class SymbolFileDWARF : public lldb_private::SymbolFile +{ +public: + friend class SymbolFileDWARFDebugMap; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static const char * + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::SymbolFile* + CreateInstance (lldb_private::ObjectFile* obj_file); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileDWARF(lldb_private::ObjectFile* ofile); + virtual ~SymbolFileDWARF(); + + virtual uint32_t GetAbilities (); + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + virtual uint32_t GetNumCompileUnits(); + virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index); + + virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc); + virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc); + virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files); + virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc); + virtual size_t ParseTypes (const lldb_private::SymbolContext& sc); + virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc); + + virtual lldb_private::Type* ResolveTypeUID(lldb::user_id_t type_uid); + virtual clang::DeclContext* GetClangDeclContextForTypeUID (lldb::user_id_t type_uid); + + virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc); + virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindGlobalVariables(const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::VariableList& variables); + virtual uint32_t FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables); + virtual uint32_t FindFunctions(const lldb_private::ConstString &name, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list); +// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types); +// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types); + + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual const char * + GetPluginName(); + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp (const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command); + + // Approach 2 - count + accessor + // Index compile units would scan the initial compile units and register + // them with the module. This would only be done on demand if and only if + // the compile units were needed. + //virtual size_t GetCompUnitCount() = 0; + //virtual CompUnitSP GetCompUnitAtIndex(size_t cu_idx) = 0; + + const lldb_private::DataExtractor& get_debug_abbrev_data(); + const lldb_private::DataExtractor& get_debug_aranges_data(); + const lldb_private::DataExtractor& get_debug_frame_data(); + const lldb_private::DataExtractor& get_debug_info_data(); + const lldb_private::DataExtractor& get_debug_line_data(); + const lldb_private::DataExtractor& get_debug_loc_data(); + const lldb_private::DataExtractor& get_debug_macinfo_data(); + const lldb_private::DataExtractor& get_debug_pubnames_data(); + const lldb_private::DataExtractor& get_debug_pubtypes_data(); + const lldb_private::DataExtractor& get_debug_ranges_data(); + const lldb_private::DataExtractor& get_debug_str_data(); + + DWARFDebugAbbrev* DebugAbbrev(); + const DWARFDebugAbbrev* DebugAbbrev() const; + + DWARFDebugAranges* DebugAranges(); + const DWARFDebugAranges*DebugAranges() const; + + DWARFDebugInfo* DebugInfo(); + const DWARFDebugInfo* DebugInfo() const; + +// These shouldn't be used unless we want to dump the DWARF line tables. +// DWARFDebugLine* DebugLine(); +// const DWARFDebugLine* DebugLine() const; + +// DWARFDebugPubnames* DebugPubnames(); +// const DWARFDebugPubnames* DebugPubnames() const; +// +// DWARFDebugPubnames* DebugPubBaseTypes(); +// const DWARFDebugPubnames* DebugPubBaseTypes() const; +// +// DWARFDebugPubnames* DebugPubtypes(); +// const DWARFDebugPubnames* DebugPubtypes() const; + + DWARFDebugRanges* DebugRanges(); + const DWARFDebugRanges* DebugRanges() const; + + const lldb_private::DataExtractor& + GetCachedSectionData (uint32_t got_flag, const lldb_private::ConstString §ion_name, lldb_private::DataExtractor &data); + + static bool SupportedVersion(uint16_t version); + + clang::DeclContext * + GetClangDeclContextForDIE (const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die); + + clang::DeclContext * + GetClangDeclContextForDIEOffset (dw_offset_t die_offset); + + lldb_private::Flags& + GetFlags () + { + return m_flags; + } + + const lldb_private::Flags& + GetFlags () const + { + return m_flags; + } + +protected: + + enum + { + flagsGotDebugAbbrevData = (1 << 0), + flagsGotDebugArangesData = (1 << 1), + flagsGotDebugFrameData = (1 << 2), + flagsGotDebugInfoData = (1 << 3), + flagsGotDebugLineData = (1 << 4), + flagsGotDebugLocData = (1 << 5), + flagsGotDebugMacInfoData = (1 << 6), + flagsGotDebugPubNamesData = (1 << 7), + flagsGotDebugPubTypesData = (1 << 8), + flagsGotDebugRangesData = (1 << 9), + flagsGotDebugStrData = (1 << 10), + // True if this is a .o file used when resolving a N_OSO entry with + // debug maps. + flagsDWARFIsOSOForDebugMap = (1 << 16) + }; + + DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF); + bool ParseCompileUnit(DWARFCompileUnit* cu, lldb::CompUnitSP& compile_unit_sp); + DWARFCompileUnit* GetDWARFCompileUnitForUID(lldb::user_id_t cu_uid); + DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu); + lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* cu, uint32_t cu_idx = UINT_MAX); + bool GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc); + lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die); + size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc, + lldb::user_id_t parentBlockID, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + lldb::addr_t subprogram_low_pc, + bool parse_siblings, + bool parse_children); + size_t ParseTypes (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children); + lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool &type_is_new); + + lldb::VariableSP ParseVariableDIE( + const lldb_private::SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die); + + size_t ParseVariables( + const lldb_private::SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + bool parse_siblings, + bool parse_children, + lldb_private::VariableList* cc_variable_list = NULL); + + size_t ParseChildMembers( + const lldb_private::SymbolContext& sc, + lldb::TypeSP& type_sp, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + std::vector<clang::CXXBaseSpecifier *>& base_classes, + std::vector<int>& member_accessibilities, + int &default_accessibility, + bool &is_a_class); + + size_t ParseChildParameters( + const lldb_private::SymbolContext& sc, + lldb::TypeSP& type_sp, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + lldb_private::TypeList* type_list, + std::vector<void *>& function_args, + std::vector<clang::ParmVarDecl*>& function_param_decls); + + size_t ParseChildEnumerators( + const lldb_private::SymbolContext& sc, + lldb::TypeSP& type_sp, + void *enumerator_qual_type, + uint32_t enumerator_byte_size, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *enum_die); + + void ParseChildArrayInfo( + const lldb_private::SymbolContext& sc, + const DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + int64_t& first_index, + std::vector<uint64_t>& element_orders, + uint32_t& byte_stride, + uint32_t& bit_stride); + + lldb_private::Type* GetUniquedTypeForDIEOffset(dw_offset_t type_die_offset, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx, bool safe); + lldb::TypeSP GetTypeForDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry* die, lldb::TypeSP& owning_type_sp, int32_t child_type, uint32_t idx); +// uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types); + + void Index(); + + lldb_private::Flags m_flags; + lldb_private::DataExtractor m_dwarf_data; + lldb_private::DataExtractor m_data_debug_abbrev; + lldb_private::DataExtractor m_data_debug_aranges; + lldb_private::DataExtractor m_data_debug_frame; + lldb_private::DataExtractor m_data_debug_info; + lldb_private::DataExtractor m_data_debug_line; + lldb_private::DataExtractor m_data_debug_loc; + lldb_private::DataExtractor m_data_debug_macinfo; + lldb_private::DataExtractor m_data_debug_pubnames; + lldb_private::DataExtractor m_data_debug_pubtypes; + lldb_private::DataExtractor m_data_debug_ranges; + lldb_private::DataExtractor m_data_debug_str; + + // The auto_ptr items below are generated on demand if and when someone accesses + // them through a non const version of this class. + std::auto_ptr<DWARFDebugAbbrev> m_abbr; + std::auto_ptr<DWARFDebugAranges> m_aranges; + std::auto_ptr<DWARFDebugInfo> m_info; + std::auto_ptr<DWARFDebugLine> m_line; + lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_function_die; // All concrete functions + lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_inlined_die; // All inlined functions + lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_global_die; // Global and static variables + lldb_private::UniqueCStringMap<dw_offset_t> m_name_to_type_die; // All type DIE offsets + bool m_indexed; + +// std::auto_ptr<DWARFDebugPubnames> m_pubnames; +// std::auto_ptr<DWARFDebugPubnames> m_pubbasetypes; // Just like m_pubtypes, but for DW_TAG_base_type DIEs +// std::auto_ptr<DWARFDebugPubnames> m_pubtypes; + std::auto_ptr<DWARFDebugRanges> m_ranges; + + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap; + DIEToDeclContextMap m_die_to_decl_ctx; + +// TypeFixupColl m_type_fixups; +// std::vector<Type*> m_indirect_fixups; + +//#define LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST 1 +#if defined(LLDB_SYMBOL_FILE_DWARF_SHRINK_TEST) + + typedef std::map<FileSpec, DWARFDIECollection> FSToDIES; + void ShrinkDSYM(CompileUnit *dc_cu, DWARFCompileUnit *dw_cu, const FileSpec& cu_fspec, const FileSpec& base_types_cu_fspec, FSToDIES& fs_to_dies, const DWARFDebugInfoEntry *die); +#endif +}; + +#endif // liblldb_SymbolFileDWARF_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp new file mode 100644 index 00000000000..7bf968dd9ce --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -0,0 +1,873 @@ +//===-- SymbolFileDWARFDebugMap.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileDWARFDebugMap.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/VariableList.h" + +#include "SymbolFileDWARF.h" + +using namespace lldb; +using namespace lldb_private; + +void +SymbolFileDWARFDebugMap::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +SymbolFileDWARFDebugMap::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + + +const char * +SymbolFileDWARFDebugMap::GetPluginNameStatic() +{ + return "symbol-file.dwarf2-debugmap"; +} + +const char * +SymbolFileDWARFDebugMap::GetPluginDescriptionStatic() +{ + return "DWARF and DWARF3 debug symbol file reader (debug map)."; +} + +SymbolFile* +SymbolFileDWARFDebugMap::CreateInstance (ObjectFile* obj_file) +{ + return new SymbolFileDWARFDebugMap (obj_file); +} + + +SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap (ObjectFile* ofile) : + SymbolFile(ofile), + m_flags(), + m_compile_unit_infos(), + m_func_indexes(), + m_glob_indexes() +{ +} + + +SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap() +{ +} + +void +SymbolFileDWARFDebugMap::InitOSO () +{ + if (m_flags.test(kHaveInitializedOSOs)) + return; + + m_flags.set(kHaveInitializedOSOs); + // In order to get the abilities of this plug-in, we look at the list of + // N_OSO entries (object files) from the symbol table and make sure that + // these files exist and also contain valid DWARF. If we get any of that + // then we return the abilities of the first N_OSO's DWARF. + + Symtab* symtab = m_obj_file->GetSymtab(); + if (symtab) + { + //StreamFile s(0, 4, eByteOrderHost, stdout); + std::vector<uint32_t> oso_indexes; + const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithType(eSymbolTypeObjectFile, oso_indexes); + + symtab->AppendSymbolIndexesWithType(eSymbolTypeFunction, m_func_indexes); + symtab->AppendSymbolIndexesWithType(eSymbolTypeGlobal, m_glob_indexes); + + symtab->SortSymbolIndexesByValue(m_func_indexes, true); + symtab->SortSymbolIndexesByValue(m_glob_indexes, true); + + if (oso_index_count > 0) + { + m_compile_unit_infos.resize(oso_index_count); +// s.Printf("%s N_OSO symbols:\n", __PRETTY_FUNCTION__); +// symtab->Dump(&s, oso_indexes); + + for (uint32_t i=0; i<oso_index_count; ++i) + { + m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 1); + if (m_compile_unit_infos[i].so_symbol->GetSiblingIndex() == 0) + m_compile_unit_infos[i].so_symbol = symtab->SymbolAtIndex(oso_indexes[i] - 2); + m_compile_unit_infos[i].oso_symbol = symtab->SymbolAtIndex(oso_indexes[i]); + } + } + } +} + +Module * +SymbolFileDWARFDebugMap::GetModuleByOSOIndex (uint32_t oso_idx) +{ + const uint32_t cu_count = GetNumCompileUnits(); + if (oso_idx < cu_count) + return GetModuleByCompUnitInfo (&m_compile_unit_infos[oso_idx]); + return NULL; +} + +Module * +SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info) +{ + if (comp_unit_info->oso_module_sp.get() == NULL) + { + Symbol *oso_symbol = comp_unit_info->oso_symbol; + if (oso_symbol) + { + FileSpec oso_file_spec(oso_symbol->GetMangled().GetName().AsCString()); + + ModuleList::GetSharedModule (oso_file_spec, + m_obj_file->GetModule()->GetArchitecture(), + NULL, // UUID pointer + NULL, // object name + 0, // object offset + comp_unit_info->oso_module_sp, + NULL, + NULL); + //comp_unit_info->oso_module_sp.reset(new Module (oso_file_spec, m_obj_file->GetModule()->GetArchitecture())); + } + } + return comp_unit_info->oso_module_sp.get(); +} + + +bool +SymbolFileDWARFDebugMap::GetFileSpecForSO (uint32_t oso_idx, FileSpec &file_spec) +{ + if (oso_idx < m_compile_unit_infos.size()) + { + if (!m_compile_unit_infos[oso_idx].so_file) + { + + if (m_compile_unit_infos[oso_idx].so_symbol == NULL) + return false; + + std::string so_path (m_compile_unit_infos[oso_idx].so_symbol->GetMangled().GetName().AsCString()); + if (m_compile_unit_infos[oso_idx].so_symbol[1].GetType() == eSymbolTypeSourceFile) + so_path += m_compile_unit_infos[oso_idx].so_symbol[1].GetMangled().GetName().AsCString(); + m_compile_unit_infos[oso_idx].so_file.SetFile(so_path.c_str()); + } + file_spec = m_compile_unit_infos[oso_idx].so_file; + return true; + } + return false; +} + + + +ObjectFile * +SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex (uint32_t oso_idx) +{ + Module *oso_module = GetModuleByOSOIndex (oso_idx); + if (oso_module) + return oso_module->GetObjectFile(); + return NULL; +} + +SymbolFileDWARF * +SymbolFileDWARFDebugMap::GetSymbolFile (const SymbolContext& sc) +{ + CompileUnitInfo *comp_unit_info = GetCompUnitInfo (sc); + if (comp_unit_info) + return GetSymbolFileByCompUnitInfo (comp_unit_info); + return NULL; +} + +ObjectFile * +SymbolFileDWARFDebugMap::GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info) +{ + Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info); + if (oso_module) + return oso_module->GetObjectFile(); + return NULL; +} + +SymbolFileDWARF * +SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex (uint32_t oso_idx) +{ + if (oso_idx < m_compile_unit_infos.size()) + return GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[oso_idx]); + return NULL; +} + +SymbolFileDWARF * +SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info) +{ + if (comp_unit_info->oso_symbol_vendor == NULL) + { + ObjectFile *oso_objfile = GetObjectFileByCompUnitInfo (comp_unit_info); + + if (oso_objfile) + { + comp_unit_info->oso_symbol_vendor = oso_objfile->GetModule()->GetSymbolVendor(); +// SymbolFileDWARF *oso_dwarf = new SymbolFileDWARF(oso_objfile); +// comp_unit_info->oso_dwarf_sp.reset (oso_dwarf); + if (comp_unit_info->oso_symbol_vendor) + { + // Set a bit that lets this DWARF file know that it is being + // used along with a debug map and that it will have the + // remapped sections that we do below. + ((SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile())->GetFlags().Set(SymbolFileDWARF::flagsDWARFIsOSOForDebugMap); + comp_unit_info->debug_map_sections_sp.reset(new SectionList); + + Symtab *exe_symtab = m_obj_file->GetSymtab(); + Module *oso_module = oso_objfile->GetModule(); + Symtab *oso_symtab = oso_objfile->GetSymtab(); +//#define DEBUG_OSO_DMAP // Do not check in with this defined... +#if defined(DEBUG_OSO_DMAP) + StreamFile s(stdout); + s << "OSO symtab:\n"; + oso_symtab->Dump(&s, NULL); + s << "OSO sections before:\n"; + oso_objfile->GetSectionList()->Dump(&s, NULL, true); +#endif + + ///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction; + //SectionList *oso_sections = oso_objfile->Sections(); + // Now we need to make sections that map from zero based object + // file addresses to where things eneded up in the main executable. + uint32_t oso_start_idx = comp_unit_info->oso_symbol->GetID() + 1; + const uint32_t oso_end_idx = comp_unit_info->so_symbol->GetSiblingIndex(); + uint32_t sect_id = 0x10000; + for (uint32_t idx = oso_start_idx; idx < oso_end_idx; ++idx) + { + Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx); + if (exe_symbol) + { + switch (exe_symbol->GetType()) + { + case eSymbolTypeFunction: + { + // For each N_FUN, or function that we run into in the debug map + // we make a new section that we add to the sections found in the + // .o file. This new section has the file address set to what the + // addresses are in the .o file, and the load address is adjusted + // to match where it ended up in the final executable! We do this + // before we parse any dwarf info so that when it goes get parsed + // all section/offset addresses that get registered will resolve + // correctly to the new addresses in the main executable. + + // First we find the original symbol in the .o file's symbol table + Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeCode); + if (oso_fun_symbol) + { + // If we found the symbol, then we + Section* exe_fun_section = const_cast<Section *>(exe_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); + Section* oso_fun_section = const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); + if (oso_fun_section) + { + // Now we create a section that we will add as a child of the + // section in which the .o symbol (the N_FUN) exists. + + // We use the exe_symbol size because the one in the .o file + // will just be a symbol with no size, and the exe_symbol + // size will reflect any size changes (ppc has been known to + // shrink function sizes when it gets rid of jump islands that + // aren't needed anymore). + SectionSP oso_fun_section_sp (new Section (const_cast<Section *>(oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()), + oso_module, // Module (the .o file) + sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs + exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated! + eSectionTypeDebug, + oso_fun_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section + exe_symbol->GetByteSize(), // File size (we need the size from the executable) + 0, 0, 0)); + + oso_fun_section_sp->SetLinkedLocation (exe_fun_section, + exe_symbol->GetValue().GetFileAddress() - exe_fun_section->GetFileAddress()); + oso_fun_section->GetChildren().AddSection(oso_fun_section_sp); + comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp); + } + } + } + break; + + case eSymbolTypeGlobal: + case eSymbolTypeStatic: + { + // For each N_GSYM we remap the address for the global by making + // a new section that we add to the sections found in the .o file. + // This new section has the file address set to what the + // addresses are in the .o file, and the load address is adjusted + // to match where it ended up in the final executable! We do this + // before we parse any dwarf info so that when it goes get parsed + // all section/offset addresses that get registered will resolve + // correctly to the new addresses in the main executable. We + // initially set the section size to be 1 byte, but will need to + // fix up these addresses further after all globals have been + // parsed to span the gaps, or we can find the global variable + // sizes from the DWARF info as we are parsing. + +#if 0 + // First we find the non-stab entry that corresponds to the N_GSYM in the executable + Symbol *exe_gsym_symbol = exe_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData); +#else + // The mach-o object file parser already matches up the N_GSYM with with the non-stab + // entry, so we shouldn't have to do that. If this ever changes, enable the code above + // in the "#if 0" block. STSYM's always match the symbol as found below. + Symbol *exe_gsym_symbol = exe_symbol; +#endif + // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file + Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData); + if (exe_gsym_symbol && oso_gsym_symbol) + { + // If we found the symbol, then we + Section* exe_gsym_section = const_cast<Section *>(exe_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); + Section* oso_gsym_section = const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); + if (oso_gsym_section) + { + SectionSP oso_gsym_section_sp (new Section (const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()), + oso_module, // Module (the .o file) + sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs + exe_symbol->GetMangled().GetName(), // Name the section the same as the symbol for which is was generated! + eSectionTypeDebug, + oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section + 1, // We don't know the size of the global, just do the main address for now. + 0, 0, 0)); + + oso_gsym_section_sp->SetLinkedLocation (exe_gsym_section, + exe_gsym_symbol->GetValue().GetFileAddress() - exe_gsym_section->GetFileAddress()); + oso_gsym_section->GetChildren().AddSection(oso_gsym_section_sp); + comp_unit_info->debug_map_sections_sp->AddSection(oso_gsym_section_sp); + } + } + } + break; + +// case eSymbolTypeStatic: +// { +// // For each N_STSYM we remap the address for the global by making +// // a new section that we add to the sections found in the .o file. +// // This new section has the file address set to what the +// // addresses are in the .o file, and the load address is adjusted +// // to match where it ended up in the final executable! We do this +// // before we parse any dwarf info so that when it goes get parsed +// // all section/offset addresses that get registered will resolve +// // correctly to the new addresses in the main executable. We +// // initially set the section size to be 1 byte, but will need to +// // fix up these addresses further after all globals have been +// // parsed to span the gaps, or we can find the global variable +// // sizes from the DWARF info as we are parsing. +// +// +// Symbol *exe_stsym_symbol = exe_symbol; +// // First we find the non-stab entry that corresponds to the N_STSYM in the .o file +// Symbol *oso_stsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData); +// if (exe_stsym_symbol && oso_stsym_symbol) +// { +// // If we found the symbol, then we +// Section* exe_stsym_section = const_cast<Section *>(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); +// Section* oso_stsym_section = const_cast<Section *>(oso_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); +// if (oso_stsym_section) +// { +// // The load address of the symbol will use the section in the +// // executable that contains the debug map that corresponds to +// // the N_FUN symbol. We set the offset to reflect the offset +// // into that section since we are creating a new section. +// AddressRange stsym_load_range(exe_stsym_section, exe_stsym_symbol->GetValue().GetFileAddress() - exe_stsym_section->GetFileAddress(), 1); +// // We need the symbol's section offset address from the .o file, but +// // we need a non-zero size. +// AddressRange stsym_file_range(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection(), exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), 1); +// +// // Now we create a section that we will add as a child of the +// // section in which the .o symbol (the N_FUN) exists. +// +//// TODO: mimic what I did for N_FUN if that works... +//// // We use the 1 byte for the size because we don't know the +//// // size of the global symbol without seeing the DWARF. +//// SectionSP oso_fun_section_sp (new Section ( NULL, oso_module, // Module (the .o file) +//// sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs +//// exe_symbol->GetMangled().GetName(),// Name the section the same as the symbol for which is was generated! +//// // &stsym_load_range, // Load offset is the offset into the executable section for the N_FUN from the debug map +//// &stsym_file_range, // File section/offset is just the same os the symbol on the .o file +//// 0, 0, 0)); +//// +//// // Now we add the new section to the .o file's sections as a child +//// // of the section in which the N_SECT symbol exists. +//// oso_stsym_section->GetChildren().AddSection(oso_fun_section_sp); +//// comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp); +// } +// } +// } +// break; + } + } + } +#if defined(DEBUG_OSO_DMAP) + s << "OSO sections after:\n"; + oso_objfile->GetSectionList()->Dump(&s, NULL, true); +#endif + } + } + } + if (comp_unit_info->oso_symbol_vendor) + return (SymbolFileDWARF *)comp_unit_info->oso_symbol_vendor->GetSymbolFile(); + return NULL; +} + +uint32_t +SymbolFileDWARFDebugMap::GetAbilities () +{ + // In order to get the abilities of this plug-in, we look at the list of + // N_OSO entries (object files) from the symbol table and make sure that + // these files exist and also contain valid DWARF. If we get any of that + // then we return the abilities of the first N_OSO's DWARF. + + const uint32_t oso_index_count = GetNumCompileUnits(); + if (oso_index_count > 0) + { + const uint32_t dwarf_abilities = SymbolFile::CompileUnits | + SymbolFile::Functions | + SymbolFile::Blocks | + SymbolFile::GlobalVariables | + SymbolFile::LocalVariables | + SymbolFile::VariableTypes | + SymbolFile::LineTables; + + for (uint32_t oso_idx=0; oso_idx<oso_index_count; ++oso_idx) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + { + uint32_t oso_abilities = oso_dwarf->GetAbilities(); + if ((oso_abilities & dwarf_abilities) == dwarf_abilities) + return oso_abilities; + } + } + } + return 0; +} + +uint32_t +SymbolFileDWARFDebugMap::GetNumCompileUnits() +{ + InitOSO (); + return m_compile_unit_infos.size(); +} + + +CompUnitSP +SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) +{ + CompUnitSP comp_unit_sp; + const uint32_t cu_count = GetNumCompileUnits(); + + if (cu_idx < cu_count) + { + if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (cu_idx); + if (oso_dwarf) + { + // There is only one compile unit for N_OSO entry right now, so + // it will always exist at index zero. + m_compile_unit_infos[cu_idx].oso_compile_unit_sp = m_compile_unit_infos[cu_idx].oso_symbol_vendor->GetCompileUnitAtIndex (0); + } + + if (m_compile_unit_infos[cu_idx].oso_compile_unit_sp.get() == NULL) + { + // We weren't able to get the DWARF for this N_OSO entry (the + // .o file may be missing or not at the specified path), make + // one up as best we can from the debug map. We set the uid + // of the compile unit to the symbol index with the MSBit set + // so that it doesn't collide with any uid values from the DWARF + Symbol *so_symbol = m_compile_unit_infos[cu_idx].so_symbol; + if (so_symbol) + { + m_compile_unit_infos[cu_idx].oso_compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(), + NULL, + so_symbol->GetMangled().GetName().AsCString(), + cu_idx, + Language::Unknown)); + } + } + } + comp_unit_sp = m_compile_unit_infos[cu_idx].oso_compile_unit_sp; + } + + return comp_unit_sp; +} + +SymbolFileDWARFDebugMap::CompileUnitInfo * +SymbolFileDWARFDebugMap::GetCompUnitInfo (const SymbolContext& sc) +{ + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t i=0; i<cu_count; ++i) + { + if (sc.comp_unit == m_compile_unit_infos[i].oso_compile_unit_sp.get()) + return &m_compile_unit_infos[i]; + } + return NULL; +} + +size_t +SymbolFileDWARFDebugMap::ParseCompileUnitFunctions (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitFunctions (sc); + return 0; +} + +bool +SymbolFileDWARFDebugMap::ParseCompileUnitLineTable (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitLineTable (sc); + return false; +} + +bool +SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitSupportFiles (sc, support_files); + return false; +} + + +size_t +SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseFunctionBlocks (sc); + return 0; +} + + +size_t +SymbolFileDWARFDebugMap::ParseTypes (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseTypes (sc); + return 0; +} + + +size_t +SymbolFileDWARFDebugMap::ParseVariablesForContext (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseTypes (sc); + return 0; +} + + + +Type* +SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid) +{ + return NULL; +} + + +uint32_t +SymbolFileDWARFDebugMap::ResolveSymbolContext (const Address& exe_so_addr, uint32_t resolve_scope, SymbolContext& sc) +{ + uint32_t resolved_flags = 0; + Symtab* symtab = m_obj_file->GetSymtab(); + if (symtab) + { + const addr_t exe_file_addr = exe_so_addr.GetFileAddress(); + sc.symbol = symtab->FindSymbolContainingFileAddress (exe_file_addr, &m_func_indexes[0], m_func_indexes.size()); + + if (sc.symbol != NULL) + { + resolved_flags |= eSymbolContextSymbol; + + uint32_t oso_idx = 0; + CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (sc.symbol->GetID(), &oso_idx); + if (comp_unit_info) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + ObjectFile *oso_objfile = GetObjectFileByOSOIndex (oso_idx); + if (oso_dwarf && oso_objfile) + { + SectionList *oso_section_list = oso_objfile->GetSectionList(); + + + SectionSP oso_section_sp(oso_section_list->FindSectionByName(exe_so_addr.GetSection()->GetName())); + if (oso_section_sp) + { + SectionSP oso_symbol_section_sp (oso_section_sp->GetChildren().FindSectionContainingLinkedFileAddress (exe_file_addr)); + + if (oso_symbol_section_sp) + { + const addr_t linked_file_addr = oso_symbol_section_sp->GetLinkedFileAddress(); + Address oso_so_addr (oso_symbol_section_sp.get(), exe_file_addr - linked_file_addr); + if (oso_so_addr.IsSectionOffset()) + resolved_flags |= oso_dwarf->ResolveSymbolContext (oso_so_addr, resolve_scope, sc); + } + } + // Map the load address from in the executable back to a + // section/offset address in the .o file so we can do + // lookups in the .o DWARF. +// Address oso_so_addr (exe_load_addr, false, comp_unit_info->debug_map_sections_sp.get()); +// +// // Make sure we were able to resolve this back to a .o +// // section offset address, and if so, resolve the context +// // for everything that was asked for. +// if (oso_so_addr.IsSectionOffset()) +// resolved_flags |= oso_dwarf->ResolveSymbolContext (oso_so_addr, resolve_scope, sc); + } + } + } + } + return resolved_flags; +} + + +uint32_t +SymbolFileDWARFDebugMap::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) +{ + uint32_t initial = sc_list.GetSize(); + const uint32_t cu_count = GetNumCompileUnits(); + + FileSpec so_file_spec; + for (uint32_t i=0; i<cu_count; ++i) + { + if (GetFileSpecForSO (i, so_file_spec)) + { + // By passing false to the comparison we will be able to match + // and files given a filename only. If both file_spec and + // so_file_spec have directories, we will still do a full match. + if (FileSpec::Compare (file_spec, so_file_spec, false) == 0) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i); + + oso_dwarf->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list); + } + } + } + return sc_list.GetSize() - initial; +} + +uint32_t +SymbolFileDWARFDebugMap::PrivateFindGlobalVariables +( + const ConstString &name, + const std::vector<uint32_t> &indexes, // Indexes into the symbol table that match "name" + uint32_t max_matches, + VariableList& variables +) +{ + const uint32_t original_size = variables.GetSize(); + const size_t match_count = indexes.size(); + for (size_t i=0; i<match_count; ++i) + { + uint32_t oso_idx; + CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx); + if (comp_unit_info) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + { + if (oso_dwarf->FindGlobalVariables(name, true, max_matches, variables)) + if (variables.GetSize() > max_matches) + break; + } + } + } + return variables.GetSize() - original_size; +} + +uint32_t +SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables) +{ + + // If we aren't appending the results to this list, then clear the list + if (!append) + variables.Clear(); + + // Remember how many variables are in the list before we search in case + // we are appending the results to a variable list. + const uint32_t original_size = variables.GetSize(); + + Symtab* symtab = m_obj_file->GetSymtab(); + if (symtab) + { + std::vector<uint32_t> indexes; + const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeGlobal, indexes); + if (match_count) + { + PrivateFindGlobalVariables (name, indexes, max_matches, variables); + } + } + // Return the number of variable that were appended to the list + return variables.GetSize() - original_size; +} + + +uint32_t +SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) +{ + return 0; +} + + +int +SymbolFileDWARFDebugMap::SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info) +{ + const uint32_t symbol_idx = *symbol_idx_ptr; + + if (symbol_idx < comp_unit_info->so_symbol->GetID()) + return -1; + + if (symbol_idx < comp_unit_info->so_symbol->GetSiblingIndex()) + return 0; + + return 1; +} + + +SymbolFileDWARFDebugMap::CompileUnitInfo* +SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr) +{ + const uint32_t oso_index_count = m_compile_unit_infos.size(); + CompileUnitInfo *comp_unit_info = NULL; + if (oso_index_count) + { + comp_unit_info = (CompileUnitInfo*)bsearch(&symbol_idx, &m_compile_unit_infos[0], m_compile_unit_infos.size(), sizeof(CompileUnitInfo), (comparison_function)SymbolContainsSymbolIndex); + } + + if (oso_idx_ptr) + { + if (comp_unit_info != NULL) + *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0]; + else + *oso_idx_ptr = UINT32_MAX; + } + return comp_unit_info; +} + +uint32_t +SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARFDebugMap::FindFunctions (name = %s)", + name.GetCString()); + + + std::vector<uint32_t> indexes; + uint32_t initial_size = 0; + if (append) + initial_size = sc_list.GetSize(); + else + sc_list.Clear(); + + const size_t match_count = m_obj_file->GetSymtab()->FindAllSymbolsWithNameAndType (name, eSymbolTypeFunction, indexes); + if (match_count > 0) + { + for (size_t i=0; i<match_count; ++i) + { + uint32_t oso_idx; + CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx); + if (comp_unit_info) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + oso_dwarf->FindFunctions(name, true, sc_list); + } + } +// Stream s(stdout); +// sc_list.Dump(&s); + } + + return sc_list.GetSize() - initial_size; +} + + +uint32_t +SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", + regex.GetText()); + + + return 0; +} + +// +//uint32_t +//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) +//{ +// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); +// if (oso_dwarf) +// return oso_dwarf->FindTypes (sc, name, append, max_matches, encoding, udt_uid, types); +// return 0; +//} +// +// +//uint32_t +//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types) +//{ +// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); +// if (oso_dwarf) +// return oso_dwarf->FindTypes (sc, regex, append, max_matches, encoding, udt_uid, types); +// return 0; +//} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +const char * +SymbolFileDWARFDebugMap::GetPluginName() +{ + return "SymbolFileDWARFDebugMap"; +} + +const char * +SymbolFileDWARFDebugMap::GetShortPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +SymbolFileDWARFDebugMap::GetPluginVersion() +{ + return 1; +} + +void +SymbolFileDWARFDebugMap::GetPluginCommandHelp (const char *command, Stream *strm) +{ +} + +Error +SymbolFileDWARFDebugMap::ExecutePluginCommand (Args &command, Stream *strm) +{ + Error error; + error.SetErrorString("No plug-in command are currently supported."); + return error; +} + +Log * +SymbolFileDWARFDebugMap::EnablePluginLogging (Stream *strm, Args &command) +{ + return NULL; +} + + diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h new file mode 100644 index 00000000000..0a312ab9f26 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -0,0 +1,186 @@ +//===-- SymbolFileDWARFDebugMap.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_SymbolFileDWARFDebugMap_h_ +#define liblldb_SymbolFileDWARFDebugMap_h_ + + +#include <vector> +#include <bitset> +#include "lldb/Symbol/SymbolFile.h" + +class SymbolFileDWARF; + +class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static const char * + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::SymbolFile * + CreateInstance (lldb_private::ObjectFile* obj_file); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile); + virtual ~ SymbolFileDWARFDebugMap (); + + virtual uint32_t GetAbilities (); + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + virtual uint32_t GetNumCompileUnits (); + virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index); + + virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc); + virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc); + virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files); + virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc); + virtual size_t ParseTypes (const lldb_private::SymbolContext& sc); + virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc); + + virtual lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid); + virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc); + virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindGlobalVariables (const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::VariableList& variables); + virtual uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables); + virtual uint32_t FindFunctions (const lldb_private::ConstString &name, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list); +// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types); +// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual const char * + GetPluginName(); + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp (const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command); + +protected: + enum + { + kHaveInitializedOSOs = (1 << 0), + kNumFlags + }; + + //------------------------------------------------------------------ + // Class specific types + //------------------------------------------------------------------ + struct CompileUnitInfo + { + lldb_private::FileSpec so_file; + lldb_private::Symbol *so_symbol; + lldb_private::Symbol *oso_symbol; + lldb::ModuleSP oso_module_sp; + lldb::CompUnitSP oso_compile_unit_sp; + lldb_private::SymbolVendor *oso_symbol_vendor; +// lldb_private::shared_ptr<SymbolFileDWARF> oso_dwarf_sp; +// lldb_private::shared_ptr<SymbolVendor> oso_dwarf_sp; + std::vector<uint32_t> function_indexes; + std::vector<uint32_t> static_indexes; + lldb::SharedPtr<lldb_private::SectionList>::Type debug_map_sections_sp; + + CompileUnitInfo() : + so_file(), + so_symbol(NULL), + oso_symbol(NULL), + oso_module_sp(), + oso_compile_unit_sp(), + oso_symbol_vendor(NULL), +// oso_dwarf_sp(), + function_indexes(), + static_indexes(), + debug_map_sections_sp() + { + } + }; + + //------------------------------------------------------------------ + // Protected Member Functions + //------------------------------------------------------------------ + void + InitOSO (); + + bool + GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec); + + CompileUnitInfo * + GetCompUnitInfo (const lldb_private::SymbolContext& sc); + + lldb_private::Module * + GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info); + + lldb_private::Module * + GetModuleByOSOIndex (uint32_t oso_idx); + + lldb_private::ObjectFile * + GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info); + + lldb_private::ObjectFile * + GetObjectFileByOSOIndex (uint32_t oso_idx); + + SymbolFileDWARF * + GetSymbolFile (const lldb_private::SymbolContext& sc); + + SymbolFileDWARF * + GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info); + + SymbolFileDWARF * + GetSymbolFileByOSOIndex (uint32_t oso_idx); + + CompileUnitInfo* + GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr); + + static int + SymbolContainsSymbolIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info); + + uint32_t + PrivateFindGlobalVariables (const lldb_private::ConstString &name, + const std::vector<uint32_t> &name_symbol_indexes, + uint32_t max_matches, + lldb_private::VariableList& variables); + + //------------------------------------------------------------------ + // Member Variables + //------------------------------------------------------------------ + std::bitset<kNumFlags> m_flags; + std::vector<CompileUnitInfo> m_compile_unit_infos; + std::vector<uint32_t> m_func_indexes; // Sorted by address + std::vector<uint32_t> m_glob_indexes; +}; + +#endif // #ifndef liblldb_SymbolFileDWARFDebugMap_h_ |