blob: 2115b4e179c0891092c3be805f131f12d8734b6b [file] [log] [blame]
//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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"
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) {
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;
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.reset(new 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 == NULL)
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 uint32_t resolve_scope =
eSymbolContextModule | eSymbolContextCompUnit |
eSymbolContextFunction | eSymbolContextSymbol;
SymbolContext first_frame_sc(
first_frame->GetSymbolContext(resolve_scope));
const AddressRange *addr_range_ptr = NULL;
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 = &range;
}
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 == NULL)
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 uint32_t resolve_scope =
eSymbolContextModule | eSymbolContextCompUnit |
eSymbolContextFunction | eSymbolContextSymbol;
SymbolContext first_frame_sc(
first_frame->GetSymbolContext(resolve_scope));
const AddressRange *addr_range_ptr = NULL;
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 = &range;
}
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();
}