Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -77,7 +77,9 @@ // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. - DwarfLine->getOrParseLineTable(LineData, 0); + // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 + // needs it in order to find indirect strings. + DwarfLine->getOrParseLineTable(LineData, 0, nullptr); } // Returns source line information for a given offset Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -22,6 +22,7 @@ namespace llvm { +class DWARFUnit; class raw_ostream; class DWARFDebugLine { @@ -95,7 +96,8 @@ void clear(); void dump(raw_ostream &OS) const; - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr); + bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFUnit *U = nullptr); }; /// Standard .debug_line state machine structure. @@ -218,7 +220,7 @@ /// Parse prologue and all rows. bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - raw_ostream *OS = nullptr); + const DWARFUnit *U, raw_ostream *OS = nullptr); using RowVector = std::vector; using RowIter = RowVector::const_iterator; @@ -236,7 +238,7 @@ const LineTable *getLineTable(uint32_t Offset) const; const LineTable *getOrParseLineTable(const DWARFDataExtractor &DebugLineData, - uint32_t Offset); + uint32_t Offset, const DWARFUnit *U); private: struct ParsingState { Index: llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -104,16 +104,12 @@ const DWARFUnit *getUnit() const { return U; } void dump(raw_ostream &OS, DIDumpOptions DumpOpts = DIDumpOptions()) const; - /// Extracts a value in \p Data at offset \p *OffsetPtr. - /// - /// The passed DWARFUnit is allowed to be nullptr, in which case some - /// kind of forms that depend on Unit information are disallowed. - /// \param Data The DWARFDataExtractor to use. - /// \param OffsetPtr The offset within \p Data where the data starts. - /// \param U The optional DWARFUnit supplying information for some forms. - /// \returns whether the extraction succeeded. + /// Extracts a value in \p Data at offset \p *OffsetPtr. The information + /// in \p FormParams is needed to interpret some forms. The optional + /// \p Unit allows extracting information if the form refers to other + /// sections (e.g., .debug_str). bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, - const DWARFUnit *U); + DWARFFormParams FormParams, const DWARFUnit *U = nullptr); bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; Index: llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -184,7 +184,7 @@ FormValue.setSValue(Spec.getImplicitConstValue()); return FormValue; } - if (FormValue.extractValue(DebugInfoData, &Offset, &U)) + if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) return FormValue; } // March Offset along until we get to the attribute we want. Index: llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -90,10 +90,11 @@ DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; dwarf::Tag DieTag = dwarf::DW_TAG_null; + DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; for (auto Atom : getAtomsDesc()) { DWARFFormValue FormValue(Atom.second); - FormValue.extractValue(AccelSection, &HashDataOffset, NULL); + FormValue.extractValue(AccelSection, &HashDataOffset, FormParams); switch (Atom.first) { case dwarf::DW_ATOM_die_offset: DieOffset = *FormValue.getAsUnsignedConstant(); @@ -145,6 +146,7 @@ uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; unsigned HashesBase = Offset + Hdr.NumBuckets * 4; unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4; + DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) { unsigned Index = AccelSection.getU32(&Offset); @@ -181,7 +183,7 @@ unsigned i = 0; for (auto &Atom : AtomForms) { OS << format("{Atom[%d]: ", i++); - if (Atom.extractValue(AccelSection, &DataOffset, nullptr)) + if (Atom.extractValue(AccelSection, &DataOffset, FormParams)) Atom.dump(OS); else OS << "Error extracting the value"; @@ -216,8 +218,10 @@ NumData = 0; return; } + DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0, + dwarf::DwarfFormat::DWARF32}; for (auto &Atom : AtomForms) - Atom.extractValue(AccelSection, &DataOffset, nullptr); + Atom.extractValue(AccelSection, &DataOffset, FormParams); ++Data; } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -329,9 +329,9 @@ // representation. OS << "debug_line[" << format("0x%8.8x", Offset) << "]\n"; if (DumpOpts.Verbose) { - LineTable.parse(lineData, &Offset, &OS); + LineTable.parse(lineData, &Offset, &*CU, &OS); } else { - LineTable.parse(lineData, &Offset); + LineTable.parse(lineData, &Offset, &*CU); LineTable.dump(OS); } } @@ -349,7 +349,7 @@ DWARFDataExtractor lineData(*DObj, DObj->getLineDWOSection(), isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; - while (LineTable.Prologue.parse(lineData, &stmtOffset)) { + while (LineTable.Prologue.parse(lineData, &stmtOffset, nullptr)) { LineTable.dump(OS); LineTable.clear(); } @@ -681,7 +681,7 @@ // We have to parse it first. DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(), U->getAddressByteSize()); - return Line->getOrParseLineTable(lineData, stmtOffset); + return Line->getOrParseLineTable(lineData, stmtOffset, U); } void DWARFContext::parseCompileUnits() { Index: llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -144,7 +144,7 @@ static bool parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, uint64_t EndPrologueOffset, - const DWARFFormParams &FormParams, + const DWARFFormParams &FormParams, const DWARFUnit *U, std::vector &IncludeDirectories, std::vector &FileNames) { // Get the directory entry description. @@ -162,7 +162,7 @@ DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) return false; IncludeDirectories.push_back(Value.getAsCString().getValue()); break; @@ -187,7 +187,7 @@ DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : FileDescriptors) { DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) return false; switch (Descriptor.Type) { case DW_LNCT_path: @@ -213,7 +213,7 @@ } bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, const DWARFUnit *U) { const uint64_t PrologueOffset = *OffsetPtr; clear(); @@ -253,7 +253,8 @@ if (getVersion() >= 5) { if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - getFormParams(), IncludeDirectories, FileNames)) { + getFormParams(), U, IncludeDirectories, + FileNames)) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 " found an invalid directory or file table description at" @@ -382,24 +383,25 @@ const DWARFDebugLine::LineTable * DWARFDebugLine::getOrParseLineTable(const DWARFDataExtractor &DebugLineData, - uint32_t Offset) { + uint32_t Offset, const DWARFUnit *U) { std::pair Pos = LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); LineTable *LT = &Pos.first->second; if (Pos.second) { - if (!LT->parse(DebugLineData, &Offset)) + if (!LT->parse(DebugLineData, &Offset, U)) return nullptr; } return LT; } bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr, raw_ostream *OS) { + uint32_t *OffsetPtr, const DWARFUnit *U, + raw_ostream *OS) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(DebugLineData, OffsetPtr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr, U)) { // Restore our offset and return false to indicate failure! *OffsetPtr = DebugLineOffset; return false; Index: llvm/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -208,7 +208,8 @@ DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); - if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U)) + if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, + U->getFormParams(), U)) return; OS << "\t("; @@ -550,7 +551,7 @@ auto U = Die.getDwarfUnit(); assert(U && "Die must have valid DWARF unit"); bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(), - &ParseOffset, U); + &ParseOffset, U->getFormParams(), U); (void)b; assert(b && "extractValue cannot fail on fully parsed DWARF"); AttrValue.ByteSize = ParseOffset - AttrValue.Offset; Index: llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -276,7 +276,8 @@ } bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, - uint32_t *OffsetPtr, const DWARFUnit *CU) { + uint32_t *OffsetPtr, DWARFFormParams FP, + const DWARFUnit *CU) { U = CU; bool Indirect = false; bool IsBlock = false; @@ -288,10 +289,8 @@ switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { - if (!U) - return false; - uint16_t Size = (Form == DW_FORM_addr) ? U->getAddressByteSize() - : U->getRefAddrByteSize(); + uint16_t Size = + (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize(); Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex); break; } @@ -360,10 +359,8 @@ case DW_FORM_GNU_strp_alt: case DW_FORM_line_strp: case DW_FORM_strp_sup: { - if (!U) - return false; Value.uval = - Data.getRelocatedValue(U->getDwarfOffsetByteSize(), OffsetPtr); + Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr); break; } case DW_FORM_flag_present: 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 (-> .debug_str) # 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/X86/dwarfdump-header-64.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-header-64.s @@ -0,0 +1,149 @@ +# 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. + +# Lines beginning with @ELF@ should be preserved for ELF targets; +# lines beginning with @MACHO@ should be preserved for Mach-O targets. + +# RUN: sed -E 's/@ELF@(.*)/\1/;s/@MACHO@(.*)//' %s | \ +# RUN: llvm-mc -triple x86_64-unknown-linux -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -v - | FileCheck %s + +# RUN: sed -E 's/@ELF@(.*)//;s/@MACHO@(.*)/\1/' %s | \ +# RUN: llvm-mc -triple x86_64-apple-darwin -filetype=obj -o - | \ +# RUN: llvm-dwarfdump -v - | FileCheck %s + + +@ELF@ .section .debug_str,"MS",@progbits,1 +@MACHO@ .section __DWARF,__debug_str,regular,debug +str_producer: + .asciz "Handmade DWARF producer" +str_CU_5: + .asciz "V5_compile_unit" +str_LT_5a: + .asciz "Directory5a" +str_LT_5b: + .asciz "Directory5b" + +@ELF@ .section .debug_abbrev,"",@progbits +@MACHO@ .section __DWARF,__debug_abbrev,regular,debug +abbrev: + .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) + +@ELF@ .section .debug_info,"",@progbits +@MACHO@ .section __DWARF,__debug_info,regular,debug + +# DWARF-32 v5 normal CU header. +Lset0 = CU_5_end-CU_5_version # Length of Unit + .long Lset0 +CU_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) +@ELF@ .long abbrev # Offset Into Abbrev. Section +@MACHO@ .long 0 +# The compile-unit DIE, with DW_AT_producer, DW_AT_name, DW_AT_stmt_list. + .byte 1 + .long str_producer + .long str_CU_5 +@ELF@ .long LH_5_start +@MACHO@ .long 0 + .byte 0 # NULL +CU_5_end: + +# CHECK-LABEL: .debug_info contents: +# 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-NEXT: DW_AT_producer {{.*}} "Handmade DWARF producer" +# CHECK-NEXT: DW_AT_name {{.*}} "V5_compile_unit" +# CHECK-NEXT: DW_AT_stmt_list {{.*}} (0x00000000) + +@ELF@ .section .debug_line,"",@progbits +@MACHO@ .section __DWARF,__debug_line,regular,debug + +# DWARF-64 v5 line-table header. +LH_5_start: + .long -1 +Lset1 = LH_5_end-LH_5_version # Length of Unit + .quad Lset1 +LH_5_version: + .short 5 # DWARF version number + .byte 8 # Address Size + .byte 0 # Segment Selector Size +Lset2 = LH_5_header_end-LH_5_params # Length of Prologue + .quad Lset2 +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 (-> .debug_str) + # 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: + +# CHECK-LABEL: .debug_line contents: +# 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 @@ -2257,7 +2257,7 @@ continue; } - Val.extractValue(Data, &Offset, &Unit); + Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); CompileUnit *ReferencedCU; if (auto RefDie = resolveDIEReference(*this, Units, Val, Unit, Die, ReferencedCU)) { @@ -2854,7 +2854,7 @@ DWARFFormValue Val(AttrSpec.Form); uint32_t AttrSize = Offset; - Val.extractValue(Data, &Offset, &U); + Val.extractValue(Data, &Offset, U.getFormParams(), &U); AttrSize = Offset - AttrSize; OutOffset += @@ -3047,7 +3047,7 @@ DWARFDataExtractor LineExtractor( OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(), OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize()); - LineTable.parse(LineExtractor, &StmtOffset); + LineTable.parse(LineExtractor, &StmtOffset, &Unit.getOrigUnit()); // This vector is the output line table. std::vector NewRows; Index: llvm/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp =================================================================== --- llvm/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp +++ llvm/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp @@ -99,7 +99,7 @@ DWARFFormValue Result(Form); DWARFDataExtractor Data(StringRef(Raw, sizeof(RawTypeT)), sys::IsLittleEndianHost, sizeof(void *)); - Result.extractValue(Data, &Offset, nullptr); + Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32}); return Result; } @@ -110,7 +110,7 @@ uint32_t Offset = 0; DWARFFormValue Result(DW_FORM_udata); DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *)); - Result.extractValue(Data, &Offset, nullptr); + Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32}); return Result; } @@ -121,7 +121,7 @@ uint32_t Offset = 0; DWARFFormValue Result(DW_FORM_sdata); DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *)); - Result.extractValue(Data, &Offset, nullptr); + Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32}); return Result; }