blob: 3d1e810f43c08aa609d532e3c3aae3a08e2194bf [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#include "libunwind.h"
43#include "config.h"
44#include "dwarf2.h"
Ed Schoutenda7d6252017-03-07 18:21:51 +000045#include "EHHeaderParser.hpp"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000046#include "Registers.hpp"
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 };
58 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
59 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
60 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
61 // In 10.7.0 or later, libSystem.dylib implements this function.
62 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
63 #else
64 // In 10.6.x and earlier, we need to implement this functionality. Note
65 // that this requires a newer version of libmacho (from cctools) than is
66 // present in libSystem on 10.6.x (for getsectiondata).
67 static inline bool _dyld_find_unwind_sections(void* addr,
68 dyld_unwind_sections* info) {
69 // Find mach-o image containing address.
70 Dl_info dlinfo;
71 if (!dladdr(addr, &dlinfo))
72 return false;
73#if __LP64__
74 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
75#else
76 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
77#endif
78
79 // Initialize the return struct
80 info->mh = (const struct mach_header *)mh;
81 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
82 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
83
84 if (!info->dwarf_section) {
85 info->dwarf_section_length = 0;
86 }
87
88 if (!info->compact_unwind_section) {
89 info->compact_unwind_section_length = 0;
90 }
91
92 return true;
93 }
94 #endif
95
whitequarkffd92e52017-12-25 17:05:07 +000096#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
97
98// When statically linked on bare-metal, the symbols for the EH table are looked
99// up without going through the dynamic loader.
100
101// The following linker script may be used to produce the necessary sections and symbols.
102// Unless the --eh-frame-hdr linker option is provided, the section is not generated
103// and does not take space in the output file.
104//
105// .eh_frame :
106// {
107// __eh_frame_start = .;
108// KEEP(*(.eh_frame))
109// __eh_frame_end = .;
110// }
111//
112// .eh_frame_hdr :
113// {
114// KEEP(*(.eh_frame_hdr))
115// }
116//
117// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
118// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
119
120extern char __eh_frame_start;
121extern char __eh_frame_end;
122
123#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
124extern char __eh_frame_hdr_start;
125extern char __eh_frame_hdr_end;
126#endif
127
John Baldwin67737ec2017-09-21 21:28:48 +0000128#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
129
130// When statically linked on bare-metal, the symbols for the EH table are looked
131// up without going through the dynamic loader.
132extern char __exidx_start;
133extern char __exidx_end;
134
135#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
136
137// ELF-based systems may use dl_iterate_phdr() to access sections
138// containing unwinding information. The ElfW() macro for pointer-size
139// independent ELF header traversal is not provided by <link.h> on some
140// systems (e.g., FreeBSD). On these systems the data structures are
141// just called Elf_XXX. Define ElfW() locally.
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000142#ifndef _WIN32
John Baldwin67737ec2017-09-21 21:28:48 +0000143#include <link.h>
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000144#else
145#include <windows.h>
146#include <psapi.h>
147#endif
John Baldwin67737ec2017-09-21 21:28:48 +0000148#if !defined(ElfW)
149#define ElfW(type) Elf_##type
150#endif
151
152#endif
153
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000154namespace libunwind {
155
156/// Used by findUnwindSections() to return info about needed sections.
157struct UnwindInfoSections {
Ranjeet Singh421231a2017-03-31 15:28:06 +0000158#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
159 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Charles Davisfa2e6202018-08-30 21:29:00 +0000160 // No dso_base for SEH or ARM EHABI.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000161 uintptr_t dso_base;
162#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000163#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000164 uintptr_t dwarf_section;
165 uintptr_t dwarf_section_length;
166#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000167#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000168 uintptr_t dwarf_index_section;
169 uintptr_t dwarf_index_section_length;
170#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000171#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000172 uintptr_t compact_unwind_section;
173 uintptr_t compact_unwind_section_length;
174#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000175#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000176 uintptr_t arm_section;
177 uintptr_t arm_section_length;
178#endif
179};
180
181
182/// LocalAddressSpace is used as a template parameter to UnwindCursor when
183/// unwinding a thread in the same process. The wrappers compile away,
184/// making local unwinds fast.
Charles Davis04f0c2e2018-08-31 13:41:05 +0000185class _LIBUNWIND_HIDDEN LocalAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000186public:
Martin Storsjocac41382017-10-27 08:11:36 +0000187 typedef uintptr_t pint_t;
188 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000189 uint8_t get8(pint_t addr) {
190 uint8_t val;
191 memcpy(&val, (void *)addr, sizeof(val));
192 return val;
193 }
194 uint16_t get16(pint_t addr) {
195 uint16_t val;
196 memcpy(&val, (void *)addr, sizeof(val));
197 return val;
198 }
199 uint32_t get32(pint_t addr) {
200 uint32_t val;
201 memcpy(&val, (void *)addr, sizeof(val));
202 return val;
203 }
204 uint64_t get64(pint_t addr) {
205 uint64_t val;
206 memcpy(&val, (void *)addr, sizeof(val));
207 return val;
208 }
209 double getDouble(pint_t addr) {
210 double val;
211 memcpy(&val, (void *)addr, sizeof(val));
212 return val;
213 }
214 v128 getVector(pint_t addr) {
215 v128 val;
216 memcpy(&val, (void *)addr, sizeof(val));
217 return val;
218 }
219 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000220 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000221 static uint64_t getULEB128(pint_t &addr, pint_t end);
222 static int64_t getSLEB128(pint_t &addr, pint_t end);
223
224 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
225 pint_t datarelBase = 0);
226 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
227 unw_word_t *offset);
228 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
229 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
230
231 static LocalAddressSpace sThisAddressSpace;
232};
233
234inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000235#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000236 return get64(addr);
237#else
238 return get32(addr);
239#endif
240}
241
John Baldwin1a6e6be2018-02-27 21:24:02 +0000242inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
243#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
244 return get64(addr);
245#else
246 return get32(addr);
247#endif
248}
249
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000250/// Read a ULEB128 into a 64-bit word.
251inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
252 const uint8_t *p = (uint8_t *)addr;
253 const uint8_t *pend = (uint8_t *)end;
254 uint64_t result = 0;
255 int bit = 0;
256 do {
257 uint64_t b;
258
259 if (p == pend)
260 _LIBUNWIND_ABORT("truncated uleb128 expression");
261
262 b = *p & 0x7f;
263
264 if (bit >= 64 || b << bit >> bit != b) {
265 _LIBUNWIND_ABORT("malformed uleb128 expression");
266 } else {
267 result |= b << bit;
268 bit += 7;
269 }
270 } while (*p++ >= 0x80);
271 addr = (pint_t) p;
272 return result;
273}
274
275/// Read a SLEB128 into a 64-bit word.
276inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
277 const uint8_t *p = (uint8_t *)addr;
278 const uint8_t *pend = (uint8_t *)end;
279 int64_t result = 0;
280 int bit = 0;
281 uint8_t byte;
282 do {
283 if (p == pend)
284 _LIBUNWIND_ABORT("truncated sleb128 expression");
285 byte = *p++;
Ryan Prichardc2174592020-07-13 22:06:47 -0700286 result |= (uint64_t)(byte & 0x7f) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000287 bit += 7;
288 } while (byte & 0x80);
289 // sign extend negative numbers
Ryan Prichardc2174592020-07-13 22:06:47 -0700290 if ((byte & 0x40) != 0 && bit < 64)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000291 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000292 addr = (pint_t) p;
293 return result;
294}
295
296inline LocalAddressSpace::pint_t
297LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
298 pint_t datarelBase) {
299 pint_t startAddr = addr;
300 const uint8_t *p = (uint8_t *)addr;
301 pint_t result;
302
303 // first get value
304 switch (encoding & 0x0F) {
305 case DW_EH_PE_ptr:
306 result = getP(addr);
307 p += sizeof(pint_t);
308 addr = (pint_t) p;
309 break;
310 case DW_EH_PE_uleb128:
311 result = (pint_t)getULEB128(addr, end);
312 break;
313 case DW_EH_PE_udata2:
314 result = get16(addr);
315 p += 2;
316 addr = (pint_t) p;
317 break;
318 case DW_EH_PE_udata4:
319 result = get32(addr);
320 p += 4;
321 addr = (pint_t) p;
322 break;
323 case DW_EH_PE_udata8:
324 result = (pint_t)get64(addr);
325 p += 8;
326 addr = (pint_t) p;
327 break;
328 case DW_EH_PE_sleb128:
329 result = (pint_t)getSLEB128(addr, end);
330 break;
331 case DW_EH_PE_sdata2:
332 // Sign extend from signed 16-bit value.
333 result = (pint_t)(int16_t)get16(addr);
334 p += 2;
335 addr = (pint_t) p;
336 break;
337 case DW_EH_PE_sdata4:
338 // Sign extend from signed 32-bit value.
339 result = (pint_t)(int32_t)get32(addr);
340 p += 4;
341 addr = (pint_t) p;
342 break;
343 case DW_EH_PE_sdata8:
344 result = (pint_t)get64(addr);
345 p += 8;
346 addr = (pint_t) p;
347 break;
348 default:
349 _LIBUNWIND_ABORT("unknown pointer encoding");
350 }
351
352 // then add relative offset
353 switch (encoding & 0x70) {
354 case DW_EH_PE_absptr:
355 // do nothing
356 break;
357 case DW_EH_PE_pcrel:
358 result += startAddr;
359 break;
360 case DW_EH_PE_textrel:
361 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
362 break;
363 case DW_EH_PE_datarel:
364 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
365 // default value of 0, and we abort in the event that someone calls this
366 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
367 if (datarelBase == 0)
368 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
369 result += datarelBase;
370 break;
371 case DW_EH_PE_funcrel:
372 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
373 break;
374 case DW_EH_PE_aligned:
375 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
376 break;
377 default:
378 _LIBUNWIND_ABORT("unknown pointer encoding");
379 break;
380 }
381
382 if (encoding & DW_EH_PE_indirect)
383 result = getP(result);
384
385 return result;
386}
387
Sterling Augustine6d474102020-03-04 12:41:54 -0800388#ifdef __APPLE__
389#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
390#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
391#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
392#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
393#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
394// Code inside findUnwindSections handles all these cases.
395//
396// Although the above ifdef chain is ugly, there doesn't seem to be a cleaner
397// way to handle it. The generalized boolean expression is:
398//
399// A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G)
400//
401// Running it through various boolean expression simplifiers gives expressions
402// that don't help at all.
403#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
404
Sterling Augustine6d474102020-03-04 12:41:54 -0800405#if !defined(Elf_Half)
406 typedef ElfW(Half) Elf_Half;
407#endif
408#if !defined(Elf_Phdr)
409 typedef ElfW(Phdr) Elf_Phdr;
410#endif
411#if !defined(Elf_Addr)
412 typedef ElfW(Addr) Elf_Addr;
413#endif
414
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800415static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800416 Elf_Addr image_base = pinfo->dlpi_addr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800417#if defined(__ANDROID__) && __ANDROID_API__ < 18
418 if (image_base == 0) {
419 // Normally, an image base of 0 indicates a non-PIE executable. On
420 // versions of Android prior to API 18, the dynamic linker reported a
421 // dlpi_addr of 0 for PIE executables. Compute the true image base
422 // using the PT_PHDR segment.
423 // See https://github.com/android/ndk/issues/505.
424 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
425 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
426 if (phdr->p_type == PT_PHDR) {
427 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
428 phdr->p_vaddr;
429 break;
430 }
431 }
432 }
433#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800434 return image_base;
435}
Sterling Augustine6d474102020-03-04 12:41:54 -0800436
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800437struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
438 LocalAddressSpace *addressSpace;
439 UnwindInfoSections *sects;
440 uintptr_t targetAddr;
441};
442
443#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Sterling Augustine6d474102020-03-04 12:41:54 -0800444 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800445 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
Sterling Augustine6d474102020-03-04 12:41:54 -0800446 #endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800447
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700448#include "FrameHeaderCache.hpp"
449
450// There should be just one of these per process.
451static FrameHeaderCache ProcessFrameHeaderCache;
452
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800453static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
454 dl_iterate_cb_data *cbdata) {
455 if (phdr->p_type == PT_LOAD) {
456 uintptr_t begin = image_base + phdr->p_vaddr;
457 uintptr_t end = begin + phdr->p_memsz;
458 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
459 cbdata->sects->dso_base = begin;
460 cbdata->sects->dwarf_section_length = phdr->p_memsz;
461 return true;
462 }
463 }
464 return false;
465}
466
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700467int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
468 void *data) {
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800469 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
470 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800471 return 0;
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700472 if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
473 return 1;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800474
475 Elf_Addr image_base = calculateImageBase(pinfo);
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800476 bool found_obj = false;
477 bool found_hdr = false;
Sterling Augustine6d474102020-03-04 12:41:54 -0800478
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800479 // Third phdr is usually the executable phdr.
480 if (pinfo->dlpi_phnum > 2)
481 found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
482
483 // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
484 // that there is one or more phdrs.
485 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
486 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
487 if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800488 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
489 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
490 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
491 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
492 found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
493 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
494 hdrInfo);
495 if (found_hdr)
496 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800497 } else if (!found_obj) {
498 found_obj = checkAddrInSegment(phdr, image_base, cbdata);
Sterling Augustine6d474102020-03-04 12:41:54 -0800499 }
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700500 if (found_obj && found_hdr) {
501 ProcessFrameHeaderCache.add(cbdata->sects);
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800502 return 1;
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700503 }
Sterling Augustine6d474102020-03-04 12:41:54 -0800504 }
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800505 cbdata->sects->dwarf_section_length = 0;
506 return 0;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800507}
508
509#else // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
510// Given all the #ifdef's above, the code here is for
511// defined(LIBUNWIND_ARM_EHABI)
512
513int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
514 auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
515 bool found_obj = false;
516 bool found_hdr = false;
517
518 assert(cbdata);
519 assert(cbdata->sects);
520
521 if (cbdata->targetAddr < pinfo->dlpi_addr)
522 return 0;
523
524 Elf_Addr image_base = calculateImageBase(pinfo);
525
Sterling Augustine6d474102020-03-04 12:41:54 -0800526 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
527 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
528 if (phdr->p_type == PT_LOAD) {
529 uintptr_t begin = image_base + phdr->p_vaddr;
530 uintptr_t end = begin + phdr->p_memsz;
531 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
532 found_obj = true;
533 } else if (phdr->p_type == PT_ARM_EXIDX) {
534 uintptr_t exidx_start = image_base + phdr->p_vaddr;
535 cbdata->sects->arm_section = exidx_start;
536 cbdata->sects->arm_section_length = phdr->p_memsz;
537 found_hdr = true;
538 }
539 }
540 return found_obj && found_hdr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800541}
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800542#endif // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
Sterling Augustine6d474102020-03-04 12:41:54 -0800543#endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
544
545
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000546inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
547 UnwindInfoSections &info) {
548#ifdef __APPLE__
549 dyld_unwind_sections dyldInfo;
550 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
551 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000552 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000553 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
554 info.dwarf_section_length = dyldInfo.dwarf_section_length;
555 #endif
556 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
557 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
558 return true;
559 }
whitequarkffd92e52017-12-25 17:05:07 +0000560#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
561 // Bare metal is statically linked, so no need to ask the dynamic loader
562 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
563 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000564 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
565 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000566#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
567 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
568 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000569 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
570 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000571#endif
572 if (info.dwarf_section_length)
573 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000574#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000575 // Bare metal is statically linked, so no need to ask the dynamic loader
576 info.arm_section = (uintptr_t)(&__exidx_start);
577 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000578 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
579 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000580 if (info.arm_section && info.arm_section_length)
581 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000582#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
583 HMODULE mods[1024];
584 HANDLE process = GetCurrentProcess();
585 DWORD needed;
586
Martin Storsjöa914ec12019-10-28 10:11:05 +0200587 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
588 DWORD err = GetLastError();
589 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
590 "returned error %d", (int)err);
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000591 return false;
Martin Storsjöa914ec12019-10-28 10:11:05 +0200592 }
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000593
594 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
595 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
596 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
597 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
598 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
599 bool found_obj = false;
600 bool found_hdr = false;
601
602 info.dso_base = (uintptr_t)mods[i];
603 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
604 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
605 uintptr_t end = begin + pish->Misc.VirtualSize;
606 if (!strncmp((const char *)pish->Name, ".text",
607 IMAGE_SIZEOF_SHORT_NAME)) {
608 if (targetAddr >= begin && targetAddr < end)
609 found_obj = true;
610 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
611 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000612 info.dwarf_section = begin;
613 info.dwarf_section_length = pish->Misc.VirtualSize;
614 found_hdr = true;
615 }
616 if (found_obj && found_hdr)
617 return true;
618 }
619 }
620 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000621#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
622 // Don't even bother, since Windows has functions that do all this stuff
623 // for us.
Martin Storsjo059a1632019-01-22 22:12:23 +0000624 (void)targetAddr;
625 (void)info;
Charles Davisfa2e6202018-08-30 21:29:00 +0000626 return true;
Ryan Prichard2a4f1362019-10-18 19:59:22 +0000627#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
628 // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
629 // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000630 int length = 0;
631 info.arm_section =
632 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
Ryan Prichard2a4f1362019-10-18 19:59:22 +0000633 info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000634 if (info.arm_section && info.arm_section_length)
635 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000636#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000637 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
Sterling Augustine6d474102020-03-04 12:41:54 -0800638 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000639 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000640#endif
641
642 return false;
643}
644
645
646inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000647 // TO DO: if OS has way to dynamically register FDEs, check that.
648 (void)targetAddr;
649 (void)fde;
650 return false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000651}
652
653inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
654 size_t bufLen,
655 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000656#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000657 Dl_info dyldInfo;
658 if (dladdr((void *)addr, &dyldInfo)) {
659 if (dyldInfo.dli_sname != NULL) {
660 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
661 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
662 return true;
663 }
664 }
Martin Storsjo059a1632019-01-22 22:12:23 +0000665#else
666 (void)addr;
667 (void)buf;
668 (void)bufLen;
669 (void)offset;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000670#endif
671 return false;
672}
673
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000674} // namespace libunwind
675
676#endif // __ADDRESSSPACE_HPP__