diff options
author | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
commit | f034231a6a1fd5d6395206c1651de8cd9402cca3 (patch) | |
tree | f561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins/SymbolFile | |
download | src-f034231a6a1fd5d6395206c1651de8cd9402cca3.tar.gz src-f034231a6a1fd5d6395206c1651de8cd9402cca3.zip |
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.)
Sponsored by: DARPA, AFRL
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=254721
Diffstat (limited to 'source/Plugins/SymbolFile')
52 files changed, 23663 insertions, 0 deletions
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp new file mode 100644 index 000000000000..06e87eab33ce --- /dev/null +++ b/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, lldb::offset_t* offset_ptr) +{ + return Extract(data, offset_ptr, data.GetULEB128(offset_ptr)); +} + +bool +DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, lldb::offset_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; + lldb::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/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h new file mode 100644 index 000000000000..f462b7fc108d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -0,0 +1,81 @@ +//===-- 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; } + size_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); + } + dw_form_t GetFormByIndexUnchecked (uint32_t idx) const + { + return m_attributes[idx].get_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, lldb::offset_t *offset_ptr); + bool Extract(const lldb_private::DataExtractor& data, lldb::offset_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/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h new file mode 100644 index 000000000000..8310b1dda5f1 --- /dev/null +++ b/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 SymbolFileDWARF_DWARFAttribute_h_ +#define SymbolFileDWARF_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 (dw_form_t)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 = (dw_form_t)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 // SymbolFileDWARF_DWARFAttribute_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp new file mode 100644 index 000000000000..493b3af6ecd1 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -0,0 +1,1027 @@ +//===-- 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/Mangled.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/ObjCLanguageRuntime.h" + +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "LogChannelDWARF.h" +#include "NameToDIE.h" +#include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDebugMap.h" + +using namespace lldb; +using namespace lldb_private; +using namespace std; + + +extern int g_verbose; + +DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) : + m_dwarf2Data (dwarf2Data), + m_abbrevs (NULL), + m_user_data (NULL), + m_die_array (), + m_func_aranges_ap (), + m_base_addr (0), + m_offset (DW_INVALID_OFFSET), + m_length (0), + m_version (0), + m_addr_size (DWARFCompileUnit::GetDefaultAddressSize()), + m_producer (eProducerInvalid), + m_producer_version_major (0), + m_producer_version_minor (0), + m_producer_version_update (0) +{ +} + +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_func_aranges_ap.reset(); + m_user_data = NULL; + m_producer = eProducerInvalid; +} + +bool +DWARFCompileUnit::Extract(const DataExtractor &debug_info, lldb::offset_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(lldb::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 hasn't already 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 and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); + + DWARFDebugInfoEntry die; + // Keep a flat array of the DIE for binary lookup by DIE offset + if (!cu_die_only) + { + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); + if (log) + { + m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, + "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at .debug_info[0x%8.8x]", + GetOffset()); + } + } + + uint32_t depth = 0; + // We are in our compile unit, parse starting at the offset + // we were told to parse + const DataExtractor& debug_info_data = m_dwarf2Data->get_debug_info_data(); + std::vector<uint32_t> die_index_stack; + die_index_stack.reserve(32); + die_index_stack.push_back(0); + bool prev_die_had_children = false; + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize()); + while (offset < next_cu_offset && + die.FastExtract (debug_info_data, this, fixed_form_sizes, &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() ? " *" : ""); + + const bool null_die = die.IsNULL(); + if (depth == 0) + { + uint64_t base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (base_addr == LLDB_INVALID_ADDRESS) + base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_entry_pc, 0); + SetBaseAddress (base_addr); + if (initial_die_array_size == 0) + AddDIE (die); + if (cu_die_only) + return 1; + } + else + { + if (null_die) + { + if (prev_die_had_children) + { + // This will only happen if a DIE says is has children + // but all it contains is a NULL tag. Since we are removing + // the NULL DIEs from the list (saves up to 25% in C++ code), + // we need a way to let the DIE know that it actually doesn't + // have children. + if (!m_die_array.empty()) + m_die_array.back().SetEmptyChildren(true); + } + } + else + { + die.SetParentIndex(m_die_array.size() - die_index_stack[depth-1]); + + if (die_index_stack.back()) + m_die_array[die_index_stack.back()].SetSiblingIndex(m_die_array.size()-die_index_stack.back()); + + // Only push the DIE if it isn't a NULL DIE + m_die_array.push_back(die); + } + } + + if (null_die) + { + // NULL DIE. + if (!die_index_stack.empty()) + die_index_stack.pop_back(); + + if (depth > 0) + --depth; + if (depth == 0) + break; // We are done with this compile unit! + + prev_die_had_children = false; + } + else + { + die_index_stack.back() = m_die_array.size() - 1; + // Normal DIE + const bool die_has_children = die.HasChildren(); + if (die_has_children) + { + die_index_stack.push_back(0); + ++depth; + } + prev_die_had_children = die_has_children; + } + } + + // Give a little bit of info if we encounter corrupt DWARF (our offset + // should always terminate at or before the start of the next compilation + // unit header). + if (offset > next_cu_offset) + { + m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning ("DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8" PRIx64 "\n", + GetOffset(), + offset); + } + + // Since std::vector objects will double their size, we really need to + // make a new array with the perfect size so we don't end up wasting + // space. So here we copy and swap to make sure we don't have any extra + // memory taken up. + + if (m_die_array.size () < m_die_array.capacity()) + { + DWARFDebugInfoEntry::collection exact_size_die_array (m_die_array.begin(), m_die_array.end()); + exact_size_die_array.swap (m_die_array); + } + Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE)); + if (log) + { + StreamString strm; + DWARFDebugInfoEntry::DumpDIECollection (strm, m_die_array); + log->PutCString (strm.GetString().c_str()); + } + + 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; +} + +void +DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, + DWARFDebugAranges* debug_aranges, + bool clear_dies_if_already_not_parsed) +{ + // This function is usually called if there in no .debug_aranges section + // in order to produce a compile unit level set of address ranges that + // is accurate. If the DIEs weren't parsed, then we don't want all dies for + // all compile units to stay loaded when they weren't needed. So we can end + // up parsing the DWARF and then throwing them all away to keep memory usage + // down. + const bool clear_dies = ExtractDIEsIfNeeded (false) > 1; + + const DWARFDebugInfoEntry* die = DIE(); + if (die) + die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); + + if (debug_aranges->IsEmpty()) + { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) + { + SymbolFileDWARFDebugMap *debug_map_sym_file = m_dwarf2Data->GetDebugMapSymfile(); + if (debug_map_sym_file == NULL) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) + { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = line_table->GetContiguousFileAddressRanges (file_ranges, append); + for (uint32_t idx=0; idx<num_ranges; ++idx) + { + const LineTable::FileAddressRanges::Entry &range = file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); + printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); + } + } + } + else + debug_map_sym_file->AddOSOARanges(dwarf2Data,debug_aranges); + } + } + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed + if (clear_dies) + ClearDIEs (true); + +} + + +const DWARFDebugAranges & +DWARFCompileUnit::GetFunctionAranges () +{ + if (m_func_aranges_ap.get() == NULL) + { + m_func_aranges_ap.reset (new DWARFDebugAranges()); + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + + if (log) + { + m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log, + "DWARFCompileUnit::GetFunctionAranges() for compile unit at .debug_info[0x%8.8x]", + GetOffset()); + } + const DWARFDebugInfoEntry* die = DIE(); + if (die) + die->BuildFunctionAddressRangeTable (m_dwarf2Data, this, m_func_aranges_ap.get()); + const bool minimize = false; + m_func_aranges_ap->Sort(minimize); + } + return *m_func_aranges_ap.get(); +} + +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()) + { + + const DWARFDebugAranges &func_aranges = GetFunctionAranges (); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + { + *function_die_handle = GetDIEPtr(func_aranges.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; +} + +//---------------------------------------------------------------------- +// 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.Append (&(*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 (const uint32_t cu_idx, + NameToDIE& func_basenames, + NameToDIE& func_fullnames, + NameToDIE& func_methods, + NameToDIE& func_selectors, + NameToDIE& objc_class_selectors, + NameToDIE& globals, + NameToDIE& types, + NameToDIE& namespaces) +{ + const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data(); + + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize()); + + Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_LOOKUPS)); + + if (log) + { + m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log, + "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]", + GetOffset()); + } + + 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: + case DW_TAG_unspecified_type: + break; + + default: + continue; + } + + DWARFDebugInfoEntry::Attributes attributes; + const char *name = NULL; + const char *mangled_cstr = NULL; + bool is_declaration = false; + //bool is_artificial = false; + bool has_address = false; + bool has_location = false; + bool is_global_or_static_variable = false; + + dw_offset_t specification_die_offset = DW_INVALID_OFFSET; + const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, fixed_form_sizes, attributes); + if (num_attributes > 0) + { + for (uint32_t 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: + case DW_AT_linkage_name: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + mangled_cstr = form_value.AsCString(debug_str); + break; + + case DW_AT_low_pc: + case DW_AT_high_pc: + case DW_AT_ranges: + has_address = true; + break; + + 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; + + case DW_AT_specification: + if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value)) + specification_die_offset = form_value.Reference(this); + break; + } + } + } + + switch (tag) + { + case DW_TAG_subprogram: + if (has_address) + { + if (name) + { + // Note, this check is also done in ParseMethodName, but since this is a hot loop, we do the + // simple inlined check outside the call. + ObjCLanguageRuntime::MethodName objc_method(name, true); + if (objc_method.IsValid(true)) + { + ConstString objc_class_name_with_category (objc_method.GetClassNameWithCategory()); + ConstString objc_selector_name (objc_method.GetSelector()); + ConstString objc_fullname_no_category_name (objc_method.GetFullNameWithoutCategory(true)); + ConstString objc_class_name_no_category (objc_method.GetClassName()); + func_fullnames.Insert (ConstString(name), die.GetOffset()); + if (objc_class_name_with_category) + objc_class_selectors.Insert(objc_class_name_with_category, die.GetOffset()); + if (objc_class_name_no_category && objc_class_name_no_category != objc_class_name_with_category) + objc_class_selectors.Insert(objc_class_name_no_category, die.GetOffset()); + if (objc_selector_name) + func_selectors.Insert (objc_selector_name, die.GetOffset()); + if (objc_fullname_no_category_name) + func_fullnames.Insert (objc_fullname_no_category_name, die.GetOffset()); + } + // If we have a mangled name, then the DW_AT_name attribute + // is usually the method name without the class or any parameters + const DWARFDebugInfoEntry *parent = die.GetParent(); + bool is_method = false; + if (parent) + { + dw_tag_t parent_tag = parent->Tag(); + if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type) + { + is_method = true; + } + else + { + if (specification_die_offset != DW_INVALID_OFFSET) + { + const DWARFDebugInfoEntry *specification_die = m_dwarf2Data->DebugInfo()->GetDIEPtr (specification_die_offset, NULL); + if (specification_die) + { + parent = specification_die->GetParent(); + if (parent) + { + parent_tag = parent->Tag(); + + if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type) + is_method = true; + } + } + } + } + } + + + if (is_method) + func_methods.Insert (ConstString(name), die.GetOffset()); + else + func_basenames.Insert (ConstString(name), die.GetOffset()); + + if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) + func_fullnames.Insert (ConstString(name), die.GetOffset()); + } + if (mangled_cstr) + { + // Make sure our mangled name isn't the same string table entry + // as our name. If it starts with '_', then it is ok, else compare + // the string to make sure it isn't the same and we don't end up + // with duplicate entries + if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (name && ::strcmp(name, mangled_cstr) != 0))) + { + Mangled mangled (ConstString(mangled_cstr), true); + func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset()); + if (mangled.GetDemangledName()) + func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset()); + } + } + } + break; + + case DW_TAG_inlined_subroutine: + if (has_address) + { + if (name) + func_basenames.Insert (ConstString(name), die.GetOffset()); + if (mangled_cstr) + { + // Make sure our mangled name isn't the same string table entry + // as our name. If it starts with '_', then it is ok, else compare + // the string to make sure it isn't the same and we don't end up + // with duplicate entries + if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) + { + Mangled mangled (ConstString(mangled_cstr), true); + func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset()); + if (mangled.GetDemangledName()) + func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset()); + } + } + else + func_fullnames.Insert (ConstString(name), 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_unspecified_type: + if (name && is_declaration == false) + { + types.Insert (ConstString(name), die.GetOffset()); + } + break; + + case DW_TAG_namespace: + if (name) + namespaces.Insert (ConstString(name), die.GetOffset()); + break; + + case DW_TAG_variable: + if (name && has_location && is_global_or_static_variable) + { + globals.Insert (ConstString(name), die.GetOffset()); + // Be sure to include variables by their mangled and demangled + // names if they have any since a variable can have a basename + // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled + // mangled name "(anonymous namespace)::i"... + + // Make sure our mangled name isn't the same string table entry + // as our name. If it starts with '_', then it is ok, else compare + // the string to make sure it isn't the same and we don't end up + // with duplicate entries + if (mangled_cstr && name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) + { + Mangled mangled (ConstString(mangled_cstr), true); + globals.Insert (mangled.GetMangledName(), die.GetOffset()); + if (mangled.GetDemangledName()) + globals.Insert (mangled.GetDemangledName(), die.GetOffset()); + } + } + break; + + default: + continue; + } + } +} + +bool +DWARFCompileUnit::Supports_unnamed_objc_bitfields () +{ + if (GetProducer() == eProducerClang) + { + const uint32_t major_version = GetProducerVersionMajor(); + if (major_version > 425 || (major_version == 425 && GetProducerVersionUpdate() >= 13)) + return true; + else + return false; + } + return true; // Assume all other compilers didn't have incorrect ObjC bitfield info +} + +bool +DWARFCompileUnit::Supports_DW_AT_APPLE_objc_complete_type () +{ + if (GetProducer() == eProducerLLVMGCC) + return false; + return true; +} + +bool +DWARFCompileUnit::DW_AT_decl_file_attributes_are_invalid() +{ + // llvm-gcc makes completely invalid decl file attributes and won't ever + // be fixed, so we need to know to ignore these. + return GetProducer() == eProducerLLVMGCC; +} + +void +DWARFCompileUnit::ParseProducerInfo () +{ + m_producer_version_major = UINT32_MAX; + m_producer_version_minor = UINT32_MAX; + m_producer_version_update = UINT32_MAX; + + const DWARFDebugInfoEntry *die = GetCompileUnitDIEOnly(); + if (die) + { + + const char *producer_cstr = die->GetAttributeValueAsString(m_dwarf2Data, this, DW_AT_producer, NULL); + if (producer_cstr) + { + RegularExpression llvm_gcc_regex("^4\\.[012]\\.[01] \\(Based on Apple Inc\\. build [0-9]+\\) \\(LLVM build [\\.0-9]+\\)$"); + if (llvm_gcc_regex.Execute (producer_cstr)) + { + m_producer = eProducerLLVMGCC; + } + else if (strstr(producer_cstr, "clang")) + { + static RegularExpression g_clang_version_regex("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)"); + RegularExpression::Match regex_match(3); + if (g_clang_version_regex.Execute (producer_cstr, ®ex_match)) + { + std::string str; + if (regex_match.GetMatchAtIndex (producer_cstr, 1, str)) + m_producer_version_major = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex (producer_cstr, 2, str)) + m_producer_version_minor = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex (producer_cstr, 3, str)) + m_producer_version_update = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10); + } + m_producer = eProducerClang; + } + else if (strstr(producer_cstr, "GNU")) + m_producer = eProducerGCC; + } + } + if (m_producer == eProducerInvalid) + m_producer = eProcucerOther; +} + +DWARFCompileUnit::Producer +DWARFCompileUnit::GetProducer () +{ + if (m_producer == eProducerInvalid) + ParseProducerInfo (); + return m_producer; +} + + +uint32_t +DWARFCompileUnit::GetProducerVersionMajor() +{ + if (m_producer_version_major == 0) + ParseProducerInfo (); + return m_producer_version_major; +} + +uint32_t +DWARFCompileUnit::GetProducerVersionMinor() +{ + if (m_producer_version_minor == 0) + ParseProducerInfo (); + return m_producer_version_minor; +} + +uint32_t +DWARFCompileUnit::GetProducerVersionUpdate() +{ + if (m_producer_version_update == 0) + ParseProducerInfo (); + return m_producer_version_update; +} + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h new file mode 100644 index 000000000000..9fee0a2d2236 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -0,0 +1,210 @@ +//===-- 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 SymbolFileDWARF_DWARFCompileUnit_h_ +#define SymbolFileDWARF_DWARFCompileUnit_h_ + +#include "DWARFDebugInfoEntry.h" +#include "SymbolFileDWARF.h" + +class NameToDIE; + +class DWARFCompileUnit +{ +public: + enum Producer + { + eProducerInvalid = 0, + eProducerClang, + eProducerGCC, + eProducerLLVMGCC, + eProcucerOther + }; + + DWARFCompileUnit(SymbolFileDWARF* dwarf2Data); + + bool Extract(const lldb_private::DataExtractor &debug_info, lldb::offset_t *offset_ptr); + dw_offset_t Extract(lldb::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 = UINT32_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 BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, + DWARFDebugAranges* debug_aranges, + bool clear_dies_if_already_not_parsed); + + void + SetBaseAddress(dw_addr_t base_addr) + { + m_base_addr = base_addr; + } + + 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 half of that since + // we are now stripping the NULL tags. + + // 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() / 24); + m_die_array.push_back(die); + } + + bool + HasDIEsParsed () const + { + return m_die_array.size() > 1; + } + + DWARFDebugInfoEntry* + GetDIEAtIndexUnchecked (uint32_t idx) + { + return &m_die_array[idx]; + } + + 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; + } + + bool + Supports_DW_AT_APPLE_objc_complete_type (); + + bool + DW_AT_decl_file_attributes_are_invalid(); + + bool + Supports_unnamed_objc_bitfields (); + +// void +// AddGlobalDIEByIndex (uint32_t die_idx); +// +// void +// AddGlobal (const DWARFDebugInfoEntry* die); +// + void + Index (const uint32_t cu_idx, + NameToDIE& func_basenames, + NameToDIE& func_fullnames, + NameToDIE& func_methods, + NameToDIE& func_selectors, + NameToDIE& objc_class_selectors, + NameToDIE& globals, + NameToDIE& types, + NameToDIE& namespaces); + + const DWARFDebugAranges & + GetFunctionAranges (); + + SymbolFileDWARF* + GetSymbolFileDWARF () const + { + return m_dwarf2Data; + } + + Producer + GetProducer (); + + uint32_t + GetProducerVersionMajor(); + + uint32_t + GetProducerVersionMinor(); + + uint32_t + GetProducerVersionUpdate(); + +protected: + SymbolFileDWARF* m_dwarf2Data; + const DWARFAbbreviationDeclarationSet *m_abbrevs; + void * m_user_data; + DWARFDebugInfoEntry::collection m_die_array; // The compile unit debug information entry item + std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs + dw_addr_t m_base_addr; + dw_offset_t m_offset; + uint32_t m_length; + uint16_t m_version; + uint8_t m_addr_size; + Producer m_producer; + uint32_t m_producer_version_major; + uint32_t m_producer_version_minor; + uint32_t m_producer_version_update; + + void + ParseProducerInfo (); +private: + DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit); +}; + +#endif // SymbolFileDWARF_DWARFCompileUnit_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp new file mode 100644 index 000000000000..1beb75d33642 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp @@ -0,0 +1,62 @@ +//===-- 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; +} + +void +DWARFDIECollection::Append (const DWARFDebugInfoEntry *die) +{ + m_dies.push_back (die); +} + +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/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h new file mode 100644 index 000000000000..173d0a5604d0 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h @@ -0,0 +1,51 @@ +//===-- 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 SymbolFileDWARF_DWARFDIECollection_h_ +#define SymbolFileDWARF_DWARFDIECollection_h_ + +#include "SymbolFileDWARF.h" +#include <vector> + +class DWARFDIECollection +{ +public: + DWARFDIECollection() : + m_dies() + { + } + ~DWARFDIECollection() + { + } + + void + Append (const DWARFDebugInfoEntry *die); + + 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/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp new file mode 100644 index 000000000000..47657d5089b2 --- /dev/null +++ b/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, lldb::offset_t *offset_ptr) +{ + const lldb::offset_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 = UINT32_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 == UINT32_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 representation 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) +{ + lldb::offset_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/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h new file mode 100644 index 000000000000..eba439928a2c --- /dev/null +++ b/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 SymbolFileDWARF_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, lldb::offset_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/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp new file mode 100644 index 000000000000..b1eb27299efb --- /dev/null +++ b/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, lldb::offset_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%*.*" PRIx64 " - 0x%*.*" PRIx64 ")\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/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h new file mode 100644 index 000000000000..19ec8d042e72 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h @@ -0,0 +1,76 @@ +//===-- 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 SymbolFileDWARF_DWARFDebugArangeSet_h_ +#define SymbolFileDWARF_DWARFDebugArangeSet_h_ + +#include "SymbolFileDWARF.h" +#include <vector> + +class SymbolFileDWARF; + +class DWARFDebugArangeSet +{ +public: + struct Header + { + 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. + }; + + struct Descriptor + { + dw_addr_t address; + dw_addr_t length; + dw_addr_t end_address() const { return address + length; } + }; + + + 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, lldb::offset_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; + size_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; + } + + const Descriptor & + GetDescriptorRef (uint32_t i) const + { + return m_arange_descriptors[i]; + } + + +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/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp new file mode 100644 index 000000000000..3b004c4b3890 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -0,0 +1,177 @@ +//===-- 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 <stdio.h> + +#include <algorithm> + +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/Timer.h" + +#include "LogChannelDWARF.h" +#include "SymbolFileDWARF.h" +#include "DWARFDebugInfo.h" +#include "DWARFCompileUnit.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Constructor +//---------------------------------------------------------------------- +DWARFDebugAranges::DWARFDebugAranges() : + m_aranges() +{ +} + +//---------------------------------------------------------------------- +// 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; +}; + + +//---------------------------------------------------------------------- +// Extract +//---------------------------------------------------------------------- +bool +DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data) +{ + if (debug_aranges_data.ValidOffset(0)) + { + lldb::offset_t offset = 0; + + DWARFDebugArangeSet set; + Range range; + while (set.Extract(debug_aranges_data, &offset)) + { + const uint32_t num_descriptors = set.NumDescriptors(); + if (num_descriptors > 0) + { + const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset(); + + for (uint32_t i=0; i<num_descriptors; ++i) + { + const DWARFDebugArangeSet::Descriptor &descriptor = set.GetDescriptorRef(i); + m_aranges.Append(RangeToDIE::Entry (descriptor.address, descriptor.length, cu_offset)); + } + } + set.Clear(); + } + } + return false; +} + +//---------------------------------------------------------------------- +// Generate +//---------------------------------------------------------------------- +bool +DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data) +{ + Clear(); + DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); + if (debug_info) + { + const bool clear_dies_if_already_not_parsed = true; + 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->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed); + } + } + return !IsEmpty(); +} + + +void +DWARFDebugAranges::Dump (Log *log) const +{ + if (log == NULL) + return; + + const size_t num_entries = m_aranges.GetSize(); + for (size_t i=0; i<num_entries; ++i) + { + const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i); + if (entry) + log->Printf ("0x%8.8x: [0x%" PRIx64 " - 0x%" PRIx64 ")", + entry->data, + entry->GetRangeBase(), + entry->GetRangeEnd()); + } +} + +void +DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) +{ + if (high_pc > low_pc) + m_aranges.Append(RangeToDIE::Entry (low_pc, high_pc - low_pc, offset)); +} + +void +DWARFDebugAranges::Sort (bool minimize) +{ + Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", + __PRETTY_FUNCTION__, this); + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + size_t orig_arange_size = 0; + if (log) + { + orig_arange_size = m_aranges.GetSize(); + log->Printf ("DWARFDebugAranges::Sort(minimize = %u) with %" PRIu64 " entries", minimize, (uint64_t)orig_arange_size); + } + + m_aranges.Sort(); + m_aranges.CombineConsecutiveEntriesWithEqualData(); + + if (log) + { + if (minimize) + { + const size_t new_arange_size = m_aranges.GetSize(); + const size_t delta = orig_arange_size - new_arange_size; + log->Printf ("DWARFDebugAranges::Sort() %" PRIu64 " entries after minimizing (%" PRIu64 " entries combined for %" PRIu64 " bytes saved)", + (uint64_t)new_arange_size, + (uint64_t)delta, + (uint64_t)delta * sizeof(Range)); + } + Dump (log); + } +} + +//---------------------------------------------------------------------- +// FindAddress +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugAranges::FindAddress(dw_addr_t address) const +{ + const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address); + if (entry) + return entry->data; + return DW_INVALID_OFFSET; +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h new file mode 100644 index 000000000000..88db929226ab --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -0,0 +1,94 @@ +//===-- 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 SymbolFileDWARF_DWARFDebugAranges_h_ +#define SymbolFileDWARF_DWARFDebugAranges_h_ + +#include "DWARFDebugArangeSet.h" +#include <list> + +#include "lldb/Core/RangeMap.h" + +class SymbolFileDWARF; + +class DWARFDebugAranges +{ +protected: + typedef lldb_private::RangeDataArray<dw_addr_t, uint32_t, dw_offset_t, 1> RangeToDIE; + +public: + typedef RangeToDIE::Entry Range; + typedef std::vector<RangeToDIE::Entry> RangeColl; + + DWARFDebugAranges(); + + void + Clear() + { + m_aranges.Clear(); + } + + bool + Extract(const lldb_private::DataExtractor &debug_aranges_data); + + bool + Generate(SymbolFileDWARF* dwarf2Data); + + // Use append range multiple times and then call sort + void + AppendRange (dw_offset_t cu_offset, + dw_addr_t low_pc, + dw_addr_t high_pc); + + void + Sort (bool minimize); + + const Range* + RangeAtIndex(uint32_t idx) const + { + return m_aranges.GetEntryAtIndex (idx); + } + + void + Dump (lldb_private::Log *log) const; + + dw_offset_t + FindAddress(dw_addr_t address) const; + + bool + IsEmpty() const + { + return m_aranges.IsEmpty(); + } + size_t + GetNumRanges() const + { + return m_aranges.GetSize(); + } + + dw_offset_t + OffsetAtIndex(uint32_t idx) const + { + const Range *range = m_aranges.GetEntryAtIndex (idx); + if (range) + return range->data; + return DW_INVALID_OFFSET; + } + + static void + Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s); + +protected: + + + RangeToDIE m_aranges; +}; + + +#endif // SymbolFileDWARF_DWARFDebugAranges_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp new file mode 100644 index 000000000000..4c76eed8166f --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -0,0 +1,797 @@ +//===-- 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 "lldb/Symbol/ObjectFile.h" + +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "DWARFCompileUnit.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFFormValue.h" +#include "LogChannelDWARF.h" + +using namespace lldb; +using namespace lldb_private; +using namespace std; + +//---------------------------------------------------------------------- +// Constructor +//---------------------------------------------------------------------- +DWARFDebugInfo::DWARFDebugInfo() : + m_dwarf2Data(NULL), + m_compile_units(), + m_cu_aranges_ap () +{ +} + +//---------------------------------------------------------------------- +// SetDwarfData +//---------------------------------------------------------------------- +void +DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data) +{ + m_dwarf2Data = dwarf2Data; + m_compile_units.clear(); +} + + +DWARFDebugAranges & +DWARFDebugInfo::GetCompileUnitAranges () +{ + if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) + { + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + + m_cu_aranges_ap.reset (new DWARFDebugAranges()); + const DataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data(); + if (debug_aranges_data.GetByteSize() > 0) + { + if (log) + log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges", + m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); + m_cu_aranges_ap->Extract (debug_aranges_data); + + } + else + { + if (log) + log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing", + m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); + const size_t num_compile_units = GetNumCompileUnits(); + const bool clear_dies_if_already_not_parsed = true; + for (size_t idx = 0; idx < num_compile_units; ++idx) + { + DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx); + if (cu) + cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed); + } + } + + const bool minimize = true; + m_cu_aranges_ap->Sort (minimize); + } + return *m_cu_aranges_ap.get(); +} + + +//---------------------------------------------------------------------- +// 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 + { + DWARFDebugAranges &cu_aranges = GetCompileUnitAranges (); + const dw_offset_t cu_offset = cu_aranges.FindAddress (address); + cu_sp = GetCompileUnit(cu_offset); + } + + 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) + { + lldb::offset_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(); + } + } + } +} + +size_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; +} + +bool +DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const +{ + // Not a verify efficient function, but it is handy for use in assertions + // to make sure that a compile unit comes from a debug information file. + CompileUnitColl::const_iterator end_pos = m_compile_units.end(); + CompileUnitColl::const_iterator pos; + + for (pos = m_compile_units.begin(); pos != end_pos; ++pos) + { + if (pos->get() == cu) + return true; + } + return false; +} + + +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 +} + +DWARFDebugInfoEntry* +DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle) +{ + assert (cu_handle); + DWARFDebugInfoEntry* die = NULL; + if (*cu_handle) + die = (*cu_handle)->GetDIEPtr(die_offset); + + if (die == NULL) + { + DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset)); + if (cu_sp.get()) + { + *cu_handle = cu_sp.get(); + die = cu_sp->GetDIEPtr(die_offset); + } + } + if (die == NULL) + *cu_handle = NULL; + return die; +} + + +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) + { + lldb::offset_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 function 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 function 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 proper + offset = next_cu_offset; + } + } +} + +typedef struct DumpInfo +{ + DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) : + strm(init_strm), + die_offset(off), + recurse_depth(depth), + found_depth(UINT32_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 +// whether 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().Test(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 == UINT32_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 != UINT32_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); + + const DWARFDebugInfoEntry* die = cu_sp->DIE(); + if (die) + 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/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h new file mode 100644 index 000000000000..50a7ae76921f --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -0,0 +1,89 @@ +//===-- 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 SymbolFileDWARF_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 std::shared_ptr<DWARFCompileUnit> 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 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); + size_t GetNumCompileUnits(); + bool ContainsCompileUnit (const DWARFCompileUnit *cu) const; + 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); + DWARFDebugInfoEntry* GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle); + + 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_ShowAncestors = (1<<2) // Show all parent DIEs when dumping single DIEs + }; + + DWARFDebugAranges & + GetCompileUnitAranges (); + +protected: + SymbolFileDWARF* m_dwarf2Data; + typedef std::vector<DWARFCompileUnitSP> CompileUnitColl; + CompileUnitColl m_compile_units; + std::unique_ptr<DWARFDebugAranges> m_cu_aranges_ap; // A quick address to compile unit table + +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/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp new file mode 100644 index 000000000000..03c12e366f92 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -0,0 +1,2317 @@ +//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugInfoEntry.h" + +#include <assert.h> + +#include <algorithm> + +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/ObjectFile.h" + +#include "DWARFCompileUnit.h" +#include "SymbolFileDWARF.h" +#include "DWARFDebugAbbrev.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "DWARFDeclContext.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "DWARFLocationDescription.h" +#include "DWARFLocationList.h" +#include "DWARFDebugRanges.h" + +using namespace lldb_private; +using namespace std; +extern int g_verbose; + + + +DWARFDebugInfoEntry::Attributes::Attributes() : + m_infos() +{ +} + +DWARFDebugInfoEntry::Attributes::~Attributes() +{ +} + + +uint32_t +DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const +{ + collection::const_iterator end = m_infos.end(); + collection::const_iterator beg = m_infos.begin(); + collection::const_iterator pos; + for (pos = beg; pos != end; ++pos) + { + if (pos->attr == attr) + return std::distance(beg, pos); + } + return UINT32_MAX; +} + +void +DWARFDebugInfoEntry::Attributes::Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form) +{ + Info info = { cu, attr_die_offset, attr, form }; + m_infos.push_back(info); +} + +bool +DWARFDebugInfoEntry::Attributes::ContainsAttribute(dw_attr_t attr) const +{ + return FindAttributeIndex(attr) != UINT32_MAX; +} + +bool +DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr) +{ + uint32_t attr_index = FindAttributeIndex(attr); + if (attr_index != UINT32_MAX) + { + m_infos.erase(m_infos.begin() + attr_index); + return true; + } + return false; +} + +bool +DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const +{ + form_value.SetForm(FormAtIndex(i)); + lldb::offset_t offset = DIEOffsetAtIndex(i); + return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i)); +} + +uint64_t +DWARFDebugInfoEntry::Attributes::FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const +{ + const uint32_t attr_idx = FindAttributeIndex (attr); + if (attr_idx != UINT32_MAX) + return FormValueAsUnsignedAtIndex (dwarf2Data, attr_idx, fail_value); + return fail_value; +} + +uint64_t +DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const +{ + DWARFFormValue form_value; + if (ExtractFormValueAtIndex(dwarf2Data, i, form_value)) + return form_value.Reference(CompileUnitAtIndex(i)); + return fail_value; +} + + + +bool +DWARFDebugInfoEntry::FastExtract +( + const DataExtractor& debug_info_data, + const DWARFCompileUnit* cu, + const uint8_t *fixed_form_sizes, + lldb::offset_t *offset_ptr +) +{ + m_offset = *offset_ptr; + m_parent_idx = 0; + m_sibling_idx = 0; + m_empty_children = false; + const uint64_t abbr_idx = debug_info_data.GetULEB128 (offset_ptr); + assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + m_abbr_idx = abbr_idx; + + //assert (fixed_form_sizes); // For best performance this should be specified! + + if (m_abbr_idx) + { + lldb::offset_t offset = *offset_ptr; + + const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(m_abbr_idx); + + if (abbrevDecl == NULL) + { + cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid abbreviation code %u, please file a bug and attach the file at the start of this error message", + m_offset, + (unsigned)abbr_idx); + // WE can't parse anymore if the DWARF is borked... + *offset_ptr = UINT32_MAX; + return false; + } + m_tag = abbrevDecl->Tag(); + m_has_children = abbrevDecl->HasChildren(); + // Skip all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + register uint32_t i; + register dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + form = abbrevDecl->GetFormByIndexUnchecked(i); + + const uint8_t fixed_skip_size = fixed_form_sizes [form]; + if (fixed_skip_size) + offset += fixed_skip_size; + else + { + bool form_is_indirect = false; + do + { + form_is_indirect = false; + register uint32_t form_size = 0; + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_exprloc : + case DW_FORM_block : form_size = debug_info_data.GetULEB128 (&offset); break; + case DW_FORM_block1 : form_size = debug_info_data.GetU8_unchecked (&offset); break; + case DW_FORM_block2 : form_size = debug_info_data.GetU16_unchecked (&offset);break; + case DW_FORM_block4 : form_size = debug_info_data.GetU32_unchecked (&offset);break; + + // Inlined NULL terminated C-strings + case DW_FORM_string : + debug_info_data.GetCStr (&offset); + break; + + // Compile unit address sized values + case DW_FORM_addr : + form_size = cu->GetAddressByteSize(); + break; + case DW_FORM_ref_addr : + if (cu->GetVersion() <= 2) + form_size = cu->GetAddressByteSize(); + else + form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + break; + + // 0 sized form + case DW_FORM_flag_present: + form_size = 0; + break; + + // 1 byte values + case DW_FORM_data1 : + case DW_FORM_flag : + case DW_FORM_ref1 : + form_size = 1; + break; + + // 2 byte values + case DW_FORM_data2 : + case DW_FORM_ref2 : + form_size = 2; + break; + + // 4 byte values + case DW_FORM_strp : + case DW_FORM_data4 : + case DW_FORM_ref4 : + form_size = 4; + break; + + // 8 byte values + case DW_FORM_data8 : + case DW_FORM_ref8 : + case DW_FORM_ref_sig8 : + form_size = 8; + break; + + // signed or unsigned LEB 128 values + case DW_FORM_sdata : + case DW_FORM_udata : + case DW_FORM_ref_udata : + debug_info_data.Skip_LEB128 (&offset); + break; + + case DW_FORM_indirect : + form_is_indirect = true; + form = debug_info_data.GetULEB128 (&offset); + break; + + case DW_FORM_sec_offset : + if (cu->GetAddressByteSize () == 4) + debug_info_data.GetU32 (offset_ptr); + else + debug_info_data.GetU64 (offset_ptr); + break; + + default: + *offset_ptr = m_offset; + return false; + } + offset += form_size; + + } while (form_is_indirect); + } + } + *offset_ptr = offset; + return true; + } + else + { + m_tag = 0; + m_has_children = false; + return true; // NULL debug tag entry + } + + return false; +} + +//---------------------------------------------------------------------- +// Extract +// +// Extract a debug info entry for a given compile unit from the +// .debug_info and .debug_abbrev data within the SymbolFileDWARF class +// starting at the given offset +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::Extract +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + lldb::offset_t *offset_ptr +) +{ + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); +// const DataExtractor& debug_str_data = dwarf2Data->get_debug_str_data(); + const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); + const uint8_t cu_addr_size = cu->GetAddressByteSize(); + lldb::offset_t offset = *offset_ptr; +// if (offset >= cu_end_offset) +// Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset); + if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset)) + { + m_offset = offset; + + const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset); + assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE)); + m_abbr_idx = abbr_idx; + if (abbr_idx) + { + const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbr_idx); + + if (abbrevDecl) + { + m_tag = abbrevDecl->Tag(); + m_has_children = abbrevDecl->HasChildren(); + + bool isCompileUnitTag = m_tag == DW_TAG_compile_unit; + if (cu && isCompileUnitTag) + ((DWARFCompileUnit*)cu)->SetBaseAddress(0); + + // Skip all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + + if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc))) + { + DWARFFormValue form_value(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) + ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned()); + } + } + else + { + bool form_is_indirect = false; + do + { + form_is_indirect = false; + register uint32_t form_size = 0; + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_exprloc : + case DW_FORM_block : form_size = debug_info_data.GetULEB128(&offset); break; + case DW_FORM_block1 : form_size = debug_info_data.GetU8(&offset); break; + case DW_FORM_block2 : form_size = debug_info_data.GetU16(&offset); break; + case DW_FORM_block4 : form_size = debug_info_data.GetU32(&offset); break; + + // Inlined NULL terminated C-strings + case DW_FORM_string : debug_info_data.GetCStr(&offset); break; + + // Compile unit address sized values + case DW_FORM_addr : + form_size = cu_addr_size; + break; + case DW_FORM_ref_addr : + if (cu->GetVersion() <= 2) + form_size = cu_addr_size; + else + form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet + break; + + // 0 sized form + case DW_FORM_flag_present: + form_size = 0; + break; + + // 1 byte values + case DW_FORM_data1 : + case DW_FORM_flag : + case DW_FORM_ref1 : + form_size = 1; + break; + + // 2 byte values + case DW_FORM_data2 : + case DW_FORM_ref2 : + form_size = 2; + break; + + // 4 byte values + case DW_FORM_strp : + form_size = 4; + break; + + case DW_FORM_data4 : + case DW_FORM_ref4 : + form_size = 4; + break; + + // 8 byte values + case DW_FORM_data8 : + case DW_FORM_ref8 : + case DW_FORM_ref_sig8 : + form_size = 8; + break; + + // signed or unsigned LEB 128 values + case DW_FORM_sdata : + case DW_FORM_udata : + case DW_FORM_ref_udata : + debug_info_data.Skip_LEB128(&offset); + break; + + case DW_FORM_indirect : + form = debug_info_data.GetULEB128(&offset); + form_is_indirect = true; + break; + + case DW_FORM_sec_offset : + if (cu->GetAddressByteSize () == 4) + debug_info_data.GetU32 (offset_ptr); + else + debug_info_data.GetU64 (offset_ptr); + break; + + default: + *offset_ptr = offset; + return false; + } + + offset += form_size; + } while (form_is_indirect); + } + } + *offset_ptr = offset; + return true; + } + } + else + { + m_tag = 0; + m_has_children = false; + *offset_ptr = offset; + return true; // NULL debug tag entry + } + } + + return false; +} + +//---------------------------------------------------------------------- +// DumpAncestry +// +// Dumps all of a debug information entries parents up until oldest and +// all of it's attributes to the specified stream. +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::DumpAncestry +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const DWARFDebugInfoEntry* oldest, + Stream &s, + uint32_t recurse_depth +) const +{ + const DWARFDebugInfoEntry* parent = GetParent(); + if (parent && parent != oldest) + parent->DumpAncestry(dwarf2Data, cu, oldest, s, 0); + Dump(dwarf2Data, cu, s, recurse_depth); +} + +//---------------------------------------------------------------------- +// Compare two DIE by comparing all their attributes values, and +// following all DW_FORM_ref attributes and comparing their contents as +// well (except for DW_AT_sibling attributes. +// +// DWARFDebugInfoEntry::CompareState compare_state; +// int result = DWARFDebugInfoEntry::Compare(this, 0x00017ccb, 0x0001eb2b, compare_state, false, true); +//---------------------------------------------------------------------- +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// dw_offset_t a_die_offset, +// dw_offset_t b_die_offset, +// CompareState &compare_state, +// bool compare_siblings, +// bool compare_children +//) +//{ +// if (a_die_offset == b_die_offset) +// return 0; +// +// DWARFCompileUnitSP a_cu_sp; +// DWARFCompileUnitSP b_cu_sp; +// const DWARFDebugInfoEntry* a_die = dwarf2Data->DebugInfo()->GetDIEPtr(a_die_offset, &a_cu_sp); +// const DWARFDebugInfoEntry* b_die = dwarf2Data->DebugInfo()->GetDIEPtr(b_die_offset, &b_cu_sp); +// +// return Compare(dwarf2Data, a_cu_sp.get(), a_die, b_cu_sp.get(), b_die, compare_state, compare_siblings, compare_children); +//} +// +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die, +// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die, +// CompareState &compare_state, +// bool compare_siblings, +// bool compare_children +//) +//{ +// if (a_die == b_die) +// return 0; +// +// if (!compare_state.AddTypePair(a_die->GetOffset(), b_die->GetOffset())) +// { +// // We are already comparing both of these types, so let +// // compares complete for the real result +// return 0; +// } +// +// //printf("DWARFDebugInfoEntry::Compare(0x%8.8x, 0x%8.8x)\n", a_die->GetOffset(), b_die->GetOffset()); +// +// // Do we have two valid DIEs? +// if (a_die && b_die) +// { +// // Both DIE are valid +// int result = 0; +// +// const dw_tag_t a_tag = a_die->Tag(); +// const dw_tag_t b_tag = b_die->Tag(); +// if (a_tag == 0 && b_tag == 0) +// return 0; +// +// //printf(" comparing tags: %s and %s\n", DW_TAG_value_to_name(a_tag), DW_TAG_value_to_name(b_tag)); +// +// if (a_tag < b_tag) +// return -1; +// else if (a_tag > b_tag) +// return 1; +// +// DWARFDebugInfoEntry::Attributes a_attrs; +// DWARFDebugInfoEntry::Attributes b_attrs; +// size_t a_attr_count = a_die->GetAttributes(dwarf2Data, a_cu, a_attrs); +// size_t b_attr_count = b_die->GetAttributes(dwarf2Data, b_cu, b_attrs); +// if (a_attr_count != b_attr_count) +// { +// a_attrs.RemoveAttribute(DW_AT_sibling); +// b_attrs.RemoveAttribute(DW_AT_sibling); +// } +// +// a_attr_count = a_attrs.Size(); +// b_attr_count = b_attrs.Size(); +// +// DWARFFormValue a_form_value; +// DWARFFormValue b_form_value; +// +// if (a_attr_count != b_attr_count) +// { +// uint32_t is_decl_index = a_attrs.FindAttributeIndex(DW_AT_declaration); +// uint32_t a_name_index = UINT32_MAX; +// uint32_t b_name_index = UINT32_MAX; +// if (is_decl_index != UINT32_MAX) +// { +// if (a_attr_count == 2) +// { +// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name); +// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name); +// } +// } +// else +// { +// is_decl_index = b_attrs.FindAttributeIndex(DW_AT_declaration); +// if (is_decl_index != UINT32_MAX && a_attr_count == 2) +// { +// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name); +// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name); +// } +// } +// if (a_name_index != UINT32_MAX && b_name_index != UINT32_MAX) +// { +// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, a_name_index, a_form_value) && +// b_attrs.ExtractFormValueAtIndex(dwarf2Data, b_name_index, b_form_value)) +// { +// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, &dwarf2Data->get_debug_str_data()); +// if (result == 0) +// { +// a_attr_count = b_attr_count = 0; +// compare_children = false; +// } +// } +// } +// } +// +// if (a_attr_count < b_attr_count) +// return -1; +// if (a_attr_count > b_attr_count) +// return 1; +// +// +// // The number of attributes are the same... +// if (a_attr_count > 0) +// { +// const DataExtractor* debug_str_data_ptr = &dwarf2Data->get_debug_str_data(); +// +// uint32_t i; +// for (i=0; i<a_attr_count; ++i) +// { +// const dw_attr_t a_attr = a_attrs.AttributeAtIndex(i); +// const dw_attr_t b_attr = b_attrs.AttributeAtIndex(i); +// //printf(" comparing attributes\n\t\t0x%8.8x: %s %s\t\t0x%8.8x: %s %s\n", +// // a_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(a_attrs.FormAtIndex(i)), DW_AT_value_to_name(a_attr), +// // b_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(b_attrs.FormAtIndex(i)), DW_AT_value_to_name(b_attr)); +// +// if (a_attr < b_attr) +// return -1; +// else if (a_attr > b_attr) +// return 1; +// +// switch (a_attr) +// { +// // Since we call a form of GetAttributes which inlines the +// // attributes from DW_AT_abstract_origin and DW_AT_specification +// // we don't care if their values mismatch... +// case DW_AT_abstract_origin: +// case DW_AT_specification: +// case DW_AT_sibling: +// case DW_AT_containing_type: +// //printf(" action = IGNORE\n"); +// result = 0; +// break; // ignore +// +// default: +// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, i, a_form_value) && +// b_attrs.ExtractFormValueAtIndex(dwarf2Data, i, b_form_value)) +// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, debug_str_data_ptr); +// break; +// } +// +// //printf("\t result = %i\n", result); +// +// if (result != 0) +// { +// // Attributes weren't equal, lets see if we care? +// switch (a_attr) +// { +// case DW_AT_decl_file: +// // TODO: add the ability to compare files in two different compile units +// if (a_cu == b_cu) +// { +// //printf(" action = RETURN RESULT\n"); +// return result; // Only return the compare results when the compile units are the same and the decl_file attributes can be compared +// } +// else +// { +// result = 0; +// //printf(" action = IGNORE\n"); +// } +// break; +// +// default: +// switch (a_attrs.FormAtIndex(i)) +// { +// case DW_FORM_ref1: +// case DW_FORM_ref2: +// case DW_FORM_ref4: +// case DW_FORM_ref8: +// case DW_FORM_ref_udata: +// case DW_FORM_ref_addr: +// //printf(" action = COMPARE DIEs 0x%8.8x 0x%8.8x\n", (dw_offset_t)a_form_value.Reference(a_cu), (dw_offset_t)b_form_value.Reference(b_cu)); +// // These attribute values refer to other DIEs, so lets compare those instead of their DIE offsets... +// result = Compare(dwarf2Data, a_form_value.Reference(a_cu), b_form_value.Reference(b_cu), compare_state, false, true); +// if (result != 0) +// return result; +// break; +// +// default: +// // We do care that they were different, return this result... +// //printf(" action = RETURN RESULT\n"); +// return result; +// } +// } +// } +// } +// } +// //printf(" SUCCESS\n\t\t0x%8.8x: %s\n\t\t0x%8.8x: %s\n", a_die->GetOffset(), DW_TAG_value_to_name(a_tag), b_die->GetOffset(), DW_TAG_value_to_name(b_tag)); +// +// if (compare_children) +// { +// bool a_has_children = a_die->HasChildren(); +// bool b_has_children = b_die->HasChildren(); +// if (a_has_children == b_has_children) +// { +// // Both either have kids or don't +// if (a_has_children) +// result = Compare( dwarf2Data, +// a_cu, a_die->GetFirstChild(), +// b_cu, b_die->GetFirstChild(), +// compare_state, true, compare_children); +// else +// result = 0; +// } +// else if (!a_has_children) +// result = -1; // A doesn't have kids, but B does +// else +// result = 1; // A has kids, but B doesn't +// } +// +// if (compare_siblings) +// { +// result = Compare( dwarf2Data, +// a_cu, a_die->GetSibling(), +// b_cu, b_die->GetSibling(), +// compare_state, true, compare_children); +// } +// +// return result; +// } +// +// if (a_die == NULL) +// return -1; // a_die is NULL, yet b_die is non-NULL +// else +// return 1; // a_die is non-NULL, yet b_die is NULL +// +//} +// +// +//int +//DWARFDebugInfoEntry::Compare +//( +// SymbolFileDWARF* dwarf2Data, +// const DWARFCompileUnit* cu_a, +// const DWARFDebugInfoEntry* die_a, +// const DWARFCompileUnit* cu_a, +// const DWARFDebugInfoEntry* die_b, +// CompareState &compare_state +//) +//{ +//} + +//---------------------------------------------------------------------- +// GetDIENamesAndRanges +// +// Gets the valid address ranges for a given DIE by looking for a +// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges +// attributes. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetDIENamesAndRanges +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const char * &name, + const char * &mangled, + DWARFDebugRanges::RangeList& ranges, + int& decl_file, + int& decl_line, + int& decl_column, + int& call_file, + int& call_line, + int& call_column, + DWARFExpression *frame_base +) const +{ + if (dwarf2Data == NULL) + return false; + + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + std::vector<dw_offset_t> die_offsets; + bool set_frame_base_loclist_addr = false; + + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + if (!debug_info_data.ValidOffset(offset)) + return false; + + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + bool do_offset = false; + + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + DWARFFormValue form_value(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + switch (attr) + { + case DW_AT_low_pc: + lo_pc = form_value.Unsigned(); + + if (do_offset) + hi_pc += lo_pc; + do_offset = false; + break; + + case DW_AT_entry_pc: + lo_pc = form_value.Unsigned(); + break; + + case DW_AT_high_pc: + hi_pc = form_value.Unsigned(); + if (form_value.Form() != DW_FORM_addr) + { + if (lo_pc == LLDB_INVALID_ADDRESS) + do_offset = hi_pc != LLDB_INVALID_ADDRESS; + else + hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save on relocations + } + break; + + case DW_AT_ranges: + { + const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); + debug_ranges->FindRanges(form_value.Unsigned(), ranges); + // All DW_AT_ranges are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + ranges.Slide(cu->GetBaseAddress()); + } + break; + + case DW_AT_name: + if (name == NULL) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + break; + + case DW_AT_MIPS_linkage_name: + case DW_AT_linkage_name: + if (mangled == NULL) + mangled = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + break; + + case DW_AT_abstract_origin: + die_offsets.push_back(form_value.Reference(cu)); + break; + + case DW_AT_specification: + die_offsets.push_back(form_value.Reference(cu)); + break; + + case DW_AT_decl_file: + if (decl_file == 0) + decl_file = form_value.Unsigned(); + break; + + case DW_AT_decl_line: + if (decl_line == 0) + decl_line = form_value.Unsigned(); + break; + + case DW_AT_decl_column: + if (decl_column == 0) + decl_column = form_value.Unsigned(); + break; + + case DW_AT_call_file: + if (call_file == 0) + call_file = form_value.Unsigned(); + break; + + case DW_AT_call_line: + if (call_line == 0) + call_line = form_value.Unsigned(); + break; + + case DW_AT_call_column: + if (call_column == 0) + call_column = form_value.Unsigned(); + break; + + case DW_AT_frame_base: + if (frame_base) + { + if (form_value.BlockData()) + { + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + frame_base->SetOpcodeData(debug_info_data, block_offset, block_length); + } + else + { + const DataExtractor &debug_loc_data = dwarf2Data->get_debug_loc_data(); + const dw_offset_t debug_loc_offset = form_value.Unsigned(); + + size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset); + if (loc_list_length > 0) + { + frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length); + if (lo_pc != LLDB_INVALID_ADDRESS) + { + assert (lo_pc >= cu->GetBaseAddress()); + frame_base->SetLocationListSlide(lo_pc - cu->GetBaseAddress()); + } + else + { + set_frame_base_loclist_addr = true; + } + } + } + } + break; + + default: + break; + } + } + } + } + + if (ranges.IsEmpty()) + { + if (lo_pc != LLDB_INVALID_ADDRESS) + { + if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc) + ranges.Append(DWARFDebugRanges::Range (lo_pc, hi_pc - lo_pc)); + else + ranges.Append(DWARFDebugRanges::Range (lo_pc, 0)); + } + } + + if (set_frame_base_loclist_addr) + { + dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); + assert (lowest_range_pc >= cu->GetBaseAddress()); + frame_base->SetLocationListSlide (lowest_range_pc - cu->GetBaseAddress()); + } + + if (ranges.IsEmpty() || name == NULL || mangled == NULL) + { + std::vector<dw_offset_t>::const_iterator pos; + std::vector<dw_offset_t>::const_iterator end = die_offsets.end(); + for (pos = die_offsets.begin(); pos != end; ++pos) + { + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = NULL; + dw_offset_t die_offset = *pos; + if (die_offset != DW_INVALID_OFFSET) + { + die = dwarf2Data->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr); + if (die) + die->GetDIENamesAndRanges(dwarf2Data, cu_sp_ptr.get(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column); + } + } + } + return !ranges.IsEmpty(); +} + +//---------------------------------------------------------------------- +// Dump +// +// Dumps a debug information entry and all of it's attributes to the +// specified stream. +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::Dump +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + Stream &s, + uint32_t recurse_depth +) const +{ + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + lldb::offset_t offset = m_offset; + + if (debug_info_data.ValidOffset(offset)) + { + dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset); + + s.Printf("\n0x%8.8x: ", m_offset); + s.Indent(); + if (abbrCode != m_abbr_idx) + { + s.Printf( "error: DWARF has been modified\n"); + } + else if (abbrCode) + { + const DWARFAbbreviationDeclaration* abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration (abbrCode); + + if (abbrevDecl) + { + s.PutCString(DW_TAG_value_to_name(abbrevDecl->Tag())); + s.Printf( " [%u] %c\n", abbrCode, abbrevDecl->HasChildren() ? '*':' '); + + // Dump all data in the .debug_info for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + for (i=0; i<numAttributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form); + + DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, form); + } + + const DWARFDebugInfoEntry* child = GetFirstChild(); + if (recurse_depth > 0 && child) + { + s.IndentMore(); + + while (child) + { + child->Dump(dwarf2Data, cu, s, recurse_depth-1); + child = child->GetSibling(); + } + s.IndentLess(); + } + } + else + s.Printf( "Abbreviation code note found in 'debug_abbrev' class for code: %u\n", abbrCode); + } + else + { + s.Printf( "NULL\n"); + } + } +} + +void +DWARFDebugInfoEntry::DumpLocation +( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + Stream &s +) const +{ + const DWARFDebugInfoEntry *cu_die = cu->GetCompileUnitDIEOnly(); + const char *cu_name = NULL; + if (cu_die != NULL) + cu_name = cu_die->GetName (dwarf2Data, cu); + const char *obj_file_name = NULL; + ObjectFile *obj_file = dwarf2Data->GetObjectFile(); + if (obj_file) + obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString(); + const char *die_name = GetName (dwarf2Data, cu); + s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)", + cu->GetOffset(), + GetOffset(), + die_name ? die_name : "", + cu_name ? cu_name : "<NULL>", + obj_file_name ? obj_file_name : "<NULL>"); +} + +//---------------------------------------------------------------------- +// DumpAttribute +// +// Dumps a debug information entry attribute along with it's form. Any +// special display of attributes is done (disassemble location lists, +// show enumeration values for attributes, etc). +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::DumpAttribute +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const DataExtractor& debug_info_data, + lldb::offset_t *offset_ptr, + Stream &s, + dw_attr_t attr, + dw_form_t form +) +{ + bool verbose = s.GetVerbose(); + bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); + + const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL; + if (verbose) + s.Offset (*offset_ptr); + else + s.Printf (" "); + s.Indent(DW_AT_value_to_name(attr)); + + if (show_form) + { + s.Printf( "[%s", DW_FORM_value_to_name(form)); + } + + DWARFFormValue form_value(form); + + if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu)) + return; + + if (show_form) + { + if (form == DW_FORM_indirect) + { + s.Printf( " [%s]", DW_FORM_value_to_name(form_value.Form())); + } + + s.PutCString("] "); + } + + s.PutCString("( "); + + // Always dump form value if verbose is enabled + if (verbose) + { + form_value.Dump(s, debug_str_data, cu); + } + + + // Check to see if we have any special attribute formatters + switch (attr) + { + case DW_AT_stmt_list: + if ( verbose ) s.PutCString(" ( "); + s.Printf( "0x%8.8" PRIx64, form_value.Unsigned()); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_language: + if ( verbose ) s.PutCString(" ( "); + s.PutCString(DW_LANG_value_to_name(form_value.Unsigned())); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_encoding: + if ( verbose ) s.PutCString(" ( "); + s.PutCString(DW_ATE_value_to_name(form_value.Unsigned())); + if ( verbose ) s.PutCString(" )"); + break; + + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_data_member_location: + { + const uint8_t* blockData = form_value.BlockData(); + if (blockData) + { + if (!verbose) + form_value.Dump(s, debug_str_data, cu); + + // Location description is inlined in data in the form value + DataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned()); + if ( verbose ) s.PutCString(" ( "); + print_dwarf_expression (s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false); + if ( verbose ) s.PutCString(" )"); + } + else + { + // We have a location list offset as the value that is + // the offset into the .debug_loc section that describes + // the value over it's lifetime + uint64_t debug_loc_offset = form_value.Unsigned(); + if (dwarf2Data) + { + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset); + } + else + { + if ( !verbose ) + form_value.Dump(s, NULL, cu); + } + } + } + break; + + case DW_AT_abstract_origin: + case DW_AT_specification: + { + uint64_t abstract_die_offset = form_value.Reference(cu); + form_value.Dump(s, debug_str_data, cu); + // *ostrm_ptr << HEX32 << abstract_die_offset << " ( "; + if ( verbose ) s.PutCString(" ( "); + GetName(dwarf2Data, cu, abstract_die_offset, s); + if ( verbose ) s.PutCString(" )"); + } + break; + + case DW_AT_type: + { + uint64_t type_die_offset = form_value.Reference(cu); + if (!verbose) + form_value.Dump(s, debug_str_data, cu); + s.PutCString(" ( "); + AppendTypeName(dwarf2Data, cu, type_die_offset, s); + s.PutCString(" )"); + } + break; + + case DW_AT_ranges: + { + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + lldb::offset_t ranges_offset = form_value.Unsigned(); + dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; + if (dwarf2Data) + DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), &ranges_offset, base_addr); + } + break; + + default: + if ( !verbose ) + form_value.Dump(s, debug_str_data, cu); + break; + } + + s.PutCString(" )\n"); +} + +//---------------------------------------------------------------------- +// Get all attribute values for a given DIE, including following any +// specification or abstract origin attributes and including those in +// the results. Any duplicate attributes will have the first instance +// take precedence (this can happen for declaration attributes). +//---------------------------------------------------------------------- +size_t +DWARFDebugInfoEntry::GetAttributes +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const uint8_t *fixed_form_sizes, + DWARFDebugInfoEntry::Attributes& attributes, + uint32_t curr_depth +) const +{ + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + if (fixed_form_sizes == NULL) + fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize()); + + const uint32_t num_attributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_attr_t attr; + dw_form_t form; + DWARFFormValue form_value; + for (i=0; i<num_attributes; ++i) + { + abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form); + + // If we are tracking down DW_AT_specification or DW_AT_abstract_origin + // attributes, the depth will be non-zero. We need to omit certain + // attributes that don't make sense. + switch (attr) + { + case DW_AT_sibling: + case DW_AT_declaration: + if (curr_depth > 0) + { + // This attribute doesn't make sense when combined with + // the DIE that references this DIE. We know a DIE is + // referencing this DIE because curr_depth is not zero + break; + } + // Fall through... + default: + attributes.Append(cu, offset, attr, form); + break; + } + + if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin)) + { + form_value.SetForm(form); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + const DWARFDebugInfoEntry* die = NULL; + dw_offset_t die_offset = form_value.Reference(cu); + if (cu->ContainsDIEOffset(die_offset)) + { + die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset); + if (die) + die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes, curr_depth + 1); + } + else + { + DWARFCompileUnitSP cu_sp_ptr; + die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr); + if (die) + die->GetAttributes(dwarf2Data, cu_sp_ptr.get(), fixed_form_sizes, attributes, curr_depth + 1); + } + } + } + else + { + const uint8_t fixed_skip_size = fixed_form_sizes [form]; + if (fixed_skip_size) + offset += fixed_skip_size; + else + DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu); + } + } + } + else + { + attributes.Clear(); + } + return attributes.Size(); + +} + +//---------------------------------------------------------------------- +// GetAttributeValue +// +// Get the value of an attribute and return the .debug_info offset of the +// attribute if it was properly extracted into form_value, or zero +// if we fail since an offset of zero is invalid for an attribute (it +// would be a compile unit header). +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugInfoEntry::GetAttributeValue +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DWARFFormValue& form_value, + dw_offset_t* end_attr_offset_ptr +) const +{ + lldb::offset_t offset; + const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl) + { + uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); + + if (attr_idx != DW_INVALID_INDEX) + { + const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data(); + + uint32_t idx=0; + while (idx<attr_idx) + DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu); + + const dw_offset_t attr_offset = offset; + form_value.SetForm(abbrevDecl->GetFormByIndex(idx)); + if (form_value.ExtractValue(debug_info_data, &offset, cu)) + { + if (end_attr_offset_ptr) + *end_attr_offset_ptr = offset; + return attr_offset; + } + } + } + + return 0; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsString +// +// Get the value of an attribute as a string return it. The resulting +// pointer to the string data exists within the supplied SymbolFileDWARF +// and will only be available as long as the SymbolFileDWARF is still around +// and it's content doesn't change. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetAttributeValueAsString +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + const char* fail_value) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.AsCString(&dwarf2Data->get_debug_str_data()); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsUnsigned +// +// Get the value of an attribute as unsigned and return it. +//---------------------------------------------------------------------- +uint64_t +DWARFDebugInfoEntry::GetAttributeValueAsUnsigned +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Unsigned(); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsSigned +// +// Get the value of an attribute a signed value and return it. +//---------------------------------------------------------------------- +int64_t +DWARFDebugInfoEntry::GetAttributeValueAsSigned +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + int64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Signed(); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeValueAsReference +// +// Get the value of an attribute as reference and fix up and compile +// unit relative offsets as needed. +//---------------------------------------------------------------------- +uint64_t +DWARFDebugInfoEntry::GetAttributeValueAsReference +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, attr, form_value)) + return form_value.Reference(cu); + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeHighPC +// +// Get the hi_pc, adding hi_pc to lo_pc when specified +// as an <offset-from-low-pc>. +// +// Returns the hi_pc or fail_value. +//---------------------------------------------------------------------- +dw_addr_t +DWARFDebugInfoEntry::GetAttributeHighPC +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t lo_pc, + uint64_t fail_value +) const +{ + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value)) + { + dw_addr_t hi_pc = form_value.Unsigned(); + if (form_value.Form() != DW_FORM_addr) + hi_pc += lo_pc; // DWARF4 can specify the hi_pc as an <offset-from-lowpc> + return hi_pc; + } + return fail_value; +} + +//---------------------------------------------------------------------- +// GetAttributeAddressRange +// +// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified +// as an <offset-from-low-pc>. +// +// Returns true or sets lo_pc and hi_pc to fail_value. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetAttributeAddressRange +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t& lo_pc, + dw_addr_t& hi_pc, + uint64_t fail_value +) const +{ + lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, fail_value); + if (lo_pc != fail_value) + { + hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, fail_value); + if (hi_pc != fail_value) + return true; + } + lo_pc = fail_value; + hi_pc = fail_value; + return false; +} +//---------------------------------------------------------------------- +// GetAttributeValueAsLocation +// +// Get the value of an attribute as reference and fix up and compile +// unit relative offsets as needed. +//---------------------------------------------------------------------- +dw_offset_t +DWARFDebugInfoEntry::GetAttributeValueAsLocation +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DataExtractor& location_data, + uint32_t &block_size +) const +{ + block_size = 0; + DWARFFormValue form_value; + + // Empty out data in case we don't find anything + location_data.Clear(); + dw_offset_t end_addr_offset = DW_INVALID_OFFSET; + const dw_offset_t attr_offset = GetAttributeValue(dwarf2Data, cu, attr, form_value, &end_addr_offset); + if (attr_offset) + { + const uint8_t* blockData = form_value.BlockData(); + if (blockData) + { + // We have an inlined location list in the .debug_info section + const DataExtractor& debug_info = dwarf2Data->get_debug_info_data(); + dw_offset_t block_offset = blockData - debug_info.GetDataStart(); + block_size = (end_addr_offset - attr_offset) - form_value.Unsigned(); + location_data.SetData(debug_info, block_offset, block_size); + } + else + { + // We have a location list offset as the value that is + // the offset into the .debug_loc section that describes + // the value over it's lifetime + lldb::offset_t debug_loc_offset = form_value.Unsigned(); + if (dwarf2Data) + { + assert(dwarf2Data->get_debug_loc_data().GetAddressByteSize() == cu->GetAddressByteSize()); + return DWARFLocationList::Extract(dwarf2Data->get_debug_loc_data(), &debug_loc_offset, location_data); + } + } + } + return attr_offset; +} + +//---------------------------------------------------------------------- +// GetName +// +// Get value of the DW_AT_name attribute and return it if one exists, +// else return NULL. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu +) const +{ + DWARFFormValue form_value; + if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + return form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else + { + if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) + { + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + if (die) + return die->GetName(dwarf2Data, cu_sp_ptr.get()); + } + } + return NULL; +} + + +//---------------------------------------------------------------------- +// GetMangledName +// +// Get value of the DW_AT_MIPS_linkage_name attribute and return it if +// one exists, else return the value of the DW_AT_name attribute +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetMangledName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + bool substitute_name_allowed +) const +{ + const char* name = NULL; + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + + if (substitute_name_allowed && name == NULL) + { + if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + } + return name; +} + + +//---------------------------------------------------------------------- +// GetPubname +// +// Get value the name for a DIE as it should appear for a +// .debug_pubnames or .debug_pubtypes section. +//---------------------------------------------------------------------- +const char* +DWARFDebugInfoEntry::GetPubname +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu +) const +{ + const char* name = NULL; + if (!dwarf2Data) + return name; + + DWARFFormValue form_value; + + if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) + { + // The specification DIE may be in another compile unit so we need + // to get a die and its compile unit. + DWARFCompileUnitSP cu_sp_ptr; + const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr); + if (die) + return die->GetPubname(dwarf2Data, cu_sp_ptr.get()); + } + return name; +} + + +//---------------------------------------------------------------------- +// GetName +// +// Get value of the DW_AT_name attribute for a debug information entry +// that exists at offset "die_offset" and place that value into the +// supplied stream object. If the DIE is a NULL object "NULL" is placed +// into the stream, and if no DW_AT_name attribute exists for the DIE +// then nothing is printed. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::GetName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + Stream &s +) +{ + if (dwarf2Data == NULL) + { + s.PutCString("NULL"); + return false; + } + + DWARFDebugInfoEntry die; + lldb::offset_t offset = die_offset; + if (die.Extract(dwarf2Data, cu, &offset)) + { + if (die.IsNULL()) + { + s.PutCString("NULL"); + return true; + } + else + { + DWARFFormValue form_value; + if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + { + const char* name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + if (name) + { + s.PutCString(name); + return true; + } + } + } + } + return false; +} + +//---------------------------------------------------------------------- +// AppendTypeName +// +// Follows the type name definition down through all needed tags to +// end up with a fully qualified type name and dump the results to +// the supplied stream. This is used to show the name of types given +// a type identifier. +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::AppendTypeName +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_offset_t die_offset, + Stream &s +) +{ + if (dwarf2Data == NULL) + { + s.PutCString("NULL"); + return false; + } + + DWARFDebugInfoEntry die; + lldb::offset_t offset = die_offset; + if (die.Extract(dwarf2Data, cu, &offset)) + { + if (die.IsNULL()) + { + s.PutCString("NULL"); + return true; + } + else + { + const char* name = die.GetPubname(dwarf2Data, cu); + // if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value)) + // name = form_value.AsCString(&dwarf2Data->get_debug_str_data()); + if (name) + s.PutCString(name); + else + { + bool result = true; + const DWARFAbbreviationDeclaration* abbrevDecl = die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset); + + if (abbrevDecl == NULL) + return false; + + switch (abbrevDecl->Tag()) + { + case DW_TAG_array_type: break; // print out a "[]" after printing the full type of the element below + case DW_TAG_base_type: s.PutCString("base "); break; + case DW_TAG_class_type: s.PutCString("class "); break; + case DW_TAG_const_type: s.PutCString("const "); break; + case DW_TAG_enumeration_type: s.PutCString("enum "); break; + case DW_TAG_file_type: s.PutCString("file "); break; + case DW_TAG_interface_type: s.PutCString("interface "); break; + case DW_TAG_packed_type: s.PutCString("packed "); break; + case DW_TAG_pointer_type: break; // print out a '*' after printing the full type below + case DW_TAG_ptr_to_member_type: break; // print out a '*' after printing the full type below + case DW_TAG_reference_type: break; // print out a '&' after printing the full type below + case DW_TAG_restrict_type: s.PutCString("restrict "); break; + case DW_TAG_set_type: s.PutCString("set "); break; + case DW_TAG_shared_type: s.PutCString("shared "); break; + case DW_TAG_string_type: s.PutCString("string "); break; + case DW_TAG_structure_type: s.PutCString("struct "); break; + case DW_TAG_subrange_type: s.PutCString("subrange "); break; + case DW_TAG_subroutine_type: s.PutCString("function "); break; + case DW_TAG_thrown_type: s.PutCString("thrown "); break; + case DW_TAG_union_type: s.PutCString("union "); break; + case DW_TAG_unspecified_type: s.PutCString("unspecified "); break; + case DW_TAG_volatile_type: s.PutCString("volatile "); break; + default: + return false; + } + + // Follow the DW_AT_type if possible + DWARFFormValue form_value; + if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value)) + { + uint64_t next_die_offset = form_value.Reference(cu); + result = AppendTypeName(dwarf2Data, cu, next_die_offset, s); + } + + switch (abbrevDecl->Tag()) + { + case DW_TAG_array_type: s.PutCString("[]"); break; + case DW_TAG_pointer_type: s.PutChar('*'); break; + case DW_TAG_ptr_to_member_type: s.PutChar('*'); break; + case DW_TAG_reference_type: s.PutChar('&'); break; + default: + break; + } + return result; + } + } + } + return false; +} + +bool +DWARFDebugInfoEntry::Contains (const DWARFDebugInfoEntry *die) const +{ + if (die) + { + const dw_offset_t die_offset = die->GetOffset(); + if (die_offset > GetOffset()) + { + const DWARFDebugInfoEntry *sibling = GetSibling(); + assert (sibling); // TODO: take this out + if (sibling) + return die_offset < sibling->GetOffset(); + } + } + return false; +} + +//---------------------------------------------------------------------- +// BuildAddressRangeTable +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::BuildAddressRangeTable +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges +) const +{ + if (m_tag) + { + if (m_tag == DW_TAG_subprogram) + { + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) + { + /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc); + debug_aranges->AppendRange (cu->GetOffset(), lo_pc, hi_pc); + } + } + + + const DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + child->BuildAddressRangeTable(dwarf2Data, cu, debug_aranges); + child = child->GetSibling(); + } + } +} + +//---------------------------------------------------------------------- +// BuildFunctionAddressRangeTable +// +// This function is very similar to the BuildAddressRangeTable function +// except that the actual DIE offset for the function is placed in the +// table instead of the compile unit offset (which is the way the +// standard .debug_aranges section does it). +//---------------------------------------------------------------------- +void +DWARFDebugInfoEntry::BuildFunctionAddressRangeTable +( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges +) const +{ + if (m_tag) + { + if (m_tag == DW_TAG_subprogram) + { + dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; + dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) + { + // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY + debug_aranges->AppendRange (GetOffset(), lo_pc, hi_pc); + } + } + + const DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges); + child = child->GetSibling(); + } + } +} + +void +DWARFDebugInfoEntry::GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDIECollection &decl_context_dies) const +{ + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + if (parent_decl_ctx_die && parent_decl_ctx_die != this) + { + decl_context_dies.Append(parent_decl_ctx_die); + parent_decl_ctx_die->GetDeclContextDIEs (dwarf2Data, cu, decl_context_dies); + } +} + +void +DWARFDebugInfoEntry::GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDeclContext &dwarf_decl_ctx) const +{ + const dw_tag_t tag = Tag(); + if (tag != DW_TAG_compile_unit) + { + dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu)); + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + if (parent_decl_ctx_die && parent_decl_ctx_die != this) + { + if (parent_decl_ctx_die->Tag() != DW_TAG_compile_unit) + parent_decl_ctx_die->GetDWARFDeclContext (dwarf2Data, cu, dwarf_decl_ctx); + } + } +} + + +bool +DWARFDebugInfoEntry::MatchesDWARFDeclContext (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDeclContext &dwarf_decl_ctx) const +{ + + DWARFDeclContext this_dwarf_decl_ctx; + GetDWARFDeclContext (dwarf2Data, cu, this_dwarf_decl_ctx); + return this_dwarf_decl_ctx == dwarf_decl_ctx; +} + +const DWARFDebugInfoEntry * +DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu) const +{ + DWARFDebugInfoEntry::Attributes attributes; + GetAttributes(dwarf2Data, cu, NULL, attributes); + return GetParentDeclContextDIE (dwarf2Data, cu, attributes); +} + +const DWARFDebugInfoEntry * +DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes) const +{ + const DWARFDebugInfoEntry * die = this; + + while (die != NULL) + { + // If this is the original DIE that we are searching for a declaration + // for, then don't look in the cache as we don't want our own decl + // context to be our decl context... + if (die != this) + { + switch (die->Tag()) + { + case DW_TAG_compile_unit: + case DW_TAG_namespace: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + return die; + + default: + break; + } + } + + dw_offset_t die_offset; + + die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_specification, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + const DWARFDebugInfoEntry *spec_die = cu->GetDIEPtr (die_offset); + if (spec_die) + { + const DWARFDebugInfoEntry *spec_die_decl_ctx_die = spec_die->GetParentDeclContextDIE (dwarf2Data, cu); + if (spec_die_decl_ctx_die) + return spec_die_decl_ctx_die; + } + } + + die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_abstract_origin, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + const DWARFDebugInfoEntry *abs_die = cu->GetDIEPtr (die_offset); + if (abs_die) + { + const DWARFDebugInfoEntry *abs_die_decl_ctx_die = abs_die->GetParentDeclContextDIE (dwarf2Data, cu); + if (abs_die_decl_ctx_die) + return abs_die_decl_ctx_die; + } + } + + die = die->GetParent(); + } + return NULL; +} + + +const char * +DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + std::string &storage) const +{ + DWARFDebugInfoEntry::Attributes attributes; + GetAttributes(dwarf2Data, cu, NULL, attributes); + return GetQualifiedName (dwarf2Data, cu, attributes, storage); +} + +const char* +DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes, + std::string &storage) const +{ + + const char *name = GetName (dwarf2Data, cu); + + if (name) + { + const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu); + storage.clear(); + // TODO: change this to get the correct decl context parent.... + while (parent_decl_ctx_die) + { + const dw_tag_t parent_tag = parent_decl_ctx_die->Tag(); + switch (parent_tag) + { + case DW_TAG_namespace: + { + const char *namespace_name = parent_decl_ctx_die->GetName (dwarf2Data, cu); + if (namespace_name) + { + storage.insert (0, "::"); + storage.insert (0, namespace_name); + } + else + { + storage.insert (0, "(anonymous namespace)::"); + } + parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu); + } + break; + + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + { + const char *class_union_struct_name = parent_decl_ctx_die->GetName (dwarf2Data, cu); + + if (class_union_struct_name) + { + storage.insert (0, "::"); + storage.insert (0, class_union_struct_name); + } + parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu); + } + break; + + default: + parent_decl_ctx_die = NULL; + break; + } + } + + if (storage.empty()) + storage.append ("::"); + + storage.append (name); + } + if (storage.empty()) + return NULL; + return storage.c_str(); +} + + +//---------------------------------------------------------------------- +// LookupAddress +//---------------------------------------------------------------------- +bool +DWARFDebugInfoEntry::LookupAddress +( + const dw_addr_t address, + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugInfoEntry** function_die, + DWARFDebugInfoEntry** block_die +) +{ + bool found_address = false; + if (m_tag) + { + bool check_children = false; + bool match_addr_range = false; + // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address); + switch (m_tag) + { + case DW_TAG_array_type : break; + case DW_TAG_class_type : check_children = true; break; + case DW_TAG_entry_point : break; + case DW_TAG_enumeration_type : break; + case DW_TAG_formal_parameter : break; + case DW_TAG_imported_declaration : break; + case DW_TAG_label : break; + case DW_TAG_lexical_block : check_children = true; match_addr_range = true; break; + case DW_TAG_member : break; + case DW_TAG_pointer_type : break; + case DW_TAG_reference_type : break; + case DW_TAG_compile_unit : match_addr_range = true; break; + case DW_TAG_string_type : break; + case DW_TAG_structure_type : check_children = true; break; + case DW_TAG_subroutine_type : break; + case DW_TAG_typedef : break; + case DW_TAG_union_type : break; + case DW_TAG_unspecified_parameters : break; + case DW_TAG_variant : break; + case DW_TAG_common_block : check_children = true; break; + case DW_TAG_common_inclusion : break; + case DW_TAG_inheritance : break; + case DW_TAG_inlined_subroutine : check_children = true; match_addr_range = true; break; + case DW_TAG_module : match_addr_range = true; break; + case DW_TAG_ptr_to_member_type : break; + case DW_TAG_set_type : break; + case DW_TAG_subrange_type : break; + case DW_TAG_with_stmt : break; + case DW_TAG_access_declaration : break; + case DW_TAG_base_type : break; + case DW_TAG_catch_block : match_addr_range = true; break; + case DW_TAG_const_type : break; + case DW_TAG_constant : break; + case DW_TAG_enumerator : break; + case DW_TAG_file_type : break; + case DW_TAG_friend : break; + case DW_TAG_namelist : break; + case DW_TAG_namelist_item : break; + case DW_TAG_packed_type : break; + case DW_TAG_subprogram : match_addr_range = true; break; + case DW_TAG_template_type_parameter : break; + case DW_TAG_template_value_parameter : break; + case DW_TAG_thrown_type : break; + case DW_TAG_try_block : match_addr_range = true; break; + case DW_TAG_variant_part : break; + case DW_TAG_variable : break; + case DW_TAG_volatile_type : break; + case DW_TAG_dwarf_procedure : break; + case DW_TAG_restrict_type : break; + case DW_TAG_interface_type : break; + case DW_TAG_namespace : check_children = true; break; + case DW_TAG_imported_module : break; + case DW_TAG_unspecified_type : break; + case DW_TAG_partial_unit : break; + case DW_TAG_imported_unit : break; + case DW_TAG_shared_type : break; + default: break; + } + + if (match_addr_range) + { + dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (lo_pc != LLDB_INVALID_ADDRESS) + { + dw_addr_t hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, LLDB_INVALID_ADDRESS); + if (hi_pc != LLDB_INVALID_ADDRESS) + { + // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc); + if ((lo_pc <= address) && (address < hi_pc)) + { + found_address = true; + // puts("***MATCH***"); + switch (m_tag) + { + case DW_TAG_compile_unit: // File + check_children = ((function_die != NULL) || (block_die != NULL)); + break; + + case DW_TAG_subprogram: // Function + if (function_die) + *function_die = this; + check_children = (block_die != NULL); + break; + + case DW_TAG_inlined_subroutine: // Inlined Function + case DW_TAG_lexical_block: // Block { } in code + if (block_die) + { + *block_die = this; + check_children = true; + } + break; + + default: + check_children = true; + break; + } + } + } + else + { // compile units may not have a valid high/low pc when there + // are address gaps in subroutines so we must always search + // if there is no valid high and low PC + check_children = (m_tag == DW_TAG_compile_unit) && ((function_die != NULL) || (block_die != NULL)); + } + } + else + { + dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET); + if (debug_ranges_offset != DW_INVALID_OFFSET) + { + DWARFDebugRanges::RangeList ranges; + DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); + debug_ranges->FindRanges(debug_ranges_offset, ranges); + // All DW_AT_ranges are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + ranges.Slide (cu->GetBaseAddress()); + if (ranges.FindEntryThatContains(address)) + { + found_address = true; + // puts("***MATCH***"); + switch (m_tag) + { + case DW_TAG_compile_unit: // File + check_children = ((function_die != NULL) || (block_die != NULL)); + break; + + case DW_TAG_subprogram: // Function + if (function_die) + *function_die = this; + check_children = (block_die != NULL); + break; + + case DW_TAG_inlined_subroutine: // Inlined Function + case DW_TAG_lexical_block: // Block { } in code + if (block_die) + { + *block_die = this; + check_children = true; + } + break; + + default: + check_children = true; + break; + } + } + else + { + check_children = false; + } + } + } + } + + + if (check_children) + { + // printf("checking children\n"); + DWARFDebugInfoEntry* child = GetFirstChild(); + while (child) + { + if (child->LookupAddress(address, dwarf2Data, cu, function_die, block_die)) + return true; + child = child->GetSibling(); + } + } + } + return found_address; +} + +const DWARFAbbreviationDeclaration* +DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit *cu, + lldb::offset_t &offset) const +{ + if (dwarf2Data) + { + offset = GetOffset(); + + const DWARFAbbreviationDeclaration* abbrev_decl = cu->GetAbbreviations()->GetAbbreviationDeclaration (m_abbr_idx); + if (abbrev_decl) + { + // Make sure the abbreviation code still matches. If it doesn't and + // the DWARF data was mmap'ed, the backing file might have been modified + // which is bad news. + const uint64_t abbrev_code = dwarf2Data->get_debug_info_data().GetULEB128 (&offset); + + if (abbrev_decl->Code() == abbrev_code) + return abbrev_decl; + + dwarf2Data->GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("0x%8.8x: the DWARF debug information has been modified (abbrev code was %u, and is now %u)", + GetOffset(), + (uint32_t)abbrev_decl->Code(), + (uint32_t)abbrev_code); + } + } + offset = DW_INVALID_OFFSET; + return NULL; +} + + +bool +DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b) +{ + return a.GetOffset() < b.GetOffset(); +} + +void +DWARFDebugInfoEntry::DumpDIECollection (Stream &strm, DWARFDebugInfoEntry::collection &die_collection) +{ + DWARFDebugInfoEntry::const_iterator pos; + DWARFDebugInfoEntry::const_iterator end = die_collection.end(); + strm.PutCString("\noffset parent sibling child\n"); + strm.PutCString("-------- -------- -------- --------\n"); + for (pos = die_collection.begin(); pos != end; ++pos) + { + const DWARFDebugInfoEntry& die_ref = *pos; + const DWARFDebugInfoEntry* p = die_ref.GetParent(); + const DWARFDebugInfoEntry* s = die_ref.GetSibling(); + const DWARFDebugInfoEntry* c = die_ref.GetFirstChild(); + strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n", + die_ref.GetOffset(), + p ? p->GetOffset() : 0, + s ? s->GetOffset() : 0, + c ? c->GetOffset() : 0, + die_ref.Tag(), + DW_TAG_value_to_name(die_ref.Tag()), + die_ref.HasChildren() ? " *" : ""); + } +} + + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h new file mode 100644 index 000000000000..85f4109ae01a --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -0,0 +1,457 @@ +//===-- 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 SymbolFileDWARF_DWARFDebugInfoEntry_h_ +#define SymbolFileDWARF_DWARFDebugInfoEntry_h_ + +#include "SymbolFileDWARF.h" +#include "llvm/ADT/SmallVector.h" + +#include "DWARFDebugAbbrev.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 DWARFDeclContext; + +#define DIE_SIBLING_IDX_BITSIZE 31 +#define DIE_ABBR_IDX_BITSIZE 15 + +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; + uint64_t FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, 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(); } + size_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; + }; + + typedef llvm::SmallVector<Info, 32> collection; + collection 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_empty_children(false), + m_abbr_idx (0), + m_has_children (false), + m_tag (0) + { + } + + void Clear () + { + m_offset = DW_INVALID_OFFSET; + m_parent_idx = 0; + m_sibling_idx = 0; + m_empty_children = false; + m_abbr_idx = 0; + m_has_children = false; + m_tag = 0; + } + + bool Contains (const DWARFDebugInfoEntry *die) const; + + void BuildAddressRangeTable( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges) const; + + void BuildFunctionAddressRangeTable( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + DWARFDebugAranges* debug_aranges) const; + + bool FastExtract( + const lldb_private::DataExtractor& debug_info_data, + const DWARFCompileUnit* cu, + const uint8_t *fixed_form_sizes, + lldb::offset_t* offset_ptr); + + bool Extract( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + lldb::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, + const uint8_t *fixed_form_sizes, + DWARFDebugInfoEntry::Attributes& attrs, + uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!! + + 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_addr_t GetAttributeHighPC( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t lo_pc, + uint64_t fail_value) const; + + bool GetAttributeAddressRange( + SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + dw_addr_t& lo_pc, + dw_addr_t& hi_pc, + uint64_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); + + const char * GetQualifiedName ( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + std::string &storage) const; + + const char * GetQualifiedName ( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes, + std::string &storage) const; + +// 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); + + 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, + lldb::offset_t *offset_ptr, + lldb_private::Stream &s, + dw_attr_t attr, + dw_form_t form); + // This one dumps the comp unit name, objfile name and die offset for this die so the stream S. + void DumpLocation( + SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + lldb_private::Stream &s) const; + + 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; + + const DWARFAbbreviationDeclaration* + GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit *cu, + lldb::offset_t &offset) const; + + dw_tag_t + Tag () const + { + return m_tag; + } + + bool + IsNULL() const + { + return m_abbr_idx == 0; + } + + dw_offset_t + GetOffset () const + { + return m_offset; + } + + void + SetOffset (dw_offset_t offset) + { + m_offset = offset; + } + + bool + HasChildren () const + { + return m_has_children; + } + + void + SetHasChildren (bool b) + { + m_has_children = b; + } + + // 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() && !m_empty_children) ? this + 1 : NULL; } + const DWARFDebugInfoEntry* GetFirstChild() const { return (HasChildren() && !m_empty_children) ? this + 1 : NULL; } + + + void GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDIECollection &decl_context_dies) const; + + void GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + DWARFDeclContext &dwarf_decl_ctx) const; + + + bool MatchesDWARFDeclContext(SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDeclContext &dwarf_decl_ctx) const; + + const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu) const; + const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry::Attributes& attributes) const; + + 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; + } + + void + SetSiblingIndex (uint32_t idx) + { + m_sibling_idx = idx; + } + + void + SetParentIndex (uint32_t idx) + { + m_parent_idx = idx; + } + + bool + GetEmptyChildren () const + { + return m_empty_children; + } + + void + SetEmptyChildren (bool b) + { + m_empty_children = b; + } + + static void + DumpDIECollection (lldb_private::Stream &strm, + DWARFDebugInfoEntry::collection &die_collection); + +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:31, // How many to add to "this" to get the sibling. + m_empty_children:1; // If a DIE says it had children, yet it just contained a NULL tag, this will be set. + uint32_t m_abbr_idx:DIE_ABBR_IDX_BITSIZE, + m_has_children:1, // Set to 1 if this DIE has children + m_tag:16; // A copy of the DW_TAG value so we don't have to go through the compile unit abbrev table + +}; + +#endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp new file mode 100644 index 000000000000..6c9336a08426 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -0,0 +1,1436 @@ +//===-- 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/Module.h" +#include "lldb/Core/Timer.h" +#include "lldb/Host/Host.h" + +#include "SymbolFileDWARF.h" +#include "LogChannelDWARF.h" + +using namespace lldb; +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(); + lldb::offset_t offset = 0; + LineTable::shared_ptr line_table_sp(new LineTable); + while (debug_line_data.ValidOffset(offset)) + { + const lldb::offset_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.16" PRIx64 " %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)) + { + lldb::offset_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) +{ + lldb::offset_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.8" PRIx64 ": 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%" PRIx64 ")", 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%x)", 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.8" PRIx64 ")", 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%" PRIx64 ", 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) +{ + lldb::offset_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, lldb::offset_t* offset_ptr, Prologue* prologue) +{ + const lldb::offset_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 lldb::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; + } + + if (*offset_ptr != end_prologue_offset) + { + Host::SystemLog (Host::eSystemLogWarning, + "warning: parsing line table prologue at 0x%8.8" PRIx64 " should have ended at 0x%8.8" PRIx64 " but it ended ad 0x%8.8" PRIx64 "\n", + prologue_offset, + end_prologue_offset, + *offset_ptr); + } + return end_prologue_offset; +} + +bool +DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp, + const DataExtractor& debug_line_data, + const char *cu_comp_dir, + dw_offset_t stmt_list, + FileSpecList &support_files) +{ + lldb::offset_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; + std::string remapped_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. + if (module_sp->RemapSourceFile (path, fullpath)) + support_files.Append(FileSpec (fullpath.c_str(), false)); + else + support_files.Append(FileSpec (path, false)); + } + 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; + if (module_sp->RemapSourceFile (fullpath.c_str(), remapped_fullpath)) + support_files.Append(FileSpec (remapped_fullpath.c_str(), false)); + else + support_files.Append(FileSpec (fullpath.c_str(), false)); + } + + } + } + + if (offset != end_prologue_offset) + { + Host::SystemLog (Host::eSystemLogError, + "warning: parsing line table prologue at 0x%8.8x should have ended at 0x%8.8x but it ended ad 0x%8.8" PRIx64 "\n", + stmt_list, + end_prologue_offset, + 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, + lldb::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); + + 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 + lldb::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) * minimum_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, lldb::offset_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 = UINT32_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 = UINT32_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.16" PRIx64 " %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 + // optimizations 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 function 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/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h new file mode 100644 index 000000000000..cfa8654ed9ba --- /dev/null +++ b/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 SymbolFileDWARF_DWARFDebugLine_h_ +#define SymbolFileDWARF_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 std::shared_ptr<Prologue> 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 std::shared_ptr<LineTable> 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 function that gets called each time an entry is 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::ModuleSP &module_sp, 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, lldb::offset_t* offset_ptr, Prologue* prologue); + static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, lldb::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, lldb::offset_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 // SymbolFileDWARF_DWARFDebugLine_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp new file mode 100644 index 000000000000..60ace9e82290 --- /dev/null +++ b/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, lldb::offset_t offset) +{ + DWARFDebugMacinfoEntry maninfo_entry; + if (macinfo_data.GetByteSize() == 0) + { + s->PutCString("< EMPTY >\n"); + return; + } + if (offset == LLDB_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/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h new file mode 100644 index 000000000000..5f3b437d964f --- /dev/null +++ b/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 SymbolFileDWARF_DWARFDebugMacinfo_h_ +#define SymbolFileDWARF_DWARFDebugMacinfo_h_ + +#include "SymbolFileDWARF.h" + +class DWARFDebugMacinfo +{ +public: + DWARFDebugMacinfo(); + + ~DWARFDebugMacinfo(); + + static void + Dump (lldb_private::Stream *s, + const lldb_private::DataExtractor& macinfo_data, + lldb::offset_t offset = LLDB_INVALID_OFFSET); +}; + + +#endif // SymbolFileDWARF_DWARFDebugMacinfo_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp new file mode 100644 index 000000000000..5cd9cb6be474 --- /dev/null +++ b/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: '%u'\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, lldb::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/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h new file mode 100644 index 000000000000..46fd44a22a63 --- /dev/null +++ b/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 SymbolFileDWARF_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, + lldb::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/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp new file mode 100644 index 000000000000..3e511007a1ec --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp @@ -0,0 +1,296 @@ +//===-- 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; +using namespace lldb_private; + +DWARFDebugPubnames::DWARFDebugPubnames() : + m_sets() +{ +} + +bool +DWARFDebugPubnames::Extract(const DataExtractor& data) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", + (uint64_t)data.GetByteSize()); + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); + if (log) + log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize()); + + if (data.ValidOffset(0)) + { + lldb::offset_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); + + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize()); + + 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; + const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes); + if (num_attributes > 0) + { + uint32_t i; + + dw_tag_t tag = die->Tag(); + + 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: + case DW_AT_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 don't 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)) + { + 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/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h new file mode 100644 index 000000000000..09eb80ab3006 --- /dev/null +++ b/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 SymbolFileDWARF_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/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp new file mode 100644 index 000000000000..2df8d525f03f --- /dev/null +++ b/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, lldb::offset_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/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h new file mode 100644 index 000000000000..941c83e58a44 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h @@ -0,0 +1,99 @@ +//===-- 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 SymbolFileDWARF_DWARFDebugPubnamesSet_h_ +#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_ + +#include "SymbolFileDWARF.h" +#include <string> +#include <vector> +#if __cplusplus >= 201103L +#include <unordered_map> +#else +#include <ext/hash_map> +#endif + +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, lldb::offset_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; +#if __cplusplus >= 201103L + typedef std::unordered_multimap<const char*, uint32_t, std::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap; +#else + typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap; +#endif + DescriptorColl m_descriptors; + mutable cstr_to_index_mmap m_name_to_descriptor_index; +}; + +#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp new file mode 100644 index 000000000000..461b17fc3aba --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -0,0 +1,192 @@ +//===-- 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; + lldb::offset_t offset = 0; + dw_offset_t debug_ranges_offset = offset; + while (Extract(dwarf2Data, &offset, range_list)) + { + m_range_map[debug_ranges_offset] = range_list; + debug_ranges_offset = offset; + } +} + +//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::Extract(SymbolFileDWARF* dwarf2Data, lldb::offset_t *offset_ptr, RangeList &range_list) +{ + range_list.Clear(); + + lldb::offset_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 consists of 32 bits of 1's to be 64 bits + // of ones + switch (addr_size) + { + case 2: + if (begin == 0xFFFFull) + begin = LLDB_INVALID_ADDRESS; + break; + + case 4: + if (begin == 0xFFFFFFFFull) + begin = LLDB_INVALID_ADDRESS; + break; + + case 8: + break; + + default: + assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size."); + break; + } + + // Filter out empty ranges + if (begin < end) + range_list.Append(Range(begin, end - begin)); + } + + // Make sure we consumed at least something + return range_offset != *offset_ptr; +} + + +void +DWARFDebugRanges::Dump(Stream &s, const DataExtractor& debug_ranges_data, lldb::offset_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 = LLDB_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 == LLDB_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/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h new file mode 100644 index 000000000000..40899abe9c25 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -0,0 +1,46 @@ +//===-- 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 SymbolFileDWARF_DWARFDebugRanges_h_ +#define SymbolFileDWARF_DWARFDebugRanges_h_ + +#include "SymbolFileDWARF.h" + +#include <map> +#include <vector> + +#include "lldb/Core/RangeMap.h" + +class DWARFDebugRanges +{ +public: + typedef lldb_private::RangeArray<dw_addr_t, dw_addr_t, 2> RangeList; + typedef RangeList::Entry Range; + + DWARFDebugRanges(); + ~DWARFDebugRanges(); + void Extract(SymbolFileDWARF* dwarf2Data); + static void Dump(lldb_private::Stream &s, const lldb_private::DataExtractor& debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr); + bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const; + +protected: + + bool + Extract (SymbolFileDWARF* dwarf2Data, + lldb::offset_t *offset_ptr, + RangeList &range_list); + + 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 // SymbolFileDWARF_DWARFDebugRanges_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp new file mode 100644 index 000000000000..abf69190c93c --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -0,0 +1,104 @@ +//===-- DWARFDeclContext.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDeclContext.h" + +const char * +DWARFDeclContext::GetQualifiedName () const +{ + if (m_qualified_name.empty()) + { + // The declaration context array for a class named "foo" in namespace + // "a::b::c" will be something like: + // [0] DW_TAG_class_type "foo" + // [1] DW_TAG_namespace "c" + // [2] DW_TAG_namespace "b" + // [3] DW_TAG_namespace "a" + if (!m_entries.empty()) + { + if (m_entries.size() == 1) + { + if (m_entries[0].name) + { + m_qualified_name.append("::"); + m_qualified_name.append(m_entries[0].name); + } + } + else + { + collection::const_reverse_iterator pos; + collection::const_reverse_iterator begin = m_entries.rbegin(); + collection::const_reverse_iterator end = m_entries.rend(); + for (pos = begin; pos != end; ++pos) + { + if (pos != begin) + m_qualified_name.append("::"); + if (pos->name == NULL) + { + if (pos->tag == DW_TAG_namespace) + m_qualified_name.append ("(anonymous namespace)"); + else if (pos->tag == DW_TAG_class_type) + m_qualified_name.append ("(anonymous class)"); + else if (pos->tag == DW_TAG_structure_type) + m_qualified_name.append ("(anonymous struct)"); + else if (pos->tag == DW_TAG_union_type) + m_qualified_name.append ("(anonymous union)"); + else + m_qualified_name.append ("(anonymous)"); + } + else + m_qualified_name.append(pos->name); + } + } + } + } + if (m_qualified_name.empty()) + return NULL; + return m_qualified_name.c_str(); +} + + +bool +DWARFDeclContext::operator==(const DWARFDeclContext& rhs) const +{ + if (m_entries.size() != rhs.m_entries.size()) + return false; + + collection::const_iterator pos; + collection::const_iterator begin = m_entries.begin(); + collection::const_iterator end = m_entries.end(); + + collection::const_iterator rhs_pos; + collection::const_iterator rhs_begin = rhs.m_entries.begin(); + // The two entry arrays have the same size + + // First compare the tags before we do expensize name compares + for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) + { + if (pos->tag != rhs_pos->tag) + { + // Check for DW_TAG_structure_type and DW_TAG_class_type as they are often + // used interchangeably in GCC + if (pos->tag == DW_TAG_structure_type && rhs_pos->tag == DW_TAG_class_type) + continue; + if (pos->tag == DW_TAG_class_type && rhs_pos->tag == DW_TAG_structure_type) + continue; + return false; + } + } + // The tags all match, now compare the names + for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) + { + if (!pos->NameMatches (*rhs_pos)) + return false; + } + // All tags and names match + return true; +} + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h new file mode 100644 index 000000000000..accd3446317a --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -0,0 +1,109 @@ +//===-- DWARFDeclContext.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFDeclContext_h_ +#define SymbolFileDWARF_DWARFDeclContext_h_ + +// C Includes +// C++ Includes +#include <string> +#include <vector> +// Other libraries and framework includes +#include "lldb/Core/ConstString.h" +// Project includes +#include "DWARFDefines.h" + +//---------------------------------------------------------------------- +// DWARFDeclContext +// +// A class that represents a declaration context all the way down to a +// DIE. This is useful when trying to find a DIE in one DWARF to a DIE +// in another DWARF file. +//---------------------------------------------------------------------- + +class DWARFDeclContext +{ +public: + struct Entry + { + Entry () : + tag(0), + name(NULL) + { + } + Entry (dw_tag_t t, const char *n) : + tag(t), + name(n) + { + } + + bool + NameMatches (const Entry& rhs) const + { + if (name == rhs.name) + return true; + else if (name && rhs.name) + return strcmp(name, rhs.name) == 0; + return false; + } + + // Test operator + operator bool() const + { + return tag != 0; + } + + dw_tag_t tag; + const char *name; + }; + + DWARFDeclContext () : + m_entries() + { + } + + void + AppendDeclContext (dw_tag_t tag, const char *name) + { + m_entries.push_back(Entry(tag, name)); + } + + bool + operator ==(const DWARFDeclContext& rhs) const; + + uint32_t + GetSize() const + { + return m_entries.size(); + } + + Entry & + operator[] (uint32_t idx) + { + // "idx" must be valid + return m_entries[idx]; + } + + const Entry & + operator[] (uint32_t idx) const + { + // "idx" must be valid + return m_entries[idx]; + } + + const char * + GetQualifiedName () const; + +protected: + typedef std::vector<Entry> collection; + collection m_entries; + mutable std::string m_qualified_name; +}; + +#endif // SymbolFileDWARF_DWARFDeclContext_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp new file mode 100644 index 000000000000..fe4093bc130e --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -0,0 +1,497 @@ +//===-- 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 <cstdio> +#include <cstring> +#include <string> +#include "lldb/Core/ConstString.h" + +namespace lldb_private { + +const char * +DW_TAG_value_to_name (uint32_t val) +{ + static char invalid[100]; + + if (val == 0) + return "NULL"; + + const char *llvmstr = llvm::dwarf::TagString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_TAG constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_CHILDREN_value_to_name (uint8_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::ChildrenString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_CHILDREN constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_AT_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::AttributeString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_AT constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_FORM_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::FormEncodingString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_FORM constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_OP_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::OperationEncodingString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_OP constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +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; + } +} + +const char * +DW_ATE_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::AttributeEncodingString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_ATE constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_ACCESS_value_to_name (uint32_t val) +{ + static char invalid[100]; + + const char *llvmstr = llvm::dwarf::AccessibilityString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_ACCESS constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_VIS_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::VisibilityString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_VIS constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_VIRTUALITY_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::VirtualityString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_LANG_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::LanguageString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_LANG constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_ID_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::CaseString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_ID constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_CC_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::ConventionString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_CC constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_INL_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::InlineCodeString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_INL constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_ORD_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::ArrayOrderString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_ORD constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_DSC_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::DiscriminantString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_DSC constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_LNS_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::LNStandardString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_LNS constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_LNE_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::LNExtendedString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_LNE constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_MACINFO_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::MacinfoString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_MACINFO constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +const char * +DW_CFA_value_to_name (uint32_t val) +{ + static char invalid[100]; + const char *llvmstr = llvm::dwarf::CallFrameString (val); + if (llvmstr == NULL) + { + snprintf (invalid, sizeof (invalid), "Unknown DW_CFA constant: 0x%x", val); + return invalid; + } + return llvmstr; +} + +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; +} + +} // namespace lldb_private + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h new file mode 100644 index 000000000000..e37aefb27a72 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -0,0 +1,116 @@ +//===-- 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 SymbolFileDWARF_DWARFDefines_h_ +#define SymbolFileDWARF_DWARFDefines_h_ + +#include <stdint.h> +#include <stdbool.h> +#include "lldb/Core/dwarf.h" + +namespace lldb_private { + +typedef uint32_t DRC_class; // Holds DRC_* class bitfields + +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); + +DW_TAG_CategoryEnum get_tag_category (uint16_t tag); + +const char *DW_CHILDREN_value_to_name (uint8_t val); + +const char *DW_AT_value_to_name (uint32_t val); + +const char *DW_FORM_value_to_name (uint32_t val); + +const char *DW_OP_value_to_name (uint32_t val); + +DRC_class DW_OP_value_to_class (uint32_t val); + +const char *DW_ATE_value_to_name (uint32_t val); + +const char *DW_ACCESS_value_to_name (uint32_t val); + +const char *DW_VIS_value_to_name (uint32_t val); + +const char *DW_VIRTUALITY_value_to_name (uint32_t val); + +const char *DW_LANG_value_to_name (uint32_t val); + +const char *DW_ID_value_to_name (uint32_t val); + +const char *DW_CC_value_to_name (uint32_t val); + +const char *DW_INL_value_to_name (uint32_t val); + +const char *DW_ORD_value_to_name (uint32_t val); + +const char *DW_DSC_value_to_name (uint32_t val); + +const char *DW_LNS_value_to_name (uint32_t val); + +const char *DW_LNE_value_to_name (uint32_t val); + +const char *DW_MACINFO_value_to_name (uint32_t val); + +const char *DW_CFA_value_to_name (uint32_t val); + +const char *DW_GNU_EH_PE_value_to_name (uint32_t val); + +/* 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 + +} // namespace lldb_private + + +#endif // SymbolFileDWARF_DWARFDefines_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp new file mode 100644 index 000000000000..6113a146c93d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -0,0 +1,599 @@ +//===-- 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; + + +static uint8_t g_form_sizes_addr4[] = +{ + 0, // 0x00 unused + 4, // 0x01 DW_FORM_addr + 0, // 0x02 unused + 0, // 0x03 DW_FORM_block2 + 0, // 0x04 DW_FORM_block4 + 2, // 0x05 DW_FORM_data2 + 4, // 0x06 DW_FORM_data4 + 8, // 0x07 DW_FORM_data8 + 0, // 0x08 DW_FORM_string + 0, // 0x09 DW_FORM_block + 0, // 0x0a DW_FORM_block1 + 1, // 0x0b DW_FORM_data1 + 1, // 0x0c DW_FORM_flag + 0, // 0x0d DW_FORM_sdata + 4, // 0x0e DW_FORM_strp + 0, // 0x0f DW_FORM_udata + 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later + 1, // 0x11 DW_FORM_ref1 + 2, // 0x12 DW_FORM_ref2 + 4, // 0x13 DW_FORM_ref4 + 8, // 0x14 DW_FORM_ref8 + 0, // 0x15 DW_FORM_ref_udata + 0, // 0x16 DW_FORM_indirect + 4, // 0x17 DW_FORM_sec_offset + 0, // 0x18 DW_FORM_exprloc + 0, // 0x19 DW_FORM_flag_present + 0, // 0x1a + 0, // 0x1b + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + 8, // 0x20 DW_FORM_ref_sig8 + +}; + +static uint8_t +g_form_sizes_addr8[] = +{ + 0, // 0x00 unused + 8, // 0x01 DW_FORM_addr + 0, // 0x02 unused + 0, // 0x03 DW_FORM_block2 + 0, // 0x04 DW_FORM_block4 + 2, // 0x05 DW_FORM_data2 + 4, // 0x06 DW_FORM_data4 + 8, // 0x07 DW_FORM_data8 + 0, // 0x08 DW_FORM_string + 0, // 0x09 DW_FORM_block + 0, // 0x0a DW_FORM_block1 + 1, // 0x0b DW_FORM_data1 + 1, // 0x0c DW_FORM_flag + 0, // 0x0d DW_FORM_sdata + 4, // 0x0e DW_FORM_strp + 0, // 0x0f DW_FORM_udata + 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later + 1, // 0x11 DW_FORM_ref1 + 2, // 0x12 DW_FORM_ref2 + 4, // 0x13 DW_FORM_ref4 + 8, // 0x14 DW_FORM_ref8 + 0, // 0x15 DW_FORM_ref_udata + 0, // 0x16 DW_FORM_indirect + 4, // 0x17 DW_FORM_sec_offset + 0, // 0x18 DW_FORM_exprloc + 0, // 0x19 DW_FORM_flag_present + 0, // 0x1a + 0, // 0x1b + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + 8, // 0x20 DW_FORM_ref_sig8 +}; + +const uint8_t * +DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size) +{ + switch (addr_size) + { + case 4: return g_form_sizes_addr4; + case 8: return g_form_sizes_addr8; + } + return NULL; +} + +DWARFFormValue::DWARFFormValue(dw_form_t form) : + m_form(form), + m_value() +{ +} + +bool +DWARFFormValue::ExtractValue(const DataExtractor& data, lldb::offset_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_exprloc: + 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: + if (cu->GetVersion() <= 2) + m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); + else + m_value.value.uval = data.GetU32(offset_ptr); // 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet + 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; + + case DW_FORM_sec_offset: m_value.value.uval = data.GetU32(offset_ptr); break; + case DW_FORM_flag_present: m_value.value.uval = 1; break; + case DW_FORM_ref_sig8: m_value.value.uval = data.GetU64(offset_ptr); 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, lldb::offset_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, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) +{ + switch (form) + { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info + case DW_FORM_exprloc: + case DW_FORM_block: { 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: + *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + return true; + + case DW_FORM_ref_addr: + if (cu->GetVersion() <= 2) + *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + else + *offset_ptr += 4;// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet + return true; + + // 0 bytes values (implied from DW_FORM) + case DW_FORM_flag_present: + 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; + + // 32 bit for DWARF 32, 64 for DWARF 64 + case DW_FORM_sec_offset: + *offset_ptr += 4; + 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: + case DW_FORM_ref_sig8: + *offset_ptr += 8; + return true; + + // signed or unsigned LEB 128 values + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + debug_info_data.Skip_LEB128(offset_ptr); + return true; + + case DW_FORM_indirect: + { + dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr); + return DWARFFormValue::SkipValue (indirect_form, + debug_info_data, + offset_ptr, + cu); + } + + default: + break; + } + return false; +} + + +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_sec_offset: + case DW_FORM_data4: s.PutHex32(uvalue); break; + case DW_FORM_ref_sig8: + case DW_FORM_data8: s.PutHex64(uvalue); break; + case DW_FORM_string: s.QuotedCString(AsCString(NULL)); break; + case DW_FORM_exprloc: + 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_exprloc: + case DW_FORM_block: s.Printf("<0x%" PRIx64 "> ", 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: + { + if (cu->GetVersion() <= 2) + s.Address(uvalue, sizeof (uint64_t) * 2); + else + s.Address(uvalue, 4 * 2);// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet + 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.8" PRIx64, uvalue); break; + case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%" PRIx64, 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; + case DW_FORM_flag_present: break; + default: + s.Printf("DW_FORM(0x%4.4x)", m_form); + break; + } + + if (cu_relative_offset) + { + if (verbose) + s.PutCString(" => "); + + s.Printf("{0x%8.8" PRIx64 "}", (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; +} + +uint64_t +DWARFFormValue::Reference (dw_offset_t base_offset) 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 += base_offset; + 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: + case DW_FORM_sec_offset: + case DW_FORM_flag_present: + case DW_FORM_ref_sig8: + { + 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: + case DW_FORM_exprloc: + { + 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/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h new file mode 100644 index 000000000000..4c400b2df58e --- /dev/null +++ b/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 SymbolFileDWARF_DWARFFormValue_h_ +#define SymbolFileDWARF_DWARFFormValue_h_ + +#include <stddef.h> // for NULL + +class DWARFCompileUnit; + +class DWARFFormValue +{ +public: + typedef struct ValueTypeTag + { + ValueTypeTag() : + value(), + data(NULL) + { + 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, + lldb::offset_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; + uint64_t Reference (dw_offset_t offset) const; + bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu); + bool Boolean() const { return m_value.value.uval != 0; } + 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, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const; + static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu); +// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& debug_info_data, lldb::offset_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 const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size); + 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/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp new file mode 100644 index 000000000000..fdc07836b88d --- /dev/null +++ b/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, lldb::offset_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; + lldb::offset_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, + lldb::offset_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_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("%" PRIu64 " %" PRIi64, 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("%+" PRIi64, sint); break; + case -2: sint = (int16_t) data.GetU16(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -4: sint = (int32_t) data.GetU32(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -8: sint = (int64_t) data.GetU64(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -128: sint = data.GetSLEB128(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case 1: uint = data.GetU8(offset_ptr); s.Printf("0x%2.2" PRIx64, uint); break; + case 2: uint = data.GetU16(offset_ptr); s.Printf("0x%4.4" PRIx64, uint); break; + case 4: uint = data.GetU32(offset_ptr); s.Printf("0x%8.8" PRIx64, uint); break; + case 8: uint = data.GetU64(offset_ptr); s.Printf("0x%16.16" PRIx64, uint); break; + case 128: uint = data.GetULEB128(offset_ptr); s.Printf("0x%" PRIx64, uint); break; + } + + return 0; +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h new file mode 100644 index 000000000000..ff7c907e921c --- /dev/null +++ b/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 SymbolFileDWARF_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/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp new file mode 100644 index 000000000000..dad5691267df --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp @@ -0,0 +1,94 @@ +//===-- 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, lldb::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(); + if (cu) + s.AddressRange (start_addr + base_addr, + end_addr + base_addr, + cu->GetAddressByteSize(), + 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, lldb::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, lldb::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/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h new file mode 100644 index 000000000000..85e11d90b36b --- /dev/null +++ b/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 SymbolFileDWARF_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, + lldb::offset_t offset); + + static bool + Extract (const lldb_private::DataExtractor& debug_loc_data, + lldb::offset_t* offset_ptr, + lldb_private::DataExtractor& location_list_data); + + static size_t + Size (const lldb_private::DataExtractor& debug_loc_data, + lldb::offset_t offset); + +}; +#endif // SymbolFileDWARF_DWARFLocationList_h_ diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h new file mode 100644 index 000000000000..c31cbaf3ca20 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -0,0 +1,933 @@ +//===-- HashedNameToDIE.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_HashedNameToDIE_h_ +#define SymbolFileDWARF_HashedNameToDIE_h_ + +#include <vector> + +#include "DWARFDefines.h" +#include "DWARFFormValue.h" + +#include "lldb/lldb-defines.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/MappedHash.h" + + +class SymbolFileDWARF; +class DWARFCompileUnit; +class DWARFDebugInfoEntry; + +struct DWARFMappedHash +{ + struct DIEInfo + { + dw_offset_t offset; // The DIE offset + dw_tag_t tag; + uint32_t type_flags; // Any flags for this DIEInfo + uint32_t qualified_name_hash; // A 32 bit hash of the fully qualified name + + DIEInfo () : + offset (DW_INVALID_OFFSET), + tag (0), + type_flags (0), + qualified_name_hash (0) + { + } + + DIEInfo (dw_offset_t o, dw_tag_t t, uint32_t f, uint32_t h) : + offset(o), + tag (t), + type_flags (f), + qualified_name_hash (h) + { + } + + void + Clear() + { + offset = DW_INVALID_OFFSET; + tag = 0; + type_flags = 0; + qualified_name_hash = 0; + } + }; + + typedef std::vector<DIEInfo> DIEInfoArray; + typedef std::vector<uint32_t> DIEArray; + + static void + ExtractDIEArray (const DIEInfoArray &die_info_array, + DIEArray &die_offsets) + { + const size_t count = die_info_array.size(); + for (size_t i=0; i<count; ++i) + { + die_offsets.push_back (die_info_array[i].offset); + } + } + + static void + ExtractDIEArray (const DIEInfoArray &die_info_array, + const dw_tag_t tag, + DIEArray &die_offsets) + { + if (tag == 0) + { + ExtractDIEArray (die_info_array, die_offsets); + } + else + { + const size_t count = die_info_array.size(); + for (size_t i=0; i<count; ++i) + { + const dw_tag_t die_tag = die_info_array[i].tag; + bool tag_matches = die_tag == 0 || tag == die_tag; + if (!tag_matches) + { + if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) + tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; + } + if (tag_matches) + die_offsets.push_back (die_info_array[i].offset); + } + } + } + + static void + ExtractDIEArray (const DIEInfoArray &die_info_array, + const dw_tag_t tag, + const uint32_t qualified_name_hash, + DIEArray &die_offsets) + { + if (tag == 0) + { + ExtractDIEArray (die_info_array, die_offsets); + } + else + { + const size_t count = die_info_array.size(); + for (size_t i=0; i<count; ++i) + { + if (qualified_name_hash != die_info_array[i].qualified_name_hash) + continue; + const dw_tag_t die_tag = die_info_array[i].tag; + bool tag_matches = die_tag == 0 || tag == die_tag; + if (!tag_matches) + { + if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) + tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; + } + if (tag_matches) + die_offsets.push_back (die_info_array[i].offset); + } + } + } + + enum AtomType + { + eAtomTypeNULL = 0u, + eAtomTypeDIEOffset = 1u, // DIE offset, check form for encoding + eAtomTypeCUOffset = 2u, // DIE offset of the compiler unit header that contains the item in question + eAtomTypeTag = 3u, // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2 + eAtomTypeNameFlags = 4u, // Flags from enum NameFlags + eAtomTypeTypeFlags = 5u, // Flags from enum TypeFlags, + eAtomTypeQualNameHash = 6u // A 32 bit hash of the full qualified name (since all hash entries are basename only) + // For example a type like "std::vector<int>::iterator" would have a name of "iterator" + // and a 32 bit hash for "std::vector<int>::iterator" to allow us to not have to pull + // in debug info for a type when we know the fully qualified name. + }; + + // Bit definitions for the eAtomTypeTypeFlags flags + enum TypeFlags + { + // Always set for C++, only set for ObjC if this is the + // @implementation for class + eTypeFlagClassIsImplementation = ( 1u << 1 ) + }; + + + static void + ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array, + bool return_implementation_only_if_available, + DIEArray &die_offsets) + { + const size_t count = die_info_array.size(); + for (size_t i=0; i<count; ++i) + { + const dw_tag_t die_tag = die_info_array[i].tag; + if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) + { + if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) + { + if (return_implementation_only_if_available) + { + // We found the one true definiton for this class, so + // only return that + die_offsets.clear(); + die_offsets.push_back (die_info_array[i].offset); + return; + } + else + { + // Put the one true definition as the first entry so it + // matches first + die_offsets.insert (die_offsets.begin(), die_info_array[i].offset); + } + } + else + { + die_offsets.push_back (die_info_array[i].offset); + } + } + } + } + + static void + ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array, + uint32_t type_flag_mask, + uint32_t type_flag_value, + DIEArray &die_offsets) + { + const size_t count = die_info_array.size(); + for (size_t i=0; i<count; ++i) + { + if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) + die_offsets.push_back (die_info_array[i].offset); + } + } + + struct Atom + { + uint16_t type; + dw_form_t form; + + Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) : + type (t), + form (f) + { + } + }; + + typedef std::vector<Atom> AtomArray; + + static uint32_t + GetTypeFlags (SymbolFileDWARF *dwarf2Data, + const DWARFCompileUnit* cu, + const DWARFDebugInfoEntry* die); + + + static const char * + GetAtomTypeName (uint16_t atom) + { + switch (atom) + { + case eAtomTypeNULL: return "NULL"; + case eAtomTypeDIEOffset: return "die-offset"; + case eAtomTypeCUOffset: return "cu-offset"; + case eAtomTypeTag: return "die-tag"; + case eAtomTypeNameFlags: return "name-flags"; + case eAtomTypeTypeFlags: return "type-flags"; + case eAtomTypeQualNameHash: return "qualified-name-hash"; + } + return "<invalid>"; + } + struct Prologue + { + // DIE offset base so die offsets in hash_data can be CU relative + dw_offset_t die_base_offset; + AtomArray atoms; + uint32_t atom_mask; + size_t min_hash_data_byte_size; + bool hash_data_has_fixed_byte_size; + + Prologue (dw_offset_t _die_base_offset = 0) : + die_base_offset (_die_base_offset), + atoms(), + atom_mask (0), + min_hash_data_byte_size(0), + hash_data_has_fixed_byte_size(true) + { + // Define an array of DIE offsets by first defining an array, + // and then define the atom type for the array, in this case + // we have an array of DIE offsets + AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4); + } + + virtual ~Prologue() + { + } + + void + ClearAtoms () + { + hash_data_has_fixed_byte_size = true; + min_hash_data_byte_size = 0; + atom_mask = 0; + atoms.clear(); + } + + bool + ContainsAtom (AtomType atom_type) const + { + return (atom_mask & (1u << atom_type)) != 0; + } + + virtual void + Clear () + { + die_base_offset = 0; + ClearAtoms (); + } + + void + AppendAtom (AtomType type, dw_form_t form) + { + atoms.push_back (Atom(type, form)); + atom_mask |= 1u << type; + switch (form) + { + case DW_FORM_indirect: + case DW_FORM_exprloc: + case DW_FORM_flag_present: + case DW_FORM_ref_sig8: + assert (!"Unhandled atom form"); + break; + + case DW_FORM_string: + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + hash_data_has_fixed_byte_size = false; + // Fall through to the cases below... + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_sec_offset: + min_hash_data_byte_size += 1; + break; + + case DW_FORM_block2: + hash_data_has_fixed_byte_size = false; + // Fall through to the cases below... + case DW_FORM_data2: + case DW_FORM_ref2: + min_hash_data_byte_size += 2; + break; + + case DW_FORM_block4: + hash_data_has_fixed_byte_size = false; + // Fall through to the cases below... + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_addr: + case DW_FORM_ref_addr: + case DW_FORM_strp: + min_hash_data_byte_size += 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + min_hash_data_byte_size += 8; + break; + + } + } + +// void +// Dump (std::ostream* ostrm_ptr); + + lldb::offset_t + Read (const lldb_private::DataExtractor &data, + lldb::offset_t offset) + { + ClearAtoms (); + + die_base_offset = data.GetU32 (&offset); + + const uint32_t atom_count = data.GetU32 (&offset); + if (atom_count == 0x00060003u) + { + // Old format, deal with contents of old pre-release format + while (data.GetU32(&offset)) + /* do nothing */; + + // Hardcode to the only known value for now. + AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4); + } + else + { + for (uint32_t i=0; i<atom_count; ++i) + { + AtomType type = (AtomType)data.GetU16 (&offset); + dw_form_t form = (dw_form_t)data.GetU16 (&offset); + AppendAtom (type, form); + } + } + return offset; + } + +// virtual void +// Write (BinaryStreamBuf &s); + + size_t + GetByteSize () const + { + // Add an extra count to the atoms size for the zero termination Atom that gets + // written to disk + return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom); + } + + size_t + GetMinumumHashDataByteSize () const + { + return min_hash_data_byte_size; + } + + bool + HashDataHasFixedByteSize() const + { + return hash_data_has_fixed_byte_size; + } + }; + + struct Header : public MappedHash::Header<Prologue> + { + Header (dw_offset_t _die_base_offset = 0) + { + } + + virtual + ~Header() + { + } + + virtual size_t + GetByteSize (const HeaderData &header_data) + { + return header_data.GetByteSize(); + } + + // virtual void + // Dump (std::ostream* ostrm_ptr); + // + virtual lldb::offset_t + Read (lldb_private::DataExtractor &data, lldb::offset_t offset) + { + offset = MappedHash::Header<Prologue>::Read (data, offset); + if (offset != UINT32_MAX) + { + offset = header_data.Read (data, offset); + } + return offset; + } + + bool + Read (const lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + DIEInfo &hash_data) const + { + const size_t num_atoms = header_data.atoms.size(); + if (num_atoms == 0) + return false; + + for (size_t i=0; i<num_atoms; ++i) + { + DWARFFormValue form_value (header_data.atoms[i].form); + + if (!form_value.ExtractValue(data, offset_ptr, NULL)) + return false; + + switch (header_data.atoms[i].type) + { + case eAtomTypeDIEOffset: // DIE offset, check form for encoding + hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset); + break; + + case eAtomTypeTag: // DW_TAG value for the DIE + hash_data.tag = (dw_tag_t)form_value.Unsigned (); + + case eAtomTypeTypeFlags: // Flags from enum TypeFlags + hash_data.type_flags = (uint32_t)form_value.Unsigned (); + break; + + case eAtomTypeQualNameHash: // Flags from enum TypeFlags + hash_data.qualified_name_hash = form_value.Unsigned (); + break; + + default: + // We can always skip atomes we don't know about + break; + } + } + return true; + } + + void + Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const + { + const size_t num_atoms = header_data.atoms.size(); + for (size_t i=0; i<num_atoms; ++i) + { + if (i > 0) + strm.PutCString (", "); + + DWARFFormValue form_value (header_data.atoms[i].form); + switch (header_data.atoms[i].type) + { + case eAtomTypeDIEOffset: // DIE offset, check form for encoding + strm.Printf ("{0x%8.8x}", hash_data.offset); + break; + + case eAtomTypeTag: // DW_TAG value for the DIE + { + const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag); + if (tag_cstr) + strm.PutCString (tag_cstr); + else + strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag); + } + break; + + case eAtomTypeTypeFlags: // Flags from enum TypeFlags + strm.Printf ("0x%2.2x", hash_data.type_flags); + if (hash_data.type_flags) + { + strm.PutCString (" ("); + if (hash_data.type_flags & eTypeFlagClassIsImplementation) + strm.PutCString (" implementation"); + strm.PutCString (" )"); + } + break; + + case eAtomTypeQualNameHash: // Flags from enum TypeFlags + strm.Printf ("0x%8.8x", hash_data.qualified_name_hash); + break; + + default: + strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type); + break; + } + } + } + }; + +// class ExportTable +// { +// public: +// ExportTable (); +// +// void +// AppendNames (DWARFDebugPubnamesSet &pubnames_set, +// StringTable &string_table); +// +// void +// AppendNamesEntry (SymbolFileDWARF *dwarf2Data, +// const DWARFCompileUnit* cu, +// const DWARFDebugInfoEntry* die, +// StringTable &string_table); +// +// void +// AppendTypesEntry (DWARFData *dwarf2Data, +// const DWARFCompileUnit* cu, +// const DWARFDebugInfoEntry* die, +// StringTable &string_table); +// +// size_t +// Save (BinaryStreamBuf &names_data, const StringTable &string_table); +// +// void +// AppendName (const char *name, +// uint32_t die_offset, +// StringTable &string_table, +// dw_offset_t name_debug_str_offset = DW_INVALID_OFFSET); // If "name" has already been looked up, then it can be supplied +// void +// AppendType (const char *name, +// uint32_t die_offset, +// StringTable &string_table); +// +// +// protected: +// struct Entry +// { +// uint32_t hash; +// uint32_t str_offset; +// uint32_t die_offset; +// }; +// +// // Map uniqued .debug_str offset to the corresponding DIE offsets +// typedef std::map<uint32_t, DIEInfoArray> NameInfo; +// // Map a name hash to one or more name infos +// typedef std::map<uint32_t, NameInfo> BucketEntry; +// +// static uint32_t +// GetByteSize (const NameInfo &name_info); +// +// typedef std::vector<BucketEntry> BucketEntryColl; +// typedef std::vector<Entry> EntryColl; +// EntryColl m_entries; +// +// }; + + + // A class for reading and using a saved hash table from a block of data + // in memory + class MemoryTable : public MappedHash::MemoryTable<uint32_t, DWARFMappedHash::Header, DIEInfoArray> + { + public: + + MemoryTable (lldb_private::DataExtractor &table_data, + const lldb_private::DataExtractor &string_table, + const char *name) : + MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data), + m_data (table_data), + m_string_table (string_table), + m_name (name) + { + } + + virtual + ~MemoryTable () + { + } + + virtual const char * + GetStringForKeyType (KeyType key) const + { + // The key in the DWARF table is the .debug_str offset for the string + return m_string_table.PeekCStr (key); + } + + virtual bool + ReadHashData (uint32_t hash_data_offset, + HashData &hash_data) const + { + lldb::offset_t offset = hash_data_offset; + offset += 4; // Skip string table offset that contains offset of hash name in .debug_str + const uint32_t count = m_data.GetU32 (&offset); + if (count > 0) + { + hash_data.resize(count); + for (uint32_t i=0; i<count; ++i) + { + if (!m_header.Read(m_data, &offset, hash_data[i])) + return false; + } + } + else + hash_data.clear(); + return true; + } + + virtual Result + GetHashDataForName (const char *name, + lldb::offset_t* hash_data_offset_ptr, + Pair &pair) const + { + pair.key = m_data.GetU32 (hash_data_offset_ptr); + pair.value.clear(); + + // If the key is zero, this terminates our chain of HashData objects + // for this hash value. + if (pair.key == 0) + return eResultEndOfHashData; + + // There definitely should be a string for this string offset, if + // there isn't, there is something wrong, return and error + const char *strp_cstr = m_string_table.PeekCStr (pair.key); + if (strp_cstr == NULL) + { + *hash_data_offset_ptr = UINT32_MAX; + return eResultError; + } + + const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); + const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize(); + if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) + { + // We have at least one HashData entry, and we have enough + // data to parse at leats "count" HashData enties. + + // First make sure the entire C string matches... + const bool match = strcmp (name, strp_cstr) == 0; + + if (!match && m_header.header_data.HashDataHasFixedByteSize()) + { + // If the string doesn't match and we have fixed size data, + // we can just add the total byte size of all HashData objects + // to the hash data offset and be done... + *hash_data_offset_ptr += min_total_hash_data_size; + } + else + { + // If the string does match, or we don't have fixed size data + // then we need to read the hash data as a stream. If the + // string matches we also append all HashData objects to the + // value array. + for (uint32_t i=0; i<count; ++i) + { + DIEInfo die_info; + if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) + { + // Only happend the HashData if the string matched... + if (match) + pair.value.push_back (die_info); + } + else + { + // Something went wrong while reading the data + *hash_data_offset_ptr = UINT32_MAX; + return eResultError; + } + } + } + // Return the correct response depending on if the string matched + // or not... + if (match) + return eResultKeyMatch; // The key (cstring) matches and we have lookup results! + else + return eResultKeyMismatch; // The key doesn't match, this function will get called + // again for the next key/value or the key terminator + // which in our case is a zero .debug_str offset. + } + else + { + *hash_data_offset_ptr = UINT32_MAX; + return eResultError; + } + } + + virtual Result + AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex, + lldb::offset_t* hash_data_offset_ptr, + Pair &pair) const + { + pair.key = m_data.GetU32 (hash_data_offset_ptr); + // If the key is zero, this terminates our chain of HashData objects + // for this hash value. + if (pair.key == 0) + return eResultEndOfHashData; + + // There definitely should be a string for this string offset, if + // there isn't, there is something wrong, return and error + const char *strp_cstr = m_string_table.PeekCStr (pair.key); + if (strp_cstr == NULL) + return eResultError; + + const uint32_t count = m_data.GetU32 (hash_data_offset_ptr); + const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize(); + if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size)) + { + const bool match = regex.Execute(strp_cstr); + + if (!match && m_header.header_data.HashDataHasFixedByteSize()) + { + // If the regex doesn't match and we have fixed size data, + // we can just add the total byte size of all HashData objects + // to the hash data offset and be done... + *hash_data_offset_ptr += min_total_hash_data_size; + } + else + { + // If the string does match, or we don't have fixed size data + // then we need to read the hash data as a stream. If the + // string matches we also append all HashData objects to the + // value array. + for (uint32_t i=0; i<count; ++i) + { + DIEInfo die_info; + if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) + { + // Only happend the HashData if the string matched... + if (match) + pair.value.push_back (die_info); + } + else + { + // Something went wrong while reading the data + *hash_data_offset_ptr = UINT32_MAX; + return eResultError; + } + } + } + // Return the correct response depending on if the string matched + // or not... + if (match) + return eResultKeyMatch; // The key (cstring) matches and we have lookup results! + else + return eResultKeyMismatch; // The key doesn't match, this function will get called + // again for the next key/value or the key terminator + // which in our case is a zero .debug_str offset. + } + else + { + *hash_data_offset_ptr = UINT32_MAX; + return eResultError; + } + } + + size_t + AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex, + DIEInfoArray &die_info_array) const + { + const uint32_t hash_count = m_header.hashes_count; + Pair pair; + for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx) + { + lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx); + while (hash_data_offset != UINT32_MAX) + { + const lldb::offset_t prev_hash_data_offset = hash_data_offset; + Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair); + if (prev_hash_data_offset == hash_data_offset) + break; + + // Check the result of getting our hash data + switch (hash_result) + { + case eResultKeyMatch: + case eResultKeyMismatch: + // Whether we matches or not, it doesn't matter, we + // keep looking. + break; + + case eResultEndOfHashData: + case eResultError: + hash_data_offset = UINT32_MAX; + break; + } + } + } + die_info_array.swap (pair.value); + return die_info_array.size(); + } + + size_t + AppendAllDIEsInRange (const uint32_t die_offset_start, + const uint32_t die_offset_end, + DIEInfoArray &die_info_array) const + { + const uint32_t hash_count = m_header.hashes_count; + for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx) + { + bool done = false; + lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx); + while (!done && hash_data_offset != UINT32_MAX) + { + KeyType key = m_data.GetU32 (&hash_data_offset); + // If the key is zero, this terminates our chain of HashData objects + // for this hash value. + if (key == 0) + break; + + const uint32_t count = m_data.GetU32 (&hash_data_offset); + for (uint32_t i=0; i<count; ++i) + { + DIEInfo die_info; + if (m_header.Read(m_data, &hash_data_offset, die_info)) + { + if (die_info.offset == 0) + done = true; + if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end) + die_info_array.push_back(die_info); + } + } + } + } + return die_info_array.size(); + } + + size_t + FindByName (const char *name, DIEArray &die_offsets) + { + DIEInfoArray die_info_array; + if (FindByName(name, die_info_array)) + DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets); + return die_info_array.size(); + } + + size_t + FindByNameAndTag (const char *name, + const dw_tag_t tag, + DIEArray &die_offsets) + { + DIEInfoArray die_info_array; + if (FindByName(name, die_info_array)) + DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets); + return die_info_array.size(); + } + + size_t + FindByNameAndTagAndQualifiedNameHash (const char *name, + const dw_tag_t tag, + const uint32_t qualified_name_hash, + DIEArray &die_offsets) + { + DIEInfoArray die_info_array; + if (FindByName(name, die_info_array)) + DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets); + return die_info_array.size(); + } + + size_t + FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation) + { + DIEInfoArray die_info_array; + if (FindByName(name, die_info_array)) + { + if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags)) + { + // If we have two atoms, then we have the DIE offset and + // the type flags so we can find the objective C class + // efficiently. + DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array, + UINT32_MAX, + eTypeFlagClassIsImplementation, + die_offsets); + } + else + { + // We don't only want the one true definition, so try and see + // what we can find, and only return class or struct DIEs. + // If we do have the full implementation, then return it alone, + // else return all possible matches. + const bool return_implementation_only_if_available = true; + DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array, + return_implementation_only_if_available, + die_offsets); + } + } + return die_offsets.size(); + } + + size_t + FindByName (const char *name, DIEInfoArray &die_info_array) + { + Pair kv_pair; + size_t old_size = die_info_array.size(); + if (Find (name, kv_pair)) + { + die_info_array.swap(kv_pair.value); + return die_info_array.size() - old_size; + } + return 0; + } + + protected: + const lldb_private::DataExtractor &m_data; + const lldb_private::DataExtractor &m_string_table; + std::string m_name; + }; +}; + + +#endif // SymbolFileDWARF_HashedNameToDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp new file mode 100644 index 000000000000..27fa261813bb --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -0,0 +1,232 @@ +//===-- 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/Interpreter/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 (); +} + +lldb_private::ConstString +LogChannelDWARF::GetPluginNameStatic() +{ + return SymbolFileDWARF::GetPluginNameStatic(); +} + +const char * +LogChannelDWARF::GetPluginDescriptionStatic() +{ + return "DWARF log channel for debugging plug-in issues."; +} + +lldb_private::ConstString +LogChannelDWARF::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +LogChannelDWARF::GetPluginVersion() +{ + return 1; +} + + +void +LogChannelDWARF::Delete () +{ + g_log_channel = NULL; +} + + +void +LogChannelDWARF::Disable (const char **categories, Stream *feedback_strm) +{ + if (m_log_ap.get() == NULL) + return; + + uint32_t flag_bits = m_log_ap->GetMask().Get(); + for (size_t i = 0; categories[i] != NULL; ++i) + { + const char *arg = categories[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, "aranges") == 0) flag_bits &= ~DWARF_LOG_DEBUG_ARANGES; + else if (::strcasecmp (arg, "lookups") == 0) flag_bits &= ~DWARF_LOG_LOOKUPS; + else if (::strcasecmp (arg, "map") == 0) flag_bits &= ~DWARF_LOG_DEBUG_MAP; + else if (::strcasecmp (arg, "default") == 0) flag_bits &= ~DWARF_LOG_DEFAULT; + else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits &= ~DWARF_LOG_TYPE_COMPLETION; + else + { + feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); + ListCategories (feedback_strm); + } + } + + if (flag_bits == 0) + Delete (); + else + m_log_ap->GetMask().Reset (flag_bits); + + return; +} + +bool +LogChannelDWARF::Enable +( + StreamSP &log_stream_sp, + uint32_t log_options, + Stream *feedback_strm, // Feedback stream for argument errors etc + const char **categories // The categories to enable within this logging stream, if empty, enable default set +) +{ + Delete (); + + if (m_log_ap) + m_log_ap->SetStream(log_stream_sp); + else + m_log_ap.reset(new Log (log_stream_sp)); + + g_log_channel = this; + uint32_t flag_bits = 0; + bool got_unknown_category = false; + for (size_t i = 0; categories[i] != NULL; ++i) + { + const char *arg = categories[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, "aranges") == 0) flag_bits |= DWARF_LOG_DEBUG_ARANGES; + else if (::strcasecmp (arg, "lookups") == 0) flag_bits |= DWARF_LOG_LOOKUPS; + else if (::strcasecmp (arg, "map") == 0) flag_bits |= DWARF_LOG_DEBUG_MAP; + else if (::strcasecmp (arg, "default") == 0) flag_bits |= DWARF_LOG_DEFAULT; + else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits |= DWARF_LOG_TYPE_COMPLETION; + 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_ap->GetMask().Reset(flag_bits); + m_log_ap->GetOptions().Reset(log_options); + return m_log_ap.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" + " lookups - log any lookups that happen by name, regex, or address\n" + " completion - log struct/unions/class type completions\n" + " map - log insertions of object files into DWARF debug maps\n", + SymbolFileDWARF::GetPluginNameStatic().GetCString()); +} + +Log * +LogChannelDWARF::GetLog () +{ + if (g_log_channel) + return g_log_channel->m_log_ap.get(); + + return NULL; +} + +Log * +LogChannelDWARF::GetLogIfAll (uint32_t mask) +{ + if (g_log_channel && g_log_channel->m_log_ap.get()) + { + if (g_log_channel->m_log_ap->GetMask().AllSet(mask)) + return g_log_channel->m_log_ap.get(); + } + return NULL; +} + +Log * +LogChannelDWARF::GetLogIfAny (uint32_t mask) +{ + if (g_log_channel && g_log_channel->m_log_ap.get()) + { + if (g_log_channel->m_log_ap->GetMask().AnySet(mask)) + return g_log_channel->m_log_ap.get(); + } + return NULL; +} + +void +LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...) +{ + if (g_log_channel) + { + Log *log = g_log_channel->m_log_ap.get(); + if (log && log->GetMask().AnySet(mask)) + { + va_list args; + va_start (args, format); + log->VAPrintf (format, args); + va_end (args); + } + } +} diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h new file mode 100644 index 000000000000..2091a8414f58 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -0,0 +1,89 @@ +//===-- 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 SymbolFileDWARF_LogChannelDWARF_h_ +#define SymbolFileDWARF_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_DEBUG_ARANGES (1u << 5) +#define DWARF_LOG_LOOKUPS (1u << 6) +#define DWARF_LOG_TYPE_COMPLETION (1u << 7) +#define DWARF_LOG_DEBUG_MAP (1u << 8) +#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 lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::LogChannel * + CreateInstance (); + + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + Disable (const char** categories, lldb_private::Stream *feedback_strm); + + void + Delete (); + + virtual bool + Enable (lldb::StreamSP &log_stream_sp, + uint32_t log_options, + lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc + const char **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 lldb_private::Log * + GetLogIfAny (uint32_t mask); + + static void + LogIf (uint32_t mask, const char *format, ...); +}; + +#endif // SymbolFileDWARF_LogChannelDWARF_h_ diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp new file mode 100644 index 000000000000..5514469d0758 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -0,0 +1,87 @@ +//===-- NameToDIE.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NameToDIE.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Symbol/ObjectFile.h" + +#include "DWARFCompileUnit.h" +#include "DWARFDebugInfo.h" +#include "DWARFDebugInfoEntry.h" +#include "SymbolFileDWARF.h" +using namespace lldb; +using namespace lldb_private; + +void +NameToDIE::Finalize() +{ + m_map.Sort (); + m_map.SizeToFit (); +} + +void +NameToDIE::Insert (const ConstString& name, uint32_t die_offset) +{ + m_map.Append(name.GetCString(), die_offset); +} + +size_t +NameToDIE::Find (const ConstString &name, DIEArray &info_array) const +{ + return m_map.GetValues (name.GetCString(), info_array); +} + +size_t +NameToDIE::Find (const RegularExpression& regex, DIEArray &info_array) const +{ + return m_map.GetValues (regex, info_array); +} + +size_t +NameToDIE::FindAllEntriesForCompileUnit (uint32_t cu_offset, + uint32_t cu_end_offset, + DIEArray &info_array) const +{ + const size_t initial_size = info_array.size(); + const uint32_t size = m_map.GetSize(); + for (uint32_t i=0; i<size; ++i) + { + const uint32_t die_offset = m_map.GetValueAtIndexUnchecked(i); + if (cu_offset < die_offset && die_offset < cu_end_offset) + info_array.push_back (die_offset); + } + return info_array.size() - initial_size; +} + +void +NameToDIE::Dump (Stream *s) +{ + const uint32_t size = m_map.GetSize(); + for (uint32_t i=0; i<size; ++i) + { + const char *cstr = m_map.GetCStringAtIndex(i); + s->Printf("%p: {0x%8.8x} \"%s\"\n", cstr, m_map.GetValueAtIndexUnchecked(i), cstr); + } +} + +void +NameToDIE::ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const +{ + const uint32_t size = m_map.GetSize(); + for (uint32_t i=0; i<size; ++i) + { + if (!callback(m_map.GetCStringAtIndexUnchecked(i), + m_map.GetValueAtIndexUnchecked (i))) + break; + } +} diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/source/Plugins/SymbolFile/DWARF/NameToDIE.h new file mode 100644 index 000000000000..f9a12736bf9e --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -0,0 +1,65 @@ +//===-- NameToDIE.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_NameToDIE_h_ +#define SymbolFileDWARF_NameToDIE_h_ + +#include "lldb/Core/UniqueCStringMap.h" + +#include <functional> + +#include "lldb/lldb-defines.h" + +class SymbolFileDWARF; + +typedef std::vector<uint32_t> DIEArray; + +class NameToDIE +{ +public: + NameToDIE () : + m_map() + { + } + + ~NameToDIE () + { + } + + void + Dump (lldb_private::Stream *s); + + void + Insert (const lldb_private::ConstString& name, uint32_t die_offset); + + void + Finalize(); + + size_t + Find (const lldb_private::ConstString &name, + DIEArray &info_array) const; + + size_t + Find (const lldb_private::RegularExpression& regex, + DIEArray &info_array) const; + + size_t + FindAllEntriesForCompileUnit (uint32_t cu_offset, + uint32_t cu_end_offset, + DIEArray &info_array) const; + + void + ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const; + +protected: + lldb_private::UniqueCStringMap<uint32_t> m_map; + +}; + +#endif // SymbolFileDWARF_NameToDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp new file mode 100644 index 000000000000..f265af837eef --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -0,0 +1,7973 @@ +//===-- 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/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.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 "clang/Sema/DeclSpec.h" + +#include "llvm/Support/Casting.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/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/Value.h" + +#include "lldb/Host/Host.h" + +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.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 "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/CPPLanguageRuntime.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 "DWARFDeclContext.h" +#include "DWARFDIECollection.h" +#include "DWARFFormValue.h" +#include "DWARFLocationList.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARFDebugMap.h" + +#include <map> + +//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN + +#ifdef ENABLE_DEBUG_PRINTF +#include <stdio.h> +#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_PRINTF(fmt, ...) +#endif + +#define DIE_IS_BEING_PARSED ((lldb_private::Type*)1) + +using namespace lldb; +using namespace lldb_private; + +//static inline bool +//child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag) +//{ +// switch (tag) +// { +// default: +// break; +// case DW_TAG_subprogram: +// case DW_TAG_inlined_subroutine: +// case DW_TAG_class_type: +// case DW_TAG_structure_type: +// case DW_TAG_union_type: +// return true; +// } +// return false; +//} +// +static AccessType +DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility) +{ + switch (dwarf_accessibility) + { + case DW_ACCESS_public: return eAccessPublic; + case DW_ACCESS_private: return eAccessPrivate; + case DW_ACCESS_protected: return eAccessProtected; + default: break; + } + return eAccessNone; +} + +#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) + +class DIEStack +{ +public: + + void Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) + { + m_dies.push_back (DIEInfo(cu, die)); + } + + + void LogDIEs (Log *log, SymbolFileDWARF *dwarf) + { + StreamString log_strm; + const size_t n = m_dies.size(); + log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n); + for (size_t i=0; i<n; i++) + { + DWARFCompileUnit *cu = m_dies[i].cu; + const DWARFDebugInfoEntry *die = m_dies[i].die; + std::string qualified_name; + die->GetQualifiedName(dwarf, cu, qualified_name); + log_strm.Printf ("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n", + (uint64_t)i, + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + qualified_name.c_str()); + } + log->PutCString(log_strm.GetData()); + } + void Pop () + { + m_dies.pop_back(); + } + + class ScopedPopper + { + public: + ScopedPopper (DIEStack &die_stack) : + m_die_stack (die_stack), + m_valid (false) + { + } + + void + Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) + { + m_valid = true; + m_die_stack.Push (cu, die); + } + + ~ScopedPopper () + { + if (m_valid) + m_die_stack.Pop(); + } + + + + protected: + DIEStack &m_die_stack; + bool m_valid; + }; + +protected: + struct DIEInfo { + DIEInfo (DWARFCompileUnit *c, const DWARFDebugInfoEntry *d) : + cu(c), + die(d) + { + } + DWARFCompileUnit *cu; + const DWARFDebugInfoEntry *die; + }; + typedef std::vector<DIEInfo> Stack; + Stack m_dies; +}; +#endif + +void +SymbolFileDWARF::Initialize() +{ + LogChannelDWARF::Initialize(); + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +SymbolFileDWARF::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); + LogChannelDWARF::Initialize(); +} + + +lldb_private::ConstString +SymbolFileDWARF::GetPluginNameStatic() +{ + static ConstString g_name("dwarf"); + return g_name; +} + +const char * +SymbolFileDWARF::GetPluginDescriptionStatic() +{ + return "DWARF and DWARF3 debug symbol file reader."; +} + + +SymbolFile* +SymbolFileDWARF::CreateInstance (ObjectFile* obj_file) +{ + return new SymbolFileDWARF(obj_file); +} + +TypeList * +SymbolFileDWARF::GetTypeList () +{ + if (GetDebugMapSymfile ()) + return m_debug_map_symfile->GetTypeList(); + return m_obj_file->GetModule()->GetTypeList(); + +} +void +SymbolFileDWARF::GetTypes (DWARFCompileUnit* cu, + const DWARFDebugInfoEntry *die, + dw_offset_t min_die_offset, + dw_offset_t max_die_offset, + uint32_t type_mask, + TypeSet &type_set) +{ + if (cu) + { + if (die) + { + const dw_offset_t die_offset = die->GetOffset(); + + if (die_offset >= max_die_offset) + return; + + if (die_offset >= min_die_offset) + { + const dw_tag_t tag = die->Tag(); + + bool add_type = false; + + switch (tag) + { + case DW_TAG_array_type: add_type = (type_mask & eTypeClassArray ) != 0; break; + case DW_TAG_unspecified_type: + case DW_TAG_base_type: add_type = (type_mask & eTypeClassBuiltin ) != 0; break; + case DW_TAG_class_type: add_type = (type_mask & eTypeClassClass ) != 0; break; + case DW_TAG_structure_type: add_type = (type_mask & eTypeClassStruct ) != 0; break; + case DW_TAG_union_type: add_type = (type_mask & eTypeClassUnion ) != 0; break; + case DW_TAG_enumeration_type: add_type = (type_mask & eTypeClassEnumeration ) != 0; break; + case DW_TAG_subroutine_type: + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: add_type = (type_mask & eTypeClassFunction ) != 0; break; + case DW_TAG_pointer_type: add_type = (type_mask & eTypeClassPointer ) != 0; break; + case DW_TAG_rvalue_reference_type: + case DW_TAG_reference_type: add_type = (type_mask & eTypeClassReference ) != 0; break; + case DW_TAG_typedef: add_type = (type_mask & eTypeClassTypedef ) != 0; break; + case DW_TAG_ptr_to_member_type: add_type = (type_mask & eTypeClassMemberPointer ) != 0; break; + } + + if (add_type) + { + const bool assert_not_being_parsed = true; + Type *type = ResolveTypeUID (cu, die, assert_not_being_parsed); + if (type) + { + if (type_set.find(type) == type_set.end()) + type_set.insert(type); + } + } + } + + for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); + child_die != NULL; + child_die = child_die->GetSibling()) + { + GetTypes (cu, child_die, min_die_offset, max_die_offset, type_mask, type_set); + } + } + } +} + +size_t +SymbolFileDWARF::GetTypes (SymbolContextScope *sc_scope, + uint32_t type_mask, + TypeList &type_list) + +{ + TypeSet type_set; + + CompileUnit *comp_unit = NULL; + DWARFCompileUnit* dwarf_cu = NULL; + if (sc_scope) + comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); + + if (comp_unit) + { + dwarf_cu = GetDWARFCompileUnit(comp_unit); + if (dwarf_cu == 0) + return 0; + GetTypes (dwarf_cu, + dwarf_cu->DIE(), + dwarf_cu->GetOffset(), + dwarf_cu->GetNextCompileUnitOffset(), + type_mask, + type_set); + } + else + { + DWARFDebugInfo* info = DebugInfo(); + if (info) + { + const size_t num_cus = info->GetNumCompileUnits(); + for (size_t cu_idx=0; cu_idx<num_cus; ++cu_idx) + { + dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); + if (dwarf_cu) + { + GetTypes (dwarf_cu, + dwarf_cu->DIE(), + 0, + UINT32_MAX, + type_mask, + type_set); + } + } + } + } +// if (m_using_apple_tables) +// { +// DWARFMappedHash::MemoryTable *apple_types = m_apple_types_ap.get(); +// if (apple_types) +// { +// apple_types->ForEach([this, &type_set, apple_types, type_mask](const DWARFMappedHash::DIEInfoArray &die_info_array) -> bool { +// +// for (auto die_info: die_info_array) +// { +// bool add_type = TagMatchesTypeMask (type_mask, 0); +// if (!add_type) +// { +// dw_tag_t tag = die_info.tag; +// if (tag == 0) +// { +// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_info.offset, NULL); +// tag = die->Tag(); +// } +// add_type = TagMatchesTypeMask (type_mask, tag); +// } +// if (add_type) +// { +// Type *type = ResolveTypeUID(die_info.offset); +// +// if (type_set.find(type) == type_set.end()) +// type_set.insert(type); +// } +// } +// return true; // Keep iterating +// }); +// } +// } +// else +// { +// if (!m_indexed) +// Index (); +// +// m_type_index.ForEach([this, &type_set, type_mask](const char *name, uint32_t die_offset) -> bool { +// +// bool add_type = TagMatchesTypeMask (type_mask, 0); +// +// if (!add_type) +// { +// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_offset, NULL); +// if (die) +// { +// const dw_tag_t tag = die->Tag(); +// add_type = TagMatchesTypeMask (type_mask, tag); +// } +// } +// +// if (add_type) +// { +// Type *type = ResolveTypeUID(die_offset); +// +// if (type_set.find(type) == type_set.end()) +// type_set.insert(type); +// } +// return true; // Keep iterating +// }); +// } + + std::set<ClangASTType> clang_type_set; + size_t num_types_added = 0; + for (Type *type : type_set) + { + ClangASTType clang_type = type->GetClangForwardType(); + if (clang_type_set.find(clang_type) == clang_type_set.end()) + { + clang_type_set.insert(clang_type); + type_list.Insert (type->shared_from_this()); + ++num_types_added; + } + } + return num_types_added; +} + + +//---------------------------------------------------------------------- +// 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* objfile) : + SymbolFile (objfile), + UserID (0), // Used by SymbolFileDWARFDebugMap to when this class parses .o files to contain the .o file index/ID + m_debug_map_module_wp (), + m_debug_map_symfile (NULL), + m_clang_tu_decl (NULL), + 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_ranges (), + m_data_debug_str (), + m_data_apple_names (), + m_data_apple_types (), + m_data_apple_namespaces (), + m_abbr(), + m_info(), + m_line(), + m_apple_names_ap (), + m_apple_types_ap (), + m_apple_namespaces_ap (), + m_apple_objc_ap (), + m_function_basename_index(), + m_function_fullname_index(), + m_function_method_index(), + m_function_selector_index(), + m_objc_class_selectors_index(), + m_global_index(), + m_type_index(), + m_namespace_index(), + m_indexed (false), + m_is_external_ast_source (false), + m_using_apple_tables (false), + m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate), + m_ranges(), + m_unique_ast_type_map () +{ +} + +SymbolFileDWARF::~SymbolFileDWARF() +{ + if (m_is_external_ast_source) + { + ModuleSP module_sp (m_obj_file->GetModule()); + if (module_sp) + module_sp->GetClangASTContext().RemoveExternalSource (); + } +} + +static const ConstString & +GetDWARFMachOSegmentName () +{ + static ConstString g_dwarf_section_name ("__DWARF"); + return g_dwarf_section_name; +} + +UniqueDWARFASTTypeMap & +SymbolFileDWARF::GetUniqueDWARFASTTypeMap () +{ + if (GetDebugMapSymfile ()) + return m_debug_map_symfile->GetUniqueDWARFASTTypeMap (); + return m_unique_ast_type_map; +} + +ClangASTContext & +SymbolFileDWARF::GetClangASTContext () +{ + if (GetDebugMapSymfile ()) + return m_debug_map_symfile->GetClangASTContext (); + + ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext(); + if (!m_is_external_ast_source) + { + m_is_external_ast_source = true; + llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap ( + new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl, + SymbolFileDWARF::CompleteObjCInterfaceDecl, + SymbolFileDWARF::FindExternalVisibleDeclsByName, + SymbolFileDWARF::LayoutRecordType, + this)); + ast.SetExternalSource (ast_source_ap); + } + return ast; +} + +void +SymbolFileDWARF::InitializeObject() +{ + // Install our external AST source callbacks so we can complete Clang types. + ModuleSP module_sp (m_obj_file->GetModule()); + if (module_sp) + { + const SectionList *section_list = module_sp->GetSectionList(); + + const Section* section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); + + // Memory map the DWARF mach-o segment so we have everything mmap'ed + // to keep our heap memory usage down. + if (section) + m_obj_file->MemoryMapSectionData(section, m_dwarf_data); + } + get_apple_names_data(); + if (m_data_apple_names.GetByteSize() > 0) + { + m_apple_names_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_names, get_debug_str_data(), ".apple_names")); + if (m_apple_names_ap->IsValid()) + m_using_apple_tables = true; + else + m_apple_names_ap.reset(); + } + get_apple_types_data(); + if (m_data_apple_types.GetByteSize() > 0) + { + m_apple_types_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_types, get_debug_str_data(), ".apple_types")); + if (m_apple_types_ap->IsValid()) + m_using_apple_tables = true; + else + m_apple_types_ap.reset(); + } + + get_apple_namespaces_data(); + if (m_data_apple_namespaces.GetByteSize() > 0) + { + m_apple_namespaces_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_namespaces, get_debug_str_data(), ".apple_namespaces")); + if (m_apple_namespaces_ap->IsValid()) + m_using_apple_tables = true; + else + m_apple_namespaces_ap.reset(); + } + + get_apple_objc_data(); + if (m_data_apple_objc.GetByteSize() > 0) + { + m_apple_objc_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_objc, get_debug_str_data(), ".apple_objc")); + if (m_apple_objc_ap->IsValid()) + m_using_apple_tables = true; + else + m_apple_objc_ap.reset(); + } +} + +bool +SymbolFileDWARF::SupportedVersion(uint16_t version) +{ + return version == 2 || version == 3 || version == 4; +} + +uint32_t +SymbolFileDWARF::CalculateAbilities () +{ + 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_info_file_size = 0; + uint64_t debug_line_file_size = 0; + + section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); + + if (section) + section_list = §ion->GetChildren (); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugInfo, true).get(); + if (section != NULL) + { + debug_info_file_size = section->GetFileSize(); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugAbbrev, true).get(); + if (section) + debug_abbrev_file_size = section->GetFileSize(); + else + m_flags.Set (flagsGotDebugAbbrevData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugAranges, true).get(); + if (!section) + m_flags.Set (flagsGotDebugArangesData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugFrame, true).get(); + if (!section) + m_flags.Set (flagsGotDebugFrameData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugLine, true).get(); + if (section) + debug_line_file_size = section->GetFileSize(); + else + m_flags.Set (flagsGotDebugLineData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugLoc, true).get(); + if (!section) + m_flags.Set (flagsGotDebugLocData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugMacInfo, true).get(); + if (!section) + m_flags.Set (flagsGotDebugMacInfoData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubNames, true).get(); + if (!section) + m_flags.Set (flagsGotDebugPubNamesData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubTypes, true).get(); + if (!section) + m_flags.Set (flagsGotDebugPubTypesData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugRanges, true).get(); + if (!section) + m_flags.Set (flagsGotDebugRangesData); + + section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get(); + if (!section) + m_flags.Set (flagsGotDebugStrData); + } + else + { + const char *symfile_dir_cstr = m_obj_file->GetFileSpec().GetDirectory().GetCString(); + if (symfile_dir_cstr) + { + if (strcasestr(symfile_dir_cstr, ".dsym")) + { + if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo) + { + // We have a dSYM file that didn't have a any debug info. + // If the string table has a size of 1, then it was made from + // an executable with no debug info, or from an executable that + // was stripped. + section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get(); + if (section && section->GetFileSize() == 1) + { + m_obj_file->GetModule()->ReportWarning ("empty dSYM file detected, dSYM was created with an executable with no debug info."); + } + } + } + } + } + + 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; + } + return abilities; +} + +const DataExtractor& +SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, SectionType sect_type, DataExtractor &data) +{ + if (m_flags.IsClear (got_flag)) + { + ModuleSP module_sp (m_obj_file->GetModule()); + m_flags.Set (got_flag); + const SectionList *section_list = module_sp->GetSectionList(); + if (section_list) + { + SectionSP section_sp (section_list->FindSectionByType(sect_type, true)); + if (section_sp) + { + // See if we memory mapped the DWARF segment? + if (m_dwarf_data.GetByteSize()) + { + data.SetData(m_dwarf_data, section_sp->GetOffset (), section_sp->GetFileSize()); + } + else + { + if (m_obj_file->ReadSectionData (section_sp.get(), data) == 0) + data.Clear(); + } + } + } + } + return data; +} + +const DataExtractor& +SymbolFileDWARF::get_debug_abbrev_data() +{ + return GetCachedSectionData (flagsGotDebugAbbrevData, eSectionTypeDWARFDebugAbbrev, m_data_debug_abbrev); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_aranges_data() +{ + return GetCachedSectionData (flagsGotDebugArangesData, eSectionTypeDWARFDebugAranges, m_data_debug_aranges); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_frame_data() +{ + return GetCachedSectionData (flagsGotDebugFrameData, eSectionTypeDWARFDebugFrame, m_data_debug_frame); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_info_data() +{ + return GetCachedSectionData (flagsGotDebugInfoData, eSectionTypeDWARFDebugInfo, m_data_debug_info); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_line_data() +{ + return GetCachedSectionData (flagsGotDebugLineData, eSectionTypeDWARFDebugLine, m_data_debug_line); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_loc_data() +{ + return GetCachedSectionData (flagsGotDebugLocData, eSectionTypeDWARFDebugLoc, m_data_debug_loc); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_ranges_data() +{ + return GetCachedSectionData (flagsGotDebugRangesData, eSectionTypeDWARFDebugRanges, m_data_debug_ranges); +} + +const DataExtractor& +SymbolFileDWARF::get_debug_str_data() +{ + return GetCachedSectionData (flagsGotDebugStrData, eSectionTypeDWARFDebugStr, m_data_debug_str); +} + +const DataExtractor& +SymbolFileDWARF::get_apple_names_data() +{ + return GetCachedSectionData (flagsGotAppleNamesData, eSectionTypeDWARFAppleNames, m_data_apple_names); +} + +const DataExtractor& +SymbolFileDWARF::get_apple_types_data() +{ + return GetCachedSectionData (flagsGotAppleTypesData, eSectionTypeDWARFAppleTypes, m_data_apple_types); +} + +const DataExtractor& +SymbolFileDWARF::get_apple_namespaces_data() +{ + return GetCachedSectionData (flagsGotAppleNamespacesData, eSectionTypeDWARFAppleNamespaces, m_data_apple_namespaces); +} + +const DataExtractor& +SymbolFileDWARF::get_apple_objc_data() +{ + return GetCachedSectionData (flagsGotAppleObjCData, eSectionTypeDWARFAppleObjC, m_data_apple_objc); +} + + +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(); +} + + +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(); +} + +DWARFCompileUnit* +SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) +{ + DWARFDebugInfo* info = DebugInfo(); + if (info) + { + if (GetDebugMapSymfile ()) + { + // The debug map symbol file made the compile units for this DWARF + // file which is .o file with DWARF in it, and we should have + // only 1 compile unit which is at offset zero in the DWARF. + // TODO: modify to support LTO .o files where each .o file might + // have multiple DW_TAG_compile_unit tags. + return info->GetCompileUnit(0).get(); + } + else + { + // Just a normal DWARF file whose user ID for the compile unit is + // the DWARF offset itself + return info->GetCompileUnit((dw_offset_t)comp_unit->GetID()).get(); + } + } + return NULL; +} + + +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(); +} + +lldb::CompUnitSP +SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) +{ + CompUnitSP cu_sp; + if (dwarf_cu) + { + CompileUnit *comp_unit = (CompileUnit*)dwarf_cu->GetUserData(); + if (comp_unit) + { + // We already parsed this compile unit, had out a shared pointer to it + cu_sp = comp_unit->shared_from_this(); + } + else + { + if (GetDebugMapSymfile ()) + { + // Let the debug map create the compile unit + cu_sp = m_debug_map_symfile->GetCompileUnit(this); + dwarf_cu->SetUserData(cu_sp.get()); + } + else + { + ModuleSP module_sp (m_obj_file->GetModule()); + if (module_sp) + { + const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly (); + if (cu_die) + { + const char * cu_die_name = cu_die->GetName(this, dwarf_cu); + const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL); + LanguageType cu_language = (LanguageType)cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0); + if (cu_die_name) + { + std::string ramapped_file; + FileSpec cu_file_spec; + + if (cu_die_name[0] == '/' || cu_comp_dir == NULL || cu_comp_dir[0] == '\0') + { + // If we have a full path to the compile unit, we don't need to resolve + // the file. This can be expensive e.g. when the source files are NFS mounted. + if (module_sp->RemapSourceFile(cu_die_name, ramapped_file)) + cu_file_spec.SetFile (ramapped_file.c_str(), false); + else + cu_file_spec.SetFile (cu_die_name, false); + } + else + { + std::string fullpath(cu_comp_dir); + if (*fullpath.rbegin() != '/') + fullpath += '/'; + fullpath += cu_die_name; + if (module_sp->RemapSourceFile (fullpath.c_str(), ramapped_file)) + cu_file_spec.SetFile (ramapped_file.c_str(), false); + else + cu_file_spec.SetFile (fullpath.c_str(), false); + } + + cu_sp.reset(new CompileUnit (module_sp, + dwarf_cu, + cu_file_spec, + MakeUserID(dwarf_cu->GetOffset()), + cu_language)); + if (cu_sp) + { + dwarf_cu->SetUserData(cu_sp.get()); + + // Figure out the compile unit index if we weren't given one + if (cu_idx == UINT32_MAX) + DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx); + + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp); + } + } + } + } + } + } + } + return cu_sp; +} + +uint32_t +SymbolFileDWARF::GetNumCompileUnits() +{ + DWARFDebugInfo* info = DebugInfo(); + if (info) + return info->GetNumCompileUnits(); + return 0; +} + +CompUnitSP +SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) +{ + CompUnitSP cu_sp; + DWARFDebugInfo* info = DebugInfo(); + if (info) + { + DWARFCompileUnit* dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); + if (dwarf_cu) + cu_sp = ParseCompileUnit(dwarf_cu, cu_idx); + } + return cu_sp; +} + +static void +AddRangesToBlock (Block& block, + DWARFDebugRanges::RangeList& ranges, + addr_t block_base_addr) +{ + const size_t num_ranges = ranges.GetSize(); + for (size_t i = 0; i<num_ranges; ++i) + { + const DWARFDebugRanges::Range &range = ranges.GetEntryRef (i); + const addr_t range_base = range.GetRangeBase(); + assert (range_base >= block_base_addr); + block.AddRange(Block::Range (range_base - block_base_addr, range.GetByteSize()));; + } + block.FinalizeRanges (); +} + + +Function * +SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, 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; + + assert (die->Tag() == DW_TAG_subprogram); + + if (die->Tag() != DW_TAG_subprogram) + return NULL; + + 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.GetMinRangeBase (0); + lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd (0); + if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr) + { + ModuleSP module_sp (m_obj_file->GetModule()); + func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, module_sp->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(ConstString(mangled), true); + else if (name) + func_name.SetValue(ConstString(name), false); + + FunctionSP func_sp; + std::unique_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)); + + // Supply the type _only_ if it has already been parsed + Type *func_type = m_die_to_type.lookup (die); + + assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); + + if (FixupAddress (func_range.GetBaseAddress())) + { + const user_id_t func_user_id = MakeUserID(die->GetOffset()); + func_sp.reset(new Function (sc.comp_unit, + MakeUserID(func_user_id), // UserID is the DIE offset + MakeUserID(func_user_id), + func_name, + func_type, + func_range)); // first address range + + if (func_sp.get() != NULL) + { + if (frame_base.IsValid()) + func_sp->GetFrameBaseExpression() = frame_base; + sc.comp_unit->AddFunction(func_sp); + return func_sp.get(); + } + } + } + } + return NULL; +} + +bool +SymbolFileDWARF::FixupAddress (Address &addr) +{ + SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile (); + if (debug_map_symfile) + { + return debug_map_symfile->LinkOSOAddress(addr); + } + // This is a normal DWARF file, no address fixups need to happen + return true; +} +lldb::LanguageType +SymbolFileDWARF::ParseCompileUnitLanguage (const SymbolContext& sc) +{ + assert (sc.comp_unit); + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + { + const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly(); + if (die) + { + const uint32_t language = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0); + if (language) + return (lldb::LanguageType)language; + } + } + return eLanguageTypeUnknown; +} + +size_t +SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) +{ + assert (sc.comp_unit); + size_t functions_added = 0; + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + { + DWARFDIECollection function_dies; + const size_t num_functions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies); + size_t func_idx; + for (func_idx = 0; func_idx < num_functions; ++func_idx) + { + const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx); + if (sc.comp_unit->FindFunctionByUID (MakeUserID(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* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + { + const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + + if (cu_die) + { + const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL); + dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_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(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files); + } + } + return false; +} + +struct ParseDWARFLineTableCallbackInfo +{ + LineTable* line_table; + std::unique_ptr<LineSequence> sequence_ap; +}; + +//---------------------------------------------------------------------- +// ParseStatementTableCallback +//---------------------------------------------------------------------- +static void +ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData) +{ + 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; + LineTable* line_table = info->line_table; + + // If this is our first time here, we need to create a + // sequence container. + if (!info->sequence_ap.get()) + { + info->sequence_ap.reset(line_table->CreateLineSequenceContainer()); + assert(info->sequence_ap.get()); + } + line_table->AppendLineEntryToSequence (info->sequence_ap.get(), + state.address, + state.line, + state.column, + state.file, + state.is_stmt, + state.basic_block, + state.prologue_end, + state.epilogue_begin, + state.end_sequence); + if (state.end_sequence) + { + // First, put the current sequence into the line table. + line_table->InsertSequence(info->sequence_ap.get()); + // Then, empty it to prepare for the next sequence. + info->sequence_ap->Clear(); + } + } +} + +bool +SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc) +{ + assert (sc.comp_unit); + if (sc.comp_unit->GetLineTable() != NULL) + return true; + + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + { + const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + if (dwarf_cu_die) + { + 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::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit)); + if (line_table_ap.get()) + { + ParseDWARFLineTableCallbackInfo info; + info.line_table = line_table_ap.get(); + lldb::offset_t offset = cu_line_offset; + DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info); + if (m_debug_map_symfile) + { + // We have an object file that has a line table with addresses + // that are not linked. We need to link the line table and convert + // the addresses that are relative to the .o file into addresses + // for the main executable. + sc.comp_unit->SetLineTable (m_debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get())); + } + else + { + sc.comp_unit->SetLineTable(line_table_ap.release()); + return true; + } + } + } + } + } + return false; +} + +size_t +SymbolFileDWARF::ParseFunctionBlocks +( + const SymbolContext& sc, + Block *parent_block, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + addr_t subprogram_low_pc, + uint32_t depth +) +{ + size_t blocks_added = 0; + while (die != NULL) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + { + Block *block = NULL; + if (tag == DW_TAG_subprogram) + { + // Skip any DW_TAG_subprogram DIEs that are inside + // of a normal or inlined functions. These will be + // parsed on their own as separate entities. + + if (depth > 0) + break; + + block = parent_block; + } + else + { + BlockSP block_sp(new Block (MakeUserID(die->GetOffset()))); + parent_block->AddChild(block_sp); + block = block_sp.get(); + } + DWARFDebugRanges::RangeList ranges; + const char *name = NULL; + const char *mangled_name = 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; + 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.GetMinRangeBase(0); + } + else if (tag == DW_TAG_inlined_subroutine) + { + // We get called here for inlined subroutines in two ways. + // The first time is when we are making the Function object + // for this inlined concrete instance. Since we're creating a top level block at + // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we need to + // adjust the containing address. + // The second time is when we are parsing the blocks inside the function that contains + // the inlined concrete instance. Since these will be blocks inside the containing "real" + // function the offset will be for that function. + if (subprogram_low_pc == LLDB_INVALID_ADDRESS) + { + subprogram_low_pc = ranges.GetMinRangeBase(0); + } + } + + AddRangesToBlock (*block, ranges, subprogram_low_pc); + + if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL)) + { + std::unique_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::unique_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)); + + block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get()); + } + + ++blocks_added; + + if (die->HasChildren()) + { + blocks_added += ParseFunctionBlocks (sc, + block, + dwarf_cu, + die->GetFirstChild(), + subprogram_low_pc, + depth + 1); + } + } + } + break; + default: + break; + } + + // Only parse siblings of the block if we are not at depth zero. A depth + // of zero indicates we are currently parsing the top level + // DW_TAG_subprogram DIE + + if (depth == 0) + die = NULL; + else + die = die->GetSibling(); + } + return blocks_added; +} + +bool +SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + const dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_template_type_parameter: + case DW_TAG_template_value_parameter: + { + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes (this, + dwarf_cu, + fixed_form_sizes, + attributes); + const char *name = NULL; + Type *lldb_type = NULL; + ClangASTType clang_type; + uint64_t uval64 = 0; + bool uval64_valid = false; + if (num_attributes > 0) + { + DWARFFormValue form_value; + for (size_t i=0; i<num_attributes; ++i) + { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + + switch (attr) + { + case DW_AT_name: + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + name = form_value.AsCString(&get_debug_str_data()); + break; + + case DW_AT_type: + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu); + lldb_type = ResolveTypeUID(type_die_offset); + if (lldb_type) + clang_type = lldb_type->GetClangForwardType(); + } + break; + + case DW_AT_const_value: + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + uval64_valid = true; + uval64 = form_value.Unsigned(); + } + break; + default: + break; + } + } + + clang::ASTContext *ast = GetClangASTContext().getASTContext(); + if (!clang_type) + clang_type = GetClangASTContext().GetBasicType(eBasicTypeVoid); + + if (clang_type) + { + bool is_signed = false; + if (name && name[0]) + template_param_infos.names.push_back(name); + else + template_param_infos.names.push_back(NULL); + + if (tag == DW_TAG_template_value_parameter && + lldb_type != NULL && + clang_type.IsIntegerType (is_signed) && + uval64_valid) + { + llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed); + template_param_infos.args.push_back (clang::TemplateArgument (*ast, + llvm::APSInt(apint), + clang_type.GetQualType())); + } + else + { + template_param_infos.args.push_back (clang::TemplateArgument (clang_type.GetQualType())); + } + } + else + { + return false; + } + + } + } + return true; + + default: + break; + } + return false; +} + +bool +SymbolFileDWARF::ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + + if (parent_die == NULL) + return false; + + Args template_parameter_names; + for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); + die != NULL; + die = die->GetSibling()) + { + const dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_template_type_parameter: + case DW_TAG_template_value_parameter: + ParseTemplateDIE (dwarf_cu, die, template_param_infos); + break; + + default: + break; + } + } + if (template_param_infos.args.empty()) + return false; + return template_param_infos.args.size() == template_param_infos.names.size(); +} + +clang::ClassTemplateDecl * +SymbolFileDWARF::ParseClassTemplateDecl (clang::DeclContext *decl_ctx, + lldb::AccessType access_type, + const char *parent_name, + int tag_decl_kind, + const ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + if (template_param_infos.IsValid()) + { + std::string template_basename(parent_name); + template_basename.erase (template_basename.find('<')); + ClangASTContext &ast = GetClangASTContext(); + + return ast.CreateClassTemplateDecl (decl_ctx, + access_type, + template_basename.c_str(), + tag_decl_kind, + template_param_infos); + } + return NULL; +} + +class SymbolFileDWARF::DelayedAddObjCClassProperty +{ +public: + DelayedAddObjCClassProperty + ( + const ClangASTType &class_opaque_type, + const char *property_name, + const ClangASTType &property_opaque_type, // The property type is only required if you don't have an ivar decl + clang::ObjCIvarDecl *ivar_decl, + const char *property_setter_name, + const char *property_getter_name, + uint32_t property_attributes, + const ClangASTMetadata *metadata + ) : + m_class_opaque_type (class_opaque_type), + m_property_name (property_name), + m_property_opaque_type (property_opaque_type), + m_ivar_decl (ivar_decl), + m_property_setter_name (property_setter_name), + m_property_getter_name (property_getter_name), + m_property_attributes (property_attributes) + { + if (metadata != NULL) + { + m_metadata_ap.reset(new ClangASTMetadata()); + *m_metadata_ap = *metadata; + } + } + + DelayedAddObjCClassProperty (const DelayedAddObjCClassProperty &rhs) + { + *this = rhs; + } + + DelayedAddObjCClassProperty& operator= (const DelayedAddObjCClassProperty &rhs) + { + m_class_opaque_type = rhs.m_class_opaque_type; + m_property_name = rhs.m_property_name; + m_property_opaque_type = rhs.m_property_opaque_type; + m_ivar_decl = rhs.m_ivar_decl; + m_property_setter_name = rhs.m_property_setter_name; + m_property_getter_name = rhs.m_property_getter_name; + m_property_attributes = rhs.m_property_attributes; + + if (rhs.m_metadata_ap.get()) + { + m_metadata_ap.reset (new ClangASTMetadata()); + *m_metadata_ap = *rhs.m_metadata_ap; + } + return *this; + } + + bool + Finalize() + { + return m_class_opaque_type.AddObjCClassProperty (m_property_name, + m_property_opaque_type, + m_ivar_decl, + m_property_setter_name, + m_property_getter_name, + m_property_attributes, + m_metadata_ap.get()); + } +private: + ClangASTType m_class_opaque_type; + const char *m_property_name; + ClangASTType m_property_opaque_type; + clang::ObjCIvarDecl *m_ivar_decl; + const char *m_property_setter_name; + const char *m_property_getter_name; + uint32_t m_property_attributes; + std::unique_ptr<ClangASTMetadata> m_metadata_ap; +}; + +struct BitfieldInfo +{ + uint64_t bit_size; + uint64_t bit_offset; + + BitfieldInfo () : + bit_size (LLDB_INVALID_ADDRESS), + bit_offset (LLDB_INVALID_ADDRESS) + { + } + + bool IsValid () + { + return (bit_size != LLDB_INVALID_ADDRESS) && + (bit_offset != LLDB_INVALID_ADDRESS); + } +}; + + +bool +SymbolFileDWARF::ClassOrStructIsVirtual (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die) +{ + if (parent_die) + { + for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + dw_tag_t tag = die->Tag(); + bool check_virtuality = false; + switch (tag) + { + case DW_TAG_inheritance: + case DW_TAG_subprogram: + check_virtuality = true; + break; + default: + break; + } + if (check_virtuality) + { + if (die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_virtuality, 0) != 0) + return true; + } + } + } + return false; +} + +size_t +SymbolFileDWARF::ParseChildMembers +( + const SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + ClangASTType &class_clang_type, + const LanguageType class_language, + std::vector<clang::CXXBaseSpecifier *>& base_classes, + std::vector<int>& member_accessibilities, + DWARFDIECollection& member_function_dies, + DelayedPropertyList& delayed_properties, + AccessType& default_accessibility, + bool &is_a_class, + LayoutInfo &layout_info +) +{ + if (parent_die == NULL) + return 0; + + size_t count = 0; + const DWARFDebugInfoEntry *die; + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + uint32_t member_idx = 0; + BitfieldInfo last_field_info; + + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_member: + case DW_TAG_APPLE_property: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes (this, + dwarf_cu, + fixed_form_sizes, + attributes); + if (num_attributes > 0) + { + Declaration decl; + //DWARFExpression location; + const char *name = NULL; + const char *prop_name = NULL; + const char *prop_getter_name = NULL; + const char *prop_setter_name = NULL; + uint32_t prop_attributes = 0; + + + bool is_artificial = false; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + AccessType accessibility = eAccessNone; + uint32_t member_byte_offset = UINT32_MAX; + size_t byte_size = 0; + size_t bit_offset = 0; + size_t bit_size = 0; + bool is_external = false; // On DW_TAG_members, this means the member is static + uint32_t i; + for (i=0; i<num_attributes && !is_artificial; ++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, // ExecutionContext * + NULL, // ClangExpressionVariableList * + NULL, // ClangExpressionDeclMap * + NULL, // RegisterContext * + debug_info_data, + block_offset, + block_length, + eRegisterKindDWARF, + &initialValue, + memberOffset, + NULL)) + { + member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); + } + } + else + { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning + // of the containing entity. + member_byte_offset = form_value.Unsigned(); + } + break; + + case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType (form_value.Unsigned()); break; + case DW_AT_artificial: is_artificial = form_value.Boolean(); break; + case DW_AT_APPLE_property_name: prop_name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_APPLE_property_getter: prop_getter_name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_APPLE_property_setter: prop_setter_name = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_APPLE_property_attribute: prop_attributes = form_value.Unsigned(); break; + case DW_AT_external: is_external = form_value.Boolean(); break; + + default: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_mutable: + case DW_AT_visibility: + case DW_AT_sibling: + break; + } + } + } + + if (prop_name) + { + ConstString fixed_getter; + ConstString fixed_setter; + + // Check if the property getter/setter were provided as full + // names. We want basenames, so we extract them. + + if (prop_getter_name && prop_getter_name[0] == '-') + { + ObjCLanguageRuntime::MethodName prop_getter_method(prop_getter_name, true); + prop_getter_name = prop_getter_method.GetSelector().GetCString(); + } + + if (prop_setter_name && prop_setter_name[0] == '-') + { + ObjCLanguageRuntime::MethodName prop_setter_method(prop_setter_name, true); + prop_setter_name = prop_setter_method.GetSelector().GetCString(); + } + + // If the names haven't been provided, they need to be + // filled in. + + if (!prop_getter_name) + { + prop_getter_name = prop_name; + } + if (!prop_setter_name && prop_name[0] && !(prop_attributes & DW_APPLE_PROPERTY_readonly)) + { + StreamString ss; + + ss.Printf("set%c%s:", + toupper(prop_name[0]), + &prop_name[1]); + + fixed_setter.SetCString(ss.GetData()); + prop_setter_name = fixed_setter.GetCString(); + } + } + + // Clang has a DWARF generation bug where sometimes it + // represents fields that are references with bad byte size + // and bit size/offset information such as: + // + // DW_AT_byte_size( 0x00 ) + // DW_AT_bit_size( 0x40 ) + // DW_AT_bit_offset( 0xffffffffffffffc0 ) + // + // So check the bit offset to make sure it is sane, and if + // the values are not sane, remove them. If we don't do this + // then we will end up with a crash if we try to use this + // type in an expression when clang becomes unhappy with its + // recycled debug info. + + if (bit_offset > 128) + { + bit_size = 0; + bit_offset = 0; + } + + // FIXME: Make Clang ignore Objective-C accessibility for expressions + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + accessibility = eAccessNone; + + if (member_idx == 0 && !is_artificial && name && (strstr (name, "_vptr$") == name)) + { + // Not all compilers will mark the vtable pointer + // member as artificial (llvm-gcc). We can't have + // the virtual members in our classes otherwise it + // throws off all child offsets since we end up + // having and extra pointer sized member in our + // class layouts. + is_artificial = true; + } + + // Handle static members + if (is_external && member_byte_offset == UINT32_MAX) + { + Type *var_type = ResolveTypeUID(encoding_uid); + + if (var_type) + { + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + class_clang_type.AddVariableToRecordType (name, + var_type->GetClangLayoutType(), + accessibility); + } + break; + } + + if (is_artificial == false) + { + Type *member_type = ResolveTypeUID(encoding_uid); + + clang::FieldDecl *field_decl = NULL; + if (tag == DW_TAG_member) + { + if (member_type) + { + if (accessibility == eAccessNone) + accessibility = default_accessibility; + member_accessibilities.push_back(accessibility); + + BitfieldInfo this_field_info; + + this_field_info.bit_size = bit_size; + + if (member_byte_offset != UINT32_MAX || bit_size != 0) + { + ///////////////////////////////////////////////////////////// + // How to locate a field given the DWARF debug information + // + // AT_byte_size indicates the size of the word in which the + // bit offset must be interpreted. + // + // AT_data_member_location indicates the byte offset of the + // word from the base address of the structure. + // + // AT_bit_offset indicates how many bits into the word + // (according to the host endianness) the low-order bit of + // the field starts. AT_bit_offset can be negative. + // + // AT_bit_size indicates the size of the field in bits. + ///////////////////////////////////////////////////////////// + + this_field_info.bit_offset = 0; + + this_field_info.bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + + if (GetObjectFile()->GetByteOrder() == eByteOrderLittle) + { + this_field_info.bit_offset += byte_size * 8; + this_field_info.bit_offset -= (bit_offset + bit_size); + } + else + { + this_field_info.bit_offset += bit_offset; + } + } + + // If the member to be emitted did not start on a character boundary and there is + // empty space between the last field and this one, then we need to emit an + // anonymous member filling up the space up to its start. There are three cases + // here: + // + // 1 If the previous member ended on a character boundary, then we can emit an + // anonymous member starting at the most recent character boundary. + // + // 2 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is less than a + // word width, then we can emit an anonymous member starting right after the + // previous member and right before this member. + // + // 3 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is greater than + // or equal a word width, then we act as in Case 1. + + const uint64_t character_width = 8; + const uint64_t word_width = 32; + + if (this_field_info.IsValid()) + { + // Objective-C has invalid DW_AT_bit_offset values in older versions + // of clang, so we have to be careful and only insert unnammed bitfields + // if we have a new enough clang. + bool detect_unnamed_bitfields = true; + + if (class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus) + detect_unnamed_bitfields = dwarf_cu->Supports_unnamed_objc_bitfields (); + + if (detect_unnamed_bitfields) + { + BitfieldInfo anon_field_info; + + if ((this_field_info.bit_offset % character_width) != 0) // not char aligned + { + uint64_t last_field_end = 0; + + if (last_field_info.IsValid()) + last_field_end = last_field_info.bit_offset + last_field_info.bit_size; + + if (this_field_info.bit_offset != last_field_end) + { + if (((last_field_end % character_width) == 0) || // case 1 + (this_field_info.bit_offset - last_field_end >= word_width)) // case 3 + { + anon_field_info.bit_size = this_field_info.bit_offset % character_width; + anon_field_info.bit_offset = this_field_info.bit_offset - anon_field_info.bit_size; + } + else // case 2 + { + anon_field_info.bit_size = this_field_info.bit_offset - last_field_end; + anon_field_info.bit_offset = last_field_end; + } + } + } + + if (anon_field_info.IsValid()) + { + clang::FieldDecl *unnamed_bitfield_decl = class_clang_type.AddFieldToRecordType (NULL, + GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width), + accessibility, + anon_field_info.bit_size); + + layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset)); + } + } + } + + ClangASTType member_clang_type = member_type->GetClangLayoutType(); + + { + // Older versions of clang emit array[0] and array[1] in the same way (<rdar://problem/12566646>). + // If the current field is at the end of the structure, then there is definitely no room for extra + // elements and we override the type to array[0]. + + ClangASTType member_array_element_type; + uint64_t member_array_size; + bool member_array_is_incomplete; + + if (member_clang_type.IsArrayType(&member_array_element_type, + &member_array_size, + &member_array_is_incomplete) && + !member_array_is_incomplete) + { + uint64_t parent_byte_size = parent_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, UINT64_MAX); + + if (member_byte_offset >= parent_byte_size) + { + if (member_array_size != 1) + { + GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64, + MakeUserID(die->GetOffset()), + name, + encoding_uid, + MakeUserID(parent_die->GetOffset())); + } + + member_clang_type = GetClangASTContext().CreateArrayType(member_array_element_type, 0, false); + } + } + } + + field_decl = class_clang_type.AddFieldToRecordType (name, + member_clang_type, + accessibility, + bit_size); + + GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset())); + + if (this_field_info.IsValid()) + { + layout_info.field_offsets.insert(std::make_pair(field_decl, this_field_info.bit_offset)); + last_field_info = this_field_info; + } + } + else + { + if (name) + GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which was unable to be parsed", + MakeUserID(die->GetOffset()), + name, + encoding_uid); + else + GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8" PRIx64 " which was unable to be parsed", + MakeUserID(die->GetOffset()), + encoding_uid); + } + } + + if (prop_name != NULL) + { + clang::ObjCIvarDecl *ivar_decl = NULL; + + if (field_decl) + { + ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); + assert (ivar_decl != NULL); + } + + ClangASTMetadata metadata; + metadata.SetUserID (MakeUserID(die->GetOffset())); + delayed_properties.push_back(DelayedAddObjCClassProperty(class_clang_type, + prop_name, + member_type->GetClangLayoutType(), + ivar_decl, + prop_setter_name, + prop_getter_name, + prop_attributes, + &metadata)); + + if (ivar_decl) + GetClangASTContext().SetMetadataAsUserID (ivar_decl, MakeUserID(die->GetOffset())); + } + } + } + ++member_idx; + } + break; + + case DW_TAG_subprogram: + // Let the type parsing code handle this one for us. + member_function_dies.Append (die); + break; + + case DW_TAG_inheritance: + { + is_a_class = true; + if (default_accessibility == eAccessNone) + default_accessibility = eAccessPrivate; + // TODO: implement DW_TAG_inheritance type parsing + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes (this, + dwarf_cu, + fixed_form_sizes, + attributes); + if (num_attributes > 0) + { + Declaration decl; + DWARFExpression location; + lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + AccessType accessibility = default_accessibility; + bool is_virtual = false; + bool is_base_of_class = true; + off_t member_byte_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, + NULL, + NULL, + debug_info_data, + block_offset, + block_length, + eRegisterKindDWARF, + &initialValue, + memberOffset, + NULL)) + { + member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); + } + } + else + { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning + // of the containing entity. + member_byte_offset = form_value.Unsigned(); + } + break; + + case DW_AT_accessibility: + accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); + break; + + case DW_AT_virtuality: + is_virtual = form_value.Boolean(); + break; + + case DW_AT_sibling: + break; + + default: + break; + } + } + } + + Type *base_class_type = ResolveTypeUID(encoding_uid); + assert(base_class_type); + + ClangASTType base_class_clang_type = base_class_type->GetClangFullType(); + assert (base_class_clang_type); + if (class_language == eLanguageTypeObjC) + { + class_clang_type.SetObjCSuperClass(base_class_clang_type); + } + else + { + base_classes.push_back (base_class_clang_type.CreateBaseClassSpecifier (accessibility, + is_virtual, + is_base_of_class)); + + if (is_virtual) + { + layout_info.vbase_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(), + clang::CharUnits::fromQuantity(member_byte_offset))); + } + else + { + layout_info.base_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(), + clang::CharUnits::fromQuantity(member_byte_offset))); + } + } + } + } + break; + + default: + break; + } + } + + return count; +} + + +clang::DeclContext* +SymbolFileDWARF::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid) +{ + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info && UserIDMatches(type_uid)) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp); + if (die) + return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL); + } + return NULL; +} + +clang::DeclContext* +SymbolFileDWARF::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid) +{ + if (UserIDMatches(type_uid)) + return GetClangDeclContextForDIEOffset (sc, type_uid); + return NULL; +} + +Type* +SymbolFileDWARF::ResolveTypeUID (lldb::user_id_t type_uid) +{ + if (UserIDMatches(type_uid)) + { + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, &cu_sp); + const bool assert_not_being_parsed = true; + return ResolveTypeUID (cu_sp.get(), type_die, assert_not_being_parsed); + } + } + return NULL; +} + +Type* +SymbolFileDWARF::ResolveTypeUID (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed) +{ + if (die != NULL) + { + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log) + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, cu)); + + // We might be coming in in the middle of a type tree (a class + // withing a class, an enum within a class), so parse any needed + // parent DIEs before we get to this one... + const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die); + switch (decl_ctx_die->Tag()) + { + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + { + // Get the type, which could be a forward declaration + if (log) + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent forward type for 0x%8.8x", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, cu), + decl_ctx_die->GetOffset()); +// +// Type *parent_type = ResolveTypeUID (cu, decl_ctx_die, assert_not_being_parsed); +// if (child_requires_parent_class_union_or_struct_to_be_completed(die->Tag())) +// { +// if (log) +// GetObjectFile()->GetModule()->LogMessage (log, +// "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent full type for 0x%8.8x since die is a function", +// die->GetOffset(), +// DW_TAG_value_to_name(die->Tag()), +// die->GetName(this, cu), +// decl_ctx_die->GetOffset()); +// // Ask the type to complete itself if it already hasn't since if we +// // want a function (method or static) from a class, the class must +// // create itself and add it's own methods and class functions. +// if (parent_type) +// parent_type->GetClangFullType(); +// } + } + break; + + default: + break; + } + return ResolveType (cu, die); + } + return NULL; +} + +// This function is used when SymbolFileDWARFDebugMap owns a bunch of +// SymbolFileDWARF objects to detect if this DWARF file is the one that +// can resolve a clang_type. +bool +SymbolFileDWARF::HasForwardDeclForClangType (const ClangASTType &clang_type) +{ + ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers(); + const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType()); + return die != NULL; +} + + +bool +SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) +{ + // We have a struct/union/class/enum that needs to be fully resolved. + ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers(); + const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType()); + if (die == NULL) + { + // We have already resolved this type... + return true; + } + // Once we start resolving this type, remove it from the forward declaration + // map in case anyone child members or other types require this type to get resolved. + // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition + // are done. + m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType()); + + + // Disable external storage for this type so we don't get anymore + // clang::ExternalASTSource queries for this type. + clang_type.SetHasExternalStorage (false); + + DWARFDebugInfo* debug_info = DebugInfo(); + + DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIE (die->GetOffset()).get(); + Type *type = m_die_to_type.lookup (die); + + const dw_tag_t tag = die->Tag(); + + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); + if (log) + { + GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, + "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", + MakeUserID(die->GetOffset()), + DW_TAG_value_to_name(tag), + type->GetName().AsCString()); + + } + assert (clang_type); + DWARFDebugInfoEntry::Attributes attributes; + + switch (tag) + { + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + { + LayoutInfo layout_info; + + { + if (die->HasChildren()) + { + + LanguageType class_language = eLanguageTypeUnknown; + if (clang_type.IsObjCObjectOrInterfaceType()) + { + class_language = eLanguageTypeObjC; + // For objective C we don't start the definition when + // the class is created. + clang_type.StartTagDeclarationDefinition (); + } + + int tag_decl_kind = -1; + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) + { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = eAccessPublic; + } + else if (tag == DW_TAG_union_type) + { + tag_decl_kind = clang::TTK_Union; + default_accessibility = eAccessPublic; + } + else if (tag == DW_TAG_class_type) + { + tag_decl_kind = clang::TTK_Class; + default_accessibility = eAccessPrivate; + } + + SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); + std::vector<clang::CXXBaseSpecifier *> base_classes; + std::vector<int> member_accessibilities; + bool is_a_class = false; + // Parse members and base classes first + DWARFDIECollection member_function_dies; + + DelayedPropertyList delayed_properties; + ParseChildMembers (sc, + dwarf_cu, + die, + clang_type, + class_language, + base_classes, + member_accessibilities, + member_function_dies, + delayed_properties, + default_accessibility, + is_a_class, + layout_info); + + // Now parse any methods if there were any... + size_t num_functions = member_function_dies.Size(); + if (num_functions > 0) + { + for (size_t i=0; i<num_functions; ++i) + { + ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i)); + } + } + + if (class_language == eLanguageTypeObjC) + { + std::string class_str (clang_type.GetTypeName()); + if (!class_str.empty()) + { + + DIEArray method_die_offsets; + if (m_using_apple_tables) + { + if (m_apple_objc_ap.get()) + m_apple_objc_ap->FindByName(class_str.c_str(), method_die_offsets); + } + else + { + if (!m_indexed) + Index (); + + ConstString class_name (class_str.c_str()); + m_objc_class_selectors_index.Find (class_name, method_die_offsets); + } + + if (!method_die_offsets.empty()) + { + DWARFDebugInfo* debug_info = DebugInfo(); + + DWARFCompileUnit* method_cu = NULL; + const size_t num_matches = method_die_offsets.size(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = method_die_offsets[i]; + DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu); + + if (method_die) + ResolveType (method_cu, method_die); + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_objc accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, class_str.c_str()); + } + } + } + } + + for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end(); + pi != pe; + ++pi) + pi->Finalize(); + } + } + + // 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 (class_language != eLanguageTypeObjC) + { + if (is_a_class && tag_decl_kind != clang::TTK_Class) + clang_type.SetTagTypeKind (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. + clang_type.SetDefaultAccessForRecordFields (eAccessPrivate, + &member_accessibilities.front(), + member_accessibilities.size()); + } + + if (!base_classes.empty()) + { + clang_type.SetBaseClassesForClassType (&base_classes.front(), + base_classes.size()); + + // Clang will copy each CXXBaseSpecifier in "base_classes" + // so we have to free them all. + ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(), + base_classes.size()); + } + } + } + + clang_type.BuildIndirectFields (); + clang_type.CompleteTagDeclarationDefinition (); + + if (!layout_info.field_offsets.empty() || + !layout_info.base_offsets.empty() || + !layout_info.vbase_offsets.empty() ) + { + if (type) + layout_info.bit_size = type->GetByteSize() * 8; + if (layout_info.bit_size == 0) + layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8; + + clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl(); + if (record_decl) + { + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])", + clang_type.GetOpaqueQualType(), + record_decl, + layout_info.bit_size, + layout_info.alignment, + (uint32_t)layout_info.field_offsets.size(), + (uint32_t)layout_info.base_offsets.size(), + (uint32_t)layout_info.vbase_offsets.size()); + + uint32_t idx; + { + llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end(); + for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }", + clang_type.GetOpaqueQualType(), + idx, + (uint32_t)pos->second, + pos->first->getNameAsString().c_str()); + } + } + + { + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end(); + for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] = { byte_offset=%u, name='%s' }", + clang_type.GetOpaqueQualType(), + idx, + (uint32_t)base_pos->second.getQuantity(), + base_pos->first->getNameAsString().c_str()); + } + } + { + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos, vbase_end = layout_info.vbase_offsets.end(); + for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end; ++vbase_pos, ++idx) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }", + clang_type.GetOpaqueQualType(), + idx, + (uint32_t)vbase_pos->second.getQuantity(), + vbase_pos->first->getNameAsString().c_str()); + } + } + } + m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info)); + } + } + } + + return clang_type; + + case DW_TAG_enumeration_type: + clang_type.StartTagDeclarationDefinition (); + if (die->HasChildren()) + { + SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); + bool is_signed = false; + clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), dwarf_cu, die); + } + clang_type.CompleteTagDeclarationDefinition (); + return clang_type; + + default: + assert(false && "not a forward clang type decl!"); + break; + } + return false; +} + +Type* +SymbolFileDWARF::ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed) +{ + if (type_die != NULL) + { + Type *type = m_die_to_type.lookup (type_die); + + if (type == NULL) + type = GetTypeForDIE (dwarf_cu, type_die).get(); + + if (assert_not_being_parsed) + { + if (type != DIE_IS_BEING_PARSED) + return type; + + GetObjectFile()->GetModule()->ReportError ("Parsing a die that is being parsed die: 0x%8.8x: %s %s", + type_die->GetOffset(), + DW_TAG_value_to_name(type_die->Tag()), + type_die->GetName(this, dwarf_cu)); + + } + else + return type; + } + return NULL; +} + +CompileUnit* +SymbolFileDWARF::GetCompUnitForDWARFCompUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) +{ + // Check if the symbol vendor already knows about this compile unit? + if (dwarf_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. + return ParseCompileUnit(dwarf_cu, cu_idx).get(); + } + return (CompileUnit*)dwarf_cu->GetUserData(); +} + +bool +SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc) +{ + sc.Clear(false); + // Check if the symbol vendor already knows about this compile unit? + sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); + + sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(func_die->GetOffset())).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, dwarf_cu, func_die); + + if (sc.function) + { + sc.module_sp = sc.function->CalculateSymbolContextModule(); + return true; + } + + return false; +} + +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%" PRIx64 " }, resolve_scope = 0x%8.8x)", + so_addr.GetSection().get(), + 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(); + + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr); + if (cu_offset != DW_INVALID_OFFSET) + { + uint32_t cu_idx = DW_INVALID_INDEX; + DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get(); + if (dwarf_cu) + { + sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); + if (sc.comp_unit) + { + resolved |= eSymbolContextCompUnit; + + bool force_check_line_table = false; + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) + { + DWARFDebugInfoEntry *function_die = NULL; + DWARFDebugInfoEntry *block_die = NULL; + if (resolve_scope & eSymbolContextBlock) + { + dwarf_cu->LookupAddress(file_vm_addr, &function_die, &block_die); + } + else + { + dwarf_cu->LookupAddress(file_vm_addr, &function_die, NULL); + } + + if (function_die != NULL) + { + sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die); + } + else + { + // We might have had a compile unit that had discontiguous + // address ranges where the gaps are symbols that don't have + // any debug info. Discontiguous compile unit address ranges + // should only happen when there aren't other functions from + // other compile units in these gaps. This helps keep the size + // of the aranges down. + force_check_line_table = true; + } + + if (sc.function != NULL) + { + resolved |= eSymbolContextFunction; + + if (resolve_scope & eSymbolContextBlock) + { + Block& block = sc.function->GetBlock (true); + + if (block_die != NULL) + sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset())); + else + sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset())); + if (sc.block) + resolved |= eSymbolContextBlock; + } + } + } + + if ((resolve_scope & eSymbolContextLineEntry) || force_check_line_table) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table != NULL) + { + // And address that makes it into this function should be in terms + // of this debug file if there is no debug map, or it will be an + // address in the .o file which needs to be fixed up to be in terms + // of the debug map executable. Either way, calling FixupAddress() + // will work for us. + Address exe_so_addr (so_addr); + if (FixupAddress(exe_so_addr)) + { + if (line_table->FindLineEntryByAddress (exe_so_addr, sc.line_entry)) + { + resolved |= eSymbolContextLineEntry; + } + } + } + } + + if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) + { + // We might have had a compile unit that had discontiguous + // address ranges where the gaps are symbols that don't have + // any debug info. Discontiguous compile unit address ranges + // should only happen when there aren't other functions from + // other compile units in these gaps. This helps keep the size + // of the aranges down. + sc.comp_unit = NULL; + resolved &= ~eSymbolContextCompUnit; + } + } + else + { + GetObjectFile()->GetModule()->ReportWarning ("0x%8.8x: compile unit %u failed to create a valid lldb_private::CompileUnit class.", + cu_offset, + cu_idx); + } + } + } + } + } + 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* dwarf_cu = NULL; + + for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx) + { + CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); + const bool full_match = file_spec.GetDirectory(); + bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Equal(file_spec, *dc_cu, full_match); + if (check_inlines || file_spec_matches_cu_file_spec) + { + SymbolContext sc (m_obj_file->GetModule()); + sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); + if (sc.comp_unit) + { + 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, true); + 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, true); + + 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 != UINT32_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; + dwarf_cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL); + + if (function_die != NULL) + { + sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get(); + if (sc.function == NULL) + sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die); + } + + if (sc.function != NULL) + { + Block& block = sc.function->GetBlock (true); + + if (block_die != NULL) + sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset())); + else + sc.block = block.FindBlockByID (MakeUserID(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* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + + bool clear_dies = dwarf_cu->ExtractDIEsIfNeeded (false) > 1; + + dwarf_cu->Index (cu_idx, + m_function_basename_index, + m_function_fullname_index, + m_function_method_index, + m_function_selector_index, + m_objc_class_selectors_index, + m_global_index, + m_type_index, + m_namespace_index); + + // Keep memory down by clearing DIEs if this generate function + // caused them to be parsed + if (clear_dies) + dwarf_cu->ClearDIEs (true); + } + + m_function_basename_index.Finalize(); + m_function_fullname_index.Finalize(); + m_function_method_index.Finalize(); + m_function_selector_index.Finalize(); + m_objc_class_selectors_index.Finalize(); + m_global_index.Finalize(); + m_type_index.Finalize(); + m_namespace_index.Finalize(); + +#if defined (ENABLE_DEBUG_PRINTF) + StreamFile s(stdout, false); + s.Printf ("DWARF index for '%s':", + GetObjectFile()->GetFileSpec().GetPath().c_str()); + s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s); + s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s); + s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s); + s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s); + s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s); + s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s); + s.Printf("\nTypes:\n"); m_type_index.Dump (&s); + s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s); +#endif + } +} + +bool +SymbolFileDWARF::NamespaceDeclMatchesThisSymbolFile (const ClangNamespaceDecl *namespace_decl) +{ + if (namespace_decl == NULL) + { + // Invalid namespace decl which means we aren't matching only things + // in this symbol file, so return true to indicate it matches this + // symbol file. + return true; + } + + clang::ASTContext *namespace_ast = namespace_decl->GetASTContext(); + + if (namespace_ast == NULL) + return true; // No AST in the "namespace_decl", return true since it + // could then match any symbol file, including this one + + if (namespace_ast == GetClangASTContext().getASTContext()) + return true; // The ASTs match, return true + + // The namespace AST was valid, and it does not match... + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + GetObjectFile()->GetModule()->LogMessage(log, "Valid namespace does not match symbol file"); + + return false; +} + +bool +SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl, + DWARFCompileUnit* cu, + const DWARFDebugInfoEntry* die) +{ + // No namespace specified, so the answesr i + if (namespace_decl == NULL) + return true; + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + const DWARFDebugInfoEntry *decl_ctx_die = NULL; + clang::DeclContext *die_clang_decl_ctx = GetClangDeclContextContainingDIE (cu, die, &decl_ctx_die); + if (decl_ctx_die) + { + clang::NamespaceDecl *clang_namespace_decl = namespace_decl->GetNamespaceDecl(); + + if (clang_namespace_decl) + { + if (decl_ctx_die->Tag() != DW_TAG_namespace) + { + if (log) + GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent is not a namespace"); + return false; + } + + if (clang_namespace_decl == die_clang_decl_ctx) + return true; + else + return false; + } + else + { + // We have a namespace_decl that was not NULL but it contained + // a NULL "clang::NamespaceDecl", so this means the global namespace + // So as long the the contained decl context DIE isn't a namespace + // we should be ok. + if (decl_ctx_die->Tag() != DW_TAG_namespace) + return true; + } + } + + if (log) + GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent doesn't exist"); + + return false; +} +uint32_t +SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables) +{ + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)", + name.GetCString(), + namespace_decl, + append, + max_matches); + } + + if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) + return 0; + + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + + // 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(); + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_names_ap.get()) + { + const char *name_cstr = name.GetCString(); + const char *base_name_start; + const char *base_name_end = NULL; + + if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end)) + base_name_start = name_cstr; + + m_apple_names_ap->FindByName (base_name_start, die_offsets); + } + } + else + { + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + m_global_index.Find (name, die_offsets); + } + + const size_t num_die_matches = die_offsets.size(); + if (num_die_matches) + { + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + assert (sc.module_sp); + + DWARFDebugInfo* debug_info = DebugInfo(); + DWARFCompileUnit* dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + bool done = false; + for (size_t i=0; i<num_die_matches && !done; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + + if (die) + { + switch (die->Tag()) + { + default: + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_try_block: + case DW_TAG_catch_block: + break; + + case DW_TAG_variable: + { + sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); + + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables); + + if (variables.GetSize() - original_size >= max_matches) + done = true; + } + break; + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, name.GetCString()); + } + } + } + } + + // Return the number of variable that were appended to the list + const uint32_t num_matches = variables.GetSize() - original_size; + if (log && num_matches > 0) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u", + name.GetCString(), + namespace_decl, + append, + max_matches, + num_matches); + } + return num_matches; +} + +uint32_t +SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) +{ + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)", + regex.GetText(), + append, + max_matches); + } + + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + + // 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(); + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_names_ap.get()) + { + DWARFMappedHash::DIEInfoArray hash_data_array; + if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex (regex, hash_data_array)) + DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); + } + } + else + { + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + m_global_index.Find (regex, die_offsets); + } + + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + assert (sc.module_sp); + + DWARFCompileUnit* dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + const size_t num_matches = die_offsets.size(); + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + + if (die) + { + sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); + + ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables); + + if (variables.GetSize() - original_size >= max_matches) + break; + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for regex '%s')\n", + die_offset, regex.GetText()); + } + } + } + } + + // Return the number of variable that were appended to the list + return variables.GetSize() - original_size; +} + + +bool +SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset, + DWARFCompileUnit *&dwarf_cu, + SymbolContextList& sc_list) +{ + const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + return ResolveFunction (dwarf_cu, die, sc_list); +} + + +bool +SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + SymbolContextList& sc_list) +{ + SymbolContext sc; + + if (die == NULL) + return false; + + // If we were passed a die that is not a function, just return false... + if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine) + return false; + + const DWARFDebugInfoEntry* inlined_die = NULL; + if (die->Tag() == DW_TAG_inlined_subroutine) + { + inlined_die = die; + + while ((die = die->GetParent()) != NULL) + { + if (die->Tag() == DW_TAG_subprogram) + break; + } + } + assert (die->Tag() == DW_TAG_subprogram); + if (GetFunction (cu, die, sc)) + { + Address addr; + // Parse all blocks if needed + if (inlined_die) + { + sc.block = sc.function->GetBlock (true).FindBlockByID (MakeUserID(inlined_die->GetOffset())); + assert (sc.block != NULL); + if (sc.block->GetStartAddress (addr) == false) + addr.Clear(); + } + else + { + sc.block = NULL; + addr = sc.function->GetAddressRange().GetBaseAddress(); + } + + if (addr.IsValid()) + { + sc_list.Append(sc); + return true; + } + } + + return false; +} + +void +SymbolFileDWARF::FindFunctions (const ConstString &name, + const NameToDIE &name_to_die, + SymbolContextList& sc_list) +{ + DIEArray die_offsets; + if (name_to_die.Find (name, die_offsets)) + { + ParseFunctions (die_offsets, sc_list); + } +} + + +void +SymbolFileDWARF::FindFunctions (const RegularExpression ®ex, + const NameToDIE &name_to_die, + SymbolContextList& sc_list) +{ + DIEArray die_offsets; + if (name_to_die.Find (regex, die_offsets)) + { + ParseFunctions (die_offsets, sc_list); + } +} + + +void +SymbolFileDWARF::FindFunctions (const RegularExpression ®ex, + const DWARFMappedHash::MemoryTable &memory_table, + SymbolContextList& sc_list) +{ + DIEArray die_offsets; + DWARFMappedHash::DIEInfoArray hash_data_array; + if (memory_table.AppendAllDIEsThatMatchingRegex (regex, hash_data_array)) + { + DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); + ParseFunctions (die_offsets, sc_list); + } +} + +void +SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets, + SymbolContextList& sc_list) +{ + const size_t num_matches = die_offsets.size(); + if (num_matches) + { + SymbolContext sc; + + DWARFCompileUnit* dwarf_cu = NULL; + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + ResolveFunction (die_offset, dwarf_cu, sc_list); + } + } +} + +bool +SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die, + const DWARFCompileUnit *dwarf_cu, + uint32_t name_type_mask, + const char *partial_name, + const char *base_name_start, + const char *base_name_end) +{ + // If we are looking only for methods, throw away all the ones that are or aren't in C++ classes: + if (name_type_mask == eFunctionNameTypeMethod || name_type_mask == eFunctionNameTypeBase) + { + clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset()); + if (!containing_decl_ctx) + return false; + + bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()); + + if (name_type_mask == eFunctionNameTypeMethod) + { + if (is_cxx_method == false) + return false; + } + + if (name_type_mask == eFunctionNameTypeBase) + { + if (is_cxx_method == true) + return false; + } + } + + // Now we need to check whether the name we got back for this type matches the extra specifications + // that were in the name we're looking up: + if (base_name_start != partial_name || *base_name_end != '\0') + { + // First see if the stuff to the left matches the full name. To do that let's see if + // we can pull out the mips linkage name attribute: + + Mangled best_name; + DWARFDebugInfoEntry::Attributes attributes; + DWARFFormValue form_value; + die->GetAttributes(this, dwarf_cu, NULL, attributes); + uint32_t idx = attributes.FindAttributeIndex(DW_AT_MIPS_linkage_name); + if (idx == UINT32_MAX) + idx = attributes.FindAttributeIndex(DW_AT_linkage_name); + if (idx != UINT32_MAX) + { + if (attributes.ExtractFormValueAtIndex(this, idx, form_value)) + { + const char *mangled_name = form_value.AsCString(&get_debug_str_data()); + if (mangled_name) + best_name.SetValue (ConstString(mangled_name), true); + } + } + + if (!best_name) + { + idx = attributes.FindAttributeIndex(DW_AT_name); + if (idx != UINT32_MAX && attributes.ExtractFormValueAtIndex(this, idx, form_value)) + { + const char *name = form_value.AsCString(&get_debug_str_data()); + best_name.SetValue (ConstString(name), false); + } + } + + if (best_name.GetDemangledName()) + { + const char *demangled = best_name.GetDemangledName().GetCString(); + if (demangled) + { + std::string name_no_parens(partial_name, base_name_end - partial_name); + const char *partial_in_demangled = strstr (demangled, name_no_parens.c_str()); + if (partial_in_demangled == NULL) + return false; + else + { + // Sort out the case where our name is something like "Process::Destroy" and the match is + // "SBProcess::Destroy" - that shouldn't be a match. We should really always match on + // namespace boundaries... + + if (partial_name[0] == ':' && partial_name[1] == ':') + { + // The partial name was already on a namespace boundary so all matches are good. + return true; + } + else if (partial_in_demangled == demangled) + { + // They both start the same, so this is an good match. + return true; + } + else + { + if (partial_in_demangled - demangled == 1) + { + // Only one character difference, can't be a namespace boundary... + return false; + } + else if (*(partial_in_demangled - 1) == ':' && *(partial_in_demangled - 2) == ':') + { + // We are on a namespace boundary, so this is also good. + return true; + } + else + return false; + } + } + } + } + } + + return true; +} + +uint32_t +SymbolFileDWARF::FindFunctions (const ConstString &name, + const lldb_private::ClangNamespaceDecl *namespace_decl, + uint32_t name_type_mask, + bool include_inlines, + bool append, + SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARF::FindFunctions (name = '%s')", + name.AsCString()); + + // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup() + assert ((name_type_mask & eFunctionNameTypeAuto) == 0); + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list)", + name.GetCString(), + name_type_mask, + append); + } + + // If we aren't appending the results to this list, then clear the list + if (!append) + sc_list.Clear(); + + if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) + return 0; + + // If name is empty then we won't find anything. + if (name.IsEmpty()) + return 0; + + // Remember how many sc_list are in the list before we search in case + // we are appending the results to a variable list. + + const char *name_cstr = name.GetCString(); + + const uint32_t original_size = sc_list.GetSize(); + + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + + DWARFCompileUnit *dwarf_cu = NULL; + std::set<const DWARFDebugInfoEntry *> resolved_dies; + if (m_using_apple_tables) + { + if (m_apple_names_ap.get()) + { + + DIEArray die_offsets; + + uint32_t num_matches = 0; + + if (name_type_mask & eFunctionNameTypeFull) + { + // If they asked for the full name, match what they typed. At some point we may + // want to canonicalize this (strip double spaces, etc. For now, we just add all the + // dies that we find by exact match. + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + for (uint32_t i = 0; i < num_matches; i++) + { + const dw_offset_t die_offset = die_offsets[i]; + const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + if (die) + { + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } + } + else + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", + die_offset, name_cstr); + } + } + } + + if (name_type_mask & eFunctionNameTypeSelector) + { + if (namespace_decl && *namespace_decl) + return 0; // no selectors in namespaces + + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + // Now make sure these are actually ObjC methods. In this case we can simply look up the name, + // and if it is an ObjC method name, we're good. + + for (uint32_t i = 0; i < num_matches; i++) + { + const dw_offset_t die_offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + if (die) + { + const char *die_name = die->GetName(this, dwarf_cu); + if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name)) + { + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } + } + } + else + { + GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", + die_offset, name_cstr); + } + } + die_offsets.clear(); + } + + if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase) + { + // The apple_names table stores just the "base name" of C++ methods in the table. So we have to + // extract the base name, look that up, and if there is any other information in the name we were + // passed in we have to post-filter based on that. + + // FIXME: Arrange the logic above so that we don't calculate the base name twice: + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + + for (uint32_t i = 0; i < num_matches; i++) + { + const dw_offset_t die_offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + if (die) + { + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + // If we get to here, the die is good, and we should add it: + if (resolved_dies.find(die) == resolved_dies.end()) + if (ResolveFunction (dwarf_cu, die, sc_list)) + { + bool keep_die = true; + if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod)) + { + // We are looking for either basenames or methods, so we need to + // trim out the ones we won't want by looking at the type + SymbolContext sc; + if (sc_list.GetLastContext(sc)) + { + if (sc.block) + { + // We have an inlined function + } + else if (sc.function) + { + Type *type = sc.function->GetType(); + + clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID()); + if (decl_ctx->isRecord()) + { + if (name_type_mask & eFunctionNameTypeBase) + { + sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); + keep_die = false; + } + } + else + { + if (name_type_mask & eFunctionNameTypeMethod) + { + sc_list.RemoveContextAtIndex(sc_list.GetSize()-1); + keep_die = false; + } + } + } + } + } + if (keep_die) + resolved_dies.insert(die); + } + } + else + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')", + die_offset, name_cstr); + } + } + die_offsets.clear(); + } + } + } + else + { + + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + if (name_type_mask & eFunctionNameTypeFull) + { + FindFunctions (name, m_function_fullname_index, sc_list); + + // Temporary workaround for global/anonymous namespace functions on linux +#if defined (__linux__) + // If we didn't find any functions in the global namespace try + // looking in the basename index but ignore any returned + // functions that have a namespace (ie. mangled names starting with + // '_ZN') but keep functions which have an anonymous namespace + if (sc_list.GetSize() == 0) + { + SymbolContextList temp_sc_list; + FindFunctions (name, m_function_basename_index, temp_sc_list); + if (!namespace_decl) + { + SymbolContext sc; + for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++) + { + if (temp_sc_list.GetContextAtIndex(i, sc)) + { + ConstString mangled_name = sc.GetFunctionName(Mangled::ePreferMangled); + ConstString demangled_name = sc.GetFunctionName(Mangled::ePreferDemangled); + if (strncmp(mangled_name.GetCString(), "_ZN", 3) || + !strncmp(demangled_name.GetCString(), "(anonymous namespace)", 21)) + { + sc_list.Append(sc); + } + } + } + } + } +#endif + } + DIEArray die_offsets; + DWARFCompileUnit *dwarf_cu = NULL; + + if (name_type_mask & eFunctionNameTypeBase) + { + uint32_t num_base = m_function_basename_index.Find(name, die_offsets); + for (uint32_t i = 0; i < num_base; i++) + { + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); + if (die) + { + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + // If we get to here, the die is good, and we should add it: + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } + } + } + die_offsets.clear(); + } + + if (name_type_mask & eFunctionNameTypeMethod) + { + if (namespace_decl && *namespace_decl) + return 0; // no methods in namespaces + + uint32_t num_base = m_function_method_index.Find(name, die_offsets); + { + for (uint32_t i = 0; i < num_base; i++) + { + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); + if (die) + { + if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine) + continue; + + // If we get to here, the die is good, and we should add it: + if (resolved_dies.find(die) == resolved_dies.end()) + { + if (ResolveFunction (dwarf_cu, die, sc_list)) + resolved_dies.insert(die); + } + } + } + } + die_offsets.clear(); + } + + if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl)) + { + FindFunctions (name, m_function_selector_index, sc_list); + } + + } + + // Return the number of variable that were appended to the list + const uint32_t num_matches = sc_list.GetSize() - original_size; + + if (log && num_matches > 0) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list) => %u", + name.GetCString(), + name_type_mask, + append, + num_matches); + } + return num_matches; +} + +uint32_t +SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARF::FindFunctions (regex = '%s')", + regex.GetText()); + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindFunctions (regex=\"%s\", append=%u, sc_list)", + regex.GetText(), + append); + } + + + // 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(); + + if (m_using_apple_tables) + { + if (m_apple_names_ap.get()) + FindFunctions (regex, *m_apple_names_ap, sc_list); + } + else + { + // Index the DWARF if we haven't already + if (!m_indexed) + Index (); + + FindFunctions (regex, m_function_basename_index, sc_list); + + FindFunctions (regex, m_function_fullname_index, sc_list); + } + + // Return the number of variable that were appended to the list + return sc_list.GetSize() - original_size; +} + +uint32_t +SymbolFileDWARF::FindTypes (const SymbolContext& sc, + const ConstString &name, + const lldb_private::ClangNamespaceDecl *namespace_decl, + bool append, + uint32_t max_matches, + TypeList& types) +{ + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + if (namespace_decl) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)", + name.GetCString(), + namespace_decl->GetNamespaceDecl(), + namespace_decl->GetQualifiedName().c_str(), + append, + max_matches); + } + else + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)", + name.GetCString(), + append, + max_matches); + } + } + + // If we aren't appending the results to this list, then clear the list + if (!append) + types.Clear(); + + if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl)) + return 0; + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_types_ap.get()) + { + const char *name_cstr = name.GetCString(); + m_apple_types_ap->FindByName (name_cstr, die_offsets); + } + } + else + { + if (!m_indexed) + Index (); + + m_type_index.Find (name, die_offsets); + } + + const size_t num_die_matches = die_offsets.size(); + + if (num_die_matches) + { + const uint32_t initial_types_size = types.GetSize(); + DWARFCompileUnit* dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_die_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + + if (die) + { + if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die)) + continue; + + Type *matching_type = ResolveType (dwarf_cu, die); + if (matching_type) + { + // We found a type pointer, now find the shared pointer form our type list + types.InsertUnique (matching_type->shared_from_this()); + if (types.GetSize() >= max_matches) + break; + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, name.GetCString()); + } + } + + } + const uint32_t num_matches = types.GetSize() - initial_types_size; + if (log && num_matches) + { + if (namespace_decl) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u", + name.GetCString(), + namespace_decl->GetNamespaceDecl(), + namespace_decl->GetQualifiedName().c_str(), + append, + max_matches, + num_matches); + } + else + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u", + name.GetCString(), + append, + max_matches, + num_matches); + } + } + return num_matches; + } + return 0; +} + + +ClangNamespaceDecl +SymbolFileDWARF::FindNamespace (const SymbolContext& sc, + const ConstString &name, + const lldb_private::ClangNamespaceDecl *parent_namespace_decl) +{ + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindNamespace (sc, name=\"%s\")", + name.GetCString()); + } + + if (!NamespaceDeclMatchesThisSymbolFile(parent_namespace_decl)) + return ClangNamespaceDecl(); + + ClangNamespaceDecl namespace_decl; + DWARFDebugInfo* info = DebugInfo(); + if (info) + { + DIEArray die_offsets; + + // Index if we already haven't to make sure the compile units + // get indexed and make their global DIE index list + if (m_using_apple_tables) + { + if (m_apple_namespaces_ap.get()) + { + const char *name_cstr = name.GetCString(); + m_apple_namespaces_ap->FindByName (name_cstr, die_offsets); + } + } + else + { + if (!m_indexed) + Index (); + + m_namespace_index.Find (name, die_offsets); + } + + DWARFCompileUnit* dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + const size_t num_matches = die_offsets.size(); + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + + if (die) + { + if (parent_namespace_decl && !DIEIsInNamespace (parent_namespace_decl, dwarf_cu, die)) + continue; + + clang::NamespaceDecl *clang_namespace_decl = ResolveNamespaceDIE (dwarf_cu, die); + if (clang_namespace_decl) + { + namespace_decl.SetASTContext (GetClangASTContext().getASTContext()); + namespace_decl.SetNamespaceDecl (clang_namespace_decl); + break; + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_namespaces accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, name.GetCString()); + } + } + + } + } + } + if (log && namespace_decl.GetNamespaceDecl()) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"", + name.GetCString(), + namespace_decl.GetNamespaceDecl(), + namespace_decl.GetQualifiedName().c_str()); + } + + return namespace_decl; +} + +uint32_t +SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, 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.GetSize(); + + 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) + { + Type *matching_type = ResolveTypeUID (die_offsets[i]); + if (matching_type) + { + // We found a type pointer, now find the shared pointer form our type list + types.InsertUnique (matching_type->shared_from_this()); + ++num_matches; + if (num_matches >= max_matches) + break; + } + } + + // Return the number of variable that were appended to the list + return types.GetSize() - original_size; +} + + +size_t +SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, + clang::DeclContext *containing_decl_ctx, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + bool skip_artificial, + bool &is_static, + TypeList* type_list, + std::vector<ClangASTType>& function_param_types, + std::vector<clang::ParmVarDecl*>& function_param_decls, + unsigned &type_quals, + ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + if (parent_die == NULL) + return 0; + + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + + size_t arg_idx = 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, fixed_form_sizes, attributes); + if (num_attributes > 0) + { + const char *name = NULL; + Declaration decl; + dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; + bool is_artificial = false; + // one of None, Auto, Register, Extern, Static, PrivateExtern + + clang::StorageClass storage = clang::SC_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_artificial: is_artificial = form_value.Boolean(); 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_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; + } + } + } + + bool skip = false; + if (skip_artificial) + { + if (is_artificial) + { + // In order to determine if a C++ member function is + // "const" we have to look at the const-ness of "this"... + // Ugly, but that + if (arg_idx == 0) + { + if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind())) + { + // Often times compilers omit the "this" name for the + // specification DIEs, so we can't rely upon the name + // being in the formal parameter DIE... + if (name == NULL || ::strcmp(name, "this")==0) + { + Type *this_type = ResolveTypeUID (param_type_die_offset); + if (this_type) + { + uint32_t encoding_mask = this_type->GetEncodingMask(); + if (encoding_mask & Type::eEncodingIsPointerUID) + { + is_static = false; + + if (encoding_mask & (1u << Type::eEncodingIsConstUID)) + type_quals |= clang::Qualifiers::Const; + if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) + type_quals |= clang::Qualifiers::Volatile; + } + } + } + } + } + skip = true; + } + else + { + + // HACK: Objective C formal parameters "self" and "_cmd" + // are not marked as artificial in the DWARF... + CompileUnit *comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX); + if (comp_unit) + { + switch (comp_unit->GetLanguage()) + { + case eLanguageTypeObjC: + case eLanguageTypeObjC_plus_plus: + if (name && name[0] && (strcmp (name, "self") == 0 || strcmp (name, "_cmd") == 0)) + skip = true; + break; + default: + break; + } + } + } + } + + if (!skip) + { + Type *type = ResolveTypeUID(param_type_die_offset); + if (type) + { + function_param_types.push_back (type->GetClangForwardType()); + + clang::ParmVarDecl *param_var_decl = GetClangASTContext().CreateParameterDeclaration (name, + type->GetClangForwardType(), + storage); + assert(param_var_decl); + function_param_decls.push_back(param_var_decl); + + GetClangASTContext().SetMetadataAsUserID (param_var_decl, MakeUserID(die->GetOffset())); + } + } + } + arg_idx++; + } + break; + + case DW_TAG_template_type_parameter: + case DW_TAG_template_value_parameter: + ParseTemplateDIE (dwarf_cu, die,template_param_infos); + break; + + default: + break; + } + } + return arg_idx; +} + +size_t +SymbolFileDWARF::ParseChildEnumerators +( + const SymbolContext& sc, + lldb_private::ClangASTType &clang_type, + bool is_signed, + uint32_t enumerator_byte_size, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die +) +{ + if (parent_die == NULL) + return 0; + + size_t enumerators_added = 0; + const DWARFDebugInfoEntry *die; + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + + 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, fixed_form_sizes, 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; + if (is_signed) + enum_value = form_value.Signed(); + else + 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) + { + clang_type.AddEnumerationValueToEnumerationType (clang_type.GetEnumerationIntegerType(), + decl, + name, + enum_value, + enumerator_byte_size * 8); + ++enumerators_added; + } + } + } + } + return enumerators_added; +} + +void +SymbolFileDWARF::ParseChildArrayInfo +( + const SymbolContext& sc, + 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; + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) + { + const dw_tag_t tag = die->Tag(); + switch (tag) + { + case DW_TAG_subrange_type: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes); + if (num_child_attributes > 0) + { + uint64_t num_elements = 0; + uint64_t lower_bound = 0; + uint64_t upper_bound = 0; + bool upper_bound_valid = false; + 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_name: + 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_lower_bound: + lower_bound = form_value.Unsigned(); + break; + + case DW_AT_upper_bound: + upper_bound_valid = true; + upper_bound = form_value.Unsigned(); + break; + + default: + 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 (num_elements == 0) + { + if (upper_bound_valid && upper_bound >= lower_bound) + num_elements = upper_bound - lower_bound + 1; + } + + element_orders.push_back (num_elements); + } + } + break; + } + } +} + +TypeSP +SymbolFileDWARF::GetTypeForDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry* die) +{ + TypeSP type_sp; + if (die != NULL) + { + assert(dwarf_cu != NULL); + Type *type_ptr = m_die_to_type.lookup (die); + if (type_ptr == NULL) + { + CompileUnit* lldb_cu = GetCompUnitForDWARFCompUnit(dwarf_cu); + assert (lldb_cu); + SymbolContext sc(lldb_cu); + type_sp = ParseType(sc, dwarf_cu, die, NULL); + } + else if (type_ptr != DIE_IS_BEING_PARSED) + { + // Grab the existing type from the master types lists + type_sp = type_ptr->shared_from_this(); + } + + } + return type_sp; +} + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset) +{ + if (die_offset != DW_INVALID_OFFSET) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp); + return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL); + } + return NULL; +} + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextForDIEOffset (const SymbolContext &sc, dw_offset_t die_offset) +{ + if (die_offset != DW_INVALID_OFFSET) + { + DWARFDebugInfo* debug_info = DebugInfo(); + if (debug_info) + { + DWARFCompileUnitSP cu_sp; + const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(die_offset, &cu_sp); + if (die) + return GetClangDeclContextForDIE (sc, cu_sp.get(), die); + } + } + return NULL; +} + +clang::NamespaceDecl * +SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry *die) +{ + if (die && die->Tag() == DW_TAG_namespace) + { + // See if we already parsed this namespace DIE and associated it with a + // uniqued namespace declaration + clang::NamespaceDecl *namespace_decl = static_cast<clang::NamespaceDecl *>(m_die_to_decl_ctx[die]); + if (namespace_decl) + return namespace_decl; + else + { + const char *namespace_name = die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL); + clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, NULL); + namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, containing_decl_ctx); + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log) + { + if (namespace_name) + { + GetObjectFile()->GetModule()->LogMessage (log, + "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)", + GetClangASTContext().getASTContext(), + MakeUserID(die->GetOffset()), + namespace_name, + namespace_decl, + namespace_decl->getOriginalNamespace()); + } + else + { + GetObjectFile()->GetModule()->LogMessage (log, + "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)", + GetClangASTContext().getASTContext(), + MakeUserID(die->GetOffset()), + namespace_decl, + namespace_decl->getOriginalNamespace()); + } + } + + if (namespace_decl) + LinkDeclContextToDIE((clang::DeclContext*)namespace_decl, die); + return namespace_decl; + } + } + return NULL; +} + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextForDIE (const SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) +{ + clang::DeclContext *clang_decl_ctx = GetCachedClangDeclContextForDIE (die); + if (clang_decl_ctx) + return clang_decl_ctx; + // If this DIE has a specification, or an abstract origin, then trace to those. + + dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + return GetClangDeclContextForDIEOffset (sc, die_offset); + + die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + return GetClangDeclContextForDIEOffset (sc, die_offset); + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log) + GetObjectFile()->GetModule()->LogMessage(log, "SymbolFileDWARF::GetClangDeclContextForDIE (die = 0x%8.8x) %s '%s'", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), die->GetName(this, cu)); + // This is the DIE we want. Parse it, then query our map. + bool assert_not_being_parsed = true; + ResolveTypeUID (cu, die, assert_not_being_parsed); + + clang_decl_ctx = GetCachedClangDeclContextForDIE (die); + + return clang_decl_ctx; +} + +clang::DeclContext * +SymbolFileDWARF::GetClangDeclContextContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die, const DWARFDebugInfoEntry **decl_ctx_die_copy) +{ + if (m_clang_tu_decl == NULL) + m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl(); + + const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die); + + if (decl_ctx_die_copy) + *decl_ctx_die_copy = decl_ctx_die; + + if (decl_ctx_die) + { + + DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find (decl_ctx_die); + if (pos != m_die_to_decl_ctx.end()) + return pos->second; + + switch (decl_ctx_die->Tag()) + { + case DW_TAG_compile_unit: + return m_clang_tu_decl; + + case DW_TAG_namespace: + return ResolveNamespaceDIE (cu, decl_ctx_die); + break; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + { + Type* type = ResolveType (cu, decl_ctx_die); + if (type) + { + clang::DeclContext *decl_ctx = type->GetClangForwardType().GetDeclContextForType (); + if (decl_ctx) + { + LinkDeclContextToDIE (decl_ctx, decl_ctx_die); + if (decl_ctx) + return decl_ctx; + } + } + } + break; + + default: + break; + } + } + return m_clang_tu_decl; +} + + +const DWARFDebugInfoEntry * +SymbolFileDWARF::GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) +{ + if (cu && die) + { + const DWARFDebugInfoEntry * const decl_die = die; + + while (die != NULL) + { + // If this is the original DIE that we are searching for a declaration + // for, then don't look in the cache as we don't want our own decl + // context to be our decl context... + if (decl_die != die) + { + switch (die->Tag()) + { + case DW_TAG_compile_unit: + case DW_TAG_namespace: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + return die; + + default: + break; + } + } + + dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + DWARFCompileUnit *spec_cu = cu; + const DWARFDebugInfoEntry *spec_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &spec_cu); + const DWARFDebugInfoEntry *spec_die_decl_ctx_die = GetDeclContextDIEContainingDIE (spec_cu, spec_die); + if (spec_die_decl_ctx_die) + return spec_die_decl_ctx_die; + } + + die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + DWARFCompileUnit *abs_cu = cu; + const DWARFDebugInfoEntry *abs_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &abs_cu); + const DWARFDebugInfoEntry *abs_die_decl_ctx_die = GetDeclContextDIEContainingDIE (abs_cu, abs_die); + if (abs_die_decl_ctx_die) + return abs_die_decl_ctx_die; + } + + die = die->GetParent(); + } + } + return NULL; +} + + +Symbol * +SymbolFileDWARF::GetObjCClassSymbol (const ConstString &objc_class_name) +{ + Symbol *objc_class_symbol = NULL; + if (m_obj_file) + { + Symtab *symtab = m_obj_file->GetSymtab (); + if (symtab) + { + objc_class_symbol = symtab->FindFirstSymbolWithNameAndType (objc_class_name, + eSymbolTypeObjCClass, + Symtab::eDebugNo, + Symtab::eVisibilityAny); + } + } + return objc_class_symbol; +} + +// Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If they don't +// then we can end up looking through all class types for a complete type and never find +// the full definition. We need to know if this attribute is supported, so we determine +// this here and cache th result. We also need to worry about the debug map DWARF file +// if we are doing darwin DWARF in .o file debugging. +bool +SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu) +{ + if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) + { + m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; + if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type()) + m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; + else + { + DWARFDebugInfo* debug_info = DebugInfo(); + const uint32_t num_compile_units = GetNumCompileUnits(); + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) + { + m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; + break; + } + } + } + if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo && GetDebugMapSymfile ()) + return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type (this); + } + return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes; +} + +// This function can be used when a DIE is found that is a forward declaration +// DIE and we want to try and find a type that has the complete definition. +TypeSP +SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die, + const ConstString &type_name, + bool must_be_implementation) +{ + + TypeSP type_sp; + + if (!type_name || (must_be_implementation && !GetObjCClassSymbol (type_name))) + return type_sp; + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_types_ap.get()) + { + const char *name_cstr = type_name.GetCString(); + m_apple_types_ap->FindCompleteObjCClassByName (name_cstr, die_offsets, must_be_implementation); + } + } + else + { + if (!m_indexed) + Index (); + + m_type_index.Find (type_name, die_offsets); + } + + const size_t num_matches = die_offsets.size(); + + DWARFCompileUnit* type_cu = NULL; + const DWARFDebugInfoEntry* type_die = NULL; + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); + + if (type_die) + { + bool try_resolving_type = false; + + // Don't try and resolve the DIE we are looking for with the DIE itself! + if (type_die != die) + { + switch (type_die->Tag()) + { + case DW_TAG_class_type: + case DW_TAG_structure_type: + try_resolving_type = true; + break; + default: + break; + } + } + + if (try_resolving_type) + { + if (must_be_implementation && type_cu->Supports_DW_AT_APPLE_objc_complete_type()) + try_resolving_type = type_die->GetAttributeValueAsUnsigned (this, type_cu, DW_AT_APPLE_objc_complete_type, 0); + + if (try_resolving_type) + { + Type *resolved_type = ResolveType (type_cu, type_die, false); + if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) + { + DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", + MakeUserID(die->GetOffset()), + MakeUserID(dwarf_cu->GetOffset()), + m_obj_file->GetFileSpec().GetFilename().AsCString(), + MakeUserID(type_die->GetOffset()), + MakeUserID(type_cu->GetOffset())); + + if (die) + m_die_to_type[die] = resolved_type; + type_sp = resolved_type->shared_from_this(); + break; + } + } + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, type_name.GetCString()); + } + } + + } + } + return type_sp; +} + + +//---------------------------------------------------------------------- +// This function helps to ensure that the declaration contexts match for +// two different DIEs. Often times debug information will refer to a +// forward declaration of a type (the equivalent of "struct my_struct;". +// There will often be a declaration of that type elsewhere that has the +// full definition. When we go looking for the full type "my_struct", we +// will find one or more matches in the accelerator tables and we will +// then need to make sure the type was in the same declaration context +// as the original DIE. This function can efficiently compare two DIEs +// and will return true when the declaration context matches, and false +// when they don't. +//---------------------------------------------------------------------- +bool +SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1, + DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2) +{ + if (die1 == die2) + return true; + +#if defined (LLDB_CONFIGURATION_DEBUG) + // You can't and shouldn't call this function with a compile unit from + // two different SymbolFileDWARF instances. + assert (DebugInfo()->ContainsCompileUnit (cu1)); + assert (DebugInfo()->ContainsCompileUnit (cu2)); +#endif + + DWARFDIECollection decl_ctx_1; + DWARFDIECollection decl_ctx_2; + //The declaration DIE stack is a stack of the declaration context + // DIEs all the way back to the compile unit. If a type "T" is + // declared inside a class "B", and class "B" is declared inside + // a class "A" and class "A" is in a namespace "lldb", and the + // namespace is in a compile unit, there will be a stack of DIEs: + // + // [0] DW_TAG_class_type for "B" + // [1] DW_TAG_class_type for "A" + // [2] DW_TAG_namespace for "lldb" + // [3] DW_TAG_compile_unit for the source file. + // + // We grab both contexts and make sure that everything matches + // all the way back to the compiler unit. + + // First lets grab the decl contexts for both DIEs + die1->GetDeclContextDIEs (this, cu1, decl_ctx_1); + die2->GetDeclContextDIEs (this, cu2, decl_ctx_2); + // Make sure the context arrays have the same size, otherwise + // we are done + const size_t count1 = decl_ctx_1.Size(); + const size_t count2 = decl_ctx_2.Size(); + if (count1 != count2) + return false; + + // Make sure the DW_TAG values match all the way back up the the + // compile unit. If they don't, then we are done. + const DWARFDebugInfoEntry *decl_ctx_die1; + const DWARFDebugInfoEntry *decl_ctx_die2; + size_t i; + for (i=0; i<count1; i++) + { + decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i); + decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i); + if (decl_ctx_die1->Tag() != decl_ctx_die2->Tag()) + return false; + } +#if defined LLDB_CONFIGURATION_DEBUG + + // Make sure the top item in the decl context die array is always + // DW_TAG_compile_unit. If it isn't then something went wrong in + // the DWARFDebugInfoEntry::GetDeclContextDIEs() function... + assert (decl_ctx_1.GetDIEPtrAtIndex (count1 - 1)->Tag() == DW_TAG_compile_unit); + +#endif + // Always skip the compile unit when comparing by only iterating up to + // "count - 1". Here we compare the names as we go. + for (i=0; i<count1 - 1; i++) + { + decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i); + decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i); + const char *name1 = decl_ctx_die1->GetName(this, cu1); + const char *name2 = decl_ctx_die2->GetName(this, cu2); + // If the string was from a DW_FORM_strp, then the pointer will often + // be the same! + if (name1 == name2) + continue; + + // Name pointers are not equal, so only compare the strings + // if both are not NULL. + if (name1 && name2) + { + // If the strings don't compare, we are done... + if (strcmp(name1, name2) != 0) + return false; + } + else + { + // One name was NULL while the other wasn't + return false; + } + } + // We made it through all of the checks and the declaration contexts + // are equal. + return true; +} + +// This function can be used when a DIE is found that is a forward declaration +// DIE and we want to try and find a type that has the complete definition. +// "cu" and "die" must be from this SymbolFileDWARF +TypeSP +SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu, + const DWARFDebugInfoEntry *die, + const ConstString &type_name) +{ + TypeSP type_sp; + +#if defined (LLDB_CONFIGURATION_DEBUG) + // You can't and shouldn't call this function with a compile unit from + // another SymbolFileDWARF instance. + assert (DebugInfo()->ContainsCompileUnit (cu)); +#endif + + if (cu == NULL || die == NULL || !type_name) + return type_sp; + + std::string qualified_name; + + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS)); + if (log) + { + die->GetQualifiedName(this, cu, qualified_name); + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x (%s), name='%s')", + die->GetOffset(), + qualified_name.c_str(), + type_name.GetCString()); + } + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_types_ap.get()) + { + const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag); + const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash); + if (has_tag && has_qualified_name_hash) + { + if (qualified_name.empty()) + die->GetQualifiedName(this, cu, qualified_name); + + const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name.c_str()); + if (log) + GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); + m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets); + } + else if (has_tag > 1) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); + m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), die->Tag(), die_offsets); + } + else + { + m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets); + } + } + } + else + { + if (!m_indexed) + Index (); + + m_type_index.Find (type_name, die_offsets); + } + + const size_t num_matches = die_offsets.size(); + + const dw_tag_t die_tag = die->Tag(); + + DWARFCompileUnit* type_cu = NULL; + const DWARFDebugInfoEntry* type_die = NULL; + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); + + if (type_die) + { + bool try_resolving_type = false; + + // Don't try and resolve the DIE we are looking for with the DIE itself! + if (type_die != die) + { + const dw_tag_t type_die_tag = type_die->Tag(); + // Make sure the tags match + if (type_die_tag == die_tag) + { + // The tags match, lets try resolving this type + try_resolving_type = true; + } + else + { + // The tags don't match, but we need to watch our for a + // forward declaration for a struct and ("struct foo") + // ends up being a class ("class foo { ... };") or + // vice versa. + switch (type_die_tag) + { + case DW_TAG_class_type: + // We had a "class foo", see if we ended up with a "struct foo { ... };" + try_resolving_type = (die_tag == DW_TAG_structure_type); + break; + case DW_TAG_structure_type: + // We had a "struct foo", see if we ended up with a "class foo { ... };" + try_resolving_type = (die_tag == DW_TAG_class_type); + break; + default: + // Tags don't match, don't event try to resolve + // using this type whose name matches.... + break; + } + } + } + + if (try_resolving_type) + { + if (log) + { + std::string qualified_name; + type_die->GetQualifiedName(this, cu, qualified_name); + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') trying die=0x%8.8x (%s)", + die->GetOffset(), + type_name.GetCString(), + type_die->GetOffset(), + qualified_name.c_str()); + } + + // Make sure the decl contexts match all the way up + if (DIEDeclContextsMatch(cu, die, type_cu, type_die)) + { + Type *resolved_type = ResolveType (type_cu, type_die, false); + if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) + { + DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", + MakeUserID(die->GetOffset()), + MakeUserID(dwarf_cu->GetOffset()), + m_obj_file->GetFileSpec().GetFilename().AsCString(), + MakeUserID(type_die->GetOffset()), + MakeUserID(type_cu->GetOffset())); + + m_die_to_type[die] = resolved_type; + type_sp = resolved_type->shared_from_this(); + break; + } + } + } + else + { + if (log) + { + std::string qualified_name; + type_die->GetQualifiedName(this, cu, qualified_name); + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') ignoring die=0x%8.8x (%s)", + die->GetOffset(), + type_name.GetCString(), + type_die->GetOffset(), + qualified_name.c_str()); + } + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, type_name.GetCString()); + } + } + + } + } + return type_sp; +} + +TypeSP +SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &dwarf_decl_ctx) +{ + TypeSP type_sp; + + const uint32_t dwarf_decl_ctx_count = dwarf_decl_ctx.GetSize(); + if (dwarf_decl_ctx_count > 0) + { + const ConstString type_name(dwarf_decl_ctx[0].name); + const dw_tag_t tag = dwarf_decl_ctx[0].tag; + + if (type_name) + { + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS)); + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s')", + DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), + dwarf_decl_ctx.GetQualifiedName()); + } + + DIEArray die_offsets; + + if (m_using_apple_tables) + { + if (m_apple_types_ap.get()) + { + const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag); + const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash); + if (has_tag && has_qualified_name_hash) + { + const char *qualified_name = dwarf_decl_ctx.GetQualifiedName(); + const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name); + if (log) + GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()"); + m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), tag, qualified_name_hash, die_offsets); + } + else if (has_tag) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()"); + m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), tag, die_offsets); + } + else + { + m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets); + } + } + } + else + { + if (!m_indexed) + Index (); + + m_type_index.Find (type_name, die_offsets); + } + + const size_t num_matches = die_offsets.size(); + + + DWARFCompileUnit* type_cu = NULL; + const DWARFDebugInfoEntry* type_die = NULL; + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu); + + if (type_die) + { + bool try_resolving_type = false; + + // Don't try and resolve the DIE we are looking for with the DIE itself! + const dw_tag_t type_tag = type_die->Tag(); + // Make sure the tags match + if (type_tag == tag) + { + // The tags match, lets try resolving this type + try_resolving_type = true; + } + else + { + // The tags don't match, but we need to watch our for a + // forward declaration for a struct and ("struct foo") + // ends up being a class ("class foo { ... };") or + // vice versa. + switch (type_tag) + { + case DW_TAG_class_type: + // We had a "class foo", see if we ended up with a "struct foo { ... };" + try_resolving_type = (tag == DW_TAG_structure_type); + break; + case DW_TAG_structure_type: + // We had a "struct foo", see if we ended up with a "class foo { ... };" + try_resolving_type = (tag == DW_TAG_class_type); + break; + default: + // Tags don't match, don't event try to resolve + // using this type whose name matches.... + break; + } + } + + if (try_resolving_type) + { + DWARFDeclContext type_dwarf_decl_ctx; + type_die->GetDWARFDeclContext (this, type_cu, type_dwarf_decl_ctx); + + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') trying die=0x%8.8x (%s)", + DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), + dwarf_decl_ctx.GetQualifiedName(), + type_die->GetOffset(), + type_dwarf_decl_ctx.GetQualifiedName()); + } + + // Make sure the decl contexts match all the way up + if (dwarf_decl_ctx == type_dwarf_decl_ctx) + { + Type *resolved_type = ResolveType (type_cu, type_die, false); + if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) + { + type_sp = resolved_type->shared_from_this(); + break; + } + } + } + else + { + if (log) + { + std::string qualified_name; + type_die->GetQualifiedName(this, type_cu, qualified_name); + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') ignoring die=0x%8.8x (%s)", + DW_TAG_value_to_name(dwarf_decl_ctx[0].tag), + dwarf_decl_ctx.GetQualifiedName(), + type_die->GetOffset(), + qualified_name.c_str()); + } + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n", + die_offset, type_name.GetCString()); + } + } + + } + } + } + } + return type_sp; +} + +bool +SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile, + Type *class_type, + DWARFCompileUnit* src_cu, + const DWARFDebugInfoEntry *src_class_die, + DWARFCompileUnit* dst_cu, + const DWARFDebugInfoEntry *dst_class_die, + llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures) +{ + if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die) + return false; + if (src_class_die->Tag() != dst_class_die->Tag()) + return false; + + // We need to complete the class type so we can get all of the method types + // parsed so we can then unique those types to their equivalent counterparts + // in "dst_cu" and "dst_class_die" + class_type->GetClangFullType(); + + const DWARFDebugInfoEntry *src_die; + const DWARFDebugInfoEntry *dst_die; + UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die; + UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die; + UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die_artificial; + UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die_artificial; + for (src_die = src_class_die->GetFirstChild(); src_die != NULL; src_die = src_die->GetSibling()) + { + if (src_die->Tag() == DW_TAG_subprogram) + { + // Make sure this is a declaration and not a concrete instance by looking + // for DW_AT_declaration set to 1. Sometimes concrete function instances + // are placed inside the class definitions and shouldn't be included in + // the list of things are are tracking here. + if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_declaration, 0) == 1) + { + const char *src_name = src_die->GetMangledName (src_symfile, src_cu); + if (src_name) + { + ConstString src_const_name(src_name); + if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_artificial, 0)) + src_name_to_die_artificial.Append(src_const_name.GetCString(), src_die); + else + src_name_to_die.Append(src_const_name.GetCString(), src_die); + } + } + } + } + for (dst_die = dst_class_die->GetFirstChild(); dst_die != NULL; dst_die = dst_die->GetSibling()) + { + if (dst_die->Tag() == DW_TAG_subprogram) + { + // Make sure this is a declaration and not a concrete instance by looking + // for DW_AT_declaration set to 1. Sometimes concrete function instances + // are placed inside the class definitions and shouldn't be included in + // the list of things are are tracking here. + if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_declaration, 0) == 1) + { + const char *dst_name = dst_die->GetMangledName (this, dst_cu); + if (dst_name) + { + ConstString dst_const_name(dst_name); + if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_artificial, 0)) + dst_name_to_die_artificial.Append(dst_const_name.GetCString(), dst_die); + else + dst_name_to_die.Append(dst_const_name.GetCString(), dst_die); + } + } + } + } + const uint32_t src_size = src_name_to_die.GetSize (); + const uint32_t dst_size = dst_name_to_die.GetSize (); + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_TYPE_COMPLETION)); + + // Is everything kosher so we can go through the members at top speed? + bool fast_path = true; + + if (src_size != dst_size) + { + if (src_size != 0 && dst_size != 0) + { + if (log) + log->Printf("warning: trying to unique class DIE 0x%8.8x to 0x%8.8x, but they didn't have the same size (src=%d, dst=%d)", + src_class_die->GetOffset(), + dst_class_die->GetOffset(), + src_size, + dst_size); + } + + fast_path = false; + } + + uint32_t idx; + + if (fast_path) + { + for (idx = 0; idx < src_size; ++idx) + { + src_die = src_name_to_die.GetValueAtIndexUnchecked (idx); + dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx); + + if (src_die->Tag() != dst_die->Tag()) + { + if (log) + log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) tags didn't match 0x%8.8x (%s)", + src_class_die->GetOffset(), + dst_class_die->GetOffset(), + src_die->GetOffset(), + DW_TAG_value_to_name(src_die->Tag()), + dst_die->GetOffset(), + DW_TAG_value_to_name(src_die->Tag())); + fast_path = false; + } + + const char *src_name = src_die->GetMangledName (src_symfile, src_cu); + const char *dst_name = dst_die->GetMangledName (this, dst_cu); + + // Make sure the names match + if (src_name == dst_name || (strcmp (src_name, dst_name) == 0)) + continue; + + if (log) + log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) names didn't match 0x%8.8x (%s)", + src_class_die->GetOffset(), + dst_class_die->GetOffset(), + src_die->GetOffset(), + src_name, + dst_die->GetOffset(), + dst_name); + + fast_path = false; + } + } + + // Now do the work of linking the DeclContexts and Types. + if (fast_path) + { + // We can do this quickly. Just run across the tables index-for-index since + // we know each node has matching names and tags. + for (idx = 0; idx < src_size; ++idx) + { + src_die = src_name_to_die.GetValueAtIndexUnchecked (idx); + dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx); + + clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; + if (src_decl_ctx) + { + if (log) + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + LinkDeclContextToDIE (src_decl_ctx, dst_die); + } + else + { + if (log) + log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + + Type *src_child_type = m_die_to_type[src_die]; + if (src_child_type) + { + if (log) + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + m_die_to_type[dst_die] = src_child_type; + } + else + { + if (log) + log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + } + } + else + { + // We must do this slowly. For each member of the destination, look + // up a member in the source with the same name, check its tag, and + // unique them if everything matches up. Report failures. + + if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) + { + src_name_to_die.Sort(); + + for (idx = 0; idx < dst_size; ++idx) + { + const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx); + dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); + src_die = src_name_to_die.Find(dst_name, NULL); + + if (src_die && (src_die->Tag() == dst_die->Tag())) + { + clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die]; + if (src_decl_ctx) + { + if (log) + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + LinkDeclContextToDIE (src_decl_ctx, dst_die); + } + else + { + if (log) + log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + + Type *src_child_type = m_die_to_type[src_die]; + if (src_child_type) + { + if (log) + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + m_die_to_type[dst_die] = src_child_type; + } + else + { + if (log) + log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + } + else + { + if (log) + log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset()); + + failures.push_back(dst_die); + } + } + } + } + + const uint32_t src_size_artificial = src_name_to_die_artificial.GetSize (); + const uint32_t dst_size_artificial = dst_name_to_die_artificial.GetSize (); + + UniqueCStringMap<const DWARFDebugInfoEntry *> name_to_die_artificial_not_in_src; + + if (src_size_artificial && dst_size_artificial) + { + dst_name_to_die_artificial.Sort(); + + for (idx = 0; idx < src_size_artificial; ++idx) + { + const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx); + src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx); + dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL); + + if (dst_die) + { + // Both classes have the artificial types, link them + clang::DeclContext *src_decl_ctx = m_die_to_decl_ctx[src_die]; + if (src_decl_ctx) + { + if (log) + log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset()); + LinkDeclContextToDIE (src_decl_ctx, dst_die); + } + else + { + if (log) + log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + + Type *src_child_type = m_die_to_type[src_die]; + if (src_child_type) + { + if (log) + log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset()); + m_die_to_type[dst_die] = src_child_type; + } + else + { + if (log) + log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset()); + } + } + } + } + + if (dst_size_artificial) + { + for (idx = 0; idx < dst_size_artificial; ++idx) + { + const char *dst_name_artificial = dst_name_to_die_artificial.GetCStringAtIndex(idx); + dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked (idx); + if (log) + log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial); + + failures.push_back(dst_die); + } + } + + return (failures.size() != 0); +} + +TypeSP +SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new_ptr) +{ + TypeSP type_sp; + + if (type_is_new_ptr) + *type_is_new_ptr = false; + +#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) + static DIEStack g_die_stack; + DIEStack::ScopedPopper scoped_die_logger(g_die_stack); +#endif + + AccessType accessibility = eAccessNone; + if (die != NULL) + { + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log) + { + const DWARFDebugInfoEntry *context_die; + clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die); + + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')", + die->GetOffset(), + context, + context_die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + +#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE) + scoped_die_logger.Push (dwarf_cu, die); + g_die_stack.LogDIEs(log, this); +#endif + } +// +// Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); +// if (log && dwarf_cu) +// { +// StreamString s; +// die->DumpLocation (this, dwarf_cu, s); +// GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData()); +// +// } + + Type *type_ptr = m_die_to_type.lookup (die); + TypeList* type_list = GetTypeList(); + if (type_ptr == NULL) + { + ClangASTContext &ast = GetClangASTContext(); + if (type_is_new_ptr) + *type_is_new_ptr = true; + + const dw_tag_t tag = die->Tag(); + + bool is_forward_declaration = false; + DWARFDebugInfoEntry::Attributes attributes; + const char *type_name_cstr = NULL; + ConstString type_name_const_str; + Type::ResolveState resolve_state = Type::eResolveStateUnresolved; + uint64_t byte_size = 0; + Declaration decl; + + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + ClangASTType clang_type; + + dw_attr_t attr; + + switch (tag) + { + case DW_TAG_base_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + case DW_TAG_typedef: + case DW_TAG_const_type: + case DW_TAG_restrict_type: + case DW_TAG_volatile_type: + case DW_TAG_unspecified_type: + { + // Set a bit that lets us know that we are currently parsing this + m_die_to_type[die] = DIE_IS_BEING_PARSED; + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); + uint32_t encoding = 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()); + // Work around a bug in llvm-gcc where they give a name to a reference type which doesn't + // include the "&"... + if (tag == DW_TAG_reference_type) + { + if (strchr (type_name_cstr, '&') == NULL) + type_name_cstr = NULL; + } + if (type_name_cstr) + type_name_const_str.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; + } + } + } + } + + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8x\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid); + + switch (tag) + { + default: + break; + + case DW_TAG_unspecified_type: + if (strcmp(type_name_cstr, "nullptr_t") == 0 || + strcmp(type_name_cstr, "decltype(nullptr)") == 0 ) + { + resolve_state = Type::eResolveStateFull; + clang_type = ast.GetBasicType(eBasicTypeNullPtr); + break; + } + // Fall through to base type below in case we can handle the type there... + + case DW_TAG_base_type: + resolve_state = Type::eResolveStateFull; + clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr, + encoding, + byte_size * 8); + break; + + case DW_TAG_pointer_type: encoding_data_type = Type::eEncodingIsPointerUID; break; + case DW_TAG_reference_type: encoding_data_type = Type::eEncodingIsLValueReferenceUID; break; + case DW_TAG_rvalue_reference_type: encoding_data_type = Type::eEncodingIsRValueReferenceUID; break; + case DW_TAG_typedef: encoding_data_type = Type::eEncodingIsTypedefUID; break; + case DW_TAG_const_type: encoding_data_type = Type::eEncodingIsConstUID; break; + case DW_TAG_restrict_type: encoding_data_type = Type::eEncodingIsRestrictUID; break; + case DW_TAG_volatile_type: encoding_data_type = Type::eEncodingIsVolatileUID; break; + } + + if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL) + { + bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus); + + if (translation_unit_is_objc) + { + if (type_name_cstr != NULL) + { + static ConstString g_objc_type_name_id("id"); + static ConstString g_objc_type_name_Class("Class"); + static ConstString g_objc_type_name_selector("SEL"); + + if (type_name_const_str == g_objc_type_name_id) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'id' built-in type.", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + clang_type = ast.GetBasicType(eBasicTypeObjCID); + encoding_data_type = Type::eEncodingIsUID; + encoding_uid = LLDB_INVALID_UID; + resolve_state = Type::eResolveStateFull; + + } + else if (type_name_const_str == g_objc_type_name_Class) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'Class' built-in type.", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + clang_type = ast.GetBasicType(eBasicTypeObjCClass); + encoding_data_type = Type::eEncodingIsUID; + encoding_uid = LLDB_INVALID_UID; + resolve_state = Type::eResolveStateFull; + } + else if (type_name_const_str == g_objc_type_name_selector) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'selector' built-in type.", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + clang_type = ast.GetBasicType(eBasicTypeObjCSel); + encoding_data_type = Type::eEncodingIsUID; + encoding_uid = LLDB_INVALID_UID; + resolve_state = Type::eResolveStateFull; + } + } + else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID) + { + // Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id". + + DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid); + + if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type) + { + if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL)) + { + if (!strcmp(struct_name, "objc_object")) + { + if (log) + GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is 'objc_object*', which we overrode to 'id'.", + die->GetOffset(), + DW_TAG_value_to_name(die->Tag()), + die->GetName(this, dwarf_cu)); + clang_type = ast.GetBasicType(eBasicTypeObjCID); + encoding_data_type = Type::eEncodingIsUID; + encoding_uid = LLDB_INVALID_UID; + resolve_state = Type::eResolveStateFull; + } + } + } + } + } + } + + type_sp.reset( new Type (MakeUserID(die->GetOffset()), + this, + type_name_const_str, + byte_size, + NULL, + encoding_uid, + encoding_data_type, + &decl, + clang_type, + resolve_state)); + + m_die_to_type[die] = 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: + { + // Set a bit that lets us know that we are currently parsing this + m_die_to_type[die] = DIE_IS_BEING_PARSED; + bool byte_size_valid = false; + + LanguageType class_language = eLanguageTypeUnknown; + bool is_complete_objc_class = false; + //bool struct_is_class = false; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, 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: + if (dwarf_cu->DW_AT_decl_file_attributes_are_invalid()) + { + // llvm-gcc outputs invalid DW_AT_decl_file attributes that always + // point to the compile unit file, so we clear this invalid value + // so that we can still unique types efficiently. + decl.SetFile(FileSpec ("<invalid>", false)); + } + else + 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_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + byte_size_valid = true; + break; + + case DW_AT_accessibility: + accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); + break; + + case DW_AT_declaration: + is_forward_declaration = form_value.Boolean(); + break; + + case DW_AT_APPLE_runtime_class: + class_language = (LanguageType)form_value.Signed(); + break; + + case DW_AT_APPLE_objc_complete_type: + is_complete_objc_class = form_value.Signed(); + 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; + } + } + } + } + + UniqueDWARFASTType unique_ast_entry; + + // Only try and unique the type if it has a name. + if (type_name_const_str && + GetUniqueDWARFASTTypeMap().Find (type_name_const_str, + this, + dwarf_cu, + die, + decl, + byte_size_valid ? byte_size : -1, + unique_ast_entry)) + { + // We have already parsed this type or from another + // compile unit. GCC loves to use the "one definition + // rule" which can result in multiple definitions + // of the same class over and over in each compile + // unit. + type_sp = unique_ast_entry.m_type_sp; + if (type_sp) + { + m_die_to_type[die] = type_sp.get(); + return type_sp; + } + } + + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); + + int tag_decl_kind = -1; + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) + { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = eAccessPublic; + } + else if (tag == DW_TAG_union_type) + { + tag_decl_kind = clang::TTK_Union; + default_accessibility = eAccessPublic; + } + else if (tag == DW_TAG_class_type) + { + tag_decl_kind = clang::TTK_Class; + default_accessibility = eAccessPrivate; + } + + if (byte_size_valid && byte_size == 0 && type_name_cstr && + die->HasChildren() == false && + sc.comp_unit->GetLanguage() == eLanguageTypeObjC) + { + // Work around an issue with clang at the moment where + // forward declarations for objective C classes are emitted + // as: + // DW_TAG_structure_type [2] + // DW_AT_name( "ForwardObjcClass" ) + // DW_AT_byte_size( 0x00 ) + // DW_AT_decl_file( "..." ) + // DW_AT_decl_line( 1 ) + // + // Note that there is no DW_AT_declaration and there are + // no children, and the byte size is zero. + is_forward_declaration = true; + } + + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + { + if (!is_complete_objc_class && Supports_DW_AT_APPLE_objc_complete_type(dwarf_cu)) + { + // We have a valid eSymbolTypeObjCClass class symbol whose + // name matches the current objective C class that we + // are trying to find and this DIE isn't the complete + // definition (we checked is_complete_objc_class above and + // know it is false), so the real definition is in here somewhere + type_sp = FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true); + + if (!type_sp && GetDebugMapSymfile ()) + { + // We weren't able to find a full declaration in + // this DWARF, see if we have a declaration anywhere + // else... + type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true); + } + + if (type_sp) + { + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64, + this, + die->GetOffset(), + DW_TAG_value_to_name(tag), + type_name_cstr, + type_sp->GetID()); + } + + // We found a real definition for this type elsewhere + // so lets use it and cache the fact that we found + // a complete type for this die + m_die_to_type[die] = type_sp.get(); + return type_sp; + } + } + } + + + if (is_forward_declaration) + { + // We have a forward declaration to a type and we need + // to try and find a full declaration. We look in the + // current type index just in case we have a forward + // declaration followed by an actual declarations in the + // DWARF. If this fails, we need to look elsewhere... + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type", + this, + die->GetOffset(), + DW_TAG_value_to_name(tag), + type_name_cstr); + } + + DWARFDeclContext die_decl_ctx; + die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx); + + //type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, type_name_const_str); + type_sp = FindDefinitionTypeForDWARFDeclContext (die_decl_ctx); + + if (!type_sp && GetDebugMapSymfile ()) + { + // We weren't able to find a full declaration in + // this DWARF, see if we have a declaration anywhere + // else... + type_sp = m_debug_map_symfile->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx); + } + + if (type_sp) + { + if (log) + { + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64, + this, + die->GetOffset(), + DW_TAG_value_to_name(tag), + type_name_cstr, + type_sp->GetID()); + } + + // We found a real definition for this type elsewhere + // so lets use it and cache the fact that we found + // a complete type for this die + m_die_to_type[die] = type_sp.get(); + return type_sp; + } + } + assert (tag_decl_kind != -1); + bool clang_type_was_created = false; + clang_type.SetClangType(ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die)); + if (!clang_type) + { + const DWARFDebugInfoEntry *decl_ctx_die; + + clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); + if (accessibility == eAccessNone && decl_ctx) + { + // Check the decl context that contains this class/struct/union. + // If it is a class we must give it an accessability. + const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); + if (DeclKindIsCXXClass (containing_decl_kind)) + accessibility = default_accessibility; + } + + ClangASTMetadata metadata; + metadata.SetUserID(MakeUserID(die->GetOffset())); + metadata.SetIsDynamicCXXType(ClassOrStructIsVirtual (dwarf_cu, die)); + + if (type_name_cstr && strchr (type_name_cstr, '<')) + { + ClangASTContext::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos (dwarf_cu, die, template_param_infos)) + { + clang::ClassTemplateDecl *class_template_decl = ParseClassTemplateDecl (decl_ctx, + accessibility, + type_name_cstr, + tag_decl_kind, + template_param_infos); + + clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx, + class_template_decl, + tag_decl_kind, + template_param_infos); + clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl); + clang_type_was_created = true; + + GetClangASTContext().SetMetadata (class_template_decl, metadata); + GetClangASTContext().SetMetadata (class_specialization_decl, metadata); + } + } + + if (!clang_type_was_created) + { + clang_type_was_created = true; + clang_type = ast.CreateRecordType (decl_ctx, + accessibility, + type_name_cstr, + tag_decl_kind, + class_language, + &metadata); + } + } + + // Store a forward declaration to this class type in case any + // parameters in any class methods need it for the clang + // types for function prototypes. + LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die); + type_sp.reset (new Type (MakeUserID(die->GetOffset()), + this, + type_name_const_str, + byte_size, + NULL, + LLDB_INVALID_UID, + Type::eEncodingIsUID, + &decl, + clang_type, + Type::eResolveStateForward)); + + type_sp->SetIsCompleteObjCClass(is_complete_objc_class); + + + // Add our type to the unique type map so we don't + // end up creating many copies of the same type over + // and over in the ASTContext for our module + unique_ast_entry.m_type_sp = type_sp; + unique_ast_entry.m_symfile = this; + unique_ast_entry.m_cu = dwarf_cu; + unique_ast_entry.m_die = die; + unique_ast_entry.m_declaration = decl; + unique_ast_entry.m_byte_size = byte_size; + GetUniqueDWARFASTTypeMap().Insert (type_name_const_str, + unique_ast_entry); + + if (is_forward_declaration && die->HasChildren()) + { + // Check to see if the DIE actually has a definition, some version of GCC will + // emit DIEs with DW_AT_declaration set to true, but yet still have subprogram, + // members, or inheritance, so we can't trust it + const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); + while (child_die) + { + switch (child_die->Tag()) + { + case DW_TAG_inheritance: + case DW_TAG_subprogram: + case DW_TAG_member: + case DW_TAG_APPLE_property: + child_die = NULL; + is_forward_declaration = false; + break; + default: + child_die = child_die->GetSibling(); + break; + } + } + } + + if (!is_forward_declaration) + { + // Always start the definition for a class type so that + // if the class has child classes or types that require + // the class to be created for use as their decl contexts + // the class will be ready to accept these child definitions. + if (die->HasChildren() == false) + { + // No children for this struct/union/class, lets finish it + clang_type.StartTagDeclarationDefinition (); + clang_type.CompleteTagDeclarationDefinition (); + + if (tag == DW_TAG_structure_type) // this only applies in C + { + clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl(); + + if (record_decl) + { + LayoutInfo layout_info; + + layout_info.alignment = 0; + layout_info.bit_size = 0; + + m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info)); + } + } + } + else if (clang_type_was_created) + { + // Start the definition if the class is not objective C since + // the underlying decls respond to isCompleteDefinition(). Objective + // C decls dont' respond to isCompleteDefinition() so we can't + // start the declaration definition right away. For C++ classs/union/structs + // we want to start the definition in case the class is needed as the + // declaration context for a contained class or type without the need + // to complete that type.. + + if (class_language != eLanguageTypeObjC && + class_language != eLanguageTypeObjC_plus_plus) + clang_type.StartTagDeclarationDefinition (); + + // Leave this as a forward declaration until we need + // to know the details of the type. lldb_private::Type + // will automatically call the SymbolFile virtual function + // "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition(Type *)" + // When the definition needs to be defined. + m_forward_decl_die_to_clang_type[die] = clang_type.GetOpaqueQualType(); + m_forward_decl_clang_type_to_die[clang_type.RemoveFastQualifiers().GetOpaqueQualType()] = die; + clang_type.SetHasExternalStorage (true); + } + } + + } + break; + + case DW_TAG_enumeration_type: + { + // Set a bit that lets us know that we are currently parsing this + m_die_to_type[die] = DIE_IS_BEING_PARSED; + + lldb::user_id_t encoding_uid = DW_INVALID_OFFSET; + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, 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_const_str.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: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; + case DW_AT_declaration: break; //is_forward_declaration = form_value.Boolean(); 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; + } + } + } + + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); + + ClangASTType enumerator_clang_type; + clang_type.SetClangType (ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die)); + if (!clang_type) + { + if (encoding_uid != DW_INVALID_OFFSET) + { + Type *enumerator_type = ResolveTypeUID(encoding_uid); + if (enumerator_type) + enumerator_clang_type = enumerator_type->GetClangFullType(); + } + + if (!enumerator_clang_type) + enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, + DW_ATE_signed, + byte_size * 8); + + clang_type = ast.CreateEnumerationType (type_name_cstr, + GetClangDeclContextContainingDIE (dwarf_cu, die, NULL), + decl, + enumerator_clang_type); + } + else + { + enumerator_clang_type = clang_type.GetEnumerationIntegerType (); + } + + LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die); + + type_sp.reset( new Type (MakeUserID(die->GetOffset()), + this, + type_name_const_str, + byte_size, + NULL, + encoding_uid, + Type::eEncodingIsUID, + &decl, + clang_type, + Type::eResolveStateForward)); + + clang_type.StartTagDeclarationDefinition (); + if (die->HasChildren()) + { + SymbolContext cu_sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); + bool is_signed = false; + enumerator_clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), dwarf_cu, die); + } + clang_type.CompleteTagDeclarationDefinition (); + } + } + break; + + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + { + // Set a bit that lets us know that we are currently parsing this + m_die_to_type[die] = DIE_IS_BEING_PARSED; + + //const char *mangled = NULL; + dw_offset_t type_die_offset = DW_INVALID_OFFSET; + bool is_variadic = false; + bool is_inline = false; + bool is_static = false; + bool is_virtual = false; + bool is_explicit = false; + bool is_artificial = false; + dw_offset_t specification_die_offset = DW_INVALID_OFFSET; + dw_offset_t abstract_origin_die_offset = DW_INVALID_OFFSET; + dw_offset_t object_pointer_die_offset = DW_INVALID_OFFSET; + + unsigned type_quals = 0; + clang::StorageClass storage = clang::SC_None;//, Extern, Static, PrivateExtern + + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, 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_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: break; // 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 = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; + case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); break; + case DW_AT_inline: is_inline = form_value.Boolean(); break; + case DW_AT_virtuality: is_virtual = form_value.Boolean(); break; + case DW_AT_explicit: is_explicit = form_value.Boolean(); break; + case DW_AT_artificial: is_artificial = form_value.Boolean(); break; + + + case DW_AT_external: + if (form_value.Unsigned()) + { + if (storage == clang::SC_None) + storage = clang::SC_Extern; + else + storage = clang::SC_PrivateExtern; + } + break; + + case DW_AT_specification: + specification_die_offset = form_value.Reference(dwarf_cu); + break; + + case DW_AT_abstract_origin: + abstract_origin_die_offset = form_value.Reference(dwarf_cu); + break; + + case DW_AT_object_pointer: + object_pointer_die_offset = form_value.Reference(dwarf_cu); + break; + + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_address_class: + case DW_AT_calling_convention: + case DW_AT_data_location: + case DW_AT_elemental: + case DW_AT_entry_pc: + case DW_AT_frame_base: + case DW_AT_high_pc: + case DW_AT_low_pc: + 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_start_scope: + case DW_AT_static_link: + case DW_AT_trampoline: + case DW_AT_visibility: + case DW_AT_vtable_elem_location: + case DW_AT_description: + case DW_AT_sibling: + break; + } + } + } + } + + std::string object_pointer_name; + if (object_pointer_die_offset != DW_INVALID_OFFSET) + { + // Get the name from the object pointer die + StreamString s; + if (DWARFDebugInfoEntry::GetName (this, dwarf_cu, object_pointer_die_offset, s)) + { + object_pointer_name.assign(s.GetData()); + } + } + + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); + + ClangASTType return_clang_type; + Type *func_type = NULL; + + if (type_die_offset != DW_INVALID_OFFSET) + func_type = ResolveTypeUID(type_die_offset); + + if (func_type) + return_clang_type = func_type->GetClangForwardType(); + else + return_clang_type = ast.GetBasicType(eBasicTypeVoid); + + + std::vector<ClangASTType> function_param_types; + std::vector<clang::ParmVarDecl*> function_param_decls; + + // Parse the function children for the parameters + + const DWARFDebugInfoEntry *decl_ctx_die = NULL; + clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); + const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind(); + + const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind); + // Start off static. This will be set to false in ParseChildParameters(...) + // if we find a "this" paramters as the first parameter + if (is_cxx_method) + is_static = true; + ClangASTContext::TemplateParameterInfos template_param_infos; + + if (die->HasChildren()) + { + bool skip_artificial = true; + ParseChildParameters (sc, + containing_decl_ctx, + dwarf_cu, + die, + skip_artificial, + is_static, + type_list, + function_param_types, + function_param_decls, + type_quals, + template_param_infos); + } + + // clang_type will get the function prototype clang type after this call + clang_type = ast.CreateFunctionType (return_clang_type, + function_param_types.data(), + function_param_types.size(), + is_variadic, + type_quals); + + bool ignore_containing_context = false; + + if (type_name_cstr) + { + bool type_handled = false; + if (tag == DW_TAG_subprogram) + { + ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true); + if (objc_method.IsValid(true)) + { + SymbolContext empty_sc; + ClangASTType class_opaque_type; + ConstString class_name(objc_method.GetClassName()); + if (class_name) + { + TypeList types; + TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false)); + + if (complete_objc_class_type_sp) + { + ClangASTType type_clang_forward_type = complete_objc_class_type_sp->GetClangForwardType(); + if (type_clang_forward_type.IsObjCObjectOrInterfaceType ()) + class_opaque_type = type_clang_forward_type; + } + } + + if (class_opaque_type) + { + // If accessibility isn't set to anything valid, assume public for + // now... + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + + clang::ObjCMethodDecl *objc_method_decl = class_opaque_type.AddMethodToObjCObjectType (type_name_cstr, + clang_type, + accessibility, + is_artificial); + type_handled = objc_method_decl != NULL; + if (type_handled) + { + LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(objc_method_decl), die); + GetClangASTContext().SetMetadataAsUserID (objc_method_decl, MakeUserID(die->GetOffset())); + } + else + { + GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), please file a bug and attach the file at the start of this error message", + die->GetOffset(), + tag, + DW_TAG_value_to_name(tag)); + } + } + } + else if (is_cxx_method) + { + // Look at the parent of this DIE and see if is is + // a class or struct and see if this is actually a + // C++ method + Type *class_type = ResolveType (dwarf_cu, decl_ctx_die); + if (class_type) + { + if (class_type->GetID() != MakeUserID(decl_ctx_die->GetOffset())) + { + // We uniqued the parent class of this function to another class + // so we now need to associate all dies under "decl_ctx_die" to + // DIEs in the DIE for "class_type"... + SymbolFileDWARF *class_symfile = NULL; + DWARFCompileUnitSP class_type_cu_sp; + const DWARFDebugInfoEntry *class_type_die = NULL; + + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + { + class_symfile = debug_map_symfile->GetSymbolFileByOSOIndex(SymbolFileDWARFDebugMap::GetOSOIndexFromUserID(class_type->GetID())); + class_type_die = class_symfile->DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp); + } + else + { + class_symfile = this; + class_type_die = DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp); + } + if (class_type_die) + { + llvm::SmallVector<const DWARFDebugInfoEntry *, 0> failures; + + CopyUniqueClassMethodTypes (class_symfile, + class_type, + class_type_cu_sp.get(), + class_type_die, + dwarf_cu, + decl_ctx_die, + failures); + + // FIXME do something with these failures that's smarter than + // just dropping them on the ground. Unfortunately classes don't + // like having stuff added to them after their definitions are + // complete... + + type_ptr = m_die_to_type[die]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) + { + type_sp = type_ptr->shared_from_this(); + break; + } + } + } + + if (specification_die_offset != DW_INVALID_OFFSET) + { + // We have a specification which we are going to base our function + // prototype off of, so we need this type to be completed so that the + // m_die_to_decl_ctx for the method in the specification has a valid + // clang decl context. + class_type->GetClangForwardType(); + // If we have a specification, then the function type should have been + // made with the specification and not with this die. + DWARFCompileUnitSP spec_cu_sp; + const DWARFDebugInfoEntry* spec_die = DebugInfo()->GetDIEPtr(specification_die_offset, &spec_cu_sp); + clang::DeclContext *spec_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, spec_die); + if (spec_clang_decl_ctx) + { + LinkDeclContextToDIE(spec_clang_decl_ctx, die); + } + else + { + GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x) has no decl\n", + MakeUserID(die->GetOffset()), + specification_die_offset); + } + type_handled = true; + } + else if (abstract_origin_die_offset != DW_INVALID_OFFSET) + { + // We have a specification which we are going to base our function + // prototype off of, so we need this type to be completed so that the + // m_die_to_decl_ctx for the method in the abstract origin has a valid + // clang decl context. + class_type->GetClangForwardType(); + + DWARFCompileUnitSP abs_cu_sp; + const DWARFDebugInfoEntry* abs_die = DebugInfo()->GetDIEPtr(abstract_origin_die_offset, &abs_cu_sp); + clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, abs_die); + if (abs_clang_decl_ctx) + { + LinkDeclContextToDIE (abs_clang_decl_ctx, die); + } + else + { + GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x) has no decl\n", + MakeUserID(die->GetOffset()), + abstract_origin_die_offset); + } + type_handled = true; + } + else + { + ClangASTType class_opaque_type = class_type->GetClangForwardType(); + if (class_opaque_type.IsCXXClassType ()) + { + if (class_opaque_type.IsBeingDefined ()) + { + // Neither GCC 4.2 nor clang++ currently set a valid accessibility + // in the DWARF for C++ methods... Default to public for now... + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + + if (!is_static && !die->HasChildren()) + { + // We have a C++ member function with no children (this pointer!) + // and clang will get mad if we try and make a function that isn't + // well formed in the DWARF, so we will just skip it... + type_handled = true; + } + else + { + clang::CXXMethodDecl *cxx_method_decl; + // REMOVE THE CRASH DESCRIPTION BELOW + Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s", + type_name_cstr, + class_type->GetName().GetCString(), + MakeUserID(die->GetOffset()), + m_obj_file->GetFileSpec().GetPath().c_str()); + + const bool is_attr_used = false; + + cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr, + clang_type, + accessibility, + is_virtual, + is_static, + is_inline, + is_explicit, + is_attr_used, + is_artificial); + + type_handled = cxx_method_decl != NULL; + + if (type_handled) + { + LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die); + + Host::SetCrashDescription (NULL); + + + ClangASTMetadata metadata; + metadata.SetUserID(MakeUserID(die->GetOffset())); + + if (!object_pointer_name.empty()) + { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + if (log) + log->Printf ("Setting object pointer name: %s on method object %p.\n", + object_pointer_name.c_str(), + cxx_method_decl); + } + GetClangASTContext().SetMetadata (cxx_method_decl, metadata); + } + else + { + ignore_containing_context = true; + } + } + } + else + { + // We were asked to parse the type for a method in a class, yet the + // class hasn't been asked to complete itself through the + // clang::ExternalASTSource protocol, so we need to just have the + // class complete itself and do things the right way, then our + // DIE should then have an entry in the m_die_to_type map. First + // we need to modify the m_die_to_type so it doesn't think we are + // trying to parse this DIE anymore... + m_die_to_type[die] = NULL; + + // Now we get the full type to force our class type to complete itself + // using the clang::ExternalASTSource protocol which will parse all + // base classes and all methods (including the method for this DIE). + class_type->GetClangFullType(); + + // The type for this DIE should have been filled in the function call above + type_ptr = m_die_to_type[die]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) + { + type_sp = type_ptr->shared_from_this(); + break; + } + + // FIXME This is fixing some even uglier behavior but we really need to + // uniq the methods of each class as well as the class itself. + // <rdar://problem/11240464> + type_handled = true; + } + } + } + } + } + } + + if (!type_handled) + { + // We just have a function that isn't part of a class + clang::FunctionDecl *function_decl = ast.CreateFunctionDeclaration (ignore_containing_context ? GetClangASTContext().GetTranslationUnitDecl() : containing_decl_ctx, + type_name_cstr, + clang_type, + storage, + is_inline); + +// if (template_param_infos.GetSize() > 0) +// { +// clang::FunctionTemplateDecl *func_template_decl = ast.CreateFunctionTemplateDecl (containing_decl_ctx, +// function_decl, +// type_name_cstr, +// template_param_infos); +// +// ast.CreateFunctionTemplateSpecializationInfo (function_decl, +// func_template_decl, +// template_param_infos); +// } + // Add the decl to our DIE to decl context map + assert (function_decl); + LinkDeclContextToDIE(function_decl, die); + if (!function_param_decls.empty()) + ast.SetFunctionParameters (function_decl, + &function_param_decls.front(), + function_param_decls.size()); + + ClangASTMetadata metadata; + metadata.SetUserID(MakeUserID(die->GetOffset())); + + if (!object_pointer_name.empty()) + { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + if (log) + log->Printf ("Setting object pointer name: %s on function object %p.", + object_pointer_name.c_str(), + function_decl); + } + GetClangASTContext().SetMetadata (function_decl, metadata); + } + } + type_sp.reset( new Type (MakeUserID(die->GetOffset()), + this, + type_name_const_str, + 0, + NULL, + LLDB_INVALID_UID, + Type::eEncodingIsUID, + &decl, + clang_type, + Type::eResolveStateFull)); + assert(type_sp.get()); + } + break; + + case DW_TAG_array_type: + { + // Set a bit that lets us know that we are currently parsing this + m_die_to_type[die] = DIE_IS_BEING_PARSED; + + lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; + int64_t first_index = 0; + uint32_t byte_stride = 0; + uint32_t bit_stride = 0; + bool is_vector = false; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, 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_const_str.SetCString(type_name_cstr); + break; + + case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_byte_size: break; // 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_GNU_vector: is_vector = form_value.Boolean(); break; + case DW_AT_accessibility: break; // accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; + case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); 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; + } + } + } + + DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr); + + 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(); + ClangASTType array_element_type = element_type->GetClangForwardType(); + 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 = ast.CreateArrayType (array_element_type, + num_elements, + is_vector); + array_element_type = clang_type; + array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride; + } + ConstString empty_name; + type_sp.reset( new Type (MakeUserID(die->GetOffset()), + this, + empty_name, + array_element_bit_stride / 8, + NULL, + type_die_offset, + Type::eEncodingIsUID, + &decl, + clang_type, + Type::eResolveStateFull)); + type_sp->SetEncodingType (element_type); + } + } + } + break; + + case DW_TAG_ptr_to_member_type: + { + dw_offset_t type_die_offset = DW_INVALID_OFFSET; + dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET; + + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, 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_type: + type_die_offset = form_value.Reference(dwarf_cu); break; + case DW_AT_containing_type: + containing_type_die_offset = form_value.Reference(dwarf_cu); break; + } + } + } + + Type *pointee_type = ResolveTypeUID(type_die_offset); + Type *class_type = ResolveTypeUID(containing_type_die_offset); + + ClangASTType pointee_clang_type = pointee_type->GetClangForwardType(); + ClangASTType class_clang_type = class_type->GetClangLayoutType(); + + clang_type = pointee_clang_type.CreateMemberPointerType(class_clang_type); + + byte_size = clang_type.GetByteSize(); + + type_sp.reset( new Type (MakeUserID(die->GetOffset()), + this, + type_name_const_str, + byte_size, + NULL, + LLDB_INVALID_UID, + Type::eEncodingIsUID, + NULL, + clang_type, + Type::eResolveStateForward)); + } + + break; + } + default: + GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and attach the file at the start of this error message", + die->GetOffset(), + tag, + DW_TAG_value_to_name(tag)); + 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->GetBlock(true).FindBlockByID(MakeUserID(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); + } + + // We are ready to put this type into the uniqued list up at the module level + type_list->Insert (type_sp); + + m_die_to_type[die] = type_sp.get(); + } + } + else if (type_ptr != DIE_IS_BEING_PARSED) + { + type_sp = type_ptr->shared_from_this(); + } + } + return type_sp; +} + +size_t +SymbolFileDWARF::ParseTypes +( + const SymbolContext& sc, + 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(MakeUserID(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 = GetDWARFCompileUnit(sc.comp_unit); + 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, &sc.function->GetBlock (false), dwarf_cu, function_die, LLDB_INVALID_ADDRESS, 0); + } + } + + 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 = GetDWARFCompileUnit(sc.comp_unit); + 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) + { + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + + if (sc.function) + { + DWARFCompileUnit* dwarf_cu = info->GetCompileUnitContainingDIE(sc.function->GetID()).get(); + + if (dwarf_cu == NULL) + return 0; + + const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID()); + + dw_addr_t func_lo_pc = function_die->GetAttributeValueAsUnsigned (this, dwarf_cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (func_lo_pc != LLDB_INVALID_ADDRESS) + { + const size_t num_variables = ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true); + + // Let all blocks know they have parse all their variables + sc.function->GetBlock (false).SetDidParseVariables (true, true); + return num_variables; + } + } + else if (sc.comp_unit) + { + DWARFCompileUnit* dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()).get(); + + if (dwarf_cu == NULL) + return 0; + + 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); + + DWARFCompileUnit* match_dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + DIEArray die_offsets; + if (m_using_apple_tables) + { + if (m_apple_names_ap.get()) + { + DWARFMappedHash::DIEInfoArray hash_data_array; + if (m_apple_names_ap->AppendAllDIEsInRange (dwarf_cu->GetOffset(), + dwarf_cu->GetNextCompileUnitOffset(), + hash_data_array)) + { + DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets); + } + } + } + else + { + // 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 (); + + m_global_index.FindAllEntriesForCompileUnit (dwarf_cu->GetOffset(), + dwarf_cu->GetNextCompileUnitOffset(), + die_offsets); + } + + const size_t num_matches = die_offsets.size(); + if (num_matches) + { + DWARFDebugInfo* debug_info = DebugInfo(); + for (size_t i=0; i<num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &match_dwarf_cu); + if (die) + { + VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, LLDB_INVALID_ADDRESS)); + if (var_sp) + { + variables->AddVariableIfUnique (var_sp); + ++vars_added; + } + } + else + { + if (m_using_apple_tables) + { + GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x)\n", die_offset); + } + } + + } + } + } + return vars_added; + } + } + return 0; +} + + +VariableSP +SymbolFileDWARF::ParseVariableDIE +( + const SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + const lldb::addr_t func_low_pc +) +{ + + VariableSP var_sp (m_die_to_variable_sp[die]); + if (var_sp) + return var_sp; // Already been parsed! + + const dw_tag_t tag = die->Tag(); + + if ((tag == DW_TAG_variable) || + (tag == DW_TAG_constant) || + (tag == DW_TAG_formal_parameter && sc.function)) + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes); + if (num_attributes > 0) + { + const char *name = NULL; + const char *mangled = NULL; + Declaration decl; + uint32_t i; + lldb::user_id_t type_uid = LLDB_INVALID_UID; + DWARFExpression location; + bool is_external = false; + bool is_artificial = false; + bool location_is_const_value_data = false; + bool has_explicit_location = false; + //AccessType accessibility = eAccessNone; + + 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_linkage_name: + case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break; + case DW_AT_type: type_uid = form_value.Reference(dwarf_cu); break; + case DW_AT_external: is_external = form_value.Boolean(); break; + case DW_AT_const_value: + // If we have already found a DW_AT_location attribute, ignore this attribute. + if (!has_explicit_location) + { + location_is_const_value_data = true; + // The constant value will be either a block, a data value or a string. + const DataExtractor& debug_info_data = get_debug_info_data(); + if (DWARFFormValue::IsBlockForm(form_value.Form())) + { + // Retrieve the value as a block expression. + uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + location.CopyOpcodeData(debug_info_data, block_offset, block_length); + } + else if (DWARFFormValue::IsDataForm(form_value.Form())) + { + // Retrieve the value as a data expression. + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + uint32_t data_offset = attributes.DIEOffsetAtIndex(i); + uint32_t data_length = fixed_form_sizes[form_value.Form()]; + location.CopyOpcodeData(debug_info_data, data_offset, data_length); + } + else + { + // Retrieve the value as a string expression. + if (form_value.Form() == DW_FORM_strp) + { + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + uint32_t data_offset = attributes.DIEOffsetAtIndex(i); + uint32_t data_length = fixed_form_sizes[form_value.Form()]; + location.CopyOpcodeData(debug_info_data, data_offset, data_length); + } + else + { + const char *str = form_value.AsCString(&debug_info_data); + uint32_t string_offset = str - (const char *)debug_info_data.GetDataStart(); + uint32_t string_length = strlen(str) + 1; + location.CopyOpcodeData(debug_info_data, string_offset, string_length); + } + } + } + break; + case DW_AT_location: + { + location_is_const_value_data = false; + has_explicit_location = true; + 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.CopyOpcodeData(get_debug_info_data(), block_offset, block_length); + } + 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) + { + location.CopyOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length); + assert (func_low_pc != LLDB_INVALID_ADDRESS); + location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress()); + } + } + } + break; + + case DW_AT_artificial: is_artificial = form_value.Boolean(); break; + case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; + 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; + } + } + } + + ValueType scope = eValueTypeInvalid; + + const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); + dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + SymbolContextScope * symbol_context_scope = NULL; + + // DWARF doesn't specify if a DW_TAG_variable is a local, global + // or static variable, so we have to do a little digging by + // looking at the location of a varaible to see if it contains + // a DW_OP_addr opcode _somewhere_ in the definition. I say + // somewhere because clang likes to combine small global variables + // into the same symbol and have locations like: + // DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus + // So if we don't have a DW_TAG_formal_parameter, we can look at + // the location to see if it contains a DW_OP_addr opcode, and + // then we can correctly classify our variables. + if (tag == DW_TAG_formal_parameter) + scope = eValueTypeVariableArgument; + else + { + bool op_error = false; + // Check if the location has a DW_OP_addr with any address value... + lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; + if (!location_is_const_value_data) + { + location_DW_OP_addr = location.GetLocation_DW_OP_addr (0, op_error); + if (op_error) + { + StreamString strm; + location.DumpLocationForAddress (&strm, eDescriptionLevelFull, 0, 0, NULL); + GetObjectFile()->GetModule()->ReportError ("0x%8.8x: %s has an invalid location: %s", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), strm.GetString().c_str()); + } + } + + if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) + { + if (is_external) + scope = eValueTypeVariableGlobal; + else + scope = eValueTypeVariableStatic; + + + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile (); + + if (debug_map_symfile) + { + // When leaving the DWARF in the .o files on darwin, + // when we have a global variable that wasn't initialized, + // the .o file might not have allocated a virtual + // address for the global variable. In this case it will + // have created a symbol for the global variable + // that is undefined/data and external and the value will + // be the byte size of the variable. When we do the + // address map in SymbolFileDWARFDebugMap we rely on + // having an address, we need to do some magic here + // so we can get the correct address for our global + // variable. The address for all of these entries + // will be zero, and there will be an undefined symbol + // in this object file, and the executable will have + // a matching symbol with a good address. So here we + // dig up the correct address and replace it in the + // location for the variable, and set the variable's + // symbol context scope to be that of the main executable + // so the file address will resolve correctly. + bool linked_oso_file_addr = false; + if (is_external && location_DW_OP_addr == 0) + { + // we have a possible uninitialized extern global + ConstString const_name(mangled ? mangled : name); + ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile(); + if (debug_map_objfile) + { + Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); + if (debug_map_symtab) + { + Symbol *exe_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType (const_name, + eSymbolTypeData, + Symtab::eDebugYes, + Symtab::eVisibilityExtern); + if (exe_symbol) + { + if (exe_symbol->ValueIsAddress()) + { + const addr_t exe_file_addr = exe_symbol->GetAddress().GetFileAddress(); + if (exe_file_addr != LLDB_INVALID_ADDRESS) + { + if (location.Update_DW_OP_addr (exe_file_addr)) + { + linked_oso_file_addr = true; + symbol_context_scope = exe_symbol; + } + } + } + } + } + } + } + + if (!linked_oso_file_addr) + { + // The DW_OP_addr is not zero, but it contains a .o file address which + // needs to be linked up correctly. + const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); + if (exe_file_addr != LLDB_INVALID_ADDRESS) + { + // Update the file address for this variable + location.Update_DW_OP_addr (exe_file_addr); + } + else + { + // Variable didn't make it into the final executable + return var_sp; + } + } + } + } + else + { + scope = eValueTypeVariableLocal; + } + } + + if (symbol_context_scope == NULL) + { + switch (parent_tag) + { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + if (sc.function) + { + symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } + break; + + default: + symbol_context_scope = sc.comp_unit; + break; + } + } + + if (symbol_context_scope) + { + var_sp.reset (new Variable (MakeUserID(die->GetOffset()), + name, + mangled, + SymbolFileTypeSP (new SymbolFileType(*this, type_uid)), + scope, + symbol_context_scope, + &decl, + location, + is_external, + is_artificial)); + + var_sp->SetLocationIsConstantValueData (location_is_const_value_data); + } + else + { + // Not ready to parse this variable yet. It might be a global + // or static variable that is in a function scope and the function + // in the symbol context wasn't filled in yet + return var_sp; + } + } + // Cache var_sp even if NULL (the variable was just a specification or + // was missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse + // this DIE over and over later... + m_die_to_variable_sp[die] = var_sp; + } + return var_sp; +} + + +const DWARFDebugInfoEntry * +SymbolFileDWARF::FindBlockContainingSpecification (dw_offset_t func_die_offset, + dw_offset_t spec_block_die_offset, + DWARFCompileUnit **result_die_cu_handle) +{ + // Give the concrete function die specified by "func_die_offset", find the + // concrete block whose DW_AT_specification or DW_AT_abstract_origin points + // to "spec_block_die_offset" + DWARFDebugInfo* info = DebugInfo(); + + const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint(func_die_offset, result_die_cu_handle); + if (die) + { + assert (*result_die_cu_handle); + return FindBlockContainingSpecification (*result_die_cu_handle, die, spec_block_die_offset, result_die_cu_handle); + } + return NULL; +} + + +const DWARFDebugInfoEntry * +SymbolFileDWARF::FindBlockContainingSpecification(DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + dw_offset_t spec_block_die_offset, + DWARFCompileUnit **result_die_cu_handle) +{ + if (die) + { + switch (die->Tag()) + { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + { + if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset) + { + *result_die_cu_handle = dwarf_cu; + return die; + } + + if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET) == spec_block_die_offset) + { + *result_die_cu_handle = dwarf_cu; + return die; + } + } + break; + } + + // Give the concrete function die specified by "func_die_offset", find the + // concrete block whose DW_AT_specification or DW_AT_abstract_origin points + // to "spec_block_die_offset" + for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); child_die != NULL; child_die = child_die->GetSibling()) + { + const DWARFDebugInfoEntry *result_die = FindBlockContainingSpecification (dwarf_cu, + child_die, + spec_block_die_offset, + result_die_cu_handle); + if (result_die) + return result_die; + } + } + + *result_die_cu_handle = NULL; + return NULL; +} + +size_t +SymbolFileDWARF::ParseVariables +( + const SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const lldb::addr_t func_low_pc, + const DWARFDebugInfoEntry *orig_die, + bool parse_siblings, + bool parse_children, + VariableList* cc_variable_list +) +{ + if (orig_die == NULL) + return 0; + + VariableListSP variable_list_sp; + + size_t vars_added = 0; + const DWARFDebugInfoEntry *die = orig_die; + while (die != NULL) + { + dw_tag_t tag = die->Tag(); + + // Check to see if we have already parsed this variable or constant? + if (m_die_to_variable_sp[die]) + { + if (cc_variable_list) + cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]); + } + else + { + // 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)) + { + if (variable_list_sp.get() == NULL) + { + const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die); + dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + switch (parent_tag) + { + case DW_TAG_compile_unit: + if (sc.comp_unit != NULL) + { + variable_list_sp = sc.comp_unit->GetVariableList(false); + if (variable_list_sp.get() == NULL) + { + variable_list_sp.reset(new VariableList()); + sc.comp_unit->SetVariableList(variable_list_sp); + } + } + else + { + GetObjectFile()->GetModule()->ReportError ("parent 0x%8.8" PRIx64 " %s with no valid compile unit in symbol context for 0x%8.8" PRIx64 " %s.\n", + MakeUserID(sc_parent_die->GetOffset()), + DW_TAG_value_to_name (parent_tag), + MakeUserID(orig_die->GetOffset()), + DW_TAG_value_to_name (orig_die->Tag())); + } + 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 + + Block *block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); + if (block == NULL) + { + // This must be a specification or abstract origin with + // a concrete block couterpart in the current function. We need + // to find the concrete block so we can correctly add the + // variable to it + DWARFCompileUnit *concrete_block_die_cu = dwarf_cu; + const DWARFDebugInfoEntry *concrete_block_die = FindBlockContainingSpecification (sc.function->GetID(), + sc_parent_die->GetOffset(), + &concrete_block_die_cu); + if (concrete_block_die) + block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(concrete_block_die->GetOffset())); + } + + if (block != NULL) + { + const bool can_create = false; + variable_list_sp = block->GetBlockVariableList (can_create); + if (variable_list_sp.get() == NULL) + { + variable_list_sp.reset(new VariableList()); + block->SetVariableList(variable_list_sp); + } + } + } + break; + + default: + GetObjectFile()->GetModule()->ReportError ("didn't find appropriate parent DIE for variable list for 0x%8.8" PRIx64 " %s.\n", + MakeUserID(orig_die->GetOffset()), + DW_TAG_value_to_name (orig_die->Tag())); + break; + } + } + + if (variable_list_sp) + { + VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, func_low_pc)); + if (var_sp) + { + variable_list_sp->AddVariableIfUnique (var_sp); + if (cc_variable_list) + cc_variable_list->AddVariableIfUnique (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, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list); + } + + if (parse_siblings) + die = die->GetSibling(); + else + die = NULL; + } + return vars_added; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +ConstString +SymbolFileDWARF::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +SymbolFileDWARF::GetPluginVersion() +{ + return 1; +} + +void +SymbolFileDWARF::CompleteTagDecl (void *baton, clang::TagDecl *decl) +{ + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); +} + +void +SymbolFileDWARF::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) +{ + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); +} + +void +SymbolFileDWARF::DumpIndexes () +{ + StreamFile s(stdout, false); + + s.Printf ("DWARF index for (%s) '%s':", + GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(), + GetObjectFile()->GetFileSpec().GetPath().c_str()); + s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s); + s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s); + s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s); + s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s); + s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s); + s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s); + s.Printf("\nTypes:\n"); m_type_index.Dump (&s); + s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s); +} + +void +SymbolFileDWARF::SearchDeclContext (const clang::DeclContext *decl_context, + const char *name, + llvm::SmallVectorImpl <clang::NamedDecl *> *results) +{ + DeclContextToDIEMap::iterator iter = m_decl_ctx_to_die.find(decl_context); + + if (iter == m_decl_ctx_to_die.end()) + return; + + for (DIEPointerSet::iterator pos = iter->second.begin(), end = iter->second.end(); pos != end; ++pos) + { + const DWARFDebugInfoEntry *context_die = *pos; + + if (!results) + return; + + DWARFDebugInfo* info = DebugInfo(); + + DIEArray die_offsets; + + DWARFCompileUnit* dwarf_cu = NULL; + const DWARFDebugInfoEntry* die = NULL; + + if (m_using_apple_tables) + { + if (m_apple_types_ap.get()) + m_apple_types_ap->FindByName (name, die_offsets); + } + else + { + if (!m_indexed) + Index (); + + m_type_index.Find (ConstString(name), die_offsets); + } + + const size_t num_matches = die_offsets.size(); + + if (num_matches) + { + for (size_t i = 0; i < num_matches; ++i) + { + const dw_offset_t die_offset = die_offsets[i]; + die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + + if (die->GetParent() != context_die) + continue; + + Type *matching_type = ResolveType (dwarf_cu, die); + + clang::QualType qual_type = matching_type->GetClangForwardType().GetQualType(); + + if (const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + results->push_back(tag_decl); + } + else if (const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(qual_type.getTypePtr())) + { + clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + results->push_back(typedef_decl); + } + } + } + } +} + +void +SymbolFileDWARF::FindExternalVisibleDeclsByName (void *baton, + const clang::DeclContext *decl_context, + clang::DeclarationName decl_name, + llvm::SmallVectorImpl <clang::NamedDecl *> *results) +{ + + switch (decl_context->getDeclKind()) + { + case clang::Decl::Namespace: + case clang::Decl::TranslationUnit: + { + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + symbol_file_dwarf->SearchDeclContext (decl_context, decl_name.getAsString().c_str(), results); + } + break; + default: + break; + } +} + +bool +SymbolFileDWARF::LayoutRecordType (void *baton, + const clang::RecordDecl *record_decl, + uint64_t &size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) +{ + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + return symbol_file_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets); +} + + +bool +SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl, + uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) +{ + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl); + bool success = false; + base_offsets.clear(); + vbase_offsets.clear(); + if (pos != m_record_decl_to_layout_map.end()) + { + bit_size = pos->second.bit_size; + alignment = pos->second.alignment; + field_offsets.swap(pos->second.field_offsets); + base_offsets.swap (pos->second.base_offsets); + vbase_offsets.swap (pos->second.vbase_offsets); + m_record_decl_to_layout_map.erase(pos); + success = true; + } + else + { + bit_size = 0; + alignment = 0; + field_offsets.clear(); + } + + if (log) + GetObjectFile()->GetModule()->LogMessage (log, + "SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i", + record_decl, + bit_size, + alignment, + (uint32_t)field_offsets.size(), + (uint32_t)base_offsets.size(), + (uint32_t)vbase_offsets.size(), + success); + return success; +} + + +SymbolFileDWARFDebugMap * +SymbolFileDWARF::GetDebugMapSymfile () +{ + if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) + { + lldb::ModuleSP module_sp (m_debug_map_module_wp.lock()); + if (module_sp) + { + SymbolVendor *sym_vendor = module_sp->GetSymbolVendor(); + if (sym_vendor) + m_debug_map_symfile = (SymbolFileDWARFDebugMap *)sym_vendor->GetSymbolFile(); + } + } + return m_debug_map_symfile; +} + + diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h new file mode 100644 index 000000000000..b6c6d94782db --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -0,0 +1,622 @@ +//===-- 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 SymbolFileDWARF_SymbolFileDWARF_h_ +#define SymbolFileDWARF_SymbolFileDWARF_h_ + +// C Includes +// C++ Includes +#include <list> +#include <map> +#include <set> +#include <vector> + +// Other libraries and framework includes +#include "clang/AST/CharUnits.h" +#include "clang/AST/ExternalASTSource.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +#include "lldb/lldb-private.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Flags.h" +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolContext.h" + +// Project includes +#include "DWARFDefines.h" +#include "HashedNameToDIE.h" +#include "NameToDIE.h" +#include "UniqueDWARFASTType.h" + +//---------------------------------------------------------------------- +// Forward Declarations for this DWARF plugin +//---------------------------------------------------------------------- +class DebugMapModule; +class DWARFAbbreviationDeclaration; +class DWARFAbbreviationDeclarationSet; +class DWARFileUnit; +class DWARFDebugAbbrev; +class DWARFDebugAranges; +class DWARFDebugInfo; +class DWARFDebugInfoEntry; +class DWARFDebugLine; +class DWARFDebugPubnames; +class DWARFDebugRanges; +class DWARFDeclContext; +class DWARFDIECollection; +class DWARFFormValue; +class SymbolFileDWARFDebugMap; + +class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID +{ +public: + friend class SymbolFileDWARFDebugMap; + friend class DebugMapModule; + friend class DWARFCompileUnit; + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + 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 CalculateAbilities (); + virtual void InitializeObject(); + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + virtual uint32_t GetNumCompileUnits(); + virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index); + + virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc); + 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 bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type); + + virtual lldb_private::Type* ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed = true); + virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid); + virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, 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, const lldb_private::ClangNamespaceDecl *namespace_decl, 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, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types); + virtual lldb_private::TypeList * + GetTypeList (); + virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope, + uint32_t type_mask, + lldb_private::TypeList &type_list); + + virtual lldb_private::ClangASTContext & + GetClangASTContext (); + + virtual lldb_private::ClangNamespaceDecl + FindNamespace (const lldb_private::SymbolContext& sc, + const lldb_private::ConstString &name, + const lldb_private::ClangNamespaceDecl *parent_namespace_decl); + + + //------------------------------------------------------------------ + // ClangASTContext callbacks for external source lookups. + //------------------------------------------------------------------ + static void + CompleteTagDecl (void *baton, clang::TagDecl *); + + static void + CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *); + + static void + FindExternalVisibleDeclsByName (void *baton, + const clang::DeclContext *DC, + clang::DeclarationName Name, + llvm::SmallVectorImpl <clang::NamedDecl *> *results); + + static bool + LayoutRecordType (void *baton, + const clang::RecordDecl *record_decl, + uint64_t &size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + + bool + LayoutRecordType (const clang::RecordDecl *record_decl, + uint64_t &size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + + struct LayoutInfo + { + LayoutInfo () : + bit_size(0), + alignment(0), + field_offsets(), + base_offsets(), + vbase_offsets() + { + } + uint64_t bit_size; + uint64_t alignment; + llvm::DenseMap <const clang::FieldDecl *, uint64_t> field_offsets; + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> base_offsets; + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets; + }; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + // 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_ranges_data (); + const lldb_private::DataExtractor& get_debug_str_data (); + const lldb_private::DataExtractor& get_apple_names_data (); + const lldb_private::DataExtractor& get_apple_types_data (); + const lldb_private::DataExtractor& get_apple_namespaces_data (); + const lldb_private::DataExtractor& get_apple_objc_data (); + + + DWARFDebugAbbrev* DebugAbbrev(); + const DWARFDebugAbbrev* DebugAbbrev() const; + + DWARFDebugInfo* DebugInfo(); + const DWARFDebugInfo* DebugInfo() const; + + DWARFDebugRanges* DebugRanges(); + const DWARFDebugRanges* DebugRanges() const; + + const lldb_private::DataExtractor& + GetCachedSectionData (uint32_t got_flag, + lldb::SectionType sect_type, + lldb_private::DataExtractor &data); + + static bool + SupportedVersion(uint16_t version); + + clang::DeclContext * + GetCachedClangDeclContextForDIE (const DWARFDebugInfoEntry *die) + { + DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die); + if (pos != m_die_to_decl_ctx.end()) + return pos->second; + else + return NULL; + } + + clang::DeclContext * + GetClangDeclContextForDIE (const lldb_private::SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die); + + clang::DeclContext * + GetClangDeclContextForDIEOffset (const lldb_private::SymbolContext &sc, dw_offset_t die_offset); + + clang::DeclContext * + GetClangDeclContextContainingDIE (DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + const DWARFDebugInfoEntry **decl_ctx_die); + + clang::DeclContext * + GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset); + + const DWARFDebugInfoEntry * + GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die); + + void + SearchDeclContext (const clang::DeclContext *decl_context, + const char *name, + llvm::SmallVectorImpl <clang::NamedDecl *> *results); + + lldb_private::Flags& + GetFlags () + { + return m_flags; + } + + const lldb_private::Flags& + GetFlags () const + { + return m_flags; + } + + bool + HasForwardDeclForClangType (const lldb_private::ClangASTType &clang_type); + +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), + flagsGotAppleNamesData = (1 << 11), + flagsGotAppleTypesData = (1 << 12), + flagsGotAppleNamespacesData = (1 << 13), + flagsGotAppleObjCData = (1 << 14) + }; + + bool NamespaceDeclMatchesThisSymbolFile (const lldb_private::ClangNamespaceDecl *namespace_decl); + + bool DIEIsInNamespace (const lldb_private::ClangNamespaceDecl *namespace_decl, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry* die); + + DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF); + lldb::CompUnitSP ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx); + DWARFCompileUnit* GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); + DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu); + lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* dwarf_cu, uint32_t cu_idx = UINT32_MAX); + bool GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc); + lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die); + size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc, + lldb_private::Block *parent_block, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + lldb::addr_t subprogram_low_pc, + uint32_t depth); + size_t ParseTypes (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children); + lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new); + lldb_private::Type* ResolveTypeUID (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed); + + lldb::VariableSP ParseVariableDIE( + const lldb_private::SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + const lldb::addr_t func_low_pc); + + size_t ParseVariables( + const lldb_private::SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const lldb::addr_t func_low_pc, + const DWARFDebugInfoEntry *die, + bool parse_siblings, + bool parse_children, + lldb_private::VariableList* cc_variable_list = NULL); + + class DelayedAddObjCClassProperty; + typedef std::vector <DelayedAddObjCClassProperty> DelayedPropertyList; + + bool ClassOrStructIsVirtual ( + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die); + + size_t ParseChildMembers( + const lldb_private::SymbolContext& sc, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + lldb_private::ClangASTType &class_clang_type, + const lldb::LanguageType class_language, + std::vector<clang::CXXBaseSpecifier *>& base_classes, + std::vector<int>& member_accessibilities, + DWARFDIECollection& member_function_dies, + DelayedPropertyList& delayed_properties, + lldb::AccessType &default_accessibility, + bool &is_a_class, + LayoutInfo &layout_info); + + size_t ParseChildParameters( + const lldb_private::SymbolContext& sc, + clang::DeclContext *containing_decl_ctx, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + bool skip_artificial, + bool &is_static, + lldb_private::TypeList* type_list, + std::vector<lldb_private::ClangASTType>& function_args, + std::vector<clang::ParmVarDecl*>& function_param_decls, + unsigned &type_quals, + lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + size_t ParseChildEnumerators( + const lldb_private::SymbolContext& sc, + lldb_private::ClangASTType &clang_type, + bool is_signed, + uint32_t enumerator_byte_size, + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *enum_die); + + void ParseChildArrayInfo( + const lldb_private::SymbolContext& sc, + 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); + + // Given a die_offset, figure out the symbol context representing that die. + bool ResolveFunction (dw_offset_t offset, + DWARFCompileUnit *&dwarf_cu, + lldb_private::SymbolContextList& sc_list); + + bool ResolveFunction (DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + lldb_private::SymbolContextList& sc_list); + + bool FunctionDieMatchesPartialName ( + const DWARFDebugInfoEntry* die, + const DWARFCompileUnit *dwarf_cu, + uint32_t name_type_mask, + const char *partial_name, + const char *base_name_start, + const char *base_name_end); + + void FindFunctions( + const lldb_private::ConstString &name, + const NameToDIE &name_to_die, + lldb_private::SymbolContextList& sc_list); + + void FindFunctions ( + const lldb_private::RegularExpression ®ex, + const NameToDIE &name_to_die, + lldb_private::SymbolContextList& sc_list); + + void FindFunctions ( + const lldb_private::RegularExpression ®ex, + const DWARFMappedHash::MemoryTable &memory_table, + lldb_private::SymbolContextList& sc_list); + + lldb::TypeSP FindDefinitionTypeForDIE ( + DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + const lldb_private::ConstString &type_name); + + lldb::TypeSP FindDefinitionTypeForDWARFDeclContext ( + const DWARFDeclContext &die_decl_ctx); + + lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE ( + const DWARFDebugInfoEntry *die, + const lldb_private::ConstString &type_name, + bool must_be_implementation); + + bool Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu); + + lldb::TypeSP FindCompleteObjCDefinitionType (const lldb_private::ConstString &type_name, + bool header_definition_ok); + + lldb_private::Symbol * GetObjCClassSymbol (const lldb_private::ConstString &objc_class_name); + + void ParseFunctions (const DIEArray &die_offsets, + lldb_private::SymbolContextList& sc_list); + lldb::TypeSP GetTypeForDIE (DWARFCompileUnit *cu, + const DWARFDebugInfoEntry* die); + + uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, lldb_private::TypeList& types); + + void Index(); + + void DumpIndexes(); + + void SetDebugMapModule (const lldb::ModuleSP &module_sp) + { + m_debug_map_module_wp = module_sp; + } + + SymbolFileDWARFDebugMap * + GetDebugMapSymfile (); + + const DWARFDebugInfoEntry * + FindBlockContainingSpecification (dw_offset_t func_die_offset, + dw_offset_t spec_block_die_offset, + DWARFCompileUnit **dwarf_cu_handle); + + const DWARFDebugInfoEntry * + FindBlockContainingSpecification (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + dw_offset_t spec_block_die_offset, + DWARFCompileUnit **dwarf_cu_handle); + + clang::NamespaceDecl * + ResolveNamespaceDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die); + + UniqueDWARFASTTypeMap & + GetUniqueDWARFASTTypeMap (); + + void LinkDeclContextToDIE (clang::DeclContext *decl_ctx, + const DWARFDebugInfoEntry *die) + { + m_die_to_decl_ctx[die] = decl_ctx; + // There can be many DIEs for a single decl context + m_decl_ctx_to_die[decl_ctx].insert(die); + } + + bool + UserIDMatches (lldb::user_id_t uid) const + { + const lldb::user_id_t high_uid = uid & 0xffffffff00000000ull; + if (high_uid) + return high_uid == GetID(); + return true; + } + + lldb::user_id_t + MakeUserID (dw_offset_t die_offset) const + { + return GetID() | die_offset; + } + + static bool + DeclKindIsCXXClass (clang::Decl::Kind decl_kind) + { + switch (decl_kind) + { + case clang::Decl::CXXRecord: + case clang::Decl::ClassTemplateSpecialization: + return true; + default: + break; + } + return false; + } + + bool + ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + bool + ParseTemplateDIE (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + clang::ClassTemplateDecl * + ParseClassTemplateDecl (clang::DeclContext *decl_ctx, + lldb::AccessType access_type, + const char *parent_name, + int tag_decl_kind, + const lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + bool + DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1, + DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2); + + bool + ClassContainsSelector (DWARFCompileUnit *dwarf_cu, + const DWARFDebugInfoEntry *class_die, + const lldb_private::ConstString &selector); + + bool + CopyUniqueClassMethodTypes (SymbolFileDWARF *class_symfile, + lldb_private::Type *class_type, + DWARFCompileUnit* src_cu, + const DWARFDebugInfoEntry *src_class_die, + DWARFCompileUnit* dst_cu, + const DWARFDebugInfoEntry *dst_class_die, + llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures); + + bool + FixupAddress (lldb_private::Address &addr); + + typedef std::set<lldb_private::Type *> TypeSet; + + void + GetTypes (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *die, + dw_offset_t min_die_offset, + dw_offset_t max_die_offset, + uint32_t type_mask, + TypeSet &type_set); + + lldb::ModuleWP m_debug_map_module_wp; + SymbolFileDWARFDebugMap * m_debug_map_symfile; + clang::TranslationUnitDecl * m_clang_tu_decl; + 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_ranges; + lldb_private::DataExtractor m_data_debug_str; + lldb_private::DataExtractor m_data_apple_names; + lldb_private::DataExtractor m_data_apple_types; + lldb_private::DataExtractor m_data_apple_namespaces; + lldb_private::DataExtractor m_data_apple_objc; + + // The unique pointer items below are generated on demand if and when someone accesses + // them through a non const version of this class. + std::unique_ptr<DWARFDebugAbbrev> m_abbr; + std::unique_ptr<DWARFDebugInfo> m_info; + std::unique_ptr<DWARFDebugLine> m_line; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_ap; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_ap; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap; + NameToDIE m_function_basename_index; // All concrete functions + NameToDIE m_function_fullname_index; // All concrete functions + NameToDIE m_function_method_index; // All inlined functions + NameToDIE m_function_selector_index; // All method names for functions of classes + NameToDIE m_objc_class_selectors_index; // Given a class name, find all selectors for the class + NameToDIE m_global_index; // Global and static variables + NameToDIE m_type_index; // All type DIE offsets + NameToDIE m_namespace_index; // All type DIE offsets + bool m_indexed:1, + m_is_external_ast_source:1, + m_using_apple_tables:1; + lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; + + std::unique_ptr<DWARFDebugRanges> m_ranges; + UniqueDWARFASTTypeMap m_unique_ast_type_map; + typedef llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> DIEPointerSet; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap; + typedef llvm::DenseMap<const clang::DeclContext *, DIEPointerSet> DeclContextToDIEMap; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> DIEToVariableSP; + typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::clang_type_t> DIEToClangType; + typedef llvm::DenseMap<lldb::clang_type_t, const DWARFDebugInfoEntry *> ClangTypeToDIE; + typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> RecordDeclToLayoutMap; + DIEToDeclContextMap m_die_to_decl_ctx; + DeclContextToDIEMap m_decl_ctx_to_die; + DIEToTypePtr m_die_to_type; + DIEToVariableSP m_die_to_variable_sp; + DIEToClangType m_forward_decl_die_to_clang_type; + ClangTypeToDIE m_forward_decl_clang_type_to_die; + RecordDeclToLayoutMap m_record_decl_to_layout_map; +}; + +#endif // SymbolFileDWARF_SymbolFileDWARF_h_ diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp new file mode 100644 index 000000000000..a0430e3d52b6 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -0,0 +1,1586 @@ +//===-- 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 "DWARFDebugAranges.h" + +#include "lldb/Core/RangeMap.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Section.h" + +//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT +#if defined(DEBUG_OSO_DMAP) +#include "lldb/Core/StreamFile.h" +#endif +#include "lldb/Core/Timer.h" + +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.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 "LogChannelDWARF.h" +#include "SymbolFileDWARF.h" + +using namespace lldb; +using namespace lldb_private; + +// Subclass lldb_private::Module so we can intercept the "Module::GetObjectFile()" +// (so we can fixup the object file sections) and also for "Module::GetSymbolVendor()" +// (so we can fixup the symbol file id. + + + + +const SymbolFileDWARFDebugMap::FileRangeMap & +SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile) +{ + if (file_range_map_valid) + return file_range_map; + + file_range_map_valid = true; + + Module *oso_module = exe_symfile->GetModuleByCompUnitInfo (this); + if (!oso_module) + return file_range_map; + + ObjectFile *oso_objfile = oso_module->GetObjectFile(); + if (!oso_objfile) + return file_range_map; + + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP)); + if (log) + { + ConstString object_name (oso_module->GetObjectName()); + log->Printf("%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')", + this, + oso_module->GetSpecificationDescription().c_str()); + } + + + std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos; + if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos)) + { + for (auto comp_unit_info : cu_infos) + { + Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab(); + ModuleSP oso_module_sp (oso_objfile->GetModule()); + Symtab *oso_symtab = oso_objfile->GetSymtab(); + + ///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. + + assert (comp_unit_info->first_symbol_index != UINT32_MAX); + // End index is one past the last valid symbol index + const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1; + for (uint32_t idx = comp_unit_info->first_symbol_index + 2; // Skip the N_SO and N_OSO + idx < oso_end_idx; + ++idx) + { + Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx); + if (exe_symbol) + { + if (exe_symbol->IsDebug() == false) + continue; + + switch (exe_symbol->GetType()) + { + default: + break; + + case eSymbolTypeCode: + { + // 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(Mangled::ePreferMangled), + eSymbolTypeCode, + Symtab::eDebugNo, + Symtab::eVisibilityAny); + if (oso_fun_symbol) + { + // Add the inverse OSO file address to debug map entry mapping + exe_symfile->AddOSOFileRange (this, + exe_symbol->GetAddress().GetFileAddress(), + oso_fun_symbol->GetAddress().GetFileAddress(), + std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize())); + + } + } + break; + + case eSymbolTypeData: + { + // 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. + + // 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(Mangled::ePreferMangled), + eSymbolTypeData, + Symtab::eDebugNo, + Symtab::eVisibilityAny); + + if (exe_symbol && oso_gsym_symbol && + exe_symbol->ValueIsAddress() && + oso_gsym_symbol->ValueIsAddress()) + { + // Add the inverse OSO file address to debug map entry mapping + exe_symfile->AddOSOFileRange (this, + exe_symbol->GetAddress().GetFileAddress(), + oso_gsym_symbol->GetAddress().GetFileAddress(), + std::min<addr_t>(exe_symbol->GetByteSize(), oso_gsym_symbol->GetByteSize())); + } + } + break; + } + } + } + + exe_symfile->FinalizeOSOFileRanges (this); + // We don't need the symbols anymore for the .o files + oso_objfile->ClearSymtab(); + } + } + return file_range_map; +} + + +class DebugMapModule : public Module +{ +public: + DebugMapModule (const ModuleSP &exe_module_sp, + uint32_t cu_idx, + const FileSpec& file_spec, + const ArchSpec& arch, + const ConstString *object_name, + off_t object_offset, + const TimeValue *object_mod_time_ptr) : + Module (file_spec, arch, object_name, object_offset, object_mod_time_ptr), + m_exe_module_wp (exe_module_sp), + m_cu_idx (cu_idx) + { + } + + virtual + ~DebugMapModule () + { + } + + + virtual SymbolVendor* + GetSymbolVendor(bool can_create = true, lldb_private::Stream *feedback_strm = NULL) + { + // Scope for locker + if (m_symfile_ap.get() || can_create == false) + return m_symfile_ap.get(); + + ModuleSP exe_module_sp (m_exe_module_wp.lock()); + if (exe_module_sp) + { + // Now get the object file outside of a locking scope + ObjectFile *oso_objfile = GetObjectFile (); + if (oso_objfile) + { + Mutex::Locker locker (m_mutex); + SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm); + if (symbol_vendor) + { + // Set a a pointer to this class to set our OSO DWARF file know + // that the DWARF is being used along with a debug map and that + // it will have the remapped sections that we do below. + SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symbol_vendor->GetSymbolFile()); + + if (!oso_symfile) + return NULL; + + ObjectFile *exe_objfile = exe_module_sp->GetObjectFile(); + SymbolVendor *exe_sym_vendor = exe_module_sp->GetSymbolVendor(); + + if (exe_objfile && exe_sym_vendor) + { + if (oso_symfile->GetNumCompileUnits() == 1) + { + oso_symfile->SetDebugMapModule(exe_module_sp); + // Set the ID of the symbol file DWARF to the index of the OSO + // shifted left by 32 bits to provide a unique prefix for any + // UserID's that get created in the symbol file. + oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull); + } + else + { + oso_symfile->SetID (UINT64_MAX); + } + } + return symbol_vendor; + } + } + } + return NULL; + } + +protected: + ModuleWP m_exe_module_wp; + const uint32_t m_cu_idx; +}; + +void +SymbolFileDWARFDebugMap::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +SymbolFileDWARFDebugMap::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + + +lldb_private::ConstString +SymbolFileDWARFDebugMap::GetPluginNameStatic() +{ + static ConstString g_name("dwarf-debugmap"); + return g_name; +} + +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(), + m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate) +{ +} + + +SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap() +{ +} + +void +SymbolFileDWARFDebugMap::InitializeObject() +{ + // Install our external AST source callbacks so we can complete Clang types. + llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap ( + new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl, + SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl, + NULL, + SymbolFileDWARFDebugMap::LayoutRecordType, + this)); + + GetClangASTContext().SetExternalSource (ast_source_ap); +} + +void +SymbolFileDWARFDebugMap::InitOSO() +{ + if (m_flags.test(kHaveInitializedOSOs)) + return; + + m_flags.set(kHaveInitializedOSOs); + + // If the object file has been stripped, there is no sense in looking further + // as all of the debug symbols for the debug map will not be available + if (m_obj_file->IsStripped()) + return; + + // Also make sure the file type is some sort of executable. Core files, debug + // info files (dSYM), object files (.o files), and stub libraries all can + switch (m_obj_file->GetType()) + { + case ObjectFile::eTypeInvalid: + case ObjectFile::eTypeCoreFile: + case ObjectFile::eTypeDebugInfo: + case ObjectFile::eTypeObjectFile: + case ObjectFile::eTypeStubLibrary: + case ObjectFile::eTypeUnknown: + return; + + case ObjectFile::eTypeExecutable: + case ObjectFile::eTypeDynamicLinker: + case ObjectFile::eTypeSharedLibrary: + break; + } + + // 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) + { + Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP)); + + std::vector<uint32_t> oso_indexes; + // When a mach-o symbol is encoded, the n_type field is encoded in bits + // 23:16, and the n_desc field is encoded in bits 15:0. + // + // To find all N_OSO entries that are part of the DWARF + debug map + // we find only object file symbols with the flags value as follows: + // bits 23:16 == 0x66 (N_OSO) + // bits 15: 0 == 0x0001 (specifies this is a debug map object file) + const uint32_t k_oso_symbol_flags_value = 0x660001u; + + const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithTypeAndFlagsValue(eSymbolTypeObjectFile, k_oso_symbol_flags_value, oso_indexes); + + if (oso_index_count > 0) + { + symtab->AppendSymbolIndexesWithType (eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes); + symtab->AppendSymbolIndexesWithType (eSymbolTypeData, Symtab::eDebugYes, Symtab::eVisibilityAny, m_glob_indexes); + + symtab->SortSymbolIndexesByValue(m_func_indexes, true); + symtab->SortSymbolIndexesByValue(m_glob_indexes, true); + + for (uint32_t sym_idx : m_func_indexes) + { + const Symbol *symbol = symtab->SymbolAtIndex(sym_idx); + lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress(); + lldb::addr_t byte_size = symbol->GetByteSize(); + DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS)); + m_debug_map.Append(debug_map_entry); + } + for (uint32_t sym_idx : m_glob_indexes) + { + const Symbol *symbol = symtab->SymbolAtIndex(sym_idx); + lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress(); + lldb::addr_t byte_size = symbol->GetByteSize(); + DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS)); + m_debug_map.Append(debug_map_entry); + } + m_debug_map.Sort(); + + m_compile_unit_infos.resize(oso_index_count); + + for (uint32_t i=0; i<oso_index_count; ++i) + { + const uint32_t so_idx = oso_indexes[i] - 1; + const uint32_t oso_idx = oso_indexes[i]; + const Symbol *so_symbol = symtab->SymbolAtIndex(so_idx); + const Symbol *oso_symbol = symtab->SymbolAtIndex(oso_idx); + if (so_symbol && + oso_symbol && + so_symbol->GetType() == eSymbolTypeSourceFile && + oso_symbol->GetType() == eSymbolTypeObjectFile) + { + m_compile_unit_infos[i].so_file.SetFile(so_symbol->GetName().AsCString(), false); + m_compile_unit_infos[i].oso_path = oso_symbol->GetName(); + TimeValue oso_mod_time; + oso_mod_time.OffsetWithSeconds(oso_symbol->GetAddress().GetOffset()); + m_compile_unit_infos[i].oso_mod_time = oso_mod_time; + uint32_t sibling_idx = so_symbol->GetSiblingIndex(); + // The sibling index can't be less that or equal to the current index "i" + if (sibling_idx <= i) + { + m_obj_file->GetModule()->ReportError ("N_SO in symbol with UID %u has invalid sibling in debug map, please file a bug and attach the binary listed in this error", so_symbol->GetID()); + } + else + { + const Symbol* last_symbol = symtab->SymbolAtIndex (sibling_idx - 1); + m_compile_unit_infos[i].first_symbol_index = so_idx; + m_compile_unit_infos[i].last_symbol_index = sibling_idx - 1; + m_compile_unit_infos[i].first_symbol_id = so_symbol->GetID(); + m_compile_unit_infos[i].last_symbol_id = last_symbol->GetID(); + + if (log) + log->Printf("Initialized OSO 0x%8.8x: file=%s", i, oso_symbol->GetName().GetCString()); + } + } + else + { + if (oso_symbol == NULL) + m_obj_file->GetModule()->ReportError ("N_OSO symbol[%u] can't be found, please file a bug and attach the binary listed in this error", oso_idx); + else if (so_symbol == NULL) + m_obj_file->GetModule()->ReportError ("N_SO not found for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_idx); + else if (so_symbol->GetType() != eSymbolTypeSourceFile) + m_obj_file->GetModule()->ReportError ("N_SO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", so_symbol->GetType(), oso_idx); + else if (oso_symbol->GetType() != eSymbolTypeSourceFile) + m_obj_file->GetModule()->ReportError ("N_OSO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_symbol->GetType(), oso_idx); + } + } + } + } +} + +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_sp) + { + auto pos = m_oso_map.find (comp_unit_info->oso_path); + if (pos != m_oso_map.end()) + { + comp_unit_info->oso_sp = pos->second; + } + else + { + ObjectFile *obj_file = GetObjectFile(); + comp_unit_info->oso_sp.reset (new OSOInfo()); + m_oso_map[comp_unit_info->oso_path] = comp_unit_info->oso_sp; + const char *oso_path = comp_unit_info->oso_path.GetCString(); + FileSpec oso_file (oso_path, false); + ConstString oso_object; + if (oso_file.Exists()) + { + TimeValue oso_mod_time (oso_file.GetModificationTime()); + if (oso_mod_time != comp_unit_info->oso_mod_time) + { + obj_file->GetModule()->ReportError ("debug map object file '%s' has changed (actual time is 0x%" PRIx64 ", debug map time is 0x%" PRIx64 ") since this executable was linked, file will be ignored", + oso_file.GetPath().c_str(), + oso_mod_time.GetAsSecondsSinceJan1_1970(), + comp_unit_info->oso_mod_time.GetAsSecondsSinceJan1_1970()); + return NULL; + } + + } + else + { + const bool must_exist = true; + + if (!ObjectFile::SplitArchivePathWithObject (oso_path, + oso_file, + oso_object, + must_exist)) + { + return NULL; + } + } + // Always create a new module for .o files. Why? Because we + // use the debug map, to add new sections to each .o file and + // even though a .o file might not have changed, the sections + // that get added to the .o file can change. + comp_unit_info->oso_sp->module_sp.reset (new DebugMapModule (obj_file->GetModule(), + GetCompUnitInfoIndex(comp_unit_info), + oso_file, + m_obj_file->GetModule()->GetArchitecture(), + oso_object ? &oso_object : NULL, + 0, + oso_object ? &comp_unit_info->oso_mod_time : NULL)); + } + } + if (comp_unit_info->oso_sp) + return comp_unit_info->oso_sp->module_sp.get(); + return NULL; +} + + +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) + { + 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; +} + + +uint32_t +SymbolFileDWARFDebugMap::GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info) +{ + if (!m_compile_unit_infos.empty()) + { + const CompileUnitInfo *first_comp_unit_info = &m_compile_unit_infos.front(); + const CompileUnitInfo *last_comp_unit_info = &m_compile_unit_infos.back(); + if (first_comp_unit_info <= comp_unit_info && comp_unit_info <= last_comp_unit_info) + return comp_unit_info - first_comp_unit_info; + } + return UINT32_MAX; +} + +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::GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file) +{ + if (sym_file && sym_file->GetPluginName() == SymbolFileDWARF::GetPluginNameStatic()) + return (SymbolFileDWARF *)sym_file; + return NULL; +} + +SymbolFileDWARF * +SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info) +{ + Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info); + if (oso_module) + { + SymbolVendor *sym_vendor = oso_module->GetSymbolVendor(); + if (sym_vendor) + return GetSymbolFileAsSymbolFileDWARF (sym_vendor->GetSymbolFile()); + } + return NULL; +} + +uint32_t +SymbolFileDWARFDebugMap::CalculateAbilities () +{ + // 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) + { + InitOSO(); + if (!m_compile_unit_infos.empty()) + { + return SymbolFile::CompileUnits | + SymbolFile::Functions | + SymbolFile::Blocks | + SymbolFile::GlobalVariables | + SymbolFile::LocalVariables | + SymbolFile::VariableTypes | + SymbolFile::LineTables ; + } + } + 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) + { + Module *oso_module = GetModuleByCompUnitInfo (&m_compile_unit_infos[cu_idx]); + if (oso_module) + { + FileSpec so_file_spec; + if (GetFileSpecForSO (cu_idx, so_file_spec)) + { + // User zero as the ID to match the compile unit at offset + // zero in each .o file since each .o file can only have + // one compile unit for now. + lldb::user_id_t cu_id = 0; + m_compile_unit_infos[cu_idx].compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(), + NULL, + so_file_spec, + cu_id, + eLanguageTypeUnknown)); + + if (m_compile_unit_infos[cu_idx].compile_unit_sp) + { + // Let our symbol vendor know about this compile unit + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex (cu_idx, m_compile_unit_infos[cu_idx].compile_unit_sp); + } + } + } + comp_unit_sp = m_compile_unit_infos[cu_idx].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].compile_unit_sp.get()) + return &m_compile_unit_infos[i]; + } + return NULL; +} + + +size_t +SymbolFileDWARFDebugMap::GetCompUnitInfosForModule (const lldb_private::Module *module, std::vector<CompileUnitInfo *>& cu_infos) +{ + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t i=0; i<cu_count; ++i) + { + if (module == GetModuleByCompUnitInfo (&m_compile_unit_infos[i])) + cu_infos.push_back (&m_compile_unit_infos[i]); + } + return cu_infos.size(); +} + +lldb::LanguageType +SymbolFileDWARFDebugMap::ParseCompileUnitLanguage (const SymbolContext& sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitLanguage (sc); + return eLanguageTypeUnknown; +} + +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->ParseVariablesForContext (sc); + return 0; +} + + + +Type* +SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid) +{ + const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid); + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + return oso_dwarf->ResolveTypeUID (type_uid); + return NULL; +} + +bool +SymbolFileDWARFDebugMap::ResolveClangOpaqueTypeDefinition (ClangASTType& clang_type) +{ + // We have a struct/union/class/enum that needs to be fully resolved. + return false; +} + +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(); + + const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains (exe_file_addr); + if (debug_map_entry) + { + + sc.symbol = symtab->SymbolAtIndex(debug_map_entry->data.GetExeSymbolIndex()); + + if (sc.symbol != NULL) + { + resolved_flags |= eSymbolContextSymbol; + + uint32_t oso_idx = 0; + CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithID (sc.symbol->GetID(), &oso_idx); + if (comp_unit_info) + { + comp_unit_info->GetFileRangeMap(this); + Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info); + if (oso_module) + { + lldb::addr_t oso_file_addr = exe_file_addr - debug_map_entry->GetRangeBase() + debug_map_entry->data.GetOSOFileAddress(); + Address oso_so_addr; + if (oso_module->ResolveFileAddress(oso_file_addr, oso_so_addr)) + { + resolved_flags |= oso_module->GetSymbolVendor()->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) +{ + const uint32_t initial = sc_list.GetSize(); + const uint32_t cu_count = GetNumCompileUnits(); + + for (uint32_t i=0; i<cu_count; ++i) + { + // If we are checking for inlines, then we need to look through all + // compile units no matter if "file_spec" matches. + bool resolve = check_inlines; + + if (!resolve) + { + FileSpec so_file_spec; + if (GetFileSpecForSO (i, so_file_spec)) + { + // Match the full path if the incoming file_spec has a directory (not just a basename) + const bool full_match = file_spec.GetDirectory(); + resolve = FileSpec::Equal (file_spec, so_file_spec, full_match); + } + } + if (resolve) + { + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i); + if (oso_dwarf) + 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 ClangNamespaceDecl *namespace_decl, + 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, namespace_decl, true, max_matches, variables)) + if (variables.GetSize() > max_matches) + break; + } + } + } + return variables.GetSize() - original_size; +} + +uint32_t +SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, const ClangNamespaceDecl *namespace_decl, 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(); + + uint32_t total_matches = 0; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (name, + namespace_decl, + true, + max_matches, + variables); + if (oso_matches > 0) + { + total_matches += oso_matches; + + // Are we getting all matches? + if (max_matches == UINT32_MAX) + continue; // Yep, continue getting everything + + // If we have found enough matches, lets get out + if (max_matches >= total_matches) + break; + + // Update the max matches for any subsequent calls to find globals + // in any other object files with DWARF + max_matches -= oso_matches; + } + } + // 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) +{ + // 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(); + + uint32_t total_matches = 0; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (regex, + true, + max_matches, + variables); + if (oso_matches > 0) + { + total_matches += oso_matches; + + // Are we getting all matches? + if (max_matches == UINT32_MAX) + continue; // Yep, continue getting everything + + // If we have found enough matches, lets get out + if (max_matches >= total_matches) + break; + + // Update the max matches for any subsequent calls to find globals + // in any other object files with DWARF + max_matches -= oso_matches; + } + } + // Return the number of variable that were appended to the list + return variables.GetSize() - original_size; +} + + +int +SymbolFileDWARFDebugMap::SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info) +{ + const uint32_t symbol_idx = *symbol_idx_ptr; + + if (symbol_idx < comp_unit_info->first_symbol_index) + return -1; + + if (symbol_idx <= comp_unit_info->last_symbol_index) + return 0; + + return 1; +} + + +int +SymbolFileDWARFDebugMap::SymbolContainsSymbolWithID (user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info) +{ + const user_id_t symbol_id = *symbol_idx_ptr; + + if (symbol_id < comp_unit_info->first_symbol_id) + return -1; + + if (symbol_id <= comp_unit_info->last_symbol_id) + 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), + (ComparisonFunction)SymbolContainsSymbolWithIndex); + } + + 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; +} + +SymbolFileDWARFDebugMap::CompileUnitInfo* +SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID (user_id_t symbol_id, 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_id, + &m_compile_unit_infos[0], + m_compile_unit_infos.size(), + sizeof(CompileUnitInfo), + (ComparisonFunction)SymbolContainsSymbolWithID); + } + + 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; +} + + +static void +RemoveFunctionsWithModuleNotEqualTo (const ModuleSP &module_sp, SymbolContextList &sc_list, uint32_t start_idx) +{ + // We found functions in .o files. Not all functions in the .o files + // will have made it into the final output file. The ones that did + // make it into the final output file will have a section whose module + // matches the module from the ObjectFile for this SymbolFile. When + // the modules don't match, then we have something that was in a + // .o file, but doesn't map to anything in the final executable. + uint32_t i=start_idx; + while (i < sc_list.GetSize()) + { + SymbolContext sc; + sc_list.GetContextAtIndex(i, sc); + if (sc.function) + { + const SectionSP section_sp (sc.function->GetAddressRange().GetBaseAddress().GetSection()); + if (section_sp->GetModule() != module_sp) + { + sc_list.RemoveContextAtIndex(i); + continue; + } + } + ++i; + } +} + +uint32_t +SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARFDebugMap::FindFunctions (name = %s)", + name.GetCString()); + + uint32_t initial_size = 0; + if (append) + initial_size = sc_list.GetSize(); + else + sc_list.Clear(); + + uint32_t oso_idx = 0; + SymbolFileDWARF *oso_dwarf; + while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL) + { + uint32_t sc_idx = sc_list.GetSize(); + if (oso_dwarf->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, true, sc_list)) + { + RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx); + } + } + + return sc_list.GetSize() - initial_size; +} + + +uint32_t +SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", + regex.GetText()); + + uint32_t initial_size = 0; + if (append) + initial_size = sc_list.GetSize(); + else + sc_list.Clear(); + + uint32_t oso_idx = 0; + SymbolFileDWARF *oso_dwarf; + while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL) + { + uint32_t sc_idx = sc_list.GetSize(); + + if (oso_dwarf->FindFunctions(regex, include_inlines, true, sc_list)) + { + RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx); + } + } + + return sc_list.GetSize() - initial_size; +} + +size_t +SymbolFileDWARFDebugMap::GetTypes (SymbolContextScope *sc_scope, + uint32_t type_mask, + TypeList &type_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)", + type_mask); + + + uint32_t initial_size = type_list.GetSize(); + SymbolFileDWARF *oso_dwarf = NULL; + if (sc_scope) + { + SymbolContext sc; + sc_scope->CalculateSymbolContext(&sc); + + CompileUnitInfo *cu_info = GetCompUnitInfo (sc); + if (cu_info) + { + oso_dwarf = GetSymbolFileByCompUnitInfo (cu_info); + if (oso_dwarf) + oso_dwarf->GetTypes (sc_scope, type_mask, type_list); + } + } + else + { + uint32_t oso_idx = 0; + while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL) + { + oso_dwarf->GetTypes (sc_scope, type_mask, type_list); + } + } + return type_list.GetSize() - initial_size; +} + + +TypeSP +SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx) +{ + TypeSP type_sp; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx); + if (type_sp) + break; + } + return type_sp; +} + + + +bool +SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso) +{ + if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) + { + m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (skip_dwarf_oso != oso_dwarf && oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(NULL)) + { + m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; + break; + } + } + } + return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes; +} + +TypeSP +SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die, + const ConstString &type_name, + bool must_be_implementation) +{ + TypeSP type_sp; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation); + if (type_sp) + break; + } + return type_sp; +} + +uint32_t +SymbolFileDWARFDebugMap::FindTypes +( + const SymbolContext& sc, + const ConstString &name, + const ClangNamespaceDecl *namespace_decl, + bool append, + uint32_t max_matches, + TypeList& types +) +{ + if (!append) + types.Clear(); + + const uint32_t initial_types_size = types.GetSize(); + SymbolFileDWARF *oso_dwarf; + + if (sc.comp_unit) + { + oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types); + } + else + { + uint32_t oso_idx = 0; + while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL) + oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types); + } + + return types.GetSize() - initial_types_size; +} + +// +//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; +//} + + +ClangNamespaceDecl +SymbolFileDWARFDebugMap::FindNamespace (const lldb_private::SymbolContext& sc, + const lldb_private::ConstString &name, + const ClangNamespaceDecl *parent_namespace_decl) +{ + ClangNamespaceDecl matching_namespace; + SymbolFileDWARF *oso_dwarf; + + if (sc.comp_unit) + { + oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl); + } + else + { + for (uint32_t oso_idx = 0; + ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); + ++oso_idx) + { + matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl); + + if (matching_namespace) + break; + } + } + + return matching_namespace; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +SymbolFileDWARFDebugMap::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +SymbolFileDWARFDebugMap::GetPluginVersion() +{ + return 1; +} + +lldb::CompUnitSP +SymbolFileDWARFDebugMap::GetCompileUnit (SymbolFileDWARF *oso_dwarf) +{ + if (oso_dwarf) + { + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx) + { + SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]); + if (oso_symfile == oso_dwarf) + { + if (!m_compile_unit_infos[cu_idx].compile_unit_sp) + m_compile_unit_infos[cu_idx].compile_unit_sp = ParseCompileUnitAtIndex (cu_idx); + + return m_compile_unit_infos[cu_idx].compile_unit_sp; + } + } + } + assert(!"this shouldn't happen"); + return lldb::CompUnitSP(); +} + +SymbolFileDWARFDebugMap::CompileUnitInfo * +SymbolFileDWARFDebugMap::GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf) +{ + if (oso_dwarf) + { + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx) + { + SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]); + if (oso_symfile == oso_dwarf) + { + return &m_compile_unit_infos[cu_idx]; + } + } + } + return NULL; +} + + +void +SymbolFileDWARFDebugMap::SetCompileUnit (SymbolFileDWARF *oso_dwarf, const CompUnitSP &cu_sp) +{ + if (oso_dwarf) + { + const uint32_t cu_count = GetNumCompileUnits(); + for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx) + { + SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]); + if (oso_symfile == oso_dwarf) + { + if (m_compile_unit_infos[cu_idx].compile_unit_sp) + { + assert (m_compile_unit_infos[cu_idx].compile_unit_sp.get() == cu_sp.get()); + } + else + { + m_compile_unit_infos[cu_idx].compile_unit_sp = cu_sp; + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp); + } + } + } + } +} + + +void +SymbolFileDWARFDebugMap::CompleteTagDecl (void *baton, clang::TagDecl *decl) +{ + SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton; + ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + { + SymbolFileDWARF *oso_dwarf; + + for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (oso_dwarf->HasForwardDeclForClangType (clang_type)) + { + oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); + return; + } + } + } +} + +void +SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) +{ + SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton; + ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + { + SymbolFileDWARF *oso_dwarf; + + for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (oso_dwarf->HasForwardDeclForClangType (clang_type)) + { + oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); + return; + } + } + } +} + +bool +SymbolFileDWARFDebugMap::LayoutRecordType (void *baton, + const clang::RecordDecl *record_decl, + uint64_t &size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) +{ + SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton; + SymbolFileDWARF *oso_dwarf; + for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (oso_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets)) + return true; + } + return false; +} + + + +clang::DeclContext* +SymbolFileDWARFDebugMap::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid) +{ + const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid); + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + return oso_dwarf->GetClangDeclContextContainingTypeUID (type_uid); + return NULL; +} + +clang::DeclContext* +SymbolFileDWARFDebugMap::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid) +{ + const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid); + SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx); + if (oso_dwarf) + return oso_dwarf->GetClangDeclContextForTypeUID (sc, type_uid); + return NULL; +} + +bool +SymbolFileDWARFDebugMap::AddOSOFileRange (CompileUnitInfo *cu_info, + lldb::addr_t exe_file_addr, + lldb::addr_t oso_file_addr, + lldb::addr_t oso_byte_size) +{ + const uint32_t debug_map_idx = m_debug_map.FindEntryIndexThatContains(exe_file_addr); + if (debug_map_idx != UINT32_MAX) + { + DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(exe_file_addr); + debug_map_entry->data.SetOSOFileAddress(oso_file_addr); + cu_info->file_range_map.Append(FileRangeMap::Entry(oso_file_addr, oso_byte_size, exe_file_addr)); + return true; + } + return false; +} + +void +SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (CompileUnitInfo *cu_info) +{ + cu_info->file_range_map.Sort(); +#if defined(DEBUG_OSO_DMAP) + const FileRangeMap &oso_file_range_map = cu_info->GetFileRangeMap(this); + const size_t n = oso_file_range_map.GetSize(); + printf ("SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (cu_info = %p) %s\n", + cu_info, + cu_info->oso_sp->module_sp->GetFileSpec().GetPath().c_str()); + for (size_t i=0; i<n; ++i) + { + const FileRangeMap::Entry &entry = oso_file_range_map.GetEntryRef(i); + printf ("oso [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") ==> exe [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", + entry.GetRangeBase(), entry.GetRangeEnd(), + entry.data, entry.data + entry.GetByteSize()); + } +#endif +} + +lldb::addr_t +SymbolFileDWARFDebugMap::LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr) +{ + CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_symfile); + if (cu_info) + { + const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr); + if (oso_range_entry) + { + const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data); + if (debug_map_entry) + { + const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase(); + const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset; + return exe_file_addr; + } + } + } + return LLDB_INVALID_ADDRESS; +} + +bool +SymbolFileDWARFDebugMap::LinkOSOAddress (Address &addr) +{ + // Make sure this address hasn't been fixed already + Module *exe_module = GetObjectFile()->GetModule().get(); + Module *addr_module = addr.GetModule().get(); + if (addr_module == exe_module) + return true; // Address is already in terms of the main executable module + + CompileUnitInfo *cu_info = GetCompileUnitInfo (GetSymbolFileAsSymbolFileDWARF(addr_module->GetSymbolVendor()->GetSymbolFile())); + if (cu_info) + { + const lldb::addr_t oso_file_addr = addr.GetFileAddress(); + const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr); + if (oso_range_entry) + { + const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data); + if (debug_map_entry) + { + const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase(); + const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset; + return exe_module->ResolveFileAddress(exe_file_addr, addr); + } + } + } + return true; +} + +LineTable * +SymbolFileDWARFDebugMap::LinkOSOLineTable (SymbolFileDWARF *oso_dwarf, LineTable *line_table) +{ + CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_dwarf); + if (cu_info) + return line_table->LinkLineTable(cu_info->GetFileRangeMap(this)); + return NULL; +} + +size_t +SymbolFileDWARFDebugMap::AddOSOARanges (SymbolFileDWARF* dwarf2Data, DWARFDebugAranges* debug_aranges) +{ + size_t num_line_entries_added = 0; + if (debug_aranges && dwarf2Data) + { + CompileUnitInfo *compile_unit_info = GetCompileUnitInfo(dwarf2Data); + if (compile_unit_info) + { + const FileRangeMap &file_range_map = compile_unit_info->GetFileRangeMap(this); + for (size_t idx = 0; + idx < file_range_map.GetSize(); + idx++) + { + const FileRangeMap::Entry* entry = file_range_map.GetEntryAtIndex(idx); + if (entry) + { + printf ("[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", entry->GetRangeBase(), entry->GetRangeEnd()); + debug_aranges->AppendRange(dwarf2Data->GetID(), entry->GetRangeBase(), entry->GetRangeEnd()); + num_line_entries_added++; + } + } + } + } + return num_line_entries_added; +} + diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h new file mode 100644 index 000000000000..06330b98dc19 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -0,0 +1,420 @@ +//===-- 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 SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ +#define SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ + + +#include <vector> +#include <bitset> + +#include "clang/AST/CharUnits.h" + +#include "lldb/Core/RangeMap.h" +#include "lldb/Symbol/SymbolFile.h" + +#include "UniqueDWARFASTType.h" + +class SymbolFileDWARF; +class DWARFCompileUnit; +class DWARFDebugAranges; +class DWARFDebugInfoEntry; +class DWARFDeclContext; +class DebugMapModule; + +class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile +{ +public: + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + 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 CalculateAbilities (); + + virtual void InitializeObject(); + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + virtual uint32_t GetNumCompileUnits (); + virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index); + + virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc); + 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* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid); + virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid); + virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type); + 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, const lldb_private::ClangNamespaceDecl *namespace_decl, 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, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types); + virtual lldb_private::ClangNamespaceDecl + FindNamespace (const lldb_private::SymbolContext& sc, + const lldb_private::ConstString &name, + const lldb_private::ClangNamespaceDecl *parent_namespace_decl); + virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope, + uint32_t type_mask, + lldb_private::TypeList &type_list); + + + //------------------------------------------------------------------ + // ClangASTContext callbacks for external source lookups. + //------------------------------------------------------------------ + static void + CompleteTagDecl (void *baton, clang::TagDecl *); + + static void + CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *); + + static bool + LayoutRecordType (void *baton, + const clang::RecordDecl *record_decl, + uint64_t &size, + uint64_t &alignment, + llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, + llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + enum + { + kHaveInitializedOSOs = (1 << 0), + kNumFlags + }; + + friend class DWARFCompileUnit; + friend class SymbolFileDWARF; + friend class DebugMapModule; + struct OSOInfo + { + lldb::ModuleSP module_sp; + + OSOInfo() : + module_sp () + { + } + }; + + typedef std::shared_ptr<OSOInfo> OSOInfoSP; + + typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> FileRangeMap; + + //------------------------------------------------------------------ + // Class specific types + //------------------------------------------------------------------ + struct CompileUnitInfo + { + lldb_private::FileSpec so_file; + lldb_private::ConstString oso_path; + lldb_private::TimeValue oso_mod_time; + OSOInfoSP oso_sp; + lldb::CompUnitSP compile_unit_sp; + uint32_t first_symbol_index; + uint32_t last_symbol_index; + uint32_t first_symbol_id; + uint32_t last_symbol_id; + FileRangeMap file_range_map; + bool file_range_map_valid; + + + CompileUnitInfo() : + so_file (), + oso_path (), + oso_mod_time (), + oso_sp (), + compile_unit_sp (), + first_symbol_index (UINT32_MAX), + last_symbol_index (UINT32_MAX), + first_symbol_id (UINT32_MAX), + last_symbol_id (UINT32_MAX), + file_range_map (), + file_range_map_valid (false) + { + } + + const FileRangeMap & + GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile); + }; + + //------------------------------------------------------------------ + // Protected Member Functions + //------------------------------------------------------------------ + void + InitOSO (); + + static uint32_t + GetOSOIndexFromUserID (lldb::user_id_t uid) + { + return (uint32_t)((uid >> 32ull) - 1ull); + } + + static SymbolFileDWARF * + GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file); + + bool + GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec); + + CompileUnitInfo * + GetCompUnitInfo (const lldb_private::SymbolContext& sc); + + size_t + GetCompUnitInfosForModule (const lldb_private::Module *oso_module, + std::vector<CompileUnitInfo *>& cu_infos); + + 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); + + uint32_t + GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info); + + 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); + + CompileUnitInfo * + GetCompileUnitInfoForSymbolWithID (lldb::user_id_t symbol_id, uint32_t *oso_idx_ptr); + + static int + SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info); + + static int + SymbolContainsSymbolWithID (lldb::user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info); + + uint32_t + PrivateFindGlobalVariables (const lldb_private::ConstString &name, + const lldb_private::ClangNamespaceDecl *namespace_decl, + const std::vector<uint32_t> &name_symbol_indexes, + uint32_t max_matches, + lldb_private::VariableList& variables); + + + void + SetCompileUnit (SymbolFileDWARF *oso_dwarf, const lldb::CompUnitSP &cu_sp); + + lldb::CompUnitSP + GetCompileUnit (SymbolFileDWARF *oso_dwarf); + + CompileUnitInfo * + GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf); + + lldb::TypeSP + FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx); + + bool + Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso); + + lldb::TypeSP + FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die, + const lldb_private::ConstString &type_name, + bool must_be_implementation); + + + UniqueDWARFASTTypeMap & + GetUniqueDWARFASTTypeMap () + { + return m_unique_ast_type_map; + } + + + //------------------------------------------------------------------ + // OSOEntry + //------------------------------------------------------------------ + class OSOEntry + { + public: + + OSOEntry () : + m_exe_sym_idx (UINT32_MAX), + m_oso_file_addr (LLDB_INVALID_ADDRESS) + { + } + + OSOEntry (uint32_t exe_sym_idx, + lldb::addr_t oso_file_addr) : + m_exe_sym_idx (exe_sym_idx), + m_oso_file_addr (oso_file_addr) + { + } + + uint32_t + GetExeSymbolIndex () const + { + return m_exe_sym_idx; + } + + bool + operator < (const OSOEntry &rhs) const + { + return m_exe_sym_idx < rhs.m_exe_sym_idx; + } + + lldb::addr_t + GetOSOFileAddress () const + { + return m_oso_file_addr; + } + + void + SetOSOFileAddress (lldb::addr_t oso_file_addr) + { + m_oso_file_addr = oso_file_addr; + } + protected: + uint32_t m_exe_sym_idx; + lldb::addr_t m_oso_file_addr; + }; + + typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap; + + //------------------------------------------------------------------ + // 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; + std::map<lldb_private::ConstString, OSOInfoSP> m_oso_map; + UniqueDWARFASTTypeMap m_unique_ast_type_map; + lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; + DebugMap m_debug_map; + + //------------------------------------------------------------------ + // When an object file from the debug map gets parsed in + // SymbolFileDWARF, it needs to tell the debug map about the object + // files addresses by calling this function once for each N_FUN, + // N_GSYM and N_STSYM and after all entries in the debug map have + // been matched up, FinalizeOSOFileRanges() should be called. + //------------------------------------------------------------------ + bool + AddOSOFileRange (CompileUnitInfo *cu_info, + lldb::addr_t exe_file_addr, + lldb::addr_t oso_file_addr, + lldb::addr_t oso_byte_size); + + //------------------------------------------------------------------ + // Called after calling AddOSOFileRange() for each object file debug + // map entry to finalize the info for the unlinked compile unit. + //------------------------------------------------------------------ + void + FinalizeOSOFileRanges (CompileUnitInfo *cu_info); + + //------------------------------------------------------------------ + /// Convert \a addr from a .o file address, to an executable address. + /// + /// @param[in] addr + /// A section offset address from a .o file + /// + /// @return + /// Returns true if \a addr was converted to be an executable + /// section/offset address, false otherwise. + //------------------------------------------------------------------ + bool + LinkOSOAddress (lldb_private::Address &addr); + + //------------------------------------------------------------------ + /// Convert a .o file "file address" to an executable "file address". + /// + /// @param[in] oso_symfile + /// The DWARF symbol file that contains \a oso_file_addr + /// + /// @param[in] oso_file_addr + /// A .o file "file address" to convert. + /// + /// @return + /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the + /// linked executable, otherwise a valid "file address" from the + /// linked executable that contains the debug map. + //------------------------------------------------------------------ + lldb::addr_t + LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr); + + //------------------------------------------------------------------ + /// Given a line table full of lines with "file adresses" that are + /// for a .o file represented by \a oso_symfile, link a new line table + /// and return it. + /// + /// @param[in] oso_symfile + /// The DWARF symbol file that produced the \a line_table + /// + /// @param[in] addr + /// A section offset address from a .o file + /// + /// @return + /// Returns a valid line table full of linked addresses, or NULL + /// if none of the line table adresses exist in the main + /// executable. + //------------------------------------------------------------------ + lldb_private::LineTable * + LinkOSOLineTable (SymbolFileDWARF *oso_symfile, + lldb_private::LineTable *line_table); + + size_t + AddOSOARanges (SymbolFileDWARF* dwarf2Data, + DWARFDebugAranges* debug_aranges); +}; + +#endif // #ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_ diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp new file mode 100644 index 000000000000..94044c0feb30 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -0,0 +1,94 @@ +//===-- UniqueDWARFASTType.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UniqueDWARFASTType.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Symbol/Declaration.h" + +#include "DWARFDebugInfoEntry.h" + +bool +UniqueDWARFASTTypeList::Find +( + SymbolFileDWARF *symfile, + const DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + const lldb_private::Declaration &decl, + const int32_t byte_size, + UniqueDWARFASTType &entry +) const +{ + collection::const_iterator pos, end = m_collection.end(); + for (pos = m_collection.begin(); pos != end; ++pos) + { + // Make sure the tags match + if (pos->m_die->Tag() == die->Tag()) + { + // Validate byte sizes of both types only if both are valid. + if (pos->m_byte_size < 0 || byte_size < 0 || pos->m_byte_size == byte_size) + { + // Make sure the file and line match + if (pos->m_declaration == decl) + { + // The type has the same name, and was defined on the same + // file and line. Now verify all of the parent DIEs match. + const DWARFDebugInfoEntry *parent_arg_die = die->GetParent(); + const DWARFDebugInfoEntry *parend_pos_die = pos->m_die->GetParent(); + bool match = true; + bool done = false; + while (!done && match && parent_arg_die && parend_pos_die) + { + if (parent_arg_die->Tag() == parend_pos_die->Tag()) + { + const dw_tag_t tag = parent_arg_die->Tag(); + switch (tag) + { + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_namespace: + { + const char *parent_arg_die_name = parent_arg_die->GetName(symfile, cu); + if (parent_arg_die_name == NULL) // Anonymous (i.e. no-name) struct + { + match = false; + } + else + { + const char *parent_pos_die_name = parend_pos_die->GetName(pos->m_symfile, pos->m_cu); + if (parent_pos_die_name == NULL || strcmp (parent_arg_die_name, parent_pos_die_name)) + match = false; + } + } + break; + + case DW_TAG_compile_unit: + done = true; + break; + } + } + parent_arg_die = parent_arg_die->GetParent(); + parend_pos_die = parend_pos_die->GetParent(); + } + + if (match) + { + entry = *pos; + return true; + } + } + } + } + } + return false; +} diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h new file mode 100644 index 000000000000..c85e175235ca --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -0,0 +1,175 @@ +//===-- UniqueDWARFASTType.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_UniqueDWARFASTType_h_ +#define lldb_UniqueDWARFASTType_h_ + +// C Includes +// C++ Includes +#include <vector> + +// Other libraries and framework includes +#include "llvm/ADT/DenseMap.h" + +// Project includes +#include "lldb/Symbol/Declaration.h" + +class DWARFCompileUnit; +class DWARFDebugInfoEntry; +class SymbolFileDWARF; + +class UniqueDWARFASTType +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + UniqueDWARFASTType () : + m_type_sp (), + m_symfile (NULL), + m_cu (NULL), + m_die (NULL), + m_declaration (), + m_byte_size (-1) // Set to negative value to make sure we have a valid value + { + } + + UniqueDWARFASTType (lldb::TypeSP &type_sp, + SymbolFileDWARF *symfile, + DWARFCompileUnit *cu, + DWARFDebugInfoEntry *die, + const lldb_private::Declaration &decl, + int32_t byte_size) : + m_type_sp (type_sp), + m_symfile (symfile), + m_cu (cu), + m_die (die), + m_declaration (decl), + m_byte_size (byte_size) + { + } + + UniqueDWARFASTType (const UniqueDWARFASTType &rhs) : + m_type_sp (rhs.m_type_sp), + m_symfile (rhs.m_symfile), + m_cu (rhs.m_cu), + m_die (rhs.m_die), + m_declaration (rhs.m_declaration), + m_byte_size (rhs.m_byte_size) + { + } + + ~UniqueDWARFASTType() + { + } + + UniqueDWARFASTType & + operator= (const UniqueDWARFASTType &rhs) + { + if (this != &rhs) + { + m_type_sp = rhs.m_type_sp; + m_symfile = rhs.m_symfile; + m_cu = rhs.m_cu; + m_die = rhs.m_die; + m_declaration = rhs.m_declaration; + m_byte_size = rhs.m_byte_size; + } + return *this; + } + + lldb::TypeSP m_type_sp; + SymbolFileDWARF *m_symfile; + const DWARFCompileUnit *m_cu; + const DWARFDebugInfoEntry *m_die; + lldb_private::Declaration m_declaration; + int32_t m_byte_size; +}; + +class UniqueDWARFASTTypeList +{ +public: + UniqueDWARFASTTypeList () : + m_collection() + { + } + + ~UniqueDWARFASTTypeList () + { + } + + uint32_t + GetSize() + { + return (uint32_t)m_collection.size(); + } + + void + Append (const UniqueDWARFASTType &entry) + { + m_collection.push_back (entry); + } + + bool + Find (SymbolFileDWARF *symfile, + const DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + const lldb_private::Declaration &decl, + const int32_t byte_size, + UniqueDWARFASTType &entry) const; + +protected: + typedef std::vector<UniqueDWARFASTType> collection; + collection m_collection; +}; + +class UniqueDWARFASTTypeMap +{ +public: + UniqueDWARFASTTypeMap () : + m_collection () + { + } + + ~UniqueDWARFASTTypeMap () + { + } + + void + Insert (const lldb_private::ConstString &name, + const UniqueDWARFASTType &entry) + { + m_collection[name.GetCString()].Append (entry); + } + + bool + Find (const lldb_private::ConstString &name, + SymbolFileDWARF *symfile, + const DWARFCompileUnit *cu, + const DWARFDebugInfoEntry *die, + const lldb_private::Declaration &decl, + const int32_t byte_size, + UniqueDWARFASTType &entry) const + { + const char *unique_name_cstr = name.GetCString(); + collection::const_iterator pos = m_collection.find (unique_name_cstr); + if (pos != m_collection.end()) + { + return pos->second.Find (symfile, cu, die, decl, byte_size, entry); + } + return false; + } + +protected: + // A unique name string should be used + typedef llvm::DenseMap<const char *, UniqueDWARFASTTypeList> collection; + collection m_collection; +}; + +#endif // lldb_UniqueDWARFASTType_h_ diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp new file mode 100644 index 000000000000..9beba517ec83 --- /dev/null +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -0,0 +1,407 @@ +//===-- SymbolFileSymtab.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileSymtab.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Symtab.h" +#include "lldb/Symbol/TypeList.h" + +using namespace lldb; +using namespace lldb_private; + +void +SymbolFileSymtab::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +SymbolFileSymtab::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + + +lldb_private::ConstString +SymbolFileSymtab::GetPluginNameStatic() +{ + static ConstString g_name("symtab"); + return g_name; +} + +const char * +SymbolFileSymtab::GetPluginDescriptionStatic() +{ + return "Reads debug symbols from an object file's symbol table."; +} + + +SymbolFile* +SymbolFileSymtab::CreateInstance (ObjectFile* obj_file) +{ + return new SymbolFileSymtab(obj_file); +} + +size_t +SymbolFileSymtab::GetTypes (SymbolContextScope *sc_scope, uint32_t type_mask, lldb_private::TypeList &type_list) +{ + return 0; +} + +SymbolFileSymtab::SymbolFileSymtab(ObjectFile* obj_file) : + SymbolFile(obj_file), + m_source_indexes(), + m_func_indexes(), + m_code_indexes(), + m_objc_class_name_to_index () +{ +} + +SymbolFileSymtab::~SymbolFileSymtab() +{ +} + +ClangASTContext & +SymbolFileSymtab::GetClangASTContext () +{ + ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext(); + + return ast; +} + +uint32_t +SymbolFileSymtab::CalculateAbilities () +{ + uint32_t abilities = 0; + if (m_obj_file) + { + const Symtab *symtab = m_obj_file->GetSymtab(); + if (symtab) + { + //---------------------------------------------------------------------- + // The snippet of code below will get the indexes the module symbol + // table entries that are code, data, or function related (debug info), + // sort them by value (address) and dump the sorted symbols. + //---------------------------------------------------------------------- + if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes)) + { + abilities |= CompileUnits; + } + + if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes)) + { + symtab->SortSymbolIndexesByValue(m_func_indexes, true); + abilities |= Functions; + } + + if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny, m_code_indexes)) + { + symtab->SortSymbolIndexesByValue(m_code_indexes, true); + } + + if (symtab->AppendSymbolIndexesWithType(eSymbolTypeData, m_data_indexes)) + { + symtab->SortSymbolIndexesByValue(m_data_indexes, true); + abilities |= GlobalVariables; + } + + lldb_private::Symtab::IndexCollection objc_class_indexes; + if (symtab->AppendSymbolIndexesWithType (eSymbolTypeObjCClass, objc_class_indexes)) + { + symtab->AppendSymbolNamesToMap (objc_class_indexes, + true, + true, + m_objc_class_name_to_index); + m_objc_class_name_to_index.Sort(); + } + } + } + return abilities; +} + +uint32_t +SymbolFileSymtab::GetNumCompileUnits() +{ + // If we don't have any source file symbols we will just have one compile unit for + // the entire object file + if (m_source_indexes.empty()) + return 0; + + // If we have any source file symbols we will logically orgnize the object symbols + // using these. + return m_source_indexes.size(); +} + +CompUnitSP +SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) +{ + CompUnitSP cu_sp; + + // If we don't have any source file symbols we will just have one compile unit for + // the entire object file + if (idx < m_source_indexes.size()) + { + const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]); + if (cu_symbol) + cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetMangled().GetName().AsCString(), 0, eLanguageTypeUnknown)); + } + return cu_sp; +} + +lldb::LanguageType +SymbolFileSymtab::ParseCompileUnitLanguage (const SymbolContext& sc) +{ + return eLanguageTypeUnknown; +} + + +size_t +SymbolFileSymtab::ParseCompileUnitFunctions (const SymbolContext &sc) +{ + size_t num_added = 0; + // We must at least have a valid compile unit + assert (sc.comp_unit != NULL); + const Symtab *symtab = m_obj_file->GetSymtab(); + const Symbol *curr_symbol = NULL; + const Symbol *next_symbol = NULL; +// const char *prefix = m_obj_file->SymbolPrefix(); +// if (prefix == NULL) +// prefix == ""; +// +// const uint32_t prefix_len = strlen(prefix); + + // If we don't have any source file symbols we will just have one compile unit for + // the entire object file + if (m_source_indexes.empty()) + { + // The only time we will have a user ID of zero is when we don't have + // and source file symbols and we declare one compile unit for the + // entire object file + if (!m_func_indexes.empty()) + { + + } + + if (!m_code_indexes.empty()) + { +// StreamFile s(stdout); +// symtab->Dump(&s, m_code_indexes); + + uint32_t idx = 0; // Index into the indexes + const uint32_t num_indexes = m_code_indexes.size(); + for (idx = 0; idx < num_indexes; ++idx) + { + uint32_t symbol_idx = m_code_indexes[idx]; + curr_symbol = symtab->SymbolAtIndex(symbol_idx); + if (curr_symbol) + { + // Union of all ranges in the function DIE (if the function is discontiguous) + AddressRange func_range(curr_symbol->GetAddress(), 0); + if (func_range.GetBaseAddress().IsSectionOffset()) + { + uint32_t symbol_size = curr_symbol->GetByteSize(); + if (symbol_size != 0 && !curr_symbol->GetSizeIsSibling()) + func_range.SetByteSize(symbol_size); + else if (idx + 1 < num_indexes) + { + next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]); + if (next_symbol) + { + func_range.SetByteSize(next_symbol->GetAddress().GetOffset() - curr_symbol->GetAddress().GetOffset()); + } + } + + FunctionSP func_sp(new Function(sc.comp_unit, + symbol_idx, // UserID is the DIE offset + LLDB_INVALID_UID, // We don't have any type info for this function + curr_symbol->GetMangled(), // Linker/mangled name + NULL, // no return type for a code symbol... + func_range)); // first address range + + if (func_sp.get() != NULL) + { + sc.comp_unit->AddFunction(func_sp); + ++num_added; + } + } + } + } + + } + } + else + { + // We assume we + } + return num_added; +} + +bool +SymbolFileSymtab::ParseCompileUnitLineTable (const SymbolContext &sc) +{ + return false; +} + +bool +SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files) +{ + return false; +} + +size_t +SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc) +{ + return 0; +} + + +size_t +SymbolFileSymtab::ParseTypes (const SymbolContext &sc) +{ + return 0; +} + + +size_t +SymbolFileSymtab::ParseVariablesForContext (const SymbolContext& sc) +{ + return 0; +} + +Type* +SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid) +{ + return NULL; +} + +bool +SymbolFileSymtab::ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_opaque_type) +{ + return false; +} + +ClangNamespaceDecl +SymbolFileSymtab::FindNamespace (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl) +{ + return ClangNamespaceDecl(); +} + +uint32_t +SymbolFileSymtab::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) +{ + if (m_obj_file->GetSymtab() == NULL) + return 0; + + uint32_t resolved_flags = 0; + if (resolve_scope & eSymbolContextSymbol) + { + sc.symbol = m_obj_file->GetSymtab()->FindSymbolContainingFileAddress(so_addr.GetFileAddress()); + if (sc.symbol) + resolved_flags |= eSymbolContextSymbol; + } + return resolved_flags; +} + +uint32_t +SymbolFileSymtab::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) +{ + return 0; +} + +uint32_t +SymbolFileSymtab::FindGlobalVariables(const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables) +{ + return 0; +} + +uint32_t +SymbolFileSymtab::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) +{ + return 0; +} + +uint32_t +SymbolFileSymtab::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileSymtab::FindFunctions (name = '%s')", + name.GetCString()); + // If we ever support finding STABS or COFF debug info symbols, + // we will need to add support here. We are not trying to find symbols + // here, just "lldb_private::Function" objects that come from complete + // debug information. Any symbol queries should go through the symbol + // table itself in the module's object file. + return 0; +} + +uint32_t +SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "SymbolFileSymtab::FindFunctions (regex = '%s')", + regex.GetText()); + // If we ever support finding STABS or COFF debug info symbols, + // we will need to add support here. We are not trying to find symbols + // here, just "lldb_private::Function" objects that come from complete + // debug information. Any symbol queries should go through the symbol + // table itself in the module's object file. + return 0; +} + +static int CountMethodArgs(const char *method_signature) +{ + int num_args = 0; + + for (const char *colon_pos = strchr(method_signature, ':'); + colon_pos != NULL; + colon_pos = strchr(colon_pos + 1, ':')) + { + num_args++; + } + + return num_args; +} + +uint32_t +SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc, + const lldb_private::ConstString &name, + const ClangNamespaceDecl *namespace_decl, + bool append, + uint32_t max_matches, + lldb_private::TypeList& types) +{ + return 0; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +SymbolFileSymtab::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +SymbolFileSymtab::GetPluginVersion() +{ + return 1; +} diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h new file mode 100644 index 000000000000..914efe6eb3c2 --- /dev/null +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -0,0 +1,142 @@ +//===-- SymbolFileSymtab.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_SymbolFileSymtab_h_ +#define liblldb_SymbolFileSymtab_h_ + +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/Symtab.h" +#include <vector> + +class SymbolFileSymtab : public lldb_private::SymbolFile +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::SymbolFile* + CreateInstance (lldb_private::ObjectFile* obj_file); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFileSymtab(lldb_private::ObjectFile* obj_file); + + virtual + ~SymbolFileSymtab(); + + virtual uint32_t CalculateAbilities (); + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + virtual uint32_t + GetNumCompileUnits(); + + virtual lldb::CompUnitSP + ParseCompileUnitAtIndex(uint32_t index); + + virtual lldb::LanguageType + ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc); + + 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 bool + ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type); + + 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, const lldb_private::ClangNamespaceDecl *namespace_decl, 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, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + + virtual uint32_t + FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list); + + virtual uint32_t + FindTypes (const lldb_private::SymbolContext& sc,const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types); + + virtual size_t + GetTypes (lldb_private::SymbolContextScope *sc_scope, + uint32_t type_mask, + lldb_private::TypeList &type_list); + + virtual lldb_private::ClangNamespaceDecl + FindNamespace (const lldb_private::SymbolContext& sc, + const lldb_private::ConstString &name, + const lldb_private::ClangNamespaceDecl *parent_namespace_decl); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + +protected: + typedef std::map<lldb_private::ConstString, lldb::TypeSP> TypeMap; + + lldb_private::Symtab::IndexCollection m_source_indexes; + lldb_private::Symtab::IndexCollection m_func_indexes; + lldb_private::Symtab::IndexCollection m_code_indexes; + lldb_private::Symtab::IndexCollection m_data_indexes; + lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index; + TypeMap m_objc_class_types; + + lldb_private::ClangASTContext & + GetClangASTContext (); + +private: + DISALLOW_COPY_AND_ASSIGN (SymbolFileSymtab); +}; + + +#endif // liblldb_SymbolFileSymtab_h_ |