[lldb/DWARF] Support the debug_str_offsets section in dwp files

Summary:
In dwp files a constant (from the debug_cu_index section) needs to be
added to each reference into the debug_str_offsets section.

I've tried to implement this to roughly match the llvm flow: I've
changed the DWARFormValue to stop resolving the indirect string
references directly -- instead, it calls into DWARFUnit, which resolves
this for it (similar to how it already resolves indirect range and
location list references). I've also done a small refactor of the string
offset base computation code in DWARFUnit in order to make it easier to
access the debug_cu_index base offset.

Reviewers: JDevlieghere, aprantl, clayborg

Subscribers: lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D74723
This commit is contained in:
Pavel Labath 2020-02-17 17:29:55 +01:00
parent 8b65f792a0
commit 00539d8b64
4 changed files with 83 additions and 52 deletions

View File

@ -454,40 +454,26 @@ void DWARFFormValue::Dump(Stream &s) const {
}
const char *DWARFFormValue::AsCString() const {
SymbolFileDWARF &symbol_file = m_unit->GetSymbolFileDWARF();
DWARFContext &context = m_unit->GetSymbolFileDWARF().GetDWARFContext();
if (m_form == DW_FORM_string) {
if (m_form == DW_FORM_string)
return m_value.value.cstr;
} else if (m_form == DW_FORM_strp) {
return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(
m_value.value.uval);
} else if (m_form == DW_FORM_GNU_str_index) {
uint32_t index_size = 4;
lldb::offset_t offset = m_value.value.uval * index_size;
dw_offset_t str_offset =
symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
&offset, index_size);
return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(
str_offset);
}
if (m_form == DW_FORM_strp)
return context.getOrLoadStrData().PeekCStr(m_value.value.uval);
if (m_form == DW_FORM_strx || m_form == DW_FORM_strx1 ||
m_form == DW_FORM_strx2 || m_form == DW_FORM_strx3 ||
m_form == DW_FORM_strx4) {
if (m_form == DW_FORM_GNU_str_index || m_form == DW_FORM_strx ||
m_form == DW_FORM_strx1 || m_form == DW_FORM_strx2 ||
m_form == DW_FORM_strx3 || m_form == DW_FORM_strx4) {
// The same code as above.
uint32_t indexSize = 4;
lldb::offset_t offset =
m_unit->GetStrOffsetsBase() + m_value.value.uval * indexSize;
dw_offset_t strOffset =
symbol_file.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
&offset, indexSize);
return symbol_file.GetDWARFContext().getOrLoadStrData().PeekCStr(strOffset);
llvm::Optional<uint64_t> offset =
m_unit->GetStringOffsetSectionItem(m_value.value.uval);
if (!offset)
return nullptr;
return context.getOrLoadStrData().PeekCStr(*offset);
}
if (m_form == DW_FORM_line_strp)
return symbol_file.GetDWARFContext().getOrLoadLineStrData().PeekCStr(
m_value.value.uval);
return context.getOrLoadLineStrData().PeekCStr(m_value.value.uval);
return nullptr;
}

View File

@ -259,23 +259,32 @@ void DWARFUnit::ExtractDIEsRWLocked() {
// .debug_str_offsets. At the same time, the corresponding split debug unit also
// may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and
// for that case, we should find the offset (skip the section header).
static void SetDwoStrOffsetsBase(DWARFUnit *dwo_cu) {
void DWARFUnit::SetDwoStrOffsetsBase() {
lldb::offset_t baseOffset = 0;
const DWARFDataExtractor &strOffsets =
dwo_cu->GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
uint64_t length = strOffsets.GetU32(&baseOffset);
if (length == 0xffffffff)
length = strOffsets.GetU64(&baseOffset);
if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) {
if (const auto *contribution = entry->getOffset(llvm::DW_SECT_STR_OFFSETS))
baseOffset = contribution->Offset;
else
return;
}
// Check version.
if (strOffsets.GetU16(&baseOffset) < 5)
return;
if (GetVersion() >= 5) {
const DWARFDataExtractor &strOffsets =
GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
uint64_t length = strOffsets.GetU32(&baseOffset);
if (length == 0xffffffff)
length = strOffsets.GetU64(&baseOffset);
// Skip padding.
baseOffset += 2;
// Check version.
if (strOffsets.GetU16(&baseOffset) < 5)
return;
dwo_cu->SetStrOffsetsBase(baseOffset);
// Skip padding.
baseOffset += 2;
}
SetStrOffsetsBase(baseOffset);
}
// m_die_array_mutex must be already held as read/write.
@ -334,8 +343,10 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
}
}
if (m_is_dwo)
if (m_is_dwo) {
SetDwoStrOffsetsBase();
return;
}
std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file =
m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die);
@ -377,10 +388,6 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));
dwo_cu->SetBaseAddress(GetBaseAddress());
for (size_t i = 0; i < dwo_symbol_file->DebugInfo()->GetNumUnits(); ++i) {
DWARFUnit *unit = dwo_symbol_file->DebugInfo()->GetUnitAtIndex(i);
SetDwoStrOffsetsBase(unit);
}
m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu);
}
@ -900,6 +907,12 @@ uint32_t DWARFUnit::GetHeaderByteSize() const {
llvm_unreachable("invalid UnitType.");
}
llvm::Optional<uint64_t>
DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
offset_t offset = GetStrOffsetsBase() + index * 4;
return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset);
}
llvm::Expected<DWARFRangeList>
DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) {
if (GetVersion() <= 4) {

View File

@ -59,6 +59,9 @@ public:
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; }
const llvm::DWARFUnitIndex::Entry *GetIndexEntry() const {
return m_index_entry;
}
uint64_t GetTypeHash() const { return m_type_hash; }
dw_offset_t GetTypeOffset() const { return m_type_offset; }
bool IsTypeUnit() const {
@ -215,6 +218,8 @@ public:
uint8_t GetUnitType() const { return m_header.GetUnitType(); }
bool IsTypeUnit() const { return m_header.IsTypeUnit(); }
llvm::Optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const;
/// Return a list of address ranges resulting from a (possibly encoded)
/// range list starting at a given offset in the appropriate ranges section.
llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset);
@ -331,6 +336,7 @@ private:
void ClearDIEsRWLocked();
void AddUnitDIE(const DWARFDebugInfoEntry &cu_die);
void SetDwoStrOffsetsBase();
void ComputeCompDirAndGuessPathStyle();
void ComputeAbsolutePath();

View File

@ -5,10 +5,10 @@
# RUN: %lldb %t -o "target variable A" -b | FileCheck %s
# RUN: lldb-test symbols %t | FileCheck %s --check-prefix=SYMBOLS
# CHECK: (int) A = 0
# CHECK: (int) A = 1
# CHECK: (int) A = 2
# CHECK: (int) A = 3
# CHECK: (INT0) A = 0
# CHECK: (INT1) A = 1
# CHECK: (INT2) A = 2
# CHECK: (INT3) A = 3
# SYMBOLS: Compile units:
# SYMBOLS-NEXT: CompileUnit{0x00000000}, language = "unknown", file = '0.c'
@ -64,6 +64,15 @@ A\I:
# This deliberately excludes compile unit 4 to check test the case of a missing
# split unit.
.irpc I,0123
.section .debug_str.dwo,"e",@progbits
.Lstr\I:
.byte 'I', 'N', 'T', '0'+\I, 0
.section .debug_str_offsets.dwo,"e",@progbits
.Lstr_offsets\I:
.long .Lstr\I-.debug_str.dwo
.Lstr_offsets_end\I:
.section .debug_abbrev.dwo,"e",@progbits
.Labbrev\I:
.byte \I*10+1 # Abbreviation Code
@ -90,13 +99,22 @@ A\I:
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_string
.byte 8 # DW_FORM_string
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte \I*10+4 # Abbreviation Code
.byte 22 # DW_TAG_typedef
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.uleb128 0x1f02 # DW_FORM_GNU_str_index
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.Labbrev_end\I:
@ -112,10 +130,14 @@ A\I:
.byte '0'+\I, '.', 'c', 0 # DW_AT_name
.byte \I*10+2 # Abbrev DW_TAG_variable
.asciz "A" # DW_AT_name
.long .Ltype\I-.Lcu_begin\I # DW_AT_type
.long .Ltypedef\I-.Lcu_begin\I# DW_AT_type
.byte 2 # DW_AT_location
.byte 0xfb # DW_OP_GNU_addr_index
.byte \I
.Ltypedef\I:
.byte \I*10+4 # Abbrev DW_TAG_typedef
.byte 0 # DW_AT_name
.long .Ltype\I-.Lcu_begin\I # DW_AT_type
.Ltype\I:
.byte \I*10+3 # Abbrev DW_TAG_base_type
.asciz "int" # DW_AT_name
@ -128,22 +150,26 @@ A\I:
.section .debug_cu_index,"e",@progbits
.short 2 # DWARF version number
.short 0 # Reserved
.long 2 # Section count
.long 3 # Section count
.long 4 # Unit count
.long 8 # Slot count
.quad 0, 1, 2, 3, 0, 0, 0, 0 # Hash table
.long 1, 2, 3, 4, 0, 0, 0, 0 # Index table
.long 1, 3 # DW_SECT_INFO, DW_SECT_ABBREV
.long 1 # DW_SECT_INFO
.long 3 # DW_SECT_ABBREV
.long 6 # DW_SECT_STR_OFFSETS
.irpc I,0123
.long .Lcu_begin\I-.debug_info.dwo
.long .Labbrev\I-.debug_abbrev.dwo
.long .Lstr_offsets\I-.debug_str_offsets.dwo
.endr
.irpc I,0123
.long .Ldebug_info_end\I-.Lcu_begin\I
.long .Labbrev_end\I-.Labbrev\I
.long .Lstr_offsets_end\I-.Lstr_offsets\I
.endr
.endif