diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp new file mode 100644 index 00000000000..558edeec1a3 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp @@ -0,0 +1,247 @@ +//===-- 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(); +} |