Summary: Update StackFrame::GetSymbolContext to mirror the logic in RegisterContextLLDB::InitializeNonZerothFrame that knows not to do the pc decrement when the given frame is a signal trap handler frame or the parent of one, because the pc may not follow a call in these frames. Accomplish this by adding a behaves_like_zeroth_frame field to lldb_private::StackFrame, set to true for the zeroth frame, for signal handler frames, and for parents of signal handler frames. Also add logic to propagate the signal handler flag from UnwindPlan to the FrameType on the RegisterContextLLDB it generates, and factor out a helper to resolve symbol and address range for an Address now that we need to invoke it in four places. Reviewers: jasonmolenda, clayborg, jfb Reviewed By: jasonmolenda Subscribers: labath, dexonsmith, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D64993 llvm-svn: 367691
248 lines
7.9 KiB
C++
248 lines
7.9 KiB
C++
//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Symbol/Symbol.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/Thread.h"
|
|
#include "lldb/Utility/ArchSpec.h"
|
|
|
|
#include "RegisterContextMacOSXFrameBackchain.h"
|
|
|
|
#include <memory>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread)
|
|
: Unwind(thread), m_cursors() {}
|
|
|
|
uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
|
|
if (m_cursors.empty()) {
|
|
ExecutionContext exe_ctx(m_thread.shared_from_this());
|
|
Target *target = exe_ctx.GetTargetPtr();
|
|
if (target) {
|
|
const ArchSpec &target_arch = target->GetArchitecture();
|
|
// Frame zero should always be supplied by the thread...
|
|
exe_ctx.SetFrameSP(m_thread.GetStackFrameAtIndex(0));
|
|
|
|
if (target_arch.GetAddressByteSize() == 8)
|
|
GetStackFrameData_x86_64(exe_ctx);
|
|
else
|
|
GetStackFrameData_i386(exe_ctx);
|
|
}
|
|
}
|
|
return m_cursors.size();
|
|
}
|
|
|
|
bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(
|
|
uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) {
|
|
const uint32_t frame_count = GetFrameCount();
|
|
if (idx < frame_count) {
|
|
if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
|
|
return false;
|
|
if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
|
|
return false;
|
|
|
|
pc = m_cursors[idx].pc;
|
|
cfa = m_cursors[idx].fp;
|
|
behaves_like_zeroth_frame = (idx == 0);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
lldb::RegisterContextSP
|
|
UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame(StackFrame *frame) {
|
|
lldb::RegisterContextSP reg_ctx_sp;
|
|
uint32_t concrete_idx = frame->GetConcreteFrameIndex();
|
|
const uint32_t frame_count = GetFrameCount();
|
|
if (concrete_idx < frame_count)
|
|
reg_ctx_sp = std::make_shared<RegisterContextMacOSXFrameBackchain>(
|
|
m_thread, concrete_idx, m_cursors[concrete_idx]);
|
|
return reg_ctx_sp;
|
|
}
|
|
|
|
size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386(
|
|
const ExecutionContext &exe_ctx) {
|
|
m_cursors.clear();
|
|
|
|
StackFrame *first_frame = exe_ctx.GetFramePtr();
|
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
if (process == nullptr)
|
|
return 0;
|
|
|
|
struct Frame_i386 {
|
|
uint32_t fp;
|
|
uint32_t pc;
|
|
};
|
|
|
|
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
|
assert(reg_ctx);
|
|
|
|
Cursor cursor;
|
|
cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
|
|
cursor.fp = reg_ctx->GetFP(0);
|
|
|
|
Frame_i386 frame = {static_cast<uint32_t>(cursor.fp),
|
|
static_cast<uint32_t>(cursor.pc)};
|
|
|
|
m_cursors.push_back(cursor);
|
|
|
|
const size_t k_frame_size = sizeof(frame);
|
|
Status error;
|
|
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
|
|
// Read both the FP and PC (8 bytes)
|
|
if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) !=
|
|
k_frame_size)
|
|
break;
|
|
if (frame.pc >= 0x1000) {
|
|
cursor.pc = frame.pc;
|
|
cursor.fp = frame.fp;
|
|
m_cursors.push_back(cursor);
|
|
}
|
|
}
|
|
if (!m_cursors.empty()) {
|
|
lldb::addr_t first_frame_pc = m_cursors.front().pc;
|
|
if (first_frame_pc != LLDB_INVALID_ADDRESS) {
|
|
const SymbolContextItem resolve_scope =
|
|
eSymbolContextModule | eSymbolContextCompUnit |
|
|
eSymbolContextFunction | eSymbolContextSymbol;
|
|
|
|
SymbolContext first_frame_sc(
|
|
first_frame->GetSymbolContext(resolve_scope));
|
|
const AddressRange *addr_range_ptr = nullptr;
|
|
AddressRange range;
|
|
if (first_frame_sc.function)
|
|
addr_range_ptr = &first_frame_sc.function->GetAddressRange();
|
|
else if (first_frame_sc.symbol) {
|
|
range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
|
|
range.SetByteSize(first_frame_sc.symbol->GetByteSize());
|
|
addr_range_ptr = ⦥
|
|
}
|
|
|
|
if (addr_range_ptr) {
|
|
if (first_frame->GetFrameCodeAddress() ==
|
|
addr_range_ptr->GetBaseAddress()) {
|
|
// We are at the first instruction, so we can recover the previous PC
|
|
// by dereferencing the SP
|
|
lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
|
|
// Read the real second frame return address into frame.pc
|
|
if (first_frame_sp &&
|
|
process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc),
|
|
error) == sizeof(frame.pc)) {
|
|
cursor.fp = m_cursors.front().fp;
|
|
cursor.pc = frame.pc; // Set the new second frame PC
|
|
|
|
// Insert the second frame
|
|
m_cursors.insert(m_cursors.begin() + 1, cursor);
|
|
|
|
m_cursors.front().fp = first_frame_sp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// uint32_t i=0;
|
|
// printf(" PC FP\n");
|
|
// printf(" ------------------ ------------------ \n");
|
|
// for (i=0; i<m_cursors.size(); ++i)
|
|
// {
|
|
// printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i,
|
|
// m_cursors[i].pc, m_cursors[i].fp);
|
|
// }
|
|
return m_cursors.size();
|
|
}
|
|
|
|
size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64(
|
|
const ExecutionContext &exe_ctx) {
|
|
m_cursors.clear();
|
|
|
|
Process *process = exe_ctx.GetProcessPtr();
|
|
if (process == nullptr)
|
|
return 0;
|
|
|
|
StackFrame *first_frame = exe_ctx.GetFramePtr();
|
|
|
|
struct Frame_x86_64 {
|
|
uint64_t fp;
|
|
uint64_t pc;
|
|
};
|
|
|
|
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
|
assert(reg_ctx);
|
|
|
|
Cursor cursor;
|
|
cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
|
|
cursor.fp = reg_ctx->GetFP(0);
|
|
|
|
Frame_x86_64 frame = {cursor.fp, cursor.pc};
|
|
|
|
m_cursors.push_back(cursor);
|
|
Status error;
|
|
const size_t k_frame_size = sizeof(frame);
|
|
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
|
|
// Read both the FP and PC (16 bytes)
|
|
if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) !=
|
|
k_frame_size)
|
|
break;
|
|
|
|
if (frame.pc >= 0x1000) {
|
|
cursor.pc = frame.pc;
|
|
cursor.fp = frame.fp;
|
|
m_cursors.push_back(cursor);
|
|
}
|
|
}
|
|
if (!m_cursors.empty()) {
|
|
lldb::addr_t first_frame_pc = m_cursors.front().pc;
|
|
if (first_frame_pc != LLDB_INVALID_ADDRESS) {
|
|
const SymbolContextItem resolve_scope =
|
|
eSymbolContextModule | eSymbolContextCompUnit |
|
|
eSymbolContextFunction | eSymbolContextSymbol;
|
|
|
|
SymbolContext first_frame_sc(
|
|
first_frame->GetSymbolContext(resolve_scope));
|
|
const AddressRange *addr_range_ptr = nullptr;
|
|
AddressRange range;
|
|
if (first_frame_sc.function)
|
|
addr_range_ptr = &first_frame_sc.function->GetAddressRange();
|
|
else if (first_frame_sc.symbol) {
|
|
range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
|
|
range.SetByteSize(first_frame_sc.symbol->GetByteSize());
|
|
addr_range_ptr = ⦥
|
|
}
|
|
|
|
if (addr_range_ptr) {
|
|
if (first_frame->GetFrameCodeAddress() ==
|
|
addr_range_ptr->GetBaseAddress()) {
|
|
// We are at the first instruction, so we can recover the previous PC
|
|
// by dereferencing the SP
|
|
lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
|
|
// Read the real second frame return address into frame.pc
|
|
if (process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc),
|
|
error) == sizeof(frame.pc)) {
|
|
cursor.fp = m_cursors.front().fp;
|
|
cursor.pc = frame.pc; // Set the new second frame PC
|
|
|
|
// Insert the second frame
|
|
m_cursors.insert(m_cursors.begin() + 1, cursor);
|
|
|
|
m_cursors.front().fp = first_frame_sp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return m_cursors.size();
|
|
}
|