]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Plugins / Process / Utility / UnwindMacOSXFrameBackchain.cpp
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"
12 #include "lldb/Target/ExecutionContext.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
18 #include "RegisterContextMacOSXFrameBackchain.h"
19
20 #include <memory>
21
22 using namespace lldb;
23 using namespace lldb_private;
24
25 UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain(Thread &thread)
26     : Unwind(thread), m_cursors() {}
27
28 uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
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
46 bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx,
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
65 UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame(StackFrame *frame) {
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 == nullptr)
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 = nullptr;
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 == nullptr)
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 = nullptr;
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 }