Index: lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/Inputs/debug-types-basic.cpp @@ -0,0 +1,13 @@ +struct A { + int i; + long l; + float f; + double d; +}; + +enum E { e1, e2, e3 }; +enum class EC { e1, e2, e3 }; + +extern constexpr A a{42, 47l, 4.2f, 4.7}; +extern constexpr E e(e2); +extern constexpr EC ec(EC::e2); Index: lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/Inputs/debug-types-expressions.cpp @@ -0,0 +1,25 @@ +struct A { + int i = 47; + int f() { return i; } + virtual ~A() = default; +}; + +struct B: public A { + int j = 42; +}; + +namespace ns { +struct A { + int i = 147; + A(); +}; +A::A() = default; +} + +int foo(A *obj) { + return obj->f(); +} + +int main() { + return foo(new B); +} Index: lit/SymbolFile/DWARF/debug-types-basic.test =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/debug-types-basic.test @@ -0,0 +1,39 @@ +# REQUIRES: lld + +# RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \ +# RUN: -g -fdebug-types-section -c -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: %lldb %t -s %s -o exit | FileCheck %s + +type lookup A +# CHECK-LABEL: type lookup A +# CHECK: struct A { +# CHECK-NEXT: int i; +# CHECK-NEXT: long l; +# CHECK-NEXT: float f; +# CHECK-NEXT: double d; +# CHECK-NEXT: } + +type lookup E +# CHECK-LABEL: type lookup E +# CHECK: enum E { +# CHECK-NEXT: e1, +# CHECK-NEXT: e2, +# CHECK-NEXT: e3 +# CHECK-NEXT: } + +type lookup EC +# CHECK-LABEL: type lookup EC +# CHECK: enum class EC { +# CHECK-NEXT: e1, +# CHECK-NEXT: e2, +# CHECK-NEXT: e3 +# CHECK-NEXT: } + +print (E) 1 +# CHECK-LABEL: print (E) 1 +# CHECK: (E) $0 = e2 + +print (EC) 1 +# CHECK-LABEL: print (EC) 1 +# CHECK: (EC) $1 = e2 Index: lit/SymbolFile/DWARF/debug-types-expressions.test =================================================================== --- /dev/null +++ lit/SymbolFile/DWARF/debug-types-expressions.test @@ -0,0 +1,22 @@ +# UNSUPPORTED: system-darwin, system-windows + +# RUN: %clangxx %S/Inputs/debug-types-expressions.cpp \ +# RUN: -g -fdebug-types-section -o %t +# RUN: %lldb %t -s %s -o exit | FileCheck %s + +breakpoint set -n foo +process launch + +# CHECK: Process {{.*}} stopped + +frame variable obj +# CHECK-LABEL: frame variable obj +# CHECK: (B *) obj = + +print obj->f() +# CHECK-LABEL: print obj->f() +# CHECK: (int) $0 = 47 + +print ns::A() +# CHECK-LABEL: print ns::A() +# CHECK: (ns::A) $1 = (i = 147) Index: lit/SymbolFile/DWARF/lit.local.cfg =================================================================== --- lit/SymbolFile/DWARF/lit.local.cfg +++ lit/SymbolFile/DWARF/lit.local.cfg @@ -1 +1 @@ -config.suffixes = ['.cpp', '.s'] +config.suffixes = ['.cpp', '.s', '.test'] Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -22,6 +22,7 @@ DWARFDIE.cpp DWARFFormValue.cpp DWARFIndex.cpp + DWARFTypeUnit.cpp DWARFUnit.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -10,7 +10,6 @@ #include "SymbolFileDWARF.h" #include "lldb/Utility/Stream.h" -#include "llvm/Object/Error.h" using namespace lldb; using namespace lldb_private; @@ -29,52 +28,8 @@ std::shared_ptr cu_sp( new DWARFCompileUnit(dwarf2Data, uid)); - cu_sp->m_offset = *offset_ptr; - - dw_offset_t abbr_offset; - const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev(); - if (!abbr) - return llvm::make_error( - "No debug_abbrev data"); - - cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr); - cu_sp->m_version = debug_info.GetU16(offset_ptr); - - if (cu_sp->m_version == 5) { - cu_sp->m_unit_type = debug_info.GetU8(offset_ptr); - cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - - if (cu_sp->m_unit_type == llvm::dwarf::DW_UT_skeleton) - cu_sp->m_dwo_id = debug_info.GetU64(offset_ptr); - } else { - abbr_offset = debug_info.GetDWARFOffset(offset_ptr); - cu_sp->m_addr_size = debug_info.GetU8(offset_ptr); - } - - bool length_OK = debug_info.ValidOffset(cu_sp->GetNextUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(cu_sp->m_version); - bool abbr_offset_OK = - dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset); - bool addr_size_OK = (cu_sp->m_addr_size == 4) || (cu_sp->m_addr_size == 8); - - if (!length_OK) - return llvm::make_error( - "Invalid compile unit length"); - if (!version_OK) - return llvm::make_error( - "Unsupported compile unit version"); - if (!abbr_offset_OK) - return llvm::make_error( - "Abbreviation offset for compile unit is not valid"); - if (!addr_size_OK) - return llvm::make_error( - "Invalid compile unit address size"); - - cu_sp->m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); - if (!cu_sp->m_abbrevs) - return llvm::make_error( - "No abbrev exists at the specified offset."); + if (llvm::Error E = cu_sp->ExtractHeader(dwarf2Data, debug_info, offset_ptr)) + return std::move(E); return cu_sp; } Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -22,6 +22,7 @@ #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" #include "DWARFFormValue.h" +#include "DWARFTypeUnit.h" using namespace lldb; using namespace lldb_private; @@ -73,34 +74,41 @@ return *m_cu_aranges_up; } -void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { - if (!m_units.empty()) - return; - if (!m_dwarf2Data) - return; - +template +void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data, + std::vector &units) { lldb::offset_t offset = 0; - const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); + while (data.ValidOffset(offset)) { + llvm::Expected unit_sp = + Unit::extract(dwarf, units.size(), data, &offset); - while (debug_info_data.ValidOffset(offset)) { - llvm::Expected cu_sp = DWARFCompileUnit::extract( - m_dwarf2Data, m_units.size(), debug_info_data, &offset); - - if (!cu_sp) { + if (!unit_sp) { // FIXME: Propagate this error up. - llvm::consumeError(cu_sp.takeError()); + llvm::consumeError(unit_sp.takeError()); return; } // If it didn't return an error, then it should be returning a valid Unit. - assert(*cu_sp); + assert(*unit_sp); - m_units.push_back(*cu_sp); + units.push_back(*unit_sp); - offset = (*cu_sp)->GetNextUnitOffset(); + offset = (*unit_sp)->GetNextUnitOffset(); } } +void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { + if (!m_units.empty()) + return; + if (!m_dwarf2Data) + return; + + Parse(m_dwarf2Data, m_dwarf2Data->get_debug_info_data(), + m_units); + Parse(m_dwarf2Data, m_dwarf2Data->get_debug_types_data(), + m_units); +} + size_t DWARFDebugInfo::GetNumUnits() { ParseUnitHeadersIfNeeded(); return m_units.size(); Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -0,0 +1,45 @@ +//===-- DWARFTypeUnit.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFTypeUnit_h_ +#define SymbolFileDWARF_DWARFTypeUnit_h_ + +#include "DWARFUnit.h" +#include "llvm/Support/Error.h" + +class DWARFTypeUnit : public DWARFUnit { +public: + static llvm::Expected + extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid, + const lldb_private::DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr); + void Dump(lldb_private::Stream *s) const override; + + /// Get the data that contains the DIE information for this unit. + /// + /// \return + /// The correct data (.debug_types for DWARF 4 and earlier, and + /// .debug_info for DWARF 5 and later) for the DIE information in + /// this unit. + const lldb_private::DWARFDataExtractor &GetData() const override; + + /// Get the size in bytes of the header. + /// + /// \return + /// Byte size of the type unit header + uint32_t GetHeaderByteSize() const override { return 23; } + + DIERef::Section GetDebugSection() const override { + return DIERef::Section::DebugTypes; + } + +private: + DWARFTypeUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid); +}; + +#endif // SymbolFileDWARF_DWARFTypeUnit_h_ Index: source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp =================================================================== --- /dev/null +++ source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.cpp @@ -0,0 +1,45 @@ +//===-- DWARFTypeUnit.cpp ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DWARFTypeUnit.h" + +#include "SymbolFileDWARF.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +DWARFTypeUnit::DWARFTypeUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid) + : DWARFUnit(dwarf2Data, uid) {} + +llvm::Expected +DWARFTypeUnit::extract(SymbolFileDWARF *dwarf2Data, user_id_t uid, + const DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr) { + assert(debug_info.ValidOffset(*offset_ptr)); + + // std::make_shared would require the ctor to be public. + std::shared_ptr tu_sp(new DWARFTypeUnit(dwarf2Data, uid)); + + if (llvm::Error E = tu_sp->ExtractHeader(dwarf2Data, debug_info, offset_ptr)) + return std::move(E); + + return tu_sp; +} + +void DWARFTypeUnit::Dump(Stream *s) const { + s->Printf("0x%8.8x: Type 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, + GetNextUnitOffset()); +} + +const lldb_private::DWARFDataExtractor &DWARFTypeUnit::GetData() const { + return m_dwarf->get_debug_types_data(); +} Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.h =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -172,6 +172,10 @@ protected: DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid); + llvm::Error ExtractHeader(SymbolFileDWARF *dwarf, + const lldb_private::DWARFDataExtractor &data, + lldb::offset_t *offset_ptr); + SymbolFileDWARF *m_dwarf = nullptr; std::unique_ptr m_dwo_symbol_file; const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include "llvm/Object/Error.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" @@ -790,3 +791,54 @@ return *m_func_aranges_up; } +llvm::Error DWARFUnit::ExtractHeader(SymbolFileDWARF *dwarf, + const DWARFDataExtractor &data, + lldb::offset_t *offset_ptr) { + m_offset = *offset_ptr; + + dw_offset_t abbr_offset; + const DWARFDebugAbbrev *abbr = dwarf->DebugAbbrev(); + if (!abbr) + return llvm::make_error( + "No debug_abbrev data"); + + m_length = data.GetDWARFInitialLength(offset_ptr); + m_version = data.GetU16(offset_ptr); + + if (m_version == 5) { + m_unit_type = data.GetU8(offset_ptr); + m_addr_size = data.GetU8(offset_ptr); + abbr_offset = data.GetDWARFOffset(offset_ptr); + + if (m_unit_type == llvm::dwarf::DW_UT_skeleton) + m_dwo_id = data.GetU64(offset_ptr); + } else { + abbr_offset = data.GetDWARFOffset(offset_ptr); + m_addr_size = data.GetU8(offset_ptr); + } + + bool length_OK = data.ValidOffset(GetNextUnitOffset() - 1); + bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); + bool abbr_offset_OK = dwarf->get_debug_abbrev_data().ValidOffset(abbr_offset); + bool addr_size_OK = (m_addr_size == 4) || (m_addr_size == 8); + + if (!length_OK) + return llvm::make_error( + "Invalid compile unit length"); + if (!version_OK) + return llvm::make_error( + "Unsupported compile unit version"); + if (!abbr_offset_OK) + return llvm::make_error( + "Abbreviation offset for compile unit is not valid"); + if (!addr_size_OK) + return llvm::make_error( + "Invalid compile unit address size"); + + m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset); + if (!m_abbrevs) + return llvm::make_error( + "No abbrev exists at the specified offset."); + + return llvm::Error::success(); +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -440,20 +440,6 @@ if (section_list == NULL) return 0; - // On non Apple platforms we might have .debug_types debug info that is - // created by using "-fdebug-types-section". LLDB currently will try to - // load this debug info, but it causes crashes during debugging when types - // are missing since it doesn't know how to parse the info in the - // .debug_types type units. This causes all complex debug info types to be - // unresolved. Because this causes LLDB to crash and since it really - // doesn't provide a solid debuggiung experience, we should disable trying - // to debug this kind of DWARF until support gets added or deprecated. - if (section_list->FindSectionByName(ConstString(".debug_types"))) { - m_obj_file->GetModule()->ReportWarning( - "lldb doesn’t support .debug_types debug info"); - return 0; - } - uint64_t debug_abbrev_file_size = 0; uint64_t debug_info_file_size = 0; uint64_t debug_line_file_size = 0;