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