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