1*202cdb0eSrobert //===----------------------------------------------------------------------===//
2f6c50668Spatrick //
3f6c50668Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f6c50668Spatrick // See https://llvm.org/LICENSE.txt for license information.
5f6c50668Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f6c50668Spatrick //
7f6c50668Spatrick //
8f6c50668Spatrick // Abstracts accessing local vs remote address spaces.
9f6c50668Spatrick //
10f6c50668Spatrick //===----------------------------------------------------------------------===//
11f6c50668Spatrick
12f6c50668Spatrick #ifndef __ADDRESSSPACE_HPP__
13f6c50668Spatrick #define __ADDRESSSPACE_HPP__
14f6c50668Spatrick
15f6c50668Spatrick #include <stdint.h>
16f6c50668Spatrick #include <stdio.h>
17f6c50668Spatrick #include <stdlib.h>
18f6c50668Spatrick #include <string.h>
19974930e3Spatrick #include <sys/tree.h>
20f6c50668Spatrick
21a0747c9fSpatrick #include "libunwind.h"
22a0747c9fSpatrick #include "config.h"
23a0747c9fSpatrick #include "dwarf2.h"
24a0747c9fSpatrick #include "EHHeaderParser.hpp"
25a0747c9fSpatrick #include "Registers.hpp"
26a0747c9fSpatrick
27f6c50668Spatrick #ifndef _LIBUNWIND_USE_DLADDR
28*202cdb0eSrobert #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
29f6c50668Spatrick #define _LIBUNWIND_USE_DLADDR 1
30f6c50668Spatrick #else
31f6c50668Spatrick #define _LIBUNWIND_USE_DLADDR 0
32f6c50668Spatrick #endif
33f6c50668Spatrick #endif
34f6c50668Spatrick
35f6c50668Spatrick #if _LIBUNWIND_USE_DLADDR
36f6c50668Spatrick #include <dlfcn.h>
37f6c50668Spatrick #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
38f6c50668Spatrick #pragma comment(lib, "dl")
39f6c50668Spatrick #endif
40f6c50668Spatrick #endif
41f6c50668Spatrick
42f6c50668Spatrick #if defined(_LIBUNWIND_ARM_EHABI)
43f6c50668Spatrick struct EHABIIndexEntry {
44f6c50668Spatrick uint32_t functionOffset;
45f6c50668Spatrick uint32_t data;
46f6c50668Spatrick };
47f6c50668Spatrick #endif
48f6c50668Spatrick
49*202cdb0eSrobert #if defined(_AIX)
50*202cdb0eSrobert namespace libunwind {
51*202cdb0eSrobert char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
52*202cdb0eSrobert unw_word_t *offset);
53*202cdb0eSrobert }
54*202cdb0eSrobert #endif
55*202cdb0eSrobert
56f6c50668Spatrick #ifdef __APPLE__
57f6c50668Spatrick
58f6c50668Spatrick struct dyld_unwind_sections
59f6c50668Spatrick {
60f6c50668Spatrick const struct mach_header* mh;
61f6c50668Spatrick const void* dwarf_section;
62f6c50668Spatrick uintptr_t dwarf_section_length;
63f6c50668Spatrick const void* compact_unwind_section;
64f6c50668Spatrick uintptr_t compact_unwind_section_length;
65f6c50668Spatrick };
66a0747c9fSpatrick
67f6c50668Spatrick // In 10.7.0 or later, libSystem.dylib implements this function.
68f6c50668Spatrick extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
69f6c50668Spatrick
70f6c50668Spatrick #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
71f6c50668Spatrick
72f6c50668Spatrick // When statically linked on bare-metal, the symbols for the EH table are looked
73f6c50668Spatrick // up without going through the dynamic loader.
74f6c50668Spatrick
75f6c50668Spatrick // The following linker script may be used to produce the necessary sections and symbols.
76f6c50668Spatrick // Unless the --eh-frame-hdr linker option is provided, the section is not generated
77f6c50668Spatrick // and does not take space in the output file.
78f6c50668Spatrick //
79f6c50668Spatrick // .eh_frame :
80f6c50668Spatrick // {
81f6c50668Spatrick // __eh_frame_start = .;
82f6c50668Spatrick // KEEP(*(.eh_frame))
83f6c50668Spatrick // __eh_frame_end = .;
84f6c50668Spatrick // }
85f6c50668Spatrick //
86f6c50668Spatrick // .eh_frame_hdr :
87f6c50668Spatrick // {
88f6c50668Spatrick // KEEP(*(.eh_frame_hdr))
89f6c50668Spatrick // }
90f6c50668Spatrick //
91f6c50668Spatrick // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
92f6c50668Spatrick // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
93f6c50668Spatrick
94f6c50668Spatrick extern char __eh_frame_start;
95f6c50668Spatrick extern char __eh_frame_end;
96f6c50668Spatrick
97f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
98f6c50668Spatrick extern char __eh_frame_hdr_start;
99f6c50668Spatrick extern char __eh_frame_hdr_end;
100f6c50668Spatrick #endif
101f6c50668Spatrick
102f6c50668Spatrick #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
103f6c50668Spatrick
104f6c50668Spatrick // When statically linked on bare-metal, the symbols for the EH table are looked
105f6c50668Spatrick // up without going through the dynamic loader.
106f6c50668Spatrick extern char __exidx_start;
107f6c50668Spatrick extern char __exidx_end;
108f6c50668Spatrick
109a0747c9fSpatrick #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
110f6c50668Spatrick
111f6c50668Spatrick #include <windows.h>
112f6c50668Spatrick #include <psapi.h>
113a0747c9fSpatrick
114a0747c9fSpatrick #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
115a0747c9fSpatrick defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
116a0747c9fSpatrick
117a0747c9fSpatrick #include <link.h>
118f6c50668Spatrick
119f6c50668Spatrick #endif
120f6c50668Spatrick
121f6c50668Spatrick namespace libunwind {
122f6c50668Spatrick
123f6c50668Spatrick /// Used by findUnwindSections() to return info about needed sections.
124f6c50668Spatrick struct UnwindInfoSections {
125a0747c9fSpatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
126a0747c9fSpatrick defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
127a0747c9fSpatrick defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
128a0747c9fSpatrick // No dso_base for SEH.
129f6c50668Spatrick uintptr_t dso_base;
130f6c50668Spatrick #endif
131a0747c9fSpatrick #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
132*202cdb0eSrobert size_t text_segment_length;
133a0747c9fSpatrick #endif
134f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
135f6c50668Spatrick uintptr_t dwarf_section;
136*202cdb0eSrobert size_t dwarf_section_length;
137f6c50668Spatrick #endif
138f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
139f6c50668Spatrick uintptr_t dwarf_index_section;
140*202cdb0eSrobert size_t dwarf_index_section_length;
141f6c50668Spatrick #endif
142f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
143f6c50668Spatrick uintptr_t compact_unwind_section;
144*202cdb0eSrobert size_t compact_unwind_section_length;
145f6c50668Spatrick #endif
146f6c50668Spatrick #if defined(_LIBUNWIND_ARM_EHABI)
147f6c50668Spatrick uintptr_t arm_section;
148*202cdb0eSrobert size_t arm_section_length;
149f6c50668Spatrick #endif
150f6c50668Spatrick };
151f6c50668Spatrick
152974930e3Spatrick class UnwindInfoSectionsCache {
153974930e3Spatrick public:
154974930e3Spatrick
155974930e3Spatrick struct CacheItem {
CacheItemlibunwind::UnwindInfoSectionsCache::CacheItem156974930e3Spatrick CacheItem(UnwindInfoSections &uis, uintptr_t pc)
157974930e3Spatrick : m_uis(uis), m_pc(pc) {
158974930e3Spatrick }
CacheItemlibunwind::UnwindInfoSectionsCache::CacheItem159974930e3Spatrick CacheItem(uintptr_t pc)
160974930e3Spatrick : m_pc(pc) {
161974930e3Spatrick }
162974930e3Spatrick
163974930e3Spatrick UnwindInfoSections m_uis;
164974930e3Spatrick uintptr_t m_pc;
165974930e3Spatrick
166974930e3Spatrick RB_ENTRY(CacheItem) entry;
167974930e3Spatrick };
168974930e3Spatrick
169974930e3Spatrick typedef uintptr_t CacheItemKey;
170974930e3Spatrick
CacheCmp(struct CacheItem * c1,struct CacheItem * c2)171974930e3Spatrick int CacheCmp(struct CacheItem *c1, struct CacheItem *c2) {
172974930e3Spatrick return (c1->m_pc < c2->m_pc ? -1 : c1->m_pc > c2->m_pc);
173974930e3Spatrick }
174974930e3Spatrick
UnwindInfoSectionsCache()175974930e3Spatrick UnwindInfoSectionsCache() {
176974930e3Spatrick m_head = RB_INITIALIZER(&head);
177974930e3Spatrick }
178974930e3Spatrick
getUnwindInfoSectionsForPC(CacheItemKey key,UnwindInfoSections & uis)179974930e3Spatrick bool getUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
180974930e3Spatrick UnwindInfoSections *result = nullptr;
181974930e3Spatrick if (m_prev_req_item && m_prev_req_item->m_pc == key)
182974930e3Spatrick result = &m_prev_req_item->m_uis;
183974930e3Spatrick else {
184974930e3Spatrick struct CacheItem find(key), *res;
185974930e3Spatrick res = RB_FIND(CacheTree, &m_head, &find);
186974930e3Spatrick if (res) {
187974930e3Spatrick m_prev_req_item = res;
188974930e3Spatrick result = &res->m_uis;
189974930e3Spatrick }
190974930e3Spatrick }
191974930e3Spatrick if (result) {
192974930e3Spatrick uis = *result;
193974930e3Spatrick return true;
194974930e3Spatrick }
195974930e3Spatrick return false;
196974930e3Spatrick }
197974930e3Spatrick
setUnwindInfoSectionsForPC(CacheItemKey key,UnwindInfoSections & uis)198974930e3Spatrick void setUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
199974930e3Spatrick CacheItem *p_item(new CacheItem(uis, key));
200974930e3Spatrick RB_INSERT(CacheTree, &m_head, p_item);
201974930e3Spatrick }
202974930e3Spatrick
203974930e3Spatrick private:
204974930e3Spatrick CacheItem *m_prev_req_item = nullptr;
205974930e3Spatrick RB_HEAD(CacheTree, CacheItem) m_head;
206974930e3Spatrick RB_GENERATE(CacheTree, CacheItem, entry, CacheCmp);
207974930e3Spatrick };
208f6c50668Spatrick
209f6c50668Spatrick /// LocalAddressSpace is used as a template parameter to UnwindCursor when
210f6c50668Spatrick /// unwinding a thread in the same process. The wrappers compile away,
211f6c50668Spatrick /// making local unwinds fast.
212f6c50668Spatrick class _LIBUNWIND_HIDDEN LocalAddressSpace {
213f6c50668Spatrick public:
214f6c50668Spatrick typedef uintptr_t pint_t;
215f6c50668Spatrick typedef intptr_t sint_t;
get8(pint_t addr)216f6c50668Spatrick uint8_t get8(pint_t addr) {
217f6c50668Spatrick uint8_t val;
218f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
219f6c50668Spatrick return val;
220f6c50668Spatrick }
get16(pint_t addr)221f6c50668Spatrick uint16_t get16(pint_t addr) {
222f6c50668Spatrick uint16_t val;
223f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
224f6c50668Spatrick return val;
225f6c50668Spatrick }
get32(pint_t addr)226f6c50668Spatrick uint32_t get32(pint_t addr) {
227f6c50668Spatrick uint32_t val;
228f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
229f6c50668Spatrick return val;
230f6c50668Spatrick }
get64(pint_t addr)231f6c50668Spatrick uint64_t get64(pint_t addr) {
232f6c50668Spatrick uint64_t val;
233f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
234f6c50668Spatrick return val;
235f6c50668Spatrick }
getDouble(pint_t addr)236f6c50668Spatrick double getDouble(pint_t addr) {
237f6c50668Spatrick double val;
238f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
239f6c50668Spatrick return val;
240f6c50668Spatrick }
getVector(pint_t addr)241f6c50668Spatrick v128 getVector(pint_t addr) {
242f6c50668Spatrick v128 val;
243f6c50668Spatrick memcpy(&val, (void *)addr, sizeof(val));
244f6c50668Spatrick return val;
245f6c50668Spatrick }
246f6c50668Spatrick uintptr_t getP(pint_t addr);
247f6c50668Spatrick uint64_t getRegister(pint_t addr);
248f6c50668Spatrick static uint64_t getULEB128(pint_t &addr, pint_t end);
249f6c50668Spatrick static int64_t getSLEB128(pint_t &addr, pint_t end);
250f6c50668Spatrick
251f6c50668Spatrick pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
252f6c50668Spatrick pint_t datarelBase = 0);
253f6c50668Spatrick bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
254f6c50668Spatrick unw_word_t *offset);
255f6c50668Spatrick bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
256f6c50668Spatrick bool findOtherFDE(pint_t targetAddr, pint_t &fde);
257f6c50668Spatrick
258f6c50668Spatrick static LocalAddressSpace sThisAddressSpace;
259f6c50668Spatrick };
260f6c50668Spatrick
getP(pint_t addr)261f6c50668Spatrick inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
262f6c50668Spatrick #if __SIZEOF_POINTER__ == 8
263f6c50668Spatrick return get64(addr);
264f6c50668Spatrick #else
265f6c50668Spatrick return get32(addr);
266f6c50668Spatrick #endif
267f6c50668Spatrick }
268f6c50668Spatrick
getRegister(pint_t addr)269f6c50668Spatrick inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
270f6c50668Spatrick #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
271f6c50668Spatrick return get64(addr);
272f6c50668Spatrick #else
273f6c50668Spatrick return get32(addr);
274f6c50668Spatrick #endif
275f6c50668Spatrick }
276f6c50668Spatrick
277f6c50668Spatrick /// Read a ULEB128 into a 64-bit word.
getULEB128(pint_t & addr,pint_t end)278f6c50668Spatrick inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
279f6c50668Spatrick const uint8_t *p = (uint8_t *)addr;
280f6c50668Spatrick const uint8_t *pend = (uint8_t *)end;
281f6c50668Spatrick uint64_t result = 0;
282f6c50668Spatrick int bit = 0;
283f6c50668Spatrick do {
284f6c50668Spatrick uint64_t b;
285f6c50668Spatrick
286f6c50668Spatrick if (p == pend)
287f6c50668Spatrick _LIBUNWIND_ABORT("truncated uleb128 expression");
288f6c50668Spatrick
289f6c50668Spatrick b = *p & 0x7f;
290f6c50668Spatrick
291f6c50668Spatrick if (bit >= 64 || b << bit >> bit != b) {
292f6c50668Spatrick _LIBUNWIND_ABORT("malformed uleb128 expression");
293f6c50668Spatrick } else {
294f6c50668Spatrick result |= b << bit;
295f6c50668Spatrick bit += 7;
296f6c50668Spatrick }
297f6c50668Spatrick } while (*p++ >= 0x80);
298f6c50668Spatrick addr = (pint_t) p;
299f6c50668Spatrick return result;
300f6c50668Spatrick }
301f6c50668Spatrick
302f6c50668Spatrick /// Read a SLEB128 into a 64-bit word.
getSLEB128(pint_t & addr,pint_t end)303f6c50668Spatrick inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
304f6c50668Spatrick const uint8_t *p = (uint8_t *)addr;
305f6c50668Spatrick const uint8_t *pend = (uint8_t *)end;
306*202cdb0eSrobert uint64_t result = 0;
307f6c50668Spatrick int bit = 0;
308f6c50668Spatrick uint8_t byte;
309f6c50668Spatrick do {
310f6c50668Spatrick if (p == pend)
311f6c50668Spatrick _LIBUNWIND_ABORT("truncated sleb128 expression");
312f6c50668Spatrick byte = *p++;
313a0747c9fSpatrick result |= (uint64_t)(byte & 0x7f) << bit;
314f6c50668Spatrick bit += 7;
315f6c50668Spatrick } while (byte & 0x80);
316f6c50668Spatrick // sign extend negative numbers
317a0747c9fSpatrick if ((byte & 0x40) != 0 && bit < 64)
318f6c50668Spatrick result |= (-1ULL) << bit;
319f6c50668Spatrick addr = (pint_t) p;
320*202cdb0eSrobert return (int64_t)result;
321f6c50668Spatrick }
322f6c50668Spatrick
323f6c50668Spatrick inline LocalAddressSpace::pint_t
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding,pint_t datarelBase)324f6c50668Spatrick LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
325f6c50668Spatrick pint_t datarelBase) {
326f6c50668Spatrick pint_t startAddr = addr;
327f6c50668Spatrick const uint8_t *p = (uint8_t *)addr;
328f6c50668Spatrick pint_t result;
329f6c50668Spatrick
330974930e3Spatrick if (encoding == DW_EH_PE_omit) {
331974930e3Spatrick return (pint_t)NULL;
332974930e3Spatrick }
333974930e3Spatrick
334f6c50668Spatrick // first get value
335f6c50668Spatrick switch (encoding & 0x0F) {
336f6c50668Spatrick case DW_EH_PE_ptr:
337f6c50668Spatrick result = getP(addr);
338f6c50668Spatrick p += sizeof(pint_t);
339f6c50668Spatrick addr = (pint_t) p;
340f6c50668Spatrick break;
341f6c50668Spatrick case DW_EH_PE_uleb128:
342f6c50668Spatrick result = (pint_t)getULEB128(addr, end);
343f6c50668Spatrick break;
344f6c50668Spatrick case DW_EH_PE_udata2:
345f6c50668Spatrick result = get16(addr);
346f6c50668Spatrick p += 2;
347f6c50668Spatrick addr = (pint_t) p;
348f6c50668Spatrick break;
349f6c50668Spatrick case DW_EH_PE_udata4:
350f6c50668Spatrick result = get32(addr);
351f6c50668Spatrick p += 4;
352f6c50668Spatrick addr = (pint_t) p;
353f6c50668Spatrick break;
354f6c50668Spatrick case DW_EH_PE_udata8:
355f6c50668Spatrick result = (pint_t)get64(addr);
356f6c50668Spatrick p += 8;
357f6c50668Spatrick addr = (pint_t) p;
358f6c50668Spatrick break;
359f6c50668Spatrick case DW_EH_PE_sleb128:
360f6c50668Spatrick result = (pint_t)getSLEB128(addr, end);
361f6c50668Spatrick break;
362f6c50668Spatrick case DW_EH_PE_sdata2:
363f6c50668Spatrick // Sign extend from signed 16-bit value.
364f6c50668Spatrick result = (pint_t)(int16_t)get16(addr);
365f6c50668Spatrick p += 2;
366f6c50668Spatrick addr = (pint_t) p;
367f6c50668Spatrick break;
368f6c50668Spatrick case DW_EH_PE_sdata4:
369f6c50668Spatrick // Sign extend from signed 32-bit value.
370f6c50668Spatrick result = (pint_t)(int32_t)get32(addr);
371f6c50668Spatrick p += 4;
372f6c50668Spatrick addr = (pint_t) p;
373f6c50668Spatrick break;
374f6c50668Spatrick case DW_EH_PE_sdata8:
375f6c50668Spatrick result = (pint_t)get64(addr);
376f6c50668Spatrick p += 8;
377f6c50668Spatrick addr = (pint_t) p;
378f6c50668Spatrick break;
379f6c50668Spatrick default:
380f6c50668Spatrick _LIBUNWIND_ABORT("unknown pointer encoding");
381f6c50668Spatrick }
382f6c50668Spatrick
383f6c50668Spatrick // then add relative offset
384f6c50668Spatrick switch (encoding & 0x70) {
385f6c50668Spatrick case DW_EH_PE_absptr:
386f6c50668Spatrick // do nothing
387f6c50668Spatrick break;
388f6c50668Spatrick case DW_EH_PE_pcrel:
389f6c50668Spatrick result += startAddr;
390f6c50668Spatrick break;
391f6c50668Spatrick case DW_EH_PE_textrel:
392f6c50668Spatrick _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
393f6c50668Spatrick break;
394f6c50668Spatrick case DW_EH_PE_datarel:
395f6c50668Spatrick // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
396f6c50668Spatrick // default value of 0, and we abort in the event that someone calls this
397f6c50668Spatrick // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
398f6c50668Spatrick if (datarelBase == 0)
399f6c50668Spatrick _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
400f6c50668Spatrick result += datarelBase;
401f6c50668Spatrick break;
402f6c50668Spatrick case DW_EH_PE_funcrel:
403f6c50668Spatrick _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
404f6c50668Spatrick break;
405f6c50668Spatrick case DW_EH_PE_aligned:
406f6c50668Spatrick _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
407f6c50668Spatrick break;
408f6c50668Spatrick default:
409f6c50668Spatrick _LIBUNWIND_ABORT("unknown pointer encoding");
410f6c50668Spatrick break;
411f6c50668Spatrick }
412f6c50668Spatrick
413f6c50668Spatrick if (encoding & DW_EH_PE_indirect)
414f6c50668Spatrick result = getP(result);
415f6c50668Spatrick
416f6c50668Spatrick return result;
417f6c50668Spatrick }
418f6c50668Spatrick
419a0747c9fSpatrick #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
420f6c50668Spatrick
421a0747c9fSpatrick // The ElfW() macro for pointer-size independent ELF header traversal is not
422a0747c9fSpatrick // provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
423a0747c9fSpatrick // data structures are just called Elf_XXX. Define ElfW() locally.
424a0747c9fSpatrick #if !defined(ElfW)
425a0747c9fSpatrick #define ElfW(type) Elf_##type
426a0747c9fSpatrick #endif
427f6c50668Spatrick #if !defined(Elf_Half)
428f6c50668Spatrick typedef ElfW(Half) Elf_Half;
429f6c50668Spatrick #endif
430f6c50668Spatrick #if !defined(Elf_Phdr)
431f6c50668Spatrick typedef ElfW(Phdr) Elf_Phdr;
432f6c50668Spatrick #endif
433f6c50668Spatrick #if !defined(Elf_Addr)
434f6c50668Spatrick typedef ElfW(Addr) Elf_Addr;
435f6c50668Spatrick #endif
436f6c50668Spatrick
437f6c50668Spatrick struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
438f6c50668Spatrick LocalAddressSpace *addressSpace;
439f6c50668Spatrick UnwindInfoSections *sects;
440f6c50668Spatrick uintptr_t targetAddr;
441f6c50668Spatrick };
442f6c50668Spatrick
443f6c50668Spatrick #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
444f6c50668Spatrick #include "FrameHeaderCache.hpp"
445f6c50668Spatrick
446a0747c9fSpatrick // Typically there is one cache per process, but when libunwind is built as a
447a0747c9fSpatrick // hermetic static library, then each shared object may have its own cache.
448a0747c9fSpatrick static FrameHeaderCache TheFrameHeaderCache;
449f6c50668Spatrick #endif
450f6c50668Spatrick
checkAddrInSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)451f6c50668Spatrick static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
452f6c50668Spatrick dl_iterate_cb_data *cbdata) {
453f6c50668Spatrick if (phdr->p_type == PT_LOAD) {
454f6c50668Spatrick uintptr_t begin = image_base + phdr->p_vaddr;
455f6c50668Spatrick uintptr_t end = begin + phdr->p_memsz;
456f6c50668Spatrick if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
457f6c50668Spatrick cbdata->sects->dso_base = begin;
458a0747c9fSpatrick cbdata->sects->text_segment_length = phdr->p_memsz;
459f6c50668Spatrick return true;
460f6c50668Spatrick }
461f6c50668Spatrick }
462f6c50668Spatrick return false;
463f6c50668Spatrick }
464f6c50668Spatrick
checkForUnwindInfoSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)465a0747c9fSpatrick static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
466a0747c9fSpatrick dl_iterate_cb_data *cbdata) {
467a0747c9fSpatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
468a0747c9fSpatrick if (phdr->p_type == PT_GNU_EH_FRAME) {
469a0747c9fSpatrick EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
470a0747c9fSpatrick uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
471a0747c9fSpatrick cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
472a0747c9fSpatrick cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
473a0747c9fSpatrick if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
474a0747c9fSpatrick *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
475a0747c9fSpatrick hdrInfo)) {
476a0747c9fSpatrick // .eh_frame_hdr records the start of .eh_frame, but not its size.
477a0747c9fSpatrick // Rely on a zero terminator to find the end of the section.
478a0747c9fSpatrick cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
479*202cdb0eSrobert cbdata->sects->dwarf_section_length = SIZE_MAX;
480a0747c9fSpatrick return true;
481a0747c9fSpatrick }
482a0747c9fSpatrick }
483a0747c9fSpatrick return false;
484a0747c9fSpatrick #elif defined(_LIBUNWIND_ARM_EHABI)
485a0747c9fSpatrick if (phdr->p_type == PT_ARM_EXIDX) {
486a0747c9fSpatrick uintptr_t exidx_start = image_base + phdr->p_vaddr;
487a0747c9fSpatrick cbdata->sects->arm_section = exidx_start;
488a0747c9fSpatrick cbdata->sects->arm_section_length = phdr->p_memsz;
489a0747c9fSpatrick return true;
490a0747c9fSpatrick }
491a0747c9fSpatrick return false;
492a0747c9fSpatrick #else
493a0747c9fSpatrick #error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
494a0747c9fSpatrick #endif
495a0747c9fSpatrick }
496a0747c9fSpatrick
findUnwindSectionsByPhdr(struct dl_phdr_info * pinfo,size_t pinfo_size,void * data)497f6c50668Spatrick static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
498f6c50668Spatrick size_t pinfo_size, void *data) {
499f6c50668Spatrick auto cbdata = static_cast<dl_iterate_cb_data *>(data);
500f6c50668Spatrick if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
501f6c50668Spatrick return 0;
502f6c50668Spatrick #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
503a0747c9fSpatrick if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
504f6c50668Spatrick return 1;
505a0747c9fSpatrick #else
506a0747c9fSpatrick // Avoid warning about unused variable.
507a0747c9fSpatrick (void)pinfo_size;
508f6c50668Spatrick #endif
509f6c50668Spatrick
510*202cdb0eSrobert Elf_Addr image_base = pinfo->dlpi_addr;
511f6c50668Spatrick
512a0747c9fSpatrick // Most shared objects seen in this callback function likely don't contain the
513a0747c9fSpatrick // target address, so optimize for that. Scan for a matching PT_LOAD segment
514a0747c9fSpatrick // first and bail when it isn't found.
515a0747c9fSpatrick bool found_text = false;
516a0747c9fSpatrick for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
517a0747c9fSpatrick if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
518a0747c9fSpatrick found_text = true;
519a0747c9fSpatrick break;
520a0747c9fSpatrick }
521a0747c9fSpatrick }
522a0747c9fSpatrick if (!found_text)
523a0747c9fSpatrick return 0;
524f6c50668Spatrick
525a0747c9fSpatrick // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
526a0747c9fSpatrick // backward.
527a0747c9fSpatrick bool found_unwind = false;
528f6c50668Spatrick for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
529f6c50668Spatrick const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
530a0747c9fSpatrick if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
531a0747c9fSpatrick found_unwind = true;
532a0747c9fSpatrick break;
533f6c50668Spatrick }
534a0747c9fSpatrick }
535a0747c9fSpatrick if (!found_unwind)
536a0747c9fSpatrick return 0;
537a0747c9fSpatrick
538f6c50668Spatrick #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
539a0747c9fSpatrick TheFrameHeaderCache.add(cbdata->sects);
540f6c50668Spatrick #endif
541f6c50668Spatrick return 1;
542f6c50668Spatrick }
543f6c50668Spatrick
544a0747c9fSpatrick #endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
545f6c50668Spatrick
546f6c50668Spatrick
findUnwindSections(pint_t targetAddr,UnwindInfoSections & info)547f6c50668Spatrick inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
548f6c50668Spatrick UnwindInfoSections &info) {
549f6c50668Spatrick #ifdef __APPLE__
550f6c50668Spatrick dyld_unwind_sections dyldInfo;
551f6c50668Spatrick if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
552f6c50668Spatrick info.dso_base = (uintptr_t)dyldInfo.mh;
553f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
554f6c50668Spatrick info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
555*202cdb0eSrobert info.dwarf_section_length = (size_t)dyldInfo.dwarf_section_length;
556f6c50668Spatrick #endif
557f6c50668Spatrick info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
558*202cdb0eSrobert info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
559f6c50668Spatrick return true;
560f6c50668Spatrick }
561f6c50668Spatrick #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
562a0747c9fSpatrick info.dso_base = 0;
563f6c50668Spatrick // Bare metal is statically linked, so no need to ask the dynamic loader
564*202cdb0eSrobert info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
565f6c50668Spatrick info.dwarf_section = (uintptr_t)(&__eh_frame_start);
566f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
567f6c50668Spatrick (void *)info.dwarf_section, (void *)info.dwarf_section_length);
568f6c50668Spatrick #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
569f6c50668Spatrick info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
570*202cdb0eSrobert info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
571f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
572f6c50668Spatrick (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
573f6c50668Spatrick #endif
574f6c50668Spatrick if (info.dwarf_section_length)
575f6c50668Spatrick return true;
576f6c50668Spatrick #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
577f6c50668Spatrick // Bare metal is statically linked, so no need to ask the dynamic loader
578f6c50668Spatrick info.arm_section = (uintptr_t)(&__exidx_start);
579*202cdb0eSrobert info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
580f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
581f6c50668Spatrick (void *)info.arm_section, (void *)info.arm_section_length);
582f6c50668Spatrick if (info.arm_section && info.arm_section_length)
583f6c50668Spatrick return true;
584f6c50668Spatrick #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
585f6c50668Spatrick HMODULE mods[1024];
586f6c50668Spatrick HANDLE process = GetCurrentProcess();
587f6c50668Spatrick DWORD needed;
588f6c50668Spatrick
589f6c50668Spatrick if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
590f6c50668Spatrick DWORD err = GetLastError();
591f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
592f6c50668Spatrick "returned error %d", (int)err);
593*202cdb0eSrobert (void)err;
594f6c50668Spatrick return false;
595f6c50668Spatrick }
596f6c50668Spatrick
597f6c50668Spatrick for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
598f6c50668Spatrick PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
599f6c50668Spatrick PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
600f6c50668Spatrick PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
601f6c50668Spatrick PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
602f6c50668Spatrick bool found_obj = false;
603f6c50668Spatrick bool found_hdr = false;
604f6c50668Spatrick
605f6c50668Spatrick info.dso_base = (uintptr_t)mods[i];
606f6c50668Spatrick for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
607f6c50668Spatrick uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
608f6c50668Spatrick uintptr_t end = begin + pish->Misc.VirtualSize;
609f6c50668Spatrick if (!strncmp((const char *)pish->Name, ".text",
610f6c50668Spatrick IMAGE_SIZEOF_SHORT_NAME)) {
611f6c50668Spatrick if (targetAddr >= begin && targetAddr < end)
612f6c50668Spatrick found_obj = true;
613f6c50668Spatrick } else if (!strncmp((const char *)pish->Name, ".eh_frame",
614f6c50668Spatrick IMAGE_SIZEOF_SHORT_NAME)) {
615f6c50668Spatrick info.dwarf_section = begin;
616f6c50668Spatrick info.dwarf_section_length = pish->Misc.VirtualSize;
617f6c50668Spatrick found_hdr = true;
618f6c50668Spatrick }
619f6c50668Spatrick if (found_obj && found_hdr)
620f6c50668Spatrick return true;
621f6c50668Spatrick }
622f6c50668Spatrick }
623f6c50668Spatrick return false;
624f6c50668Spatrick #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
625f6c50668Spatrick // Don't even bother, since Windows has functions that do all this stuff
626f6c50668Spatrick // for us.
627f6c50668Spatrick (void)targetAddr;
628f6c50668Spatrick (void)info;
629f6c50668Spatrick return true;
630*202cdb0eSrobert #elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
631*202cdb0eSrobert // The traceback table is used for unwinding.
632*202cdb0eSrobert (void)targetAddr;
633*202cdb0eSrobert (void)info;
634*202cdb0eSrobert return true;
635a0747c9fSpatrick #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
636f6c50668Spatrick int length = 0;
637f6c50668Spatrick info.arm_section =
638f6c50668Spatrick (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
639*202cdb0eSrobert info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
640f6c50668Spatrick if (info.arm_section && info.arm_section_length)
641f6c50668Spatrick return true;
642a0747c9fSpatrick #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
643*202cdb0eSrobert // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
644*202cdb0eSrobert // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
645*202cdb0eSrobert // support for _dl_find_object on other unwind formats is not implemented,
646*202cdb0eSrobert // yet.
647*202cdb0eSrobert #if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
648*202cdb0eSrobert // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
649*202cdb0eSrobert #if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
650*202cdb0eSrobert #error _dl_find_object retrieves an unexpected section type
651*202cdb0eSrobert #endif
652*202cdb0eSrobert // We look-up `dl_find_object` dynamically at runtime to ensure backwards
653*202cdb0eSrobert // compatibility with earlier version of glibc not yet providing it. On older
654*202cdb0eSrobert // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
655*202cdb0eSrobert // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
656*202cdb0eSrobert static decltype(_dl_find_object) *dlFindObject;
657*202cdb0eSrobert static bool dlFindObjectChecked = false;
658*202cdb0eSrobert if (!dlFindObjectChecked) {
659*202cdb0eSrobert dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
660*202cdb0eSrobert dlsym(RTLD_DEFAULT, "_dl_find_object"));
661*202cdb0eSrobert dlFindObjectChecked = true;
662*202cdb0eSrobert }
663*202cdb0eSrobert // Try to find the unwind info using `dl_find_object`
664*202cdb0eSrobert dl_find_object findResult;
665*202cdb0eSrobert if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
666*202cdb0eSrobert if (findResult.dlfo_eh_frame == nullptr) {
667*202cdb0eSrobert // Found an entry for `targetAddr`, but there is no unwind info.
668*202cdb0eSrobert return false;
669*202cdb0eSrobert }
670*202cdb0eSrobert info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
671*202cdb0eSrobert info.text_segment_length = static_cast<size_t>(
672*202cdb0eSrobert (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
673*202cdb0eSrobert
674*202cdb0eSrobert // Record the start of PT_GNU_EH_FRAME.
675*202cdb0eSrobert info.dwarf_index_section =
676*202cdb0eSrobert reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
677*202cdb0eSrobert // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
678*202cdb0eSrobert // Setting length to `SIZE_MAX` effectively disables all range checks.
679*202cdb0eSrobert info.dwarf_index_section_length = SIZE_MAX;
680*202cdb0eSrobert EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
681*202cdb0eSrobert if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
682*202cdb0eSrobert *this, info.dwarf_index_section, info.dwarf_index_section_length,
683*202cdb0eSrobert hdrInfo)) {
684*202cdb0eSrobert return false;
685*202cdb0eSrobert }
686*202cdb0eSrobert // Record the start of the FDE and use SIZE_MAX to indicate that we do
687*202cdb0eSrobert // not know the end address.
688*202cdb0eSrobert info.dwarf_section = hdrInfo.eh_frame_ptr;
689*202cdb0eSrobert info.dwarf_section_length = SIZE_MAX;
690*202cdb0eSrobert return true;
691*202cdb0eSrobert }
692*202cdb0eSrobert #endif
693f6c50668Spatrick dl_iterate_cb_data cb_data = {this, &info, targetAddr};
694f6c50668Spatrick int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
695f6c50668Spatrick return static_cast<bool>(found);
696f6c50668Spatrick #endif
697f6c50668Spatrick
698f6c50668Spatrick return false;
699f6c50668Spatrick }
700f6c50668Spatrick
findOtherFDE(pint_t targetAddr,pint_t & fde)701f6c50668Spatrick inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
702f6c50668Spatrick // TO DO: if OS has way to dynamically register FDEs, check that.
703f6c50668Spatrick (void)targetAddr;
704f6c50668Spatrick (void)fde;
705f6c50668Spatrick return false;
706f6c50668Spatrick }
707f6c50668Spatrick
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)708f6c50668Spatrick inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
709f6c50668Spatrick size_t bufLen,
710f6c50668Spatrick unw_word_t *offset) {
711f6c50668Spatrick #if _LIBUNWIND_USE_DLADDR
712f6c50668Spatrick Dl_info dyldInfo;
713f6c50668Spatrick if (dladdr((void *)addr, &dyldInfo)) {
714f6c50668Spatrick if (dyldInfo.dli_sname != NULL) {
715f6c50668Spatrick snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
716f6c50668Spatrick *offset = (addr - (pint_t) dyldInfo.dli_saddr);
717f6c50668Spatrick return true;
718f6c50668Spatrick }
719f6c50668Spatrick }
720*202cdb0eSrobert #elif defined(_AIX)
721*202cdb0eSrobert uint16_t nameLen;
722*202cdb0eSrobert char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
723*202cdb0eSrobert if (funcName != NULL) {
724*202cdb0eSrobert snprintf(buf, bufLen, "%.*s", nameLen, funcName);
725*202cdb0eSrobert return true;
726*202cdb0eSrobert }
727f6c50668Spatrick #else
728f6c50668Spatrick (void)addr;
729f6c50668Spatrick (void)buf;
730f6c50668Spatrick (void)bufLen;
731f6c50668Spatrick (void)offset;
732f6c50668Spatrick #endif
733f6c50668Spatrick return false;
734f6c50668Spatrick }
735f6c50668Spatrick
736f6c50668Spatrick } // namespace libunwind
737f6c50668Spatrick
738f6c50668Spatrick #endif // __ADDRESSSPACE_HPP__
739