blob: 83af9aeaef7794b23ac9101cef34dd342d976745 [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===------------------------- AddressSpace.hpp ---------------------------===//
2//
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
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +000020#ifndef _LIBUNWIND_USE_DLADDR
21 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
22 #define _LIBUNWIND_USE_DLADDR 1
23 #else
24 #define _LIBUNWIND_USE_DLADDR 0
25 #endif
26#endif
27
28#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +000029#include <dlfcn.h>
Michał Górnyf939ab72019-11-30 15:13:56 +010030#if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
Petr Hosek7b727032019-05-30 01:34:41 +000031#pragma comment(lib, "dl")
32#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +000033#endif
34
Ryan Prichard2a4f1362019-10-18 19:59:22 +000035#if defined(_LIBUNWIND_ARM_EHABI)
36struct EHABIIndexEntry {
37 uint32_t functionOffset;
38 uint32_t data;
39};
40#endif
41
Saleem Abdulrasool17552662015-04-24 19:39:17 +000042#ifdef __APPLE__
43#include <mach-o/getsect.h>
44namespace libunwind {
45 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
46}
47#endif
48
49#include "libunwind.h"
50#include "config.h"
51#include "dwarf2.h"
Ed Schoutenda7d6252017-03-07 18:21:51 +000052#include "EHHeaderParser.hpp"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000053#include "Registers.hpp"
54
John Baldwin67737ec2017-09-21 21:28:48 +000055#ifdef __APPLE__
56
57 struct dyld_unwind_sections
58 {
59 const struct mach_header* mh;
60 const void* dwarf_section;
61 uintptr_t dwarf_section_length;
62 const void* compact_unwind_section;
63 uintptr_t compact_unwind_section_length;
64 };
65 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
66 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
67 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
68 // In 10.7.0 or later, libSystem.dylib implements this function.
69 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
70 #else
71 // In 10.6.x and earlier, we need to implement this functionality. Note
72 // that this requires a newer version of libmacho (from cctools) than is
73 // present in libSystem on 10.6.x (for getsectiondata).
74 static inline bool _dyld_find_unwind_sections(void* addr,
75 dyld_unwind_sections* info) {
76 // Find mach-o image containing address.
77 Dl_info dlinfo;
78 if (!dladdr(addr, &dlinfo))
79 return false;
80#if __LP64__
81 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
82#else
83 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
84#endif
85
86 // Initialize the return struct
87 info->mh = (const struct mach_header *)mh;
88 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
89 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
90
91 if (!info->dwarf_section) {
92 info->dwarf_section_length = 0;
93 }
94
95 if (!info->compact_unwind_section) {
96 info->compact_unwind_section_length = 0;
97 }
98
99 return true;
100 }
101 #endif
102
whitequarkffd92e52017-12-25 17:05:07 +0000103#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
104
105// When statically linked on bare-metal, the symbols for the EH table are looked
106// up without going through the dynamic loader.
107
108// The following linker script may be used to produce the necessary sections and symbols.
109// Unless the --eh-frame-hdr linker option is provided, the section is not generated
110// and does not take space in the output file.
111//
112// .eh_frame :
113// {
114// __eh_frame_start = .;
115// KEEP(*(.eh_frame))
116// __eh_frame_end = .;
117// }
118//
119// .eh_frame_hdr :
120// {
121// KEEP(*(.eh_frame_hdr))
122// }
123//
124// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
125// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
126
127extern char __eh_frame_start;
128extern char __eh_frame_end;
129
130#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
131extern char __eh_frame_hdr_start;
132extern char __eh_frame_hdr_end;
133#endif
134
John Baldwin67737ec2017-09-21 21:28:48 +0000135#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
136
137// When statically linked on bare-metal, the symbols for the EH table are looked
138// up without going through the dynamic loader.
139extern char __exidx_start;
140extern char __exidx_end;
141
142#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
143
144// ELF-based systems may use dl_iterate_phdr() to access sections
145// containing unwinding information. The ElfW() macro for pointer-size
146// independent ELF header traversal is not provided by <link.h> on some
147// systems (e.g., FreeBSD). On these systems the data structures are
148// just called Elf_XXX. Define ElfW() locally.
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000149#ifndef _WIN32
John Baldwin67737ec2017-09-21 21:28:48 +0000150#include <link.h>
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000151#else
152#include <windows.h>
153#include <psapi.h>
154#endif
John Baldwin67737ec2017-09-21 21:28:48 +0000155#if !defined(ElfW)
156#define ElfW(type) Elf_##type
157#endif
158
159#endif
160
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000161namespace libunwind {
162
163/// Used by findUnwindSections() to return info about needed sections.
164struct UnwindInfoSections {
Ranjeet Singh421231a2017-03-31 15:28:06 +0000165#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
166 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Charles Davisfa2e6202018-08-30 21:29:00 +0000167 // No dso_base for SEH or ARM EHABI.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000168 uintptr_t dso_base;
169#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000170#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000171 uintptr_t dwarf_section;
172 uintptr_t dwarf_section_length;
173#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000174#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000175 uintptr_t dwarf_index_section;
176 uintptr_t dwarf_index_section_length;
177#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000178#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000179 uintptr_t compact_unwind_section;
180 uintptr_t compact_unwind_section_length;
181#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000182#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000183 uintptr_t arm_section;
184 uintptr_t arm_section_length;
185#endif
186};
187
188
189/// LocalAddressSpace is used as a template parameter to UnwindCursor when
190/// unwinding a thread in the same process. The wrappers compile away,
191/// making local unwinds fast.
Charles Davis04f0c2e2018-08-31 13:41:05 +0000192class _LIBUNWIND_HIDDEN LocalAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000193public:
Martin Storsjocac41382017-10-27 08:11:36 +0000194 typedef uintptr_t pint_t;
195 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000196 uint8_t get8(pint_t addr) {
197 uint8_t val;
198 memcpy(&val, (void *)addr, sizeof(val));
199 return val;
200 }
201 uint16_t get16(pint_t addr) {
202 uint16_t val;
203 memcpy(&val, (void *)addr, sizeof(val));
204 return val;
205 }
206 uint32_t get32(pint_t addr) {
207 uint32_t val;
208 memcpy(&val, (void *)addr, sizeof(val));
209 return val;
210 }
211 uint64_t get64(pint_t addr) {
212 uint64_t val;
213 memcpy(&val, (void *)addr, sizeof(val));
214 return val;
215 }
216 double getDouble(pint_t addr) {
217 double val;
218 memcpy(&val, (void *)addr, sizeof(val));
219 return val;
220 }
221 v128 getVector(pint_t addr) {
222 v128 val;
223 memcpy(&val, (void *)addr, sizeof(val));
224 return val;
225 }
226 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000227 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000228 static uint64_t getULEB128(pint_t &addr, pint_t end);
229 static int64_t getSLEB128(pint_t &addr, pint_t end);
230
231 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
232 pint_t datarelBase = 0);
233 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
234 unw_word_t *offset);
235 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
236 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
237
238 static LocalAddressSpace sThisAddressSpace;
239};
240
241inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000242#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000243 return get64(addr);
244#else
245 return get32(addr);
246#endif
247}
248
John Baldwin1a6e6be2018-02-27 21:24:02 +0000249inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
250#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
251 return get64(addr);
252#else
253 return get32(addr);
254#endif
255}
256
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000257/// Read a ULEB128 into a 64-bit word.
258inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
259 const uint8_t *p = (uint8_t *)addr;
260 const uint8_t *pend = (uint8_t *)end;
261 uint64_t result = 0;
262 int bit = 0;
263 do {
264 uint64_t b;
265
266 if (p == pend)
267 _LIBUNWIND_ABORT("truncated uleb128 expression");
268
269 b = *p & 0x7f;
270
271 if (bit >= 64 || b << bit >> bit != b) {
272 _LIBUNWIND_ABORT("malformed uleb128 expression");
273 } else {
274 result |= b << bit;
275 bit += 7;
276 }
277 } while (*p++ >= 0x80);
278 addr = (pint_t) p;
279 return result;
280}
281
282/// Read a SLEB128 into a 64-bit word.
283inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
284 const uint8_t *p = (uint8_t *)addr;
285 const uint8_t *pend = (uint8_t *)end;
286 int64_t result = 0;
287 int bit = 0;
288 uint8_t byte;
289 do {
290 if (p == pend)
291 _LIBUNWIND_ABORT("truncated sleb128 expression");
292 byte = *p++;
293 result |= ((byte & 0x7f) << bit);
294 bit += 7;
295 } while (byte & 0x80);
296 // sign extend negative numbers
297 if ((byte & 0x40) != 0)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000298 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000299 addr = (pint_t) p;
300 return result;
301}
302
303inline LocalAddressSpace::pint_t
304LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
305 pint_t datarelBase) {
306 pint_t startAddr = addr;
307 const uint8_t *p = (uint8_t *)addr;
308 pint_t result;
309
310 // first get value
311 switch (encoding & 0x0F) {
312 case DW_EH_PE_ptr:
313 result = getP(addr);
314 p += sizeof(pint_t);
315 addr = (pint_t) p;
316 break;
317 case DW_EH_PE_uleb128:
318 result = (pint_t)getULEB128(addr, end);
319 break;
320 case DW_EH_PE_udata2:
321 result = get16(addr);
322 p += 2;
323 addr = (pint_t) p;
324 break;
325 case DW_EH_PE_udata4:
326 result = get32(addr);
327 p += 4;
328 addr = (pint_t) p;
329 break;
330 case DW_EH_PE_udata8:
331 result = (pint_t)get64(addr);
332 p += 8;
333 addr = (pint_t) p;
334 break;
335 case DW_EH_PE_sleb128:
336 result = (pint_t)getSLEB128(addr, end);
337 break;
338 case DW_EH_PE_sdata2:
339 // Sign extend from signed 16-bit value.
340 result = (pint_t)(int16_t)get16(addr);
341 p += 2;
342 addr = (pint_t) p;
343 break;
344 case DW_EH_PE_sdata4:
345 // Sign extend from signed 32-bit value.
346 result = (pint_t)(int32_t)get32(addr);
347 p += 4;
348 addr = (pint_t) p;
349 break;
350 case DW_EH_PE_sdata8:
351 result = (pint_t)get64(addr);
352 p += 8;
353 addr = (pint_t) p;
354 break;
355 default:
356 _LIBUNWIND_ABORT("unknown pointer encoding");
357 }
358
359 // then add relative offset
360 switch (encoding & 0x70) {
361 case DW_EH_PE_absptr:
362 // do nothing
363 break;
364 case DW_EH_PE_pcrel:
365 result += startAddr;
366 break;
367 case DW_EH_PE_textrel:
368 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
369 break;
370 case DW_EH_PE_datarel:
371 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
372 // default value of 0, and we abort in the event that someone calls this
373 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
374 if (datarelBase == 0)
375 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
376 result += datarelBase;
377 break;
378 case DW_EH_PE_funcrel:
379 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
380 break;
381 case DW_EH_PE_aligned:
382 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
383 break;
384 default:
385 _LIBUNWIND_ABORT("unknown pointer encoding");
386 break;
387 }
388
389 if (encoding & DW_EH_PE_indirect)
390 result = getP(result);
391
392 return result;
393}
394
Sterling Augustine6d474102020-03-04 12:41:54 -0800395#ifdef __APPLE__
396#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
397#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
398#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
399#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
400#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
401// Code inside findUnwindSections handles all these cases.
402//
403// Although the above ifdef chain is ugly, there doesn't seem to be a cleaner
404// way to handle it. The generalized boolean expression is:
405//
406// A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G)
407//
408// Running it through various boolean expression simplifiers gives expressions
409// that don't help at all.
410#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
411
Sterling Augustine6d474102020-03-04 12:41:54 -0800412#if !defined(Elf_Half)
413 typedef ElfW(Half) Elf_Half;
414#endif
415#if !defined(Elf_Phdr)
416 typedef ElfW(Phdr) Elf_Phdr;
417#endif
418#if !defined(Elf_Addr)
419 typedef ElfW(Addr) Elf_Addr;
420#endif
421
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800422static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800423 Elf_Addr image_base = pinfo->dlpi_addr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800424#if defined(__ANDROID__) && __ANDROID_API__ < 18
425 if (image_base == 0) {
426 // Normally, an image base of 0 indicates a non-PIE executable. On
427 // versions of Android prior to API 18, the dynamic linker reported a
428 // dlpi_addr of 0 for PIE executables. Compute the true image base
429 // using the PT_PHDR segment.
430 // See https://github.com/android/ndk/issues/505.
431 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
432 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
433 if (phdr->p_type == PT_PHDR) {
434 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
435 phdr->p_vaddr;
436 break;
437 }
438 }
439 }
440#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800441 return image_base;
442}
Sterling Augustine6d474102020-03-04 12:41:54 -0800443
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800444struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
445 LocalAddressSpace *addressSpace;
446 UnwindInfoSections *sects;
447 uintptr_t targetAddr;
448};
449
450#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Sterling Augustine6d474102020-03-04 12:41:54 -0800451 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800452 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
Sterling Augustine6d474102020-03-04 12:41:54 -0800453 #endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800454
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800455static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
456 dl_iterate_cb_data *cbdata) {
457 if (phdr->p_type == PT_LOAD) {
458 uintptr_t begin = image_base + phdr->p_vaddr;
459 uintptr_t end = begin + phdr->p_memsz;
460 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
461 cbdata->sects->dso_base = begin;
462 cbdata->sects->dwarf_section_length = phdr->p_memsz;
463 return true;
464 }
465 }
466 return false;
467}
468
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800469int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800470 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
471 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800472 return 0;
473
474 Elf_Addr image_base = calculateImageBase(pinfo);
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800475 bool found_obj = false;
476 bool found_hdr = false;
Sterling Augustine6d474102020-03-04 12:41:54 -0800477
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800478 // Third phdr is usually the executable phdr.
479 if (pinfo->dlpi_phnum > 2)
480 found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
481
482 // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
483 // that there is one or more phdrs.
484 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
485 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
486 if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800487 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
488 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
489 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
490 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
491 found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
492 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
493 hdrInfo);
494 if (found_hdr)
495 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800496 } else if (!found_obj) {
497 found_obj = checkAddrInSegment(phdr, image_base, cbdata);
Sterling Augustine6d474102020-03-04 12:41:54 -0800498 }
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800499 if (found_obj && found_hdr)
500 return 1;
Sterling Augustine6d474102020-03-04 12:41:54 -0800501 }
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800502 cbdata->sects->dwarf_section_length = 0;
503 return 0;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800504}
505
506#else // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
507// Given all the #ifdef's above, the code here is for
508// defined(LIBUNWIND_ARM_EHABI)
509
510int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
511 auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
512 bool found_obj = false;
513 bool found_hdr = false;
514
515 assert(cbdata);
516 assert(cbdata->sects);
517
518 if (cbdata->targetAddr < pinfo->dlpi_addr)
519 return 0;
520
521 Elf_Addr image_base = calculateImageBase(pinfo);
522
Sterling Augustine6d474102020-03-04 12:41:54 -0800523 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
524 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
525 if (phdr->p_type == PT_LOAD) {
526 uintptr_t begin = image_base + phdr->p_vaddr;
527 uintptr_t end = begin + phdr->p_memsz;
528 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
529 found_obj = true;
530 } else if (phdr->p_type == PT_ARM_EXIDX) {
531 uintptr_t exidx_start = image_base + phdr->p_vaddr;
532 cbdata->sects->arm_section = exidx_start;
533 cbdata->sects->arm_section_length = phdr->p_memsz;
534 found_hdr = true;
535 }
536 }
537 return found_obj && found_hdr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800538}
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800539#endif // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
Sterling Augustine6d474102020-03-04 12:41:54 -0800540#endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
541
542
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000543inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
544 UnwindInfoSections &info) {
545#ifdef __APPLE__
546 dyld_unwind_sections dyldInfo;
547 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
548 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000549 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000550 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
551 info.dwarf_section_length = dyldInfo.dwarf_section_length;
552 #endif
553 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
554 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
555 return true;
556 }
whitequarkffd92e52017-12-25 17:05:07 +0000557#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
558 // Bare metal is statically linked, so no need to ask the dynamic loader
559 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
560 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000561 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
562 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000563#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
564 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
565 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000566 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
567 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000568#endif
569 if (info.dwarf_section_length)
570 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000571#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000572 // Bare metal is statically linked, so no need to ask the dynamic loader
573 info.arm_section = (uintptr_t)(&__exidx_start);
574 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000575 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
576 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000577 if (info.arm_section && info.arm_section_length)
578 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000579#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
580 HMODULE mods[1024];
581 HANDLE process = GetCurrentProcess();
582 DWORD needed;
583
Martin Storsjöa914ec12019-10-28 10:11:05 +0200584 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
585 DWORD err = GetLastError();
586 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
587 "returned error %d", (int)err);
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000588 return false;
Martin Storsjöa914ec12019-10-28 10:11:05 +0200589 }
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000590
591 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
592 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
593 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
594 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
595 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
596 bool found_obj = false;
597 bool found_hdr = false;
598
599 info.dso_base = (uintptr_t)mods[i];
600 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
601 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
602 uintptr_t end = begin + pish->Misc.VirtualSize;
603 if (!strncmp((const char *)pish->Name, ".text",
604 IMAGE_SIZEOF_SHORT_NAME)) {
605 if (targetAddr >= begin && targetAddr < end)
606 found_obj = true;
607 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
608 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000609 info.dwarf_section = begin;
610 info.dwarf_section_length = pish->Misc.VirtualSize;
611 found_hdr = true;
612 }
613 if (found_obj && found_hdr)
614 return true;
615 }
616 }
617 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000618#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
619 // Don't even bother, since Windows has functions that do all this stuff
620 // for us.
Martin Storsjo059a1632019-01-22 22:12:23 +0000621 (void)targetAddr;
622 (void)info;
Charles Davisfa2e6202018-08-30 21:29:00 +0000623 return true;
Ryan Prichard2a4f1362019-10-18 19:59:22 +0000624#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
625 // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
626 // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000627 int length = 0;
628 info.arm_section =
629 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
Ryan Prichard2a4f1362019-10-18 19:59:22 +0000630 info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000631 if (info.arm_section && info.arm_section_length)
632 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000633#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000634 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
Sterling Augustine6d474102020-03-04 12:41:54 -0800635 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000636 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000637#endif
638
639 return false;
640}
641
642
643inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
644#ifdef __APPLE__
645 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
646#else
647 // TO DO: if OS has way to dynamically register FDEs, check that.
648 (void)targetAddr;
649 (void)fde;
650 return false;
651#endif
652}
653
654inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
655 size_t bufLen,
656 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000657#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000658 Dl_info dyldInfo;
659 if (dladdr((void *)addr, &dyldInfo)) {
660 if (dyldInfo.dli_sname != NULL) {
661 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
662 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
663 return true;
664 }
665 }
Martin Storsjo059a1632019-01-22 22:12:23 +0000666#else
667 (void)addr;
668 (void)buf;
669 (void)bufLen;
670 (void)offset;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000671#endif
672 return false;
673}
674
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000675} // namespace libunwind
676
677#endif // __ADDRESSSPACE_HPP__