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