From 9837f54843df864092be162823c6cdd0607dced0 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Tue, 9 Apr 2019 08:05:11 +0000 Subject: [PATCH] Breakpad: Parse Stack CFI records Summary: This patch adds support for parsing STACK CFI records from breakpad files. The expressions specifying the values of registers are not parsed.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. Reviewers: clayborg, amccarth, markmentovai Subscribers: aprantl, lldb-commits Differential Revision: https://reviews.llvm.org/D60268 llvm-svn: 357975 --- lldb/lit/Modules/Breakpad/sections.test | 2 +- .../ObjectFile/Breakpad/BreakpadRecords.cpp | 54 ++++++++++++++++++++-- .../Plugins/ObjectFile/Breakpad/BreakpadRecords.h | 18 +++++++- .../ObjectFile/Breakpad/ObjectFileBreakpad.cpp | 3 -- .../ObjectFile/Breakpad/BreakpadRecordsTest.cpp | 24 +++++++++- 5 files changed, 91 insertions(+), 10 deletions(-) diff --git a/lldb/lit/Modules/Breakpad/sections.test b/lldb/lit/Modules/Breakpad/sections.test index cbb0330..90f3d92 100644 --- a/lldb/lit/Modules/Breakpad/sections.test +++ b/lldb/lit/Modules/Breakpad/sections.test @@ -73,7 +73,7 @@ CHECK-NEXT: ) 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 diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index 6807563..d5b87e3 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -143,8 +143,7 @@ llvm::Optional Record::classify(llvm::StringRef Line) { Tok = consume(Line); switch (Tok) { case Token::CFI: - Tok = consume(Line); - return Tok == Token::Init ? Record::StackCFIInit : Record::StackCFI; + return Record::StackCFI; default: return llvm::None; } @@ -359,6 +358,55 @@ llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS, R.Name); } +llvm::Optional 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(Line) != Token::Stack) + return llvm::None; + if (consume(Line) != Token::CFI) + return llvm::None; + + llvm::StringRef Str; + std::tie(Str, Line) = getToken(Line); + + bool IsInitRecord = stringTo(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 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: @@ -373,8 +421,6 @@ llvm::StringRef breakpad::toString(Record::Kind K) { return "LINE"; case Record::Public: return "PUBLIC"; - case Record::StackCFIInit: - return "STACK CFI INIT"; case Record::StackCFI: return "STACK CFI"; } diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h index e80cc22..5d5cdb3 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h @@ -20,7 +20,7 @@ namespace breakpad { 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 @@ -141,6 +141,22 @@ public: 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 parse(llvm::StringRef Line); + StackCFIRecord(lldb::addr_t Address, llvm::Optional Size, + llvm::StringRef UnwindRules) + : Record(StackCFI), Address(Address), Size(Size), + UnwindRules(UnwindRules) {} + + lldb::addr_t Address; + llvm::Optional 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 diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp index e68d80c..60dd9f9 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -153,9 +153,6 @@ void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { // 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; diff --git a/lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp b/lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp index ad0b7d3..a25a707 100644 --- a/lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp +++ b/lldb/unittests/ObjectFile/Breakpad/BreakpadRecordsTest.cpp @@ -19,7 +19,6 @@ TEST(Record, classify) { 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. @@ -97,3 +96,26 @@ TEST(PublicRecord, parse) { 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")); +} -- 2.7.4