mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-22 04:05:05 +00:00
[DWARF parser] Add basic support for DWZ DWARF multifile extensions.
This change implements basic support for DWARF alternate sections proposal: http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open LLVM tools now understand new forms: DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt, which are used as references to .debug_info and .debug_str sections respectively, stored in a separate file, and possibly shared between different executables / shared objects. llvm-dwarfdump and llvm-symbolizer don't yet know how to access this alternate debug file (usually pointed by .gnu_debugaltlink section), but they can at lease properly parse and dump regular files, which refer to it. This change should fix crashes of llvm-dwarfdump and llvm-symbolizer on files produced by running "dwz" tool. Such files are already installed on some modern Linux distributions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237721 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4d88c3ebad
commit
4ca606f22f
@ -87,6 +87,8 @@ public:
|
||||
|
||||
static ArrayRef<uint8_t> getFixedFormSizes(uint8_t AddrSize,
|
||||
uint16_t Version);
|
||||
private:
|
||||
void dumpString(raw_ostream &OS, const DWARFUnit *U) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -285,7 +285,11 @@ enum Form : uint16_t {
|
||||
|
||||
// Extensions for Fission proposal
|
||||
DW_FORM_GNU_addr_index = 0x1f01,
|
||||
DW_FORM_GNU_str_index = 0x1f02
|
||||
DW_FORM_GNU_str_index = 0x1f02,
|
||||
|
||||
// Alternate debug sections proposal (output of "dwz" tool).
|
||||
DW_FORM_GNU_ref_alt = 0x1f20,
|
||||
DW_FORM_GNU_strp_alt = 0x1f21
|
||||
};
|
||||
|
||||
enum LocationAtom {
|
||||
|
@ -161,14 +161,15 @@ void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS,
|
||||
// We have dumped the attribute raw value. For some attributes
|
||||
// having both the raw value and the pretty-printed value is
|
||||
// interesting. These attributes are handled below.
|
||||
if ((attr == DW_AT_specification || attr == DW_AT_abstract_origin) &&
|
||||
// The signature references aren't handled.
|
||||
formValue.getForm() != DW_FORM_ref_sig8) {
|
||||
uint32_t Ref = formValue.getAsReference(u).getValue();
|
||||
DWARFDebugInfoEntryMinimal DIE;
|
||||
if (const DWARFUnit *RefU = findUnitAndExtractFast(DIE, u, &Ref))
|
||||
if (const char *Ref = DIE.getName(RefU, DINameKind::LinkageName))
|
||||
OS << " \"" << Ref << '\"';
|
||||
if (attr == DW_AT_specification || attr == DW_AT_abstract_origin) {
|
||||
Optional<uint64_t> Ref = formValue.getAsReference(u);
|
||||
if (Ref.hasValue()) {
|
||||
uint32_t RefOffset = Ref.getValue();
|
||||
DWARFDebugInfoEntryMinimal DIE;
|
||||
if (const DWARFUnit *RefU = findUnitAndExtractFast(DIE, u, &RefOffset))
|
||||
if (const char *Name = DIE.getName(RefU, DINameKind::LinkageName))
|
||||
OS << " \"" << Name << '\"';
|
||||
}
|
||||
} else if (attr == DW_AT_APPLE_property_attribute) {
|
||||
if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant())
|
||||
dumpApplePropertyAttribute(OS, *OptVal);
|
||||
|
@ -113,14 +113,17 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
|
||||
if (Form < ArrayRef<FormClass>(DWARF4FormClasses).size() &&
|
||||
DWARF4FormClasses[Form] == FC)
|
||||
return true;
|
||||
// Check DW_FORM_ref_sig8 from DWARF4.
|
||||
if (Form == DW_FORM_ref_sig8)
|
||||
// Check more forms from DWARF4 and DWARF5 proposals.
|
||||
switch (Form) {
|
||||
case DW_FORM_ref_sig8:
|
||||
case DW_FORM_GNU_ref_alt:
|
||||
return (FC == FC_Reference);
|
||||
// Check for some DWARF5 forms.
|
||||
if (Form == DW_FORM_GNU_addr_index)
|
||||
case DW_FORM_GNU_addr_index:
|
||||
return (FC == FC_Address);
|
||||
if (Form == DW_FORM_GNU_str_index)
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
return (FC == FC_String);
|
||||
}
|
||||
// In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset.
|
||||
// Don't check for DWARF version here, as some producers may still do this
|
||||
// by mistake.
|
||||
@ -199,15 +202,6 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr,
|
||||
case DW_FORM_sdata:
|
||||
Value.sval = data.getSLEB128(offset_ptr);
|
||||
break;
|
||||
case DW_FORM_strp: {
|
||||
Value.uval = data.getU32(offset_ptr);
|
||||
if (!cu)
|
||||
break;
|
||||
RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4);
|
||||
if (AI != cu->getRelocMap()->end())
|
||||
Value.uval += AI->second.second;
|
||||
break;
|
||||
}
|
||||
case DW_FORM_udata:
|
||||
case DW_FORM_ref_udata:
|
||||
Value.uval = data.getULEB128(offset_ptr);
|
||||
@ -219,14 +213,18 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr,
|
||||
Form = data.getULEB128(offset_ptr);
|
||||
indirect = true;
|
||||
break;
|
||||
case DW_FORM_sec_offset: {
|
||||
case DW_FORM_sec_offset:
|
||||
case DW_FORM_strp:
|
||||
case DW_FORM_GNU_ref_alt:
|
||||
case DW_FORM_GNU_strp_alt: {
|
||||
// FIXME: This is 64-bit for DWARF64.
|
||||
Value.uval = data.getU32(offset_ptr);
|
||||
if (!cu)
|
||||
break;
|
||||
RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4);
|
||||
RelocAddrMap::const_iterator AI =
|
||||
cu->getRelocMap()->find(*offset_ptr - 4);
|
||||
if (AI != cu->getRelocMap()->end())
|
||||
Value.uval += AI->second.second;
|
||||
Value.uval += AI->second.second;
|
||||
break;
|
||||
}
|
||||
case DW_FORM_flag_present:
|
||||
@ -323,7 +321,6 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data,
|
||||
return true;
|
||||
|
||||
// 4 byte values
|
||||
case DW_FORM_strp:
|
||||
case DW_FORM_data4:
|
||||
case DW_FORM_ref4:
|
||||
*offset_ptr += 4;
|
||||
@ -353,6 +350,9 @@ DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data,
|
||||
|
||||
// FIXME: 4 for DWARF32, 8 for DWARF64.
|
||||
case DW_FORM_sec_offset:
|
||||
case DW_FORM_strp:
|
||||
case DW_FORM_GNU_ref_alt:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
*offset_ptr += 4;
|
||||
return true;
|
||||
|
||||
@ -424,24 +424,17 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const {
|
||||
case DW_FORM_udata: OS << Value.uval; break;
|
||||
case DW_FORM_strp: {
|
||||
OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
|
||||
Optional<const char *> DbgStr = getAsCString(cu);
|
||||
if (DbgStr.hasValue()) {
|
||||
raw_ostream &COS = WithColor(OS, syntax::String);
|
||||
COS << '"';
|
||||
COS.write_escaped(DbgStr.getValue());
|
||||
COS << '"';
|
||||
}
|
||||
dumpString(OS, cu);
|
||||
break;
|
||||
}
|
||||
case DW_FORM_GNU_str_index: {
|
||||
OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue);
|
||||
Optional<const char *> DbgStr = getAsCString(cu);
|
||||
if (DbgStr.hasValue()) {
|
||||
raw_ostream &COS = WithColor(OS, syntax::String);
|
||||
COS << '"';
|
||||
COS.write_escaped(DbgStr.getValue());
|
||||
COS << '"';
|
||||
}
|
||||
dumpString(OS, cu);
|
||||
break;
|
||||
}
|
||||
case DW_FORM_GNU_strp_alt: {
|
||||
OS << format("alt indirect string, offset: 0x%" PRIx64 "", uvalue);
|
||||
dumpString(OS, cu);
|
||||
break;
|
||||
}
|
||||
case DW_FORM_ref_addr:
|
||||
@ -467,6 +460,9 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const {
|
||||
cu_relative_offset = true;
|
||||
OS << format("cu + 0x%" PRIx64, uvalue);
|
||||
break;
|
||||
case DW_FORM_GNU_ref_alt:
|
||||
OS << format("<alt 0x%" PRIx64 ">", uvalue);
|
||||
break;
|
||||
|
||||
// All DW_FORM_indirect attributes should be resolved prior to calling
|
||||
// this function
|
||||
@ -492,12 +488,23 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const {
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFFormValue::dumpString(raw_ostream &OS, const DWARFUnit *U) const {
|
||||
Optional<const char *> DbgStr = getAsCString(U);
|
||||
if (DbgStr.hasValue()) {
|
||||
raw_ostream &COS = WithColor(OS, syntax::String);
|
||||
COS << '"';
|
||||
COS.write_escaped(DbgStr.getValue());
|
||||
COS << '"';
|
||||
}
|
||||
}
|
||||
|
||||
Optional<const char *> DWARFFormValue::getAsCString(const DWARFUnit *U) const {
|
||||
if (!isFormClass(FC_String))
|
||||
return None;
|
||||
if (Form == DW_FORM_string)
|
||||
return Value.cstr;
|
||||
if (!U)
|
||||
// FIXME: Add support for DW_FORM_GNU_strp_alt
|
||||
if (Form == DW_FORM_GNU_strp_alt || U == nullptr)
|
||||
return None;
|
||||
uint32_t Offset = Value.uval;
|
||||
if (Form == DW_FORM_GNU_str_index) {
|
||||
@ -539,9 +546,9 @@ Optional<uint64_t> DWARFFormValue::getAsReference(const DWARFUnit *U) const {
|
||||
return Value.uval + U->getOffset();
|
||||
case DW_FORM_ref_addr:
|
||||
return Value.uval;
|
||||
// FIXME: Add proper support for DW_FORM_ref_sig8
|
||||
// FIXME: Add proper support for DW_FORM_ref_sig8 and DW_FORM_GNU_ref_alt.
|
||||
default:
|
||||
return Value.uval;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,10 @@ const char *llvm::dwarf::FormEncodingString(unsigned Encoding) {
|
||||
// DWARF5 Fission Extension Forms
|
||||
case DW_FORM_GNU_addr_index: return "DW_FORM_GNU_addr_index";
|
||||
case DW_FORM_GNU_str_index: return "DW_FORM_GNU_str_index";
|
||||
|
||||
// Alternate debug sections proposal (output of "dwz" tool).
|
||||
case DW_FORM_GNU_ref_alt: return "DW_FORM_GNU_ref_alt";
|
||||
case DW_FORM_GNU_strp_alt: return "DW_FORM_GNU_strp_alt";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
BIN
test/DebugInfo/Inputs/dwarfdump-test-dwz.elf-x86-64
Executable file
BIN
test/DebugInfo/Inputs/dwarfdump-test-dwz.elf-x86-64
Executable file
Binary file not shown.
@ -21,3 +21,9 @@ int main() {
|
||||
// $ cp dwarfdump-test.cc /tmp/dbginfo
|
||||
// $ cd /tmp/dbginfo
|
||||
// $ clang++ -g dwarfdump-test.cc -o <output>
|
||||
|
||||
// The result is also used as an input to .dwz tool:
|
||||
// $ cp <output> output1.dwz
|
||||
// $ cp <output> output2.dwz
|
||||
// $ dwz -m output.dwz -r output1.dwz output2.dwz
|
||||
// $ rm output2.dwz
|
||||
|
BIN
test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64.dwz
Normal file
BIN
test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64.dwz
Normal file
Binary file not shown.
14
test/DebugInfo/dwarfdump-dwz.test
Normal file
14
test/DebugInfo/dwarfdump-dwz.test
Normal file
@ -0,0 +1,14 @@
|
||||
; RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test-dwz.elf-x86-64 -debug-dump=info | FileCheck %s -check-prefix DUMP_INFO
|
||||
|
||||
; DUMP_INFO: .debug_info
|
||||
; DUMP_INFO: DW_TAG_compile_unit [2] *
|
||||
; DUMP_INFO-NEXT: DW_AT_producer [DW_FORM_GNU_strp_alt] (alt indirect string, offset: 0x0)
|
||||
; DUMP_INFO-NEXT: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
|
||||
; DUMP_INFO-NEXT: DW_AT_name [DW_FORM_GNU_strp_alt] (alt indirect string, offset: 0x31)
|
||||
; DUMP_INFO-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
|
||||
; DUMP_INFO-NEXT: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
|
||||
; DUMP_INFO-NEXT: DW_AT_comp_dir [DW_FORM_GNU_strp_alt] (alt indirect string, offset: 0x6b)
|
||||
|
||||
; DUMP_INFO: DW_TAG_imported_unit [4]
|
||||
; DUMP_INFO-NEXT: DW_AT_import [DW_FORM_GNU_ref_alt] (<alt 0xb>)
|
||||
|
Loading…
x
Reference in New Issue
Block a user