blob: 2d9e02109295fb19003a4e9b6f345bc655c660f2 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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/Target/Thread.h"
16#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
18
19#include "RegisterContextMacOSXFrameBackchain.h"
20
21using namespace lldb;
22using namespace lldb_private;
23
24UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
25 Unwind (thread),
26 m_cursors()
27{
28}
29
30uint32_t
31UnwindMacOSXFrameBackchain::GetFrameCount()
32{
33 if (m_cursors.empty())
34 {
35 const ArchSpec target_arch (m_thread.GetProcess().GetTarget().GetArchitecture ());
36 // Frame zero should always be supplied by the thread...
37 StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0));
38 if (target_arch == ArchSpec("x86_64"))
39 GetStackFrameData_x86_64 (frame_sp.get());
40 else if (target_arch == ArchSpec("i386"))
41 GetStackFrameData_i386 (frame_sp.get());
42
43 }
44 return m_cursors.size();
45}
46
47bool
48UnwindMacOSXFrameBackchain::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
49{
50 const uint32_t frame_count = GetFrameCount();
51 if (idx < frame_count)
52 {
53 if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
54 return false;
55 if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
56 return false;
57
58 pc = m_cursors[idx].pc;
59 cfa = m_cursors[idx].fp;
60
61 return true;
62 }
63 return false;
64}
65
Greg Clayton08d7d3a2011-01-06 22:15:06 +000066lldb::RegisterContextSP
Chris Lattner24943d22010-06-08 16:52:24 +000067UnwindMacOSXFrameBackchain::CreateRegisterContextForFrame (StackFrame *frame)
68{
Greg Clayton08d7d3a2011-01-06 22:15:06 +000069 lldb::RegisterContextSP reg_ctx_sp;
70 uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
Chris Lattner24943d22010-06-08 16:52:24 +000071 const uint32_t frame_count = GetFrameCount();
Greg Clayton08d7d3a2011-01-06 22:15:06 +000072 if (concrete_idx < frame_count)
73 reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
74 return reg_ctx_sp;
Chris Lattner24943d22010-06-08 16:52:24 +000075}
76
77size_t
78UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (StackFrame *first_frame)
79{
80 m_cursors.clear();
81
82 std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
83
Greg Claytonc0418152010-07-07 17:07:17 +000084 struct Frame_i386
Chris Lattner24943d22010-06-08 16:52:24 +000085 {
86 uint32_t fp;
87 uint32_t pc;
88 };
89
Greg Clayton08d7d3a2011-01-06 22:15:06 +000090 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
Chris Lattner24943d22010-06-08 16:52:24 +000091 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 = { cursor.fp, cursor.pc };
98
99 m_cursors.push_back(cursor);
100
101 const size_t k_frame_size = sizeof(frame);
102 Error error;
103 while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
104 {
105 // Read both the FP and PC (8 bytes)
106 if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
107 break;
108 if (frame.pc >= 0x1000)
109 {
110 cursor.pc = frame.pc;
111 cursor.fp = frame.fp;
112 m_cursors.push_back (cursor);
113 }
114 }
115 if (!m_cursors.empty())
116 {
117 lldb::addr_t first_frame_pc = m_cursors.front().pc;
118 if (first_frame_pc != LLDB_INVALID_ADDRESS)
119 {
120 const uint32_t resolve_scope = eSymbolContextModule |
121 eSymbolContextCompUnit |
122 eSymbolContextFunction |
123 eSymbolContextSymbol;
124
125 SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
126 const AddressRange *addr_range_ptr = NULL;
127 if (first_frame_sc.function)
128 addr_range_ptr = &first_frame_sc.function->GetAddressRange();
129 else if (first_frame_sc.symbol)
130 addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
131
132 if (addr_range_ptr)
133 {
Greg Claytonb04e7a82010-08-24 21:05:24 +0000134 if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
Chris Lattner24943d22010-06-08 16:52:24 +0000135 {
136 // We are at the first instruction, so we can recover the
137 // previous PC 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 && m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
141 {
142 cursor.fp = m_cursors.front().fp;
143 cursor.pc = frame.pc; // Set the new second frame PC
144
145 // Insert the second frame
146 m_cursors.insert(m_cursors.begin()+1, cursor);
147
148 m_cursors.front().fp = first_frame_sp;
149 }
150 }
151 }
152 }
153 }
154// uint32_t i=0;
155// printf(" PC FP\n");
156// printf(" ------------------ ------------------ \n");
157// for (i=0; i<m_cursors.size(); ++i)
158// {
159// printf("[%3u] 0x%16.16llx 0x%16.16llx\n", i, m_cursors[i].pc, m_cursors[i].fp);
160// }
161 return m_cursors.size();
162}
163
164
165size_t
166UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (StackFrame *first_frame)
167{
168 m_cursors.clear();
169
170 std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
171
Greg Claytonc0418152010-07-07 17:07:17 +0000172 struct Frame_x86_64
Chris Lattner24943d22010-06-08 16:52:24 +0000173 {
174 uint64_t fp;
175 uint64_t pc;
176 };
177
Greg Clayton08d7d3a2011-01-06 22:15:06 +0000178 RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000179 assert (reg_ctx);
180
181 Cursor cursor;
182 cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
183 cursor.fp = reg_ctx->GetFP (0);
184
185 Frame_x86_64 frame = { cursor.fp, cursor.pc };
186
187 m_cursors.push_back(cursor);
188 Error error;
189 const size_t k_frame_size = sizeof(frame);
190 while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
191 {
192 // Read both the FP and PC (16 bytes)
193 if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
194 break;
195
196 if (frame.pc >= 0x1000)
197 {
198 cursor.pc = frame.pc;
199 cursor.fp = frame.fp;
200 m_cursors.push_back (cursor);
201 }
202 }
203 if (!m_cursors.empty())
204 {
205 lldb::addr_t first_frame_pc = m_cursors.front().pc;
206 if (first_frame_pc != LLDB_INVALID_ADDRESS)
207 {
208 const uint32_t resolve_scope = eSymbolContextModule |
209 eSymbolContextCompUnit |
210 eSymbolContextFunction |
211 eSymbolContextSymbol;
212
213 SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
214 const AddressRange *addr_range_ptr = NULL;
215 if (first_frame_sc.function)
216 addr_range_ptr = &first_frame_sc.function->GetAddressRange();
217 else if (first_frame_sc.symbol)
218 addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
219
220 if (addr_range_ptr)
221 {
Greg Claytonb04e7a82010-08-24 21:05:24 +0000222 if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
Chris Lattner24943d22010-06-08 16:52:24 +0000223 {
224 // We are at the first instruction, so we can recover the
225 // previous PC by dereferencing the SP
226 lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
227 // Read the real second frame return address into frame.pc
228 if (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
229 {
230 cursor.fp = m_cursors.front().fp;
231 cursor.pc = frame.pc; // Set the new second frame PC
232
233 // Insert the second frame
234 m_cursors.insert(m_cursors.begin()+1, cursor);
235
236 m_cursors.front().fp = first_frame_sp;
237 }
238 }
239 }
240 }
241 }
242 return m_cursors.size();
243}
244