1 //===--------------------------- libuwind.cpp -----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 // 9 // Implements unw_* functions from <libunwind.h> 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include <libunwind.h> 14 15 #ifndef NDEBUG 16 #include <cstdlib> // getenv 17 #endif 18 #include <new> 19 #include <tuple> 20 #include <memory> 21 #include <vector> 22 23 #include "libunwind_ext.h" 24 #include "config.h" 25 26 #include <stdlib.h> 27 28 29 #include "UnwindCursor.hpp" 30 31 using namespace libunwind; 32 33 /// internal object to represent this processes address space 34 LocalAddressSpace LocalAddressSpace::sThisAddressSpace; 35 36 _LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = 37 (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace; 38 39 /// record the registers and stack position of the caller 40 extern int unw_getcontext(unw_context_t *); 41 // note: unw_getcontext() implemented in assembly 42 43 /// Create a cursor of a thread in this process given 'context' recorded by 44 /// unw_getcontext(). 45 _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, 46 unw_context_t *context) { 47 _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", 48 static_cast<void *>(cursor), 49 static_cast<void *>(context)); 50 // Use "placement new" to allocate UnwindCursor in the cursor buffer. 51 #if defined(__i386__) 52 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>( 53 context, LocalAddressSpace::sThisAddressSpace); 54 #elif defined(__x86_64__) 55 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>( 56 context, LocalAddressSpace::sThisAddressSpace); 57 #elif defined(__ppc__) 58 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>( 59 context, LocalAddressSpace::sThisAddressSpace); 60 #elif defined(__arm64__) 61 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>( 62 context, LocalAddressSpace::sThisAddressSpace); 63 #elif LIBCXXABI_ARM_EHABI 64 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>( 65 context, LocalAddressSpace::sThisAddressSpace); 66 #endif 67 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 68 co->setInfoBasedOnIPRegister(); 69 70 return UNW_ESUCCESS; 71 } 72 73 #ifdef UNW_REMOTE 74 /// Create a cursor into a thread in another process. 75 _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, 76 unw_addr_space_t as, 77 void *arg) { 78 // special case: unw_init_remote(xx, unw_local_addr_space, xx) 79 if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace) 80 return unw_init_local(cursor, NULL); //FIXME 81 82 // use "placement new" to allocate UnwindCursor in the cursor buffer 83 switch (as->cpuType) { 84 case CPU_TYPE_I386: 85 new ((void *)cursor) 86 UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >, 87 Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); 88 break; 89 case CPU_TYPE_X86_64: 90 new ((void *)cursor) UnwindCursor< 91 OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>( 92 ((unw_addr_space_x86_64 *)as)->oas, arg); 93 break; 94 case CPU_TYPE_POWERPC: 95 new ((void *)cursor) 96 UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>( 97 ((unw_addr_space_ppc *)as)->oas, arg); 98 break; 99 default: 100 return UNW_EUNSPEC; 101 } 102 return UNW_ESUCCESS; 103 } 104 105 106 static bool is64bit(task_t task) { 107 return false; // FIXME 108 } 109 110 /// Create an address_space object for use in examining another task. 111 _LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { 112 #if __i386__ 113 if (is64bit(task)) { 114 unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task); 115 as->taskPort = task; 116 as->cpuType = CPU_TYPE_X86_64; 117 //as->oas 118 } else { 119 unw_addr_space_i386 *as = new unw_addr_space_i386(task); 120 as->taskPort = task; 121 as->cpuType = CPU_TYPE_I386; 122 //as->oas 123 } 124 #else 125 // FIXME 126 #endif 127 } 128 129 130 /// Delete an address_space object. 131 _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { 132 switch (asp->cpuType) { 133 #if __i386__ || __x86_64__ 134 case CPU_TYPE_I386: { 135 unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp; 136 delete as; 137 } 138 break; 139 case CPU_TYPE_X86_64: { 140 unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp; 141 delete as; 142 } 143 break; 144 #endif 145 case CPU_TYPE_POWERPC: { 146 unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp; 147 delete as; 148 } 149 break; 150 } 151 } 152 #endif // UNW_REMOTE 153 154 155 /// Get value of specified register at cursor position in stack frame. 156 _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, 157 unw_word_t *value) { 158 _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", 159 static_cast<void *>(cursor), regNum, 160 static_cast<void *>(value)); 161 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 162 if (co->validReg(regNum)) { 163 *value = co->getReg(regNum); 164 return UNW_ESUCCESS; 165 } 166 return UNW_EBADREG; 167 } 168 169 170 /// Set value of specified register at cursor position in stack frame. 171 _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, 172 unw_word_t value) { 173 _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", 174 static_cast<void *>(cursor), regNum, (long long)value); 175 typedef LocalAddressSpace::pint_t pint_t; 176 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 177 if (co->validReg(regNum)) { 178 co->setReg(regNum, (pint_t)value); 179 // specical case altering IP to re-find info (being called by personality 180 // function) 181 if (regNum == UNW_REG_IP) 182 co->setInfoBasedOnIPRegister(false); 183 return UNW_ESUCCESS; 184 } 185 return UNW_EBADREG; 186 } 187 188 189 /// Get value of specified float register at cursor position in stack frame. 190 _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, 191 unw_fpreg_t *value) { 192 _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", 193 static_cast<void *>(cursor), regNum, 194 static_cast<void *>(value)); 195 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 196 if (co->validFloatReg(regNum)) { 197 *value = co->getFloatReg(regNum); 198 return UNW_ESUCCESS; 199 } 200 return UNW_EBADREG; 201 } 202 203 204 /// Set value of specified float register at cursor position in stack frame. 205 _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, 206 unw_fpreg_t value) { 207 #if LIBCXXABI_ARM_EHABI 208 _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n", 209 static_cast<void *>(cursor), regNum, value); 210 #else 211 _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", 212 static_cast<void *>(cursor), regNum, value); 213 #endif 214 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 215 if (co->validFloatReg(regNum)) { 216 co->setFloatReg(regNum, value); 217 return UNW_ESUCCESS; 218 } 219 return UNW_EBADREG; 220 } 221 222 223 /// Move cursor to next frame. 224 _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { 225 _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", static_cast<void *>(cursor)); 226 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 227 return co->step(); 228 } 229 230 231 /// Get unwind info at cursor position in stack frame. 232 _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, 233 unw_proc_info_t *info) { 234 _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n", 235 static_cast<void *>(cursor), static_cast<void *>(info)); 236 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 237 co->getInfo(info); 238 if (info->end_ip == 0) 239 return UNW_ENOINFO; 240 else 241 return UNW_ESUCCESS; 242 } 243 244 245 /// Resume execution at cursor position (aka longjump). 246 _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { 247 _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", static_cast<void *>(cursor)); 248 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 249 co->jumpto(); 250 return UNW_EUNSPEC; 251 } 252 253 254 /// Get name of function at cursor position in stack frame. 255 _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, 256 size_t bufLen, unw_word_t *offset) { 257 _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)\n", 258 static_cast<void *>(cursor), static_cast<void *>(buf), 259 static_cast<unsigned long>(bufLen)); 260 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 261 if (co->getFunctionName(buf, bufLen, offset)) 262 return UNW_ESUCCESS; 263 else 264 return UNW_EUNSPEC; 265 } 266 267 268 /// Checks if a register is a floating-point register. 269 _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { 270 _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", 271 static_cast<void *>(cursor), regNum); 272 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 273 return co->validFloatReg(regNum); 274 } 275 276 277 /// Checks if a register is a floating-point register. 278 _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, 279 unw_regnum_t regNum) { 280 _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n", 281 static_cast<void *>(cursor), regNum); 282 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 283 return co->getRegisterName(regNum); 284 } 285 286 287 /// Checks if current frame is signal trampoline. 288 _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { 289 _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", 290 static_cast<void *>(cursor)); 291 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 292 return co->isSignalFrame(); 293 } 294 295 #ifdef __arm__ 296 // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD 297 _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) { 298 _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)\n", 299 static_cast<void *>(cursor)); 300 AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; 301 return co->saveVFPAsX(); 302 } 303 #endif 304 305 306 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND 307 /// SPI: walks cached dwarf entries 308 _LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( 309 unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { 310 _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", 311 reinterpret_cast<void *>(func)); 312 DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func); 313 } 314 315 316 /// IPI: for __register_frame() 317 void _unw_add_dynamic_fde(unw_word_t fde) { 318 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 319 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 320 const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE( 321 LocalAddressSpace::sThisAddressSpace, 322 (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); 323 if (message == NULL) { 324 // dynamically registered FDEs don't have a mach_header group they are in. 325 // Use fde as mh_group 326 unw_word_t mh_group = fdeInfo.fdeStart; 327 DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group, 328 fdeInfo.pcStart, fdeInfo.pcEnd, 329 fdeInfo.fdeStart); 330 } else { 331 _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); 332 } 333 } 334 335 /// IPI: for __deregister_frame() 336 void _unw_remove_dynamic_fde(unw_word_t fde) { 337 // fde is own mh_group 338 DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde); 339 } 340 #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND 341 342 343 344 // Add logging hooks in Debug builds only 345 #ifndef NDEBUG 346 #include <stdlib.h> 347 348 _LIBUNWIND_HIDDEN 349 bool logAPIs() { 350 // do manual lock to avoid use of _cxa_guard_acquire or initializers 351 static bool checked = false; 352 static bool log = false; 353 if (!checked) { 354 log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); 355 checked = true; 356 } 357 return log; 358 } 359 360 _LIBUNWIND_HIDDEN 361 bool logUnwinding() { 362 // do manual lock to avoid use of _cxa_guard_acquire or initializers 363 static bool checked = false; 364 static bool log = false; 365 if (!checked) { 366 log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); 367 checked = true; 368 } 369 return log; 370 } 371 372 #endif // NDEBUG 373 374