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