blob: b0135b0c0519c4a5864995c49ee6065597f4732d [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 -0800376struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
377 LocalAddressSpace *addressSpace;
378 UnwindInfoSections *sects;
379 uintptr_t targetAddr;
380};
381
Sterling Augustineb778c912020-08-18 12:05:07 -0700382#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700383#include "FrameHeaderCache.hpp"
384
Ryan Prichardc155d182020-08-19 01:54:17 -0700385// Typically there is one cache per process, but when libunwind is built as a
386// hermetic static library, then each shared object may have its own cache.
387static FrameHeaderCache TheFrameHeaderCache;
Sterling Augustineb778c912020-08-18 12:05:07 -0700388#endif
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700389
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800390static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
391 dl_iterate_cb_data *cbdata) {
392 if (phdr->p_type == PT_LOAD) {
393 uintptr_t begin = image_base + phdr->p_vaddr;
394 uintptr_t end = begin + phdr->p_memsz;
395 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
396 cbdata->sects->dso_base = begin;
Ryan Prichard0cff8572020-09-16 01:22:55 -0700397 cbdata->sects->text_segment_length = phdr->p_memsz;
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800398 return true;
399 }
400 }
401 return false;
402}
403
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700404static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
405 dl_iterate_cb_data *cbdata) {
406#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
407 if (phdr->p_type == PT_GNU_EH_FRAME) {
408 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
409 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
410 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
411 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
412 if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
413 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
414 hdrInfo)) {
415 // .eh_frame_hdr records the start of .eh_frame, but not its size.
416 // Rely on a zero terminator to find the end of the section.
417 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000418 cbdata->sects->dwarf_section_length = SIZE_MAX;
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700419 return true;
420 }
421 }
422 return false;
423#elif defined(_LIBUNWIND_ARM_EHABI)
424 if (phdr->p_type == PT_ARM_EXIDX) {
425 uintptr_t exidx_start = image_base + phdr->p_vaddr;
426 cbdata->sects->arm_section = exidx_start;
427 cbdata->sects->arm_section_length = phdr->p_memsz;
428 return true;
429 }
430 return false;
431#else
432#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
433#endif
434}
435
Ryan Prichard6de71032020-08-22 17:12:52 -0700436static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
437 size_t pinfo_size, void *data) {
Sterling Augustine5101ebe2020-03-06 15:59:16 -0800438 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
439 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800440 return 0;
Sterling Augustineb778c912020-08-18 12:05:07 -0700441#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
Ryan Prichardc155d182020-08-19 01:54:17 -0700442 if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700443 return 1;
Mikael Holmen7c371492020-08-25 12:26:48 +0200444#else
445 // Avoid warning about unused variable.
446 (void)pinfo_size;
Sterling Augustineb778c912020-08-18 12:05:07 -0700447#endif
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800448
Fangrui Song754d0162022-08-12 10:46:46 -0700449 Elf_Addr image_base = pinfo->dlpi_addr;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700450
451 // Most shared objects seen in this callback function likely don't contain the
452 // target address, so optimize for that. Scan for a matching PT_LOAD segment
453 // first and bail when it isn't found.
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700454 bool found_text = false;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700455 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
456 if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
Ryan Prichardb15aa7a2020-09-23 14:25:13 -0700457 found_text = true;
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700458 break;
Sterling Augustine2e9018a2020-03-10 12:03:24 -0700459 }
Sterling Augustine6d474102020-03-04 12:41:54 -0800460 }
Ryan Pricharda72d12f2020-09-23 14:25:23 -0700461 if (!found_text)
462 return 0;
463
464 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
465 // backward.
466 bool found_unwind = false;
467 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
468 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
469 if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
470 found_unwind = true;
471 break;
472 }
473 }
474 if (!found_unwind)
475 return 0;
476
477#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
478 TheFrameHeaderCache.add(cbdata->sects);
479#endif
480 return 1;
Sterling Augustine8eb93ce2020-03-05 11:50:51 -0800481}
482
Ryan Prichard7629c302020-08-27 23:46:49 -0700483#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Sterling Augustine6d474102020-03-04 12:41:54 -0800484
485
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000486inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
487 UnwindInfoSections &info) {
488#ifdef __APPLE__
489 dyld_unwind_sections dyldInfo;
490 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
491 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000492 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000493 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000494 info.dwarf_section_length = (size_t)dyldInfo.dwarf_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000495 #endif
496 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000497 info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000498 return true;
499 }
whitequarkffd92e52017-12-25 17:05:07 +0000500#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
Ryan Prichard2cfcb8c2020-09-09 15:43:35 -0700501 info.dso_base = 0;
whitequarkffd92e52017-12-25 17:05:07 +0000502 // Bare metal is statically linked, so no need to ask the dynamic loader
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000503 info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
whitequarkffd92e52017-12-25 17:05:07 +0000504 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000505 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
506 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000507#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
508 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000509 info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000510 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
511 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000512#endif
513 if (info.dwarf_section_length)
514 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000515#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000516 // Bare metal is statically linked, so no need to ask the dynamic loader
517 info.arm_section = (uintptr_t)(&__exidx_start);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000518 info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000519 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
520 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000521 if (info.arm_section && info.arm_section_length)
522 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000523#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
524 HMODULE mods[1024];
525 HANDLE process = GetCurrentProcess();
526 DWORD needed;
527
Martin Storsjöa914ec12019-10-28 10:11:05 +0200528 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
529 DWORD err = GetLastError();
530 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
531 "returned error %d", (int)err);
Martin Storsjö3d54d412022-05-04 12:53:58 +0300532 (void)err;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000533 return false;
Martin Storsjöa914ec12019-10-28 10:11:05 +0200534 }
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000535
536 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
537 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
538 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
539 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
540 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
541 bool found_obj = false;
542 bool found_hdr = false;
543
544 info.dso_base = (uintptr_t)mods[i];
545 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
546 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
547 uintptr_t end = begin + pish->Misc.VirtualSize;
548 if (!strncmp((const char *)pish->Name, ".text",
549 IMAGE_SIZEOF_SHORT_NAME)) {
550 if (targetAddr >= begin && targetAddr < end)
551 found_obj = true;
552 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
553 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000554 info.dwarf_section = begin;
555 info.dwarf_section_length = pish->Misc.VirtualSize;
556 found_hdr = true;
557 }
558 if (found_obj && found_hdr)
559 return true;
560 }
561 }
562 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000563#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
564 // Don't even bother, since Windows has functions that do all this stuff
565 // for us.
Martin Storsjo059a1632019-01-22 22:12:23 +0000566 (void)targetAddr;
567 (void)info;
Charles Davisfa2e6202018-08-30 21:29:00 +0000568 return true;
Xing Xuebbcbce92022-04-13 11:01:59 -0400569#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
570 // The traceback table is used for unwinding.
571 (void)targetAddr;
572 (void)info;
573 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700574#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000575 int length = 0;
576 info.arm_section =
577 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
Jessica Clarkeefb2cbd2022-01-18 23:50:05 +0000578 info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000579 if (info.arm_section && info.arm_section_length)
580 return true;
Ryan Prichard7629c302020-08-27 23:46:49 -0700581#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
Adrian Vogelsgesanga097a1a2022-07-27 13:55:58 -0700582 // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
583 // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
584 // support for _dl_find_object on other unwind formats is not implemented,
585 // yet.
586#if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Adrian Vogelsgesanga097a1a2022-07-27 13:55:58 -0700587 // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
588#if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
589#error _dl_find_object retrieves an unexpected section type
590#endif
591 // We look-up `dl_find_object` dynamically at runtime to ensure backwards
592 // compatibility with earlier version of glibc not yet providing it. On older
593 // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
594 // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
595 static decltype(_dl_find_object) *dlFindObject;
596 static bool dlFindObjectChecked = false;
597 if (!dlFindObjectChecked) {
598 dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
599 dlsym(RTLD_DEFAULT, "_dl_find_object"));
600 dlFindObjectChecked = true;
601 }
602 // Try to find the unwind info using `dl_find_object`
603 dl_find_object findResult;
604 if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
605 if (findResult.dlfo_eh_frame == nullptr) {
606 // Found an entry for `targetAddr`, but there is no unwind info.
607 return false;
608 }
609 info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
610 info.text_segment_length = static_cast<size_t>(
611 (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
612
613 // Record the start of PT_GNU_EH_FRAME.
614 info.dwarf_index_section =
615 reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
616 // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
617 // Setting length to `SIZE_MAX` effectively disables all range checks.
618 info.dwarf_index_section_length = SIZE_MAX;
619 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
620 if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
621 *this, info.dwarf_index_section, info.dwarf_index_section_length,
622 hdrInfo)) {
623 return false;
624 }
625 // Record the start of the FDE and use SIZE_MAX to indicate that we do
626 // not know the end address.
627 info.dwarf_section = hdrInfo.eh_frame_ptr;
628 info.dwarf_section_length = SIZE_MAX;
629 return true;
630 }
631#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000632 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
Sterling Augustine6d474102020-03-04 12:41:54 -0800633 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000634 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000635#endif
636
637 return false;
638}
639
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000640inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000641 // TO DO: if OS has way to dynamically register FDEs, check that.
642 (void)targetAddr;
643 (void)fde;
644 return false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000645}
646
647inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
648 size_t bufLen,
649 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000650#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000651 Dl_info dyldInfo;
652 if (dladdr((void *)addr, &dyldInfo)) {
653 if (dyldInfo.dli_sname != NULL) {
654 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
655 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
656 return true;
657 }
658 }
Xing Xuebbcbce92022-04-13 11:01:59 -0400659#elif defined(_AIX)
660 uint16_t nameLen;
661 char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
662 if (funcName != NULL) {
663 snprintf(buf, bufLen, "%.*s", nameLen, funcName);
664 return true;
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__