Index: include/lldb/Symbol/SymbolFile.h =================================================================== --- include/lldb/Symbol/SymbolFile.h +++ 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 @@ -242,6 +242,16 @@ return nullptr; } + virtual llvm::Expected GetParameterSize(Symbol &symbol) { + return llvm::createStringError(make_error_code(llvm::errc::not_supported), + "Operation not supported."); + } + + virtual llvm::Expected GetOwnFrameSize(Symbol &symbol) { + return llvm::createStringError(make_error_code(llvm::errc::not_supported), + "Operation not supported."); + } + virtual void Dump(Stream &s); protected: Index: include/lldb/Symbol/UnwindPlan.h =================================================================== --- include/lldb/Symbol/UnwindPlan.h +++ 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) + isFoundHeuristically, // FA = ??? }; FAValue() : m_type(unspecified), m_value() {} @@ -214,6 +215,8 @@ bool IsUnspecified() const { return m_type == unspecified; } + void SetFoundHeuristically() { m_type = isFoundHeuristically; } + bool IsRegisterPlusOffset() const { return m_type == isRegisterPlusOffset; } Index: source/Plugins/Process/Utility/RegisterContextLLDB.h =================================================================== --- source/Plugins/Process/Utility/RegisterContextLLDB.h +++ 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(); + lldb_private::Thread &m_thread; /// Index: source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ 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,73 @@ error.AsCString()); break; } + case UnwindPlan::Row::FAValue::isFoundHeuristically: { + Process &process = *m_thread.GetProcess(); + lldb::addr_t return_address_hint = GetReturnAddressHint(); + if (return_address_hint == LLDB_INVALID_ADDRESS) + return false; + const unsigned max_iterations = 100; + 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; + if (addr.SetLoadAddress(candidate, &process.GetTarget()) && + addr.GetSection()->GetPermissions() & 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() { + 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; + + if (auto expected_size = + m_sym_ctx.module_sp->GetSymbolFile()->GetOwnFrameSize( + *m_sym_ctx.symbol)) + hint += *expected_size; + else { + UnwindLogMsgVerbose("Could not retrieve own frame size: %s", + llvm::toString(expected_size.takeError()).c_str()); + return LLDB_INVALID_ADDRESS; + } + + 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()->GetParameterSize( + *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: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h =================================================================== --- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -135,6 +135,9 @@ void AddSymbols(Symtab &symtab) override; + llvm::Expected GetParameterSize(Symbol &symbol) override; + llvm::Expected GetOwnFrameSize(Symbol &symbol) override; + lldb::UnwindPlanSP GetUnwindPlan(const Address &address, const RegisterInfoResolver &resolver) override; Index: source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp =================================================================== --- source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -374,6 +374,33 @@ symtab.CalculateSymbolSizes(); } +llvm::Expected SymbolFileBreakpad::GetParameterSize(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."); +} + +llvm::Expected SymbolFileBreakpad::GetOwnFrameSize(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->LocalSize + record->SavedRegisterSize; + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Own frame size unknown."); +} + + static llvm::Optional> GetRule(llvm::StringRef &unwind_rules) { // Unwind rules are of the form @@ -584,12 +611,18 @@ // We assume the first value will be the CFA. It is usually called T0, but // clang will use T1, if it needs to realing 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(it->second); + if (symbol && symbol->GetName() == ".raSearch") { + row_sp->GetCFAValue().SetFoundHeuristically(); + } else { + if (!postfix::ResolveSymbols(it->second, symbol_resolver)) { + LLDB_LOG(log, "Resolving symbols in `{0}` failed.", + record->ProgramString); + return nullptr; + } + llvm::ArrayRef saved = SaveAsDWARF(*it->second); + row_sp->GetCFAValue().SetIsDWARFExpression(saved.data(), saved.size()); } - llvm::ArrayRef 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: source/Symbol/UnwindPlan.cpp =================================================================== --- source/Symbol/UnwindPlan.cpp +++ source/Symbol/UnwindPlan.cpp @@ -170,6 +170,7 @@ if (m_type == rhs.m_type) { switch (m_type) { case unspecified: + case isFoundHeuristically: return true; case isRegisterPlusOffset: