UnwindMacOSXFrameBackchain.cpp revision 360784
1//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/Symbol/Function.h" 10#include "lldb/Symbol/ObjectFile.h" 11#include "lldb/Symbol/Symbol.h" 12#include "lldb/Target/ExecutionContext.h" 13#include "lldb/Target/Process.h" 14#include "lldb/Target/Target.h" 15#include "lldb/Target/Thread.h" 16#include "lldb/Utility/ArchSpec.h" 17 18#include "RegisterContextMacOSXFrameBackchain.h" 19 20#include <memory> 21 22using namespace lldb; 23using namespace lldb_private; 24 25UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread) 26 : Unwind(thread), m_cursors() {} 27 28uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() { 29 if (m_cursors.empty()) { 30 ExecutionContext exe_ctx(m_thread.shared_from_this()); 31 Target *target = exe_ctx.GetTargetPtr(); 32 if (target) { 33 const ArchSpec &target_arch = target->GetArchitecture(); 34 // Frame zero should always be supplied by the thread... 35 exe_ctx.SetFrameSP(m_thread.GetStackFrameAtIndex(0)); 36 37 if (target_arch.GetAddressByteSize() == 8) 38 GetStackFrameData_x86_64(exe_ctx); 39 else 40 GetStackFrameData_i386(exe_ctx); 41 } 42 } 43 return m_cursors.size(); 44} 45 46bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex( 47 uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) { 48 const uint32_t frame_count = GetFrameCount(); 49 if (idx < frame_count) { 50 if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS) 51 return false; 52 if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS) 53 return false; 54 55 pc = m_cursors[idx].pc; 56 cfa = m_cursors[idx].fp; 57 behaves_like_zeroth_frame = (idx == 0); 58 59 return true; 60 } 61 return false; 62} 63 64lldb::RegisterContextSP 65UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame(StackFrame *frame) { 66 lldb::RegisterContextSP reg_ctx_sp; 67 uint32_t concrete_idx = frame->GetConcreteFrameIndex(); 68 const uint32_t frame_count = GetFrameCount(); 69 if (concrete_idx < frame_count) 70 reg_ctx_sp = std::make_shared<RegisterContextMacOSXFrameBackchain>( 71 m_thread, concrete_idx, m_cursors[concrete_idx]); 72 return reg_ctx_sp; 73} 74 75size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386( 76 const ExecutionContext &exe_ctx) { 77 m_cursors.clear(); 78 79 StackFrame *first_frame = exe_ctx.GetFramePtr(); 80 81 Process *process = exe_ctx.GetProcessPtr(); 82 if (process == nullptr) 83 return 0; 84 85 struct Frame_i386 { 86 uint32_t fp; 87 uint32_t pc; 88 }; 89 90 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 91 assert(reg_ctx); 92 93 Cursor cursor; 94 cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS); 95 cursor.fp = reg_ctx->GetFP(0); 96 97 Frame_i386 frame = {static_cast<uint32_t>(cursor.fp), 98 static_cast<uint32_t>(cursor.pc)}; 99 100 m_cursors.push_back(cursor); 101 102 const size_t k_frame_size = sizeof(frame); 103 Status error; 104 while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) { 105 // Read both the FP and PC (8 bytes) 106 if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) != 107 k_frame_size) 108 break; 109 if (frame.pc >= 0x1000) { 110 cursor.pc = frame.pc; 111 cursor.fp = frame.fp; 112 m_cursors.push_back(cursor); 113 } 114 } 115 if (!m_cursors.empty()) { 116 lldb::addr_t first_frame_pc = m_cursors.front().pc; 117 if (first_frame_pc != LLDB_INVALID_ADDRESS) { 118 const SymbolContextItem resolve_scope = 119 eSymbolContextModule | eSymbolContextCompUnit | 120 eSymbolContextFunction | eSymbolContextSymbol; 121 122 SymbolContext first_frame_sc( 123 first_frame->GetSymbolContext(resolve_scope)); 124 const AddressRange *addr_range_ptr = nullptr; 125 AddressRange range; 126 if (first_frame_sc.function) 127 addr_range_ptr = &first_frame_sc.function->GetAddressRange(); 128 else if (first_frame_sc.symbol) { 129 range.GetBaseAddress() = first_frame_sc.symbol->GetAddress(); 130 range.SetByteSize(first_frame_sc.symbol->GetByteSize()); 131 addr_range_ptr = ⦥ 132 } 133 134 if (addr_range_ptr) { 135 if (first_frame->GetFrameCodeAddress() == 136 addr_range_ptr->GetBaseAddress()) { 137 // We are at the first instruction, so we can recover the previous PC 138 // by dereferencing the SP 139 lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); 140 // Read the real second frame return address into frame.pc 141 if (first_frame_sp && 142 process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc), 143 error) == sizeof(frame.pc)) { 144 cursor.fp = m_cursors.front().fp; 145 cursor.pc = frame.pc; // Set the new second frame PC 146 147 // Insert the second frame 148 m_cursors.insert(m_cursors.begin() + 1, cursor); 149 150 m_cursors.front().fp = first_frame_sp; 151 } 152 } 153 } 154 } 155 } 156 // uint32_t i=0; 157 // printf(" PC FP\n"); 158 // printf(" ------------------ ------------------ \n"); 159 // for (i=0; i<m_cursors.size(); ++i) 160 // { 161 // printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, 162 // m_cursors[i].pc, m_cursors[i].fp); 163 // } 164 return m_cursors.size(); 165} 166 167size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64( 168 const ExecutionContext &exe_ctx) { 169 m_cursors.clear(); 170 171 Process *process = exe_ctx.GetProcessPtr(); 172 if (process == nullptr) 173 return 0; 174 175 StackFrame *first_frame = exe_ctx.GetFramePtr(); 176 177 struct Frame_x86_64 { 178 uint64_t fp; 179 uint64_t pc; 180 }; 181 182 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); 183 assert(reg_ctx); 184 185 Cursor cursor; 186 cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS); 187 cursor.fp = reg_ctx->GetFP(0); 188 189 Frame_x86_64 frame = {cursor.fp, cursor.pc}; 190 191 m_cursors.push_back(cursor); 192 Status error; 193 const size_t k_frame_size = sizeof(frame); 194 while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) { 195 // Read both the FP and PC (16 bytes) 196 if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) != 197 k_frame_size) 198 break; 199 200 if (frame.pc >= 0x1000) { 201 cursor.pc = frame.pc; 202 cursor.fp = frame.fp; 203 m_cursors.push_back(cursor); 204 } 205 } 206 if (!m_cursors.empty()) { 207 lldb::addr_t first_frame_pc = m_cursors.front().pc; 208 if (first_frame_pc != LLDB_INVALID_ADDRESS) { 209 const SymbolContextItem resolve_scope = 210 eSymbolContextModule | eSymbolContextCompUnit | 211 eSymbolContextFunction | eSymbolContextSymbol; 212 213 SymbolContext first_frame_sc( 214 first_frame->GetSymbolContext(resolve_scope)); 215 const AddressRange *addr_range_ptr = nullptr; 216 AddressRange range; 217 if (first_frame_sc.function) 218 addr_range_ptr = &first_frame_sc.function->GetAddressRange(); 219 else if (first_frame_sc.symbol) { 220 range.GetBaseAddress() = first_frame_sc.symbol->GetAddress(); 221 range.SetByteSize(first_frame_sc.symbol->GetByteSize()); 222 addr_range_ptr = ⦥ 223 } 224 225 if (addr_range_ptr) { 226 if (first_frame->GetFrameCodeAddress() == 227 addr_range_ptr->GetBaseAddress()) { 228 // We are at the first instruction, so we can recover the previous PC 229 // by dereferencing the SP 230 lldb::addr_t first_frame_sp = reg_ctx->GetSP(0); 231 // Read the real second frame return address into frame.pc 232 if (process->ReadMemory(first_frame_sp, &frame.pc, sizeof(frame.pc), 233 error) == sizeof(frame.pc)) { 234 cursor.fp = m_cursors.front().fp; 235 cursor.pc = frame.pc; // Set the new second frame PC 236 237 // Insert the second frame 238 m_cursors.insert(m_cursors.begin() + 1, cursor); 239 240 m_cursors.front().fp = first_frame_sp; 241 } 242 } 243 } 244 } 245 } 246 return m_cursors.size(); 247} 248