aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp')
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp783
1 files changed, 542 insertions, 241 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 11adb1e47640..3ca21e97888c 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -16,6 +16,7 @@
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -41,6 +42,10 @@ using ContentDescriptors = SmallVector<ContentDescriptor, 4>;
} // end anonymous namespace
+static bool versionIsSupported(uint16_t Version) {
+ return Version >= 2 && Version <= 5;
+}
+
void DWARFDebugLine::ContentTypeTracker::trackContentType(
dwarf::LineNumberEntryFormat ContentType) {
switch (ContentType) {
@@ -99,13 +104,21 @@ void DWARFDebugLine::Prologue::clear() {
void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
DIDumpOptions DumpOptions) const {
+ if (!totalLengthIsValid())
+ return;
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(FormParams.Format);
OS << "Line table prologue:\n"
- << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength)
+ << format(" total_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
+ TotalLength)
+ << " format: " << dwarf::FormatString(FormParams.Format) << "\n"
<< format(" version: %u\n", getVersion());
+ if (!versionIsSupported(getVersion()))
+ return;
if (getVersion() >= 5)
OS << format(" address_size: %u\n", getAddressSize())
<< format(" seg_select_size: %u\n", SegSelectorSize);
- OS << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength)
+ OS << format(" prologue_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
+ PrologueLength)
<< format(" min_inst_length: %u\n", MinInstLength)
<< format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
<< format(" default_is_stmt: %u\n", DefaultIsStmt)
@@ -114,8 +127,9 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
<< format(" opcode_base: %u\n", OpcodeBase);
for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I)
- OS << format("standard_opcode_lengths[%s] = %u\n",
- LNStandardString(I + 1).data(), StandardOpcodeLengths[I]);
+ OS << formatv("standard_opcode_lengths[{0}] = {1}\n",
+ static_cast<dwarf::LineNumberOps>(I + 1),
+ StandardOpcodeLengths[I]);
if (!IncludeDirectories.empty()) {
// DWARF v5 starts directory indexes at 0.
@@ -153,14 +167,21 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
}
// Parse v2-v4 directory and file tables.
-static void
+static Error
parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
- uint64_t *OffsetPtr, uint64_t EndPrologueOffset,
+ uint64_t *OffsetPtr,
DWARFDebugLine::ContentTypeTracker &ContentTypes,
std::vector<DWARFFormValue> &IncludeDirectories,
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
- while (*OffsetPtr < EndPrologueOffset) {
- StringRef S = DebugLineData.getCStrRef(OffsetPtr);
+ while (true) {
+ Error Err = Error::success();
+ StringRef S = DebugLineData.getCStrRef(OffsetPtr, &Err);
+ if (Err) {
+ consumeError(std::move(Err));
+ return createStringError(errc::invalid_argument,
+ "include directories table was not null "
+ "terminated before the end of the prologue");
+ }
if (S.empty())
break;
DWARFFormValue Dir =
@@ -168,21 +189,33 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
IncludeDirectories.push_back(Dir);
}
- while (*OffsetPtr < EndPrologueOffset) {
- StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
- if (Name.empty())
+ ContentTypes.HasModTime = true;
+ ContentTypes.HasLength = true;
+
+ while (true) {
+ Error Err = Error::success();
+ StringRef Name = DebugLineData.getCStrRef(OffsetPtr, &Err);
+ if (!Err && Name.empty())
break;
+
DWARFDebugLine::FileNameEntry FileEntry;
FileEntry.Name =
DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data());
- FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
- FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
- FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr, &Err);
+ FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr, &Err);
+ FileEntry.Length = DebugLineData.getULEB128(OffsetPtr, &Err);
+
+ if (Err) {
+ consumeError(std::move(Err));
+ return createStringError(
+ errc::invalid_argument,
+ "file names table was not null terminated before "
+ "the end of the prologue");
+ }
FileNames.push_back(FileEntry);
}
- ContentTypes.HasModTime = true;
- ContentTypes.HasLength = true;
+ return Error::success();
}
// Parse v5 directory/file entry content descriptions.
@@ -191,14 +224,15 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
static llvm::Expected<ContentDescriptors>
parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
DWARFDebugLine::ContentTypeTracker *ContentTypes) {
+ Error Err = Error::success();
ContentDescriptors Descriptors;
- int FormatCount = DebugLineData.getU8(OffsetPtr);
+ int FormatCount = DebugLineData.getU8(OffsetPtr, &Err);
bool HasPath = false;
- for (int I = 0; I != FormatCount; ++I) {
+ for (int I = 0; I != FormatCount && !Err; ++I) {
ContentDescriptor Descriptor;
Descriptor.Type =
- dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
- Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
+ dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr, &Err));
+ Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr, &Err));
if (Descriptor.Type == dwarf::DW_LNCT_path)
HasPath = true;
if (ContentTypes)
@@ -206,6 +240,11 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
Descriptors.push_back(Descriptor);
}
+ if (Err)
+ return createStringError(errc::invalid_argument,
+ "failed to parse entry content descriptors: %s",
+ toString(std::move(Err)).c_str());
+
if (!HasPath)
return createStringError(errc::invalid_argument,
"failed to parse entry content descriptions"
@@ -227,8 +266,8 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
return DirDescriptors.takeError();
// Get the directory entries, according to the format described above.
- int DirEntryCount = DebugLineData.getU8(OffsetPtr);
- for (int I = 0; I != DirEntryCount; ++I) {
+ uint64_t DirEntryCount = DebugLineData.getULEB128(OffsetPtr);
+ for (uint64_t I = 0; I != DirEntryCount; ++I) {
for (auto Descriptor : *DirDescriptors) {
DWARFFormValue Value(Descriptor.Form);
switch (Descriptor.Type) {
@@ -236,14 +275,14 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
return createStringError(errc::invalid_argument,
"failed to parse directory entry because "
- "extracting the form value failed.");
+ "extracting the form value failed");
IncludeDirectories.push_back(Value);
break;
default:
if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
return createStringError(errc::invalid_argument,
"failed to parse directory entry because "
- "skipping the form value failed.");
+ "skipping the form value failed");
}
}
}
@@ -255,15 +294,15 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
return FileDescriptors.takeError();
// Get the file entries, according to the format described above.
- int FileEntryCount = DebugLineData.getU8(OffsetPtr);
- for (int I = 0; I != FileEntryCount; ++I) {
+ uint64_t FileEntryCount = DebugLineData.getULEB128(OffsetPtr);
+ for (uint64_t I = 0; I != FileEntryCount; ++I) {
DWARFDebugLine::FileNameEntry FileEntry;
for (auto Descriptor : *FileDescriptors) {
DWARFFormValue Value(Descriptor.Form);
if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
return createStringError(errc::invalid_argument,
"failed to parse file entry because "
- "extracting the form value failed.");
+ "extracting the form value failed");
switch (Descriptor.Type) {
case DW_LNCT_path:
FileEntry.Name = Value;
@@ -297,78 +336,114 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
return Error::success();
}
-Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
- uint64_t *OffsetPtr,
- const DWARFContext &Ctx,
- const DWARFUnit *U) {
+uint64_t DWARFDebugLine::Prologue::getLength() const {
+ uint64_t Length = PrologueLength + sizeofTotalLength() +
+ sizeof(getVersion()) + sizeofPrologueLength();
+ if (getVersion() >= 5)
+ Length += 2; // Address + Segment selector sizes.
+ return Length;
+}
+
+Error DWARFDebugLine::Prologue::parse(
+ DWARFDataExtractor DebugLineData, uint64_t *OffsetPtr,
+ function_ref<void(Error)> RecoverableErrorHandler, const DWARFContext &Ctx,
+ const DWARFUnit *U) {
const uint64_t PrologueOffset = *OffsetPtr;
clear();
- TotalLength = DebugLineData.getRelocatedValue(4, OffsetPtr);
- if (TotalLength == dwarf::DW_LENGTH_DWARF64) {
- FormParams.Format = dwarf::DWARF64;
- TotalLength = DebugLineData.getU64(OffsetPtr);
- } else if (TotalLength >= dwarf::DW_LENGTH_lo_reserved) {
- return createStringError(errc::invalid_argument,
+ DataExtractor::Cursor Cursor(*OffsetPtr);
+ std::tie(TotalLength, FormParams.Format) =
+ DebugLineData.getInitialLength(Cursor);
+
+ DebugLineData =
+ DWARFDataExtractor(DebugLineData, Cursor.tell() + TotalLength);
+ FormParams.Version = DebugLineData.getU16(Cursor);
+ if (Cursor && !versionIsSupported(getVersion())) {
+ // Treat this error as unrecoverable - we cannot be sure what any of
+ // the data represents including the length field, so cannot skip it or make
+ // any reasonable assumptions.
+ *OffsetPtr = Cursor.tell();
+ return createStringError(
+ errc::not_supported,
"parsing line table prologue at offset 0x%8.8" PRIx64
- " unsupported reserved unit length found of value 0x%8.8" PRIx64,
- PrologueOffset, TotalLength);
+ ": unsupported version %" PRIu16,
+ PrologueOffset, getVersion());
}
- FormParams.Version = DebugLineData.getU16(OffsetPtr);
- if (getVersion() < 2)
- return createStringError(errc::not_supported,
- "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);
- assert((DebugLineData.getAddressSize() == 0 ||
+ FormParams.AddrSize = DebugLineData.getU8(Cursor);
+ assert((!Cursor || DebugLineData.getAddressSize() == 0 ||
DebugLineData.getAddressSize() == getAddressSize()) &&
"Line table header and data extractor disagree");
- SegSelectorSize = DebugLineData.getU8(OffsetPtr);
+ SegSelectorSize = DebugLineData.getU8(Cursor);
}
PrologueLength =
- DebugLineData.getRelocatedValue(sizeofPrologueLength(), OffsetPtr);
- const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr;
- MinInstLength = DebugLineData.getU8(OffsetPtr);
+ DebugLineData.getRelocatedValue(Cursor, sizeofPrologueLength());
+ const uint64_t EndPrologueOffset = PrologueLength + Cursor.tell();
+ DebugLineData = DWARFDataExtractor(DebugLineData, EndPrologueOffset);
+ MinInstLength = DebugLineData.getU8(Cursor);
if (getVersion() >= 4)
- MaxOpsPerInst = DebugLineData.getU8(OffsetPtr);
- DefaultIsStmt = DebugLineData.getU8(OffsetPtr);
- LineBase = DebugLineData.getU8(OffsetPtr);
- LineRange = DebugLineData.getU8(OffsetPtr);
- OpcodeBase = DebugLineData.getU8(OffsetPtr);
-
- StandardOpcodeLengths.reserve(OpcodeBase - 1);
- for (uint32_t I = 1; I < OpcodeBase; ++I) {
- uint8_t OpLen = DebugLineData.getU8(OffsetPtr);
- StandardOpcodeLengths.push_back(OpLen);
+ MaxOpsPerInst = DebugLineData.getU8(Cursor);
+ DefaultIsStmt = DebugLineData.getU8(Cursor);
+ LineBase = DebugLineData.getU8(Cursor);
+ LineRange = DebugLineData.getU8(Cursor);
+ OpcodeBase = DebugLineData.getU8(Cursor);
+
+ if (Cursor && OpcodeBase == 0) {
+ // If the opcode base is 0, we cannot read the standard opcode lengths (of
+ // which there are supposed to be one fewer than the opcode base). Assume
+ // there are no standard opcodes and continue parsing.
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at offset 0x%8.8" PRIx64
+ " found opcode base of 0. Assuming no standard opcodes",
+ PrologueOffset));
+ } else if (Cursor) {
+ StandardOpcodeLengths.reserve(OpcodeBase - 1);
+ for (uint32_t I = 1; I < OpcodeBase; ++I) {
+ uint8_t OpLen = DebugLineData.getU8(Cursor);
+ StandardOpcodeLengths.push_back(OpLen);
+ }
}
- if (getVersion() >= 5) {
- if (Error E =
- parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U,
- ContentTypes, IncludeDirectories, FileNames)) {
- return joinErrors(
- createStringError(
- errc::invalid_argument,
- "parsing line table prologue at 0x%8.8" PRIx64
- " found an invalid directory or file table description at"
- " 0x%8.8" PRIx64,
- PrologueOffset, *OffsetPtr),
- std::move(E));
- }
- } else
- parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
- ContentTypes, IncludeDirectories, FileNames);
+ *OffsetPtr = Cursor.tell();
+ // A corrupt file name or directory table does not prevent interpretation of
+ // the main line program, so check the cursor state now so that its errors can
+ // be handled separately.
+ if (!Cursor)
+ return createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at offset 0x%8.8" PRIx64 ": %s",
+ PrologueOffset, toString(Cursor.takeError()).c_str());
+
+ Error E =
+ getVersion() >= 5
+ ? parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U,
+ ContentTypes, IncludeDirectories, FileNames)
+ : parseV2DirFileTables(DebugLineData, OffsetPtr, ContentTypes,
+ IncludeDirectories, FileNames);
+ if (E) {
+ RecoverableErrorHandler(joinErrors(
+ createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at 0x%8.8" PRIx64
+ " found an invalid directory or file table description at"
+ " 0x%8.8" PRIx64,
+ PrologueOffset, *OffsetPtr),
+ std::move(E)));
+ return Error::success();
+ }
- if (*OffsetPtr != EndPrologueOffset)
- return createStringError(errc::invalid_argument,
- "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, *OffsetPtr);
+ assert(*OffsetPtr <= EndPrologueOffset);
+ if (*OffsetPtr != EndPrologueOffset) {
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "unknown data in line table prologue at offset 0x%8.8" PRIx64
+ ": parsing ended (at offset 0x%8.8" PRIx64
+ ") before reaching the prologue end at offset 0x%8.8" PRIx64,
+ PrologueOffset, *OffsetPtr, EndPrologueOffset));
+ }
return Error::success();
}
@@ -396,10 +471,12 @@ void DWARFDebugLine::Row::reset(bool DefaultIsStmt) {
EpilogueBegin = false;
}
-void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) {
- OS << "Address Line Column File ISA Discriminator Flags\n"
- << "------------------ ------ ------ ------ --- ------------- "
- "-------------\n";
+void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS, unsigned Indent) {
+ OS.indent(Indent)
+ << "Address Line Column File ISA Discriminator Flags\n";
+ OS.indent(Indent)
+ << "------------------ ------ ------ ------ --- ------------- "
+ "-------------\n";
}
void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
@@ -430,7 +507,7 @@ void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
if (!Rows.empty()) {
OS << '\n';
- Row::dumpTableHeader(OS);
+ Row::dumpTableHeader(OS, 0);
for (const Row &R : Rows) {
R.dump(OS);
}
@@ -447,8 +524,10 @@ void DWARFDebugLine::LineTable::clear() {
Sequences.clear();
}
-DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
- : LineTable(LT) {
+DWARFDebugLine::ParsingState::ParsingState(
+ struct LineTable *LT, uint64_t TableOffset,
+ function_ref<void(Error)> ErrorHandler)
+ : LineTable(LT), LineTableOffset(TableOffset), ErrorHandler(ErrorHandler) {
resetRowAndSequence();
}
@@ -488,7 +567,7 @@ DWARFDebugLine::getLineTable(uint64_t Offset) const {
Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx,
- const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorCallback) {
+ const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) {
if (!DebugLineData.isValidOffset(Offset))
return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64
" is not a valid debug line section offset",
@@ -499,32 +578,163 @@ Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
LineTable *LT = &Pos.first->second;
if (Pos.second) {
if (Error Err =
- LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback))
+ LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorHandler))
return std::move(Err);
return LT;
}
return LT;
}
+static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) {
+ assert(Opcode != 0);
+ if (Opcode < OpcodeBase)
+ return LNStandardString(Opcode);
+ return "special";
+}
+
+uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance,
+ uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ StringRef OpcodeName = getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase);
+ // For versions less than 4, the MaxOpsPerInst member is set to 0, as the
+ // maximum_operations_per_instruction field wasn't introduced until DWARFv4.
+ // Don't warn about bad values in this situation.
+ if (ReportAdvanceAddrProblem && LineTable->Prologue.getVersion() >= 4 &&
+ LineTable->Prologue.MaxOpsPerInst != 1)
+ ErrorHandler(createStringError(
+ errc::not_supported,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue maximum_operations_per_instruction value is %" PRId8
+ ", which is unsupported. Assuming a value of 1 instead",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset,
+ LineTable->Prologue.MaxOpsPerInst));
+ if (ReportAdvanceAddrProblem && LineTable->Prologue.MinInstLength == 0)
+ ErrorHandler(
+ createStringError(errc::invalid_argument,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue minimum_instruction_length value "
+ "is 0, which prevents any address advancing",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset));
+ ReportAdvanceAddrProblem = false;
+ uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength;
+ Row.Address.Address += AddrOffset;
+ return AddrOffset;
+}
+
+DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode
+DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ assert(Opcode == DW_LNS_const_add_pc ||
+ Opcode >= LineTable->Prologue.OpcodeBase);
+ if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) {
+ StringRef OpcodeName =
+ getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase);
+ ErrorHandler(
+ createStringError(errc::not_supported,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue line_range value is 0. The "
+ "address and line will not be adjusted",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset));
+ ReportBadLineRange = false;
+ }
+
+ uint8_t OpcodeValue = Opcode;
+ if (Opcode == DW_LNS_const_add_pc)
+ OpcodeValue = 255;
+ uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase;
+ uint64_t OperationAdvance =
+ LineTable->Prologue.LineRange != 0
+ ? AdjustedOpcode / LineTable->Prologue.LineRange
+ : 0;
+ uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset);
+ return {AddrOffset, AdjustedOpcode};
+}
+
+DWARFDebugLine::ParsingState::AddrAndLineDelta
+DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) +
+ // (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) *
+ // minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult =
+ advanceAddrForOpcode(Opcode, OpcodeOffset);
+ int32_t LineOffset = 0;
+ if (LineTable->Prologue.LineRange != 0)
+ LineOffset =
+ LineTable->Prologue.LineBase +
+ (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange);
+ Row.Line += LineOffset;
+ return {AddrAdvanceResult.AddrDelta, LineOffset};
+}
+
+/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on
+/// success, or None if \p Cursor is in a failing state.
+template <typename T>
+static Optional<T> parseULEB128(DWARFDataExtractor &Data,
+ DataExtractor::Cursor &Cursor) {
+ T Value = Data.getULEB128(Cursor);
+ if (Cursor)
+ return Value;
+ return None;
+}
+
Error DWARFDebugLine::LineTable::parse(
DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
const DWARFContext &Ctx, const DWARFUnit *U,
- function_ref<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
+ function_ref<void(Error)> RecoverableErrorHandler, raw_ostream *OS,
+ bool Verbose) {
+ assert((OS || !Verbose) && "cannot have verbose output without stream");
const uint64_t DebugLineOffset = *OffsetPtr;
clear();
- Error PrologueErr = Prologue.parse(DebugLineData, OffsetPtr, Ctx, U);
+ Error PrologueErr =
+ Prologue.parse(DebugLineData, OffsetPtr, RecoverableErrorHandler, Ctx, U);
if (OS) {
- // The presence of OS signals verbose dumping.
DIDumpOptions DumpOptions;
- DumpOptions.Verbose = true;
+ DumpOptions.Verbose = Verbose;
Prologue.dump(*OS, DumpOptions);
}
- if (PrologueErr)
+ if (PrologueErr) {
+ // Ensure there is a blank line after the prologue to clearly delineate it
+ // from later dumps.
+ if (OS)
+ *OS << "\n";
return PrologueErr;
+ }
uint64_t ProgramLength = Prologue.TotalLength + Prologue.sizeofTotalLength();
if (!DebugLineData.isValidOffsetForDataOfSize(DebugLineOffset,
@@ -532,7 +742,7 @@ Error DWARFDebugLine::LineTable::parse(
assert(DebugLineData.size() > DebugLineOffset &&
"prologue parsing should handle invalid offset");
uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset;
- RecoverableErrorCallback(
+ RecoverableErrorHandler(
createStringError(errc::invalid_argument,
"line table program with offset 0x%8.8" PRIx64
" has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64
@@ -542,41 +752,62 @@ Error DWARFDebugLine::LineTable::parse(
ProgramLength = BytesRemaining;
}
+ // Create a DataExtractor which can only see the data up to the end of the
+ // table, to prevent reading past the end.
const uint64_t EndOffset = DebugLineOffset + ProgramLength;
+ DWARFDataExtractor TableData(DebugLineData, EndOffset);
// See if we should tell the data extractor the address size.
- if (DebugLineData.getAddressSize() == 0)
- DebugLineData.setAddressSize(Prologue.getAddressSize());
+ if (TableData.getAddressSize() == 0)
+ TableData.setAddressSize(Prologue.getAddressSize());
else
assert(Prologue.getAddressSize() == 0 ||
- Prologue.getAddressSize() == DebugLineData.getAddressSize());
+ Prologue.getAddressSize() == TableData.getAddressSize());
- ParsingState State(this);
+ ParsingState State(this, DebugLineOffset, RecoverableErrorHandler);
+ *OffsetPtr = DebugLineOffset + Prologue.getLength();
+ if (OS && *OffsetPtr < EndOffset) {
+ *OS << '\n';
+ Row::dumpTableHeader(*OS, /*Indent=*/Verbose ? 12 : 0);
+ }
while (*OffsetPtr < EndOffset) {
- if (OS)
+ DataExtractor::Cursor Cursor(*OffsetPtr);
+
+ if (Verbose)
*OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
- uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
+ uint64_t OpcodeOffset = *OffsetPtr;
+ uint8_t Opcode = TableData.getU8(Cursor);
+ size_t RowCount = Rows.size();
- if (OS)
+ if (Cursor && Verbose)
*OS << format("%02.02" PRIx8 " ", Opcode);
if (Opcode == 0) {
// Extended Opcodes always start with a zero opcode followed by
// a uleb128 length so you can skip ones you don't know about
- uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
- uint64_t ExtOffset = *OffsetPtr;
+ uint64_t Len = TableData.getULEB128(Cursor);
+ uint64_t ExtOffset = Cursor.tell();
// Tolerate zero-length; assume length is correct and soldier on.
if (Len == 0) {
- if (OS)
+ if (Cursor && Verbose)
*OS << "Badly formed extended line op (length 0)\n";
+ if (!Cursor) {
+ if (Verbose)
+ *OS << "\n";
+ RecoverableErrorHandler(Cursor.takeError());
+ }
+ *OffsetPtr = Cursor.tell();
continue;
}
- uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
- if (OS)
+ uint8_t SubOpcode = TableData.getU8(Cursor);
+ // OperandOffset will be the same as ExtOffset, if it was not possible to
+ // read the SubOpcode.
+ uint64_t OperandOffset = Cursor.tell();
+ if (Verbose)
*OS << LNExtendedString(SubOpcode);
switch (SubOpcode) {
case DW_LNE_end_sequence:
@@ -588,11 +819,15 @@ Error DWARFDebugLine::LineTable::parse(
// address is that of the byte after the last target machine instruction
// of the sequence.
State.Row.EndSequence = true;
- if (OS) {
+ // No need to test the Cursor is valid here, since it must be to get
+ // into this code path - if it were invalid, the default case would be
+ // followed.
+ if (Verbose) {
*OS << "\n";
OS->indent(12);
- State.Row.dump(*OS);
}
+ if (OS)
+ State.Row.dump(*OS);
State.appendRowToMatrix();
State.resetRowAndSequence();
break;
@@ -608,25 +843,39 @@ Error DWARFDebugLine::LineTable::parse(
// Make sure the extractor knows the address size. If not, infer it
// from the size of the operand.
{
- uint8_t ExtractorAddressSize = DebugLineData.getAddressSize();
- if (ExtractorAddressSize != Len - 1 && ExtractorAddressSize != 0)
- RecoverableErrorCallback(createStringError(
+ uint8_t ExtractorAddressSize = TableData.getAddressSize();
+ uint64_t OpcodeAddressSize = Len - 1;
+ if (ExtractorAddressSize != OpcodeAddressSize &&
+ ExtractorAddressSize != 0)
+ RecoverableErrorHandler(createStringError(
errc::invalid_argument,
"mismatching address size at offset 0x%8.8" PRIx64
" expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
ExtOffset, ExtractorAddressSize, Len - 1));
// Assume that the line table is correct and temporarily override the
- // address size.
- DebugLineData.setAddressSize(Len - 1);
- State.Row.Address.Address = DebugLineData.getRelocatedAddress(
- OffsetPtr, &State.Row.Address.SectionIndex);
-
- // Restore the address size if the extractor already had it.
- if (ExtractorAddressSize != 0)
- DebugLineData.setAddressSize(ExtractorAddressSize);
+ // address size. If the size is unsupported, give up trying to read
+ // the address and continue to the next opcode.
+ if (OpcodeAddressSize != 1 && OpcodeAddressSize != 2 &&
+ OpcodeAddressSize != 4 && OpcodeAddressSize != 8) {
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "address size 0x%2.2" PRIx64
+ " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64
+ " is unsupported",
+ OpcodeAddressSize, ExtOffset));
+ TableData.skip(Cursor, OpcodeAddressSize);
+ } else {
+ TableData.setAddressSize(OpcodeAddressSize);
+ State.Row.Address.Address = TableData.getRelocatedAddress(
+ Cursor, &State.Row.Address.SectionIndex);
+
+ // Restore the address size if the extractor already had it.
+ if (ExtractorAddressSize != 0)
+ TableData.setAddressSize(ExtractorAddressSize);
+ }
- if (OS)
+ if (Cursor && Verbose)
*OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address.Address);
}
break;
@@ -654,14 +903,14 @@ Error DWARFDebugLine::LineTable::parse(
// the file register of the state machine.
{
FileNameEntry FileEntry;
- const char *Name = DebugLineData.getCStr(OffsetPtr);
+ const char *Name = TableData.getCStr(Cursor);
FileEntry.Name =
DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name);
- FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
- FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
- FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.DirIdx = TableData.getULEB128(Cursor);
+ FileEntry.ModTime = TableData.getULEB128(Cursor);
+ FileEntry.Length = TableData.getULEB128(Cursor);
Prologue.FileNames.push_back(FileEntry);
- if (OS)
+ if (Cursor && Verbose)
*OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
<< format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
<< ", length=" << FileEntry.Length << ")";
@@ -669,41 +918,63 @@ Error DWARFDebugLine::LineTable::parse(
break;
case DW_LNE_set_discriminator:
- State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr);
- if (OS)
+ State.Row.Discriminator = TableData.getULEB128(Cursor);
+ if (Cursor && Verbose)
*OS << " (" << State.Row.Discriminator << ")";
break;
default:
- if (OS)
+ if (Cursor && Verbose)
*OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
<< format(" length %" PRIx64, Len);
// Len doesn't include the zero opcode byte or the length itself, but
// it does include the sub_opcode, so we have to adjust for that.
- (*OffsetPtr) += Len - 1;
+ TableData.skip(Cursor, Len - 1);
break;
}
- // Make sure the stated and parsed lengths are the same.
- // Otherwise we have an unparseable line-number program.
- if (*OffsetPtr - ExtOffset != Len)
- return createStringError(errc::illegal_byte_sequence,
- "unexpected line op length at offset 0x%8.8" PRIx64
- " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
- ExtOffset, Len, *OffsetPtr - ExtOffset);
+ // Make sure the length as recorded in the table and the standard length
+ // for the opcode match. If they don't, continue from the end as claimed
+ // by the table. Similarly, continue from the claimed end in the event of
+ // a parsing error.
+ uint64_t End = ExtOffset + Len;
+ if (Cursor && Cursor.tell() != End)
+ RecoverableErrorHandler(createStringError(
+ errc::illegal_byte_sequence,
+ "unexpected line op length at offset 0x%8.8" PRIx64
+ " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
+ ExtOffset, Len, Cursor.tell() - ExtOffset));
+ if (!Cursor && Verbose) {
+ DWARFDataExtractor::Cursor ByteCursor(OperandOffset);
+ uint8_t Byte = TableData.getU8(ByteCursor);
+ if (ByteCursor) {
+ *OS << " (<parsing error>";
+ do {
+ *OS << format(" %2.2" PRIx8, Byte);
+ Byte = TableData.getU8(ByteCursor);
+ } while (ByteCursor);
+ *OS << ")";
+ }
+
+ // The only parse failure in this case should be if the end was reached.
+ // In that case, throw away the error, as the main Cursor's error will
+ // be sufficient.
+ consumeError(ByteCursor.takeError());
+ }
+ *OffsetPtr = End;
} else if (Opcode < Prologue.OpcodeBase) {
- if (OS)
+ if (Verbose)
*OS << LNStandardString(Opcode);
switch (Opcode) {
// Standard Opcodes
case DW_LNS_copy:
// Takes no arguments. Append a row to the matrix using the
// current values of the state-machine registers.
- if (OS) {
+ if (Verbose) {
*OS << "\n";
OS->indent(12);
- State.Row.dump(*OS);
- *OS << "\n";
}
+ if (OS)
+ State.Row.dump(*OS);
State.appendRowToMatrix();
break;
@@ -711,11 +982,11 @@ Error DWARFDebugLine::LineTable::parse(
// Takes a single unsigned LEB128 operand, multiplies it by the
// min_inst_length field of the prologue, and adds the
// result to the address register of the state machine.
- {
+ if (Optional<uint64_t> Operand =
+ parseULEB128<uint64_t>(TableData, Cursor)) {
uint64_t AddrOffset =
- DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength;
- State.Row.Address.Address += AddrOffset;
- if (OS)
+ State.advanceAddr(*Operand, Opcode, OpcodeOffset);
+ if (Verbose)
*OS << " (" << AddrOffset << ")";
}
break;
@@ -723,25 +994,36 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_advance_line:
// Takes a single signed LEB128 operand and adds that value to
// the line register of the state machine.
- State.Row.Line += DebugLineData.getSLEB128(OffsetPtr);
- if (OS)
- *OS << " (" << State.Row.Line << ")";
+ {
+ int64_t LineDelta = TableData.getSLEB128(Cursor);
+ if (Cursor) {
+ State.Row.Line += LineDelta;
+ if (Verbose)
+ *OS << " (" << State.Row.Line << ")";
+ }
+ }
break;
case DW_LNS_set_file:
// Takes a single unsigned LEB128 operand and stores it in the file
// register of the state machine.
- State.Row.File = DebugLineData.getULEB128(OffsetPtr);
- if (OS)
- *OS << " (" << State.Row.File << ")";
+ if (Optional<uint16_t> File =
+ parseULEB128<uint16_t>(TableData, Cursor)) {
+ State.Row.File = *File;
+ if (Verbose)
+ *OS << " (" << State.Row.File << ")";
+ }
break;
case DW_LNS_set_column:
// Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine.
- State.Row.Column = DebugLineData.getULEB128(OffsetPtr);
- if (OS)
- *OS << " (" << State.Row.Column << ")";
+ if (Optional<uint16_t> Column =
+ parseULEB128<uint16_t>(TableData, Cursor)) {
+ State.Row.Column = *Column;
+ if (Verbose)
+ *OS << " (" << State.Row.Column << ")";
+ }
break;
case DW_LNS_negate_stmt:
@@ -769,13 +1051,10 @@ Error DWARFDebugLine::LineTable::parse(
// than twice that range will it need to use both DW_LNS_advance_pc
// and a special opcode, requiring three or more bytes.
{
- uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase;
uint64_t AddrOffset =
- (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
- State.Row.Address.Address += AddrOffset;
- if (OS)
- *OS
- << format(" (0x%16.16" PRIx64 ")", AddrOffset);
+ State.advanceAddrForOpcode(Opcode, OpcodeOffset).AddrDelta;
+ if (Verbose)
+ *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset);
}
break;
@@ -790,11 +1069,13 @@ Error DWARFDebugLine::LineTable::parse(
// requires the use of DW_LNS_advance_pc. Such assemblers, however,
// can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
{
- uint16_t PCOffset = DebugLineData.getRelocatedValue(2, OffsetPtr);
- State.Row.Address.Address += PCOffset;
- if (OS)
- *OS
- << format(" (0x%4.4" PRIx16 ")", PCOffset);
+ uint16_t PCOffset =
+ TableData.getRelocatedValue(Cursor, 2);
+ if (Cursor) {
+ State.Row.Address.Address += PCOffset;
+ if (Verbose)
+ *OS << format(" (0x%4.4" PRIx16 ")", PCOffset);
+ }
}
break;
@@ -812,10 +1093,12 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_set_isa:
// Takes a single unsigned LEB128 operand and stores it in the
- // column register of the state machine.
- State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
- if (OS)
- *OS << " (" << (uint64_t)State.Row.Isa << ")";
+ // ISA register of the state machine.
+ if (Optional<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) {
+ State.Row.Isa = *Isa;
+ if (Verbose)
+ *OS << " (" << (uint64_t)State.Row.Isa << ")";
+ }
break;
default:
@@ -824,73 +1107,72 @@ Error DWARFDebugLine::LineTable::parse(
// as a multiple of LEB128 operands for each opcode.
{
assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
+ if (Verbose)
+ *OS << "Unrecognized standard opcode";
uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
+ std::vector<uint64_t> Operands;
for (uint8_t I = 0; I < OpcodeLength; ++I) {
- uint64_t Value = DebugLineData.getULEB128(OffsetPtr);
- if (OS)
- *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n",
- Value);
+ if (Optional<uint64_t> Value =
+ parseULEB128<uint64_t>(TableData, Cursor))
+ Operands.push_back(*Value);
+ else
+ break;
+ }
+ if (Verbose && !Operands.empty()) {
+ *OS << " (operands: ";
+ bool First = true;
+ for (uint64_t Value : Operands) {
+ if (!First)
+ *OS << ", ";
+ First = false;
+ *OS << format("0x%16.16" PRIx64, Value);
+ }
+ if (Verbose)
+ *OS << ')';
}
}
break;
}
+
+ *OffsetPtr = Cursor.tell();
} else {
- // Special Opcodes
-
- // A special opcode value is chosen based on the amount that needs
- // to be added to the line and address registers. The maximum line
- // increment for a special opcode is the value of the line_base
- // field in the header, plus the value of the line_range field,
- // minus 1 (line base + line range - 1). If the desired line
- // increment is greater than the maximum line increment, a standard
- // opcode must be used instead of a special opcode. The "address
- // advance" is calculated by dividing the desired address increment
- // by the minimum_instruction_length field from the header. The
- // special opcode is then calculated using the following formula:
- //
- // opcode = (desired line increment - line_base) +
- // (line_range * address advance) + opcode_base
- //
- // If the resulting opcode is greater than 255, a standard opcode
- // must be used instead.
- //
- // To decode a special opcode, subtract the opcode_base from the
- // opcode itself to give the adjusted opcode. The amount to
- // increment the address register is the result of the adjusted
- // opcode divided by the line_range multiplied by the
- // minimum_instruction_length field from the header. That is:
- //
- // address increment = (adjusted opcode / line_range) *
- // minimum_instruction_length
- //
- // The amount to increment the line register is the line_base plus
- // the result of the adjusted opcode modulo the line_range. That is:
- //
- // line increment = line_base + (adjusted opcode % line_range)
-
- uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase;
- uint64_t AddrOffset =
- (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
- int32_t LineOffset =
- Prologue.LineBase + (AdjustOpcode % Prologue.LineRange);
- State.Row.Line += LineOffset;
- State.Row.Address.Address += AddrOffset;
-
- if (OS) {
- *OS << "address += " << AddrOffset << ", line += " << LineOffset
+ // Special Opcodes.
+ ParsingState::AddrAndLineDelta Delta =
+ State.handleSpecialOpcode(Opcode, OpcodeOffset);
+
+ if (Verbose) {
+ *OS << "address += " << Delta.Address << ", line += " << Delta.Line
<< "\n";
OS->indent(12);
- State.Row.dump(*OS);
}
+ if (OS)
+ State.Row.dump(*OS);
State.appendRowToMatrix();
+ *OffsetPtr = Cursor.tell();
}
- if(OS)
+
+ // When a row is added to the matrix, it is also dumped, which includes a
+ // new line already, so don't add an extra one.
+ if (Verbose && Rows.size() == RowCount)
*OS << "\n";
+
+ // Most parse failures other than when parsing extended opcodes are due to
+ // failures to read ULEBs. Bail out of parsing, since we don't know where to
+ // continue reading from as there is no stated length for such byte
+ // sequences. Print the final trailing new line if needed before doing so.
+ if (!Cursor && Opcode != 0) {
+ if (Verbose)
+ *OS << "\n";
+ return Cursor.takeError();
+ }
+
+ if (!Cursor)
+ RecoverableErrorHandler(Cursor.takeError());
}
if (!State.Sequence.Empty)
- RecoverableErrorCallback(createStringError(
+ RecoverableErrorHandler(createStringError(
errc::illegal_byte_sequence,
"last sequence in debug line table at offset 0x%8.8" PRIx64
" is not terminated",
@@ -907,6 +1189,11 @@ Error DWARFDebugLine::LineTable::parse(
// rudimentary sequences for address ranges [0x0, 0xsomething).
}
+ // Terminate the table with a final blank line to clearly delineate it from
+ // later dumps.
+ if (OS)
+ *OS << "\n";
+
return Error::success();
}
@@ -1054,9 +1341,13 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
if (!Name)
return false;
StringRef FileName = *Name;
- if (Kind != FileLineInfoKind::AbsoluteFilePath ||
+ if (Kind == FileLineInfoKind::RawValue ||
isPathAbsoluteOnWindowsOrPosix(FileName)) {
- Result = FileName;
+ Result = std::string(FileName);
+ return true;
+ }
+ if (Kind == FileLineInfoKind::BaseNameOnly) {
+ Result = std::string(llvm::sys::path::filename(FileName));
return true;
}
@@ -1064,23 +1355,31 @@ bool DWARFDebugLine::Prologue::getFileNameByIndex(
StringRef IncludeDir;
// Be defensive about the contents of Entry.
if (getVersion() >= 5) {
- if (Entry.DirIdx < IncludeDirectories.size())
+ // DirIdx 0 is the compilation directory, so don't include it for
+ // relative names.
+ if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) &&
+ Entry.DirIdx < IncludeDirectories.size())
IncludeDir = IncludeDirectories[Entry.DirIdx].getAsCString().getValue();
} else {
if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size())
IncludeDir =
IncludeDirectories[Entry.DirIdx - 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.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
- sys::path::append(FilePath, Style, CompDir);
}
+ // For absolute paths only, include the 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 (Kind == FileLineInfoKind::AbsoluteFilePath && !CompDir.empty() &&
+ !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
+ sys::path::append(FilePath, Style, CompDir);
+
+ assert((Kind == FileLineInfoKind::AbsoluteFilePath ||
+ Kind == FileLineInfoKind::RelativeFilePath) &&
+ "invalid FileLineInfo Kind");
+
// sys::path::append skips empty strings.
sys::path::append(FilePath, Style, IncludeDir, FileName);
- Result = FilePath.str();
+ Result = std::string(FilePath.str());
return true;
}
@@ -1131,34 +1430,36 @@ DWARFDebugLine::SectionParser::SectionParser(DWARFDataExtractor &Data,
}
bool DWARFDebugLine::Prologue::totalLengthIsValid() const {
- return TotalLength == dwarf::DW_LENGTH_DWARF64 ||
- TotalLength < dwarf::DW_LENGTH_lo_reserved;
+ return TotalLength != 0u;
}
DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext(
- function_ref<void(Error)> RecoverableErrorCallback,
- function_ref<void(Error)> UnrecoverableErrorCallback, raw_ostream *OS) {
+ function_ref<void(Error)> RecoverableErrorHandler,
+ function_ref<void(Error)> UnrecoverableErrorHandler, raw_ostream *OS,
+ bool Verbose) {
assert(DebugLineData.isValidOffset(Offset) &&
"parsing should have terminated");
DWARFUnit *U = prepareToParse(Offset);
uint64_t OldOffset = Offset;
LineTable LT;
if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
- RecoverableErrorCallback, OS))
- UnrecoverableErrorCallback(std::move(Err));
+ RecoverableErrorHandler, OS, Verbose))
+ UnrecoverableErrorHandler(std::move(Err));
moveToNextTable(OldOffset, LT.Prologue);
return LT;
}
void DWARFDebugLine::SectionParser::skip(
- function_ref<void(Error)> ErrorCallback) {
+ function_ref<void(Error)> RecoverableErrorHandler,
+ function_ref<void(Error)> UnrecoverableErrorHandler) {
assert(DebugLineData.isValidOffset(Offset) &&
"parsing should have terminated");
DWARFUnit *U = prepareToParse(Offset);
uint64_t OldOffset = Offset;
LineTable LT;
- if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U))
- ErrorCallback(std::move(Err));
+ if (Error Err = LT.Prologue.parse(DebugLineData, &Offset,
+ RecoverableErrorHandler, Context, U))
+ UnrecoverableErrorHandler(std::move(Err));
moveToNextTable(OldOffset, LT.Prologue);
}