This revision was automatically updated to reflect the committed changes.
Closed by commit rLLDB360574: Breakpad: Generate unwind plans from STACK CFI 
records (authored by labath, committed by ).
Herald added a subscriber: abidh.
Herald added a project: LLDB.

Changed prior to commit:
  https://reviews.llvm.org/D61733?vs=198993&id=199246#toc

Repository:
  rLLDB LLDB

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61733/new/

https://reviews.llvm.org/D61733

Files:
  lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.syms
  lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.yaml
  lit/SymbolFile/Breakpad/stack-cfi-parsing.test
  source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
  source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h

Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
===================================================================
--- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -15,9 +15,11 @@
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/PostfixExpression.h"
 #include "lldb/Symbol/SymbolVendor.h"
 #include "lldb/Symbol/TypeMap.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
 #include "llvm/ADT/StringExtras.h"
 
 using namespace lldb;
@@ -370,6 +372,155 @@
   symtab.CalculateSymbolSizes();
 }
 
+static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+GetRule(llvm::StringRef &unwind_rules) {
+  // Unwind rules are of the form
+  //   register1: expression1 register2: expression2 ...
+  // We assume none of the tokens in expression<n> end with a colon.
+
+  llvm::StringRef lhs, rest;
+  std::tie(lhs, rest) = getToken(unwind_rules);
+  if (!lhs.consume_back(":"))
+    return llvm::None;
+
+  // Seek forward to the next register: expression pair
+  llvm::StringRef::size_type pos = rest.find(": ");
+  if (pos == llvm::StringRef::npos) {
+    // No pair found, this means the rest of the string is a single expression.
+    unwind_rules = llvm::StringRef();
+    return std::make_pair(lhs, rest);
+  }
+
+  // Go back one token to find the end of the current rule.
+  pos = rest.rfind(' ', pos);
+  if (pos == llvm::StringRef::npos)
+    return llvm::None;
+
+  llvm::StringRef rhs = rest.take_front(pos);
+  unwind_rules = rest.drop_front(pos);
+  return std::make_pair(lhs, rhs);
+}
+
+static const RegisterInfo *
+ResolveRegister(const SymbolFile::RegisterInfoResolver &resolver,
+                llvm::StringRef name) {
+  if (name.consume_front("$"))
+    return resolver.ResolveName(name);
+
+  return nullptr;
+}
+
+static const RegisterInfo *
+ResolveRegisterOrRA(const SymbolFile::RegisterInfoResolver &resolver,
+                    llvm::StringRef name) {
+  if (name == ".ra")
+    return resolver.ResolveNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+  return ResolveRegister(resolver, name);
+}
+
+bool SymbolFileBreakpad::ParseUnwindRow(llvm::StringRef unwind_rules,
+                                        const RegisterInfoResolver &resolver,
+                                        UnwindPlan::Row &row) {
+  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
+
+  llvm::BumpPtrAllocator node_alloc;
+  while (auto rule = GetRule(unwind_rules)) {
+    node_alloc.Reset();
+    llvm::StringRef lhs = rule->first;
+    postfix::Node *rhs = postfix::Parse(rule->second, node_alloc);
+    if (!rhs) {
+      LLDB_LOG(log, "Could not parse `{0}` as unwind rhs.", rule->second);
+      return false;
+    }
+
+    bool success = postfix::ResolveSymbols(
+        rhs, [&](postfix::SymbolNode &symbol) -> postfix::Node * {
+          llvm::StringRef name = symbol.GetName();
+          if (name == ".cfa" && lhs != ".cfa")
+            return postfix::MakeNode<postfix::InitialValueNode>(node_alloc);
+
+          if (const RegisterInfo *info = ResolveRegister(resolver, name)) {
+            return postfix::MakeNode<postfix::RegisterNode>(
+                node_alloc, info->kinds[eRegisterKindLLDB]);
+          }
+          return nullptr;
+        });
+
+    if (!success) {
+      LLDB_LOG(log, "Resolving symbols in `{0}` failed.", rule->second);
+      return false;
+    }
+
+    ArchSpec arch = m_obj_file->GetArchitecture();
+    StreamString dwarf(Stream::eBinary, arch.GetAddressByteSize(),
+                       arch.GetByteOrder());
+    ToDWARF(*rhs, dwarf);
+    uint8_t *saved = m_allocator.Allocate<uint8_t>(dwarf.GetSize());
+    std::memcpy(saved, dwarf.GetData(), dwarf.GetSize());
+
+    if (lhs == ".cfa") {
+      row.GetCFAValue().SetIsDWARFExpression(saved, dwarf.GetSize());
+    } else if (const RegisterInfo *info = ResolveRegisterOrRA(resolver, lhs)) {
+      UnwindPlan::Row::RegisterLocation loc;
+      loc.SetIsDWARFExpression(saved, dwarf.GetSize());
+      row.SetRegisterInfo(info->kinds[eRegisterKindLLDB], loc);
+    } else
+      LLDB_LOG(log, "Invalid register `{0}` in unwind rule.", lhs);
+  }
+  if (unwind_rules.empty())
+    return true;
+
+  LLDB_LOG(log, "Could not parse `{0}` as an unwind rule.", unwind_rules);
+  return false;
+}
+
+UnwindPlanSP
+SymbolFileBreakpad::GetUnwindPlan(const Address &address,
+                                  const RegisterInfoResolver &resolver) {
+  ParseUnwindData();
+  const UnwindMap::Entry *entry =
+      m_unwind_data->FindEntryThatContains(address.GetFileAddress());
+  if (!entry)
+    return nullptr;
+
+  addr_t base = GetBaseFileAddress();
+  if (base == LLDB_INVALID_ADDRESS)
+    return nullptr;
+
+  LineIterator It(*m_obj_file, Record::StackCFI, entry->data), End(*m_obj_file);
+  llvm::Optional<StackCFIRecord> init_record = StackCFIRecord::parse(*It);
+  assert(init_record.hasValue());
+  assert(init_record->Size.hasValue());
+
+  auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindLLDB);
+  plan_sp->SetSourceName("breakpad STACK CFI");
+  plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+  plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
+  plan_sp->SetPlanValidAddressRange(
+      AddressRange(base + init_record->Address, *init_record->Size,
+                   m_obj_file->GetModule()->GetSectionList()));
+
+  auto row_sp = std::make_shared<UnwindPlan::Row>();
+  row_sp->SetOffset(0);
+  if (!ParseUnwindRow(init_record->UnwindRules, resolver, *row_sp))
+    return nullptr;
+  plan_sp->AppendRow(row_sp);
+  for (++It; It != End; ++It) {
+    llvm::Optional<StackCFIRecord> record = StackCFIRecord::parse(*It);
+    if (!record.hasValue())
+      return nullptr;
+    if (record->Size.hasValue())
+      break;
+
+    row_sp = std::make_shared<UnwindPlan::Row>(*row_sp);
+    row_sp->SetOffset(record->Address - init_record->Address);
+    if (!ParseUnwindRow(record->UnwindRules, resolver, *row_sp))
+      return nullptr;
+    plan_sp->AppendRow(row_sp);
+  }
+  return plan_sp;
+}
+
 SymbolVendor &SymbolFileBreakpad::GetSymbolVendor() {
   return *m_obj_file->GetModule()->GetSymbolVendor();
 }
@@ -476,3 +627,27 @@
     finish_sequence();
   data.support_files = map.translate(cu, *m_files);
 }
+
+void SymbolFileBreakpad::ParseUnwindData() {
+  if (m_unwind_data)
+    return;
+
+  m_unwind_data.emplace();
+  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
+  addr_t base = GetBaseFileAddress();
+  if (base == LLDB_INVALID_ADDRESS) {
+    LLDB_LOG(log, "SymbolFile parsing failed: Unable to fetch the base address "
+                  "of object file.");
+  }
+
+  for (LineIterator It(*m_obj_file, Record::StackCFI), End(*m_obj_file);
+       It != End; ++It) {
+    if (auto record = StackCFIRecord::parse(*It)) {
+      if (record->Size)
+        m_unwind_data->Append(UnwindMap::Entry(
+            base + record->Address, *record->Size, It.GetBookmark()));
+    } else
+      LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", *It);
+  }
+  m_unwind_data->Sort();
+}
Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
===================================================================
--- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -13,6 +13,7 @@
 #include "lldb/Core/FileSpecList.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
 
 namespace lldb_private {
 
@@ -133,6 +134,10 @@
 
   void AddSymbols(Symtab &symtab) override;
 
+  lldb::UnwindPlanSP
+  GetUnwindPlan(const Address &address,
+                const RegisterInfoResolver &resolver) override;
+
   ConstString GetPluginName() override { return GetPluginNameStatic(); }
   uint32_t GetPluginVersion() override { return 1; }
 
@@ -144,6 +149,11 @@
   struct Bookmark {
     uint32_t section;
     size_t offset;
+
+    friend bool operator<(const Bookmark &lhs, const Bookmark &rhs) {
+      return std::tie(lhs.section, lhs.offset) <
+             std::tie(rhs.section, rhs.offset);
+    }
   };
 
   // At iterator class for simplifying algorithms reading data from the breakpad
@@ -177,8 +187,7 @@
       return *this;
     }
     friend bool operator<(const CompUnitData &lhs, const CompUnitData &rhs) {
-      return std::tie(lhs.bookmark.section, lhs.bookmark.offset) <
-             std::tie(rhs.bookmark.section, rhs.bookmark.offset);
+      return lhs.bookmark < rhs.bookmark;
     }
 
     Bookmark bookmark;
@@ -192,11 +201,19 @@
   void ParseFileRecords();
   void ParseCUData();
   void ParseLineTableAndSupportFiles(CompileUnit &cu, CompUnitData &data);
+  void ParseUnwindData();
+  bool ParseUnwindRow(llvm::StringRef unwind_rules,
+                      const RegisterInfoResolver &resolver,
+                      UnwindPlan::Row &row);
 
   using CompUnitMap = RangeDataVector<lldb::addr_t, lldb::addr_t, CompUnitData>;
 
   llvm::Optional<std::vector<FileSpec>> m_files;
   llvm::Optional<CompUnitMap> m_cu_data;
+
+  using UnwindMap = RangeDataVector<lldb::addr_t, lldb::addr_t, Bookmark>;
+  llvm::Optional<UnwindMap> m_unwind_data;
+  llvm::BumpPtrAllocator m_allocator;
 };
 
 } // namespace breakpad
Index: lit/SymbolFile/Breakpad/stack-cfi-parsing.test
===================================================================
--- lit/SymbolFile/Breakpad/stack-cfi-parsing.test
+++ lit/SymbolFile/Breakpad/stack-cfi-parsing.test
@@ -0,0 +1,48 @@
+# RUN: yaml2obj %S/Inputs/stack-cfi-parsing.yaml > %t
+# RUN: %lldb -c %t -o "target symbols add %S/Inputs/stack-cfi-parsing.syms" \
+# RUN:   -s %s -b | FileCheck %s
+
+image show-unwind -n func0
+# CHECK-LABEL: image show-unwind -n func0
+# CHECK:      Symbol file UnwindPlan:
+# CHECK-NEXT: This UnwindPlan originally sourced from breakpad STACK CFI
+# CHECK-NEXT: This UnwindPlan is sourced from the compiler: yes.
+# CHECK-NEXT: This UnwindPlan is valid at all instruction locations: no.
+# CHECK-NEXT: Address range of this UnwindPlan: [stack-cfi-parsing.out..module_image + 0-0x0000000000000002)
+# CHECK-NEXT: row[0]:    0: CFA=DW_OP_breg7 +0 => rbp=DW_OP_breg7 +0 rip=DW_OP_pick 0x00 
+# CHECK-NEXT: row[1]:    1: CFA=DW_OP_breg7 +0 => rbx=DW_OP_breg2 +0 rbp=DW_OP_breg0 +0 rip=DW_OP_pick 0x00 
+
+# The following plans are all (syntactically) invalid for various reasons.
+# Processing those should not cause a crash.
+
+image show-unwind -n func2
+# CHECK-LABEL: image show-unwind -n func2
+# CHECK-NOT: Symbol file
+
+image show-unwind -n func3
+# CHECK-LABEL: image show-unwind -n func3
+# CHECK-NOT: Symbol file
+
+image show-unwind -n func4
+# CHECK-LABEL: image show-unwind -n func4
+# CHECK-NOT: Symbol file
+
+image show-unwind -n func5
+# CHECK-LABEL: image show-unwind -n func5
+# CHECK-NOT: Symbol file
+
+image show-unwind -n func6
+# CHECK-LABEL: image show-unwind -n func6
+# CHECK-NOT: Symbol file
+
+image show-unwind -n func7
+# CHECK-LABEL: image show-unwind -n func7
+# CHECK-NOT: Symbol file
+
+# Finally, try an unwind plan with just a single row
+image show-unwind -n func9
+# CHECK-LABEL: image show-unwind -n func9
+# CHECK: Symbol file UnwindPlan:
+# CHECK: Address range of this UnwindPlan: [stack-cfi-parsing.out..module_image + 9-0x000000000000000a)
+# CHECK: row[0]:    0: CFA=DW_OP_breg6 +0 => rip=DW_OP_breg0 +0
+
Index: lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.syms
===================================================================
--- lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.syms
+++ lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.syms
@@ -0,0 +1,20 @@
+MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 linux.out
+INFO CODE_ID E35C283BC327C28762DB788BF5A4078BE2351448
+FUNC 0 2 0 func0
+FUNC 2 1 0 func2
+FUNC 3 1 0 func3
+FUNC 4 1 0 func4
+FUNC 5 1 0 func5
+FUNC 6 1 0 func6
+FUNC 7 2 0 func7
+FUNC 9 1 0 func9
+STACK CFI INIT 0 2 .cfa: $rsp .ra: .cfa $rbp: $rsp
+STACK CFI 1 $rbp: $rax $rbx: $rcx
+STACK CFI INIT 2 1 $r47: $r42
+STACK CFI INIT 3 1 $rbp:
+STACK CFI INIT 4 1 $rbp
+STACK CFI INIT 5 1 $rbp: $rbx $rsp:
+STACK CFI INIT 6 1 $rbp: $rsp:
+STACK CFI INIT 7 1 .cfa: $rsp
+STACK CFI bogus
+STACK CFI INIT 9 1 .cfa: $rbp .ra: $rax
Index: lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.yaml
===================================================================
--- lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.yaml
+++ lit/SymbolFile/Breakpad/Inputs/stack-cfi-parsing.yaml
@@ -0,0 +1,36 @@
+--- !minidump
+Streams:         
+  - Type:            ThreadList
+    Threads:         
+      - Thread Id:       0x00003E81
+        Context:         DEAD
+        Stack:           
+          Start of Memory Range: 0x00007FFCEB34A000
+          Content:         DEAD
+  - Type:            ModuleList
+    Modules:         
+      - Base of Image:   0x0000000000400000
+        Size of Image:   0x00001000
+        Module Name:     '/tmp/stack-cfi-parsing.out'
+        CodeView Record: 4C457042E35C283BC327C28762DB788BF5A4078BE2351448
+  - Type:            SystemInfo
+    Processor Arch:  AMD64
+    Processor Level: 6
+    Processor Revision: 15876
+    Number of Processors: 40
+    Platform ID:     Linux
+    CSD Version:     'Linux 3.13.0-91-generic'
+    CPU:             
+      Vendor ID:       GenuineIntel
+      Version Info:    0x00000000
+      Feature Info:    0x00000000
+  - Type:            LinuxProcStatus
+    Text:             |
+      Name:	linux-x86_64
+      State:	t (tracing stop)
+      Tgid:	29917
+      Ngid:	0
+      Pid:	29917
+      PPid:	29370
+
+...
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to