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