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

Reply via email to