1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2007-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#include <mach/mach_types.h> 27#include <mach/machine.h> 28#include <new> 29 30#include "libunwind.h" 31#include "libunwind_priv.h" 32 33#include "UnwindCursor.hpp" 34 35 36 37using namespace libunwind; 38 39 40// setup debug logging hooks 41INITIALIZE_DEBUG_PRINT_API 42INITIALIZE_DEBUG_PRINT_UNWINDING 43 44 45#if __ppc__ || __i386__ || __x86_64__ 46 47// internal object to represent this processes address space 48static LocalAddressSpace sThisAddressSpace; 49 50/// 51/// record the registers and stack position of the caller 52/// 53extern int unw_getcontext(unw_context_t*); 54// note: unw_getcontext() implemented in assembly 55 56 57/// 58/// create a cursor of a thread in this process given 'context' recorded by unw_getcontext() 59/// 60EXPORT int unw_init_local(unw_cursor_t* cursor, unw_context_t* context) 61{ 62 DEBUG_PRINT_API("unw_init_local(cursor=%p, context=%p)\n", cursor, context); 63 // use "placement new" to allocate UnwindCursor in the cursor buffer 64#if __i386__ 65 new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86>(context, sThisAddressSpace); 66#elif __x86_64__ 67 new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_x86_64>(context, sThisAddressSpace); 68#elif __ppc__ 69 new ((void*)cursor) UnwindCursor<LocalAddressSpace,Registers_ppc>(context, sThisAddressSpace); 70#endif 71 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 72 co->setInfoBasedOnIPRegister(); 73 74 return UNW_ESUCCESS; 75} 76 77#if UNW_REMOTE 78 79EXPORT unw_addr_space_t unw_local_addr_space = (unw_addr_space_t)&sThisAddressSpace; 80 81/// 82/// create a cursor into a thread in another process 83/// 84EXPORT int unw_init_remote_thread(unw_cursor_t* cursor, unw_addr_space_t as, thread_t thread) 85{ 86 // special case: unw_init_remote(xx, unw_local_addr_space, xx) 87 if ( as == (unw_addr_space_t)&sThisAddressSpace ) 88 return unw_init_local(cursor, NULL); //FIXME 89 90 // use "placement new" to allocate UnwindCursor in the cursor buffer 91 switch ( as->cpuType ) { 92 case CPU_TYPE_I386: 93 new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >, 94 Registers_x86>(((unw_addr_space_i386*)as)->oas, thread); 95 break; 96 case CPU_TYPE_X86_64: 97 new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer64<LittleEndian> >, 98 Registers_x86_64>(((unw_addr_space_x86_64*)as)->oas, thread); 99 break; 100 case CPU_TYPE_POWERPC: 101 new ((void*)cursor) UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, 102 Registers_ppc>(((unw_addr_space_ppc*)as)->oas, thread); 103 break; 104 default: 105 return UNW_EUNSPEC; 106 } 107 return UNW_ESUCCESS; 108} 109 110static bool rosetta(task_t task) 111{ 112 return false; // FIXME 113} 114 115static bool is64bit(task_t task) 116{ 117 return false; // FIXME 118} 119 120/// 121/// create an address_space object for use in examining another task 122/// 123EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) 124{ 125#if __i386__ 126 if ( rosetta(task) ) { 127 unw_addr_space_ppc* as = new unw_addr_space_ppc(task); 128 as->taskPort = task; 129 as->cpuType = CPU_TYPE_POWERPC; 130 //as->oas 131 } 132 else if ( is64bit(task) ) { 133 unw_addr_space_x86_64* as = new unw_addr_space_x86_64(task); 134 as->taskPort = task; 135 as->cpuType = CPU_TYPE_X86_64; 136 //as->oas 137 } 138 else { 139 unw_addr_space_i386* as = new unw_addr_space_i386(task); 140 as->taskPort = task; 141 as->cpuType = CPU_TYPE_I386; 142 //as->oas 143 } 144#else 145 // FIXME 146#endif 147} 148 149 150/// 151/// delete an address_space object 152/// 153EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) 154{ 155 switch ( asp->cpuType ) { 156#if __i386__ || __x86_64__ 157 case CPU_TYPE_I386: 158 { 159 unw_addr_space_i386* as = (unw_addr_space_i386*)asp; 160 delete as; 161 } 162 break; 163 case CPU_TYPE_X86_64: 164 { 165 unw_addr_space_x86_64* as = (unw_addr_space_x86_64*)asp; 166 delete as; 167 } 168 break; 169#endif 170 case CPU_TYPE_POWERPC: 171 { 172 unw_addr_space_ppc* as = (unw_addr_space_ppc*)asp; 173 delete as; 174 } 175 break; 176 } 177} 178#endif // UNW_REMOTE 179 180 181/// 182/// get value of specified register at cursor position in stack frame 183/// 184EXPORT int unw_get_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t* value) 185{ 186 DEBUG_PRINT_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value); 187 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 188 if ( co->validReg(regNum) ) { 189 *value = co->getReg(regNum); 190 return UNW_ESUCCESS; 191 } 192 return UNW_EBADREG; 193} 194 195 196/// 197/// set value of specified register at cursor position in stack frame 198/// 199EXPORT int unw_set_reg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_word_t value) 200{ 201 DEBUG_PRINT_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", cursor, regNum, value); 202 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 203 if ( co->validReg(regNum) ) { 204 co->setReg(regNum, value); 205 // specical case altering IP to re-find info (being called by personality function) 206 if ( regNum == UNW_REG_IP ) { 207 unw_proc_info_t info; 208 co->getInfo(&info); 209 uint64_t orgArgSize = info.gp; 210 uint64_t orgFuncStart = info.start_ip; 211 co->setInfoBasedOnIPRegister(false); 212 // and adjust REG_SP if there was a DW_CFA_GNU_args_size 213 if ( (orgFuncStart == info.start_ip) && (orgArgSize != 0) ) 214 co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize); 215 } 216 return UNW_ESUCCESS; 217 } 218 return UNW_EBADREG; 219} 220 221 222/// 223/// get value of specified float register at cursor position in stack frame 224/// 225EXPORT int unw_get_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t* value) 226{ 227 DEBUG_PRINT_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", cursor, regNum, value); 228 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 229 if ( co->validFloatReg(regNum) ) { 230 *value = co->getFloatReg(regNum); 231 return UNW_ESUCCESS; 232 } 233 return UNW_EBADREG; 234} 235 236/// 237/// set value of specified float register at cursor position in stack frame 238/// 239EXPORT int unw_set_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum, unw_fpreg_t value) 240{ 241 DEBUG_PRINT_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", cursor, regNum, value); 242 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 243 if ( co->validFloatReg(regNum) ) { 244 co->setFloatReg(regNum, value); 245 return UNW_ESUCCESS; 246 } 247 return UNW_EBADREG; 248} 249 250 251/// 252/// move cursor to next frame 253/// 254EXPORT int unw_step(unw_cursor_t* cursor) 255{ 256 DEBUG_PRINT_API("unw_step(cursor=%p)\n", cursor); 257 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 258 return co->step(); 259} 260 261 262/// 263/// get unwind info at cursor position in stack frame 264/// 265EXPORT int unw_get_proc_info(unw_cursor_t* cursor, unw_proc_info_t* info) 266{ 267 DEBUG_PRINT_API("unw_get_proc_info(cursor=%p, &info=%p)\n", cursor, info); 268 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 269 co->getInfo(info); 270 if ( info->end_ip == 0 ) 271 return UNW_ENOINFO; 272 else 273 return UNW_ESUCCESS; 274} 275 276/// 277/// resume execution at cursor position (aka longjump) 278/// 279EXPORT int unw_resume(unw_cursor_t* cursor) 280{ 281 DEBUG_PRINT_API("unw_resume(cursor=%p)\n", cursor); 282 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 283 co->jumpto(); 284 return UNW_EUNSPEC; 285} 286 287 288/// 289/// get name of function at cursor position in stack frame 290/// 291EXPORT int unw_get_proc_name(unw_cursor_t* cursor, char* buf, size_t bufLen, unw_word_t* offset) 292{ 293 DEBUG_PRINT_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%ld)\n", cursor, buf, bufLen); 294 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 295 if ( co->getFunctionName(buf, bufLen, offset) ) 296 return UNW_ESUCCESS; 297 else 298 return UNW_EUNSPEC; 299} 300 301 302/// 303/// checks if a register is a floating-point register 304/// 305EXPORT int unw_is_fpreg(unw_cursor_t* cursor, unw_regnum_t regNum) 306{ 307 DEBUG_PRINT_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", cursor, regNum); 308 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 309 return co->validFloatReg(regNum); 310} 311 312 313/// 314/// checks if a register is a floating-point register 315/// 316EXPORT const char* unw_regname(unw_cursor_t* cursor, unw_regnum_t regNum) 317{ 318 DEBUG_PRINT_API("unw_regname(cursor=%p, regNum=%d)\n", cursor, regNum); 319 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 320 return co->getRegisterName(regNum); 321} 322 323 324/// 325/// checks if current frame is signal trampoline 326/// 327EXPORT int unw_is_signal_frame(unw_cursor_t* cursor) 328{ 329 DEBUG_PRINT_API("unw_is_signal_frame(cursor=%p)\n", cursor); 330 AbstractUnwindCursor* co = (AbstractUnwindCursor*)cursor; 331 return co->isSignalFrame(); 332} 333 334#if !FOR_DYLD 335/// 336/// SPI: walks cached dwarf entries 337/// 338EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) 339{ 340 DEBUG_PRINT_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func); 341 DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func); 342} 343#endif // !FOR_DYLD 344 345 346#if !FOR_DYLD 347// 348// IPI: for __register_frame() 349// 350void _unw_add_dynamic_fde(unw_word_t fde) 351{ 352 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 353 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 354 const char* message = CFI_Parser<LocalAddressSpace>::decodeFDE(sThisAddressSpace, (LocalAddressSpace::pint_t)fde, & fdeInfo, &cieInfo); 355 if ( message == NULL ) { 356 // dynamically registered FDEs don't have a mach_header group they are in. Use fde as mh_group 357 unw_word_t mh_group = fdeInfo.fdeStart; 358 DwarfFDECache<LocalAddressSpace>::add(mh_group, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); 359 } 360 else { 361 DEBUG_MESSAGE("_unw_add_dynamic_fde: bad fde: %s", message); 362 } 363} 364 365// 366// IPI: for __deregister_frame() 367// 368void _unw_remove_dynamic_fde(unw_word_t fde) 369{ 370 // fde is own mh_group 371 DwarfFDECache<LocalAddressSpace>::removeAllIn(fde); 372} 373#endif 374 375 376#endif // __ppc__ || __i386__ || __x86_64__ 377 378 379 380 381