blob: 32ff1f3d104d3f717a69a5840cf693a1408076d5 [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===------------------------- AddressSpace.hpp ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// Abstracts accessing local vs remote address spaces.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef __ADDRESSSPACE_HPP__
14#define __ADDRESSSPACE_HPP__
15
16#include <stdint.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
Martin Storsjo4c1f84d2017-10-11 20:06:18 +000021#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
Saleem Abdulrasool17552662015-04-24 19:39:17 +000022#include <dlfcn.h>
23#endif
24
25#ifdef __APPLE__
26#include <mach-o/getsect.h>
27namespace libunwind {
28 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
29}
30#endif
31
32#include "libunwind.h"
33#include "config.h"
34#include "dwarf2.h"
Ed Schoutenda7d6252017-03-07 18:21:51 +000035#include "EHHeaderParser.hpp"
Saleem Abdulrasool17552662015-04-24 19:39:17 +000036#include "Registers.hpp"
37
John Baldwin67737ec2017-09-21 21:28:48 +000038#ifdef __APPLE__
39
40 struct dyld_unwind_sections
41 {
42 const struct mach_header* mh;
43 const void* dwarf_section;
44 uintptr_t dwarf_section_length;
45 const void* compact_unwind_section;
46 uintptr_t compact_unwind_section_length;
47 };
48 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
49 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
50 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
51 // In 10.7.0 or later, libSystem.dylib implements this function.
52 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
53 #else
54 // In 10.6.x and earlier, we need to implement this functionality. Note
55 // that this requires a newer version of libmacho (from cctools) than is
56 // present in libSystem on 10.6.x (for getsectiondata).
57 static inline bool _dyld_find_unwind_sections(void* addr,
58 dyld_unwind_sections* info) {
59 // Find mach-o image containing address.
60 Dl_info dlinfo;
61 if (!dladdr(addr, &dlinfo))
62 return false;
63#if __LP64__
64 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
65#else
66 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
67#endif
68
69 // Initialize the return struct
70 info->mh = (const struct mach_header *)mh;
71 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
72 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
73
74 if (!info->dwarf_section) {
75 info->dwarf_section_length = 0;
76 }
77
78 if (!info->compact_unwind_section) {
79 info->compact_unwind_section_length = 0;
80 }
81
82 return true;
83 }
84 #endif
85
whitequarkffd92e52017-12-25 17:05:07 +000086#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
87
88// When statically linked on bare-metal, the symbols for the EH table are looked
89// up without going through the dynamic loader.
90
91// The following linker script may be used to produce the necessary sections and symbols.
92// Unless the --eh-frame-hdr linker option is provided, the section is not generated
93// and does not take space in the output file.
94//
95// .eh_frame :
96// {
97// __eh_frame_start = .;
98// KEEP(*(.eh_frame))
99// __eh_frame_end = .;
100// }
101//
102// .eh_frame_hdr :
103// {
104// KEEP(*(.eh_frame_hdr))
105// }
106//
107// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
108// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
109
110extern char __eh_frame_start;
111extern char __eh_frame_end;
112
113#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
114extern char __eh_frame_hdr_start;
115extern char __eh_frame_hdr_end;
116#endif
117
John Baldwin67737ec2017-09-21 21:28:48 +0000118#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
119
120// When statically linked on bare-metal, the symbols for the EH table are looked
121// up without going through the dynamic loader.
122extern char __exidx_start;
123extern char __exidx_end;
124
125#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
126
127// ELF-based systems may use dl_iterate_phdr() to access sections
128// containing unwinding information. The ElfW() macro for pointer-size
129// independent ELF header traversal is not provided by <link.h> on some
130// systems (e.g., FreeBSD). On these systems the data structures are
131// just called Elf_XXX. Define ElfW() locally.
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000132#ifndef _WIN32
John Baldwin67737ec2017-09-21 21:28:48 +0000133#include <link.h>
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000134#else
135#include <windows.h>
136#include <psapi.h>
137#endif
John Baldwin67737ec2017-09-21 21:28:48 +0000138#if !defined(ElfW)
139#define ElfW(type) Elf_##type
140#endif
141
142#endif
143
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000144namespace libunwind {
145
146/// Used by findUnwindSections() to return info about needed sections.
147struct UnwindInfoSections {
Ranjeet Singh421231a2017-03-31 15:28:06 +0000148#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
149 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000150 // No dso_base for ARM EHABI.
151 uintptr_t dso_base;
152#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000153#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000154 uintptr_t dwarf_section;
155 uintptr_t dwarf_section_length;
156#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000157#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000158 uintptr_t dwarf_index_section;
159 uintptr_t dwarf_index_section_length;
160#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000161#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000162 uintptr_t compact_unwind_section;
163 uintptr_t compact_unwind_section_length;
164#endif
Ranjeet Singh421231a2017-03-31 15:28:06 +0000165#if defined(_LIBUNWIND_ARM_EHABI)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000166 uintptr_t arm_section;
167 uintptr_t arm_section_length;
168#endif
169};
170
171
172/// LocalAddressSpace is used as a template parameter to UnwindCursor when
173/// unwinding a thread in the same process. The wrappers compile away,
174/// making local unwinds fast.
175class __attribute__((visibility("hidden"))) LocalAddressSpace {
176public:
Martin Storsjocac41382017-10-27 08:11:36 +0000177 typedef uintptr_t pint_t;
178 typedef intptr_t sint_t;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000179 uint8_t get8(pint_t addr) {
180 uint8_t val;
181 memcpy(&val, (void *)addr, sizeof(val));
182 return val;
183 }
184 uint16_t get16(pint_t addr) {
185 uint16_t val;
186 memcpy(&val, (void *)addr, sizeof(val));
187 return val;
188 }
189 uint32_t get32(pint_t addr) {
190 uint32_t val;
191 memcpy(&val, (void *)addr, sizeof(val));
192 return val;
193 }
194 uint64_t get64(pint_t addr) {
195 uint64_t val;
196 memcpy(&val, (void *)addr, sizeof(val));
197 return val;
198 }
199 double getDouble(pint_t addr) {
200 double val;
201 memcpy(&val, (void *)addr, sizeof(val));
202 return val;
203 }
204 v128 getVector(pint_t addr) {
205 v128 val;
206 memcpy(&val, (void *)addr, sizeof(val));
207 return val;
208 }
209 uintptr_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000210 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000211 static uint64_t getULEB128(pint_t &addr, pint_t end);
212 static int64_t getSLEB128(pint_t &addr, pint_t end);
213
214 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
215 pint_t datarelBase = 0);
216 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
217 unw_word_t *offset);
218 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
219 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
220
221 static LocalAddressSpace sThisAddressSpace;
222};
223
224inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
Martin Storsjocac41382017-10-27 08:11:36 +0000225#if __SIZEOF_POINTER__ == 8
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000226 return get64(addr);
227#else
228 return get32(addr);
229#endif
230}
231
John Baldwin1a6e6be2018-02-27 21:24:02 +0000232inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
233#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
234 return get64(addr);
235#else
236 return get32(addr);
237#endif
238}
239
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000240/// Read a ULEB128 into a 64-bit word.
241inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
242 const uint8_t *p = (uint8_t *)addr;
243 const uint8_t *pend = (uint8_t *)end;
244 uint64_t result = 0;
245 int bit = 0;
246 do {
247 uint64_t b;
248
249 if (p == pend)
250 _LIBUNWIND_ABORT("truncated uleb128 expression");
251
252 b = *p & 0x7f;
253
254 if (bit >= 64 || b << bit >> bit != b) {
255 _LIBUNWIND_ABORT("malformed uleb128 expression");
256 } else {
257 result |= b << bit;
258 bit += 7;
259 }
260 } while (*p++ >= 0x80);
261 addr = (pint_t) p;
262 return result;
263}
264
265/// Read a SLEB128 into a 64-bit word.
266inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
267 const uint8_t *p = (uint8_t *)addr;
268 const uint8_t *pend = (uint8_t *)end;
269 int64_t result = 0;
270 int bit = 0;
271 uint8_t byte;
272 do {
273 if (p == pend)
274 _LIBUNWIND_ABORT("truncated sleb128 expression");
275 byte = *p++;
276 result |= ((byte & 0x7f) << bit);
277 bit += 7;
278 } while (byte & 0x80);
279 // sign extend negative numbers
280 if ((byte & 0x40) != 0)
Marshall Clowa6d7c382017-06-21 16:02:53 +0000281 result |= (-1ULL) << bit;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000282 addr = (pint_t) p;
283 return result;
284}
285
286inline LocalAddressSpace::pint_t
287LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
288 pint_t datarelBase) {
289 pint_t startAddr = addr;
290 const uint8_t *p = (uint8_t *)addr;
291 pint_t result;
292
293 // first get value
294 switch (encoding & 0x0F) {
295 case DW_EH_PE_ptr:
296 result = getP(addr);
297 p += sizeof(pint_t);
298 addr = (pint_t) p;
299 break;
300 case DW_EH_PE_uleb128:
301 result = (pint_t)getULEB128(addr, end);
302 break;
303 case DW_EH_PE_udata2:
304 result = get16(addr);
305 p += 2;
306 addr = (pint_t) p;
307 break;
308 case DW_EH_PE_udata4:
309 result = get32(addr);
310 p += 4;
311 addr = (pint_t) p;
312 break;
313 case DW_EH_PE_udata8:
314 result = (pint_t)get64(addr);
315 p += 8;
316 addr = (pint_t) p;
317 break;
318 case DW_EH_PE_sleb128:
319 result = (pint_t)getSLEB128(addr, end);
320 break;
321 case DW_EH_PE_sdata2:
322 // Sign extend from signed 16-bit value.
323 result = (pint_t)(int16_t)get16(addr);
324 p += 2;
325 addr = (pint_t) p;
326 break;
327 case DW_EH_PE_sdata4:
328 // Sign extend from signed 32-bit value.
329 result = (pint_t)(int32_t)get32(addr);
330 p += 4;
331 addr = (pint_t) p;
332 break;
333 case DW_EH_PE_sdata8:
334 result = (pint_t)get64(addr);
335 p += 8;
336 addr = (pint_t) p;
337 break;
338 default:
339 _LIBUNWIND_ABORT("unknown pointer encoding");
340 }
341
342 // then add relative offset
343 switch (encoding & 0x70) {
344 case DW_EH_PE_absptr:
345 // do nothing
346 break;
347 case DW_EH_PE_pcrel:
348 result += startAddr;
349 break;
350 case DW_EH_PE_textrel:
351 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
352 break;
353 case DW_EH_PE_datarel:
354 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
355 // default value of 0, and we abort in the event that someone calls this
356 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
357 if (datarelBase == 0)
358 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
359 result += datarelBase;
360 break;
361 case DW_EH_PE_funcrel:
362 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
363 break;
364 case DW_EH_PE_aligned:
365 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
366 break;
367 default:
368 _LIBUNWIND_ABORT("unknown pointer encoding");
369 break;
370 }
371
372 if (encoding & DW_EH_PE_indirect)
373 result = getP(result);
374
375 return result;
376}
377
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000378inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
379 UnwindInfoSections &info) {
380#ifdef __APPLE__
381 dyld_unwind_sections dyldInfo;
382 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
383 info.dso_base = (uintptr_t)dyldInfo.mh;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000384 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000385 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
386 info.dwarf_section_length = dyldInfo.dwarf_section_length;
387 #endif
388 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
389 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
390 return true;
391 }
whitequarkffd92e52017-12-25 17:05:07 +0000392#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
393 // Bare metal is statically linked, so no need to ask the dynamic loader
394 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
395 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000396 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
397 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000398#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
399 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
400 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000401 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
402 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
whitequarkffd92e52017-12-25 17:05:07 +0000403#endif
404 if (info.dwarf_section_length)
405 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000406#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000407 // Bare metal is statically linked, so no need to ask the dynamic loader
408 info.arm_section = (uintptr_t)(&__exidx_start);
409 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
Chandler Carruth3d957272017-12-27 05:46:53 +0000410 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
411 (void *)info.arm_section, (void *)info.arm_section_length);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000412 if (info.arm_section && info.arm_section_length)
413 return true;
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000414#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
415 HMODULE mods[1024];
416 HANDLE process = GetCurrentProcess();
417 DWORD needed;
418
419 if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
420 return false;
421
422 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
423 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
424 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
425 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
426 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
427 bool found_obj = false;
428 bool found_hdr = false;
429
430 info.dso_base = (uintptr_t)mods[i];
431 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
432 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
433 uintptr_t end = begin + pish->Misc.VirtualSize;
434 if (!strncmp((const char *)pish->Name, ".text",
435 IMAGE_SIZEOF_SHORT_NAME)) {
436 if (targetAddr >= begin && targetAddr < end)
437 found_obj = true;
438 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
439 IMAGE_SIZEOF_SHORT_NAME)) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000440 info.dwarf_section = begin;
441 info.dwarf_section_length = pish->Misc.VirtualSize;
442 found_hdr = true;
443 }
444 if (found_obj && found_hdr)
445 return true;
446 }
447 }
448 return false;
Dan Albert1bf6ebe2017-11-01 21:26:06 +0000449#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
450 (__ANDROID_API__ < 21)
451 int length = 0;
452 info.arm_section =
453 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
454 info.arm_section_length = (uintptr_t)length;
455 if (info.arm_section && info.arm_section_length)
456 return true;
Ranjeet Singh421231a2017-03-31 15:28:06 +0000457#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000458 struct dl_iterate_cb_data {
459 LocalAddressSpace *addressSpace;
460 UnwindInfoSections *sects;
461 uintptr_t targetAddr;
462 };
463
464 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
465 int found = dl_iterate_phdr(
466 [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
467 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
Ed Schouten08032ee2017-02-23 09:13:22 +0000468 bool found_obj = false;
469 bool found_hdr = false;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000470
471 assert(cbdata);
472 assert(cbdata->sects);
473
474 if (cbdata->targetAddr < pinfo->dlpi_addr) {
475 return false;
476 }
477
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000478#if !defined(Elf_Half)
479 typedef ElfW(Half) Elf_Half;
480#endif
481#if !defined(Elf_Phdr)
482 typedef ElfW(Phdr) Elf_Phdr;
483#endif
Ivan Krasind34d77f2017-04-06 17:35:35 +0000484#if !defined(Elf_Addr) && defined(__ANDROID__)
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000485 typedef ElfW(Addr) Elf_Addr;
486#endif
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000487
Ranjeet Singh421231a2017-03-31 15:28:06 +0000488 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
489 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
Ed Schouten6a4939b2017-03-05 19:11:24 +0000490 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
491 #endif
492 size_t object_length;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000493#if defined(__ANDROID__)
494 Elf_Addr image_base =
Saleem Abdulrasoole4fe5f92017-04-05 21:29:38 +0000495 pinfo->dlpi_phnum
496 ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
497 reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
498 ->p_offset
499 : 0;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000500#endif
501
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000502 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
503 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000504 if (phdr->p_type == PT_LOAD) {
505 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000506#if defined(__ANDROID__)
507 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
508 begin = begin + image_base;
509#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000510 uintptr_t end = begin + phdr->p_memsz;
511 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
512 cbdata->sects->dso_base = begin;
513 object_length = phdr->p_memsz;
514 found_obj = true;
515 }
516 } else if (phdr->p_type == PT_GNU_EH_FRAME) {
517 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
518 uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
Saleem Abdulrasool241fe722017-04-05 18:33:23 +0000519#if defined(__ANDROID__)
520 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
521 eh_frame_hdr_start = eh_frame_hdr_start + image_base;
522#endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000523 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
524 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
525 EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
526 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
527 hdrInfo);
528 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
529 found_hdr = true;
530 }
531 }
532
533 if (found_obj && found_hdr) {
534 cbdata->sects->dwarf_section_length = object_length;
535 return true;
536 } else {
537 return false;
538 }
Ranjeet Singh421231a2017-03-31 15:28:06 +0000539 #else // defined(_LIBUNWIND_ARM_EHABI)
Ed Schouten6a4939b2017-03-05 19:11:24 +0000540 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
541 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
542 if (phdr->p_type == PT_LOAD) {
543 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
544 uintptr_t end = begin + phdr->p_memsz;
545 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
546 found_obj = true;
547 } else if (phdr->p_type == PT_ARM_EXIDX) {
548 uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
549 cbdata->sects->arm_section = exidx_start;
Ed Schouten5d3f35b2017-03-07 15:21:57 +0000550 cbdata->sects->arm_section_length = phdr->p_memsz;
Ed Schouten6a4939b2017-03-05 19:11:24 +0000551 found_hdr = true;
552 }
553 }
554 return found_obj && found_hdr;
555 #endif
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000556 },
557 &cb_data);
558 return static_cast<bool>(found);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000559#endif
560
561 return false;
562}
563
564
565inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
566#ifdef __APPLE__
567 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
568#else
569 // TO DO: if OS has way to dynamically register FDEs, check that.
570 (void)targetAddr;
571 (void)fde;
572 return false;
573#endif
574}
575
576inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
577 size_t bufLen,
578 unw_word_t *offset) {
Martin Storsjo4c1f84d2017-10-11 20:06:18 +0000579#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000580 Dl_info dyldInfo;
581 if (dladdr((void *)addr, &dyldInfo)) {
582 if (dyldInfo.dli_sname != NULL) {
583 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
584 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
585 return true;
586 }
587 }
588#endif
589 return false;
590}
591
592
593
594#ifdef UNW_REMOTE
595
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000596/// RemoteAddressSpace is used as a template parameter to UnwindCursor when
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000597/// unwinding a thread in the another process. The other process can be a
598/// different endianness and a different pointer size which is handled by
599/// the P template parameter.
600template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000601class RemoteAddressSpace {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000602public:
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000603 RemoteAddressSpace(task_t task) : fTask(task) {}
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000604
605 typedef typename P::uint_t pint_t;
606
607 uint8_t get8(pint_t addr);
608 uint16_t get16(pint_t addr);
609 uint32_t get32(pint_t addr);
610 uint64_t get64(pint_t addr);
611 pint_t getP(pint_t addr);
John Baldwin1a6e6be2018-02-27 21:24:02 +0000612 uint64_t getRegister(pint_t addr);
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000613 uint64_t getULEB128(pint_t &addr, pint_t end);
614 int64_t getSLEB128(pint_t &addr, pint_t end);
615 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
616 pint_t datarelBase = 0);
617 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
618 unw_word_t *offset);
619 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
620 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
621private:
622 void *localCopy(pint_t addr);
623
624 task_t fTask;
625};
626
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000627template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000628 return *((uint8_t *)localCopy(addr));
629}
630
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000631template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000632 return P::E::get16(*(uint16_t *)localCopy(addr));
633}
634
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000635template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000636 return P::E::get32(*(uint32_t *)localCopy(addr));
637}
638
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000639template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000640 return P::E::get64(*(uint64_t *)localCopy(addr));
641}
642
643template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000644typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000645 return P::getP(*(uint64_t *)localCopy(addr));
646}
647
648template <typename P>
John Baldwin1a6e6be2018-02-27 21:24:02 +0000649typename P::uint_t OtherAddressSpace<P>::getRegister(pint_t addr) {
650 return P::getRegister(*(uint64_t *)localCopy(addr));
651}
652
653template <typename P>
654uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000655 uintptr_t size = (end - addr);
656 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
657 LocalAddressSpace::pint_t sladdr = laddr;
658 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
659 addr += (laddr - sladdr);
660 return result;
661}
662
663template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000664int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000665 uintptr_t size = (end - addr);
666 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
667 LocalAddressSpace::pint_t sladdr = laddr;
668 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
669 addr += (laddr - sladdr);
670 return result;
671}
672
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000673template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000674 // FIX ME
675}
676
677template <typename P>
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000678bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
679 size_t bufLen,
680 unw_word_t *offset) {
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000681 // FIX ME
682}
683
684/// unw_addr_space is the base class that abstract unw_addr_space_t type in
685/// libunwind.h points to.
686struct unw_addr_space {
687 cpu_type_t cpuType;
688 task_t taskPort;
689};
690
691/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
692/// to when examining
693/// a 32-bit intel process.
694struct unw_addr_space_i386 : public unw_addr_space {
695 unw_addr_space_i386(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000696 RemoteAddressSpace<Pointer32<LittleEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000697};
698
699/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
700/// points to when examining
701/// a 64-bit intel process.
702struct unw_addr_space_x86_64 : public unw_addr_space {
703 unw_addr_space_x86_64(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000704 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000705};
706
707/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
708/// to when examining
709/// a 32-bit PowerPC process.
710struct unw_addr_space_ppc : public unw_addr_space {
711 unw_addr_space_ppc(task_t task) : oas(task) {}
Saleem Abdulrasool66efa8e2017-01-21 16:22:46 +0000712 RemoteAddressSpace<Pointer32<BigEndian>> oas;
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000713};
714
Martin Storsjo8338b0a2018-01-02 22:11:30 +0000715/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
716/// to when examining a 64-bit PowerPC process.
717struct unw_addr_space_ppc64 : public unw_addr_space {
718 unw_addr_space_ppc64(task_t task) : oas(task) {}
719 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
720};
721
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000722#endif // UNW_REMOTE
723
724} // namespace libunwind
725
726#endif // __ADDRESSSPACE_HPP__