LLDB  mainline
UnwindMacOSXFrameBackchain.cpp
Go to the documentation of this file.
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"
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 
19 
20 #include <memory>
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
26  : Unwind(thread), m_cursors() {}
27 
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 
47  addr_t &cfa,
48  addr_t &pc) {
49  const uint32_t frame_count = GetFrameCount();
50  if (idx < frame_count) {
51  if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
52  return false;
53  if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
54  return false;
55 
56  pc = m_cursors[idx].pc;
57  cfa = m_cursors[idx].fp;
58 
59  return true;
60  }
61  return false;
62 }
63 
64 lldb::RegisterContextSP
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 
75 size_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 == NULL)
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 = NULL;
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 = &range;
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 
167 size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64(
168  const ExecutionContext &exe_ctx) {
169  m_cursors.clear();
170 
171  Process *process = exe_ctx.GetProcessPtr();
172  if (process == NULL)
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 = NULL;
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 = &range;
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 }
lldb::RegisterContextSP DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition: ArchSpec.cpp:742
UnwindMacOSXFrameBackchain(lldb_private::Thread &thread)
uint64_t GetSP(uint64_t fail_value=LLDB_INVALID_ADDRESS)
An architecture specification class.
Definition: ArchSpec.h:32
uint64_t GetFP(uint64_t fail_value=LLDB_INVALID_ADDRESS)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, lldb::addr_t &pc) override
uint32_t GetFrameCount()
Definition: Unwind.h:31
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame&#39;s current pc value.
Definition: StackFrame.cpp:267
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
uint64_t GetPC(uint64_t fail_value=LLDB_INVALID_ADDRESS)
Thread & m_thread
Definition: Unwind.h:74
virtual lldb::RegisterContextSP GetRegisterContext()=0
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
Process * GetProcessPtr() const
Returns a pointer to the process object.
uint64_t addr_t
Definition: lldb-types.h:83
Definition: SBAddress.h:15
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:220
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:395
uint32_t GetConcreteFrameIndex() const
Query this frame to find what frame it is in this Thread&#39;s StackFrameList, not counting inlined frame...
Definition: StackFrame.h:389
A section + offset based address range class.
Definition: AddressRange.h:32
This base class provides an interface to stack frames.
Definition: StackFrame.h:40
const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
Definition: StackFrame.cpp:181
An error handling class.
Definition: Status.h:44
void SetByteSize(lldb::addr_t byte_size)
Set accessor for the byte size of this range.
Definition: AddressRange.h:248
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition: Process.cpp:1966