CHECK: Index: 5
CHECK-NEXT: ID: 0x6
-CHECK-NEXT: Name: STACK CFI INIT
+CHECK-NEXT: Name: STACK CFI
CHECK-NEXT: Type: regular
CHECK-NEXT: Permissions: ---
CHECK-NEXT: Thread specific: no
Tok = consume<Token>(Line);
switch (Tok) {
case Token::CFI:
- Tok = consume<Token>(Line);
- return Tok == Token::Init ? Record::StackCFIInit : Record::StackCFI;
+ return Record::StackCFI;
default:
return llvm::None;
}
R.Name);
}
+llvm::Optional<StackCFIRecord> StackCFIRecord::parse(llvm::StringRef Line) {
+ // STACK CFI INIT address size reg1: expr1 reg2: expr2 ...
+ // or
+ // STACK CFI address reg1: expr1 reg2: expr2 ...
+ // No token in exprN ends with a colon.
+
+ if (consume<Token>(Line) != Token::Stack)
+ return llvm::None;
+ if (consume<Token>(Line) != Token::CFI)
+ return llvm::None;
+
+ llvm::StringRef Str;
+ std::tie(Str, Line) = getToken(Line);
+
+ bool IsInitRecord = stringTo<Token>(Str) == Token::Init;
+ if (IsInitRecord)
+ std::tie(Str, Line) = getToken(Line);
+
+ lldb::addr_t Address;
+ if (!to_integer(Str, Address, 16))
+ return llvm::None;
+
+ llvm::Optional<lldb::addr_t> Size;
+ if (IsInitRecord) {
+ Size.emplace();
+ std::tie(Str, Line) = getToken(Line);
+ if (!to_integer(Str, *Size, 16))
+ return llvm::None;
+ }
+
+ return StackCFIRecord(Address, Size, Line.trim());
+}
+
+bool breakpad::operator==(const StackCFIRecord &L, const StackCFIRecord &R) {
+ return L.Address == R.Address && L.Size == R.Size &&
+ L.UnwindRules == R.UnwindRules;
+}
+
+llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS,
+ const StackCFIRecord &R) {
+ OS << "STACK CFI ";
+ if (R.Size)
+ OS << "INIT ";
+ OS << llvm::formatv("{0:x-} ", R.Address);
+ if (R.Size)
+ OS << llvm::formatv("{0:x-} ", *R.Size);
+ return OS << " " << R.UnwindRules;
+}
+
llvm::StringRef breakpad::toString(Record::Kind K) {
switch (K) {
case Record::Module:
return "LINE";
case Record::Public:
return "PUBLIC";
- case Record::StackCFIInit:
- return "STACK CFI INIT";
case Record::StackCFI:
return "STACK CFI";
}
class Record {
public:
- enum Kind { Module, Info, File, Func, Line, Public, StackCFIInit, StackCFI };
+ enum Kind { Module, Info, File, Func, Line, Public, StackCFI };
/// Attempt to guess the kind of the record present in the argument without
/// doing a full parse. The returned kind will always be correct for valid
bool operator==(const PublicRecord &L, const PublicRecord &R);
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PublicRecord &R);
+class StackCFIRecord : public Record {
+public:
+ static llvm::Optional<StackCFIRecord> parse(llvm::StringRef Line);
+ StackCFIRecord(lldb::addr_t Address, llvm::Optional<lldb::addr_t> Size,
+ llvm::StringRef UnwindRules)
+ : Record(StackCFI), Address(Address), Size(Size),
+ UnwindRules(UnwindRules) {}
+
+ lldb::addr_t Address;
+ llvm::Optional<lldb::addr_t> Size;
+ llvm::StringRef UnwindRules;
+};
+
+bool operator==(const StackCFIRecord &L, const StackCFIRecord &R);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackCFIRecord &R);
+
} // namespace breakpad
} // namespace lldb_private
// Line records logically belong to the preceding Func record, so we put
// them in the same section.
next_section = Record::Func;
- } else if (next_section == Record::StackCFI) {
- // Same goes for StackCFI and StackCFIInit
- next_section = Record::StackCFIInit;
}
if (next_section == current_section)
continue;
EXPECT_EQ(Record::File, Record::classify("FILE"));
EXPECT_EQ(Record::Func, Record::classify("FUNC"));
EXPECT_EQ(Record::Public, Record::classify("PUBLIC"));
- EXPECT_EQ(Record::StackCFIInit, Record::classify("STACK CFI INIT"));
EXPECT_EQ(Record::StackCFI, Record::classify("STACK CFI"));
// Any obviously incorrect lines will be classified as such.
EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC m"));
EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC"));
}
+
+TEST(StackCFIRecord, parse) {
+ EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 + $eip: .cfa 4 - ^"),
+ StackCFIRecord::parse(
+ "STACK CFI INIT 47 8 .cfa: $esp 4 + $eip: .cfa 4 - ^"));
+
+ EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 +"),
+ StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: $esp 4 + "));
+
+ EXPECT_EQ(StackCFIRecord(0x47, llvm::None, ".cfa: $esp 4 +"),
+ StackCFIRecord::parse("STACK CFI 47 .cfa: $esp 4 +"));
+
+ // The validity of the register value expressions is not checked
+ EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: ^ ^ ^"),
+ StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: ^ ^ ^"));
+
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI INIT 47"));
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI INIT"));
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI"));
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK"));
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("FILE 47 foo"));
+ EXPECT_EQ(llvm::None, StackCFIRecord::parse("42 47"));
+}