1472758f3SLionel Sambuc //===------------------------- AddressSpace.hpp ---------------------------===//
2472758f3SLionel Sambuc //
3472758f3SLionel Sambuc // The LLVM Compiler Infrastructure
4472758f3SLionel Sambuc //
5472758f3SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
6472758f3SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
7472758f3SLionel Sambuc //
8472758f3SLionel Sambuc //
9472758f3SLionel Sambuc // Abstracts accessing local vs remote address spaces.
10472758f3SLionel Sambuc //
11472758f3SLionel Sambuc //===----------------------------------------------------------------------===//
12472758f3SLionel Sambuc
13472758f3SLionel Sambuc #ifndef __ADDRESSSPACE_HPP__
14472758f3SLionel Sambuc #define __ADDRESSSPACE_HPP__
15472758f3SLionel Sambuc
16472758f3SLionel Sambuc #include <sys/rbtree.h>
17472758f3SLionel Sambuc #include <cassert>
18472758f3SLionel Sambuc #include <cstddef>
19472758f3SLionel Sambuc #include <cstdint>
20472758f3SLionel Sambuc #include <cstdlib>
21472758f3SLionel Sambuc #include <cstring>
22472758f3SLionel Sambuc #include <dlfcn.h>
23472758f3SLionel Sambuc #include <elf.h>
24472758f3SLionel Sambuc #include <link.h>
25472758f3SLionel Sambuc #if !defined(__minix)
26472758f3SLionel Sambuc #include <pthread.h>
27472758f3SLionel Sambuc #else
28472758f3SLionel Sambuc #define pthread_rwlock_init(l, d) /* nothing */
29472758f3SLionel Sambuc #define pthread_rwlock_rdlock(l) /* nothing */
30472758f3SLionel Sambuc #define pthread_rwlock_wrlock(l) /* nothing */
31472758f3SLionel Sambuc #define pthread_rwlock_unlock(l) /* nothing */
32472758f3SLionel Sambuc #endif /* !defined(__minix) */
33472758f3SLionel Sambuc
34472758f3SLionel Sambuc #include "dwarf2.h"
35472758f3SLionel Sambuc
36472758f3SLionel Sambuc namespace _Unwind {
37472758f3SLionel Sambuc
38472758f3SLionel Sambuc static int rangeCmp(void *, const void *, const void *);
39472758f3SLionel Sambuc static int rangeCmpKey(void *, const void *, const void *);
40472758f3SLionel Sambuc static int dsoTableCmp(void *, const void *, const void *);
41472758f3SLionel Sambuc static int dsoTableCmpKey(void *, const void *, const void *);
42472758f3SLionel Sambuc static int phdr_callback(struct dl_phdr_info *, size_t, void *);
43472758f3SLionel Sambuc
44472758f3SLionel Sambuc struct unw_proc_info_t {
45472758f3SLionel Sambuc uintptr_t data_base; // Base address for data-relative relocations
46472758f3SLionel Sambuc uintptr_t start_ip; // Start address of function
47472758f3SLionel Sambuc uintptr_t end_ip; // First address after end of function
48472758f3SLionel Sambuc uintptr_t lsda; // Address of Language Specific Data Area
49472758f3SLionel Sambuc uintptr_t handler; // Personality routine
50472758f3SLionel Sambuc uintptr_t extra_args; // Extra stack space for frameless routines
51472758f3SLionel Sambuc uintptr_t unwind_info; // Address of DWARF unwind info
52472758f3SLionel Sambuc };
53472758f3SLionel Sambuc
54472758f3SLionel Sambuc /// LocalAddressSpace is used as a template parameter to UnwindCursor when
55472758f3SLionel Sambuc /// unwinding a thread in the same process. The wrappers compile away,
56472758f3SLionel Sambuc /// making local unwinds fast.
57472758f3SLionel Sambuc class LocalAddressSpace {
58472758f3SLionel Sambuc public:
59472758f3SLionel Sambuc typedef uintptr_t pint_t;
60472758f3SLionel Sambuc typedef intptr_t sint_t;
61472758f3SLionel Sambuc
62472758f3SLionel Sambuc typedef void (*findPCRange_t)(LocalAddressSpace &, pint_t, pint_t &pcStart,
63472758f3SLionel Sambuc pint_t &pcEnd);
64472758f3SLionel Sambuc
LocalAddressSpace(findPCRange_t findPCRange_)65472758f3SLionel Sambuc LocalAddressSpace(findPCRange_t findPCRange_)
66472758f3SLionel Sambuc : findPCRange(findPCRange_), needsReload(true) {
67472758f3SLionel Sambuc static const rb_tree_ops_t segmentTreeOps = {
68472758f3SLionel Sambuc rangeCmp, rangeCmpKey, offsetof(Range, range_link), NULL
69472758f3SLionel Sambuc };
70472758f3SLionel Sambuc static const rb_tree_ops_t dsoTreeOps = {
71472758f3SLionel Sambuc dsoTableCmp, dsoTableCmpKey, offsetof(Range, dso_link), NULL
72472758f3SLionel Sambuc };
73472758f3SLionel Sambuc rb_tree_init(&segmentTree, &segmentTreeOps);
74472758f3SLionel Sambuc rb_tree_init(&dsoTree, &dsoTreeOps);
75472758f3SLionel Sambuc pthread_rwlock_init(&fdeTreeLock, NULL);
76472758f3SLionel Sambuc }
77472758f3SLionel Sambuc
get8(pint_t addr)78b029fb59SBen Gras uint8_t get8(pint_t addr) {
79b029fb59SBen Gras uint8_t val;
80b029fb59SBen Gras memcpy(&val, (void *)addr, sizeof(val));
81b029fb59SBen Gras return val;
82b029fb59SBen Gras }
83472758f3SLionel Sambuc
get16(pint_t addr)84b029fb59SBen Gras uint16_t get16(pint_t addr) {
85b029fb59SBen Gras uint16_t val;
86b029fb59SBen Gras memcpy(&val, (void *)addr, sizeof(val));
87b029fb59SBen Gras return val;
88b029fb59SBen Gras }
89472758f3SLionel Sambuc
get32(pint_t addr)90b029fb59SBen Gras uint32_t get32(pint_t addr) {
91b029fb59SBen Gras uint32_t val;
92b029fb59SBen Gras memcpy(&val, (void *)addr, sizeof(val));
93b029fb59SBen Gras return val;
94b029fb59SBen Gras }
95472758f3SLionel Sambuc
get64(pint_t addr)96b029fb59SBen Gras uint64_t get64(pint_t addr) {
97b029fb59SBen Gras uint64_t val;
98b029fb59SBen Gras memcpy(&val, (void *)addr, sizeof(val));
99b029fb59SBen Gras return val;
100b029fb59SBen Gras }
101472758f3SLionel Sambuc
getP(pint_t addr)102472758f3SLionel Sambuc uintptr_t getP(pint_t addr) {
103472758f3SLionel Sambuc if (sizeof(uintptr_t) == sizeof(uint32_t))
104472758f3SLionel Sambuc return get32(addr);
105472758f3SLionel Sambuc else
106472758f3SLionel Sambuc return get64(addr);
107472758f3SLionel Sambuc }
108472758f3SLionel Sambuc
getULEB128(pint_t & addr,pint_t end)109472758f3SLionel Sambuc uint64_t getULEB128(pint_t &addr, pint_t end) {
110472758f3SLionel Sambuc uint64_t result = 0;
111472758f3SLionel Sambuc uint8_t byte;
112472758f3SLionel Sambuc int bit = 0;
113472758f3SLionel Sambuc do {
114472758f3SLionel Sambuc uint64_t b;
115472758f3SLionel Sambuc
116472758f3SLionel Sambuc assert(addr != end);
117472758f3SLionel Sambuc
118472758f3SLionel Sambuc byte = get8(addr++);
119472758f3SLionel Sambuc b = byte & 0x7f;
120472758f3SLionel Sambuc
121472758f3SLionel Sambuc assert(bit < 64);
122472758f3SLionel Sambuc assert(b << bit >> bit == b);
123472758f3SLionel Sambuc
124472758f3SLionel Sambuc result |= b << bit;
125472758f3SLionel Sambuc bit += 7;
126472758f3SLionel Sambuc } while (byte >= 0x80);
127472758f3SLionel Sambuc return result;
128472758f3SLionel Sambuc }
129472758f3SLionel Sambuc
getSLEB128(pint_t & addr,pint_t end)130472758f3SLionel Sambuc int64_t getSLEB128(pint_t &addr, pint_t end) {
131472758f3SLionel Sambuc uint64_t result = 0;
132472758f3SLionel Sambuc uint8_t byte;
133472758f3SLionel Sambuc int bit = 0;
134472758f3SLionel Sambuc do {
135472758f3SLionel Sambuc uint64_t b;
136472758f3SLionel Sambuc
137472758f3SLionel Sambuc assert(addr != end);
138472758f3SLionel Sambuc
139472758f3SLionel Sambuc byte = get8(addr++);
140472758f3SLionel Sambuc b = byte & 0x7f;
141472758f3SLionel Sambuc
142472758f3SLionel Sambuc assert(bit < 64);
143472758f3SLionel Sambuc assert(b << bit >> bit == b);
144472758f3SLionel Sambuc
145472758f3SLionel Sambuc result |= b << bit;
146472758f3SLionel Sambuc bit += 7;
147472758f3SLionel Sambuc } while (byte >= 0x80);
148472758f3SLionel Sambuc // sign extend negative numbers
149472758f3SLionel Sambuc if ((byte & 0x40) != 0)
150472758f3SLionel Sambuc result |= (-1LL) << bit;
151472758f3SLionel Sambuc return result;
152472758f3SLionel Sambuc }
153472758f3SLionel Sambuc
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding,const unw_proc_info_t * ctx)154472758f3SLionel Sambuc pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
155472758f3SLionel Sambuc const unw_proc_info_t *ctx) {
156472758f3SLionel Sambuc pint_t startAddr = addr;
157472758f3SLionel Sambuc const uint8_t *p = (uint8_t *)addr;
158472758f3SLionel Sambuc pint_t result;
159472758f3SLionel Sambuc
160472758f3SLionel Sambuc if (encoding == DW_EH_PE_omit)
161472758f3SLionel Sambuc return 0;
162472758f3SLionel Sambuc if (encoding == DW_EH_PE_aligned) {
163472758f3SLionel Sambuc addr = (addr + sizeof(pint_t) - 1) & sizeof(pint_t);
164472758f3SLionel Sambuc return getP(addr);
165472758f3SLionel Sambuc }
166472758f3SLionel Sambuc
167472758f3SLionel Sambuc // first get value
168472758f3SLionel Sambuc switch (encoding & 0x0F) {
169472758f3SLionel Sambuc case DW_EH_PE_ptr:
170472758f3SLionel Sambuc result = getP(addr);
171472758f3SLionel Sambuc p += sizeof(pint_t);
172472758f3SLionel Sambuc addr = (pint_t)p;
173472758f3SLionel Sambuc break;
174472758f3SLionel Sambuc case DW_EH_PE_uleb128:
175472758f3SLionel Sambuc result = getULEB128(addr, end);
176472758f3SLionel Sambuc break;
177472758f3SLionel Sambuc case DW_EH_PE_udata2:
178472758f3SLionel Sambuc result = get16(addr);
179472758f3SLionel Sambuc p += 2;
180472758f3SLionel Sambuc addr = (pint_t)p;
181472758f3SLionel Sambuc break;
182472758f3SLionel Sambuc case DW_EH_PE_udata4:
183472758f3SLionel Sambuc result = get32(addr);
184472758f3SLionel Sambuc p += 4;
185472758f3SLionel Sambuc addr = (pint_t)p;
186472758f3SLionel Sambuc break;
187472758f3SLionel Sambuc case DW_EH_PE_udata8:
188472758f3SLionel Sambuc result = get64(addr);
189472758f3SLionel Sambuc p += 8;
190472758f3SLionel Sambuc addr = (pint_t)p;
191472758f3SLionel Sambuc break;
192472758f3SLionel Sambuc case DW_EH_PE_sleb128:
193472758f3SLionel Sambuc result = getSLEB128(addr, end);
194472758f3SLionel Sambuc break;
195472758f3SLionel Sambuc case DW_EH_PE_sdata2:
196472758f3SLionel Sambuc result = (int16_t)get16(addr);
197472758f3SLionel Sambuc p += 2;
198472758f3SLionel Sambuc addr = (pint_t)p;
199472758f3SLionel Sambuc break;
200472758f3SLionel Sambuc case DW_EH_PE_sdata4:
201472758f3SLionel Sambuc result = (int32_t)get32(addr);
202472758f3SLionel Sambuc p += 4;
203472758f3SLionel Sambuc addr = (pint_t)p;
204472758f3SLionel Sambuc break;
205472758f3SLionel Sambuc case DW_EH_PE_sdata8:
206472758f3SLionel Sambuc result = get64(addr);
207472758f3SLionel Sambuc p += 8;
208472758f3SLionel Sambuc addr = (pint_t)p;
209472758f3SLionel Sambuc break;
210472758f3SLionel Sambuc case DW_EH_PE_omit:
211472758f3SLionel Sambuc result = 0;
212472758f3SLionel Sambuc break;
213472758f3SLionel Sambuc default:
214472758f3SLionel Sambuc assert(0 && "unknown pointer encoding");
215472758f3SLionel Sambuc }
216472758f3SLionel Sambuc
217472758f3SLionel Sambuc // then add relative offset
218472758f3SLionel Sambuc switch (encoding & 0x70) {
219472758f3SLionel Sambuc case DW_EH_PE_absptr:
220472758f3SLionel Sambuc // do nothing
221472758f3SLionel Sambuc break;
222472758f3SLionel Sambuc case DW_EH_PE_pcrel:
223472758f3SLionel Sambuc result += startAddr;
224472758f3SLionel Sambuc break;
225472758f3SLionel Sambuc case DW_EH_PE_textrel:
226472758f3SLionel Sambuc assert(0 && "DW_EH_PE_textrel pointer encoding not supported");
227472758f3SLionel Sambuc break;
228472758f3SLionel Sambuc case DW_EH_PE_datarel:
229472758f3SLionel Sambuc assert(ctx != NULL && "DW_EH_PE_datarel without context");
230472758f3SLionel Sambuc if (ctx)
231472758f3SLionel Sambuc result += ctx->data_base;
232472758f3SLionel Sambuc break;
233472758f3SLionel Sambuc case DW_EH_PE_funcrel:
234472758f3SLionel Sambuc assert(ctx != NULL && "DW_EH_PE_funcrel without context");
235472758f3SLionel Sambuc if (ctx)
236472758f3SLionel Sambuc result += ctx->start_ip;
237472758f3SLionel Sambuc break;
238472758f3SLionel Sambuc case DW_EH_PE_aligned:
239472758f3SLionel Sambuc __builtin_unreachable();
240472758f3SLionel Sambuc default:
241472758f3SLionel Sambuc assert(0 && "unknown pointer encoding");
242472758f3SLionel Sambuc break;
243472758f3SLionel Sambuc }
244472758f3SLionel Sambuc
245472758f3SLionel Sambuc if (encoding & DW_EH_PE_indirect)
246472758f3SLionel Sambuc result = getP(result);
247472758f3SLionel Sambuc
248472758f3SLionel Sambuc return result;
249472758f3SLionel Sambuc }
250472758f3SLionel Sambuc
findFDE(pint_t pc,pint_t & fdeStart,pint_t & data_base)251472758f3SLionel Sambuc bool findFDE(pint_t pc, pint_t &fdeStart, pint_t &data_base) {
252472758f3SLionel Sambuc Range *n;
253472758f3SLionel Sambuc for (;;) {
254472758f3SLionel Sambuc pthread_rwlock_rdlock(&fdeTreeLock);
255472758f3SLionel Sambuc n = (Range *)rb_tree_find_node(&segmentTree, &pc);
256472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
257472758f3SLionel Sambuc if (n != NULL)
258472758f3SLionel Sambuc break;
259472758f3SLionel Sambuc if (!needsReload)
260472758f3SLionel Sambuc break;
261472758f3SLionel Sambuc lazyReload();
262472758f3SLionel Sambuc }
263472758f3SLionel Sambuc if (n == NULL)
264472758f3SLionel Sambuc return false;
265472758f3SLionel Sambuc if (n->hdr_start == 0) {
266472758f3SLionel Sambuc fdeStart = n->hdr_base;
267b029fb59SBen Gras data_base = n->data_base;
268472758f3SLionel Sambuc return true;
269472758f3SLionel Sambuc }
270472758f3SLionel Sambuc
271472758f3SLionel Sambuc pint_t base = n->hdr_base;
272472758f3SLionel Sambuc pint_t first = n->hdr_start;
273*0a6a1f1dSLionel Sambuc for (pint_t len = n->hdr_entries; len > 1; ) {
274*0a6a1f1dSLionel Sambuc pint_t next = first + (len / 2) * 8;
275472758f3SLionel Sambuc pint_t nextPC = base + (int32_t)get32(next);
276472758f3SLionel Sambuc if (nextPC == pc) {
277472758f3SLionel Sambuc first = next;
278472758f3SLionel Sambuc break;
279472758f3SLionel Sambuc }
280472758f3SLionel Sambuc if (nextPC < pc) {
281472758f3SLionel Sambuc first = next;
282*0a6a1f1dSLionel Sambuc len -= (len / 2);
283*0a6a1f1dSLionel Sambuc } else {
284*0a6a1f1dSLionel Sambuc len /= 2;
285*0a6a1f1dSLionel Sambuc }
286472758f3SLionel Sambuc }
287472758f3SLionel Sambuc fdeStart = base + (int32_t)get32(first + 4);
288b029fb59SBen Gras data_base = n->data_base;
289472758f3SLionel Sambuc return true;
290472758f3SLionel Sambuc }
291472758f3SLionel Sambuc
addFDE(pint_t pcStart,pint_t pcEnd,pint_t fde)292472758f3SLionel Sambuc bool addFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
293472758f3SLionel Sambuc pthread_rwlock_wrlock(&fdeTreeLock);
294472758f3SLionel Sambuc Range *n = (Range *)malloc(sizeof(*n));
295472758f3SLionel Sambuc n->hdr_base = fde;
296472758f3SLionel Sambuc n->hdr_start = 0;
297472758f3SLionel Sambuc n->hdr_entries = 0;
298472758f3SLionel Sambuc n->first_pc = pcStart;
299472758f3SLionel Sambuc n->last_pc = pcEnd;
300472758f3SLionel Sambuc n->data_base = 0;
301472758f3SLionel Sambuc n->ehframe_base = 0;
302*0a6a1f1dSLionel Sambuc if (static_cast<Range *>(rb_tree_insert_node(&segmentTree, n)) == n) {
303472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
304472758f3SLionel Sambuc return true;
305472758f3SLionel Sambuc }
306472758f3SLionel Sambuc free(n);
307472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
308472758f3SLionel Sambuc return false;
309472758f3SLionel Sambuc }
310472758f3SLionel Sambuc
removeFDE(pint_t pcStart,pint_t pcEnd,pint_t fde)311472758f3SLionel Sambuc bool removeFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
312472758f3SLionel Sambuc pthread_rwlock_wrlock(&fdeTreeLock);
313*0a6a1f1dSLionel Sambuc Range *n = static_cast<Range *>(rb_tree_find_node(&segmentTree, &pcStart));
314472758f3SLionel Sambuc if (n == NULL) {
315472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
316472758f3SLionel Sambuc return false;
317472758f3SLionel Sambuc }
318472758f3SLionel Sambuc assert(n->first_pc == pcStart);
319472758f3SLionel Sambuc assert(n->last_pc == pcEnd);
320472758f3SLionel Sambuc assert(n->hdr_base == fde);
321472758f3SLionel Sambuc assert(n->hdr_start == 0);
322472758f3SLionel Sambuc assert(n->hdr_entries == 0);
323472758f3SLionel Sambuc assert(n->data_base == 0);
324472758f3SLionel Sambuc assert(n->ehframe_base == 0);
325472758f3SLionel Sambuc rb_tree_remove_node(&segmentTree, n);
326472758f3SLionel Sambuc free(n);
327472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
328472758f3SLionel Sambuc return true;
329472758f3SLionel Sambuc }
330472758f3SLionel Sambuc
removeDSO(pint_t ehFrameBase)331472758f3SLionel Sambuc void removeDSO(pint_t ehFrameBase) {
332472758f3SLionel Sambuc pthread_rwlock_wrlock(&fdeTreeLock);
333472758f3SLionel Sambuc Range *n;
334472758f3SLionel Sambuc n = (Range *)rb_tree_find_node(&dsoTree, &ehFrameBase);
335472758f3SLionel Sambuc if (n == NULL) {
336472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
337472758f3SLionel Sambuc return;
338472758f3SLionel Sambuc }
339472758f3SLionel Sambuc rb_tree_remove_node(&dsoTree, n);
340472758f3SLionel Sambuc rb_tree_remove_node(&segmentTree, n);
341472758f3SLionel Sambuc free(n);
342472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
343472758f3SLionel Sambuc }
344472758f3SLionel Sambuc
setLazyReload()345472758f3SLionel Sambuc void setLazyReload() {
346472758f3SLionel Sambuc pthread_rwlock_wrlock(&fdeTreeLock);
347472758f3SLionel Sambuc needsReload = true;
348472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
349472758f3SLionel Sambuc }
350472758f3SLionel Sambuc
351472758f3SLionel Sambuc private:
352472758f3SLionel Sambuc findPCRange_t findPCRange;
353472758f3SLionel Sambuc bool needsReload;
354*0a6a1f1dSLionel Sambuc #if !defined(__minix)
355472758f3SLionel Sambuc pthread_rwlock_t fdeTreeLock;
356*0a6a1f1dSLionel Sambuc #endif /* !defined(__minix) */
357472758f3SLionel Sambuc rb_tree_t segmentTree;
358472758f3SLionel Sambuc rb_tree_t dsoTree;
359472758f3SLionel Sambuc
360472758f3SLionel Sambuc friend int phdr_callback(struct dl_phdr_info *, size_t, void *);
361472758f3SLionel Sambuc friend int rangeCmp(void *, const void *, const void *);
362472758f3SLionel Sambuc friend int rangeCmpKey(void *, const void *, const void *);
363472758f3SLionel Sambuc friend int dsoTableCmp(void *, const void *, const void *);
364472758f3SLionel Sambuc friend int dsoTableCmpKey(void *, const void *, const void *);
365472758f3SLionel Sambuc
366472758f3SLionel Sambuc void updateRange();
367472758f3SLionel Sambuc
368472758f3SLionel Sambuc struct Range {
369472758f3SLionel Sambuc rb_node_t range_link;
370472758f3SLionel Sambuc rb_node_t dso_link;
371472758f3SLionel Sambuc pint_t hdr_base; // Pointer to FDE if hdr_start == 0
372472758f3SLionel Sambuc pint_t hdr_start;
373472758f3SLionel Sambuc pint_t hdr_entries;
374472758f3SLionel Sambuc pint_t first_pc;
375472758f3SLionel Sambuc pint_t last_pc;
376472758f3SLionel Sambuc pint_t data_base;
377472758f3SLionel Sambuc pint_t ehframe_base;
378472758f3SLionel Sambuc };
379472758f3SLionel Sambuc
lazyReload()380472758f3SLionel Sambuc void lazyReload() {
381472758f3SLionel Sambuc pthread_rwlock_wrlock(&fdeTreeLock);
382472758f3SLionel Sambuc dl_iterate_phdr(phdr_callback, this);
383472758f3SLionel Sambuc needsReload = false;
384472758f3SLionel Sambuc pthread_rwlock_unlock(&fdeTreeLock);
385472758f3SLionel Sambuc }
386472758f3SLionel Sambuc
addDSO(pint_t header,pint_t data_base)387472758f3SLionel Sambuc void addDSO(pint_t header, pint_t data_base) {
388472758f3SLionel Sambuc if (header == 0)
389472758f3SLionel Sambuc return;
390472758f3SLionel Sambuc if (get8(header) != 1)
391472758f3SLionel Sambuc return;
392472758f3SLionel Sambuc if (get8(header + 3) != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
393472758f3SLionel Sambuc return;
394472758f3SLionel Sambuc pint_t end = header + 4;
395472758f3SLionel Sambuc pint_t ehframe_base = getEncodedP(end, 0, get8(header + 1), NULL);
396472758f3SLionel Sambuc pint_t entries = getEncodedP(end, 0, get8(header + 2), NULL);
397472758f3SLionel Sambuc pint_t start = (end + 3) & ~pint_t(3);
398472758f3SLionel Sambuc if (entries == 0)
399472758f3SLionel Sambuc return;
400472758f3SLionel Sambuc Range *n = (Range *)malloc(sizeof(*n));
401472758f3SLionel Sambuc n->hdr_base = header;
402472758f3SLionel Sambuc n->hdr_start = start;
403472758f3SLionel Sambuc n->hdr_entries = entries;
404472758f3SLionel Sambuc n->first_pc = header + (int32_t)get32(n->hdr_start);
405472758f3SLionel Sambuc pint_t tmp;
406472758f3SLionel Sambuc (*findPCRange)(
407472758f3SLionel Sambuc *this, header + (int32_t)get32(n->hdr_start + (entries - 1) * 8 + 4),
408472758f3SLionel Sambuc tmp, n->last_pc);
409472758f3SLionel Sambuc n->data_base = data_base;
410472758f3SLionel Sambuc n->ehframe_base = ehframe_base;
411472758f3SLionel Sambuc
412*0a6a1f1dSLionel Sambuc if (static_cast<Range *>(rb_tree_insert_node(&segmentTree, n)) != n) {
413472758f3SLionel Sambuc free(n);
414472758f3SLionel Sambuc return;
415472758f3SLionel Sambuc }
416472758f3SLionel Sambuc rb_tree_insert_node(&dsoTree, n);
417472758f3SLionel Sambuc }
418472758f3SLionel Sambuc };
419472758f3SLionel Sambuc
phdr_callback(struct dl_phdr_info * info,size_t size,void * data_)420472758f3SLionel Sambuc static int phdr_callback(struct dl_phdr_info *info, size_t size, void *data_) {
421472758f3SLionel Sambuc LocalAddressSpace *data = (LocalAddressSpace *)data_;
422472758f3SLionel Sambuc size_t eh_frame = 0, data_base = 0;
423472758f3SLionel Sambuc const Elf_Phdr *hdr = info->dlpi_phdr;
424472758f3SLionel Sambuc const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
425472758f3SLionel Sambuc const Elf_Dyn *dyn;
426472758f3SLionel Sambuc
427472758f3SLionel Sambuc for (; hdr != last_hdr; ++hdr) {
428472758f3SLionel Sambuc switch (hdr->p_type) {
429472758f3SLionel Sambuc case PT_GNU_EH_FRAME:
430472758f3SLionel Sambuc eh_frame = info->dlpi_addr + hdr->p_vaddr;
431472758f3SLionel Sambuc break;
432472758f3SLionel Sambuc case PT_DYNAMIC:
433472758f3SLionel Sambuc dyn = (const Elf_Dyn *)(info->dlpi_addr + hdr->p_vaddr);
434472758f3SLionel Sambuc while (dyn->d_tag != DT_NULL) {
435472758f3SLionel Sambuc if (dyn->d_tag == DT_PLTGOT) {
436472758f3SLionel Sambuc data_base = info->dlpi_addr + dyn->d_un.d_ptr;
437472758f3SLionel Sambuc break;
438472758f3SLionel Sambuc }
439472758f3SLionel Sambuc ++dyn;
440472758f3SLionel Sambuc }
441472758f3SLionel Sambuc }
442472758f3SLionel Sambuc }
443472758f3SLionel Sambuc
444472758f3SLionel Sambuc if (eh_frame)
445472758f3SLionel Sambuc data->addDSO(eh_frame, data_base);
446472758f3SLionel Sambuc
447472758f3SLionel Sambuc return 0;
448472758f3SLionel Sambuc }
449472758f3SLionel Sambuc
rangeCmp(void * context,const void * n1_,const void * n2_)450472758f3SLionel Sambuc static int rangeCmp(void *context, const void *n1_, const void *n2_) {
451b029fb59SBen Gras const LocalAddressSpace::Range *n1 = (const LocalAddressSpace::Range *)n1_;
452b029fb59SBen Gras const LocalAddressSpace::Range *n2 = (const LocalAddressSpace::Range *)n2_;
453472758f3SLionel Sambuc
454472758f3SLionel Sambuc if (n1->first_pc < n2->first_pc)
455472758f3SLionel Sambuc return -1;
456472758f3SLionel Sambuc if (n1->first_pc > n2->first_pc)
457472758f3SLionel Sambuc return 1;
458472758f3SLionel Sambuc assert(n1->last_pc == n2->last_pc);
459472758f3SLionel Sambuc return 0;
460472758f3SLionel Sambuc }
461472758f3SLionel Sambuc
rangeCmpKey(void * context,const void * n_,const void * pc_)462472758f3SLionel Sambuc static int rangeCmpKey(void *context, const void *n_, const void *pc_) {
463b029fb59SBen Gras const LocalAddressSpace::Range *n = (const LocalAddressSpace::Range *)n_;
464b029fb59SBen Gras const LocalAddressSpace::pint_t *pc = (const LocalAddressSpace::pint_t *)pc_;
465472758f3SLionel Sambuc if (n->last_pc < *pc)
466472758f3SLionel Sambuc return -1;
467472758f3SLionel Sambuc if (n->first_pc > *pc)
468472758f3SLionel Sambuc return 1;
469472758f3SLionel Sambuc return 0;
470472758f3SLionel Sambuc }
471472758f3SLionel Sambuc
dsoTableCmp(void * context,const void * n1_,const void * n2_)472472758f3SLionel Sambuc static int dsoTableCmp(void *context, const void *n1_, const void *n2_) {
473b029fb59SBen Gras const LocalAddressSpace::Range *n1 = (const LocalAddressSpace::Range *)n1_;
474b029fb59SBen Gras const LocalAddressSpace::Range *n2 = (const LocalAddressSpace::Range *)n2_;
475472758f3SLionel Sambuc
476472758f3SLionel Sambuc if (n1->ehframe_base < n2->ehframe_base)
477472758f3SLionel Sambuc return -1;
478472758f3SLionel Sambuc if (n1->ehframe_base > n2->ehframe_base)
479472758f3SLionel Sambuc return 1;
480472758f3SLionel Sambuc return 0;
481472758f3SLionel Sambuc }
482472758f3SLionel Sambuc
dsoTableCmpKey(void * context,const void * n_,const void * ptr_)483472758f3SLionel Sambuc static int dsoTableCmpKey(void *context, const void *n_, const void *ptr_) {
484b029fb59SBen Gras const LocalAddressSpace::Range *n = (const LocalAddressSpace::Range *)n_;
485b029fb59SBen Gras const LocalAddressSpace::pint_t *ptr = (const LocalAddressSpace::pint_t *)ptr_;
486472758f3SLionel Sambuc if (n->ehframe_base < *ptr)
487472758f3SLionel Sambuc return -1;
488472758f3SLionel Sambuc if (n->ehframe_base > *ptr)
489472758f3SLionel Sambuc return 1;
490472758f3SLionel Sambuc return 0;
491472758f3SLionel Sambuc }
492472758f3SLionel Sambuc
493472758f3SLionel Sambuc } // namespace _Unwind
494472758f3SLionel Sambuc
495472758f3SLionel Sambuc #endif // __ADDRESSSPACE_HPP__
496