1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2008-2011 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 <Availability.h> 40 41#include "FileAbstraction.hpp" 42#include "libunwind.h" 43#include "InternalMacros.h" 44#include "dwarf2.h" 45 46 47#if __i386__ && defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 48// For iOS simulator to link, we need a __dyld section 49// We need one to access private _dyld_func_lookup function. 50 51struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); }; 52 53static volatile struct __DATA__dyld myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL }; 54 55 56static int my_dyld_func_lookup(const char* dyld_func_name, void **address) 57{ 58 return (*myDyldSection.lookup)(dyld_func_name, address); 59} 60 61bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) 62{ 63 static void* (*p)(void*, dyld_unwind_sections*) = NULL; 64 65 if(p == NULL) 66 my_dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p); 67 return p(addr, info); 68} 69#endif 70 71 72namespace libunwind { 73 74/// 75/// LocalAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread 76/// in the same process. It compiles away and making local unwinds very fast. 77/// 78class LocalAddressSpace 79{ 80public: 81 82 #if __LP64__ 83 typedef uint64_t pint_t; 84 typedef int64_t sint_t; 85 #else 86 typedef uint32_t pint_t; 87 typedef int32_t sint_t; 88 #endif 89 uint8_t get8(pint_t addr) { return *((uint8_t*)addr); } 90 uint16_t get16(pint_t addr) { return *((uint16_t*)addr); } 91 uint32_t get32(pint_t addr) { return *((uint32_t*)addr); } 92 uint64_t get64(pint_t addr) { return *((uint64_t*)addr); } 93 double getDouble(pint_t addr) { return *((double*)addr); } 94 v128 getVector(pint_t addr) { return *((v128*)addr); } 95 uintptr_t getP(pint_t addr); 96 static uint64_t getULEB128(pint_t& addr, pint_t end); 97 static int64_t getSLEB128(pint_t& addr, pint_t end); 98 99 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding); 100 bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset); 101 bool findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart); 102 103}; 104 105LocalAddressSpace sThisAddress; 106 107inline uintptr_t LocalAddressSpace::getP(pint_t addr) 108{ 109#if __LP64__ 110 return get64(addr); 111#else 112 return get32(addr); 113#endif 114} 115 116/* Read a ULEB128 into a 64-bit word. */ 117inline uint64_t 118LocalAddressSpace::getULEB128(pint_t& addr, pint_t end) 119{ 120 const uint8_t* p = (uint8_t*)addr; 121 const uint8_t* pend = (uint8_t*)end; 122 uint64_t result = 0; 123 int bit = 0; 124 do { 125 uint64_t b; 126 127 if ( p == pend ) 128 ABORT("truncated uleb128 expression"); 129 130 b = *p & 0x7f; 131 132 if (bit >= 64 || b << bit >> bit != b) { 133 ABORT("malformed uleb128 expression"); 134 } 135 else { 136 result |= b << bit; 137 bit += 7; 138 } 139 } while ( *p++ >= 0x80 ); 140 addr = (pint_t)p; 141 return result; 142} 143 144/* Read a SLEB128 into a 64-bit word. */ 145inline int64_t 146LocalAddressSpace::getSLEB128(pint_t& addr, pint_t end) 147{ 148 const uint8_t* p = (uint8_t*)addr; 149 int64_t result = 0; 150 int bit = 0; 151 uint8_t byte; 152 do { 153 byte = *p++; 154 result |= ((byte & 0x7f) << bit); 155 bit += 7; 156 } while (byte & 0x80); 157 // sign extend negative numbers 158 if ( (byte & 0x40) != 0 ) 159 result |= (-1LL) << bit; 160 addr = (pint_t)p; 161 return result; 162} 163 164LocalAddressSpace::pint_t 165LocalAddressSpace::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding) 166{ 167 pint_t startAddr = addr; 168 const uint8_t* p = (uint8_t*)addr; 169 pint_t result; 170 171 // first get value 172 switch (encoding & 0x0F) { 173 case DW_EH_PE_ptr: 174 result = getP(addr); 175 p += sizeof(pint_t); 176 addr = (pint_t)p; 177 break; 178 case DW_EH_PE_uleb128: 179 result = getULEB128(addr, end); 180 break; 181 case DW_EH_PE_udata2: 182 result = get16(addr); 183 p += 2; 184 addr = (pint_t)p; 185 break; 186 case DW_EH_PE_udata4: 187 result = get32(addr); 188 p += 4; 189 addr = (pint_t)p; 190 break; 191 case DW_EH_PE_udata8: 192 result = get64(addr); 193 p += 8; 194 addr = (pint_t)p; 195 break; 196 case DW_EH_PE_sleb128: 197 result = getSLEB128(addr, end); 198 break; 199 case DW_EH_PE_sdata2: 200 result = (int16_t)get16(addr); 201 p += 2; 202 addr = (pint_t)p; 203 break; 204 case DW_EH_PE_sdata4: 205 result = (int32_t)get32(addr); 206 p += 4; 207 addr = (pint_t)p; 208 break; 209 case DW_EH_PE_sdata8: 210 result = get64(addr); 211 p += 8; 212 addr = (pint_t)p; 213 break; 214 default: 215 ABORT("unknown pointer encoding"); 216 } 217 218 // then add relative offset 219 switch ( encoding & 0x70 ) { 220 case DW_EH_PE_absptr: 221 // do nothing 222 break; 223 case DW_EH_PE_pcrel: 224 result += startAddr; 225 break; 226 case DW_EH_PE_textrel: 227 ABORT("DW_EH_PE_textrel pointer encoding not supported"); 228 break; 229 case DW_EH_PE_datarel: 230 ABORT("DW_EH_PE_datarel pointer encoding not supported"); 231 break; 232 case DW_EH_PE_funcrel: 233 ABORT("DW_EH_PE_funcrel pointer encoding not supported"); 234 break; 235 case DW_EH_PE_aligned: 236 ABORT("DW_EH_PE_aligned pointer encoding not supported"); 237 break; 238 default: 239 ABORT("unknown pointer encoding"); 240 break; 241 } 242 243 if ( encoding & DW_EH_PE_indirect ) 244 result = getP(result); 245 246 return result; 247} 248 249 250inline bool LocalAddressSpace::findUnwindSections(pint_t addr, pint_t& mh, pint_t& dwarfStart, pint_t& dwarfLen, pint_t& compactStart) 251{ 252 dyld_unwind_sections info; 253 if ( _dyld_find_unwind_sections((void*)addr, &info) ) { 254 mh = (pint_t)info.mh; 255 dwarfStart = (pint_t)info.dwarf_section; 256 dwarfLen = (pint_t)info.dwarf_section_length; 257 compactStart = (pint_t)info.compact_unwind_section; 258 return true; 259 } 260 return false; 261} 262 263 264inline bool LocalAddressSpace::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset) 265{ 266 dl_info dyldInfo; 267 if ( dladdr((void*)addr, &dyldInfo) ) { 268 if ( dyldInfo.dli_sname != NULL ) { 269 strlcpy(buf, dyldInfo.dli_sname, bufLen); 270 *offset = (addr - (pint_t)dyldInfo.dli_saddr); 271 return true; 272 } 273 } 274 return false; 275} 276 277 278 279#if UNW_REMOTE 280 281/// 282/// OtherAddressSpace is used as a template parameter to UnwindCursor when unwinding a thread 283/// in the another process. The other process can be a different endianness and a different 284/// pointer size and is handled by the P template parameter. 285/// 286template <typename P> 287class OtherAddressSpace 288{ 289public: 290 OtherAddressSpace(task_t task) : fTask(task) {} 291 292 typedef typename P::uint_t pint_t; 293 294 uint8_t get8(pint_t addr); 295 uint16_t get16(pint_t addr); 296 uint32_t get32(pint_t addr); 297 uint64_t get64(pint_t addr); 298 pint_t getP(pint_t addr); 299 uint64_t getULEB128(pint_t& addr, pint_t end); 300 int64_t getSLEB128(pint_t& addr, pint_t end); 301 pint_t getEncodedP(pint_t& addr, pint_t end, uint8_t encoding); 302 bool findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset); 303 bool findUnwindSections(pint_t addr, unwind_sections& info); 304private: 305 void* localCopy(pint_t addr); 306 307 308 task_t fTask; 309}; 310 311 312template <typename P> 313uint8_t OtherAddressSpace<P>::get8(pint_t addr) 314{ 315 return *((uint8_t*)localCopy(addr)); 316} 317 318template <typename P> 319uint16_t OtherAddressSpace<P>::get16(pint_t addr) 320{ 321 return P::E::get16(*(uint16_t*)localCopy(addr)); 322} 323 324template <typename P> 325uint32_t OtherAddressSpace<P>::get32(pint_t addr) 326{ 327 return P::E::get32(*(uint32_t*)localCopy(addr)); 328} 329 330template <typename P> 331uint64_t OtherAddressSpace<P>::get64(pint_t addr) 332{ 333 return P::E::get64(*(uint64_t*)localCopy(addr)); 334} 335 336template <typename P> 337typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) 338{ 339 return P::getP(*(uint64_t*)localCopy(addr)); 340} 341 342template <typename P> 343uint64_t OtherAddressSpace<P>::getULEB128(pint_t& addr, pint_t end) 344{ 345 uintptr_t size = (end - addr); 346 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr); 347 LocalAddressSpace::pint_t sladdr = laddr; 348 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr+size); 349 addr += (laddr-sladdr); 350 return result; 351} 352 353template <typename P> 354int64_t OtherAddressSpace<P>::getSLEB128(pint_t& addr, pint_t end) 355{ 356 uintptr_t size = (end - addr); 357 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t)localCopy(addr); 358 LocalAddressSpace::pint_t sladdr = laddr; 359 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr+size); 360 addr += (laddr-sladdr); 361 return result; 362} 363 364template <typename P> 365void* OtherAddressSpace<P>::localCopy(pint_t addr) 366{ 367 // FIX ME 368} 369 370template <typename P> 371bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char* buf, size_t bufLen, unw_word_t* offset) 372{ 373 // FIX ME 374} 375 376 377 378/// 379/// unw_addr_space is the base class that abstract unw_addr_space_t type in libunwind.h points to. 380/// 381struct unw_addr_space 382{ 383 cpu_type_t cpuType; 384 task_t taskPort; 385}; 386 387 388/// 389/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points to when examining 390/// a 32-bit intel process. 391/// 392struct unw_addr_space_i386 : public unw_addr_space 393{ 394 unw_addr_space_i386(task_t task) : oas(task) {} 395 OtherAddressSpace<Pointer32<LittleEndian> > oas; 396}; 397 398 399/// 400/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t points to when examining 401/// a 64-bit intel process. 402/// 403struct unw_addr_space_x86_64 : public unw_addr_space 404{ 405 unw_addr_space_x86_64(task_t task) : oas(task) {} 406 OtherAddressSpace<Pointer64<LittleEndian> > oas; 407}; 408 409 410/// 411/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points to when examining 412/// a 32-bit PowerPC process. 413/// 414struct unw_addr_space_ppc : public unw_addr_space 415{ 416 unw_addr_space_ppc(task_t task) : oas(task) {} 417 OtherAddressSpace<Pointer32<BigEndian> > oas; 418}; 419 420 421#endif // UNW_REMOTE 422 423 424} // namespace libunwind 425 426 427#endif // __ADDRESSSPACE_HPP__ 428 429 430 431 432