From 4ca606f22fe311dc20828242d3961cbafa040343 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Tue, 19 May 2015 20:29:28 +0000 Subject: [PATCH] [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 --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h | 2 + include/llvm/Support/Dwarf.h | 6 +- lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp | 17 ++-- lib/DebugInfo/DWARF/DWARFFormValue.cpp | 77 ++++++++++-------- lib/Support/Dwarf.cpp | 4 + .../Inputs/dwarfdump-test-dwz.elf-x86-64 | Bin 0 -> 9399 bytes test/DebugInfo/Inputs/dwarfdump-test.cc | 6 ++ .../Inputs/dwarfdump-test.elf-x86-64.dwz | Bin 0 -> 1026 bytes test/DebugInfo/dwarfdump-dwz.test | 14 ++++ 9 files changed, 82 insertions(+), 44 deletions(-) create mode 100755 test/DebugInfo/Inputs/dwarfdump-test-dwz.elf-x86-64 create mode 100644 test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64.dwz create mode 100644 test/DebugInfo/dwarfdump-dwz.test diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 02f468189d2..7ddcc0d81d5 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -87,6 +87,8 @@ public: static ArrayRef getFixedFormSizes(uint8_t AddrSize, uint16_t Version); +private: + void dumpString(raw_ostream &OS, const DWARFUnit *U) const; }; } diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h index c294a72a04b..c3d94d19f91 100644 --- a/include/llvm/Support/Dwarf.h +++ b/include/llvm/Support/Dwarf.h @@ -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 { diff --git a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index e963b7ca6e6..5abbde4ac0f 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -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 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 OptVal = formValue.getAsUnsignedConstant()) dumpApplePropertyAttribute(OS, *OptVal); diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 6946f833424..75ca7622139 100644 --- a/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -113,14 +113,17 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { if (Form < ArrayRef(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 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 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("", 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 DbgStr = getAsCString(U); + if (DbgStr.hasValue()) { + raw_ostream &COS = WithColor(OS, syntax::String); + COS << '"'; + COS.write_escaped(DbgStr.getValue()); + COS << '"'; + } +} + Optional 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 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; } } diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp index 95c4bc32701..6229825a8ee 100644 --- a/lib/Support/Dwarf.cpp +++ b/lib/Support/Dwarf.cpp @@ -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; } diff --git a/test/DebugInfo/Inputs/dwarfdump-test-dwz.elf-x86-64 b/test/DebugInfo/Inputs/dwarfdump-test-dwz.elf-x86-64 new file mode 100755 index 0000000000000000000000000000000000000000..937961b59bea345982c6b494a752800c73e44b59 GIT binary patch literal 9399 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 OfcBM8zUv~mRPk?-pIegv literal 0 HcmV?d00001 diff --git a/test/DebugInfo/Inputs/dwarfdump-test.cc b/test/DebugInfo/Inputs/dwarfdump-test.cc index 40899986490..14295d3cffa 100644 --- a/test/DebugInfo/Inputs/dwarfdump-test.cc +++ b/test/DebugInfo/Inputs/dwarfdump-test.cc @@ -21,3 +21,9 @@ int main() { // $ cp dwarfdump-test.cc /tmp/dbginfo // $ cd /tmp/dbginfo // $ clang++ -g dwarfdump-test.cc -o + +// The result is also used as an input to .dwz tool: +// $ cp output1.dwz +// $ cp output2.dwz +// $ dwz -m output.dwz -r output1.dwz output2.dwz +// $ rm output2.dwz diff --git a/test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64.dwz b/test/DebugInfo/Inputs/dwarfdump-test.elf-x86-64.dwz new file mode 100644 index 0000000000000000000000000000000000000000..32db372fcda65c3aa556076c15e27cc944b023b5 GIT binary patch literal 1026 zcmbu8&u-H|5XNV1Cn;D24#^=Zl_FXpg6JkqKq|Bii6b|j05R*>sb%%XD(m^?H{Xmm()z8nyQ2{T`693dr&&$` zeiq;m*0C^z8dSkR)xfReez5lx{(QE3zi#~4`1@(+_q%7`m%qNheew`%8g77vG(1Oj z?gSqdLtk2WgTf%hxQ?+wG;JC5iekhd)kV^P8nH3kR;1EM3Fu3x!EWN%O>(KaSjYEY zOmpJ`=ykh!$J{X2&-YDy1tof2rJJq0Ed{Eo@n#F4MoHiNFs#qYc2gPD3DIwwssj(X zg44E46D3^1t-)n=45EJgC5t>h4Ubk6H%{nyj1_=!z@*MYfQ^8GbH*6PIe0KS*jww}pN8S^AgY0lR24*viBC^GE>fP zGdsMfUgP;)aTAfNbbG@%3WvbV}chU)68)q_c+f2A>CZ##9W4K98KUK DzZQEF literal 0 HcmV?d00001 diff --git a/test/DebugInfo/dwarfdump-dwz.test b/test/DebugInfo/dwarfdump-dwz.test new file mode 100644 index 00000000000..e5f67ebe487 --- /dev/null +++ b/test/DebugInfo/dwarfdump-dwz.test @@ -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] () + -- 2.34.1