This revision was automatically updated to reflect the committed changes.
Closed by commit rL373072: Unwind: Add a stack scanning mechanism to support
win32 unwinding (authored by labath, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
Repository:
rL LLVM
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D66638/new/
https://reviews.llvm.org/D66638
Files:
lldb/trunk/include/lldb/Symbol/SymbolFile.h
lldb/trunk/include/lldb/Symbol/UnwindPlan.h
lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-raSearch.syms
lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml
lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-raSearch.test
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
lldb/trunk/source/Symbol/UnwindPlan.cpp
Index: lldb/trunk/source/Symbol/UnwindPlan.cpp
===================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp
@@ -170,7 +170,8 @@
if (m_type == rhs.m_type) {
switch (m_type) {
case unspecified:
- return true;
+ case isRaSearch:
+ return m_value.ra_search_offset == rhs.m_value.ra_search_offset;
case isRegisterPlusOffset:
return m_value.reg.offset == rhs.m_value.reg.offset;
@@ -205,9 +206,12 @@
llvm::makeArrayRef(m_value.expr.opcodes, m_value.expr.length),
thread);
break;
- default:
+ case unspecified:
s.PutCString("unspecified");
break;
+ case isRaSearch:
+ s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);
+ break;
}
}
Index: lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -135,6 +135,8 @@
void AddSymbols(Symtab &symtab) override;
+ llvm::Expected<lldb::addr_t> GetParameterStackSize(Symbol &symbol) override;
+
lldb::UnwindPlanSP
GetUnwindPlan(const Address &address,
const RegisterInfoResolver &resolver) override;
Index: lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
===================================================================
--- lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ lldb/trunk/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -374,6 +374,20 @@
symtab.CalculateSymbolSizes();
}
+llvm::Expected<lldb::addr_t>
+SymbolFileBreakpad::GetParameterStackSize(Symbol &symbol) {
+ ParseUnwindData();
+ if (auto *entry = m_unwind_data->win.FindEntryThatContains(
+ symbol.GetAddress().GetFileAddress())) {
+ auto record = StackWinRecord::parse(
+ *LineIterator(*m_objfile_sp, Record::StackWin, entry->data));
+ assert(record.hasValue());
+ return record->ParameterSize;
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Parameter size unknown.");
+}
+
static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
GetRule(llvm::StringRef &unwind_rules) {
// Unwind rules are of the form
@@ -585,12 +599,19 @@
// We assume the first value will be the CFA. It is usually called T0, but
// clang will use T1, if it needs to realign the stack.
- if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
- LLDB_LOG(log, "Resolving symbols in `{0}` failed.", record->ProgramString);
- return nullptr;
+ auto *symbol = llvm::dyn_cast<postfix::SymbolNode>(it->second);
+ if (symbol && symbol->GetName() == ".raSearch") {
+ row_sp->GetCFAValue().SetRaSearch(record->LocalSize +
+ record->SavedRegisterSize);
+ } else {
+ if (!postfix::ResolveSymbols(it->second, symbol_resolver)) {
+ LLDB_LOG(log, "Resolving symbols in `{0}` failed.",
+ record->ProgramString);
+ return nullptr;
+ }
+ llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
+ row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
}
- llvm::ArrayRef<uint8_t> saved = SaveAsDWARF(*it->second);
- row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size());
// Replace the node value with InitialValueNode, so that subsequent
// expressions refer to the CFA value instead of recomputing the whole
Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
===================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -201,6 +201,8 @@
bool IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp,
int &valid_pc_offset);
+ lldb::addr_t GetReturnAddressHint(int32_t plan_offset);
+
lldb_private::Thread &m_thread;
///
Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -18,6 +18,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
@@ -1852,12 +1853,66 @@
error.AsCString());
break;
}
+ case UnwindPlan::Row::FAValue::isRaSearch: {
+ Process &process = *m_thread.GetProcess();
+ lldb::addr_t return_address_hint = GetReturnAddressHint(fa.GetOffset());
+ if (return_address_hint == LLDB_INVALID_ADDRESS)
+ return false;
+ const unsigned max_iterations = 256;
+ for (unsigned i = 0; i < max_iterations; ++i) {
+ Status st;
+ lldb::addr_t candidate_addr =
+ return_address_hint + i * process.GetAddressByteSize();
+ lldb::addr_t candidate =
+ process.ReadPointerFromMemory(candidate_addr, st);
+ if (st.Fail()) {
+ UnwindLogMsg("Cannot read memory at 0x%" PRIx64 ": %s", candidate_addr,
+ st.AsCString());
+ return false;
+ }
+ Address addr;
+ uint32_t permissions;
+ if (process.GetLoadAddressPermissions(candidate, permissions) &&
+ permissions & lldb::ePermissionsExecutable) {
+ address = candidate_addr;
+ UnwindLogMsg("Heuristically found CFA: 0x%" PRIx64, address);
+ return true;
+ }
+ }
+ UnwindLogMsg("No suitable CFA found");
+ break;
+ }
default:
return false;
}
return false;
}
+lldb::addr_t RegisterContextLLDB::GetReturnAddressHint(int32_t plan_offset) {
+ addr_t hint;
+ if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, hint))
+ return LLDB_INVALID_ADDRESS;
+ if (!m_sym_ctx.module_sp || !m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+
+ hint += plan_offset;
+
+ if (auto next = GetNextFrame()) {
+ if (!next->m_sym_ctx.module_sp || !next->m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+ if (auto expected_size =
+ next->m_sym_ctx.module_sp->GetSymbolFile()->GetParameterStackSize(
+ *next->m_sym_ctx.symbol))
+ hint += *expected_size;
+ else {
+ UnwindLogMsgVerbose("Could not retrieve parameter size: %s",
+ llvm::toString(expected_size.takeError()).c_str());
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ return hint;
+}
+
// Retrieve a general purpose register value for THIS frame, as saved by the
// NEXT frame, i.e. the frame that
// this frame called. e.g.
Index: lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-raSearch.test
===================================================================
--- lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-raSearch.test
+++ lldb/trunk/lit/SymbolFile/Breakpad/unwind-via-raSearch.test
@@ -0,0 +1,43 @@
+# RUN: yaml2obj %S/Inputs/unwind-via-stack-win.yaml > %t
+# RUN: %lldb -c %t \
+# RUN: -o "target symbols add %S/Inputs/unwind-via-raSearch.syms" \
+# RUN: -s %s -b | FileCheck %s
+
+# First check that unwind plan generation works correctly.
+# This function has a "typical" unwind rule.
+image show-unwind -n call_many
+# CHECK-LABEL: image show-unwind -n call_many
+# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`call_many
+# CHECK: Symbol file UnwindPlan:
+# CHECK: This UnwindPlan originally sourced from breakpad STACK WIN
+# CHECK: This UnwindPlan is sourced from the compiler: yes.
+# CHECK: This UnwindPlan is valid at all instruction locations: no.
+# CHECK: Address range of this UnwindPlan: [unwind-via-stack-win.exe..module_image + 16-0x0000007d)
+# CHECK: row[0]: 0: CFA=RaSearch@SP+0 => esp=DW_OP_pick 0x00, DW_OP_consts +4, DW_OP_plus eip=DW_OP_pick 0x00, DW_OP_deref
+
+image show-unwind -n nonzero_frame_size
+# CHECK-LABEL: image show-unwind -n nonzero_frame_size
+# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`nonzero_frame_size
+# CHECK: Symbol file UnwindPlan:
+# CHECK: row[0]: 0: CFA=RaSearch@SP+12 => esp=DW_OP_pick 0x00, DW_OP_consts +4, DW_OP_plus eip=DW_OP_pick 0x00, DW_OP_deref
+
+# Then, some invalid rules.
+image show-unwind -n complex_rasearch
+# CHECK-LABEL: image show-unwind -n complex_rasearch
+# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`complex_rasearch
+# CHECK-NOT: Symbol file
+
+image show-unwind -n esp_rasearch
+# CHECK-LABEL: image show-unwind -n esp_rasearch
+# CHECK: UNWIND PLANS for unwind-via-stack-win.exe`esp_rasearch
+# CHECK-NOT: Symbol file
+
+# And finally, check that backtracing works as a whole by unwinding a simple
+# stack.
+thread backtrace
+# CHECK-LABEL: thread backtrace
+# CHECK: frame #0: 0x000b1092 unwind-via-stack-win.exe`many_pointer_args
+# CHECK: frame #1: 0x000b1079 unwind-via-stack-win.exe`call_many + 105
+# CHECK: frame #2: 0x000b1085 unwind-via-stack-win.exe`main + 5
+# CHECK: frame #3: 0x77278494 kernel32.dll
+# CHECK-NOT: frame
Index: lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-raSearch.syms
===================================================================
--- lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-raSearch.syms
+++ lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-raSearch.syms
@@ -0,0 +1,15 @@
+MODULE windows x86 897DD83EA8C8411897F3A925EE4BF7411 unwind-via-stack-win.pdb
+INFO CODE_ID 5D499B5C5000 unwind-via-stack-win.exe
+PUBLIC 0 0 dummy
+PUBLIC 10 0 call_many
+PUBLIC 80 0 main
+PUBLIC 90 0 many_pointer_args
+PUBLIC 100 0 complex_rasearch
+PUBLIC 110 0 esp_rasearch
+PUBLIC 120 0 nonzero_frame_size
+STACK WIN 4 10 6d 0 0 0 0 0 0 1 $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+STACK WIN 4 80 8 0 0 0 0 0 0 1 $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+STACK WIN 4 90 5 0 0 50 0 0 0 1 $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+STACK WIN 4 100 4 0 0 0 0 0 0 1 $T0 .raSearch 80 + = $eip $T0 ^ = $esp $T0 4 + =
+STACK WIN 4 110 4 0 0 0 0 0 0 1 $T0 .raSearch = $eip $T0 ^ = $esp .raSearch 4 + =
+STACK WIN 4 120 4 0 0 0 4 8 0 1 $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
Index: lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml
===================================================================
--- lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml
+++ lldb/trunk/lit/SymbolFile/Breakpad/Inputs/unwind-via-stack-win.yaml
@@ -23,6 +23,8 @@
Memory Ranges:
- Start of Memory Range: 0x0000000000CFFE78
Content: 0000000079100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0085100B0094842777
+ - Type: MemoryInfoList
+ Content: 1000000030000000020000000000000000100B00000000000000000000000000000000000000000000400000000000000010000010000000000000010000000000002677000000000000000000000000000000000000000000000E000000000000100000100000000000000100000000
- Type: SystemInfo
Processor Arch: X86
Platform ID: Win32NT
Index: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
===================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h
@@ -201,7 +201,8 @@
unspecified, // not specified
isRegisterPlusOffset, // FA = register + offset
isRegisterDereferenced, // FA = [reg]
- isDWARFExpression // FA = eval(dwarf_expr)
+ isDWARFExpression, // FA = eval(dwarf_expr)
+ isRaSearch, // FA = SP + offset + ???
};
FAValue() : m_type(unspecified), m_value() {}
@@ -214,6 +215,11 @@
bool IsUnspecified() const { return m_type == unspecified; }
+ void SetRaSearch(int32_t offset) {
+ m_type = isRaSearch;
+ m_value.ra_search_offset = offset;
+ }
+
bool IsRegisterPlusOffset() const {
return m_type == isRegisterPlusOffset;
}
@@ -250,9 +256,14 @@
ValueType GetValueType() const { return m_type; }
int32_t GetOffset() const {
- if (m_type == isRegisterPlusOffset)
- return m_value.reg.offset;
- return 0;
+ switch (m_type) {
+ case isRegisterPlusOffset:
+ return m_value.reg.offset;
+ case isRaSearch:
+ return m_value.ra_search_offset;
+ default:
+ return 0;
+ }
}
void IncOffset(int32_t delta) {
@@ -304,6 +315,8 @@
const uint8_t *opcodes;
uint16_t length;
} expr;
+ // For m_type == isRaSearch
+ int32_t ra_search_offset;
} m_value;
}; // class FAValue
Index: lldb/trunk/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/trunk/include/lldb/Symbol/SymbolFile.h
+++ lldb/trunk/include/lldb/Symbol/SymbolFile.h
@@ -19,8 +19,8 @@
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/lldb-private.h"
-
#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Errc.h"
#include <mutex>
@@ -245,6 +245,13 @@
return nullptr;
}
+ /// Return the number of stack bytes taken up by the parameters to this
+ /// function.
+ virtual llvm::Expected<lldb::addr_t> GetParameterStackSize(Symbol &symbol) {
+ return llvm::createStringError(make_error_code(llvm::errc::not_supported),
+ "Operation not supported.");
+ }
+
virtual void Dump(Stream &s);
protected:
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits