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