Index: llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -238,7 +238,7 @@ virtual StringRef getARangeSection() = 0; virtual StringRef getDebugFrameSection() = 0; virtual StringRef getEHFrameSection() = 0; - virtual const DWARFSection &getLineSection() = 0; + virtual const DWARFSection &getLineSection() const = 0; virtual StringRef getStringSection() = 0; virtual const DWARFSection& getRangeSection() = 0; virtual StringRef getMacinfoSection() = 0; @@ -250,6 +250,7 @@ /// DWARF v5 /// @{ virtual const DWARFSection &getStringOffsetSection() = 0; + virtual DataExtractor getStringExtractor() const = 0; /// @} // Sections for DWARF5 split dwarf proposal. @@ -360,7 +361,7 @@ StringRef getARangeSection() override { return ARangeSection; } StringRef getDebugFrameSection() override { return DebugFrameSection; } StringRef getEHFrameSection() override { return EHFrameSection; } - const DWARFSection &getLineSection() override { return LineSection; } + const DWARFSection &getLineSection() const override { return LineSection; } StringRef getStringSection() override { return StringSection; } const DWARFSection &getRangeSection() override { return RangeSection; } StringRef getMacinfoSection() override { return MacinfoSection; } @@ -377,6 +378,10 @@ const DWARFSection &getStringOffsetSection() override { return StringOffsetSection; } + DataExtractor getStringExtractor() const override { + return DataExtractor(StringSection, false, 0); + } + // Sections for DWARF5 split dwarf proposal. const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; } Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -21,11 +21,11 @@ namespace llvm { class raw_ostream; +class DWARFContext; class DWARFDebugLine { public: - DWARFDebugLine(const RelocAddrMap *LineInfoRelocMap) - : RelocMap(LineInfoRelocMap) {} + DWARFDebugLine(const DWARFContext *Ctx) : Context(Ctx) {} struct FileNameEntry { FileNameEntry() = default; @@ -93,7 +93,8 @@ void clear(); void dump(raw_ostream &OS) const; - bool parse(DataExtractor DebugLineData, uint32_t *OffsetPtr); + bool parse(DataExtractor DebugLineData, uint32_t *OffsetPtr, + const DWARFContext *Ctx); }; /// Standard .debug_line state machine structure. @@ -213,7 +214,7 @@ void clear(); /// Parse prologue and all rows. - bool parse(DataExtractor DebugLineData, const RelocAddrMap *RMap, + bool parse(DataExtractor DebugLineData, const DWARFContext *Ctx, uint32_t *OffsetPtr); struct Prologue Prologue; @@ -253,7 +254,7 @@ typedef LineTableMapTy::iterator LineTableIter; typedef LineTableMapTy::const_iterator LineTableConstIter; - const RelocAddrMap *RelocMap; + const DWARFContext *Context; LineTableMapTy LineTableMap; }; Index: llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -14,13 +14,16 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" #include namespace llvm { +class DWARFContext; class DWARFUnit; class raw_ostream; +class FormSizeHelper; class DWARFFormValue { public: @@ -53,6 +56,8 @@ dwarf::Form Form; /// Form for this value. ValueType Value; /// Contains all data for the form. const DWARFUnit *U = nullptr; /// Remember the DWARFUnit at extract time. + const RelocAddrMap *RMap = nullptr; + const DWARFContext *C = nullptr; public: DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} @@ -86,6 +91,12 @@ bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, const DWARFUnit *U); + // FIXME: doxygen + bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const RelocAddrMap &RelocMap, + uint16_t Version, uint8_t AddrSize, + dwarf::DwarfFormat Format); + bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; } @@ -180,6 +191,8 @@ private: void dumpString(raw_ostream &OS) const; + bool extractValueImpl(const DataExtractor &Data, uint32_t *OffsetPtr, + const FormSizeHelper *U); }; namespace dwarf { Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -292,7 +292,7 @@ savedAddressByteSize); DWARFDebugLine::LineTable LineTable; uint32_t Offset = *StmtOffset; - LineTable.parse(lineData, &getLineSection().Relocs, &Offset); + LineTable.parse(lineData, this, &Offset); LineTable.dump(OS); } } @@ -314,7 +314,7 @@ DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; - while (LineTable.Prologue.parse(lineData, &stmtOffset)) { + while (LineTable.Prologue.parse(lineData, &stmtOffset, this)) { LineTable.dump(OS); LineTable.clear(); } @@ -808,7 +808,7 @@ const DWARFLineTable * DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!Line) - Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); + Line.reset(new DWARFDebugLine(this)); auto UnitDIE = U->getUnitDIE(); if (!UnitDIE) Index: llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -136,7 +136,8 @@ static bool parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, - uint64_t EndPrologueOffset, + uint64_t EndPrologueOffset, const DWARFContext *Ctx, + uint16_t Version, uint8_t AddrSize, bool IsDWARF64, std::vector &IncludeDirectories, std::vector &FileNames) { // Get the directory entry description. @@ -146,6 +147,8 @@ return false; // Get the directory entries, according to the format described above. + dwarf::DwarfFormat Format = IsDWARF64 ? dwarf::DwarfFormat::DWARF64 + : dwarf::DwarfFormat::DWARF32; int DirEntryCount = DebugLineData.getU8(OffsetPtr); for (int I = 0; I != DirEntryCount; ++I) { if (*OffsetPtr >= EndPrologueOffset) @@ -154,12 +157,15 @@ DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, *Ctx, + Ctx->getLineSection().Relocs, Version, AddrSize, + Format)) return false; IncludeDirectories.push_back(Value.getAsCString().getValue()); break; default: - if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr)) + if (!DWARFFormValue::skipValue(Descriptor.Form, DebugLineData, + OffsetPtr, Version, AddrSize, Format)) return false; } } @@ -179,7 +185,9 @@ DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : FileDescriptors) { DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, *Ctx, + Ctx->getLineSection().Relocs, Version, AddrSize, + Format)) return false; switch (Descriptor.Type) { case DW_LNCT_path: @@ -205,7 +213,8 @@ } bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, + const DWARFContext *Ctx) { const uint64_t PrologueOffset = *OffsetPtr; clear(); @@ -243,6 +252,7 @@ if (Version >= 5) { if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, + Ctx, Version, AddressSize, IsDWARF64, IncludeDirectories, FileNames)) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 @@ -377,20 +387,20 @@ LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); LineTable *LT = &Pos.first->second; if (Pos.second) { - if (!LT->parse(DebugLineData, RelocMap, &Offset)) + if (!LT->parse(DebugLineData, Context, &Offset)) return nullptr; } return LT; } bool DWARFDebugLine::LineTable::parse(DataExtractor DebugLineData, - const RelocAddrMap *RMap, + const DWARFContext *Ctx, uint32_t *OffsetPtr) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(DebugLineData, OffsetPtr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr, Ctx)) { // Restore our offset and return false to indicate failure! *OffsetPtr = DebugLineOffset; return false; @@ -434,7 +444,8 @@ // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. State.Row.Address = getRelocatedValue( - DebugLineData, DebugLineData.getAddressSize(), OffsetPtr, RMap); + DebugLineData, DebugLineData.getAddressSize(), OffsetPtr, + &Ctx->getLineSection().Relocs); break; case DW_LNE_define_file: Index: llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -59,7 +59,7 @@ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; -namespace { +namespace llvm { /// A helper class that can be used in DWARFFormValue.cpp functions that need /// to know the byte size of DW_FORM values that vary in size depending on the @@ -92,7 +92,7 @@ } }; -} // end anonymous namespace +} // end namespace llvm template static Optional getFixedByteSize(dwarf::Form Form, const T *U) { @@ -318,8 +318,32 @@ } bool DWARFFormValue::extractValue(const DataExtractor &Data, + uint32_t *OffsetPtr, const DWARFContext &Ctx, + const RelocAddrMap &RelocMap, + uint16_t Version, uint8_t AddrSize, + dwarf::DwarfFormat Format) { + C = &Ctx; + RMap = &RelocMap; + FormSizeHelper FSH(Version, AddrSize, Format); + return extractValueImpl(Data, OffsetPtr, &FSH); +} + +bool DWARFFormValue::extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, const DWARFUnit *CU) { - U = CU; + if (CU) { + U = CU; + C = &CU->getContext(); + RMap = CU->getRelocMap(); + FormSizeHelper FSH(CU->getVersion(), CU->getAddressByteSize(), + CU->getFormat()); + return extractValueImpl(Data, OffsetPtr, &FSH); + } + return extractValueImpl(Data, OffsetPtr, nullptr); +} + +bool DWARFFormValue::extractValueImpl(const DataExtractor &Data, + uint32_t *OffsetPtr, + const FormSizeHelper *FSH) { bool Indirect = false; bool IsBlock = false; Value.data = nullptr; @@ -330,12 +354,12 @@ switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { - if (!U) + if (!FSH) return false; - uint16_t AddrSize = (Form == DW_FORM_addr) ? U->getAddressByteSize() - : U->getRefAddrByteSize(); - Value.uval = getRelocatedValue(Data, AddrSize, OffsetPtr, - U->getRelocMap(), &Value.SectionIndex); + uint16_t AddrSize = (Form == DW_FORM_addr) ? FSH->getAddressByteSize() + : FSH->getRefAddrByteSize(); + Value.uval = getRelocatedValue(Data, AddrSize, OffsetPtr, RMap, + &Value.SectionIndex); break; } case DW_FORM_exprloc: @@ -372,11 +396,9 @@ case DW_FORM_ref4: case DW_FORM_ref_sup4: case DW_FORM_strx4: - case DW_FORM_addrx4: { - const RelocAddrMap *RelocMap = U ? U->getRelocMap() : nullptr; - Value.uval = getRelocatedValue(Data, 4, OffsetPtr, RelocMap); + case DW_FORM_addrx4: + Value.uval = getRelocatedValue(Data, 4, OffsetPtr, RMap); break; - } case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sup8: @@ -402,10 +424,10 @@ case DW_FORM_GNU_strp_alt: case DW_FORM_line_strp: case DW_FORM_strp_sup: { - if (!U) + if (!FSH) return false; - Value.uval = getRelocatedValue(Data, U->getDwarfOffsetByteSize(), - OffsetPtr, U->getRelocMap()); + Value.uval = getRelocatedValue(Data, FSH->getDwarfOffsetByteSize(), + OffsetPtr, RMap); break; } case DW_FORM_flag_present: @@ -620,19 +642,21 @@ if (Form == DW_FORM_string) return Value.cstr; // FIXME: Add support for DW_FORM_GNU_strp_alt - if (Form == DW_FORM_GNU_strp_alt || U == nullptr) + if (Form == DW_FORM_GNU_strp_alt || C == nullptr) return None; uint32_t Offset = Value.uval; if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx) { uint64_t StrOffset; - if (!U->getStringOffsetSectionItem(Offset, StrOffset)) + if (!U || !U->getStringOffsetSectionItem(Offset, StrOffset)) return None; StrOffset += U->getStringOffsetSectionRelocation(Offset); Offset = StrOffset; } - if (const char *Str = U->getStringExtractor().getCStr(&Offset)) { + if (U) { + if (const char *Str = U->getStringExtractor().getCStr(&Offset)) + return Str; + } else if (const char *Str = C->getStringExtractor().getCStr(&Offset)) return Str; - } return None; } Index: llvm/test/DebugInfo/Inputs/dwarfdump-header-64.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/Inputs/dwarfdump-header-64.s @@ -0,0 +1,108 @@ +# Test object to verify dwarfdump handles a DWARF-64 v5 line header. +# FIXME: Make the other headers DWARF-64 also. +# FIXME: Add variants for earlier DWARF versions. + +# To generate the test object: +# llvm-mc -triple x86_64-unknown-linux dwarfdump-header-64.s -filetype=obj \ +# -o dwarfdump-header-64.elf-x86-64 + + .section .debug_str,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" +str_CU_5: + .asciz "V5_compile_unit" +str_LT_5a: + .asciz "Directory5a" +str_LT_5b: + .asciz "Directory5b" + + .section .debug_abbrev,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x00 # DW_CHILDREN_no + .byte 0x25 # DW_AT_producer + .byte 0x0e # DW_FORM_strp + .byte 0x03 # DW_AT_name + .byte 0x0e # DW_FORM_strp + .byte 0x10 # DW_AT_stmt_list + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + + .section .debug_info,"",@progbits + +# DWARF-32 v5 normal CU header. + .long CU_5_end-CU_5_version # Length of Unit +CU_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, with DW_AT_producer, DW_AT_name, DW_AT_stmt_list. + .byte 1 + .long str_producer + .long str_CU_5 + .long LH_5_start + .byte 0 # NULL +CU_5_end: + + .section .debug_line,"",@progbits +# DWARF-64 v5 line-table header. +LH_5_start: + .long -1 + .quad LH_5_end-LH_5_version # Length of Unit +LH_5_version: + .short 5 # DWARF version number + .byte 8 # Address Size + .byte 0 # Segment Selector Size + .quad LH_5_header_end-LH_5_params # Length of Prologue +LH_5_params: + .byte 1 # Minimum Instruction Length + .byte 1 # Maximum Operations per Instruction + .byte 1 # Default is_stmt + .byte -5 # Line Base + .byte 14 # Line Range + .byte 13 # Opcode Base + .byte 0 # Standard Opcode Lengths + .byte 1 + .byte 1 + .byte 1 + .byte 1 + .byte 0 + .byte 0 + .byte 0 + .byte 1 + .byte 0 + .byte 0 + .byte 1 + # Directory table format + .byte 1 # One element per directory entry + .byte 1 # DW_LNCT_path + .byte 0x0e # DW_FORM_strp + # Directory table entries + .byte 2 # Two directories + .quad str_LT_5a + .quad str_LT_5b + # File table format + .byte 4 # Four elements per file entry + .byte 1 # DW_LNCT_path + .byte 0x08 # DW_FORM_string + .byte 2 # DW_LNCT_directory_index + .byte 0x0b # DW_FORM_data1 + .byte 3 # DW_LNCT_timestamp + .byte 0x0f # DW_FORM_udata + .byte 4 # DW_LNCT_size + .byte 0x0f # DW_FORM_udata + # File table entries + .byte 2 # Two files + .asciz "File5a" + .byte 1 + .byte 0x51 + .byte 0x52 + .asciz "File5b" + .byte 2 + .byte 0x53 + .byte 0x54 +LH_5_header_end: + # Line number program, which is empty. +LH_5_end: Index: llvm/test/DebugInfo/Inputs/dwarfdump-header.s =================================================================== --- llvm/test/DebugInfo/Inputs/dwarfdump-header.s +++ llvm/test/DebugInfo/Inputs/dwarfdump-header.s @@ -15,6 +15,10 @@ .asciz "V5_compile_unit" str_TU_4: .asciz "V4_type_unit" +str_LT_5a: + .asciz "Directory5a" +str_LT_5b: + .asciz "Directory5b" .section .debug_str.dwo,"MS",@progbits,1 dwo_TU_5: @@ -227,11 +231,11 @@ # Directory table format .byte 1 # One element per directory entry .byte 1 # DW_LNCT_path - .byte 0x08 # DW_FORM_string + .byte 0x0e # DW_FORM_strp # Directory table entries .byte 2 # Two directories - .asciz "Directory5a" - .asciz "Directory5b" + .long str_LT_5a + .long str_LT_5b # File table format .byte 4 # Four elements per file entry .byte 1 # DW_LNCT_path Index: llvm/test/DebugInfo/dwarfdump-header-64.test =================================================================== --- /dev/null +++ llvm/test/DebugInfo/dwarfdump-header-64.test @@ -0,0 +1,29 @@ +RUN: llvm-dwarfdump %p/Inputs/dwarfdump-header-64.elf-x86-64 | FileCheck %s + +The input file is hand-coded assembler to generate DWARF-64 information, +so we're willing to make exact checks for offsets and such. + +CHECK-LABEL: .debug_info contents: + +The v5 CU header. + +CHECK: 0x00000000: Compile Unit: length = 0x00000016 version = 0x0005 unit_type = DW_UT_compile abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x0000001a) +CHECK: 0x0000000c: DW_TAG_compile_unit + +CHECK-LABEL: .debug_line contents: + +The DWARF-64 v5 line table header. + +CHECK: Line table prologue: +CHECK: total_length: 0x00000050 +CHECK: version: 5 +CHECK: address_size: 8 +CHECK: seg_select_size: 0 +CHECK: prologue_length: 0x00000044 +CHECK: max_ops_per_inst: 1 +CHECK: include_directories[ 1] = 'Directory5a' +CHECK: include_directories[ 2] = 'Directory5b' +CHECK-NOT: include_directories +CHECK: file_names[ 1] 1 0x00000051 0x00000052 File5a{{$}} +CHECK: file_names[ 2] 2 0x00000053 0x00000054 File5b{{$}} +CHECK-NOT: file_names Index: llvm/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/tools/dsymutil/DwarfLinker.cpp +++ llvm/tools/dsymutil/DwarfLinker.cpp @@ -2982,8 +2982,7 @@ StringRef LineData = OrigDwarf.getLineSection().Data; DataExtractor LineExtractor(LineData, OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize()); - LineTable.parse(LineExtractor, &OrigDwarf.getLineSection().Relocs, - &StmtOffset); + LineTable.parse(LineExtractor, &OrigDwarf, &StmtOffset); // This vector is the output line table. std::vector NewRows;