diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/DebugInfo/DWARF/DWARFDebugLine.cpp | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'lib/DebugInfo/DWARF/DWARFDebugLine.cpp')
-rw-r--r-- | lib/DebugInfo/DWARF/DWARFDebugLine.cpp | 387 |
1 files changed, 290 insertions, 97 deletions
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index e5ef4eaceebe..53a8e193ef56 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -16,6 +17,7 @@ #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -40,6 +42,28 @@ using ContentDescriptors = SmallVector<ContentDescriptor, 4>; } // end anonmyous namespace +void DWARFDebugLine::ContentTypeTracker::trackContentType( + dwarf::LineNumberEntryFormat ContentType) { + switch (ContentType) { + case dwarf::DW_LNCT_timestamp: + HasModTime = true; + break; + case dwarf::DW_LNCT_size: + HasLength = true; + break; + case dwarf::DW_LNCT_MD5: + HasMD5 = true; + break; + case dwarf::DW_LNCT_LLVM_source: + HasSource = true; + break; + default: + // We only care about values we consider optional, and new values may be + // added in the vendor extension range, so we do not match exhaustively. + break; + } +} + DWARFDebugLine::Prologue::Prologue() { clear(); } void DWARFDebugLine::Prologue::clear() { @@ -47,14 +71,15 @@ void DWARFDebugLine::Prologue::clear() { SegSelectorSize = 0; MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; OpcodeBase = 0; - FormParams = DWARFFormParams({0, 0, DWARF32}); - HasMD5 = false; + FormParams = dwarf::FormParams({0, 0, DWARF32}); + ContentTypes = ContentTypeTracker(); StandardOpcodeLengths.clear(); IncludeDirectories.clear(); FileNames.clear(); } -void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { +void DWARFDebugLine::Prologue::dump(raw_ostream &OS, + DIDumpOptions DumpOptions) const { OS << "Line table prologue:\n" << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength) << format(" version: %u\n", getVersion()); @@ -73,29 +98,37 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { OS << format("standard_opcode_lengths[%s] = %u\n", LNStandardString(I + 1).data(), StandardOpcodeLengths[I]); - if (!IncludeDirectories.empty()) - for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) - OS << format("include_directories[%3u] = '", I + 1) - << IncludeDirectories[I] << "'\n"; + if (!IncludeDirectories.empty()) { + // DWARF v5 starts directory indexes at 0. + uint32_t DirBase = getVersion() >= 5 ? 0 : 1; + for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) { + OS << format("include_directories[%3u] = ", I + DirBase); + IncludeDirectories[I].dump(OS, DumpOptions); + OS << '\n'; + } + } if (!FileNames.empty()) { - if (HasMD5) - OS << " Dir MD5 Checksum File Name\n" - << " ---- -------------------------------- -----------" - "---------------\n"; - else - OS << " Dir Mod Time File Len File Name\n" - << " ---- ---------- ---------- -----------" - "----------------\n"; + // DWARF v5 starts file indexes at 0. + uint32_t FileBase = getVersion() >= 5 ? 0 : 1; for (uint32_t I = 0; I != FileNames.size(); ++I) { const FileNameEntry &FileEntry = FileNames[I]; - OS << format("file_names[%3u] %4" PRIu64 " ", I + 1, FileEntry.DirIdx); - if (HasMD5) - OS << FileEntry.Checksum.digest(); - else - OS << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64, FileEntry.ModTime, - FileEntry.Length); - OS << ' ' << FileEntry.Name << '\n'; + OS << format("file_names[%3u]:\n", I + FileBase); + OS << " name: "; + FileEntry.Name.dump(OS, DumpOptions); + OS << '\n' + << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx); + if (ContentTypes.HasMD5) + OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n'; + if (ContentTypes.HasModTime) + OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime); + if (ContentTypes.HasLength) + OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length); + if (ContentTypes.HasSource) { + OS << " source: "; + FileEntry.Source.dump(OS, DumpOptions); + OS << '\n'; + } } } } @@ -104,13 +137,16 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { static void parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, uint64_t EndPrologueOffset, - std::vector<StringRef> &IncludeDirectories, + DWARFDebugLine::ContentTypeTracker &ContentTypes, + std::vector<DWARFFormValue> &IncludeDirectories, std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { while (*OffsetPtr < EndPrologueOffset) { StringRef S = DebugLineData.getCStrRef(OffsetPtr); if (S.empty()) break; - IncludeDirectories.push_back(S); + DWARFFormValue Dir(dwarf::DW_FORM_string); + Dir.setPValue(S.data()); + IncludeDirectories.push_back(Dir); } while (*OffsetPtr < EndPrologueOffset) { @@ -118,20 +154,25 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, if (Name.empty()) break; DWARFDebugLine::FileNameEntry FileEntry; - FileEntry.Name = Name; + FileEntry.Name.setForm(dwarf::DW_FORM_string); + FileEntry.Name.setPValue(Name.data()); FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); FileNames.push_back(FileEntry); } + + ContentTypes.HasModTime = true; + ContentTypes.HasLength = true; } // Parse v5 directory/file entry content descriptions. // Returns the descriptors, or an empty vector if we did not find a path or // ran off the end of the prologue. static ContentDescriptors -parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - uint64_t EndPrologueOffset, bool *HasMD5) { +parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t + *OffsetPtr, uint64_t EndPrologueOffset, DWARFDebugLine::ContentTypeTracker + *ContentTypes) { ContentDescriptors Descriptors; int FormatCount = DebugLineData.getU8(OffsetPtr); bool HasPath = false; @@ -144,8 +185,8 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr)); if (Descriptor.Type == dwarf::DW_LNCT_path) HasPath = true; - else if (Descriptor.Type == dwarf::DW_LNCT_MD5 && HasMD5) - *HasMD5 = true; + if (ContentTypes) + ContentTypes->trackContentType(Descriptor.Type); Descriptors.push_back(Descriptor); } return HasPath ? Descriptors : ContentDescriptors(); @@ -154,8 +195,10 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, static bool parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, uint64_t EndPrologueOffset, - const DWARFFormParams &FormParams, const DWARFUnit *U, - bool &HasMD5, std::vector<StringRef> &IncludeDirectories, + const dwarf::FormParams &FormParams, + const DWARFContext &Ctx, const DWARFUnit *U, + DWARFDebugLine::ContentTypeTracker &ContentTypes, + std::vector<DWARFFormValue> &IncludeDirectories, std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { // Get the directory entry description. ContentDescriptors DirDescriptors = @@ -172,9 +215,9 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) return false; - IncludeDirectories.push_back(Value.getAsCString().getValue()); + IncludeDirectories.push_back(Value); break; default: if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams)) @@ -185,7 +228,8 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, // Get the file entry description. ContentDescriptors FileDescriptors = - parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, &HasMD5); + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, + &ContentTypes); if (FileDescriptors.empty()) return false; @@ -197,11 +241,14 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : FileDescriptors) { DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) return false; switch (Descriptor.Type) { case DW_LNCT_path: - FileEntry.Name = Value.getAsCString().getValue(); + FileEntry.Name = Value; + break; + case DW_LNCT_LLVM_source: + FileEntry.Source = Value; break; case DW_LNCT_directory_index: FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue(); @@ -226,8 +273,28 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, return true; } -bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr, const DWARFUnit *U) { +template <typename... Ts> +static std::string formatErrorString(char const *Fmt, const Ts &... Vals) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + return Stream.str(); +} + +template <typename... Ts> +static Error createError(char const *Fmt, const Ts &... Vals) { + return make_error<StringError>(formatErrorString(Fmt, Vals...), + inconvertibleErrorCode()); +} + +static Error createError(char const *Msg) { + return make_error<StringError>(Msg, inconvertibleErrorCode()); +} + +Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr, + const DWARFContext &Ctx, + const DWARFUnit *U) { const uint64_t PrologueOffset = *OffsetPtr; clear(); @@ -236,11 +303,16 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, FormParams.Format = dwarf::DWARF64; TotalLength = DebugLineData.getU64(OffsetPtr); } else if (TotalLength >= 0xffffff00) { - return false; + return createError( + "parsing line table prologue at offset 0x%8.8" PRIx64 + " unsupported reserved unit length found of value 0x%8.8" PRIx64, + PrologueOffset, TotalLength); } FormParams.Version = DebugLineData.getU16(OffsetPtr); if (getVersion() < 2) - return false; + return createError("parsing line table prologue at offset 0x%8.8" PRIx64 + " found unsupported version 0x%2.2" PRIx16, + PrologueOffset, getVersion()); if (getVersion() >= 5) { FormParams.AddrSize = DebugLineData.getU8(OffsetPtr); @@ -268,27 +340,24 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, if (getVersion() >= 5) { if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - getFormParams(), U, HasMD5, IncludeDirectories, - FileNames)) { - fprintf(stderr, - "warning: parsing line table prologue at 0x%8.8" PRIx64 - " found an invalid directory or file table description at" - " 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr); - return false; + FormParams, Ctx, U, ContentTypes, + IncludeDirectories, FileNames)) { + return createError( + "parsing line table prologue at 0x%8.8" PRIx64 + " found an invalid directory or file table description at" + " 0x%8.8" PRIx64, + PrologueOffset, (uint64_t)*OffsetPtr); } } else parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - IncludeDirectories, FileNames); - - if (*OffsetPtr != EndPrologueOffset) { - fprintf(stderr, - "warning: parsing line table prologue at 0x%8.8" PRIx64 - " should have ended at 0x%8.8" PRIx64 - " but it ended at 0x%8.8" PRIx64 "\n", - PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr); - return false; - } - return true; + ContentTypes, IncludeDirectories, FileNames); + + if (*OffsetPtr != EndPrologueOffset) + return createError("parsing line table prologue at 0x%8.8" PRIx64 + " should have ended at 0x%8.8" PRIx64 + " but it ended at 0x%8.8" PRIx64, + PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr); + return Error::success(); } DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); } @@ -340,8 +409,9 @@ void DWARFDebugLine::Sequence::reset() { DWARFDebugLine::LineTable::LineTable() { clear(); } -void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const { - Prologue.dump(OS); +void DWARFDebugLine::LineTable::dump(raw_ostream &OS, + DIDumpOptions DumpOptions) const { + Prologue.dump(OS, DumpOptions); OS << '\n'; if (!Rows.empty()) { @@ -396,34 +466,45 @@ DWARFDebugLine::getLineTable(uint32_t Offset) const { return nullptr; } -const DWARFDebugLine::LineTable * -DWARFDebugLine::getOrParseLineTable(DWARFDataExtractor &DebugLineData, - uint32_t Offset, const DWARFUnit *U) { +Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable( + DWARFDataExtractor &DebugLineData, uint32_t Offset, const DWARFContext &Ctx, + const DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) { + if (!DebugLineData.isValidOffset(Offset)) + return createError("offset 0x%8.8" PRIx32 + " is not a valid debug line section offset", + Offset); + std::pair<LineTableIter, bool> Pos = LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); LineTable *LT = &Pos.first->second; if (Pos.second) { - if (!LT->parse(DebugLineData, &Offset, U)) - return nullptr; + if (Error Err = + LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback)) + return std::move(Err); + return LT; } return LT; } -bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr, const DWARFUnit *U, - raw_ostream *OS) { +Error DWARFDebugLine::LineTable::parse( + DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U, + std::function<void(Error)> RecoverableErrorCallback, raw_ostream *OS) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(DebugLineData, OffsetPtr, U)) { - // Restore our offset and return false to indicate failure! - *OffsetPtr = DebugLineOffset; - return false; + Error PrologueErr = Prologue.parse(DebugLineData, OffsetPtr, Ctx, U); + + if (OS) { + // The presence of OS signals verbose dumping. + DIDumpOptions DumpOptions; + DumpOptions.Verbose = true; + Prologue.dump(*OS, DumpOptions); } - if (OS) - Prologue.dump(*OS); + if (PrologueErr) + return PrologueErr; const uint32_t EndOffset = DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength(); @@ -493,8 +574,12 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, // from the size of the operand. if (DebugLineData.getAddressSize() == 0) DebugLineData.setAddressSize(Len - 1); - else - assert(DebugLineData.getAddressSize() == Len - 1); + else if (DebugLineData.getAddressSize() != Len - 1) { + return createError("mismatching address size at offset 0x%8.8" PRIx32 + " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64, + ExtOffset, DebugLineData.getAddressSize(), + Len - 1); + } State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr); if (OS) *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address); @@ -523,14 +608,15 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, // the file register of the state machine. { FileNameEntry FileEntry; - FileEntry.Name = DebugLineData.getCStr(OffsetPtr); + const char *Name = DebugLineData.getCStr(OffsetPtr); + FileEntry.Name.setForm(dwarf::DW_FORM_string); + FileEntry.Name.setPValue(Name); FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); Prologue.FileNames.push_back(FileEntry); if (OS) - *OS << " (" << FileEntry.Name.str() - << ", dir=" << FileEntry.DirIdx << ", mod_time=" + *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time=" << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime) << ", length=" << FileEntry.Length << ")"; } @@ -553,14 +639,10 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, } // Make sure the stated and parsed lengths are the same. // Otherwise we have an unparseable line-number program. - if (*OffsetPtr - ExtOffset != Len) { - fprintf(stderr, "Unexpected line op length at offset 0x%8.8" PRIx32 - " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32 "\n", - ExtOffset, Len, *OffsetPtr - ExtOffset); - // Skip the rest of the line-number program. - *OffsetPtr = EndOffset; - return false; - } + if (*OffsetPtr - ExtOffset != Len) + return createError("unexpected line op length at offset 0x%8.8" PRIx32 + " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32, + ExtOffset, Len, *OffsetPtr - ExtOffset); } else if (Opcode < Prologue.OpcodeBase) { if (OS) *OS << LNStandardString(Opcode); @@ -763,14 +845,13 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, *OS << "\n"; } - if (!State.Sequence.Empty) { - fprintf(stderr, "warning: last sequence in debug line table is not" - "terminated!\n"); - } + if (!State.Sequence.Empty) + RecoverableErrorCallback( + createError("last sequence in debug line table is not terminated!")); // Sort all sequences so that address lookup will work faster. if (!Sequences.empty()) { - std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC); + llvm::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC); // Note: actually, instruction address ranges of sequences should not // overlap (in shared objects and executables). If they do, the address // lookup would still work, though, but result would be ambiguous. @@ -779,7 +860,7 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, // rudimentary sequences for address ranges [0x0, 0xsomething). } - return EndOffset; + return Error::success(); } uint32_t @@ -887,6 +968,24 @@ bool DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { return FileIndex != 0 && FileIndex <= Prologue.FileNames.size(); } +Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex, + FileLineInfoKind Kind) const { + if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) + return None; + const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; + if (Optional<const char *> source = Entry.Source.getAsCString()) + return StringRef(*source); + return None; +} + +static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) { + // Debug info can contain paths from any OS, not necessarily + // an OS we're currently running on. Moreover different compilation units can + // be compiled on different operating systems and linked together later. + return sys::path::is_absolute(Path, sys::path::Style::posix) || + sys::path::is_absolute(Path, sys::path::Style::windows); +} + bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, const char *CompDir, FileLineInfoKind Kind, @@ -894,9 +993,9 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) return false; const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; - StringRef FileName = Entry.Name; + StringRef FileName = Entry.Name.getAsCString().getValue(); if (Kind != FileLineInfoKind::AbsoluteFilePath || - sys::path::is_absolute(FileName)) { + isPathAbsoluteOnWindowsOrPosix(FileName)) { Result = FileName; return true; } @@ -907,13 +1006,15 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, // Be defensive about the contents of Entry. if (IncludeDirIndex > 0 && IncludeDirIndex <= Prologue.IncludeDirectories.size()) - IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1]; + IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1] + .getAsCString() + .getValue(); // We may still need to append compilation directory of compile unit. // We know that FileName is not absolute, the only way to have an // absolute path at this point would be if IncludeDir is absolute. if (CompDir && Kind == FileLineInfoKind::AbsoluteFilePath && - sys::path::is_relative(IncludeDir)) + !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) sys::path::append(FilePath, CompDir); // sys::path::append skips empty strings. @@ -936,5 +1037,97 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress( Result.Line = Row.Line; Result.Column = Row.Column; Result.Discriminator = Row.Discriminator; + Result.Source = getSourceByIndex(Row.File, Kind); return true; } + +// We want to supply the Unit associated with a .debug_line[.dwo] table when +// we dump it, if possible, but still dump the table even if there isn't a Unit. +// Therefore, collect up handles on all the Units that point into the +// line-table section. +static DWARFDebugLine::SectionParser::LineToUnitMap +buildLineToUnitMap(DWARFDebugLine::SectionParser::cu_range CUs, + DWARFDebugLine::SectionParser::tu_range TUSections) { + DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit; + for (const auto &CU : CUs) + if (auto CUDIE = CU->getUnitDIE()) + if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) + LineToUnit.insert(std::make_pair(*StmtOffset, &*CU)); + for (const auto &TUS : TUSections) + for (const auto &TU : TUS) + if (auto TUDIE = TU->getUnitDIE()) + if (auto StmtOffset = toSectionOffset(TUDIE.find(DW_AT_stmt_list))) + LineToUnit.insert(std::make_pair(*StmtOffset, &*TU)); + return LineToUnit; +} + +DWARFDebugLine::SectionParser::SectionParser(DWARFDataExtractor &Data, + const DWARFContext &C, + cu_range CUs, tu_range TUs) + : DebugLineData(Data), Context(C) { + LineToUnit = buildLineToUnitMap(CUs, TUs); + if (!DebugLineData.isValidOffset(Offset)) + Done = true; +} + +bool DWARFDebugLine::Prologue::totalLengthIsValid() const { + return TotalLength == 0xffffffff || TotalLength < 0xffffff00; +} + +DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext( + function_ref<void(Error)> RecoverableErrorCallback, + function_ref<void(Error)> UnrecoverableErrorCallback, raw_ostream *OS) { + assert(DebugLineData.isValidOffset(Offset) && + "parsing should have terminated"); + DWARFUnit *U = prepareToParse(Offset); + uint32_t OldOffset = Offset; + LineTable LT; + if (Error Err = LT.parse(DebugLineData, &Offset, Context, U, + RecoverableErrorCallback, OS)) + UnrecoverableErrorCallback(std::move(Err)); + moveToNextTable(OldOffset, LT.Prologue); + return LT; +} + +void DWARFDebugLine::SectionParser::skip( + function_ref<void(Error)> ErrorCallback) { + assert(DebugLineData.isValidOffset(Offset) && + "parsing should have terminated"); + DWARFUnit *U = prepareToParse(Offset); + uint32_t OldOffset = Offset; + LineTable LT; + if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U)) + ErrorCallback(std::move(Err)); + moveToNextTable(OldOffset, LT.Prologue); +} + +DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint32_t Offset) { + DWARFUnit *U = nullptr; + auto It = LineToUnit.find(Offset); + if (It != LineToUnit.end()) + U = It->second; + DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0); + return U; +} + +void DWARFDebugLine::SectionParser::moveToNextTable(uint32_t OldOffset, + const Prologue &P) { + // If the length field is not valid, we don't know where the next table is, so + // cannot continue to parse. Mark the parser as done, and leave the Offset + // value as it currently is. This will be the end of the bad length field. + if (!P.totalLengthIsValid()) { + Done = true; + return; + } + + Offset = OldOffset + P.TotalLength + P.sizeofTotalLength(); + if (!DebugLineData.isValidOffset(Offset)) { + Done = true; + } +} + +void DWARFDebugLine::warn(Error Err) { + handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) { + WithColor::warning() << Info.message() << '\n'; + }); +} |