labath created this revision. labath added reviewers: clayborg, amccarth, markmentovai. Herald added a subscriber: aprantl.
This patch adds support for parsing STACK CFI records from breakpad files. For the expressions specifying the values of registers, only a basic parse is performed -- the record is split into a bunch of key-value pairs, where both keys and values are strings. The idea is that these will be handed off to the postfix expression -> dwarf compiler, once it is extracted from the internals of the NativePDB plugin https://reviews.llvm.org/D60268 Files: source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp
Index: unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp =================================================================== --- unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp +++ unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp @@ -97,3 +97,36 @@ EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC m")); EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC")); } + +TEST(StackCFIInitRecord, parse) { + EXPECT_EQ(StackCFIInitRecord(0x47, 0x8, + {{".cfa", "$esp 4 +"}, {"$eip", ".cfa 4 - ^"}}), + StackCFIInitRecord::parse( + "STACK CFI INIT 47 8 .cfa: $esp 4 + $eip: .cfa 4 - ^")); + EXPECT_EQ(StackCFIInitRecord(0x47, 0x8, {{".cfa", "$esp 4 +"}}), + StackCFIInitRecord::parse("STACK CFI INIT 47 8 .cfa: $esp 4 +")); + + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse( + "STACK CFI INIT 47 8 .cfa: $esp 4 + $eip:")); + EXPECT_EQ(llvm::None, + StackCFIInitRecord::parse("STACK CFI INIT 47 8 .cfa: $eip: .cfa")); + EXPECT_EQ(llvm::None, + StackCFIInitRecord::parse("STACK CFI INIT 47 8 $esp .cfa: $esp")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK CFI INIT 47 8 .cfa:")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK CFI INIT 47 8")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK CFI INIT 47")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK CFI INIT")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK CFI")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse("STACK")); + EXPECT_EQ(llvm::None, StackCFIInitRecord::parse( + "STACK CFI 47 .cfa: $esp 4 + $eip: .cfa 4 - ^")); +} + +TEST(StackCFIRecord, parse) { + EXPECT_EQ( + StackCFIRecord(0x47, {{".cfa", "$esp 4 +"}, {"$eip", ".cfa 4 - ^"}}), + StackCFIRecord::parse("STACK CFI 47 .cfa: $esp 4 + $eip: .cfa 4 - ^")); + + EXPECT_EQ(llvm::None, + StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: $esp 4 +")); +} Index: source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h =================================================================== --- source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h +++ source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h @@ -11,6 +11,7 @@ #include "lldb/Utility/UUID.h" #include "lldb/lldb-types.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/FormatProviders.h" @@ -141,6 +142,39 @@ bool operator==(const PublicRecord &L, const PublicRecord &R); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PublicRecord &R); +class StackCFIInitRecord : public Record { +public: + static llvm::Optional<StackCFIInitRecord> parse(llvm::StringRef Line); + StackCFIInitRecord( + lldb::addr_t Address, lldb::addr_t Size, + llvm::DenseMap<llvm::StringRef, llvm::StringRef> UnwindRules) + : Record(StackCFIInit), Address(Address), Size(Size), + UnwindRules(std::move(UnwindRules)) {} + + lldb::addr_t Address; + lldb::addr_t Size; + llvm::DenseMap<llvm::StringRef, llvm::StringRef> UnwindRules; +}; + +bool operator==(const StackCFIInitRecord &L, const StackCFIInitRecord &R); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const StackCFIInitRecord &R); + +class StackCFIRecord : public Record { +public: + static llvm::Optional<StackCFIRecord> parse(llvm::StringRef Line); + StackCFIRecord(lldb::addr_t Address, + llvm::DenseMap<llvm::StringRef, llvm::StringRef> UnwindRules) + : Record(StackCFIInit), Address(Address), + UnwindRules(std::move(UnwindRules)) {} + + lldb::addr_t Address; + llvm::DenseMap<llvm::StringRef, 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 Index: source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp =================================================================== --- source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -359,6 +359,120 @@ R.Name); } +static bool +parseStackCFI(llvm::StringRef Line, lldb::addr_t &Address, lldb::addr_t *Size, + llvm::DenseMap<llvm::StringRef, llvm::StringRef> &UnwindRules) { + // 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. + + bool IsInitRecord = Size != nullptr; + + if (consume<Token>(Line) != Token::Stack) + return false; + if (consume<Token>(Line) != Token::CFI) + return false; + if (IsInitRecord && consume<Token>(Line) != Token::Init) + return false; + + llvm::StringRef Str; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, Address, 16)) + return false; + + if (IsInitRecord) { + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, *Size, 16)) + return false; + } + + llvm::StringRef LHS, RHS; + while (std::tie(Str, Line) = getToken(Line), !Str.empty()) { + if (Str.back() == ':') { // regN + // Flush the previous expression, if there is one. + if (!LHS.empty()) { + if (RHS.empty()) + return false; // regN without an exprN + UnwindRules[LHS] = RHS; + } + + LHS = Str.drop_back(); + RHS = llvm::StringRef(); + continue; + } + + if (LHS.empty()) + return false; // exprN without a preceding regN. + + // Append token to RHS. + if (RHS.empty()) + RHS = Str; + else + RHS = llvm::StringRef(RHS.begin(), Str.end() - RHS.begin()); + } + + // Append last rule, if it is valid. + if (RHS.empty()) + return false; + + UnwindRules[LHS] = RHS; + return true; +} + +llvm::Optional<StackCFIInitRecord> +StackCFIInitRecord::parse(llvm::StringRef Line) { + lldb::addr_t Address, Size; + llvm::DenseMap<llvm::StringRef, llvm::StringRef> UnwindRules(8); + if (parseStackCFI(Line, Address, &Size, UnwindRules)) + return StackCFIInitRecord(Address, Size, std::move(UnwindRules)); + + return llvm::None; +} + +bool breakpad::operator==(const StackCFIInitRecord &L, + const StackCFIInitRecord &R) { + return L.Address == R.Address && L.Size == R.Size && + L.UnwindRules == R.UnwindRules; +} + +static void printRules( + llvm::raw_ostream &OS, + const llvm::DenseMap<llvm::StringRef, llvm::StringRef> &UnwindRules) { + llvm::StringRef Sep; + for (const auto &KV : UnwindRules) { + OS << Sep << KV.first << ": " << KV.second; + Sep = " "; + } +} + +llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS, + const StackCFIInitRecord &R) { + OS << llvm::formatv("STACK CFI INIT {0:x-} {1:x-} ", R.Address, R.Size); + printRules(OS, R.UnwindRules); + return OS; +} + +llvm::Optional<StackCFIRecord> StackCFIRecord::parse(llvm::StringRef Line) { + lldb::addr_t Address; + llvm::DenseMap<llvm::StringRef, llvm::StringRef> UnwindRules(8); + if (parseStackCFI(Line, Address, nullptr, UnwindRules)) + return StackCFIRecord(Address, std::move(UnwindRules)); + + return llvm::None; +} + +bool breakpad::operator==(const StackCFIRecord &L, const StackCFIRecord &R) { + return L.Address == R.Address && L.UnwindRules == R.UnwindRules; +} + +llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS, + const StackCFIRecord &R) { + OS << llvm::formatv("STACK CFI {0:x-} ", R.Address); + printRules(OS, R.UnwindRules); + return OS; +} + llvm::StringRef breakpad::toString(Record::Kind K) { switch (K) { case Record::Module:
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits