Index: include/llvm/DebugInfo/DWARF/DWARFDebugLine.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -20,6 +20,7 @@ namespace llvm { +class DWARFUnit; class raw_ostream; class DWARFDebugLine { @@ -93,7 +94,8 @@ void clear(); void dump(raw_ostream &OS) const; - bool parse(DataExtractor DebugLineData, uint32_t *OffsetPtr); + bool parse(DataExtractor DebugLineData, uint32_t *OffsetPtr, + const DWARFUnit *U, const RelocAddrMap *RMap = nullptr); }; /// Standard .debug_line state machine structure. @@ -214,7 +216,7 @@ /// Parse prologue and all rows. bool parse(DataExtractor DebugLineData, const RelocAddrMap *RMap, - uint32_t *OffsetPtr); + uint32_t *OffsetPtr, const DWARFUnit *U); struct Prologue Prologue; typedef std::vector RowVector; @@ -231,7 +233,7 @@ const LineTable *getLineTable(uint32_t Offset) const; const LineTable *getOrParseLineTable(DataExtractor DebugLineData, - uint32_t Offset); + uint32_t Offset, const DWARFUnit *U); private: struct ParsingState { Index: include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -13,14 +13,17 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" #include +#include namespace llvm { class DWARFUnit; class raw_ostream; +class DWARFUnitProxy; class DWARFFormValue { public: @@ -51,7 +54,7 @@ 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. + std::shared_ptr U; // Info useful during extraction. public: DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {} @@ -69,18 +72,38 @@ } bool isFormClass(FormClass FC) const; - const DWARFUnit *getUnit() const { return U; } void dump(raw_ostream &OS) const; - /// \brief extracts a value in data at offset *offset_ptr. + /// Extracts a value in \p Data at offset from \p OffsetPtr. /// /// The passed DWARFUnit is allowed to be nullptr, in which /// case no relocation processing will be performed and some /// kind of forms that depend on Unit information are disallowed. + /// \param Data The DataExtractor to use. + /// \param OffsetPtr The offset within DataExtractor where the data starts. + /// \param U The optional DWARFUnit supplying information for some forms. /// \returns whether the extraction succeeded. bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, const DWARFUnit *U); + /// Extracts a value in \p Data at offset from \p OffsetPtr, from a + /// section other than .debug_info (e.g., .debug_line). + /// + /// The passed DWARFUnit mainly provides information about other sections + /// that might be needed for reference or indirect forms. Additional + /// parameters specify the relocations, DWARF format, and DWARF version to + /// use for interpreting certain forms. + /// \param Data The DataExtractor to use. + /// \param OffsetPtr The offset within DataExtractor where the data starts. + /// \param U The DWARFUnit supplying information about other sections. + /// \param RM The relocations for the section referenced by \p Data. + /// \param Format DWARF format (32-bit or 64-bit). + /// \param Version DWARF version number. + /// \returns whether the extraction succeeded. + bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, + const DWARFUnit *U, const RelocAddrMap *RM, + dwarf::DwarfFormat Format, uint16_t Version); + bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; } @@ -173,8 +196,27 @@ uint32_t *OffsetPtr, uint16_t Version, uint8_t AddrSize, llvm::dwarf::DwarfFormat Format); + /// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr. + /// + /// Skips the bytes for this form in a section other than .debug_info, + /// and updates the offset. + /// + /// \param Form the DW_FORM enumeration that indicates the form to skip. + /// \param DebugInfoData the .debug_info data to use to skip the value. + /// \param OffsetPtr a reference to the offset that will be updated. + /// \param DU a DWARFUnit describing other sections that might be needed. + /// \param RM relocations for the section used by \p DebugInfoData. + /// \param Format enum value from llvm::dwarf::DwarfFormat. + /// \param Version DWARF version number. + /// \returns true on success, false if the form was not skipped. + bool skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, + const DWARFUnit *DU, const RelocAddrMap *RM, + dwarf::DwarfFormat Format, uint16_t Version); + private: void dumpString(raw_ostream &OS) const; + bool extractValueImpl(const DataExtractor &DebugInfoData, + uint32_t *OffsetPtr); }; namespace dwarf { Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -168,7 +168,7 @@ savedAddressByteSize); DWARFDebugLine::LineTable LineTable; uint32_t Offset = *StmtOffset; - LineTable.parse(lineData, &getLineSection().Relocs, &Offset); + LineTable.parse(lineData, &getLineSection().Relocs, &Offset, &*CU); LineTable.dump(OS); } } @@ -190,7 +190,10 @@ DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; - while (LineTable.Prologue.parse(lineData, &stmtOffset)) { + DWARFUnit *U = nullptr; + if (!CUs.empty()) + U = &**CUs.begin(); + while (LineTable.Prologue.parse(lineData, &stmtOffset, U)) { LineTable.dump(OS); LineTable.clear(); } @@ -699,7 +702,7 @@ // We have to parse it first. DataExtractor lineData(U->getLineSection(), isLittleEndian(), U->getAddressByteSize()); - return Line->getOrParseLineTable(lineData, stmtOffset); + return Line->getOrParseLineTable(lineData, stmtOffset, U); } void DWARFContext::parseCompileUnits() { Index: lib/DebugInfo/DWARF/DWARFDebugLine.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -136,9 +136,13 @@ static bool parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, - uint64_t EndPrologueOffset, + uint64_t EndPrologueOffset, const DWARFUnit *U, + const RelocAddrMap *RM, bool IsDwarf64, uint16_t Version, std::vector &IncludeDirectories, std::vector &FileNames) { + dwarf::DwarfFormat Format = + IsDwarf64 ? dwarf::DwarfFormat::DWARF64 : dwarf::DwarfFormat::DWARF32; + // Get the directory entry description. ContentDescriptors DirDescriptors = parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); @@ -154,12 +158,13 @@ DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, U, RM, Format, + Version)) return false; IncludeDirectories.push_back(Value.getAsCString().getValue()); break; default: - if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.skipValue(DebugLineData, OffsetPtr, U, RM, Format, Version)) return false; } } @@ -179,7 +184,7 @@ DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : FileDescriptors) { DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, U, RM, Format, Version)) return false; switch (Descriptor.Type) { case DW_LNCT_path: @@ -205,7 +210,8 @@ } bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, const DWARFUnit *U, + const RelocAddrMap *RM) { const uint64_t PrologueOffset = *OffsetPtr; clear(); @@ -242,8 +248,9 @@ } if (Version >= 5) { - if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - IncludeDirectories, FileNames)) { + if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, U, + RM, IsDWARF64, Version, IncludeDirectories, + FileNames)) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 " found an invalid directory or file table description at" @@ -372,12 +379,12 @@ const DWARFDebugLine::LineTable * DWARFDebugLine::getOrParseLineTable(DataExtractor 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, RelocMap, &Offset)) + if (!LT->parse(DebugLineData, RelocMap, &Offset, U)) return nullptr; } return LT; @@ -385,12 +392,12 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor DebugLineData, const RelocAddrMap *RMap, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, const DWARFUnit *U) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(DebugLineData, OffsetPtr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr, U, RMap)) { // Restore our offset and return false to indicate failure! *OffsetPtr = DebugLineOffset; return false; Index: lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -59,19 +59,41 @@ 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 -/// DWARF version, address byte size, or DWARF32 or DWARF64. -class FormSizeHelper { +/// A helper class that provides information we would like to get from a +/// DWARFUnit, except we don't always have a real DWARFUnit handy, and +/// sometimes we need info relevant to a different section (e.g., .debug_line). +/// The API follows the equivalent DWARFUnit method names. +class DWARFUnitProxy { + const DWARFUnit *U; + const RelocAddrMap *RM; uint16_t Version; uint8_t AddrSize; - llvm::dwarf::DwarfFormat Format; + dwarf::DwarfFormat Format; public: - FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) - : Version(V), AddrSize(A), Format(F) {} + DWARFUnitProxy(const DWARFUnit *U) : U(U) { + if (U) { + RM = U->getRelocMap(); + Version = U->getVersion(); + AddrSize = U->getAddressByteSize(); + Format = U->getFormat(); + } else { + RM = nullptr; + Version = 0; + AddrSize = 0; + Format = dwarf::DwarfFormat::DWARF32; + } + } + + DWARFUnitProxy(const DWARFUnit *U, const RelocAddrMap *RM, + dwarf::DwarfFormat F, uint16_t V) + : U(U), RM(RM), Version(V), AddrSize(U ? U->getAddressByteSize() : 0), + Format(F) {} + + DWARFUnitProxy(uint16_t V, uint8_t A, dwarf::DwarfFormat F) + : U(nullptr), RM(nullptr), Version(V), AddrSize(A), Format(F) {} uint8_t getAddressByteSize() const { return AddrSize; } @@ -90,12 +112,34 @@ } llvm_unreachable("Invalid Format value"); } + + uint32_t getOffset() const { + if (U) + return U->getOffset(); + llvm_unreachable("Invalid use of DWARFUnitProxy"); + } + const RelocAddrMap *getRelocMap() const { return RM; } + DataExtractor getStringExtractor() const { + if (U) + return U->getStringExtractor(); + llvm_unreachable("Invalid use of DWARFUnitProxy"); + } + bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { + if (U) + return U->getAddrOffsetSectionItem(Index, Result); + llvm_unreachable("Invalid use of DWARFUnitProxy"); + } + bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const { + if (U) + return U->getStringOffsetSectionItem(Index, Result); + llvm_unreachable("Invalid use of DWARFUnitProxy"); + } }; -} // end anonymous namespace +} // end namespace llvm -template -static Optional getFixedByteSize(dwarf::Form Form, const T *U) { +static Optional getFixedByteSize(dwarf::Form Form, + const DWARFUnitProxy *U) { switch (Form) { case DW_FORM_addr: if (U) @@ -178,9 +222,8 @@ return None; } -template static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, - uint32_t *OffsetPtr, const T *U) { + uint32_t *OffsetPtr, const DWARFUnitProxy *U) { bool Indirect = false; do { switch (Form) { @@ -276,15 +319,16 @@ Optional DWARFFormValue::getFixedByteSize(dwarf::Form Form, const DWARFUnit *U) { - return ::getFixedByteSize(Form, U); + DWARFUnitProxy FVU(U); + return ::getFixedByteSize(Form, U ? &FVU : nullptr); } Optional DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, uint8_t AddrSize, llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return ::getFixedByteSize(Form, &FSH); + DWARFUnitProxy FVU(Version, AddrSize, Format); + return ::getFixedByteSize(Form, &FVU); } bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { @@ -318,7 +362,22 @@ bool DWARFFormValue::extractValue(const DataExtractor &Data, uint32_t *OffsetPtr, const DWARFUnit *CU) { - U = CU; + if (CU) + U = std::make_shared(CU); + return extractValueImpl(Data, OffsetPtr); +} + +bool DWARFFormValue::extractValue(const DataExtractor &Data, + uint32_t *OffsetPtr, const DWARFUnit *CU, + const RelocAddrMap *RM, + dwarf::DwarfFormat Format, uint16_t Version) { + if (CU) + U = std::make_shared(CU, RM, Format, Version); + return extractValueImpl(Data, OffsetPtr); +} + +bool DWARFFormValue::extractValueImpl(const DataExtractor &Data, + uint32_t *OffsetPtr) { bool Indirect = false; bool IsBlock = false; Value.data = nullptr; @@ -441,17 +500,25 @@ return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U); } +bool DWARFFormValue::skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, + const DWARFUnit *DU, const RelocAddrMap *RM, + dwarf::DwarfFormat Format, uint16_t Version) { + DWARFUnitProxy FVU(DU, RM, Format, Version); + return skipFormValue(Form, DebugInfoData, OffsetPtr, DU ? &FVU : nullptr); +} + bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, const DWARFUnit *U) { - return skipFormValue(Form, DebugInfoData, OffsetPtr, U); + uint32_t *OffsetPtr, const DWARFUnit *DU) { + DWARFUnitProxy FVU(DU); + return skipFormValue(Form, DebugInfoData, OffsetPtr, DU ? &FVU : nullptr); } bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, uint32_t *OffsetPtr, uint16_t Version, uint8_t AddrSize, llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return skipFormValue(Form, DebugInfoData, OffsetPtr, &FSH); + DWARFUnitProxy FVU(Version, AddrSize, Format); + return skipFormValue(Form, DebugInfoData, OffsetPtr, &FVU); } void DWARFFormValue::dump(raw_ostream &OS) const { Index: test/DebugInfo/Inputs/dwarfdump-header.s =================================================================== --- test/DebugInfo/Inputs/dwarfdump-header.s +++ 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: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -2984,7 +2984,7 @@ DataExtractor LineExtractor(LineData, OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize()); LineTable.parse(LineExtractor, &OrigDwarf.getLineSection().Relocs, - &StmtOffset); + &StmtOffset, &Unit.getOrigUnit()); // This vector is the output line table. std::vector NewRows;