blob: cfceac29537f9f499a4e98bdf5c24c586f8616d6 [file] [log] [blame]
Louis Dionne7f068e52021-11-17 16:25:01 -05001//===----------------------------------------------------------------------===//
Saleem Abdulrasool17552662015-04-24 19:39:17 +00002//
Chandler Carruth61860a52019-01-19 10:56:40 +00003// 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
Saleem Abdulrasool17552662015-04-24 19:39:17 +00006//
7//
8// Abstracts accessing local vs remote address spaces.
9//
10//===----------------------------------------------------------------------===//
11
12#ifndef __ADDRESSSPACE_HPP__
13#define __ADDRESSSPACE_HPP__
14
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
Ryan Prichardc155d182020-08-19 01:54:17 -070020#include "libunwind.h"
21#include "config.h"
22#include "dwarf2.h"
23#include "EHHeaderParser.hpp"
24#include "Registers.hpp"
25
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +000026#ifndef _LIBUNWIND_USE_DLADDR
27 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
28 #define _LIBUNWIND_USE_DLADDR 1
29 #else
30 #define _LIBUNWIND_USE_DLADDR 0
31 #endif
32#endif
33
34#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +000035#include <dlfcn.h>
Michał Górnyf939ab72019-11-30 15:13:56 +010036#if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
Petr Hosek7b727032019-05-30 01:34:41 +000037#pragma comment(lib, "dl")
38#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +000039#endif
40
Ryan Prichard2a4f1362019-10-18 19:59:22 +000041#if defined(_LIBUNWIND_ARM_EHABI)
42struct EHABIIndexEntry {
43 uint32_t functionOffset;
44 uint32_t data;
45};
46#endif
47
John Baldwin67737ec2017-09-21 21:28:48 +000048#ifdef __APPLE__
49
50 struct dyld_unwind_sections
51 {
52 const struct mach_header* mh;
53 const void* dwarf_section;
54 uintptr_t dwarf_section_length;
55 const void* compact_unwind_section;
56 uintptr_t compact_unwind_section_length;
57 };
John Baldwin67737ec2017-09-21 21:28:48 +000058
Steven Wu8d1344f2020-08-17 14:08:50 -070059 // In 10.7.0 or later, libSystem.dylib implements this function.
60 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
John Baldwin67737ec2017-09-21 21:28:48 +000061
whitequarkffd92e52017-12-25 17:05:07 +000062#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
63
64// When statically linked on bare-metal, the symbols for the EH table are looked
65// up without going through the dynamic loader.
66
67// The following linker script may be used to produce the necessary sections and symbols.
68// Unless the --eh-frame-hdr linker option is provided, the section is not generated
69// and does not take space in the output file.
70//
71// .eh_frame :
72// {
73// __eh_frame_start = .;
74// KEEP(*(.eh_frame))
75// __eh_frame_end = .;
76// }
77//
78// .eh_frame_hdr :
79// {
80// KEEP(*(.eh_frame_hdr))
81// }
82//
83// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
84// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
85
86extern char __eh_frame_start;
87extern char __eh_frame_end;
88
89#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
90extern char __eh_frame_hdr_start;
91extern char __eh_frame_hdr_end;
92#endif
93
John Baldwin67737ec2017-09-21 21:28:48 +000094#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
95
96// When statically linked on bare-metal, the symbols for the EH table are looked
97// up without going through the dynamic loader.
98extern char __exidx_start;
99extern char __exidx_end;
100
Ryan Prichard7629c302020-08-27 23:46:49 -0700101#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
John Baldwin67737ec2017-09-21 21:28:48 +0000102
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000103#include <windows.h>
104#include <psapi.h>
Ryan Prichard7629c302020-08-27 23:46:49 -0700105
106#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
107 defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
108
109#include <link.h>
John Baldwin67737ec2017-09-21 21:28:48 +0000110
111#endif
112
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000113namespace libunwind {
114
115/// Used by findUnwindSections() to return info about needed sections.
116struct UnwindInfoSections {
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700117#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
118 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
119 defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
120 // No dso_base for SEH.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000121 uintptr_t dso_base;
122#endif
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700123#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Ryan Prichard0cff8572020-09-16 01:22:55 -0700124 uintptr_t text_segment_length;
125#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000126#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000127 uintptr_t dwarf_section;
128 uintptr_t dwarf_section_length;
129#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000130#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000131 uintptr_t dwarf_index_section;
132 uintptr_t dwarf_index_section_length;
133#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000134#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000135 uintptr_t compact_unwind_section;
136 uintptr_t compact_unwind_section_length;
137#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000138#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000139 uintptr_t arm_section;
140 uintptr_t arm_section_length;
141#endif
142};
143
144
145/// LocalAddressSpace is used as a template parameter to UnwindCursor when
146/// unwinding a thread in the same process. The wrappers compile away,
147/// making local unwinds fast.
Charles Davis04f0c2e2018-08-31 13:41:05 +0000148class _LIBUNWIND_HIDDEN LocalAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000149public:
Martin Storsjocac41382017-10-27 08:11:36 +0000150 typedef uintptr_t pint_t;
151 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000152 uint8_t get8(pint_t addr) {
153 uint8_t val;
154 memcpy(&val, (void *)addr, sizeof(val));
155 return val;
156 }
157 uint16_t get16(pint_t addr) {
158 uint16_t val;
159 memcpy(&val, (void *)addr, sizeof(val));
160 return val;
161 }
162 uint32_t get32(pint_t addr) {
163 uint32_t val;
164 memcpy(&val, (void *)addr, sizeof(val));
165 return val;
166 }
167 uint64_t get64(pint_t addr) {
168 uint64_t val;
169 memcpy(&val, (void *)addr, sizeof(val));
170 return val;
171 }
172 double getDouble(pint_t addr) {
173 double val;
174 memcpy(&val, (void *)addr, sizeof(val));
175 return val;
176 }
177 v128 getVector(pint_t addr) {
178 v128 val;
179 memcpy(&val, (void *)addr, sizeof(val));
180 return val;
181 }
182 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000183 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000184 static uint64_t getULEB128(pint_t &addr, pint_t end);
185 static int64_t getSLEB128(pint_t &addr, pint_t end);
186
187 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
188 pint_t datarelBase = 0);
189 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
190 unw_word_t *offset);
191 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
192 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
193
194 static LocalAddressSpace sThisAddressSpace;
195};
196
197inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000198#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000199 return get64(addr);
200#else
201 return get32(addr);
202#endif
203}
204
John Baldwin1a6e6be2018-02-27 21:24:02 +0000205inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
206#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
207 return get64(addr);
208#else
209 return get32(addr);
210#endif
211}
212
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000213/// Read a ULEB128 into a 64-bit word.
214inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
215 const uint8_t *p = (uint8_t *)addr;
216 const uint8_t *pend = (uint8_t *)end;
217 uint64_t result = 0;
218 int bit = 0;
219 do {
220 uint64_t b;
221
222 if (p == pend)
223 _LIBUNWIND_ABORT("truncated uleb128 expression");
224
225 b = *p & 0x7f;
226
227 if (bit >= 64 || b << bit >> bit != b) {
228 _LIBUNWIND_ABORT("malformed uleb128 expression");
229 } else {
230 result |= b << bit;
231 bit += 7;
232 }
233 } while (*p++ >= 0x80);
234 addr = (pint_t) p;
235 return result;
236}
237
238/// Read a SLEB128 into a 64-bit word.
239inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
240 const uint8_t *p = (uint8_t *)addr;
241 const uint8_t *pend = (uint8_t *)end;
242 int64_t result = 0;
243 int bit = 0;
244 uint8_t byte;
245 do {
246 if (p == pend)
247 _LIBUNWIND_ABORT("truncated sleb128 expression");
248 byte = *p++;
Ryan Prichardc2174592020-07-13 22:06:47 -0700249 result |= (uint64_t)(byte & 0x7f) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000250 bit += 7;
251 } while (byte & 0x80);
252 // sign extend negative numbers
Ryan Prichardc2174592020-07-13 22:06:47 -0700253 if ((byte & 0x40) != 0 && bit < 64)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000254 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000255 addr = (pint_t) p;
256 return result;
257}
258
259inline LocalAddressSpace::pint_t
260LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
261 pint_t datarelBase) {
262 pint_t startAddr = addr;
263 const uint8_t *p = (uint8_t *)addr;
264 pint_t result;
265
266 // first get value
267 switch (encoding & 0x0F) {
268 case DW_EH_PE_ptr:
269 result = getP(addr);
270 p += sizeof(pint_t);
271 addr = (pint_t) p;
272 break;
273 case DW_EH_PE_uleb128:
274 result = (pint_t)getULEB128(addr, end);
275 break;
276 case DW_EH_PE_udata2:
277 result = get16(addr);
278 p += 2;
279 addr = (pint_t) p;
280 break;
281 case DW_EH_PE_udata4:
282 result = get32(addr);
283 p += 4;
284 addr = (pint_t) p;
285 break;
286 case DW_EH_PE_udata8:
287 result = (pint_t)get64(addr);
288 p += 8;
289 addr = (pint_t) p;
290 break;
291 case DW_EH_PE_sleb128:
292 result = (pint_t)getSLEB128(addr, end);
293 break;
294 case DW_EH_PE_sdata2:
295 // Sign extend from signed 16-bit value.
296 result = (pint_t)(int16_t)get16(addr);
297 p += 2;
298 addr = (pint_t) p;
299 break;
300 case DW_EH_PE_sdata4:
301 // Sign extend from signed 32-bit value.
302 result = (pint_t)(int32_t)get32(addr);
303 p += 4;
304 addr = (pint_t) p;
305 break;
306 case DW_EH_PE_sdata8:
307 result = (pint_t)get64(addr);
308 p += 8;
309 addr = (pint_t) p;
310 break;
311 default:
312 _LIBUNWIND_ABORT("unknown pointer encoding");
313 }
314
315 // then add relative offset
316 switch (encoding & 0x70) {
317 case DW_EH_PE_absptr:
318 // do nothing
319 break;
320 case DW_EH_PE_pcrel:
321 result += startAddr;
322 break;
323 case DW_EH_PE_textrel:
324 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
325 break;
326 case DW_EH_PE_datarel:
327 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
328 // default value of 0, and we abort in the event that someone calls this
329 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
330 if (datarelBase == 0)
331 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
332 result += datarelBase;
333 break;
334 case DW_EH_PE_funcrel:
335 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
336 break;
337 case DW_EH_PE_aligned:
338 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
339 break;
340 default:
341 _LIBUNWIND_ABORT("unknown pointer encoding");
342 break;
343 }
344
345 if (encoding & DW_EH_PE_indirect)
346 result = getP(result);
347
348 return result;
349}
350
Ryan Prichard7629c302020-08-27 23:46:49 -0700351#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Sterling Augustine6d474102020-03-04 12:41:54 -0800352
Ryan Prichard7629c302020-08-27 23:46:49 -0700353// The ElfW() macro for pointer-size independent ELF header traversal is not
354// provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
355// data structures are just called Elf_XXX. Define ElfW() locally.
356#if !defined(ElfW)
357 #define ElfW(type) Elf_##type
358#endif
Sterling Augustine6d474102020-03-04 12:41:54 -0800359#if !defined(Elf_Half)
360 typedef ElfW(Half) Elf_Half;
361#endif
362#if !defined(Elf_Phdr)
363 typedef ElfW(Phdr) Elf_Phdr;
364#endif
365#if !defined(Elf_Addr)
366 typedef ElfW(Addr) Elf_Addr;
367#endif
368
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800369static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800370 Elf_Addr image_base = pinfo->dlpi_addr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800371#if defined(__ANDROID__) && __ANDROID_API__ < 18
372 if (image_base == 0) {
373 // Normally, an image base of 0 indicates a non-PIE executable. On
374 // versions of Android prior to API 18, the dynamic linker reported a
375 // dlpi_addr of 0 for PIE executables. Compute the true image base
376 // using the PT_PHDR segment.
377 // See https://github.com/android/ndk/issues/505.
378 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
379 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
380 if (phdr->p_type == PT_PHDR) {
381 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
382 phdr->p_vaddr;
383 break;
384 }
385 }
386 }
387#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800388 return image_base;
389}
Sterling Augustine6d474102020-03-04 12:41:54 -0800390
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800391struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
392 LocalAddressSpace *addressSpace;
393 UnwindInfoSections *sects;
394 uintptr_t targetAddr;
395};
396
Sterling Augustineb778c912020-08-18 12:05:07 -0700397#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700398#include "FrameHeaderCache.hpp"
399
Ryan Prichardc155d182020-08-19 01:54:17 -0700400// Typically there is one cache per process, but when libunwind is built as a
401// hermetic static library, then each shared object may have its own cache.
402static FrameHeaderCache TheFrameHeaderCache;
Sterling Augustineb778c912020-08-18 12:05:07 -0700403#endif
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700404
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800405static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
406 dl_iterate_cb_data *cbdata) {
407 if (phdr->p_type == PT_LOAD) {
408 uintptr_t begin = image_base + phdr->p_vaddr;
409 uintptr_t end = begin + phdr->p_memsz;
410 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
411 cbdata->sects->dso_base = begin;
Ryan Prichard0cff8572020-09-16 01:22:55 -0700412 cbdata->sects->text_segment_length = phdr->p_memsz;
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800413 return true;
414 }
415 }
416 return false;
417}
418
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700419static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
420 dl_iterate_cb_data *cbdata) {
421#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
422 if (phdr->p_type == PT_GNU_EH_FRAME) {
423 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
424 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
425 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
426 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
427 if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
428 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
429 hdrInfo)) {
430 // .eh_frame_hdr records the start of .eh_frame, but not its size.
431 // Rely on a zero terminator to find the end of the section.
432 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
433 cbdata->sects->dwarf_section_length = UINTPTR_MAX;
434 return true;
435 }
436 }
437 return false;
438#elif defined(_LIBUNWIND_ARM_EHABI)
439 if (phdr->p_type == PT_ARM_EXIDX) {
440 uintptr_t exidx_start = image_base + phdr->p_vaddr;
441 cbdata->sects->arm_section = exidx_start;
442 cbdata->sects->arm_section_length = phdr->p_memsz;
443 return true;
444 }
445 return false;
446#else
447#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
448#endif
449}
450
Ryan Prichard6de71032020-08-22 17:12:52 -0700451static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
452 size_t pinfo_size, void *data) {
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800453 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
454 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800455 return 0;
Sterling Augustineb778c912020-08-18 12:05:07 -0700456#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Ryan Prichardc155d182020-08-19 01:54:17 -0700457 if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700458 return 1;
Mikael Holmen7c371492020-08-25 12:26:48 +0200459#else
460 // Avoid warning about unused variable.
461 (void)pinfo_size;
Sterling Augustineb778c912020-08-18 12:05:07 -0700462#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800463
464 Elf_Addr image_base = calculateImageBase(pinfo);
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700465
466 // Most shared objects seen in this callback function likely don't contain the
467 // target address, so optimize for that. Scan for a matching PT_LOAD segment
468 // first and bail when it isn't found.
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700469 bool found_text = false;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700470 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
471 if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700472 found_text = true;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700473 break;
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700474 }
Sterling Augustine6d474102020-03-04 12:41:54 -0800475 }
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700476 if (!found_text)
477 return 0;
478
479 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
480 // backward.
481 bool found_unwind = false;
482 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
483 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
484 if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
485 found_unwind = true;
486 break;
487 }
488 }
489 if (!found_unwind)
490 return 0;
491
492#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
493 TheFrameHeaderCache.add(cbdata->sects);
494#endif
495 return 1;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800496}
497
Ryan Prichard7629c302020-08-27 23:46:49 -0700498#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Sterling Augustine6d474102020-03-04 12:41:54 -0800499
500
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000501inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
502 UnwindInfoSections &info) {
503#ifdef __APPLE__
504 dyld_unwind_sections dyldInfo;
505 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
506 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000507 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000508 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
509 info.dwarf_section_length = dyldInfo.dwarf_section_length;
510 #endif
511 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
512 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
513 return true;
514 }
whitequarkffd92e52017-12-25 17:05:07 +0000515#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
Ryan Prichard2cfcb8c2020-09-09 15:43:35 -0700516 info.dso_base = 0;
whitequarkffd92e52017-12-25 17:05:07 +0000517 // Bare metal is statically linked, so no need to ask the dynamic loader
518 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
519 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000520 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
521 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000522#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
523 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
524 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000525 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
526 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000527#endif
528 if (info.dwarf_section_length)
529 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000530#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000531 // Bare metal is statically linked, so no need to ask the dynamic loader
532 info.arm_section = (uintptr_t)(&__exidx_start);
533 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000534 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
535 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000536 if (info.arm_section && info.arm_section_length)
537 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000538#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
539 HMODULE mods[1024];
540 HANDLE process = GetCurrentProcess();
541 DWORD needed;
542
Martin Storsjöa914ec12019-10-28 10:11:05 +0200543 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
544 DWORD err = GetLastError();
545 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
546 "returned error %d", (int)err);
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000547 return false;
Martin Storsjöa914ec12019-10-28 10:11:05 +0200548 }
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000549
550 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
551 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
552 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
553 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
554 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
555 bool found_obj = false;
556 bool found_hdr = false;
557
558 info.dso_base = (uintptr_t)mods[i];
559 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
560 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
561 uintptr_t end = begin + pish->Misc.VirtualSize;
562 if (!strncmp((const char *)pish->Name, ".text",
563 IMAGE_SIZEOF_SHORT_NAME)) {
564 if (targetAddr >= begin && targetAddr < end)
565 found_obj = true;
566 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
567 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000568 info.dwarf_section = begin;
569 info.dwarf_section_length = pish->Misc.VirtualSize;
570 found_hdr = true;
571 }
572 if (found_obj && found_hdr)
573 return true;
574 }
575 }
576 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000577#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
578 // Don't even bother, since Windows has functions that do all this stuff
579 // for us.
Martin Storsjo059a1632019-01-22 22:12:23 +0000580 (void)targetAddr;
581 (void)info;
Charles Davisfa2e6202018-08-30 21:29:00 +0000582 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700583#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000584 int length = 0;
585 info.arm_section =
586 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
Ryan Prichard2a4f1362019-10-18 19:59:22 +0000587 info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000588 if (info.arm_section && info.arm_section_length)
589 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700590#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000591 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
Sterling Augustine6d474102020-03-04 12:41:54 -0800592 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000593 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000594#endif
595
596 return false;
597}
598
599
600inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000601 // TO DO: if OS has way to dynamically register FDEs, check that.
602 (void)targetAddr;
603 (void)fde;
604 return false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000605}
606
607inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
608 size_t bufLen,
609 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000610#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000611 Dl_info dyldInfo;
612 if (dladdr((void *)addr, &dyldInfo)) {
613 if (dyldInfo.dli_sname != NULL) {
614 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
615 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
616 return true;
617 }
618 }
Martin Storsjo059a1632019-01-22 22:12:23 +0000619#else
620 (void)addr;
621 (void)buf;
622 (void)bufLen;
623 (void)offset;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000624#endif
625 return false;
626}
627
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000628} // namespace libunwind
629
630#endif // __ADDRESSSPACE_HPP__