]> git.saurik.com Git - apple/ld64.git/blob - src/ld/parsers/libunwind/AddressSpace.hpp
ld64-136.tar.gz
[apple/ld64.git] / src / ld / parsers / libunwind / AddressSpace.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 //
26 // C++ interface to lower levels of libuwind
27 //
28
29 #ifndef __ADDRESSSPACE_HPP__
30 #define __ADDRESSSPACE_HPP__
31
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <dlfcn.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/getsect.h>
38 #include <mach-o/dyld_priv.h>
39 #include <mach/i386/thread_status.h>
40 #include <Availability.h>
41
42 #include "FileAbstraction.hpp"
43 #include "libunwind.h"
44 #include "InternalMacros.h"
45 #include "dwarf2.h"
46
47
48 #if 0
49 #if __i386__ || __x86_64__
50 // In 10.6 and later i386 and x86_64 don't have a __dyld section
51 // We need one to access private _dyld_func_lookup function.
52
53 struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
54
55 static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
56
57
58 static int my_dyld_func_lookup(const char* dyld_func_name, void **address)
59 {
60 return (*myDyldSection.lookup)(dyld_func_name, address);
61 }
62 #else
63 #define my_dyld_func_lookup _dyld_func_lookup
64 #endif
65
66
67 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
68 {
69 static void* (*p)(void*, dyld_unwind_sections*) = NULL;
70
71 if(p == NULL)
72 my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
73 return p(addr, info);
74 }
75 #endif // 0
76
77
78
79 namespace libunwind {
80
81 ///
82 /// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
83 /// in the same process. It compiles away and making local unwinds very fast.
84 ///
85 class LocalAddressSpace
86 {
87 public:
88
89 #if __LP64__
90 typedef uint64_t pint_t;
91 typedef int64_t sint_t;
92 #else
93 typedef uint32_t pint_t;
94 typedef int32_t sint_t;
95 #endif
96 uint8_t get8(pint_t addr) { return *((uint8_t*)addr); }
97 uint16_t get16(pint_t addr) { return *((uint16_t*)addr); }
98 uint32_t get32(pint_t addr) { return *((uint32_t*)addr); }
99 uint64_t get64(pint_t addr) { return *((uint64_t*)addr); }
100 double getDouble(pint_t addr) { return *((double*)addr); }
101 v128 getVector(pint_t addr) { return *((v128*)addr); }
102 uintptr_t getP(pint_t addr);
103 static uint64_t getULEB128(pint_t& addr, pint_t end);
104 static int64_t getSLEB128(pint_t& addr, pint_t end);
105
106 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
107 bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
108 bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart);
109
110 };
111
112 LocalAddressSpace sThisAddress;
113
114 inline uintptr_t LocalAddressSpace::getP(pint_t addr)
115 {
116 #if __LP64__
117 return get64(addr);
118 #else
119 return get32(addr);
120 #endif
121 }
122
123 /* Read a ULEB128 into a 64-bit word. */
124 inline uint64_t
125 LocalAddressSpace::getULEB128(pint_t& addr, pint_t end)
126 {
127 const uint8_t* p = (uint8_t*)addr;
128 const uint8_t* pend = (uint8_t*)end;
129 uint64_t result = 0;
130 int bit = 0;
131 do {
132 uint64_t b;
133
134 if ( p == pend )
135 ABORT("truncated uleb128 expression");
136
137 b = *p & 0x7f;
138
139 if (bit >= 64 || b << bit >> bit != b) {
140 ABORT("malformed uleb128 expression");
141 }
142 else {
143 result |= b << bit;
144 bit += 7;
145 }
146 } while ( *p++ >= 0x80 );
147 addr = (pint_t)p;
148 return result;
149 }
150
151 /* Read a SLEB128 into a 64-bit word. */
152 inline int64_t
153 LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end)
154 {
155 const uint8_t* p = (uint8_t*)addr;
156 int64_t result = 0;
157 int bit = 0;
158 uint8_t byte;
159 do {
160 byte = *p++;
161 result |= ((byte & 0x7f) << bit);
162 bit += 7;
163 } while (byte & 0x80);
164 // sign extend negative numbers
165 if ( (byte & 0x40) != 0 )
166 result |= (-1LL) << bit;
167 addr = (pint_t)p;
168 return result;
169 }
170
171 LocalAddressSpace::pint_t
172 LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
173 {
174 pint_t startAddr = addr;
175 const uint8_t* p = (uint8_t*)addr;
176 pint_t result;
177
178 // first get value
179 switch (encoding & 0x0F) {
180 case DW_EH_PE_ptr:
181 result = getP(addr);
182 p += sizeof(pint_t);
183 addr = (pint_t)p;
184 break;
185 case DW_EH_PE_uleb128:
186 result = getULEB128(addr, end);
187 break;
188 case DW_EH_PE_udata2:
189 result = get16(addr);
190 p += 2;
191 addr = (pint_t)p;
192 break;
193 case DW_EH_PE_udata4:
194 result = get32(addr);
195 p += 4;
196 addr = (pint_t)p;
197 break;
198 case DW_EH_PE_udata8:
199 result = get64(addr);
200 p += 8;
201 addr = (pint_t)p;
202 break;
203 case DW_EH_PE_sleb128:
204 result = getSLEB128(addr, end);
205 break;
206 case DW_EH_PE_sdata2:
207 result = (int16_t)get16(addr);
208 p += 2;
209 addr = (pint_t)p;
210 break;
211 case DW_EH_PE_sdata4:
212 result = (int32_t)get32(addr);
213 p += 4;
214 addr = (pint_t)p;
215 break;
216 case DW_EH_PE_sdata8:
217 result = get64(addr);
218 p += 8;
219 addr = (pint_t)p;
220 break;
221 default:
222 ABORT("unknown pointer encoding");
223 }
224
225 // then add relative offset
226 switch ( encoding & 0x70 ) {
227 case DW_EH_PE_absptr:
228 // do nothing
229 break;
230 case DW_EH_PE_pcrel:
231 result += startAddr;
232 break;
233 case DW_EH_PE_textrel:
234 ABORT("DW_EH_PE_textrel pointer encoding not supported");
235 break;
236 case DW_EH_PE_datarel:
237 ABORT("DW_EH_PE_datarel pointer encoding not supported");
238 break;
239 case DW_EH_PE_funcrel:
240 ABORT("DW_EH_PE_funcrel pointer encoding not supported");
241 break;
242 case DW_EH_PE_aligned:
243 ABORT("DW_EH_PE_aligned pointer encoding not supported");
244 break;
245 default:
246 ABORT("unknown pointer encoding");
247 break;
248 }
249
250 if ( encoding & DW_EH_PE_indirect )
251 result = getP(result);
252
253 return result;
254 }
255
256
257 inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart)
258 {
259 dyld_unwind_sections info;
260 if ( _dyld_find_unwind_sections((void*)addr, &info) ) {
261 mh = (pint_t)info.mh;
262 dwarfStart = (pint_t)info.dwarf_section;
263 dwarfLen = (pint_t)info.dwarf_section_length;
264 compactStart = (pint_t)info.compact_unwind_section;
265 return true;
266 }
267 return false;
268 }
269
270
271 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
272 {
273 dl_info dyldInfo;
274 if ( dladdr((void*)addr, &dyldInfo) ) {
275 if ( dyldInfo.dli_sname != NULL ) {
276 strlcpy(buf, dyldInfo.dli_sname, bufLen);
277 *offset = (addr - (pint_t)dyldInfo.dli_saddr);
278 return true;
279 }
280 }
281 return false;
282 }
283
284
285
286 #if UNW_REMOTE
287
288 ///
289 /// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread
290 /// in the another process. The other process can be a different endianness and a different
291 /// pointer size and is handled by the P template parameter.
292 ///
293 template <typename P>
294 class OtherAddressSpace
295 {
296 public:
297 OtherAddressSpace(task_t task) : fTask(task) {}
298
299 typedef typename P::uint_t pint_t;
300
301 uint8_t get8(pint_t addr);
302 uint16_t get16(pint_t addr);
303 uint32_t get32(pint_t addr);
304 uint64_t get64(pint_t addr);
305 pint_t getP(pint_t addr);
306 uint64_t getULEB128(pint_t& addr, pint_t end);
307 int64_t getSLEB128(pint_t& addr, pint_t end);
308 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
309 bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset);
310 bool findUnwindSections(pint_t addr, unwind_sections& info);
311 private:
312 void* localCopy(pint_t addr);
313
314
315 task_t fTask;
316 };
317
318
319 template <typename P>
320 uint8_t OtherAddressSpace<P>::get8(pint_t addr)
321 {
322 return *((uint8_t*)localCopy(addr));
323 }
324
325 template <typename P>
326 uint16_t OtherAddressSpace<P>::get16(pint_t addr)
327 {
328 return P::E::get16(*(uint16_t*)localCopy(addr));
329 }
330
331 template <typename P>
332 uint32_t OtherAddressSpace<P>::get32(pint_t addr)
333 {
334 return P::E::get32(*(uint32_t*)localCopy(addr));
335 }
336
337 template <typename P>
338 uint64_t OtherAddressSpace<P>::get64(pint_t addr)
339 {
340 return P::E::get64(*(uint64_t*)localCopy(addr));
341 }
342
343 template <typename P>
344 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr)
345 {
346 return P::getP(*(uint64_t*)localCopy(addr));
347 }
348
349 template <typename P>
350 uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end)
351 {
352 uintptr_t size = (end - addr);
353 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
354 LocalAddressSpace::pint_t sladdr = laddr;
355 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size);
356 addr += (laddr-sladdr);
357 return result;
358 }
359
360 template <typename P>
361 int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end)
362 {
363 uintptr_t size = (end - addr);
364 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr);
365 LocalAddressSpace::pint_t sladdr = laddr;
366 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size);
367 addr += (laddr-sladdr);
368 return result;
369 }
370
371 template <typename P>
372 void* OtherAddressSpace<P>::localCopy(pint_t addr)
373 {
374 // FIX ME
375 }
376
377 template <typename P>
378 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset)
379 {
380 // FIX ME
381 }
382
383
384
385 ///
386 /// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to.
387 ///
388 struct unw_addr_space
389 {
390 cpu_type_t cpuType;
391 task_t taskPort;
392 };
393
394
395 ///
396 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining
397 /// a 32-bit intel process.
398 ///
399 struct unw_addr_space_i386 : public unw_addr_space
400 {
401 unw_addr_space_i386(task_t task) : oas(task) {}
402 OtherAddressSpace<Pointer32<LittleEndian> > oas;
403 };
404
405
406 ///
407 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining
408 /// a 64-bit intel process.
409 ///
410 struct unw_addr_space_x86_64 : public unw_addr_space
411 {
412 unw_addr_space_x86_64(task_t task) : oas(task) {}
413 OtherAddressSpace<Pointer64<LittleEndian> > oas;
414 };
415
416
417 ///
418 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining
419 /// a 32-bit PowerPC process.
420 ///
421 struct unw_addr_space_ppc : public unw_addr_space
422 {
423 unw_addr_space_ppc(task_t task) : oas(task) {}
424 OtherAddressSpace<Pointer32<BigEndian> > oas;
425 };
426
427
428 #endif // UNW_REMOTE
429
430
431 } // namespace libunwind
432
433
434
435 #endif // __ADDRESSSPACE_HPP__
436
437
438
439