1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include "common.h"
6 #include "daccess.h"
7
8 #define UNW_STEP_SUCCESS 1
9 #define UNW_STEP_END 0
10
11 #ifdef __APPLE__
12 #include <mach-o/getsect.h>
13 #endif
14
15 #include <regdisplay.h>
16 #include "UnwindHelpers.h"
17
18 // libunwind headers
19 #include <libunwind.h>
20 #include <src/config.h>
21 #include <src/Registers.hpp>
22 #include <src/AddressSpace.hpp>
23 #include <src/UnwindCursor.hpp>
24
25 using libunwind::Registers_x86_64;
26 using libunwind::LocalAddressSpace;
27 using libunwind::EHHeaderParser;
28 using libunwind::DwarfInstructions;
29 using libunwind::UnwindInfoSections;
30
31 LocalAddressSpace _addressSpace;
32
33 #ifdef __APPLE__
34
35 struct dyld_unwind_sections
36 {
37 const struct mach_header* mh;
38 const void* dwarf_section;
39 uintptr_t dwarf_section_length;
40 const void* compact_unwind_section;
41 uintptr_t compact_unwind_section_length;
42 };
43
44 #else // __APPLE__
45
46 // Passed to the callback function called by dl_iterate_phdr
47 struct dl_iterate_cb_data
48 {
49 UnwindInfoSections *sects;
50 uintptr_t targetAddr;
51 };
52
53 // Callback called by dl_iterate_phdr. Locates unwind info sections for the target
54 // address.
LocateSectionsCallback(struct dl_phdr_info * info,size_t size,void * data)55 static int LocateSectionsCallback(struct dl_phdr_info *info, size_t size, void *data)
56 {
57 // info is a pointer to a structure containing information about the shared object
58 dl_iterate_cb_data* cbdata = static_cast<dl_iterate_cb_data*>(data);
59 uintptr_t addrOfInterest = (uintptr_t)cbdata->targetAddr;
60
61 size_t object_length;
62 bool found_obj = false;
63 bool found_hdr = false;
64
65 // If the base address of the SO is past the address we care about, move on.
66 if (info->dlpi_addr > addrOfInterest)
67 {
68 return 0;
69 }
70
71 // Iterate through the program headers for this SO
72 for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++)
73 {
74 const ElfW(Phdr) *phdr = &info->dlpi_phdr[i];
75
76 if (phdr->p_type == PT_LOAD)
77 {
78 // This is a loadable entry. Loader loads all segments of this type.
79
80 uintptr_t begin = info->dlpi_addr + phdr->p_vaddr;
81 uintptr_t end = begin + phdr->p_memsz;
82
83 if (addrOfInterest >= begin && addrOfInterest < end)
84 {
85 cbdata->sects->dso_base = begin;
86 object_length = phdr->p_memsz;
87 found_obj = true;
88 }
89 }
90 else if (phdr->p_type == PT_GNU_EH_FRAME)
91 {
92 // This element specifies the location and size of the exception handling
93 // information as defined by the .eh_frame_hdr section.
94
95 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
96
97 uintptr_t eh_frame_hdr_start = info->dlpi_addr + phdr->p_vaddr;
98 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
99 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
100
101 EHHeaderParser<LocalAddressSpace> ehp;
102 ehp.decodeEHHdr(_addressSpace, eh_frame_hdr_start, phdr->p_memsz, hdrInfo);
103
104 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
105 found_hdr = true;
106 }
107 }
108
109 return 0;
110 }
111
112 #endif // __APPLE__
113
114 #ifdef _TARGET_AMD64_
115
116 // Shim that implements methods required by libunwind over REGDISPLAY
117 struct Registers_REGDISPLAY : REGDISPLAY
118 {
getRegisterRegisters_REGDISPLAY119 inline uint64_t getRegister(int regNum) const
120 {
121 switch (regNum)
122 {
123 case UNW_REG_IP:
124 return IP;
125 case UNW_REG_SP:
126 return SP;
127 case UNW_X86_64_RAX:
128 return *pRax;
129 case UNW_X86_64_RDX:
130 return *pRdx;
131 case UNW_X86_64_RCX:
132 return *pRcx;
133 case UNW_X86_64_RBX:
134 return *pRbx;
135 case UNW_X86_64_RSI:
136 return *pRsi;
137 case UNW_X86_64_RDI:
138 return *pRdi;
139 case UNW_X86_64_RBP:
140 return *pRbp;
141 case UNW_X86_64_RSP:
142 return SP;
143 case UNW_X86_64_R8:
144 return *pR8;
145 case UNW_X86_64_R9:
146 return *pR9;
147 case UNW_X86_64_R10:
148 return *pR10;
149 case UNW_X86_64_R11:
150 return *pR11;
151 case UNW_X86_64_R12:
152 return *pR12;
153 case UNW_X86_64_R13:
154 return *pR13;
155 case UNW_X86_64_R14:
156 return *pR14;
157 case UNW_X86_64_R15:
158 return *pR15;
159 }
160
161 // Unsupported register requested
162 abort();
163 }
164
setRegisterRegisters_REGDISPLAY165 inline void setRegister(int regNum, uint64_t value, uint64_t location)
166 {
167 switch (regNum)
168 {
169 case UNW_REG_IP:
170 IP = value;
171 pIP = (PTR_PCODE)location;
172 return;
173 case UNW_REG_SP:
174 SP = value;
175 return;
176 case UNW_X86_64_RAX:
177 pRax = (PTR_UIntNative)location;
178 return;
179 case UNW_X86_64_RDX:
180 pRdx = (PTR_UIntNative)location;
181 return;
182 case UNW_X86_64_RCX:
183 pRcx = (PTR_UIntNative)location;
184 return;
185 case UNW_X86_64_RBX:
186 pRbx = (PTR_UIntNative)location;
187 return;
188 case UNW_X86_64_RSI:
189 pRsi = (PTR_UIntNative)location;
190 return;
191 case UNW_X86_64_RDI:
192 pRdi = (PTR_UIntNative)location;
193 return;
194 case UNW_X86_64_RBP:
195 pRbp = (PTR_UIntNative)location;
196 return;
197 case UNW_X86_64_RSP:
198 SP = value;
199 return;
200 case UNW_X86_64_R8:
201 pR8 = (PTR_UIntNative)location;
202 return;
203 case UNW_X86_64_R9:
204 pR9 = (PTR_UIntNative)location;
205 return;
206 case UNW_X86_64_R10:
207 pR10 = (PTR_UIntNative)location;
208 return;
209 case UNW_X86_64_R11:
210 pR11 = (PTR_UIntNative)location;
211 return;
212 case UNW_X86_64_R12:
213 pR12 = (PTR_UIntNative)location;
214 return;
215 case UNW_X86_64_R13:
216 pR13 = (PTR_UIntNative)location;
217 return;
218 case UNW_X86_64_R14:
219 pR14 = (PTR_UIntNative)location;
220 return;
221 case UNW_X86_64_R15:
222 pR15 = (PTR_UIntNative)location;
223 return;
224 }
225
226 // Unsupported x86_64 register
227 abort();
228 }
229
230 // N/A for x86_64
validFloatRegisterRegisters_REGDISPLAY231 inline bool validFloatRegister(int) { return false; }
validVectorRegisterRegisters_REGDISPLAY232 inline bool validVectorRegister(int) { return false; }
233
lastDwarfRegNumRegisters_REGDISPLAY234 inline static int lastDwarfRegNum() { return 16; }
235
validRegisterRegisters_REGDISPLAY236 inline bool validRegister(int regNum) const
237 {
238 if (regNum == UNW_REG_IP)
239 return true;
240 if (regNum == UNW_REG_SP)
241 return true;
242 if (regNum < 0)
243 return false;
244 if (regNum > 15)
245 return false;
246 return true;
247 }
248
249 // N/A for x86_64
getFloatRegisterRegisters_REGDISPLAY250 inline double getFloatRegister(int) const { abort(); }
setFloatRegisterRegisters_REGDISPLAY251 inline void setFloatRegister(int, double) { abort(); }
getVectorRegisterRegisters_REGDISPLAY252 inline double getVectorRegister(int) const { abort(); }
setVectorRegisterRegisters_REGDISPLAY253 inline void setVectorRegister(int, ...) { abort(); }
254
getSPRegisters_REGDISPLAY255 uint64_t getSP() const { return SP; }
setSPRegisters_REGDISPLAY256 void setSP(uint64_t value, uint64_t location) { SP = value; }
257
getIPRegisters_REGDISPLAY258 uint64_t getIP() const { return IP; }
259
setIPRegisters_REGDISPLAY260 void setIP(uint64_t value, uint64_t location)
261 {
262 IP = value;
263 pIP = (PTR_PCODE)location;
264 }
265
getRBPRegisters_REGDISPLAY266 uint64_t getRBP() const { return *pRbp; }
setRBPRegisters_REGDISPLAY267 void setRBP(uint64_t value, uint64_t location) { pRbp = (PTR_UIntNative)location; }
getRBXRegisters_REGDISPLAY268 uint64_t getRBX() const { return *pRbx; }
setRBXRegisters_REGDISPLAY269 void setRBX(uint64_t value, uint64_t location) { pRbx = (PTR_UIntNative)location; }
getR12Registers_REGDISPLAY270 uint64_t getR12() const { return *pR12; }
setR12Registers_REGDISPLAY271 void setR12(uint64_t value, uint64_t location) { pR12 = (PTR_UIntNative)location; }
getR13Registers_REGDISPLAY272 uint64_t getR13() const { return *pR13; }
setR13Registers_REGDISPLAY273 void setR13(uint64_t value, uint64_t location) { pR13 = (PTR_UIntNative)location; }
getR14Registers_REGDISPLAY274 uint64_t getR14() const { return *pR14; }
setR14Registers_REGDISPLAY275 void setR14(uint64_t value, uint64_t location) { pR14 = (PTR_UIntNative)location; }
getR15Registers_REGDISPLAY276 uint64_t getR15() const { return *pR15; }
setR15Registers_REGDISPLAY277 void setR15(uint64_t value, uint64_t location) { pR15 = (PTR_UIntNative)location; }
278 };
279
280 #endif // _TARGET_AMD64_
281
DoTheStep(uintptr_t pc,UnwindInfoSections uwInfoSections,REGDISPLAY * regs)282 bool DoTheStep(uintptr_t pc, UnwindInfoSections uwInfoSections, REGDISPLAY *regs)
283 {
284 #if defined(_TARGET_AMD64_)
285 libunwind::UnwindCursor<LocalAddressSpace, Registers_x86_64> uc(_addressSpace);
286 #elif defined(_TARGET_ARM_)
287 libunwind::UnwindCursor<LocalAddressSpace, Registers_arm> uc(_addressSpace);
288 #else
289 #error "Unwinding is not implemented for this architecture yet."
290 #endif
291
292 bool retVal = uc.getInfoFromDwarfSection(pc, uwInfoSections, 0 /* fdeSectionOffsetHint */);
293 if (!retVal)
294 {
295 return false;
296 }
297
298 unw_proc_info_t procInfo;
299 uc.getInfo(&procInfo);
300
301 DwarfInstructions<LocalAddressSpace, Registers_REGDISPLAY> dwarfInst;
302
303 int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, procInfo.unwind_info, *(Registers_REGDISPLAY*)regs);
304 if (stepRet != UNW_STEP_SUCCESS)
305 {
306 return false;
307 }
308
309 regs->pIP = PTR_PCODE(regs->SP - sizeof(TADDR));
310
311 return true;
312 }
313
LocateUnwindSections(uintptr_t pc)314 UnwindInfoSections LocateUnwindSections(uintptr_t pc)
315 {
316 UnwindInfoSections uwInfoSections;
317
318 #ifdef __APPLE__
319 // On macOS, we can use a dyld function from libSystem in order
320 // to find the unwind sections.
321
322 libunwind::dyld_unwind_sections dyldInfo;
323
324 if (libunwind::_dyld_find_unwind_sections((void *)pc, &dyldInfo))
325 {
326 uwInfoSections.dso_base = (uintptr_t)dyldInfo.mh;
327
328 uwInfoSections.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
329 uwInfoSections.dwarf_section_length = dyldInfo.dwarf_section_length;
330
331 uwInfoSections.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
332 uwInfoSections.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
333 }
334 #else // __APPLE__
335
336 dl_iterate_cb_data cb_data = {&uwInfoSections, pc };
337 dl_iterate_phdr(LocateSectionsCallback, &cb_data);
338
339 #endif
340
341 return uwInfoSections;
342 }
343
StepFrame(REGDISPLAY * regs)344 bool UnwindHelpers::StepFrame(REGDISPLAY *regs)
345 {
346 uintptr_t pc = regs->GetIP();
347
348 UnwindInfoSections uwInfoSections = LocateUnwindSections(pc);
349 if (uwInfoSections.dwarf_section == NULL)
350 {
351 return false;
352 }
353
354 return DoTheStep(pc, uwInfoSections, regs);
355 }
356