+enum E { e1, e2, e3 };
+enum class EC { e1, e2, e3 };
+
struct A {
int i;
long l;
float f;
double d;
+ E e;
+ EC ec;
};
-enum E { e1, e2, e3 };
-enum class EC { e1, e2, e3 };
-
-extern constexpr A a{42, 47l, 4.2f, 4.7};
+extern constexpr A a{42, 47l, 4.2f, 4.7, e1, EC::e3};
extern constexpr E e(e2);
extern constexpr EC ec(EC::e2);
namespace ns {
struct A {
int i = 147;
+ ::A getA();
A();
};
A::A() = default;
+
+::A A::getA() {
+ ::A a;
+ a.i = i - 1;
+ return a;
}
+} // namespace ns
+
int foo(A *a) {
return a->f();
}
# CHECK-NEXT: long l;
# CHECK-NEXT: float f;
# CHECK-NEXT: double d;
+# CHECK-NEXT: E e;
+# CHECK-NEXT: EC ec;
# CHECK-NEXT: }
type lookup E
print (EC) 1
# CHECK-LABEL: print (EC) 1
# CHECK: (EC) $1 = e2
+
+target variable a e ec
+# CHECK-LABEL: target variable a e ec
+# CHECK: (const A) a = (i = 42, l = 47, f = 4.{{[12].*}}, d = 4.{{[67].*}}, e = e1, ec = e3)
+# CHECK: (const E) e = e2
+# CHECK: (const EC) ec = e2
# CHECK-LABEL: frame variable a
# CHECK: (B *) a =
+frame variable *a
+# CHECK-LABEL: frame variable *a
+# CHECK: (B) *a = {
+# CHECK-NEXT: A = (i = 47)
+# CHECK-NEXT: j = 42
+# CHECK-NEXT: }
+
print a->f()
# CHECK-LABEL: print a->f()
# CHECK: (int) $0 = 47
print ns::A()
# CHECK-LABEL: print ns::A()
# CHECK: (ns::A) $1 = (i = 147)
+
+print ns::A().i + a->i
+# CHECK-LABEL: print ns::A().i + a->i
+# CHECK: (int) $2 = 194
+
+print ns::A().getA()
+# CHECK-LABEL: ns::A().getA()
+# CHECK: (A) $3 = (i = 146)
--- /dev/null
+Create a dangling DW_AT_signature reference by stripping the debug_types
+section, and make sure lldb does something reasonable.
+RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \
+RUN: -g -gdwarf-4 -fdebug-types-section -c -o %t.o
+RUN: llvm-objcopy --remove-section=.debug_types %t.o %t
+
+
+RUN: %lldb %t -b -o "type lookup A" | FileCheck --check-prefix=LOOKUPA %s
+LOOKUPA: no type was found matching 'A'
+
+RUN: %lldb %t -b -o "type lookup E" | FileCheck --check-prefix=LOOKUPE %s
+LOOKUPE: no type was found matching 'E'
+
+RUN: %lldb %t -b -o "type lookup EC" | FileCheck --check-prefix=LOOKUPEC %s
+LOOKUPEC: no type was found matching 'EC'
+
+RUN: %lldb %t -b -o "print (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s
+PRINTE: use of undeclared identifier 'E'
+
+RUN: %lldb %t -b -o "print (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s
+PRINTEC: use of undeclared identifier 'EC'
+
+RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s
+VARS: (const (anonymous struct)) a = {}
+VARS: (const (anonymous enum)) e = 1
+VARS: (const (anonymous enum)) ec = 1
--- /dev/null
+# REQUIRES: lld
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux -o %t.o %s
+# RUN: ld.lld %t.o -o %t
+# RUN: %lldb %t -o "target variable e" -b | FileCheck %s
+
+# CHECK: e = <could not resolve type>
+
+ .type e,@object # @e
+ .section .rodata,"a",@progbits
+ .globl e
+ .p2align 2
+e:
+ .long 0 # 0x0
+ .size e, 4
+
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "Hand-written DWARF"
+.Linfo_string1:
+ .asciz "a.cpp"
+.Linfo_string3:
+ .asciz "e"
+.Linfo_string4:
+ .asciz "unsigned int"
+.Linfo_string5:
+ .asciz "e1"
+.Linfo_string6:
+ .asciz "E"
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 65 # DW_TAG_type_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 8 # Abbreviation Code
+ .byte 4 # DW_TAG_enumeration_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 60 # DW_AT_declaration
+ .byte 25 # DW_FORM_flag_present
+ .byte 105 # DW_AT_signature
+ .byte 32 # DW_FORM_ref_sig8
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+.Ltu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 2 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .quad 5390450678491038984 # Type Signature
+ .long .LE-.Ltu_begin0 # Type DIE Offset
+ .byte 1 # Abbrev [1] 0x18:0x1d DW_TAG_type_unit
+ .short 4 # DW_AT_language
+.LE:
+ .byte 8 # Abbrev [8] 0x23:0xd DW_TAG_enumeration_type
+ # DW_AT_declaration
+ .quad 5390450678491038984 # DW_AT_signature
+.Lbase:
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+
+.Lcu_begin0:
+ .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 5 # Abbrev [5] 0xc:0x2c DW_TAG_compile_unit
+ .long .Linfo_string0 # DW_AT_producer
+ .short 4 # DW_AT_language
+ .long .Linfo_string1 # DW_AT_name
+ .byte 6 # Abbrev [6] 0x1e:0xb DW_TAG_variable
+ .long .Linfo_string3 # DW_AT_name
+ .long .LE_sig-.Lcu_begin0 # DW_AT_type
+ .byte 9 # DW_AT_location
+ .byte 3
+ .quad e
+.LE_sig:
+ .byte 8 # Abbrev [8] 0x2e:0x9 DW_TAG_enumeration_type
+ # DW_AT_declaration
+ .quad 5390450678491038984 # DW_AT_signature
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end1:
AccessType accessibility = eAccessNone;
if (!die)
return nullptr;
-
SymbolFileDWARF *dwarf = die.GetDWARF();
if (log) {
DWARFDIE context_die;
die.GetTagAsCString(), die.GetName());
}
+
Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE());
if (type_ptr == DIE_IS_BEING_PARSED)
return nullptr;
if (type_ptr)
return type_ptr->shared_from_this();
+ // Set a bit that lets us know that we are currently parsing this
+ dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
+
+ if (DWARFDIE signature_die =
+ die.GetAttributeValueAsReferenceDIE(DW_AT_signature)) {
+ if (TypeSP type_sp =
+ ParseTypeFromDWARF(sc, signature_die, log, type_is_new_ptr)) {
+ dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
+ if (clang::DeclContext *decl_ctx =
+ GetCachedClangDeclContextForDIE(signature_die))
+ LinkDeclContextToDIE(decl_ctx, die);
+ return type_sp;
+ }
+ return nullptr;
+ }
TypeList *type_list = dwarf->GetTypeList();
if (type_is_new_ptr)
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
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
-
const size_t num_attributes = die.GetAttributes(attributes);
uint32_t encoding = 0;
DWARFFormValue encoding_uid;
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
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
-
LanguageType class_language = eLanguageTypeUnknown;
bool is_complete_objc_class = false;
size_t calling_convention = llvm::dwarf::CallingConvention::DW_CC_normal;
} break;
case DW_TAG_enumeration_type: {
- // Set a bit that lets us know that we are currently parsing this
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
-
bool is_scoped = false;
DWARFFormValue encoding_form;
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
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
-
DWARFFormValue type_die_form;
bool is_variadic = false;
bool is_inline = false;
} break;
case DW_TAG_array_type: {
- // Set a bit that lets us know that we are currently parsing this
- dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED;
-
DWARFFormValue type_die_form;
uint32_t byte_stride = 0;
uint32_t bit_stride = 0;
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
+#include "llvm/Support/Casting.h"
#include "DWARFCompileUnit.h"
#include "DWARFContext.h"
return *m_cu_aranges_up;
}
-void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data,
- DIERef::Section section, std::vector<DWARFUnitSP> &units) {
+void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) {
+ DWARFDataExtractor data = section == DIERef::Section::DebugTypes
+ ? m_context.getOrLoadDebugTypesData()
+ : m_context.getOrLoadDebugInfoData();
lldb::offset_t offset = 0;
while (data.ValidOffset(offset)) {
- llvm::Expected<DWARFUnitSP> unit_sp =
- DWARFUnit::extract(dwarf, units.size(), data, section, &offset);
+ llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract(
+ m_dwarf2Data, m_units.size(), data, section, &offset);
if (!unit_sp) {
// FIXME: Propagate this error up.
// If it didn't return an error, then it should be returning a valid Unit.
assert(*unit_sp);
-
- units.push_back(*unit_sp);
-
+ m_units.push_back(*unit_sp);
offset = (*unit_sp)->GetNextUnitOffset();
+
+ if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) {
+ m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(),
+ unit_sp.get()->GetID());
+ }
}
}
if (!m_dwarf2Data)
return;
- Parse(m_dwarf2Data, m_context.getOrLoadDebugInfoData(),
- DIERef::Section::DebugInfo, m_units);
- Parse(m_dwarf2Data, m_context.getOrLoadDebugTypesData(),
- DIERef::Section::DebugTypes, m_units);
+ ParseUnitsFor(DIERef::Section::DebugInfo);
+ ParseUnitsFor(DIERef::Section::DebugTypes);
+ llvm::sort(m_type_hash_to_unit_index, llvm::less_first());
}
size_t DWARFDebugInfo::GetNumUnits() {
return result;
}
+DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
+ auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
+ std::make_pair(hash, 0u), llvm::less_first());
+ if (pos == m_type_hash_to_unit_index.end() || pos->first != hash)
+ return nullptr;
+ return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second));
+}
+
DWARFDIE
DWARFDebugInfo::GetDIEForDIEOffset(DIERef::Section section,
dw_offset_t die_offset) {
#include <vector>
#include "DWARFDIE.h"
+#include "DWARFTypeUnit.h"
#include "DWARFUnit.h"
#include "SymbolFileDWARF.h"
#include "lldb/Core/STLUtils.h"
DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section,
dw_offset_t die_offset);
DWARFUnit *GetUnit(const DIERef &die_ref);
+ DWARFTypeUnit *GetTypeUnitForHash(uint64_t hash);
DWARFDIE GetDIEForDIEOffset(DIERef::Section section,
dw_offset_t die_offset);
DWARFDIE GetDIE(const DIERef &die_ref);
std::unique_ptr<DWARFDebugAranges>
m_cu_aranges_up; // A quick address to compile unit table
+ std::vector<std::pair<uint64_t, uint32_t>> m_type_hash_to_unit_index;
+
private:
// All parsing needs to be done partially any managed by this class as
// accessors are called.
void ParseUnitHeadersIfNeeded();
+ void ParseUnitsFor(DIERef::Section section);
+
uint32_t FindUnitIndex(DIERef::Section section, dw_offset_t offset);
DISALLOW_COPY_AND_ASSIGN(DWARFDebugInfo);
return ref_cu->GetDIE(value);
}
+ case DW_FORM_ref_sig8: {
+ DWARFTypeUnit *tu =
+ m_unit->GetSymbolFileDWARF()->DebugInfo()->GetTypeUnitForHash(value);
+ if (!tu)
+ return {};
+ return tu->GetDIE(tu->GetTypeOffset());
+ }
+
default:
return {};
}
using namespace lldb;
using namespace lldb_private;
-
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 "
void Dump(lldb_private::Stream *s) const override;
+ uint64_t GetTypeHash() { return m_header.GetTypeHash(); }
+
+ dw_offset_t GetTypeOffset() { return GetOffset() + m_header.GetTypeOffset(); }
+
+ static bool classof(const DWARFUnit *unit) {
+ return unit->GetUnitType() == DW_UT_type;
+ }
+
private:
DWARFTypeUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile;
}
+ if (header.IsTypeUnit()) {
+ header.m_type_hash = data.GetU64(offset_ptr);
+ header.m_type_offset = data.GetDWARFOffset(offset_ptr);
+ }
+
bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1);
bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version);
bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8);
+ bool type_offset_OK =
+ !header.IsTypeUnit() || (header.m_type_offset <= header.GetLength());
if (!length_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
if (!addr_size_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Invalid unit address size");
+ if (!type_offset_OK)
+ return llvm::make_error<llvm::object::GenericBinaryError>(
+ "Type offset out of range");
return header;
}
dw_offset_t m_abbr_offset = 0;
uint8_t m_unit_type = 0;
uint8_t m_addr_size = 0;
+
+ uint64_t m_type_hash = 0;
+ uint32_t m_type_offset = 0;
+
uint64_t m_dwo_id = 0;
DWARFUnitHeader() = default;
dw_offset_t GetLength() const { return m_length; }
dw_offset_t GetAbbrOffset() const { return m_abbr_offset; }
uint8_t GetUnitType() const { return m_unit_type; }
+ uint64_t GetTypeHash() const { return m_type_hash; }
+ dw_offset_t GetTypeOffset() const { return m_type_offset; }
bool IsTypeUnit() const {
return m_unit_type == DW_UT_type || m_unit_type == DW_UT_split_type;
}
DIERef::Section GetDebugSection() const { return m_section; }
+ uint8_t GetUnitType() const { return m_header.GetUnitType(); }
+
protected:
DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,