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