Skip to content

Commit 0a9f47d

Browse files
committedAug 26, 2019
Breakpad: Add support for parsing STACK WIN records
Summary: The fields that aren't useful for us right now are simply ignored. Reviewers: amccarth, markmentovai Subscribers: rnk, lldb-commits Differential Revision: https://reviews.llvm.org/D66633 llvm-svn: 369892
1 parent 140f06f commit 0a9f47d

File tree

3 files changed

+151
-4
lines changed

3 files changed

+151
-4
lines changed
 

‎lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp

+95-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,19 @@ using namespace lldb_private;
1616
using namespace lldb_private::breakpad;
1717

1818
namespace {
19-
enum class Token { Unknown, Module, Info, CodeID, File, Func, Public, Stack, CFI, Init };
19+
enum class Token {
20+
Unknown,
21+
Module,
22+
Info,
23+
CodeID,
24+
File,
25+
Func,
26+
Public,
27+
Stack,
28+
CFI,
29+
Init,
30+
Win,
31+
};
2032
}
2133

2234
template<typename T>
@@ -33,6 +45,7 @@ template <> Token stringTo<Token>(llvm::StringRef Str) {
3345
.Case("STACK", Token::Stack)
3446
.Case("CFI", Token::CFI)
3547
.Case("INIT", Token::Init)
48+
.Case("WIN", Token::Win)
3649
.Default(Token::Unknown);
3750
}
3851

@@ -127,20 +140,22 @@ llvm::Optional<Record::Kind> Record::classify(llvm::StringRef Line) {
127140
switch (Tok) {
128141
case Token::CFI:
129142
return Record::StackCFI;
143+
case Token::Win:
144+
return Record::StackWin;
130145
default:
131146
return llvm::None;
132147
}
133148

134149
case Token::Unknown:
135150
// Optimistically assume that any unrecognised token means this is a line
136151
// record, those don't have a special keyword and start directly with a
137-
// hex number. CODE_ID should never be at the start of a line, but if it
138-
// is, it can be treated the same way as a garbled line record.
152+
// hex number.
139153
return Record::Line;
140154

141155
case Token::CodeID:
142156
case Token::CFI:
143157
case Token::Init:
158+
case Token::Win:
144159
// These should never appear at the start of a valid record.
145160
return llvm::None;
146161
}
@@ -390,6 +405,81 @@ llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
390405
return OS << " " << R.UnwindRules;
391406
}
392407

408+
llvm::Optional<StackWinRecord> StackWinRecord::parse(llvm::StringRef Line) {
409+
// STACK WIN type rva code_size prologue_size epilogue_size parameter_size
410+
// saved_register_size local_size max_stack_size has_program_string
411+
// program_string_OR_allocates_base_pointer
412+
413+
if (consume<Token>(Line) != Token::Stack)
414+
return llvm::None;
415+
if (consume<Token>(Line) != Token::Win)
416+
return llvm::None;
417+
418+
llvm::StringRef Str;
419+
uint8_t Type;
420+
std::tie(Str, Line) = getToken(Line);
421+
// Right now we only support the "FrameData" frame type.
422+
if (!to_integer(Str, Type) || FrameType(Type) != FrameType::FrameData)
423+
return llvm::None;
424+
425+
lldb::addr_t RVA;
426+
std::tie(Str, Line) = getToken(Line);
427+
if (!to_integer(Str, RVA, 16))
428+
return llvm::None;
429+
430+
lldb::addr_t CodeSize;
431+
std::tie(Str, Line) = getToken(Line);
432+
if (!to_integer(Str, CodeSize, 16))
433+
return llvm::None;
434+
435+
// Skip fields which we aren't using right now.
436+
std::tie(Str, Line) = getToken(Line); // prologue_size
437+
std::tie(Str, Line) = getToken(Line); // epilogue_size
438+
439+
lldb::addr_t ParameterSize;
440+
std::tie(Str, Line) = getToken(Line);
441+
if (!to_integer(Str, ParameterSize, 16))
442+
return llvm::None;
443+
444+
lldb::addr_t SavedRegisterSize;
445+
std::tie(Str, Line) = getToken(Line);
446+
if (!to_integer(Str, SavedRegisterSize, 16))
447+
return llvm::None;
448+
449+
lldb::addr_t LocalSize;
450+
std::tie(Str, Line) = getToken(Line);
451+
if (!to_integer(Str, LocalSize, 16))
452+
return llvm::None;
453+
454+
std::tie(Str, Line) = getToken(Line); // max_stack_size
455+
456+
uint8_t HasProgramString;
457+
std::tie(Str, Line) = getToken(Line);
458+
if (!to_integer(Str, HasProgramString))
459+
return llvm::None;
460+
// FrameData records should always have a program string.
461+
if (!HasProgramString)
462+
return llvm::None;
463+
464+
return StackWinRecord(RVA, CodeSize, ParameterSize, SavedRegisterSize,
465+
LocalSize, Line.trim());
466+
}
467+
468+
bool breakpad::operator==(const StackWinRecord &L, const StackWinRecord &R) {
469+
return L.RVA == R.RVA && L.CodeSize == R.CodeSize &&
470+
L.ParameterSize == R.ParameterSize &&
471+
L.SavedRegisterSize == R.SavedRegisterSize &&
472+
L.LocalSize == R.LocalSize && L.ProgramString == R.ProgramString;
473+
}
474+
475+
llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
476+
const StackWinRecord &R) {
477+
return OS << llvm::formatv(
478+
"STACK WIN 4 {0:x-} {1:x-} ? ? {2} {3} {4} ? 1 {5}", R.RVA,
479+
R.CodeSize, R.ParameterSize, R.SavedRegisterSize, R.LocalSize,
480+
R.ProgramString);
481+
}
482+
393483
llvm::StringRef breakpad::toString(Record::Kind K) {
394484
switch (K) {
395485
case Record::Module:
@@ -406,6 +496,8 @@ llvm::StringRef breakpad::toString(Record::Kind K) {
406496
return "PUBLIC";
407497
case Record::StackCFI:
408498
return "STACK CFI";
499+
case Record::StackWin:
500+
return "STACK WIN";
409501
}
410502
llvm_unreachable("Unknown record kind!");
411503
}

‎lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace breakpad {
2020

2121
class Record {
2222
public:
23-
enum Kind { Module, Info, File, Func, Line, Public, StackCFI };
23+
enum Kind { Module, Info, File, Func, Line, Public, StackCFI, StackWin };
2424

2525
/// Attempt to guess the kind of the record present in the argument without
2626
/// doing a full parse. The returned kind will always be correct for valid
@@ -157,6 +157,29 @@ class StackCFIRecord : public Record {
157157
bool operator==(const StackCFIRecord &L, const StackCFIRecord &R);
158158
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackCFIRecord &R);
159159

160+
class StackWinRecord : public Record {
161+
public:
162+
static llvm::Optional<StackWinRecord> parse(llvm::StringRef Line);
163+
164+
StackWinRecord(lldb::addr_t RVA, lldb::addr_t CodeSize,
165+
lldb::addr_t ParameterSize, lldb::addr_t SavedRegisterSize,
166+
lldb::addr_t LocalSize, llvm::StringRef ProgramString)
167+
: Record(StackWin), RVA(RVA), CodeSize(CodeSize),
168+
ParameterSize(ParameterSize), SavedRegisterSize(SavedRegisterSize),
169+
LocalSize(LocalSize), ProgramString(ProgramString) {}
170+
171+
enum class FrameType : uint8_t { FPO = 0, FrameData = 4 };
172+
lldb::addr_t RVA;
173+
lldb::addr_t CodeSize;
174+
lldb::addr_t ParameterSize;
175+
lldb::addr_t SavedRegisterSize;
176+
lldb::addr_t LocalSize;
177+
llvm::StringRef ProgramString;
178+
};
179+
180+
bool operator==(const StackWinRecord &L, const StackWinRecord &R);
181+
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackWinRecord &R);
182+
160183
} // namespace breakpad
161184
} // namespace lldb_private
162185

‎lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ TEST(Record, classify) {
2020
EXPECT_EQ(Record::Func, Record::classify("FUNC"));
2121
EXPECT_EQ(Record::Public, Record::classify("PUBLIC"));
2222
EXPECT_EQ(Record::StackCFI, Record::classify("STACK CFI"));
23+
EXPECT_EQ(Record::StackWin, Record::classify("STACK WIN"));
2324

2425
// Any obviously incorrect lines will be classified as such.
2526
EXPECT_EQ(llvm::None, Record::classify("STACK"));
@@ -119,3 +120,34 @@ TEST(StackCFIRecord, parse) {
119120
EXPECT_EQ(llvm::None, StackCFIRecord::parse("FILE 47 foo"));
120121
EXPECT_EQ(llvm::None, StackCFIRecord::parse("42 47"));
121122
}
123+
124+
TEST(StackWinRecord, parse) {
125+
EXPECT_EQ(
126+
StackWinRecord(0x47, 0x8, 3, 4, 5, llvm::StringRef("$eip $esp ^ =")),
127+
StackWinRecord::parse("STACK WIN 4 47 8 1 2 3 4 5 6 1 $eip $esp ^ ="));
128+
129+
EXPECT_EQ(llvm::None, StackWinRecord::parse(
130+
"STACK WIN 0 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
131+
EXPECT_EQ(llvm::None,
132+
StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0 0 1"));
133+
EXPECT_EQ(llvm::None, StackWinRecord::parse(
134+
"STACK WIN 3 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
135+
EXPECT_EQ(llvm::None,
136+
StackWinRecord::parse("STACK WIN 3 47 8 1 0 0 0 0 0 0 1"));
137+
EXPECT_EQ(llvm::None, StackWinRecord::parse(
138+
"STACK WIN 4 47 8 1 0 0 0 0 1 $eip $esp ^ ="));
139+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0"));
140+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0"));
141+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0"));
142+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0"));
143+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0"));
144+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1"));
145+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8"));
146+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47"));
147+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4"));
148+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN"));
149+
EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK"));
150+
EXPECT_EQ(llvm::None, StackWinRecord::parse(""));
151+
EXPECT_EQ(llvm::None, StackCFIRecord::parse("FILE 47 foo"));
152+
EXPECT_EQ(llvm::None, StackCFIRecord::parse("42 47"));
153+
}

0 commit comments

Comments
 (0)
Please sign in to comment.