/// Parse prologue and all rows.
Error parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
const DWARFContext &Ctx, const DWARFUnit *U,
- std::function<void(StringRef)> WarnCallback = warn,
+ std::function<void(Error)> RecoverableErrorCallback = warn,
raw_ostream *OS = nullptr);
using RowVector = std::vector<Row>;
};
const LineTable *getLineTable(uint32_t Offset) const;
- Expected<const LineTable *>
- getOrParseLineTable(DWARFDataExtractor &DebugLineData, uint32_t Offset,
- const DWARFContext &Ctx, const DWARFUnit *U,
- std::function<void(StringRef)> WarnCallback = warn);
+ Expected<const LineTable *> getOrParseLineTable(
+ DWARFDataExtractor &DebugLineData, uint32_t Offset,
+ const DWARFContext &Ctx, const DWARFUnit *U,
+ std::function<void(Error)> RecoverableErrorCallback = warn);
/// Helper to allow for parsing of an entire .debug_line section in sequence.
class SectionParser {
/// Get the next line table from the section. Report any issues via the
/// callbacks.
///
- /// \param StringCallback - any issues that don't indicate that the line
- /// table is invalid are reported using this function.
- /// \param ErrorCallback - any issues that mean that the line table is
- /// invalid are reported using this callback.
+ /// \param RecoverableErrorCallback - any issues that don't prevent further
+ /// parsing of the table will be reported through this callback.
+ /// \param UnrecoverableErrorCallback - any issues that prevent further
+ /// parsing of the table will be reported through this callback.
/// \param OS - if not null, the parser will print information about the
/// table as it parses it.
- LineTable parseNext(
- function_ref<void(StringRef)> StringCallback = warn,
- function_ref<void(Error)> ErrorCallback = warnForError,
- raw_ostream *OS = nullptr);
+ LineTable
+ parseNext(function_ref<void(Error)> RecoverableErrorCallback = warn,
+ function_ref<void(Error)> UnrecoverableErrorCallback = warn,
+ raw_ostream *OS = nullptr);
/// Skip the current line table and go to the following line table (if
/// present) immediately.
///
/// \param ErrorCallback - report any prologue parsing issues via this
/// callback.
- void skip(function_ref<void(Error)> ErrorCallback = warnForError);
+ void skip(function_ref<void(Error)> ErrorCallback = warn);
/// Indicates if the parser has parsed as much as possible.
///
bool Done = false;
};
- /// Helper function for DWARFDebugLine parse functions, to report issues that
- /// don't prevent parsing the remainder of the table as warnings.
- ///
- /// \param Message The message to report.
- static void warn(StringRef Message);
-
- /// Helper function for DWARFDebugLine parse functions, to report issues that
- /// prevent parsing the remainder of the table as warnings.
+ /// Helper function for DWARFDebugLine parse functions, to report issues
+ /// identified during parsing.
///
/// \param Err The Error to report.
- static void warnForError(Error Err);
+ static void warn(Error Err);
private:
struct ParsingState {
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,
Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
DWARFDataExtractor &DebugLineData, uint32_t Offset, const DWARFContext &Ctx,
- const DWARFUnit *U, std::function<void(StringRef)> WarnCallback) {
+ 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",
LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable()));
LineTable *LT = &Pos.first->second;
if (Pos.second) {
- if (Error Err = LT->parse(DebugLineData, &Offset, Ctx, U, WarnCallback))
+ if (Error Err =
+ LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback))
return std::move(Err);
return LT;
}
Error DWARFDebugLine::LineTable::parse(
DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
const DWARFContext &Ctx, const DWARFUnit *U,
- std::function<void(StringRef)> WarnCallback, raw_ostream *OS) {
+ std::function<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
const uint32_t DebugLineOffset = *OffsetPtr;
clear();
}
if (!State.Sequence.Empty)
- WarnCallback("last sequence in debug line table is not terminated!");
+ RecoverableErrorCallback(
+ createError("last sequence in debug line table is not terminated!"));
// Sort all sequences so that address lookup will work faster.
if (!Sequences.empty()) {
}
DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext(
- function_ref<void(StringRef)> StringCallback,
- function_ref<void(Error)> ErrorCallback, raw_ostream *OS) {
+ 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;
- Error Err = LT.parse(DebugLineData, &Offset, Context, U, StringCallback, OS);
- ErrorCallback(std::move(Err));
+ if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
+ RecoverableErrorCallback, OS))
+ UnrecoverableErrorCallback(std::move(Err));
moveToNextTable(OldOffset, LT.Prologue);
return LT;
}
DWARFUnit *U = prepareToParse(Offset);
uint32_t OldOffset = Offset;
LineTable LT;
- Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U);
- ErrorCallback(std::move(Err));
+ if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U))
+ ErrorCallback(std::move(Err));
moveToNextTable(OldOffset, LT.Prologue);
}
}
}
-void DWARFDebugLine::warn(StringRef Message) {
- WithColor::warning() << Message << '\n';
-}
-
-void DWARFDebugLine::warnForError(Error Err) {
- handleAllErrors(std::move(Err),
- [](ErrorInfoBase &Info) { warn(Info.message()); });
+void DWARFDebugLine::warn(Error Err) {
+ handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) {
+ WithColor::warning() << Info.message() << '\n';
+ });
}
namespace {
struct CommonFixture {
CommonFixture()
- : LineData("", true, 0),
- RecordIssue(std::bind(&CommonFixture::recordIssue, this,
- std::placeholders::_1)),
- FoundError(Error::success()),
- RecordError(std::bind(&CommonFixture::recordError, this,
- std::placeholders::_1)){};
-
- ~CommonFixture() { EXPECT_FALSE(FoundError); }
+ : LineData("", true, 0), Recoverable(Error::success()),
+ RecordRecoverable(std::bind(&CommonFixture::recordRecoverable, this,
+ std::placeholders::_1)),
+ Unrecoverable(Error::success()),
+ RecordUnrecoverable(std::bind(&CommonFixture::recordUnrecoverable, this,
+ std::placeholders::_1)){};
+
+ ~CommonFixture() {
+ EXPECT_FALSE(Recoverable);
+ EXPECT_FALSE(Unrecoverable);
+ }
bool setupGenerator(uint16_t Version = 4) {
Triple T = getHostTripleForAddrSize(8);
return DWARFDebugLine::SectionParser(LineData, *Context, CUs, TUs);
}
- void recordIssue(StringRef Message) { IssueMessage = Message; }
- void recordError(Error Err) {
- FoundError = joinErrors(std::move(FoundError), std::move(Err));
+ void recordRecoverable(Error Err) {
+ Recoverable = joinErrors(std::move(Recoverable), std::move(Err));
+ }
+ void recordUnrecoverable(Error Err) {
+ Unrecoverable = joinErrors(std::move(Unrecoverable), std::move(Err));
}
void checkError(ArrayRef<StringRef> ExpectedMsgs, Error Err) {
void checkGetOrParseLineTableEmitsError(StringRef ExpectedMsg,
uint64_t Offset = 0) {
auto ExpectedLineTable = Line.getOrParseLineTable(
- LineData, Offset, *Context, nullptr, RecordIssue);
+ LineData, Offset, *Context, nullptr, RecordRecoverable);
EXPECT_FALSE(ExpectedLineTable);
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
checkError(ExpectedMsg, ExpectedLineTable.takeError());
}
std::unique_ptr<DWARFContext> Context;
DWARFDataExtractor LineData;
DWARFDebugLine Line;
- std::string IssueMessage;
- std::function<void(StringRef)> RecordIssue;
- Error FoundError;
- std::function<void(Error)> RecordError;
+ Error Recoverable;
+ std::function<void(Error)> RecordRecoverable;
+ Error Unrecoverable;
+ std::function<void(Error)> RecordUnrecoverable;
SmallVector<std::unique_ptr<DWARFCompileUnit>, 2> CUs;
std::deque<DWARFUnitSection<DWARFTypeUnit>> TUs;
generate();
- auto ExpectedLineTable =
- Line.getOrParseLineTable(LineData, 0, *Context, nullptr, RecordIssue);
+ auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
+ nullptr, RecordRecoverable);
ASSERT_TRUE(ExpectedLineTable.operator bool());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected = *ExpectedLineTable;
checkDefaultPrologue(Version, Format, Expected->Prologue, 16);
EXPECT_EQ(Expected->Sequences.size(), 1u);
uint64_t SecondOffset =
Expected->Prologue.sizeofTotalLength() + Expected->Prologue.TotalLength;
- IssueMessage.clear();
+ Recoverable = Error::success();
auto ExpectedLineTable2 = Line.getOrParseLineTable(
- LineData, SecondOffset, *Context, nullptr, RecordIssue);
+ LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE(ExpectedLineTable2.operator bool());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
const DWARFDebugLine::LineTable *Expected2 = *ExpectedLineTable2;
checkDefaultPrologue(Version, Format, Expected2->Prologue, 32);
EXPECT_EQ(Expected2->Sequences.size(), 2u);
// Check that if the same offset is requested, the exact same pointer is
// returned.
- IssueMessage.clear();
- auto ExpectedLineTable3 =
- Line.getOrParseLineTable(LineData, 0, *Context, nullptr, RecordIssue);
+ Recoverable = Error::success();
+ auto ExpectedLineTable3 = Line.getOrParseLineTable(
+ LineData, 0, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE(ExpectedLineTable3.operator bool());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
EXPECT_EQ(Expected, *ExpectedLineTable3);
- IssueMessage.clear();
+ Recoverable = Error::success();
auto ExpectedLineTable4 = Line.getOrParseLineTable(
- LineData, SecondOffset, *Context, nullptr, RecordIssue);
+ LineData, SecondOffset, *Context, nullptr, RecordRecoverable);
ASSERT_TRUE(ExpectedLineTable4.operator bool());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
EXPECT_EQ(Expected2, *ExpectedLineTable4);
// TODO: Add tests that show that the body of the programs have been read
2, DWARF32), // Test lower-bound of v2-3 fields and DWARF32.
std::make_pair(3, DWARF32), // Test upper-bound of v2-3 fields.
std::make_pair(4, DWARF64), // Test v4 fields and DWARF64.
- std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)),);
+ std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)), );
TEST_F(DebugLineBasicFixture, ErrorForInvalidExtendedOpcodeLength) {
if (!setupGenerator())
generate();
- auto ExpectedLineTable =
- Line.getOrParseLineTable(LineData, 0, *Context, nullptr, RecordIssue);
- EXPECT_EQ(IssueMessage,
- "last sequence in debug line table is not terminated!");
+ auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
+ nullptr, RecordRecoverable);
+ checkError("last sequence in debug line table is not terminated!",
+ std::move(Recoverable));
ASSERT_TRUE(ExpectedLineTable.operator bool());
EXPECT_EQ((*ExpectedLineTable)->Rows.size(), 6u);
// The unterminated sequence is not added to the sequence list.
EXPECT_EQ(Parser.getOffset(), 0u);
ASSERT_FALSE(Parser.done());
- DWARFDebugLine::LineTable Parsed = Parser.parseNext(RecordIssue, RecordError);
+ DWARFDebugLine::LineTable Parsed =
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
checkDefaultPrologue(4, DWARF32, Parsed.Prologue, 16);
EXPECT_EQ(Parsed.Sequences.size(), 1u);
EXPECT_EQ(Parser.getOffset(), 62u);
ASSERT_FALSE(Parser.done());
DWARFDebugLine::LineTable Parsed2 =
- Parser.parseNext(RecordIssue, RecordError);
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
checkDefaultPrologue(4, DWARF64, Parsed2.Prologue, 16);
EXPECT_EQ(Parsed2.Sequences.size(), 1u);
EXPECT_EQ(Parser.getOffset(), 136u);
EXPECT_TRUE(Parser.done());
- EXPECT_TRUE(IssueMessage.empty());
- EXPECT_FALSE(FoundError);
+ EXPECT_FALSE(Recoverable);
+ EXPECT_FALSE(Unrecoverable);
}
TEST_F(DebugLineBasicFixture, ParserSkipsCorrectly) {
EXPECT_EQ(Parser.getOffset(), 0u);
ASSERT_FALSE(Parser.done());
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
EXPECT_EQ(Parser.getOffset(), 62u);
ASSERT_FALSE(Parser.done());
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
EXPECT_EQ(Parser.getOffset(), 136u);
EXPECT_TRUE(Parser.done());
- EXPECT_FALSE(FoundError);
+ EXPECT_FALSE(Unrecoverable);
}
TEST_F(DebugLineBasicFixture, ParserAlwaysDoneForEmptySection) {
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.parseNext(RecordIssue, RecordError);
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
EXPECT_EQ(Parser.getOffset(), 4u);
EXPECT_TRUE(Parser.done());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
checkError("parsing line table prologue at offset 0x00000000 unsupported "
"reserved unit length found of value 0xffffff00",
- std::move(FoundError));
+ std::move(Unrecoverable));
}
TEST_F(DebugLineBasicFixture, ParserMovesToEndForBadLengthWhenSkipping) {
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
EXPECT_EQ(Parser.getOffset(), 4u);
EXPECT_TRUE(Parser.done());
checkError("parsing line table prologue at offset 0x00000000 unsupported "
"reserved unit length found of value 0xffffff00",
- std::move(FoundError));
+ std::move(Unrecoverable));
}
TEST_F(DebugLineBasicFixture, ParserReportsFirstErrorInEachTableWhenParsing) {
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.parseNext(RecordIssue, RecordError);
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
ASSERT_FALSE(Parser.done());
- Parser.parseNext(RecordIssue, RecordError);
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
EXPECT_TRUE(Parser.done());
- EXPECT_TRUE(IssueMessage.empty());
+ EXPECT_FALSE(Recoverable);
checkError({"parsing line table prologue at offset 0x00000000 found "
"unsupported version 0x00",
"parsing line table prologue at offset 0x00000006 found "
"unsupported version 0x01"},
- std::move(FoundError));
+ std::move(Unrecoverable));
}
TEST_F(DebugLineBasicFixture, ParserReportsNonPrologueProblemsWhenParsing) {
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.parseNext(RecordIssue, RecordError);
- EXPECT_TRUE(IssueMessage.empty());
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
+ EXPECT_FALSE(Recoverable);
ASSERT_FALSE(Parser.done());
checkError(
"unexpected line op length at offset 0x00000030 expected 0x42 found 0x01",
- std::move(FoundError));
+ std::move(Unrecoverable));
// Reset the error state so that it does not confuse the next set of checks.
- FoundError = Error::success();
- Parser.parseNext(RecordIssue, RecordError);
+ Unrecoverable = Error::success();
+ Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
EXPECT_TRUE(Parser.done());
- EXPECT_EQ(IssueMessage,
- "last sequence in debug line table is not terminated!");
- EXPECT_TRUE(!FoundError);
+ checkError("last sequence in debug line table is not terminated!",
+ std::move(Recoverable));
+ EXPECT_FALSE(Unrecoverable);
}
TEST_F(DebugLineBasicFixture,
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
ASSERT_FALSE(Parser.done());
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
EXPECT_TRUE(Parser.done());
"unsupported version 0x00",
"parsing line table prologue at offset 0x00000006 found "
"unsupported version 0x01"},
- std::move(FoundError));
+ std::move(Unrecoverable));
}
TEST_F(DebugLineBasicFixture, ParserIgnoresNonPrologueErrorsWhenSkipping) {
generate();
DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
- Parser.skip(RecordError);
+ Parser.skip(RecordUnrecoverable);
EXPECT_TRUE(Parser.done());
- EXPECT_TRUE(!FoundError);
+ EXPECT_FALSE(Unrecoverable);
}
} // end anonymous namespace