1 //===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
18 #include "RegisterContextMacOSXFrameBackchain.h"
23 using namespace lldb_private;
25 UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread)
26 : Unwind(thread), m_cursors() {}
28 uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
29 if (m_cursors.empty()) {
30 ExecutionContext exe_ctx(m_thread.shared_from_this());
31 Target *target = exe_ctx.GetTargetPtr();
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));
37 if (target_arch.GetAddressByteSize() == 8)
38 GetStackFrameData_x86_64(exe_ctx);
40 GetStackFrameData_i386(exe_ctx);
43 return m_cursors.size();
46 bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx,
49 const uint32_t frame_count = GetFrameCount();
50 if (idx < frame_count) {
51 if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
53 if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
56 pc = m_cursors[idx].pc;
57 cfa = m_cursors[idx].fp;
64 lldb::RegisterContextSP
65 UnwindMacOSXFrameBackchain::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]);
75 size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386(
76 const ExecutionContext &exe_ctx) {
79 StackFrame *first_frame = exe_ctx.GetFramePtr();
81 Process *process = exe_ctx.GetProcessPtr();
82 if (process == nullptr)
90 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
94 cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
95 cursor.fp = reg_ctx->GetFP(0);
97 Frame_i386 frame = {static_cast<uint32_t>(cursor.fp),
98 static_cast<uint32_t>(cursor.pc)};
100 m_cursors.push_back(cursor);
102 const size_t k_frame_size = sizeof(frame);
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) !=
109 if (frame.pc >= 0x1000) {
110 cursor.pc = frame.pc;
111 cursor.fp = frame.fp;
112 m_cursors.push_back(cursor);
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;
122 SymbolContext first_frame_sc(
123 first_frame->GetSymbolContext(resolve_scope));
124 const AddressRange *addr_range_ptr = nullptr;
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 = ⦥
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
147 // Insert the second frame
148 m_cursors.insert(m_cursors.begin() + 1, cursor);
150 m_cursors.front().fp = first_frame_sp;
157 // printf(" PC FP\n");
158 // printf(" ------------------ ------------------ \n");
159 // for (i=0; i<m_cursors.size(); ++i)
161 // printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i,
162 // m_cursors[i].pc, m_cursors[i].fp);
164 return m_cursors.size();
167 size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64(
168 const ExecutionContext &exe_ctx) {
171 Process *process = exe_ctx.GetProcessPtr();
172 if (process == nullptr)
175 StackFrame *first_frame = exe_ctx.GetFramePtr();
177 struct Frame_x86_64 {
182 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
186 cursor.pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
187 cursor.fp = reg_ctx->GetFP(0);
189 Frame_x86_64 frame = {cursor.fp, cursor.pc};
191 m_cursors.push_back(cursor);
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) !=
200 if (frame.pc >= 0x1000) {
201 cursor.pc = frame.pc;
202 cursor.fp = frame.fp;
203 m_cursors.push_back(cursor);
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;
213 SymbolContext first_frame_sc(
214 first_frame->GetSymbolContext(resolve_scope));
215 const AddressRange *addr_range_ptr = nullptr;
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 = ⦥
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
237 // Insert the second frame
238 m_cursors.insert(m_cursors.begin() + 1, cursor);
240 m_cursors.front().fp = first_frame_sp;
246 return m_cursors.size();