Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 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 | |
Greg Clayton | 1f74607 | 2012-08-29 21:13:06 +0000 | [diff] [blame] | 10 | #include "lldb/Symbol/Function.h" |
Greg Clayton | 1f74607 | 2012-08-29 21:13:06 +0000 | [diff] [blame] | 11 | #include "lldb/Symbol/ObjectFile.h" |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 12 | #include "lldb/Symbol/Symbol.h" |
Greg Clayton | 1ac04c3 | 2012-02-21 00:09:25 +0000 | [diff] [blame] | 13 | #include "lldb/Target/ExecutionContext.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 14 | #include "lldb/Target/Process.h" |
| 15 | #include "lldb/Target/Target.h" |
Greg Clayton | 1ac04c3 | 2012-02-21 00:09:25 +0000 | [diff] [blame] | 16 | #include "lldb/Target/Thread.h" |
Pavel Labath | 5f19b90 | 2017-11-13 16:16:33 +0000 | [diff] [blame] | 17 | #include "lldb/Utility/ArchSpec.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 18 | |
| 19 | #include "RegisterContextMacOSXFrameBackchain.h" |
| 20 | |
| 21 | using namespace lldb; |
| 22 | using namespace lldb_private; |
| 23 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 24 | UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread) |
| 25 | : Unwind(thread), m_cursors() {} |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 26 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 40 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 41 | } |
| 42 | return m_cursors.size(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 43 | } |
| 44 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 54 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 55 | pc = m_cursors[idx].pc; |
| 56 | cfa = m_cursors[idx].fp; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 57 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 58 | return true; |
| 59 | } |
| 60 | return false; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 61 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 62 | |
Greg Clayton | 5ccbd29 | 2011-01-06 22:15:06 +0000 | [diff] [blame] | 63 | lldb::RegisterContextSP |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 72 | } |
| 73 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 74 | size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386( |
| 75 | const ExecutionContext &exe_ctx) { |
| 76 | m_cursors.clear(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 77 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 78 | StackFrame *first_frame = exe_ctx.GetFramePtr(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 79 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 80 | Process *process = exe_ctx.GetProcessPtr(); |
| 81 | if (process == NULL) |
| 82 | return 0; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 83 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 84 | struct Frame_i386 { |
| 85 | uint32_t fp; |
| 86 | uint32_t pc; |
| 87 | }; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 88 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 89 | RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); |
| 90 | assert(reg_ctx); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 91 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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); |
Zachary Turner | 97206d5 | 2017-05-12 04:51:55 +0000 | [diff] [blame] | 102 | Status error; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 112 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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) { |
Zachary Turner | 991e445 | 2018-10-25 20:45:19 +0000 | [diff] [blame] | 117 | const SymbolContextItem resolve_scope = |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 118 | eSymbolContextModule | eSymbolContextCompUnit | |
| 119 | eSymbolContextFunction | eSymbolContextSymbol; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 120 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 132 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 133 | if (addr_range_ptr) { |
| 134 | if (first_frame->GetFrameCodeAddress() == |
| 135 | addr_range_ptr->GetBaseAddress()) { |
Adrian Prantl | 0509724 | 2018-04-30 16:49:04 +0000 | [diff] [blame] | 136 | // We are at the first instruction, so we can recover the previous PC |
| 137 | // by dereferencing the SP |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 145 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 146 | // Insert the second frame |
| 147 | m_cursors.insert(m_cursors.begin() + 1, cursor); |
| 148 | |
| 149 | m_cursors.front().fp = first_frame_sp; |
| 150 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 151 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 152 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 153 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 164 | } |
| 165 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 166 | size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64( |
| 167 | const ExecutionContext &exe_ctx) { |
| 168 | m_cursors.clear(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 169 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 170 | Process *process = exe_ctx.GetProcessPtr(); |
| 171 | if (process == NULL) |
| 172 | return 0; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 173 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 174 | StackFrame *first_frame = exe_ctx.GetFramePtr(); |
Greg Clayton | 1ac04c3 | 2012-02-21 00:09:25 +0000 | [diff] [blame] | 175 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 176 | struct Frame_x86_64 { |
| 177 | uint64_t fp; |
| 178 | uint64_t pc; |
| 179 | }; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 180 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 181 | RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); |
| 182 | assert(reg_ctx); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 183 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 184 | Cursor cursor; |
| 185 | cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS); |
| 186 | cursor.fp = reg_ctx->GetFP(0); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 187 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 188 | Frame_x86_64 frame = {cursor.fp, cursor.pc}; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 189 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 190 | m_cursors.push_back(cursor); |
Zachary Turner | 97206d5 | 2017-05-12 04:51:55 +0000 | [diff] [blame] | 191 | Status error; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 203 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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) { |
Zachary Turner | 991e445 | 2018-10-25 20:45:19 +0000 | [diff] [blame] | 208 | const SymbolContextItem resolve_scope = |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 209 | eSymbolContextModule | eSymbolContextCompUnit | |
| 210 | eSymbolContextFunction | eSymbolContextSymbol; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 211 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 223 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 224 | if (addr_range_ptr) { |
| 225 | if (first_frame->GetFrameCodeAddress() == |
| 226 | addr_range_ptr->GetBaseAddress()) { |
Adrian Prantl | 0509724 | 2018-04-30 16:49:04 +0000 | [diff] [blame] | 227 | // We are at the first instruction, so we can recover the previous PC |
| 228 | // by dereferencing the SP |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 235 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 236 | // Insert the second frame |
| 237 | m_cursors.insert(m_cursors.begin() + 1, cursor); |
| 238 | |
| 239 | m_cursors.front().fp = first_frame_sp; |
| 240 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 241 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 242 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 243 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 244 | } |
| 245 | return m_cursors.size(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 246 | } |