//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/ArchSpec.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.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; std::pair fp_pc_pair; 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(cursor.fp), static_cast(cursor.pc) }; m_cursors.push_back(cursor); const size_t k_frame_size = sizeof(frame); Error 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 = ⦥ } 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 fp_pc_pair; 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); Error 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 = ⦥ } 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(); }