blob: 97dce1f95132157a7df7f68c7a04d8f0f4bb6b37 [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>
30#endif
31
32#ifdef __APPLE__
33#include <mach-o/getsect.h>
34namespace libunwind {
35 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
36}
37#endif
38
39#include "libunwind.h"
40#include "config.h"
41#include "dwarf2.h"
Ed Schoutenda7d6252017-03-07 18:21:51 +000042#include "EHHeaderParser.hpp"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000043#include "Registers.hpp"
44
John Baldwin67737ec2017-09-21 21:28:48 +000045#ifdef __APPLE__
46
47 struct dyld_unwind_sections
48 {
49 const struct mach_header* mh;
50 const void* dwarf_section;
51 uintptr_t dwarf_section_length;
52 const void* compact_unwind_section;
53 uintptr_t compact_unwind_section_length;
54 };
55 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
56 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
57 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
58 // In 10.7.0 or later, libSystem.dylib implements this function.
59 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
60 #else
61 // In 10.6.x and earlier, we need to implement this functionality. Note
62 // that this requires a newer version of libmacho (from cctools) than is
63 // present in libSystem on 10.6.x (for getsectiondata).
64 static inline bool _dyld_find_unwind_sections(void* addr,
65 dyld_unwind_sections* info) {
66 // Find mach-o image containing address.
67 Dl_info dlinfo;
68 if (!dladdr(addr, &dlinfo))
69 return false;
70#if __LP64__
71 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
72#else
73 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
74#endif
75
76 // Initialize the return struct
77 info->mh = (const struct mach_header *)mh;
78 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
79 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
80
81 if (!info->dwarf_section) {
82 info->dwarf_section_length = 0;
83 }
84
85 if (!info->compact_unwind_section) {
86 info->compact_unwind_section_length = 0;
87 }
88
89 return true;
90 }
91 #endif
92
whitequarkffd92e52017-12-25 17:05:07 +000093#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
94
95// When statically linked on bare-metal, the symbols for the EH table are looked
96// up without going through the dynamic loader.
97
98// The following linker script may be used to produce the necessary sections and symbols.
99// Unless the --eh-frame-hdr linker option is provided, the section is not generated
100// and does not take space in the output file.
101//
102// .eh_frame :
103// {
104// __eh_frame_start = .;
105// KEEP(*(.eh_frame))
106// __eh_frame_end = .;
107// }
108//
109// .eh_frame_hdr :
110// {
111// KEEP(*(.eh_frame_hdr))
112// }
113//
114// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
115// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
116
117extern char __eh_frame_start;
118extern char __eh_frame_end;
119
120#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
121extern char __eh_frame_hdr_start;
122extern char __eh_frame_hdr_end;
123#endif
124
John Baldwin67737ec2017-09-21 21:28:48 +0000125#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
126
127// When statically linked on bare-metal, the symbols for the EH table are looked
128// up without going through the dynamic loader.
129extern char __exidx_start;
130extern char __exidx_end;
131
132#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
133
134// ELF-based systems may use dl_iterate_phdr() to access sections
135// containing unwinding information. The ElfW() macro for pointer-size
136// independent ELF header traversal is not provided by <link.h> on some
137// systems (e.g., FreeBSD). On these systems the data structures are
138// just called Elf_XXX. Define ElfW() locally.
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000139#ifndef _WIN32
John Baldwin67737ec2017-09-21 21:28:48 +0000140#include <link.h>
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000141#else
142#include <windows.h>
143#include <psapi.h>
144#endif
John Baldwin67737ec2017-09-21 21:28:48 +0000145#if !defined(ElfW)
146#define ElfW(type) Elf_##type
147#endif
148
149#endif
150
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000151namespace libunwind {
152
153/// Used by findUnwindSections() to return info about needed sections.
154struct UnwindInfoSections {
Ranjeet Singh421231a2017-03-31 15:28:06 +0000155#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
156 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Charles Davisfa2e6202018-08-30 21:29:00 +0000157 // No dso_base for SEH or ARM EHABI.
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000158 uintptr_t dso_base;
159#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000160#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000161 uintptr_t dwarf_section;
162 uintptr_t dwarf_section_length;
163#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000164#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000165 uintptr_t dwarf_index_section;
166 uintptr_t dwarf_index_section_length;
167#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000168#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000169 uintptr_t compact_unwind_section;
170 uintptr_t compact_unwind_section_length;
171#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000172#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000173 uintptr_t arm_section;
174 uintptr_t arm_section_length;
175#endif
176};
177
178
179/// LocalAddressSpace is used as a template parameter to UnwindCursor when
180/// unwinding a thread in the same process. The wrappers compile away,
181/// making local unwinds fast.
Charles Davis04f0c2e2018-08-31 13:41:05 +0000182class _LIBUNWIND_HIDDEN LocalAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000183public:
Martin Storsjocac41382017-10-27 08:11:36 +0000184 typedef uintptr_t pint_t;
185 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000186 uint8_t get8(pint_t addr) {
187 uint8_t val;
188 memcpy(&val, (void *)addr, sizeof(val));
189 return val;
190 }
191 uint16_t get16(pint_t addr) {
192 uint16_t val;
193 memcpy(&val, (void *)addr, sizeof(val));
194 return val;
195 }
196 uint32_t get32(pint_t addr) {
197 uint32_t val;
198 memcpy(&val, (void *)addr, sizeof(val));
199 return val;
200 }
201 uint64_t get64(pint_t addr) {
202 uint64_t val;
203 memcpy(&val, (void *)addr, sizeof(val));
204 return val;
205 }
206 double getDouble(pint_t addr) {
207 double val;
208 memcpy(&val, (void *)addr, sizeof(val));
209 return val;
210 }
211 v128 getVector(pint_t addr) {
212 v128 val;
213 memcpy(&val, (void *)addr, sizeof(val));
214 return val;
215 }
216 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000217 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000218 static uint64_t getULEB128(pint_t &addr, pint_t end);
219 static int64_t getSLEB128(pint_t &addr, pint_t end);
220
221 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
222 pint_t datarelBase = 0);
223 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
224 unw_word_t *offset);
225 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
226 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
227
228 static LocalAddressSpace sThisAddressSpace;
229};
230
231inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000232#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000233 return get64(addr);
234#else
235 return get32(addr);
236#endif
237}
238
John Baldwin1a6e6be2018-02-27 21:24:02 +0000239inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
240#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
241 return get64(addr);
242#else
243 return get32(addr);
244#endif
245}
246
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000247/// Read a ULEB128 into a 64-bit word.
248inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
249 const uint8_t *p = (uint8_t *)addr;
250 const uint8_t *pend = (uint8_t *)end;
251 uint64_t result = 0;
252 int bit = 0;
253 do {
254 uint64_t b;
255
256 if (p == pend)
257 _LIBUNWIND_ABORT("truncated uleb128 expression");
258
259 b = *p & 0x7f;
260
261 if (bit >= 64 || b << bit >> bit != b) {
262 _LIBUNWIND_ABORT("malformed uleb128 expression");
263 } else {
264 result |= b << bit;
265 bit += 7;
266 }
267 } while (*p++ >= 0x80);
268 addr = (pint_t) p;
269 return result;
270}
271
272/// Read a SLEB128 into a 64-bit word.
273inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
274 const uint8_t *p = (uint8_t *)addr;
275 const uint8_t *pend = (uint8_t *)end;
276 int64_t result = 0;
277 int bit = 0;
278 uint8_t byte;
279 do {
280 if (p == pend)
281 _LIBUNWIND_ABORT("truncated sleb128 expression");
282 byte = *p++;
283 result |= ((byte & 0x7f) << bit);
284 bit += 7;
285 } while (byte & 0x80);
286 // sign extend negative numbers
287 if ((byte & 0x40) != 0)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000288 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000289 addr = (pint_t) p;
290 return result;
291}
292
293inline LocalAddressSpace::pint_t
294LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
295 pint_t datarelBase) {
296 pint_t startAddr = addr;
297 const uint8_t *p = (uint8_t *)addr;
298 pint_t result;
299
300 // first get value
301 switch (encoding & 0x0F) {
302 case DW_EH_PE_ptr:
303 result = getP(addr);
304 p += sizeof(pint_t);
305 addr = (pint_t) p;
306 break;
307 case DW_EH_PE_uleb128:
308 result = (pint_t)getULEB128(addr, end);
309 break;
310 case DW_EH_PE_udata2:
311 result = get16(addr);
312 p += 2;
313 addr = (pint_t) p;
314 break;
315 case DW_EH_PE_udata4:
316 result = get32(addr);
317 p += 4;
318 addr = (pint_t) p;
319 break;
320 case DW_EH_PE_udata8:
321 result = (pint_t)get64(addr);
322 p += 8;
323 addr = (pint_t) p;
324 break;
325 case DW_EH_PE_sleb128:
326 result = (pint_t)getSLEB128(addr, end);
327 break;
328 case DW_EH_PE_sdata2:
329 // Sign extend from signed 16-bit value.
330 result = (pint_t)(int16_t)get16(addr);
331 p += 2;
332 addr = (pint_t) p;
333 break;
334 case DW_EH_PE_sdata4:
335 // Sign extend from signed 32-bit value.
336 result = (pint_t)(int32_t)get32(addr);
337 p += 4;
338 addr = (pint_t) p;
339 break;
340 case DW_EH_PE_sdata8:
341 result = (pint_t)get64(addr);
342 p += 8;
343 addr = (pint_t) p;
344 break;
345 default:
346 _LIBUNWIND_ABORT("unknown pointer encoding");
347 }
348
349 // then add relative offset
350 switch (encoding & 0x70) {
351 case DW_EH_PE_absptr:
352 // do nothing
353 break;
354 case DW_EH_PE_pcrel:
355 result += startAddr;
356 break;
357 case DW_EH_PE_textrel:
358 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
359 break;
360 case DW_EH_PE_datarel:
361 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
362 // default value of 0, and we abort in the event that someone calls this
363 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
364 if (datarelBase == 0)
365 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
366 result += datarelBase;
367 break;
368 case DW_EH_PE_funcrel:
369 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
370 break;
371 case DW_EH_PE_aligned:
372 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
373 break;
374 default:
375 _LIBUNWIND_ABORT("unknown pointer encoding");
376 break;
377 }
378
379 if (encoding & DW_EH_PE_indirect)
380 result = getP(result);
381
382 return result;
383}
384
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000385inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
386 UnwindInfoSections &info) {
387#ifdef __APPLE__
388 dyld_unwind_sections dyldInfo;
389 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
390 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000391 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000392 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
393 info.dwarf_section_length = dyldInfo.dwarf_section_length;
394 #endif
395 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
396 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
397 return true;
398 }
whitequarkffd92e52017-12-25 17:05:07 +0000399#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
400 // Bare metal is statically linked, so no need to ask the dynamic loader
401 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
402 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000403 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
404 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000405#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
406 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
407 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000408 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
409 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000410#endif
411 if (info.dwarf_section_length)
412 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000413#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000414 // Bare metal is statically linked, so no need to ask the dynamic loader
415 info.arm_section = (uintptr_t)(&__exidx_start);
416 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000417 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
418 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000419 if (info.arm_section && info.arm_section_length)
420 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000421#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
422 HMODULE mods[1024];
423 HANDLE process = GetCurrentProcess();
424 DWORD needed;
425
426 if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
427 return false;
428
429 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
430 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
431 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
432 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
433 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
434 bool found_obj = false;
435 bool found_hdr = false;
436
437 info.dso_base = (uintptr_t)mods[i];
438 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
439 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
440 uintptr_t end = begin + pish->Misc.VirtualSize;
441 if (!strncmp((const char *)pish->Name, ".text",
442 IMAGE_SIZEOF_SHORT_NAME)) {
443 if (targetAddr >= begin && targetAddr < end)
444 found_obj = true;
445 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
446 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000447 info.dwarf_section = begin;
448 info.dwarf_section_length = pish->Misc.VirtualSize;
449 found_hdr = true;
450 }
451 if (found_obj && found_hdr)
452 return true;
453 }
454 }
455 return false;
Charles Davisfa2e6202018-08-30 21:29:00 +0000456#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
457 // Don't even bother, since Windows has functions that do all this stuff
458 // for us.
459 return true;
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000460#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
461 (__ANDROID_API__ < 21)
462 int length = 0;
463 info.arm_section =
464 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
465 info.arm_section_length = (uintptr_t)length;
466 if (info.arm_section && info.arm_section_length)
467 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000468#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000469 struct dl_iterate_cb_data {
470 LocalAddressSpace *addressSpace;
471 UnwindInfoSections *sects;
472 uintptr_t targetAddr;
473 };
474
475 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
476 int found = dl_iterate_phdr(
477 [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
478 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
Ed Schouten08032ee2017-02-23 09:13:22 +0000479 bool found_obj = false;
480 bool found_hdr = false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000481
482 assert(cbdata);
483 assert(cbdata->sects);
484
485 if (cbdata->targetAddr < pinfo->dlpi_addr) {
486 return false;
487 }
488
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000489#if !defined(Elf_Half)
490 typedef ElfW(Half) Elf_Half;
491#endif
492#if !defined(Elf_Phdr)
493 typedef ElfW(Phdr) Elf_Phdr;
494#endif
Ivan Krasind34d77f2017-04-06 17:35:35 +0000495#if !defined(Elf_Addr) && defined(__ANDROID__)
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000496 typedef ElfW(Addr) Elf_Addr;
497#endif
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000498
Ranjeet Singh421231a2017-03-31 15:28:06 +0000499 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
500 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Ed Schouten6a4939b2017-03-05 19:11:24 +0000501 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
502 #endif
503 size_t object_length;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000504#if defined(__ANDROID__)
505 Elf_Addr image_base =
Saleem Abdulrasoole4fe5f92017-04-05 21:29:38 +0000506 pinfo->dlpi_phnum
507 ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
508 reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
509 ->p_offset
510 : 0;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000511#endif
512
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000513 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
514 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000515 if (phdr->p_type == PT_LOAD) {
516 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000517#if defined(__ANDROID__)
518 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
519 begin = begin + image_base;
520#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000521 uintptr_t end = begin + phdr->p_memsz;
522 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
523 cbdata->sects->dso_base = begin;
524 object_length = phdr->p_memsz;
525 found_obj = true;
526 }
527 } else if (phdr->p_type == PT_GNU_EH_FRAME) {
528 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
529 uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000530#if defined(__ANDROID__)
531 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
532 eh_frame_hdr_start = eh_frame_hdr_start + image_base;
533#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000534 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
535 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
536 EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
537 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
538 hdrInfo);
539 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
540 found_hdr = true;
541 }
542 }
543
544 if (found_obj && found_hdr) {
545 cbdata->sects->dwarf_section_length = object_length;
546 return true;
547 } else {
548 return false;
549 }
Ranjeet Singh421231a2017-03-31 15:28:06 +0000550 #else // defined(_LIBUNWIND_ARM_EHABI)
Ed Schouten6a4939b2017-03-05 19:11:24 +0000551 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
552 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
553 if (phdr->p_type == PT_LOAD) {
554 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
555 uintptr_t end = begin + phdr->p_memsz;
556 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
557 found_obj = true;
558 } else if (phdr->p_type == PT_ARM_EXIDX) {
559 uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
560 cbdata->sects->arm_section = exidx_start;
Ed Schouten5d3f35b2017-03-07 15:21:57 +0000561 cbdata->sects->arm_section_length = phdr->p_memsz;
Ed Schouten6a4939b2017-03-05 19:11:24 +0000562 found_hdr = true;
563 }
564 }
565 return found_obj && found_hdr;
566 #endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000567 },
568 &cb_data);
569 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000570#endif
571
572 return false;
573}
574
575
576inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
577#ifdef __APPLE__
578 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
579#else
580 // TO DO: if OS has way to dynamically register FDEs, check that.
581 (void)targetAddr;
582 (void)fde;
583 return false;
584#endif
585}
586
587inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
588 size_t bufLen,
589 unw_word_t *offset) {
Jordan Rupprecht8ac87db2018-06-29 20:41:50 +0000590#if _LIBUNWIND_USE_DLADDR
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000591 Dl_info dyldInfo;
592 if (dladdr((void *)addr, &dyldInfo)) {
593 if (dyldInfo.dli_sname != NULL) {
594 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
595 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
596 return true;
597 }
598 }
599#endif
600 return false;
601}
602
603
604
605#ifdef UNW_REMOTE
606
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000607/// RemoteAddressSpace is used as a template parameter to UnwindCursor when
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000608/// unwinding a thread in the another process. The other process can be a
609/// different endianness and a different pointer size which is handled by
610/// the P template parameter.
611template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000612class RemoteAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000613public:
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000614 RemoteAddressSpace(task_t task) : fTask(task) {}
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000615
616 typedef typename P::uint_t pint_t;
617
618 uint8_t get8(pint_t addr);
619 uint16_t get16(pint_t addr);
620 uint32_t get32(pint_t addr);
621 uint64_t get64(pint_t addr);
622 pint_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000623 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000624 uint64_t getULEB128(pint_t &addr, pint_t end);
625 int64_t getSLEB128(pint_t &addr, pint_t end);
626 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
627 pint_t datarelBase = 0);
628 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
629 unw_word_t *offset);
630 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
631 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
632private:
633 void *localCopy(pint_t addr);
634
635 task_t fTask;
636};
637
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000638template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000639 return *((uint8_t *)localCopy(addr));
640}
641
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000642template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000643 return P::E::get16(*(uint16_t *)localCopy(addr));
644}
645
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000646template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000647 return P::E::get32(*(uint32_t *)localCopy(addr));
648}
649
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000650template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000651 return P::E::get64(*(uint64_t *)localCopy(addr));
652}
653
654template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000655typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000656 return P::getP(*(uint64_t *)localCopy(addr));
657}
658
659template <typename P>
John Baldwin1a6e6be2018-02-27 21:24:02 +0000660typename P::uint_t OtherAddressSpace<P>::getRegister(pint_t addr) {
661 return P::getRegister(*(uint64_t *)localCopy(addr));
662}
663
664template <typename P>
665uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000666 uintptr_t size = (end - addr);
667 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
668 LocalAddressSpace::pint_t sladdr = laddr;
669 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
670 addr += (laddr - sladdr);
671 return result;
672}
673
674template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000675int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000676 uintptr_t size = (end - addr);
677 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
678 LocalAddressSpace::pint_t sladdr = laddr;
679 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
680 addr += (laddr - sladdr);
681 return result;
682}
683
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000684template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000685 // FIX ME
686}
687
688template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000689bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
690 size_t bufLen,
691 unw_word_t *offset) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000692 // FIX ME
693}
694
695/// unw_addr_space is the base class that abstract unw_addr_space_t type in
696/// libunwind.h points to.
697struct unw_addr_space {
698 cpu_type_t cpuType;
699 task_t taskPort;
700};
701
702/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
703/// to when examining
704/// a 32-bit intel process.
705struct unw_addr_space_i386 : public unw_addr_space {
706 unw_addr_space_i386(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000707 RemoteAddressSpace<Pointer32<LittleEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000708};
709
710/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
711/// points to when examining
712/// a 64-bit intel process.
713struct unw_addr_space_x86_64 : public unw_addr_space {
714 unw_addr_space_x86_64(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000715 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000716};
717
718/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
719/// to when examining
720/// a 32-bit PowerPC process.
721struct unw_addr_space_ppc : public unw_addr_space {
722 unw_addr_space_ppc(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000723 RemoteAddressSpace<Pointer32<BigEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000724};
725
Martin Storsjo8338b0a2018-01-02 22:11:30 +0000726/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
727/// to when examining a 64-bit PowerPC process.
728struct unw_addr_space_ppc64 : public unw_addr_space {
729 unw_addr_space_ppc64(task_t task) : oas(task) {}
730 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
731};
732
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000733#endif // UNW_REMOTE
734
735} // namespace libunwind
736
737#endif // __ADDRESSSPACE_HPP__