Implement out of context stack unwinder (#13302)
[platform/upstream/coreclr.git] / src / pal / src / exception / remote-unwind.cpp
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 /*++
6
7 Module Name:
8
9     remote-unwind.cpp
10
11 Abstract:
12
13     Implementation of out of context unwind using libunwind8
14     remote unwind API.
15
16 This file contains code based on libunwind8
17
18 Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
19    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
20
21 Permission is hereby granted, free of charge, to any person obtaining
22 a copy of this software and associated documentation files (the
23 "Software"), to deal in the Software without restriction, including
24 without limitation the rights to use, copy, modify, merge, publish,
25 distribute, sublicense, and/or sell copies of the Software, and to
26 permit persons to whom the Software is furnished to do so, subject to
27 the following conditions:
28
29 The above copyright notice and this permission notice shall be
30 included in all copies or substantial portions of the Software.
31
32 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
40 --*/
41
42 #include "config.h"
43 #include "pal/palinternal.h"
44 #include "pal/dbgmsg.h"
45 #include "pal/critsect.h"
46 #include "pal/debug.h"
47 #include "pal_endian.h"
48 #include "pal.h"
49 #include <dlfcn.h>
50
51 #if HAVE_LIBUNWIND_H
52 #ifndef __linux__
53 #define UNW_LOCAL_ONLY
54 #endif // !__linux__       
55 #include <libunwind.h>
56 #endif // HAVE_LIBUNWIND_H
57
58 SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
59
60 // Only used on the AMD64 build
61 #if defined(_AMD64_) && defined(HAVE_UNW_GET_ACCESSORS)
62
63 #include <elf.h>
64 #include <link.h>
65
66 #define Ehdr   ElfW(Ehdr)
67 #define Phdr   ElfW(Phdr)
68 #define Shdr   ElfW(Shdr)
69 #define Nhdr   ElfW(Nhdr)
70 #define Dyn    ElfW(Dyn)
71
72 extern void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext);
73 extern void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOLATILE_CONTEXT_POINTERS *contextPointers);
74
75 typedef struct _libunwindInfo
76 {
77     SIZE_T BaseAddress;
78     CONTEXT *Context;
79     UnwindReadMemoryCallback ReadMemory;
80 } libunwindInfo;
81
82 #define DW_EH_VERSION           1
83
84 // DWARF Pointer-Encoding (PEs).
85 //
86 // Pointer-Encodings were invented for the GCC exception-handling
87 // support for C++, but they represent a rather generic way of
88 // describing the format in which an address/pointer is stored.
89 // The Pointer-Encoding format is partially documented in Linux Base
90 // Spec v1.3 (http://www.linuxbase.org/spec/).
91
92 #define DW_EH_PE_FORMAT_MASK    0x0f    // format of the encoded value
93 #define DW_EH_PE_APPL_MASK      0x70    // how the value is to be applied
94 #define DW_EH_PE_indirect       0x80    // Flag bit. If set, the resulting pointer is the
95                                         //  address of the word that contains the final address
96 // Pointer-encoding formats
97 #define DW_EH_PE_omit           0xff
98 #define DW_EH_PE_ptr            0x00    // pointer-sized unsigned value
99 #define DW_EH_PE_uleb128        0x01    // unsigned LE base-128 value
100 #define DW_EH_PE_udata2         0x02    // unsigned 16-bit value
101 #define DW_EH_PE_udata4         0x03    // unsigned 32-bit value
102 #define DW_EH_PE_udata8         0x04    // unsigned 64-bit value
103 #define DW_EH_PE_sleb128        0x09    // signed LE base-128 value
104 #define DW_EH_PE_sdata2         0x0a    // signed 16-bit value
105 #define DW_EH_PE_sdata4         0x0b    // signed 32-bit value
106 #define DW_EH_PE_sdata8         0x0c    // signed 64-bit value
107
108 // Pointer-encoding application
109 #define DW_EH_PE_absptr         0x00    // absolute value
110 #define DW_EH_PE_pcrel          0x10    // rel. to addr. of encoded value
111 #define DW_EH_PE_textrel        0x20    // text-relative (GCC-specific???)
112 #define DW_EH_PE_datarel        0x30    // data-relative
113
114 // The following are not documented by LSB v1.3, yet they are used by
115 // GCC, presumably they aren't documented by LSB since they aren't
116 // used on Linux
117 #define DW_EH_PE_funcrel        0x40    // start-of-procedure-relative
118 #define DW_EH_PE_aligned        0x50    // aligned pointer
119
120 #define DWARF_CIE_VERSION       3       // GCC emits version 1???
121
122 // DWARF frame header
123 typedef struct _eh_frame_hdr
124 {
125     unsigned char version;
126     unsigned char eh_frame_ptr_enc;
127     unsigned char fde_count_enc;
128     unsigned char table_enc;
129     // The rest of the header is variable-length and consists of the
130     // following members:
131     //
132     //   encoded_t eh_frame_ptr;
133     //   encoded_t fde_count;
134     //   struct
135     //   {
136     //      encoded_t start_ip;     // first address covered by this FDE
137     //      encoded_t fde_offset;   // offset of the FDE
138     //   } binary_search_table[fde_count]; 
139 } eh_frame_hdr;
140
141 // "DW_EH_PE_datarel|DW_EH_PE_sdata4" encoded fde table entry
142 typedef struct _table_entry
143 {
144     int32_t start_ip;
145     int32_t fde_offset;
146 } table_entry;
147
148 // DWARF unwind info
149 typedef struct dwarf_cie_info
150 {
151     unw_word_t cie_instr_start;     // start addr. of CIE "initial_instructions"
152     unw_word_t cie_instr_end;       // end addr. of CIE "initial_instructions"
153     unw_word_t fde_instr_start;     // start addr. of FDE "instructions"
154     unw_word_t fde_instr_end;       // end addr. of FDE "instructions"
155     unw_word_t code_align;          // code-alignment factor
156     unw_word_t data_align;          // data-alignment factor
157     unw_word_t ret_addr_column;     // column of return-address register
158     unw_word_t handler;             // address of personality-routine
159     uint16_t abi;
160     uint16_t tag;
161     uint8_t fde_encoding;
162     uint8_t lsda_encoding;
163     unsigned int sized_augmentation : 1;
164     unsigned int have_abi_marker : 1;
165     unsigned int signal_frame : 1;
166 } dwarf_cie_info_t;
167
168 static bool 
169 ReadValue8(const libunwindInfo* info, unw_word_t* addr, uint8_t* valp)
170 {
171     uint8_t value;
172     if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
173         return false;
174     }
175     *addr += sizeof(value);
176     *valp = value;
177     return true;
178 }
179
180 static bool 
181 ReadValue16(const libunwindInfo* info, unw_word_t* addr, uint16_t* valp)
182 {
183     uint16_t value;
184     if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
185         return false;
186     }
187     *addr += sizeof(value);
188     *valp = VAL16(value);
189     return true;
190 }
191
192 static bool 
193 ReadValue32(const libunwindInfo* info, unw_word_t* addr, uint32_t* valp)
194 {
195     uint32_t value;
196     if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
197         return false;
198     }
199     *addr += sizeof(value);
200     *valp = VAL32(value);
201     return true;
202 }
203
204 static bool 
205 ReadValue64(const libunwindInfo* info, unw_word_t* addr, uint64_t* valp)
206 {
207     uint64_t value;
208     if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
209         return false;
210     }
211     *addr += sizeof(value);
212     *valp = VAL64(value);
213     return true;
214 }
215
216 static bool 
217 ReadPointer(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
218 {
219 #ifdef BIT64
220     uint64_t val64;
221     if (ReadValue64(info, addr, &val64)) {
222         *valp = val64;
223         return true;
224     }
225 #else
226     uint32_t val32;
227     if (ReadValue32(info, addr, &val32)) {
228         *valp = val32;
229         return true;
230     }
231 #endif
232     return false;
233 }
234
235 // Read a unsigned "little-endian base 128" value. See Chapter 7.6 of DWARF spec v3.
236 static bool 
237 ReadULEB128(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
238 {
239     unw_word_t value = 0;
240     unsigned char byte;
241     int shift = 0;
242
243     do
244     {
245         if (!ReadValue8(info, addr, &byte)) {
246             return false;
247         }
248         value |= ((unw_word_t)byte & 0x7f) << shift;
249         shift += 7;
250     } while (byte & 0x80);
251
252     *valp = value;
253     return true;
254 }
255
256 // Read a signed "little-endian base 128" value. See Chapter 7.6 of DWARF spec v3.
257 static bool 
258 ReadSLEB128(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
259 {
260     unw_word_t value = 0;
261     unsigned char byte;
262     int shift = 0;
263
264     do
265     {
266         if (!ReadValue8(info, addr, &byte)) {
267             return false;
268         }
269         value |= ((unw_word_t)byte & 0x7f) << shift;
270         shift += 7;
271     } while (byte & 0x80);
272
273     if ((shift < (8 * sizeof(unw_word_t))) && ((byte & 0x40) != 0)) {
274         value |= ((unw_word_t)-1) << shift;
275     }
276
277     *valp = value;
278     return true;
279 }
280
281 static bool 
282 ReadEncodedPointer(const libunwindInfo* info, unw_word_t* addr, unsigned char encoding, unw_word_t funcRel, unw_word_t* valp)
283 {
284     unw_word_t initialAddr = *addr;
285     uint16_t value16;
286     uint32_t value32;
287     uint64_t value64;
288     unw_word_t value;
289
290     if (encoding == DW_EH_PE_omit)
291     {
292         *valp = 0;
293         return true;
294     }
295     else if (encoding == DW_EH_PE_aligned)
296     {
297         int size = sizeof(unw_word_t);
298         *addr = (initialAddr + size - 1) & -size;
299         return ReadPointer(info, addr, valp);
300     }
301
302     switch (encoding & DW_EH_PE_FORMAT_MASK)
303     {
304     case DW_EH_PE_ptr:
305         if (!ReadPointer(info, addr, &value)) {
306             return false;
307         }
308         break;
309
310     case DW_EH_PE_uleb128:
311         if (!ReadULEB128(info, addr, &value)) {
312             return false;
313         }
314         break;
315
316     case DW_EH_PE_sleb128:
317         if (!ReadSLEB128(info, addr, &value)) {
318             return false;
319         }
320         break;
321
322     case DW_EH_PE_udata2:
323         if (!ReadValue16(info, addr, &value16)) {
324             return false;
325         }
326         value = value16;
327         break;
328
329     case DW_EH_PE_udata4:
330         if (!ReadValue32(info, addr, &value32)) {
331             return false;
332         }
333         value = value32;
334         break;
335
336     case DW_EH_PE_udata8:
337         if (!ReadValue64(info, addr, &value64)) {
338             return false;
339         }
340         value = value64;
341         break;
342
343     case DW_EH_PE_sdata2:
344         if (!ReadValue16(info, addr, &value16)) {
345             return false;
346         }
347         value = (int16_t)value16;
348         break;
349
350     case DW_EH_PE_sdata4:
351         if (!ReadValue32(info, addr, &value32)) {
352             return false;
353         }
354         value = (int32_t)value32;
355         break;
356
357     case DW_EH_PE_sdata8:
358         if (!ReadValue64(info, addr, &value64)) {
359             return false;
360         }
361         value = (int64_t)value64;
362         break;
363
364     default:
365         ASSERT("ReadEncodedPointer: invalid encoding format %x\n", encoding);
366         return false;
367     }
368
369     // 0 is a special value and always absolute
370     if (value == 0) {
371         *valp = 0;
372         return true;
373     }
374
375     switch (encoding & DW_EH_PE_APPL_MASK)
376     {
377     case DW_EH_PE_absptr:
378         break;
379
380     case DW_EH_PE_pcrel:
381         value += initialAddr;
382         break;
383
384     case DW_EH_PE_funcrel:
385         _ASSERTE(funcRel != UINTPTR_MAX);
386         value += funcRel;
387         break;
388
389     case DW_EH_PE_textrel:
390     case DW_EH_PE_datarel:
391     default:
392         ASSERT("ReadEncodedPointer: invalid application type %x\n", encoding);
393         return false;
394     }
395
396     if (encoding & DW_EH_PE_indirect)
397     {
398         unw_word_t indirect_addr = value;
399         if (!ReadPointer(info, &indirect_addr, &value)) {
400             return false;
401         }
402     }
403
404     *valp = value;
405     return true;
406 }
407
408 static bool 
409 LookupTableEntry(const libunwindInfo* info, int32_t ip, unw_word_t tableAddr, size_t tableCount, table_entry* entry, bool* found)
410 {
411     size_t low, high, mid;
412     unw_word_t addr;
413     int32_t start_ip;
414
415     *found = false;
416
417     // do a binary search on table
418     for (low = 0, high = tableCount; low < high;)
419     {
420         mid = (low + high) / 2;
421         addr = tableAddr + (mid * sizeof(table_entry));
422
423         if (!ReadValue32(info, &addr, (uint32_t*)&start_ip)) {
424             return false;
425         }
426         if (ip < start_ip) {
427             high = mid;
428         }
429         else {
430             low = mid + 1;
431         }
432     }
433
434     if (high > 0) {
435         addr = tableAddr + ((high - 1) * sizeof(table_entry));
436         // Assumes that the table_entry is two 32 bit values
437         _ASSERTE(sizeof(*entry) == sizeof(uint64_t));
438         if (!ReadValue64(info, &addr, (uint64_t*)entry)) {
439             return false;
440         }
441         *found = true;
442     }
443
444     return true;
445 }
446
447 static bool
448 ParseCie(const libunwindInfo* info, unw_word_t addr, dwarf_cie_info_t* dci)
449 {
450     uint8_t ch, version, fdeEncoding, handlerEncoding;
451     unw_word_t cieLength, cieEndAddr;
452     uint32_t value32;
453     uint64_t value64;
454
455     memset(dci, 0, sizeof (*dci));
456
457     // Pick appropriate default for FDE-encoding. DWARF spec says
458     // start-IP (initial_location) and the code-size (address_range) are
459     // "address-unit sized constants".  The `R' augmentation can be used
460     // to override this, but by default, we pick an address-sized unit
461     // for fde_encoding.
462 #if BIT64
463     fdeEncoding = DW_EH_PE_udata8;
464 #else
465     fdeEncoding = DW_EH_PE_udata4;
466 #endif
467
468     dci->lsda_encoding = DW_EH_PE_omit;
469     dci->handler = 0;
470
471     if (!ReadValue32(info, &addr, &value32)) {
472         return false;
473     }
474
475     if (value32 != 0xffffffff)
476     {
477         // The CIE is in the 32-bit DWARF format
478         uint32_t cieId;
479
480         // DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0
481         const uint32_t expectedId = 0;
482
483         cieLength = value32;
484         cieEndAddr = addr + cieLength;
485
486         if (!ReadValue32(info, &addr, &cieId)) {
487             return false;
488         }
489         if (cieId != expectedId) {
490             ASSERT("ParseCie: unexpected cie id %x\n", cieId);
491             return false;
492         }
493     }
494     else
495     {
496         // The CIE is in the 64-bit DWARF format
497         uint64_t cieId;
498
499         // DWARF says CIE id should be 0xffffffffffffffff, but in .eh_frame, it's 0
500         const uint64_t expectedId = 0;
501
502         if (!ReadValue64(info, &addr, &value64)) {
503             return false;
504         }
505         cieLength = value64;
506         cieEndAddr = addr + cieLength;
507
508         if (!ReadValue64(info, &addr, &cieId)) {
509             return false;
510         }
511         if (cieId != expectedId) {
512             ASSERT("ParseCie: unexpected cie id %lx\n", cieId);
513             return false;
514         }
515     }
516     dci->cie_instr_end = cieEndAddr;
517
518     if (!ReadValue8(info, &addr, &version)) {
519         return false;
520     }
521     if (version != 1 && version != DWARF_CIE_VERSION) {
522         ASSERT("ParseCie: invalid cie version %x\n", version);
523         return false;
524     }
525
526     // Read the augmentation string
527     uint8_t augmentationString[8];
528     memset(augmentationString, 0, sizeof(augmentationString));
529
530     for (int i = 0; i < sizeof(augmentationString); i++)
531     {
532         if (!ReadValue8(info, &addr, &ch)) {
533             return false;
534         }
535         if (ch == 0) {
536             break;
537         }
538         augmentationString[i] = ch;
539     }
540
541     // Read the code and data alignment
542     if (!ReadULEB128(info, &addr, &dci->code_align)) {
543         return false;
544     }
545     if (!ReadSLEB128(info, &addr, &dci->data_align)) {
546         return false;
547     }
548
549     // Read the return-address column either as a u8 or as a uleb128
550     if (version == 1)
551     {
552         if (!ReadValue8(info, &addr, &ch)) {
553             return false;
554         }
555         dci->ret_addr_column = ch;
556     }
557     else
558     {
559         if (!ReadULEB128(info, &addr, &dci->ret_addr_column)) {
560             return false;
561         }
562     }
563
564     // Parse the augmentation string
565     for (int i = 0; i < sizeof(augmentationString); i++)
566     {
567         bool done = false;
568         unw_word_t augmentationSize;
569
570         switch (augmentationString[i])
571         {
572         case '\0':
573             done = true;
574             break;
575
576         case 'z':
577             dci->sized_augmentation = 1;
578             if (!ReadULEB128(info, &addr, &augmentationSize)) {
579                 return false;
580             }
581             break;
582
583         case 'L':
584             // read the LSDA pointer-encoding format
585             if (!ReadValue8(info, &addr, &ch)) {
586                 return false;
587             }
588             dci->lsda_encoding = ch;
589             break;
590
591         case 'R':
592             // read the FDE pointer-encoding format
593             if (!ReadValue8(info, &addr, &fdeEncoding)) {
594                 return false;
595             }
596             break;
597
598         case 'P':
599             // read the personality-routine pointer-encoding format
600             if (!ReadValue8(info, &addr, &handlerEncoding)) {
601                 return false;
602             }
603             if (!ReadEncodedPointer(info, &addr, handlerEncoding, UINTPTR_MAX, &dci->handler)) {
604                 return false;
605             }
606             break;
607
608         case 'S':
609            // This is a signal frame
610            dci->signal_frame = 1;
611
612            // Temporarily set it to one so dwarf_parse_fde() knows that
613            // it should fetch the actual ABI/TAG pair from the FDE.
614            dci->have_abi_marker = 1;
615            break;
616
617         default:
618             if (dci->sized_augmentation) {
619                 // If we have the size of the augmentation body, we can skip
620                 // over the parts that we don't understand, so we're OK
621                 done = true;
622                 break;
623             }
624             ASSERT("ParseCie: unexpected argumentation string '%s'\n", augmentationString[i]);
625             return false;
626         }
627
628         if (done) {
629             break;
630         }
631     }
632     dci->fde_encoding = fdeEncoding;
633     dci->cie_instr_start = addr;
634     return true;
635 }
636
637 static bool
638 ExtractProcInfoFromFde(const libunwindInfo* info, unw_word_t* addrp, unw_proc_info_t *pip, int need_unwind_info)
639 {
640     unw_word_t addr = *addrp, fdeEndAddr, cieOffsetAddr, cieAddr;
641     uint32_t value32;
642     uint64_t value64;
643
644     if (!ReadValue32(info, &addr, &value32)) {
645         return false;
646     }
647     if (value32 != 0xffffffff)
648     {
649         int32_t cieOffset = 0;
650
651         // In some configurations, an FDE with a 0 length indicates the end of the FDE-table
652         if (value32 == 0) {
653             return false;
654         }
655         // the FDE is in the 32-bit DWARF format */
656         *addrp = fdeEndAddr = addr + value32;
657         cieOffsetAddr = addr;
658
659         if (!ReadValue32(info, &addr, (uint32_t*)&cieOffset)) {
660             return false;
661         }
662         // Ignore CIEs (happens during linear search)
663         if (cieOffset == 0) {
664             return true;
665         }
666         // DWARF says that the CIE_pointer in the FDE is a .debug_frame-relative offset, 
667         // but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, 
668         // which is just as fine as it's self-contained
669         cieAddr = cieOffsetAddr - cieOffset;
670     }
671     else 
672     {
673         int64_t cieOffset = 0;
674
675         // the FDE is in the 64-bit DWARF format */
676         if (!ReadValue64(info, &addr, (uint64_t*)&value64)) {
677             return false;
678         }
679         *addrp = fdeEndAddr = addr + value64;
680         cieOffsetAddr = addr;
681
682         if (!ReadValue64(info, &addr, (uint64_t*)&cieOffset)) {
683             return false;
684         }
685         // Ignore CIEs (happens during linear search)
686         if (cieOffset == 0) {
687             return true;
688         }
689         // DWARF says that the CIE_pointer in the FDE is a .debug_frame-relative offset, 
690         // but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, 
691         // which is just as fine as it's self-contained
692         cieAddr = (unw_word_t)((uint64_t)cieOffsetAddr - cieOffset);
693     }
694
695     dwarf_cie_info_t dci;
696     if (!ParseCie(info, cieAddr, &dci)) {
697         return false;
698     }
699
700     unw_word_t ipStart, ipRange;
701     if (!ReadEncodedPointer(info, &addr, dci.fde_encoding, UINTPTR_MAX, &ipStart)) {
702         return false;
703     }
704
705     // IP-range has same encoding as FDE pointers, except that it's always an absolute value
706     uint8_t ipRangeEncoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
707     if (!ReadEncodedPointer(info, &addr, ipRangeEncoding, UINTPTR_MAX, &ipRange)) {
708         return false;
709     }
710     pip->start_ip = ipStart;
711     pip->end_ip = ipStart + ipRange;
712     pip->handler = dci.handler;
713
714     unw_word_t augmentationSize, augmentationEndAddr;
715     if (dci.sized_augmentation) {
716         if (!ReadULEB128(info, &addr, &augmentationSize)) {
717             return false;
718         }
719         augmentationEndAddr = addr + augmentationSize;
720     }
721
722     // Read language specific data area address
723     if (!ReadEncodedPointer(info, &addr, dci.lsda_encoding, pip->start_ip, &pip->lsda)) {
724         return false;
725     }
726
727     // Now fill out the proc info if requested
728     if (need_unwind_info)
729     {
730         if (dci.have_abi_marker)
731         {
732             if (!ReadValue16(info, &addr, &dci.abi)) {
733                 return false;
734             }
735             if (!ReadValue16(info, &addr, &dci.tag)) {
736                 return false;
737             }
738         }
739         if (dci.sized_augmentation) {
740             dci.fde_instr_start = augmentationEndAddr;
741         }
742         else {
743             dci.fde_instr_start = addr;
744         }
745         dci.fde_instr_end = fdeEndAddr;
746
747         pip->format = UNW_INFO_FORMAT_TABLE;
748         pip->unwind_info_size = sizeof(dci);
749         pip->unwind_info = malloc(sizeof(dci));
750         if (pip->unwind_info == nullptr) {
751             return -UNW_ENOMEM;
752         }
753         memcpy(pip->unwind_info, &dci, sizeof(dci));
754     }
755
756     return true;
757 }
758
759
760 static int 
761 get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
762 {
763     return -UNW_ENOINFO;
764 }
765
766 static int 
767 access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
768 {
769     if (write)
770     {
771         ASSERT("Memory write must never be called by libunwind during stackwalk\n");
772         return -UNW_EINVAL;
773     }
774     const auto *info = (libunwindInfo*)arg;
775
776     if (info->ReadMemory((PVOID)addr, valp, sizeof(*valp)))
777     {
778         return UNW_ESUCCESS;
779     }
780     else
781     {
782         return -UNW_EUNSPEC;
783     }
784 }
785
786 static int 
787 access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
788 {
789     if (write)
790     {
791         ASSERT("Register write must never be called by libunwind during stackwalk\n");
792         return -UNW_EREADONLYREG;
793     }
794
795     const auto *info = (libunwindInfo*)arg;
796     CONTEXT *winContext = info->Context;
797
798     switch (regnum)
799     {
800 #if defined(_AMD64_)
801     case UNW_REG_IP:       *valp = (unw_word_t)winContext->Rip; break;
802     case UNW_REG_SP:       *valp = (unw_word_t)winContext->Rsp; break;
803     case UNW_X86_64_RBP:   *valp = (unw_word_t)winContext->Rbp; break;
804     case UNW_X86_64_RBX:   *valp = (unw_word_t)winContext->Rbx; break;
805     case UNW_X86_64_R12:   *valp = (unw_word_t)winContext->R12; break;
806     case UNW_X86_64_R13:   *valp = (unw_word_t)winContext->R13; break;
807     case UNW_X86_64_R14:   *valp = (unw_word_t)winContext->R14; break;
808     case UNW_X86_64_R15:   *valp = (unw_word_t)winContext->R15; break;
809 #elif defined(_ARM_)
810     case UNW_ARM_R13:      *valp = (unw_word_t)winContext->Sp; break;
811     case UNW_ARM_R14:      *valp = (unw_word_t)winContext->Lr; break;
812     case UNW_ARM_R15:      *valp = (unw_word_t)winContext->Pc; break;
813     case UNW_ARM_R4:       *valp = (unw_word_t)winContext->R4; break;
814     case UNW_ARM_R5:       *valp = (unw_word_t)winContext->R5; break;
815     case UNW_ARM_R6:       *valp = (unw_word_t)winContext->R6; break;
816     case UNW_ARM_R7:       *valp = (unw_word_t)winContext->R7; break;
817     case UNW_ARM_R8:       *valp = (unw_word_t)winContext->R8; break;
818     case UNW_ARM_R9:       *valp = (unw_word_t)winContext->R9; break;
819     case UNW_ARM_R10:      *valp = (unw_word_t)winContext->R10; break;
820     case UNW_ARM_R11:      *valp = (unw_word_t)winContext->R11; break;
821 #elif defined(_ARM64_)
822     case UNW_REG_IP:       *valp = (unw_word_t)winContext->Pc; break;
823     case UNW_REG_SP:       *valp = (unw_word_t)winContext->Sp; break;
824     case UNW_AARCH64_X29:  *valp = (unw_word_t)winContext->Fp; break;
825     case UNW_AARCH64_X30:  *valp = (unw_word_t)winContext->Lr; break;
826     case UNW_AARCH64_X19:  *valp = (unw_word_t)winContext->X19; break;
827     case UNW_AARCH64_X20:  *valp = (unw_word_t)winContext->X20; break;
828     case UNW_AARCH64_X21:  *valp = (unw_word_t)winContext->X21; break;
829     case UNW_AARCH64_X22:  *valp = (unw_word_t)winContext->X22; break;
830     case UNW_AARCH64_X23:  *valp = (unw_word_t)winContext->X23; break;
831     case UNW_AARCH64_X24:  *valp = (unw_word_t)winContext->X24; break;
832     case UNW_AARCH64_X25:  *valp = (unw_word_t)winContext->X25; break;
833     case UNW_AARCH64_X26:  *valp = (unw_word_t)winContext->X26; break;
834     case UNW_AARCH64_X27:  *valp = (unw_word_t)winContext->X27; break;
835     case UNW_AARCH64_X28:  *valp = (unw_word_t)winContext->X28; break;
836 #else
837 #error unsupported architecture
838 #endif
839     default:
840         ASSERT("Attempt to read an unknown register\n");
841         return -UNW_EBADREG;
842     }
843     return UNW_ESUCCESS;
844 }
845
846 static int 
847 access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
848 {
849     ASSERT("Not supposed to be ever called\n");
850     return -UNW_EINVAL;
851 }
852
853 static int 
854 resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
855 {
856     ASSERT("Not supposed to be ever called\n");
857     return -UNW_EINVAL;
858 }
859
860 static int 
861 get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, unw_word_t *offp, void *arg)
862 {
863     ASSERT("Not supposed to be ever called\n");
864     return -UNW_EINVAL;
865 }
866
867 static int 
868 find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int need_unwind_info, void *arg)
869 {
870     const auto *info = (libunwindInfo*)arg;
871     memset(pip, 0, sizeof(*pip));
872
873     Ehdr ehdr;
874     if (!info->ReadMemory((void*)info->BaseAddress, &ehdr, sizeof(ehdr))) {
875         ERROR("ELF: reading ehdr %p\n", info->BaseAddress);
876         return -UNW_EINVAL;
877     }
878     Phdr* phdrAddr = reinterpret_cast<Phdr*>(info->BaseAddress + ehdr.e_phoff);
879     int phnum = ehdr.e_phnum;
880     TRACE("ELF: base %p ip %p e_type %d e_phnum %d e_phoff %p\n", info->BaseAddress, ip, ehdr.e_type, ehdr.e_phnum, ehdr.e_phoff);
881
882     // The eh_frame header
883     Phdr ehPhdr;
884     memset(&ehPhdr, 0, sizeof(ehPhdr));
885
886     // Search for the module's dynamic header and unwind frames
887     Dyn* dynamicAddr = nullptr;
888
889     for (int i = 0; i < phnum; i++, phdrAddr++)
890     {
891         Phdr ph;
892         if (!info->ReadMemory(phdrAddr, &ph, sizeof(ph))) {
893             ERROR("ELF: reading phdrAddr %p\n", phdrAddr);
894             return -UNW_EINVAL;
895         }
896         TRACE("ELF: phdr %p type %d (%x) vaddr %p memsz %016llx paddr %p filesz %016llx offset %p align %016llx\n",
897             phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_paddr, ph.p_filesz, ph.p_offset, ph.p_align);
898
899         switch (ph.p_type)
900         {
901         case PT_DYNAMIC:
902             if (ehdr.e_type == ET_EXEC) {
903                 dynamicAddr = reinterpret_cast<Dyn*>(ph.p_vaddr);
904             }
905             if (ehdr.e_type == ET_DYN) {
906                 dynamicAddr = reinterpret_cast<Dyn*>(ph.p_vaddr + info->BaseAddress);
907             }
908             break;
909
910         case PT_GNU_EH_FRAME:
911             ehPhdr = ph;
912             break;
913         }
914     }
915
916     if (dynamicAddr != nullptr)
917     {
918         for (;;)
919         {
920             Dyn dyn;
921             if (!info->ReadMemory(dynamicAddr, &dyn, sizeof(dyn))) {
922                 ERROR("ELF: reading dynamicAddr %p\n", dynamicAddr);
923                 return -UNW_EINVAL;
924             }
925             if (dyn.d_tag == DT_PLTGOT) {
926                 TRACE("ELF: dyn %p tag %d (%x) d_ptr %p\n", dynamicAddr, dyn.d_tag, dyn.d_tag, dyn.d_un.d_ptr);
927                 pip->gp = dyn.d_un.d_ptr;
928                 break;
929             }
930             else if (dyn.d_tag == DT_NULL) {
931                 break;
932             }
933             dynamicAddr++;
934         }
935     }
936     unw_word_t ehFrameHdrAddr = ehPhdr.p_offset + info->BaseAddress;
937     eh_frame_hdr ehFrameHdr;
938
939     if (!info->ReadMemory((PVOID)ehFrameHdrAddr, &ehFrameHdr, sizeof(eh_frame_hdr))) {
940         ERROR("ELF: reading ehFrameHdrAddr %p\n", ehFrameHdrAddr);
941         return -UNW_EINVAL;
942     }
943     TRACE("ehFrameHdrAddr %p version %d eh_frame_ptr_enc %d fde_count_enc %d table_enc %d\n", 
944         ehFrameHdrAddr, ehFrameHdr.version, ehFrameHdr.eh_frame_ptr_enc, ehFrameHdr.fde_count_enc, ehFrameHdr.table_enc);
945
946     if (ehFrameHdr.version != DW_EH_VERSION) {
947         ASSERT("ehFrameHdr version %x not supported\n", ehFrameHdr.version);
948         return -UNW_EBADVERSION;
949     }
950     unw_word_t addr = ehFrameHdrAddr + sizeof(eh_frame_hdr);
951     unw_word_t ehFrameStart;
952     unw_word_t fdeCount;
953
954     // Decode the eh_frame_hdr info
955     if (!ReadEncodedPointer(info, &addr, ehFrameHdr.eh_frame_ptr_enc, UINTPTR_MAX, &ehFrameStart)) {
956         ERROR("decoding eh_frame_ptr\n");
957         return -UNW_EINVAL;
958     }
959     if (!ReadEncodedPointer(info, &addr, ehFrameHdr.fde_count_enc, UINTPTR_MAX, &fdeCount)) {
960         ERROR("decoding fde_count_enc\n");
961         return -UNW_EINVAL;
962     }
963     TRACE("ehFrameStart %p fdeCount %p ip offset %08x\n", ehFrameStart, fdeCount, (int32_t)(ip - ehFrameHdrAddr));
964
965     // LookupTableEntry assumes this encoding
966     if (ehFrameHdr.table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
967         ASSERT("Table encoding not supported %x\n", ehFrameHdr.table_enc);
968         return -UNW_EINVAL;
969     }
970     // Find the fde using a binary search on the frame table
971     table_entry entry;
972     bool found;
973     if (!LookupTableEntry(info, ip - ehFrameHdrAddr, addr, fdeCount, &entry, &found)) {
974         ERROR("LookupTableEntry\n");
975         return -UNW_EINVAL;
976     }
977     unw_word_t fdeAddr = entry.fde_offset + ehFrameHdrAddr;
978     TRACE("start_ip %08x fde_offset %08x fdeAddr %p found %d\n", entry.start_ip, entry.fde_offset, fdeAddr, found);
979
980     // Unwind info not found
981     if (!found) {
982         return -UNW_ENOINFO;
983     }
984
985     // Now get the unwind info
986     if (!ExtractProcInfoFromFde(info, &fdeAddr, pip, need_unwind_info)) {
987         ERROR("ExtractProcInfoFromFde\n");
988         return -UNW_EINVAL;
989     }
990
991     _ASSERTE(ip >= pip->start_ip && ip <= pip->end_ip);
992     return UNW_ESUCCESS;
993 }
994
995 static void 
996 put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
997 {
998     if (pip->unwind_info != nullptr) {
999         free(pip->unwind_info);
1000         pip->unwind_info = nullptr;
1001     }
1002 }
1003
1004 static unw_accessors_t unwind_accessors =
1005 {
1006     .find_proc_info = find_proc_info,
1007     .put_unwind_info = put_unwind_info,
1008     .get_dyn_info_list_addr = get_dyn_info_list_addr,
1009     .access_mem = access_mem,
1010     .access_reg = access_reg,
1011     .access_fpreg = access_fpreg,
1012     .resume = resume,
1013     .get_proc_name = get_proc_name
1014 };
1015
1016 /*++
1017 Function:
1018     PAL_VirtualUnwindOutOfProc
1019
1020     Unwind the stack given the context for a "remote" target using the
1021     provided read memory callback.
1022
1023     Assumes the IP is in the module of the base address provided (coreclr).
1024
1025 Parameters:
1026     context - the start context in the target
1027     contextPointers - the context of the next frame
1028     baseAddress - base address of the module to find the unwind info
1029     readMemoryCallback - reads memory from the target
1030 --*/
1031 BOOL
1032 PALAPI
1033 PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
1034 {
1035     unw_addr_space_t addrSpace = 0;
1036     unw_cursor_t cursor;
1037     libunwindInfo info;
1038     BOOL result = FALSE;
1039     int st;
1040
1041     info.BaseAddress = baseAddress;
1042     info.Context = context;
1043     info.ReadMemory = readMemoryCallback;
1044
1045     addrSpace = unw_create_addr_space(&unwind_accessors, 0);
1046
1047     st = unw_init_remote(&cursor, addrSpace, &info);
1048     if (st < 0)
1049     {
1050         result = FALSE;
1051         goto exit;
1052     }
1053
1054     st = unw_step(&cursor);
1055     if (st < 0)
1056     {
1057         result = FALSE;
1058         goto exit;
1059     }
1060
1061     UnwindContextToWinContext(&cursor, context);
1062
1063     if (contextPointers != NULL)
1064     {
1065         GetContextPointers(&cursor, NULL, contextPointers);
1066     }
1067     result = TRUE;
1068
1069 exit:
1070     if (addrSpace != 0)
1071     {
1072         unw_destroy_addr_space(addrSpace);
1073     }
1074     return result;
1075 }
1076
1077 #else
1078
1079 BOOL
1080 PALAPI
1081 PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
1082 {
1083     return FALSE;
1084 }
1085
1086 #endif // defined(_AMD64_) && defined(HAVE_UNW_GET_ACCESSORS)