aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/SymbolFile
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins/SymbolFile
downloadsrc-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')
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp211
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAttribute.h45
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp1027
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h210
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp62
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h51
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp202
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h74
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp274
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h76
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp177
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp797
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp2317
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h457
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp1436
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h225
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp48
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h29
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp132
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h57
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp296
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h38
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp166
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h99
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp192
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h46
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp104
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h109
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp497
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.h116
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp599
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp172
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h24
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.h34
-rw-r--r--source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h933
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp232
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.cpp87
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.h65
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp7973
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h622
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp1586
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h420
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h175
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp407
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h142
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, &regex_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 = &section->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 &regex,
+ 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 &regex,
+ 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 &regex,
+ const NameToDIE &name_to_die,
+ lldb_private::SymbolContextList& sc_list);
+
+ void FindFunctions (
+ const lldb_private::RegularExpression &regex,
+ 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_