blob: 36c9f5a9e36f9f39eacfa5c51330a0cf5c432c5f [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
Xing Xue1acfbbb2022-04-13 13:18:10 -040027 #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
28 #define _LIBUNWIND_USE_DLADDR 1
29 #else
30 #define _LIBUNWIND_USE_DLADDR 0
31 #endif
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +000032#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
Xing Xuebbcbce92022-04-13 11:01:59 -040048#if defined(_AIX)
49namespace libunwind {
50char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
51 unw_word_t *offset);
52}
53#endif
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 };
John Baldwin67737ec2017-09-21 21:28:48 +000065
Steven Wu8d1344f2020-08-17 14:08:50 -070066 // In 10.7.0 or later, libSystem.dylib implements this function.
67 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
John Baldwin67737ec2017-09-21 21:28:48 +000068
whitequarkffd92e52017-12-25 17:05:07 +000069#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
70
71// When statically linked on bare-metal, the symbols for the EH table are looked
72// up without going through the dynamic loader.
73
74// The following linker script may be used to produce the necessary sections and symbols.
75// Unless the --eh-frame-hdr linker option is provided, the section is not generated
76// and does not take space in the output file.
77//
78// .eh_frame :
79// {
80// __eh_frame_start = .;
81// KEEP(*(.eh_frame))
82// __eh_frame_end = .;
83// }
84//
85// .eh_frame_hdr :
86// {
87// KEEP(*(.eh_frame_hdr))
88// }
89//
90// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
91// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
92
93extern char __eh_frame_start;
94extern char __eh_frame_end;
95
96#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
97extern char __eh_frame_hdr_start;
98extern char __eh_frame_hdr_end;
99#endif
100
John Baldwin67737ec2017-09-21 21:28:48 +0000101#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
102
103// When statically linked on bare-metal, the symbols for the EH table are looked
104// up without going through the dynamic loader.
105extern char __exidx_start;
106extern char __exidx_end;
107
Ryan Prichard7629c302020-08-27 23:46:49 -0700108#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
John Baldwin67737ec2017-09-21 21:28:48 +0000109
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000110#include <windows.h>
111#include <psapi.h>
Ryan Prichard7629c302020-08-27 23:46:49 -0700112
113#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
114 defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
115
116#include <link.h>
John Baldwin67737ec2017-09-21 21:28:48 +0000117
118#endif
119
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000120namespace libunwind {
121
122/// Used by findUnwindSections() to return info about needed sections.
123struct UnwindInfoSections {
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700124#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
125 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
126 defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
127 // No dso_base for SEH.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000128 uintptr_t dso_base;
129#endif
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700130#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000131 size_t text_segment_length;
Ryan Prichard0cff8572020-09-16 01:22:55 -0700132#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000133#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000134 uintptr_t dwarf_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000135 size_t dwarf_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000136#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000137#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000138 uintptr_t dwarf_index_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000139 size_t dwarf_index_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000140#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000141#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000142 uintptr_t compact_unwind_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000143 size_t compact_unwind_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000144#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000145#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000146 uintptr_t arm_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000147 size_t arm_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000148#endif
149};
150
151
152/// LocalAddressSpace is used as a template parameter to UnwindCursor when
153/// unwinding a thread in the same process. The wrappers compile away,
154/// making local unwinds fast.
Charles Davis04f0c2e2018-08-31 13:41:05 +0000155class _LIBUNWIND_HIDDEN LocalAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000156public:
Martin Storsjocac41382017-10-27 08:11:36 +0000157 typedef uintptr_t pint_t;
158 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000159 uint8_t get8(pint_t addr) {
160 uint8_t val;
161 memcpy(&val, (void *)addr, sizeof(val));
162 return val;
163 }
164 uint16_t get16(pint_t addr) {
165 uint16_t val;
166 memcpy(&val, (void *)addr, sizeof(val));
167 return val;
168 }
169 uint32_t get32(pint_t addr) {
170 uint32_t val;
171 memcpy(&val, (void *)addr, sizeof(val));
172 return val;
173 }
174 uint64_t get64(pint_t addr) {
175 uint64_t val;
176 memcpy(&val, (void *)addr, sizeof(val));
177 return val;
178 }
179 double getDouble(pint_t addr) {
180 double val;
181 memcpy(&val, (void *)addr, sizeof(val));
182 return val;
183 }
184 v128 getVector(pint_t addr) {
185 v128 val;
186 memcpy(&val, (void *)addr, sizeof(val));
187 return val;
188 }
189 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000190 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000191 static uint64_t getULEB128(pint_t &addr, pint_t end);
192 static int64_t getSLEB128(pint_t &addr, pint_t end);
193
194 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
195 pint_t datarelBase = 0);
196 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
197 unw_word_t *offset);
198 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
199 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
200
201 static LocalAddressSpace sThisAddressSpace;
202};
203
204inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000205#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000206 return get64(addr);
207#else
208 return get32(addr);
209#endif
210}
211
John Baldwin1a6e6be2018-02-27 21:24:02 +0000212inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
213#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
214 return get64(addr);
215#else
216 return get32(addr);
217#endif
218}
219
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000220/// Read a ULEB128 into a 64-bit word.
221inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
222 const uint8_t *p = (uint8_t *)addr;
223 const uint8_t *pend = (uint8_t *)end;
224 uint64_t result = 0;
225 int bit = 0;
226 do {
227 uint64_t b;
228
229 if (p == pend)
230 _LIBUNWIND_ABORT("truncated uleb128 expression");
231
232 b = *p & 0x7f;
233
234 if (bit >= 64 || b << bit >> bit != b) {
235 _LIBUNWIND_ABORT("malformed uleb128 expression");
236 } else {
237 result |= b << bit;
238 bit += 7;
239 }
240 } while (*p++ >= 0x80);
241 addr = (pint_t) p;
242 return result;
243}
244
245/// Read a SLEB128 into a 64-bit word.
246inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
247 const uint8_t *p = (uint8_t *)addr;
248 const uint8_t *pend = (uint8_t *)end;
249 int64_t result = 0;
250 int bit = 0;
251 uint8_t byte;
252 do {
253 if (p == pend)
254 _LIBUNWIND_ABORT("truncated sleb128 expression");
255 byte = *p++;
Ryan Prichardc2174592020-07-13 22:06:47 -0700256 result |= (uint64_t)(byte & 0x7f) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000257 bit += 7;
258 } while (byte & 0x80);
259 // sign extend negative numbers
Ryan Prichardc2174592020-07-13 22:06:47 -0700260 if ((byte & 0x40) != 0 && bit < 64)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000261 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000262 addr = (pint_t) p;
263 return result;
264}
265
266inline LocalAddressSpace::pint_t
267LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
268 pint_t datarelBase) {
269 pint_t startAddr = addr;
270 const uint8_t *p = (uint8_t *)addr;
271 pint_t result;
272
273 // first get value
274 switch (encoding & 0x0F) {
275 case DW_EH_PE_ptr:
276 result = getP(addr);
277 p += sizeof(pint_t);
278 addr = (pint_t) p;
279 break;
280 case DW_EH_PE_uleb128:
281 result = (pint_t)getULEB128(addr, end);
282 break;
283 case DW_EH_PE_udata2:
284 result = get16(addr);
285 p += 2;
286 addr = (pint_t) p;
287 break;
288 case DW_EH_PE_udata4:
289 result = get32(addr);
290 p += 4;
291 addr = (pint_t) p;
292 break;
293 case DW_EH_PE_udata8:
294 result = (pint_t)get64(addr);
295 p += 8;
296 addr = (pint_t) p;
297 break;
298 case DW_EH_PE_sleb128:
299 result = (pint_t)getSLEB128(addr, end);
300 break;
301 case DW_EH_PE_sdata2:
302 // Sign extend from signed 16-bit value.
303 result = (pint_t)(int16_t)get16(addr);
304 p += 2;
305 addr = (pint_t) p;
306 break;
307 case DW_EH_PE_sdata4:
308 // Sign extend from signed 32-bit value.
309 result = (pint_t)(int32_t)get32(addr);
310 p += 4;
311 addr = (pint_t) p;
312 break;
313 case DW_EH_PE_sdata8:
314 result = (pint_t)get64(addr);
315 p += 8;
316 addr = (pint_t) p;
317 break;
318 default:
319 _LIBUNWIND_ABORT("unknown pointer encoding");
320 }
321
322 // then add relative offset
323 switch (encoding & 0x70) {
324 case DW_EH_PE_absptr:
325 // do nothing
326 break;
327 case DW_EH_PE_pcrel:
328 result += startAddr;
329 break;
330 case DW_EH_PE_textrel:
331 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
332 break;
333 case DW_EH_PE_datarel:
334 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
335 // default value of 0, and we abort in the event that someone calls this
336 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
337 if (datarelBase == 0)
338 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
339 result += datarelBase;
340 break;
341 case DW_EH_PE_funcrel:
342 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
343 break;
344 case DW_EH_PE_aligned:
345 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
346 break;
347 default:
348 _LIBUNWIND_ABORT("unknown pointer encoding");
349 break;
350 }
351
352 if (encoding & DW_EH_PE_indirect)
353 result = getP(result);
354
355 return result;
356}
357
Ryan Prichard7629c302020-08-27 23:46:49 -0700358#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Sterling Augustine6d474102020-03-04 12:41:54 -0800359
Ryan Prichard7629c302020-08-27 23:46:49 -0700360// The ElfW() macro for pointer-size independent ELF header traversal is not
361// provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
362// data structures are just called Elf_XXX. Define ElfW() locally.
363#if !defined(ElfW)
364 #define ElfW(type) Elf_##type
365#endif
Sterling Augustine6d474102020-03-04 12:41:54 -0800366#if !defined(Elf_Half)
367 typedef ElfW(Half) Elf_Half;
368#endif
369#if !defined(Elf_Phdr)
370 typedef ElfW(Phdr) Elf_Phdr;
371#endif
372#if !defined(Elf_Addr)
373 typedef ElfW(Addr) Elf_Addr;
374#endif
375
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800376static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
Sterling Augustine6d474102020-03-04 12:41:54 -0800377 Elf_Addr image_base = pinfo->dlpi_addr;
Sterling Augustine6d474102020-03-04 12:41:54 -0800378#if defined(__ANDROID__) && __ANDROID_API__ < 18
379 if (image_base == 0) {
380 // Normally, an image base of 0 indicates a non-PIE executable. On
381 // versions of Android prior to API 18, the dynamic linker reported a
382 // dlpi_addr of 0 for PIE executables. Compute the true image base
383 // using the PT_PHDR segment.
384 // See https://github.com/android/ndk/issues/505.
385 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
386 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
387 if (phdr->p_type == PT_PHDR) {
388 image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
389 phdr->p_vaddr;
390 break;
391 }
392 }
393 }
394#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800395 return image_base;
396}
Sterling Augustine6d474102020-03-04 12:41:54 -0800397
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800398struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
399 LocalAddressSpace *addressSpace;
400 UnwindInfoSections *sects;
401 uintptr_t targetAddr;
402};
403
Sterling Augustineb778c912020-08-18 12:05:07 -0700404#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700405#include "FrameHeaderCache.hpp"
406
Ryan Prichardc155d182020-08-19 01:54:17 -0700407// Typically there is one cache per process, but when libunwind is built as a
408// hermetic static library, then each shared object may have its own cache.
409static FrameHeaderCache TheFrameHeaderCache;
Sterling Augustineb778c912020-08-18 12:05:07 -0700410#endif
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700411
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800412static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
413 dl_iterate_cb_data *cbdata) {
414 if (phdr->p_type == PT_LOAD) {
415 uintptr_t begin = image_base + phdr->p_vaddr;
416 uintptr_t end = begin + phdr->p_memsz;
417 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
418 cbdata->sects->dso_base = begin;
Ryan Prichard0cff8572020-09-16 01:22:55 -0700419 cbdata->sects->text_segment_length = phdr->p_memsz;
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800420 return true;
421 }
422 }
423 return false;
424}
425
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700426static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
427 dl_iterate_cb_data *cbdata) {
428#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
429 if (phdr->p_type == PT_GNU_EH_FRAME) {
430 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
431 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
432 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
433 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
434 if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
435 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
436 hdrInfo)) {
437 // .eh_frame_hdr records the start of .eh_frame, but not its size.
438 // Rely on a zero terminator to find the end of the section.
439 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000440 cbdata->sects->dwarf_section_length = SIZE_MAX;
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700441 return true;
442 }
443 }
444 return false;
445#elif defined(_LIBUNWIND_ARM_EHABI)
446 if (phdr->p_type == PT_ARM_EXIDX) {
447 uintptr_t exidx_start = image_base + phdr->p_vaddr;
448 cbdata->sects->arm_section = exidx_start;
449 cbdata->sects->arm_section_length = phdr->p_memsz;
450 return true;
451 }
452 return false;
453#else
454#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
455#endif
456}
457
Ryan Prichard6de71032020-08-22 17:12:52 -0700458static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
459 size_t pinfo_size, void *data) {
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800460 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
461 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800462 return 0;
Sterling Augustineb778c912020-08-18 12:05:07 -0700463#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Ryan Prichardc155d182020-08-19 01:54:17 -0700464 if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700465 return 1;
Mikael Holmen7c371492020-08-25 12:26:48 +0200466#else
467 // Avoid warning about unused variable.
468 (void)pinfo_size;
Sterling Augustineb778c912020-08-18 12:05:07 -0700469#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800470
471 Elf_Addr image_base = calculateImageBase(pinfo);
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700472
473 // Most shared objects seen in this callback function likely don't contain the
474 // target address, so optimize for that. Scan for a matching PT_LOAD segment
475 // first and bail when it isn't found.
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700476 bool found_text = false;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700477 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
478 if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700479 found_text = true;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700480 break;
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700481 }
Sterling Augustine6d474102020-03-04 12:41:54 -0800482 }
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700483 if (!found_text)
484 return 0;
485
486 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
487 // backward.
488 bool found_unwind = false;
489 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
490 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
491 if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
492 found_unwind = true;
493 break;
494 }
495 }
496 if (!found_unwind)
497 return 0;
498
499#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
500 TheFrameHeaderCache.add(cbdata->sects);
501#endif
502 return 1;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800503}
504
Ryan Prichard7629c302020-08-27 23:46:49 -0700505#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Sterling Augustine6d474102020-03-04 12:41:54 -0800506
507
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000508inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
509 UnwindInfoSections &info) {
510#ifdef __APPLE__
511 dyld_unwind_sections dyldInfo;
512 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
513 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000514 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000515 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000516 info.dwarf_section_length = (size_t)dyldInfo.dwarf_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000517 #endif
518 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000519 info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000520 return true;
521 }
whitequarkffd92e52017-12-25 17:05:07 +0000522#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
Ryan Prichard2cfcb8c2020-09-09 15:43:35 -0700523 info.dso_base = 0;
whitequarkffd92e52017-12-25 17:05:07 +0000524 // Bare metal is statically linked, so no need to ask the dynamic loader
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000525 info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
whitequarkffd92e52017-12-25 17:05:07 +0000526 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000527 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
528 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000529#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
530 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000531 info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000532 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
533 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000534#endif
535 if (info.dwarf_section_length)
536 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000537#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000538 // Bare metal is statically linked, so no need to ask the dynamic loader
539 info.arm_section = (uintptr_t)(&__exidx_start);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000540 info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000541 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
542 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000543 if (info.arm_section && info.arm_section_length)
544 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000545#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
546 HMODULE mods[1024];
547 HANDLE process = GetCurrentProcess();
548 DWORD needed;
549
Martin Storsjöa914ec12019-10-28 10:11:05 +0200550 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
551 DWORD err = GetLastError();
552 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
553 "returned error %d", (int)err);
Martin Storsjö3d54d412022-05-04 12:53:58 +0300554 (void)err;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000555 return false;
Martin Storsjöa914ec12019-10-28 10:11:05 +0200556 }
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000557
558 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
559 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
560 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
561 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
562 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
563 bool found_obj = false;
564 bool found_hdr = false;
565
566 info.dso_base = (uintptr_t)mods[i];
567 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
568 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
569 uintptr_t end = begin + pish->Misc.VirtualSize;
570 if (!strncmp((const char *)pish->Name, ".text",
571 IMAGE_SIZEOF_SHORT_NAME)) {
572 if (targetAddr >= begin && targetAddr < end)
573 found_obj = true;
574 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
575 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000576 info.dwarf_section = begin;
577 info.dwarf_section_length = pish->Misc.VirtualSize;
578 found_hdr = true;
579 }
580 if (found_obj && found_hdr)
581 return true;
582 }
583 }
584 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000585#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
586 // Don't even bother, since Windows has functions that do all this stuff
587 // for us.
Martin Storsjo059a1632019-01-22 22:12:23 +0000588 (void)targetAddr;
589 (void)info;
Charles Davisfa2e6202018-08-30 21:29:00 +0000590 return true;
Xing Xuebbcbce92022-04-13 11:01:59 -0400591#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
592 // The traceback table is used for unwinding.
593 (void)targetAddr;
594 (void)info;
595 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700596#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000597 int length = 0;
598 info.arm_section =
599 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000600 info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000601 if (info.arm_section && info.arm_section_length)
602 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700603#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000604 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
Sterling Augustine6d474102020-03-04 12:41:54 -0800605 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000606 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000607#endif
608
609 return false;
610}
611
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000612inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000613 // TO DO: if OS has way to dynamically register FDEs, check that.
614 (void)targetAddr;
615 (void)fde;
616 return false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000617}
618
619inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
620 size_t bufLen,
621 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000622#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000623 Dl_info dyldInfo;
624 if (dladdr((void *)addr, &dyldInfo)) {
625 if (dyldInfo.dli_sname != NULL) {
626 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
627 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
628 return true;
629 }
630 }
Xing Xuebbcbce92022-04-13 11:01:59 -0400631#elif defined(_AIX)
632 uint16_t nameLen;
633 char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
634 if (funcName != NULL) {
635 snprintf(buf, bufLen, "%.*s", nameLen, funcName);
636 return true;
637 }
Martin Storsjo059a1632019-01-22 22:12:23 +0000638#else
639 (void)addr;
640 (void)buf;
641 (void)bufLen;
642 (void)offset;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000643#endif
644 return false;
645}
646
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000647} // namespace libunwind
648
649#endif // __ADDRESSSPACE_HPP__