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.
13 Implementation of out of context unwind using libunwind8
16 This file contains code based on libunwind8
18 Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
19 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
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:
29 The above copyright notice and this permission notice shall be
30 included in all copies or substantial portions of the Software.
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.
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"
53 #define UNW_LOCAL_ONLY
55 #include <libunwind.h>
56 #endif // HAVE_LIBUNWIND_H
58 SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
60 // Only used on the AMD64 build
61 #if defined(_AMD64_) && defined(HAVE_UNW_GET_ACCESSORS)
66 #define Ehdr ElfW(Ehdr)
67 #define Phdr ElfW(Phdr)
68 #define Shdr ElfW(Shdr)
69 #define Nhdr ElfW(Nhdr)
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);
75 typedef struct _libunwindInfo
79 UnwindReadMemoryCallback ReadMemory;
82 #define DW_EH_VERSION 1
84 // DWARF Pointer-Encoding (PEs).
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/).
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
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
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
117 #define DW_EH_PE_funcrel 0x40 // start-of-procedure-relative
118 #define DW_EH_PE_aligned 0x50 // aligned pointer
120 #define DWARF_CIE_VERSION 3 // GCC emits version 1???
122 // DWARF frame header
123 typedef struct _eh_frame_hdr
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:
132 // encoded_t eh_frame_ptr;
133 // encoded_t fde_count;
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];
141 // "DW_EH_PE_datarel|DW_EH_PE_sdata4" encoded fde table entry
142 typedef struct _table_entry
149 typedef struct dwarf_cie_info
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
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;
169 ReadValue8(const libunwindInfo* info, unw_word_t* addr, uint8_t* valp)
172 if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
175 *addr += sizeof(value);
181 ReadValue16(const libunwindInfo* info, unw_word_t* addr, uint16_t* valp)
184 if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
187 *addr += sizeof(value);
188 *valp = VAL16(value);
193 ReadValue32(const libunwindInfo* info, unw_word_t* addr, uint32_t* valp)
196 if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
199 *addr += sizeof(value);
200 *valp = VAL32(value);
205 ReadValue64(const libunwindInfo* info, unw_word_t* addr, uint64_t* valp)
208 if (!info->ReadMemory((PVOID)*addr, &value, sizeof(value))) {
211 *addr += sizeof(value);
212 *valp = VAL64(value);
217 ReadPointer(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
221 if (ReadValue64(info, addr, &val64)) {
227 if (ReadValue32(info, addr, &val32)) {
235 // Read a unsigned "little-endian base 128" value. See Chapter 7.6 of DWARF spec v3.
237 ReadULEB128(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
239 unw_word_t value = 0;
245 if (!ReadValue8(info, addr, &byte)) {
248 value |= ((unw_word_t)byte & 0x7f) << shift;
250 } while (byte & 0x80);
256 // Read a signed "little-endian base 128" value. See Chapter 7.6 of DWARF spec v3.
258 ReadSLEB128(const libunwindInfo* info, unw_word_t* addr, unw_word_t* valp)
260 unw_word_t value = 0;
266 if (!ReadValue8(info, addr, &byte)) {
269 value |= ((unw_word_t)byte & 0x7f) << shift;
271 } while (byte & 0x80);
273 if ((shift < (8 * sizeof(unw_word_t))) && ((byte & 0x40) != 0)) {
274 value |= ((unw_word_t)-1) << shift;
282 ReadEncodedPointer(const libunwindInfo* info, unw_word_t* addr, unsigned char encoding, unw_word_t funcRel, unw_word_t* valp)
284 unw_word_t initialAddr = *addr;
290 if (encoding == DW_EH_PE_omit)
295 else if (encoding == DW_EH_PE_aligned)
297 int size = sizeof(unw_word_t);
298 *addr = (initialAddr + size - 1) & -size;
299 return ReadPointer(info, addr, valp);
302 switch (encoding & DW_EH_PE_FORMAT_MASK)
305 if (!ReadPointer(info, addr, &value)) {
310 case DW_EH_PE_uleb128:
311 if (!ReadULEB128(info, addr, &value)) {
316 case DW_EH_PE_sleb128:
317 if (!ReadSLEB128(info, addr, &value)) {
322 case DW_EH_PE_udata2:
323 if (!ReadValue16(info, addr, &value16)) {
329 case DW_EH_PE_udata4:
330 if (!ReadValue32(info, addr, &value32)) {
336 case DW_EH_PE_udata8:
337 if (!ReadValue64(info, addr, &value64)) {
343 case DW_EH_PE_sdata2:
344 if (!ReadValue16(info, addr, &value16)) {
347 value = (int16_t)value16;
350 case DW_EH_PE_sdata4:
351 if (!ReadValue32(info, addr, &value32)) {
354 value = (int32_t)value32;
357 case DW_EH_PE_sdata8:
358 if (!ReadValue64(info, addr, &value64)) {
361 value = (int64_t)value64;
365 ASSERT("ReadEncodedPointer: invalid encoding format %x\n", encoding);
369 // 0 is a special value and always absolute
375 switch (encoding & DW_EH_PE_APPL_MASK)
377 case DW_EH_PE_absptr:
381 value += initialAddr;
384 case DW_EH_PE_funcrel:
385 _ASSERTE(funcRel != UINTPTR_MAX);
389 case DW_EH_PE_textrel:
390 case DW_EH_PE_datarel:
392 ASSERT("ReadEncodedPointer: invalid application type %x\n", encoding);
396 if (encoding & DW_EH_PE_indirect)
398 unw_word_t indirect_addr = value;
399 if (!ReadPointer(info, &indirect_addr, &value)) {
409 LookupTableEntry(const libunwindInfo* info, int32_t ip, unw_word_t tableAddr, size_t tableCount, table_entry* entry, bool* found)
411 size_t low, high, mid;
417 // do a binary search on table
418 for (low = 0, high = tableCount; low < high;)
420 mid = (low + high) / 2;
421 addr = tableAddr + (mid * sizeof(table_entry));
423 if (!ReadValue32(info, &addr, (uint32_t*)&start_ip)) {
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)) {
448 ParseCie(const libunwindInfo* info, unw_word_t addr, dwarf_cie_info_t* dci)
450 uint8_t ch, version, fdeEncoding, handlerEncoding;
451 unw_word_t cieLength, cieEndAddr;
455 memset(dci, 0, sizeof (*dci));
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
463 fdeEncoding = DW_EH_PE_udata8;
465 fdeEncoding = DW_EH_PE_udata4;
468 dci->lsda_encoding = DW_EH_PE_omit;
471 if (!ReadValue32(info, &addr, &value32)) {
475 if (value32 != 0xffffffff)
477 // The CIE is in the 32-bit DWARF format
480 // DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0
481 const uint32_t expectedId = 0;
484 cieEndAddr = addr + cieLength;
486 if (!ReadValue32(info, &addr, &cieId)) {
489 if (cieId != expectedId) {
490 ASSERT("ParseCie: unexpected cie id %x\n", cieId);
496 // The CIE is in the 64-bit DWARF format
499 // DWARF says CIE id should be 0xffffffffffffffff, but in .eh_frame, it's 0
500 const uint64_t expectedId = 0;
502 if (!ReadValue64(info, &addr, &value64)) {
506 cieEndAddr = addr + cieLength;
508 if (!ReadValue64(info, &addr, &cieId)) {
511 if (cieId != expectedId) {
512 ASSERT("ParseCie: unexpected cie id %lx\n", cieId);
516 dci->cie_instr_end = cieEndAddr;
518 if (!ReadValue8(info, &addr, &version)) {
521 if (version != 1 && version != DWARF_CIE_VERSION) {
522 ASSERT("ParseCie: invalid cie version %x\n", version);
526 // Read the augmentation string
527 uint8_t augmentationString[8];
528 memset(augmentationString, 0, sizeof(augmentationString));
530 for (int i = 0; i < sizeof(augmentationString); i++)
532 if (!ReadValue8(info, &addr, &ch)) {
538 augmentationString[i] = ch;
541 // Read the code and data alignment
542 if (!ReadULEB128(info, &addr, &dci->code_align)) {
545 if (!ReadSLEB128(info, &addr, &dci->data_align)) {
549 // Read the return-address column either as a u8 or as a uleb128
552 if (!ReadValue8(info, &addr, &ch)) {
555 dci->ret_addr_column = ch;
559 if (!ReadULEB128(info, &addr, &dci->ret_addr_column)) {
564 // Parse the augmentation string
565 for (int i = 0; i < sizeof(augmentationString); i++)
568 unw_word_t augmentationSize;
570 switch (augmentationString[i])
577 dci->sized_augmentation = 1;
578 if (!ReadULEB128(info, &addr, &augmentationSize)) {
584 // read the LSDA pointer-encoding format
585 if (!ReadValue8(info, &addr, &ch)) {
588 dci->lsda_encoding = ch;
592 // read the FDE pointer-encoding format
593 if (!ReadValue8(info, &addr, &fdeEncoding)) {
599 // read the personality-routine pointer-encoding format
600 if (!ReadValue8(info, &addr, &handlerEncoding)) {
603 if (!ReadEncodedPointer(info, &addr, handlerEncoding, UINTPTR_MAX, &dci->handler)) {
609 // This is a signal frame
610 dci->signal_frame = 1;
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;
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
624 ASSERT("ParseCie: unexpected argumentation string '%s'\n", augmentationString[i]);
632 dci->fde_encoding = fdeEncoding;
633 dci->cie_instr_start = addr;
638 ExtractProcInfoFromFde(const libunwindInfo* info, unw_word_t* addrp, unw_proc_info_t *pip, int need_unwind_info)
640 unw_word_t addr = *addrp, fdeEndAddr, cieOffsetAddr, cieAddr;
644 if (!ReadValue32(info, &addr, &value32)) {
647 if (value32 != 0xffffffff)
649 int32_t cieOffset = 0;
651 // In some configurations, an FDE with a 0 length indicates the end of the FDE-table
655 // the FDE is in the 32-bit DWARF format */
656 *addrp = fdeEndAddr = addr + value32;
657 cieOffsetAddr = addr;
659 if (!ReadValue32(info, &addr, (uint32_t*)&cieOffset)) {
662 // Ignore CIEs (happens during linear search)
663 if (cieOffset == 0) {
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;
673 int64_t cieOffset = 0;
675 // the FDE is in the 64-bit DWARF format */
676 if (!ReadValue64(info, &addr, (uint64_t*)&value64)) {
679 *addrp = fdeEndAddr = addr + value64;
680 cieOffsetAddr = addr;
682 if (!ReadValue64(info, &addr, (uint64_t*)&cieOffset)) {
685 // Ignore CIEs (happens during linear search)
686 if (cieOffset == 0) {
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);
695 dwarf_cie_info_t dci;
696 if (!ParseCie(info, cieAddr, &dci)) {
700 unw_word_t ipStart, ipRange;
701 if (!ReadEncodedPointer(info, &addr, dci.fde_encoding, UINTPTR_MAX, &ipStart)) {
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)) {
710 pip->start_ip = ipStart;
711 pip->end_ip = ipStart + ipRange;
712 pip->handler = dci.handler;
714 unw_word_t augmentationSize, augmentationEndAddr;
715 if (dci.sized_augmentation) {
716 if (!ReadULEB128(info, &addr, &augmentationSize)) {
719 augmentationEndAddr = addr + augmentationSize;
722 // Read language specific data area address
723 if (!ReadEncodedPointer(info, &addr, dci.lsda_encoding, pip->start_ip, &pip->lsda)) {
727 // Now fill out the proc info if requested
728 if (need_unwind_info)
730 if (dci.have_abi_marker)
732 if (!ReadValue16(info, &addr, &dci.abi)) {
735 if (!ReadValue16(info, &addr, &dci.tag)) {
739 if (dci.sized_augmentation) {
740 dci.fde_instr_start = augmentationEndAddr;
743 dci.fde_instr_start = addr;
745 dci.fde_instr_end = fdeEndAddr;
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) {
753 memcpy(pip->unwind_info, &dci, sizeof(dci));
761 get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
767 access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
771 ASSERT("Memory write must never be called by libunwind during stackwalk\n");
774 const auto *info = (libunwindInfo*)arg;
776 if (info->ReadMemory((PVOID)addr, valp, sizeof(*valp)))
787 access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
791 ASSERT("Register write must never be called by libunwind during stackwalk\n");
792 return -UNW_EREADONLYREG;
795 const auto *info = (libunwindInfo*)arg;
796 CONTEXT *winContext = info->Context;
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;
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;
837 #error unsupported architecture
840 ASSERT("Attempt to read an unknown register\n");
847 access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
849 ASSERT("Not supposed to be ever called\n");
854 resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
856 ASSERT("Not supposed to be ever called\n");
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)
863 ASSERT("Not supposed to be ever called\n");
868 find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int need_unwind_info, void *arg)
870 const auto *info = (libunwindInfo*)arg;
871 memset(pip, 0, sizeof(*pip));
874 if (!info->ReadMemory((void*)info->BaseAddress, &ehdr, sizeof(ehdr))) {
875 ERROR("ELF: reading ehdr %p\n", info->BaseAddress);
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);
882 // The eh_frame header
884 memset(&ehPhdr, 0, sizeof(ehPhdr));
886 // Search for the module's dynamic header and unwind frames
887 Dyn* dynamicAddr = nullptr;
889 for (int i = 0; i < phnum; i++, phdrAddr++)
892 if (!info->ReadMemory(phdrAddr, &ph, sizeof(ph))) {
893 ERROR("ELF: reading phdrAddr %p\n", phdrAddr);
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);
902 if (ehdr.e_type == ET_EXEC) {
903 dynamicAddr = reinterpret_cast<Dyn*>(ph.p_vaddr);
905 if (ehdr.e_type == ET_DYN) {
906 dynamicAddr = reinterpret_cast<Dyn*>(ph.p_vaddr + info->BaseAddress);
910 case PT_GNU_EH_FRAME:
916 if (dynamicAddr != nullptr)
921 if (!info->ReadMemory(dynamicAddr, &dyn, sizeof(dyn))) {
922 ERROR("ELF: reading dynamicAddr %p\n", dynamicAddr);
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;
930 else if (dyn.d_tag == DT_NULL) {
936 unw_word_t ehFrameHdrAddr = ehPhdr.p_offset + info->BaseAddress;
937 eh_frame_hdr ehFrameHdr;
939 if (!info->ReadMemory((PVOID)ehFrameHdrAddr, &ehFrameHdr, sizeof(eh_frame_hdr))) {
940 ERROR("ELF: reading ehFrameHdrAddr %p\n", ehFrameHdrAddr);
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);
946 if (ehFrameHdr.version != DW_EH_VERSION) {
947 ASSERT("ehFrameHdr version %x not supported\n", ehFrameHdr.version);
948 return -UNW_EBADVERSION;
950 unw_word_t addr = ehFrameHdrAddr + sizeof(eh_frame_hdr);
951 unw_word_t ehFrameStart;
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");
959 if (!ReadEncodedPointer(info, &addr, ehFrameHdr.fde_count_enc, UINTPTR_MAX, &fdeCount)) {
960 ERROR("decoding fde_count_enc\n");
963 TRACE("ehFrameStart %p fdeCount %p ip offset %08x\n", ehFrameStart, fdeCount, (int32_t)(ip - ehFrameHdrAddr));
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);
970 // Find the fde using a binary search on the frame table
973 if (!LookupTableEntry(info, ip - ehFrameHdrAddr, addr, fdeCount, &entry, &found)) {
974 ERROR("LookupTableEntry\n");
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);
980 // Unwind info not found
985 // Now get the unwind info
986 if (!ExtractProcInfoFromFde(info, &fdeAddr, pip, need_unwind_info)) {
987 ERROR("ExtractProcInfoFromFde\n");
991 _ASSERTE(ip >= pip->start_ip && ip <= pip->end_ip);
996 put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
998 if (pip->unwind_info != nullptr) {
999 free(pip->unwind_info);
1000 pip->unwind_info = nullptr;
1004 static unw_accessors_t unwind_accessors =
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,
1013 .get_proc_name = get_proc_name
1018 PAL_VirtualUnwindOutOfProc
1020 Unwind the stack given the context for a "remote" target using the
1021 provided read memory callback.
1023 Assumes the IP is in the module of the base address provided (coreclr).
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
1033 PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
1035 unw_addr_space_t addrSpace = 0;
1036 unw_cursor_t cursor;
1038 BOOL result = FALSE;
1041 info.BaseAddress = baseAddress;
1042 info.Context = context;
1043 info.ReadMemory = readMemoryCallback;
1045 addrSpace = unw_create_addr_space(&unwind_accessors, 0);
1047 st = unw_init_remote(&cursor, addrSpace, &info);
1054 st = unw_step(&cursor);
1061 UnwindContextToWinContext(&cursor, context);
1063 if (contextPointers != NULL)
1065 GetContextPointers(&cursor, NULL, contextPointers);
1072 unw_destroy_addr_space(addrSpace);
1081 PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
1086 #endif // defined(_AMD64_) && defined(HAVE_UNW_GET_ACCESSORS)