static void handler(int sig) { unw_context_t context; unw_getcontext(&context); unw_cursor_t cursor; unw_init_local(&cursor, &context); SkDebugf("\nSignal %d:\n", sig); while (unw_step(&cursor) > 0) { static const size_t kMax = 256; char mangled[kMax], demangled[kMax]; unw_word_t offset; unw_get_proc_name(&cursor, mangled, kMax, &offset); int ok; size_t len = kMax; abi::__cxa_demangle(mangled, demangled, &len, &ok); SkDebugf("%s (+0x%zx)\n", ok == 0 ? demangled : mangled, (size_t)offset); } SkDebugf("\n"); // Exit NOW. Don't notify other threads, don't call anything registered with atexit(). _Exit(sig); }
/* * ut_dump_backtrace -- dump stacktrace to error log using libunwind */ void ut_dump_backtrace(void) { unw_context_t context; unw_proc_info_t pip; pip.unwind_info = NULL; int ret = unw_getcontext(&context); if (ret) { ERR("unw_getcontext: %s [%d]", unw_strerror(ret), ret); return; } unw_cursor_t cursor; ret = unw_init_local(&cursor, &context); if (ret) { ERR("unw_init_local: %s [%d]", unw_strerror(ret), ret); return; } ret = unw_step(&cursor); char procname[PROCNAMELEN]; unsigned i = 0; while (ret > 0) { ret = unw_get_proc_info(&cursor, &pip); if (ret) { ERR("unw_get_proc_info: %s [%d]", unw_strerror(ret), ret); break; } unw_word_t off; ret = unw_get_proc_name(&cursor, procname, PROCNAMELEN, &off); if (ret && ret != -UNW_ENOMEM) { if (ret != -UNW_EUNSPEC) { ERR("unw_get_proc_name: %s [%d]", unw_strerror(ret), ret); } strcpy(procname, "?"); } void *ptr = (void *)(pip.start_ip + off); Dl_info dlinfo; const char *fname = "?"; if (dladdr(ptr, &dlinfo) && dlinfo.dli_fname && *dlinfo.dli_fname) fname = dlinfo.dli_fname; ERR("%u: %s (%s%s+0x%lx) [%p]", i++, fname, procname, ret == -UNW_ENOMEM ? "..." : "", off, ptr); ret = unw_step(&cursor); if (ret < 0) ERR("unw_step: %s [%d]", unw_strerror(ret), ret); } }
static void findRealErrorOnStack (ShockerScriptableControlObject* obj) { unw_context_t uc; unw_cursor_t cursor, prev; unw_word_t bp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); char framename [1024]; int count = 0; while (unw_step(&cursor) > 0 && count < 18) { count++; unw_get_proc_name (&cursor, framename, sizeof(framename), 0); if (!*framename) continue; if (strstr (framename, "js_ReportErrorAgain")) { #if (__i386__) unw_get_reg(&prev, UNW_X86_EBP, &bp); #elif (__amd64__) unw_get_reg(&prev, UNW_X86_64_RBP, &bp); #endif bp += 12; char ** n = (char**)bp; obj->GetLogProvider ()->LogError (*n); break; } prev = cursor; } }
void VSDebugLib::printStack() { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp, off; unw_proc_info_t pi; char file[256], name[256]; int line; int status; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_get_proc_name (&cursor, name, sizeof (name), &off); getFileAndLine((long)ip, file, 256, &line); if (line >= 0) { char *realname; realname = abi::__cxa_demangle(name, 0, 0, &status); if (realname) { printf("%s: %s, %d\n", realname, file, line); free(realname); } else { printf("%s: %s, %d\n", name, file, line); } } } }
void backtrace() { unw_cursor_t cursor; unw_context_t context; // Initialize cursor to current frame for local unwinding. unw_getcontext(&context); unw_init_local(&cursor, &context); // Unwind frames one by one, going up the frame stack. while (unw_step(&cursor) > 0) { unw_word_t offset, pc; unw_get_reg(&cursor, UNW_REG_IP, &pc); if (pc == 0) { break; } printf("0x%lx:", pc); char sym[256]; if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { char* nameptr = sym; int status; char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &status); if (status == 0) { nameptr = demangled; } char file[256]; int line = 0; getFileAndLine((long)pc, file, 256, &line); printf(" (%s+0x%lx) in %s:%d\n", nameptr, offset, file, line); free(demangled); } else { printf(" -- error: unable to obtain symbol name for this frame\n"); } } }
void dumpStack(FILE* file, unw_cursor_t cursor) { int nframe = 0; char buffer[100]; unw_word_t off; do { const char * name = !unw_get_proc_name(&cursor, buffer, 100, &off) ? buffer : "?"; int status; // Unmangle C++ names: char* realname = abi::__cxa_demangle(name, 0, 0, &status); #if defined(__x86_64__) unw_word_t rip = 0; unw_word_t rsp = 0; unw_get_reg(&cursor, UNW_X86_64_RIP, &rip); unw_get_reg(&cursor, UNW_X86_64_RSP, &rsp); fprintf(file, " %i: %s (RIP=0x%" PRIx64 " RSP=0x%" PRIx64 ")\n", nframe, realname ? realname : name, (std::uint64_t) rip, (std::uint64_t) rsp); #else fprintf(file, " %i: %s\n", nframe, realname ? realname : name); #endif free(realname); ++nframe; } while(unw_step(&cursor)); }
/* TODO with some refactoring we might be able to re-use debug_symbol_name_cached() * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded * from build? */ static const char * symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip) { void *addr = (void *)(uintptr_t)pip->start_ip; char *name; mtx_lock(&symbols_mutex); if(!symbols_hash) symbols_hash = util_hash_table_create(hash_ptr, compare_ptr); name = util_hash_table_get(symbols_hash, addr); if(!name) { char procname[256]; unw_word_t off; int ret; ret = unw_get_proc_name(cursor, procname, sizeof(procname), &off); if (ret && ret != -UNW_ENOMEM) { procname[0] = '?'; procname[1] = 0; } if (asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "") == -1) name = "??"; util_hash_table_set(symbols_hash, addr, (void*)name); } mtx_unlock(&symbols_mutex); return name; }
void _dump_crash_report(unsigne pid) // shortened code from android's debuggerd // to get a backtrace on ARM { unw_addr_space_t as; struct UPT_info *ui; unw_cursor_t cursor; as = unw_create_addr_space(&_UPT_accessors, 0); ui = _UPT_create(pid); int ret = unw_init_remote(&cursor, as, ui); if (ret < 0) { PRINTF("WARNING: unw_init_remote() failed [pid %i]\n", pid); _UPT_destroy(ui); return; } PRINTF("DEBUG: backtrace of the remote process (pid %d) using libunwind-ptrace:\n", pid); do { unw_word_t ip, sp, offp; char buf[512]; unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_get_proc_name(&cursor, buf, sizeof (buf), &offp); PRINTF("DEBUG: ip: %10p, sp: %10p %s\n", (void*) ip, (void*) sp, buf); } while ((ret = unw_step (&cursor)) > 0); _UPT_destroy (ui); }
static void print_trace (void) { #ifdef HAVE_LIBUNWIND unw_context_t uc; unw_cursor_t cursor; guint stack_num = 0; if (!display_filter (DISPLAY_FLAG_BACKTRACE)) return; unw_getcontext (&uc); unw_init_local (&cursor, &uc); while (unw_step (&cursor) > 0) { gchar name[129]; unw_word_t off; int result; result = unw_get_proc_name (&cursor, name, sizeof (name) - 1, &off); if (result < 0 && result != UNW_ENOMEM) { g_print ("Error getting proc name\n"); break; } g_print ("#%d %s + [0x%08x]\n", stack_num++, name, (unsigned int)off); } }
int backtrace(void **trace, int size) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip; int n = 0; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); trace[n++] = (void *)ip; { char buf[256]; unw_get_proc_name(&cursor, buf, 256, &ip); if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) { goto darwin_sigtramp; } } } return n; darwin_sigtramp: /* darwin's bundled libunwind doesn't support signal trampoline */ { ucontext_t *uctx; /* get _sigtramp's ucontext_t and set values to cursor * http://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s * http://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s */ unw_get_reg(&cursor, UNW_X86_64_RBX, &ip); uctx = (ucontext_t *)ip; unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->__ss.__rax); unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->__ss.__rbx); unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->__ss.__rcx); unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->__ss.__rdx); unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->__ss.__rdi); unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->__ss.__rsi); unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->__ss.__rbp); unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->__ss.__rsp)); unw_set_reg(&cursor, UNW_X86_64_R8, uctx->uc_mcontext->__ss.__r8); unw_set_reg(&cursor, UNW_X86_64_R9, uctx->uc_mcontext->__ss.__r9); unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->__ss.__r10); unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->__ss.__r11); unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->__ss.__r12); unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->__ss.__r13); unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->__ss.__r14); unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->__ss.__r15); ip = *(unw_word_t*)uctx->uc_mcontext->__ss.__rsp; unw_set_reg(&cursor, UNW_REG_IP, ip); trace[n++] = (void *)uctx->uc_mcontext->__ss.__rip; trace[n++] = (void *)ip; } while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); trace[n++] = (void *)ip; } return n; }
void jffi_longjmp (jmp_buf env, int val) { extern int _jffi_longjmp_cont; unw_context_t uc; unw_cursor_t c; unw_word_t sp, ip, bp = 0; uintptr_t *wp = (uintptr_t *) env; int i, setjmp_frame; if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) { debug("failed to get context"); abort (); } #ifdef __x86_86__ # define UNW_REG_BP UNW_X86_64_RBP #else # define UNW_REG_BP UNW_X86_EBP #endif setjmp_frame = 0; do { char name[256]; unw_proc_info_t pi; unw_word_t off; if (unw_get_reg (&c, UNW_REG_BP, &bp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0) { abort(); } unw_get_proc_name(&c, name, sizeof(name), &off); unw_get_proc_info(&c, &pi); // debug("frame %s ip=%llx sp=%llx bp=%llx wp[RP]=%p wp[SP]=%p, pi.start_ip=%llx, pi.end_ip=%llx", // name, (long long) ip, (long long) sp, (long long) bp, (void *) wp[JB_RP], (void *) wp[JB_SP], // pi.start_ip, pi.end_ip); if (wp[JB_SP] > sp || wp[JB_RP] < pi.start_ip || wp[JB_RP] > pi.end_ip) continue; /* found the right frame: */ // debug("found frame to jump back to"); assert (UNW_NUM_EH_REGS >= 2); if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) &_jffi_longjmp_cont)) abort (); unw_resume (&c); // should not reach here abort (); } while (unw_step (&c) > 0); // debug("failed to find correct frame to jmp to"); }
void log_stack_trace(const char *msg) { #ifdef USE_UNWIND unw_context_t ctx; unw_cursor_t cur; unw_word_t ip, off; unsigned level; char sym[512], *dsym; int status; const char *log = stack_trace_log.empty() ? NULL : stack_trace_log.c_str(); #endif if (msg) ST_LOG(msg); ST_LOG("Unwound call stack:"); #ifdef USE_UNWIND if (unw_getcontext(&ctx) < 0) { ST_LOG("Failed to create unwind context"); return; } if (unw_init_local(&cur, &ctx) < 0) { ST_LOG("Failed to find the first unwind frame"); return; } for (level = 1; level < 999; ++level) { // 999 for safety int ret = unw_step(&cur); if (ret < 0) { ST_LOG("Failed to find the next frame"); return; } if (ret == 0) break; if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) { ST_LOG(" " << std::setw(4) << level); continue; } if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) { ST_LOG(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip); continue; } dsym = abi::__cxa_demangle(sym, NULL, NULL, &status); ST_LOG(" " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off); free(dsym); } #else std::stringstream ss; ss << el::base::debug::StackTrace(); std::vector<std::string> lines; std::string s = ss.str(); boost::split(lines, s, boost::is_any_of("\n")); for (const auto &line: lines) ST_LOG(line); #endif }
void AS_UTL_catchCrash(int sig_num, siginfo_t *info, void *ctx) { WRITE_STRING("\nFailed with '"); WRITE_STRING(strsignal(sig_num)); WRITE_STRING("'\n"); WRITE_STRING("\nBacktrace (mangled):\n\n"); unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; int depth = 0; unw_getcontext(&uc); // Get state unw_init_local(&cursor, &uc); // Initialize state cursor while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); unw_word_t off; char name[256]; if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0) { if (off) fprintf(stderr, "%02d <%s + 0x%lx> ip=%lx sp=%lx\n", depth, name, (long)off, ip, sp); else fprintf(stderr, "%02d <%s> ip=%lx sp=%lx\n", depth, name, ip, sp); } else { fprintf(stderr, "%02d <?> ip=%lx sp=%lx\n", depth, ip, sp); } depth++; } //WRITE_STRING("\nBacktrace (demangled):\n\n"); //WRITE_STRING("\nGDB:\n\n"); //AS_UTL_envokeGDB(); // Pass the signal through, only so a core file can get generated. struct sigaction sa; sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction(sig_num, &sa, NULL); raise(sig_num); }
void fill_in_backtrace(FaultData* fdp) { unw_context_t uc; unw_cursor_t c; int i, boff; memset(&uc, 0, sizeof(uc)); memset(&c, 0, sizeof(c)); if (unw_getcontext(&uc) < 0) { abort(); } if (unw_init_local(&c, &uc) < 0) { abort(); } // Skip the signal handler, and the signal trampoline for (i = 0; i < SKIP_FRAME_COUNT; i++) { if (unw_step(&c) <= 0) { break; } } memset(fdp->frame, 0, sizeof(fdp->frame)); fdp->frame_count = 0; boff = 0; do { char fn[256]; unw_word_t off, ip; Dl_info dli; unw_proc_info_t pi; unw_get_reg (&c, UNW_REG_IP, &ip); fdp->frame[fdp->frame_count].addr = (uintptr_t) ip; fdp->frame[fdp->frame_count].procname = (uintptr_t) &fdp->backtrace_buf[boff]; unw_get_proc_name(&c, (char *) fdp->frame[fdp->frame_count].procname, sizeof(fdp->backtrace_buf) - boff, &off); unw_get_proc_info(&c, &pi); boff += strlen((char *) fdp->frame[fdp->frame_count].procname) + 1; fdp->frame[fdp->frame_count].libname = (uintptr_t) &fdp->backtrace_buf[boff]; dladdr((void *)(uintptr_t) ip, &dli); strcpy((char *) (uintptr_t) fdp->frame[fdp->frame_count].libname, dli.dli_fname); boff += strlen((char *) fdp->frame[fdp->frame_count].libname) + 1; fdp->frame_count++; } while (unw_step(&c) > 0); }
int bt_backtrace(struct bt_data *btd, void** frames, char **buffer, int size, int resolve_name) { unw_cursor_t c; unw_word_t ip, off; int n = 0, ret; char buf[512] = "in "; if (size == 0) return 0; if ((ret = unw_init_remote(&c, btd->as, btd->ui)) < 0) { printf("unw_init_remote() failed.\n"); //debug(1, "bt_backtrace(): unw_init_remote() failed, ret=%d", ret); return -1; } do { if ((ret = unw_get_reg(&c, UNW_REG_IP, &ip)) < 0) { //debug(1, "bt_backtrace(): unw_get_reg() failed, ret=%d", ret); return -1; } frames[n] = (void*)ip; if (resolve_name) { char* ptr = buf; ret = unw_get_proc_name(&c, buf + 3, sizeof(buf) - 3, &off); if (ret < 0) { ptr = buf + 3; strcpy(ptr, "<undefined>"); } else if (off) { size_t len = strlen(buf); /* Reserve the last 64 bytes for the offset */ if (len >= sizeof(buf) - 64) len = sizeof(buf) - 64; sprintf(buf + len, "+0x%lx", (unsigned long)off); } buffer[n] = strdup(ptr); } n++; if ((ret = unw_step(&c)) < 0) { //debug(1, "bt_backtrace(): unw_step() failed, ret=%d", ret); return -1; } } while (ret > 0 && n < size); return n; }
G_GNUC_UNUSED static void print_ctx (MonoContext *ctx) { char name[256]; unw_word_t off, ip, sp; unw_proc_info_t pi; int res; unw_get_proc_name (&ctx->cursor, name, 256, &off); unw_get_proc_info(&ctx->cursor, &pi); res = unw_get_reg (&ctx->cursor, UNW_IA64_IP, &ip); g_assert (res == 0); res = unw_get_reg (&ctx->cursor, UNW_IA64_SP, &sp); g_assert (res == 0); printf ("%s:%lx [%lx-%lx] SP: %lx\n", name, ip - pi.start_ip, pi.start_ip, pi.end_ip, sp); }
void zmq::print_backtrace (void) { static zmq::mutex_t mtx; mtx.lock (); Dl_info dl_info; unw_cursor_t cursor; unw_context_t ctx; unsigned frame_n = 0; unw_getcontext (&ctx); unw_init_local (&cursor, &ctx); while (unw_step (&cursor) > 0) { unw_word_t offset; unw_proc_info_t p_info; const char *file_name; char *demangled_name; char func_name[256] = ""; void *addr; int rc; if (unw_get_proc_info (&cursor, &p_info)) break; addr = (void *)(p_info.start_ip + offset); if (dladdr (addr, &dl_info) && dl_info.dli_fname) file_name = dl_info.dli_fname; else file_name = "?"; rc = unw_get_proc_name (&cursor, func_name, 256, &offset); if (rc == -UNW_ENOINFO) strcpy(func_name, "?"); demangled_name = abi::__cxa_demangle (func_name, NULL, NULL, &rc); printf ("#%u %p in %s (%s+0x%lx)\n", frame_n++, addr, file_name, rc ? func_name : demangled_name, (unsigned long) offset); free (demangled_name); } puts (""); fflush (stdout); mtx.unlock (); }
void do_backtrace() { unw_cursor_t cursor; unw_context_t context; int ret; ret = unw_getcontext(&context); if(ret != 0) { printf("[do_backtrace] unw_getcontext returned %d.\n", ret); } ret = unw_init_local(&cursor, &context); if(ret != 0) { printf("[do_backtrace] unw_init_local returned %d.\n", ret); } do { unw_word_t offset, pc; char fname[64]; unw_get_reg(&cursor, UNW_REG_IP, &pc); fname[0]='\0'; (void) unw_get_proc_name(&cursor, fname, sizeof(fname), &offset); printf("%p : (%s+0x%x) [%p]\n", (void*)pc, fname, (unsigned int)offset, (void*)pc); } while(unw_step(&cursor) > 0); }
void backtrace() { unw_cursor_t cursor; unw_context_t context; unw_getcontext( & context); unw_init_local( & cursor, & context); while ( 0 < unw_step( & cursor) ) { unw_word_t offset, pc; unw_get_reg( & cursor, UNW_REG_IP, & pc); if ( 0 == pc) { break; } std::cout << "0x" << pc << ":"; char sym[256]; if ( 0 == unw_get_proc_name( & cursor, sym, sizeof( sym), & offset) ) { std::cout << " (" << sym << "+0x" << offset << ")" << std::endl; } else { std::cout << " -- error: unable to obtain symbol name for this frame" << std::endl; } } }
int bar(const char** list) { char functionName[64]; unw_cursor_t cursor; unw_context_t uc; unw_word_t offset; int index = 0; unw_getcontext(&uc); unw_init_local(&cursor, &uc); do { unw_get_proc_name(&cursor, functionName, 64, &offset); //fprintf(stderr, "in function: %s\n", functionName); if ( (list[index] != NULL) && (strcmp(functionName, list[index]) != 0) ) { //fprintf(stderr, "unexpected function: %s\n", functionName); exit(1); } ++index; } while (unw_step(&cursor) > 0); return 0; }
static void print_trace (void) { unw_context_t uc; unw_cursor_t cursor; guint stack_num = 0; unw_getcontext (&uc); unw_init_local (&cursor, &uc); while (unw_step (&cursor) > 0 && stack_num < 32) { gchar name[256]; unw_word_t off; if (unw_get_proc_name (&cursor, name, 255, &off) < 0) strcpy (name, "<no name>"); g_print ("#%d [%s+0x%x]\n", stack_num++, name, (unsigned int)off); } }
tt_result_t tt_backtrace_ntv(IN tt_buf_t *buf, IN OPT const tt_char_t *prefix, IN OPT const tt_char_t *suffix) { tt_u32_t plen, slen, i; unw_context_t ctx; unw_cursor_t cur; if (prefix == NULL) { prefix = ""; } plen = (tt_u32_t)tt_strlen(prefix); if (suffix == NULL) { suffix = ""; } slen = (tt_u32_t)tt_strlen(suffix); if ((unw_getcontext(&ctx) != 0) || (unw_init_local(&cur, &ctx) != 0)) { return TT_FAIL; } i = 0; while (unw_step(&cur) > 0) { unw_word_t ip, off; char name[128] = {0}; if ((unw_get_reg(&cur, UNW_REG_IP, &ip) != 0) || (unw_get_proc_name(&cur, name, sizeof(name) - 1, &off)) != 0) { break; } TT_DO_G(done, tt_buf_put(buf, (tt_u8_t *)prefix, plen)); TT_DO_G(done, tt_buf_putf(buf, "#%d <%p> in %s(+0x%x)", i++, ip, name, off)); TT_DO_G(done, tt_buf_put(buf, (tt_u8_t *)suffix, slen)); } done: return TT_SUCCESS; }
void show_backtrace(void) { char name[256]; unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp, offp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { char file[256]; int line = 0; name[0] = '\0'; unw_get_proc_name(&cursor, name, 256, &offp); unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); //printf ("%s ip = %lx, sp = %lx\n", name, (long) ip, (long) sp); getFileAndLine((long)ip, file, 256, &line); printf("%s in file %s line %d\n", name, file, line); } }
static void print_backtrace(FILE *f) { unw_cursor_t cursor; unw_context_t ctx; unw_word_t ip; unw_getcontext(&ctx); unw_init_local(&cursor, &ctx); fprintf(f, " called by:\n"); while (unw_step(&cursor) > 0) { Dl_info info; unw_get_reg(&cursor, UNW_REG_IP, &ip); if (ip == 0) break; dladdr(reinterpret_cast<void *>(ip), &info); if (info.dli_sname) { fprintf(f, " 0x%zx %s+0x%zx (%s)\n", static_cast<uintptr_t>(ip), info.dli_sname, static_cast<uintptr_t>(ip) - reinterpret_cast<uintptr_t>(info.dli_saddr), info.dli_fname); continue; } // If dladdr() failed, try libunwind unw_word_t offsetInFn; char fnName[MAX_SYMBOL_LENGTH]; if (!unw_get_proc_name(&cursor, fnName, MAX_SYMBOL_LENGTH, &offsetInFn)) { fprintf(f, " 0x%zx %s+0x%zx (%s)\n", static_cast<uintptr_t>(ip), fnName, offsetInFn, info.dli_fname); continue; } else fprintf(f, " 0x%zx\n", static_cast<uintptr_t>(ip)); } }
static void handler(int sig) { unw_cursor_t cursor; unw_context_t uc; unw_word_t offp; char buf[128]; int i = 0; fprintf(stderr, "Stack trace:\n"); unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { int ret = unw_get_proc_name(&cursor, buf, sizeof buf/sizeof buf[0], &offp); if (ret == 0) { printf("%d\t%s + %ld\n", i, buf, offp); } else { printf("%d\t???\n", i); } i++; } exit(EXIT_FAILURE); }
int main(int argc , char **argv) { unw_addr_space_t as; unw_cursor_t cursor; struct UCD_info *ui; unw_word_t ip, sp, off; char buf[512], name[256]; int line; int depth = 0; int ret; bool pybt_done = false; #define TEST_NAME_LEN 256 install_signal_handler(); if (argc != 3) { fprintf(stderr, "Usage: %s <binary> <corefile>", argv[0]); exit(1); } as = unw_create_addr_space(&_UCD_accessors, 0); if (!as) { fprintf(stderr, "unw_create_addr_space() failed"); exit(1); } ui = _UCD_create(argv[2]); if (!ui) { fprintf(stderr,"_UCD_create('%s') failed", argv[1]); exit(1); } ret = unw_init_remote(&cursor, as, ui); if (ret < 0) { fprintf(stderr,"unw_init_remote() failed: ret=%d\n", ret); exit(1); } read_elfnotes(argv[2], ui); while (unw_step(&cursor) > 0) { // Avoid going too deep if (depth++ > MAX_STACK_DEPTH) { exit(1); } unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); if (unw_get_proc_name(&cursor, name, sizeof (name), &off) == 0) { if (off) { snprintf(buf, sizeof (buf), "<%s+0x%lx>", name, (long) off); } else { snprintf(buf, sizeof (buf), "<%s>", name); } } /* Check for Python backtrace */ if (!strncmp(name,"PyEval_EvalFrameEx", 18) && !pybt_done) { pybacktrace(cursor); pybt_done = true; } rw_get_file_and_line((long)ip, name, argv[1], 256, &line); printf("%016lx %s <%s:%d> (sp=%016lx)\n", (long) ip, buf, basename(name), line, (long) sp); } _UCD_destroy(ui); unw_destroy_addr_space(as); return 0; }
static void chpl_stack_unwind(void){ // This is just a prototype using libunwind unw_cursor_t cursor; unw_context_t uc; unw_word_t wordValue; char buffer[128]; unsigned int line; #ifdef __linux__ unw_proc_info_t info; // Get the exec path and name for the precise line printing char process_name[128]; line = readlink("/proc/self/exe", process_name, sizeof(process_name)); // It unlikely to happen but this means that the process name is too big // for our buffer. In this case, we truncate the name if(line == sizeof(process_name)) line = sizeof(process_name)-1; process_name[line] = '\0'; #endif // Check if we need to print the stack trace (default = yes) if(! chpl_get_rt_env_bool("UNWIND", true)) { return; } line = 0; unw_getcontext(&uc); unw_init_local(&cursor, &uc); if(chpl_sizeSymTable > 0) fprintf(stderr,"Stacktrace\n\n"); // This loop does the effective stack unwind, see libunwind documentation while (unw_step(&cursor) > 0) { unw_get_proc_name(&cursor, buffer, sizeof(buffer), &wordValue); // Since this stack trace is printed out a program exit, we do not believe // it is performance sensitive. Additionally, this initial implementation // favors simplicity over performance. // // If it becomes necessary to improve performance, this code could use be // faster using one of these two strategies: // 1) Use a hashtable or map to find entries in chpl_funSymTable, or // 2) Emit chpl_funSymTable in sorted order and use binary search on it for(int t = 0; t < chpl_sizeSymTable; t+=2 ){ if (!strcmp(chpl_funSymTable[t], buffer)){ #ifdef __linux__ // Maybe we can get a more precise line number unw_get_proc_info(&cursor, &info); line = chpl_unwind_getLineNum(process_name, (void *)(info.start_ip + wordValue)); // We wasn't able to obtain the line number, let's use the procedure // line number if(line == 0) line = chpl_filenumSymTable[t+1]; #else line = chpl_filenumSymTable[t+1]; #endif fprintf(stderr,"%s() at %s:%d\n", chpl_funSymTable[t+1], chpl_lookupFilename(chpl_filenumSymTable[t]), line); break; } } } }
int main(int argc UNUSED, char **argv) { unw_addr_space_t as; struct UCD_info *ui; unw_cursor_t c; int ret; #define TEST_FRAMES 4 #define TEST_NAME_LEN 32 int testcase = 0; int test_cur = 0; long test_start_ips[TEST_FRAMES]; char test_names[TEST_FRAMES][TEST_NAME_LEN]; install_sigsegv_handler(); const char *progname = strrchr(argv[0], '/'); if (progname) progname++; else progname = argv[0]; if (!argv[1]) error_msg_and_die("Usage: %s COREDUMP [VADDR:BINARY_FILE]...", progname); msg_prefix = progname; as = unw_create_addr_space(&_UCD_accessors, 0); if (!as) error_msg_and_die("unw_create_addr_space() failed"); ui = _UCD_create(argv[1]); if (!ui) error_msg_and_die("_UCD_create('%s') failed", argv[1]); ret = unw_init_remote(&c, as, ui); if (ret < 0) error_msg_and_die("unw_init_remote() failed: ret=%d\n", ret); argv += 2; /* Enable checks for the crasher test program? */ if (*argv && !strcmp(*argv, "-testcase")) { testcase = 1; logmode = LOGMODE_NONE; argv++; } while (*argv) { char *colon; unsigned long vaddr = strtoul(*argv, &colon, 16); if (*colon != ':') error_msg_and_die("Bad format: '%s'", *argv); if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0) error_msg_and_die("Can't add backing file '%s'", colon + 1); argv++; } for (;;) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) error_msg_and_die("unw_get_reg(UNW_REG_IP) failed: ret=%d\n", ret); unw_proc_info_t pi; ret = unw_get_proc_info(&c, &pi); if (ret < 0) error_msg_and_die("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret); if (!testcase) printf("\tip=0x%08lx proc=%08lx-%08lx handler=0x%08lx lsda=0x%08lx\n", (long) ip, (long) pi.start_ip, (long) pi.end_ip, (long) pi.handler, (long) pi.lsda); if (testcase && test_cur < TEST_FRAMES) { unw_word_t off; test_start_ips[test_cur] = (long) pi.start_ip; if (unw_get_proc_name(&c, test_names[test_cur], sizeof(test_names[0]), &off) != 0) { test_names[test_cur][0] = '\0'; } test_cur++; } log("step"); ret = unw_step(&c); log("step done:%d", ret); if (ret < 0) error_msg_and_die("FAILURE: unw_step() returned %d", ret); if (ret == 0) break; } log("stepping ended"); /* Check that the second and third frames are equal, but distinct of the * others */ if (testcase && (test_cur != 4 || test_start_ips[1] != test_start_ips[2] || test_start_ips[0] == test_start_ips[1] || test_start_ips[2] == test_start_ips[3] ) ) { fprintf(stderr, "FAILURE: start IPs incorrect\n"); return -1; } if (testcase && ( strcmp(test_names[0], "a") || strcmp(test_names[1], "b") || strcmp(test_names[2], "b") || strcmp(test_names[3], "main") ) ) { fprintf(stderr, "FAILURE: procedure names are missing/incorrect\n"); return -1; } _UCD_destroy(ui); unw_destroy_addr_space(as); return 0; }
static struct frame* unwind_thread(Dwfl *dwfl, unw_addr_space_t as, struct UCD_info *ui, int thread_no, struct expr_context *ctx) { info("thread %d:", thread_no); int i, ret; unw_cursor_t c, c_cfa; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); fail_if(ret < 0, "unw_init_remote"); ret = unw_init_remote(&c_cfa, as, ui); fail_if(ret < 0, "unw_init_remote"); struct frame *head = NULL, *tail = NULL; /* infinite loop insurance */ int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); fail_if(ret < 0, "unw_get_reg"); if (ip == 0) break; unw_word_t off; char funcname[10*1024]; funcname[0] = '\0'; ret = unw_get_proc_name(&c, funcname, sizeof(funcname)-1, &off); if (ret < 0) { warn("unw_get_proc_name failed for IP %lx", (unsigned long)ip); } info("\t%llx %s", (unsigned long long)ip, funcname); /* According to spec[1], CFA is RSP of the previous frame. However, * libunwind returns CFA = RSP of the current frame. So we need to keep * track of the previous (i.e. next to be unwound) frame. * * [1] System V Application Binary Interface AMD64 Architecture * Processor Supplement * http://www.x86-64.org/documentation/abi.pdf */ ctx->cfa = 0; ret = unw_step(&c_cfa); if (ret > 0) { unw_word_t cfa; ret = unw_get_reg(&c_cfa, UNW_X86_64_CFA, &cfa); if (ret == 0) { ctx->cfa = (Dwarf_Addr)cfa; } } /* find compilation unit owning the IP */ Dwarf_Die *cu = dwfl_addrdie(dwfl, (Dwarf_Addr)ip, &(ctx->bias)); if (!cu) { warn("\t\tcannot find CU for ip %lx", (unsigned long)ip); goto synth_frame; } if (!supported_language(cu)) { warn("\t\tunsupported CU language"); goto synth_frame; } /* needed by child_variables */ Dwarf_Files *files; ret = dwarf_getsrcfiles(cu, &files, NULL); fail_if(ret == -1, "dwarf_getsrcfiles"); /* dwarf expression evaluation needs register values */ ctx->curs = &c; ctx->ip = (Dwarf_Addr)ip; /* TODO: subtract 1 as this is return address? */ /* TODO: we have CU - fall back to CU name if subprogram not found */ /* Following code deals with inlined functions, which do not have their * own stack frame. It is somewhat ugly due to two constraints: * - we want to produce at least one frame even if analyze_scopes * fails * - we may want to further process the frame that is returned the * last, i.e. the one that belongs to the non-inlined function */ Dwarf_Die *scopes; int nscopes = dwarf_getscopes(cu, (Dwarf_Addr)ip, &scopes); struct frame *frame = analyze_scopes(&scopes, &nscopes, ctx, files, false); if (frame == NULL) { goto synth_frame; } struct frame *last_frame; while (frame) { list_append(head, tail, frame); last_frame = frame; frame = analyze_scopes(&scopes, &nscopes, ctx, files, true); } frame = last_frame; /* frame->ip = (uint64_t)ip; */ goto next; synth_frame: /* synthesize frame even though we have no other information except * that it's there */ frame = xalloc(sizeof(*frame)); list_append(head, tail, frame); /* frame->ip = (uint64_t)ip; */ next: ret = unw_step(&c); fail_if(ret < 0, "unw_step"); if (ret == 0) break; } return head; }
static void print_stack_trace(pid_t pid, int * count) { void * pinfo = NULL; unw_addr_space_t aspace = NULL; unw_cursor_t cursor; unw_word_t ip, sp; char nbuf[256]; unw_word_t off; int ret; if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { fprintf(stderr, "Failed to attach to process %llu: %s\n", (unsigned long long)pid, strerror(errno)); return; } /* Wait until the attach is complete. */ waitpid(pid, NULL, 0); if (((pinfo = _UPT_create(pid)) == NULL) || ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) { /* Probably out of memory. */ fprintf(stderr, "Unable to initialize stack unwind for process %llu\n", (unsigned long long)pid); goto cleanup; } if ((ret = unw_init_remote(&cursor, aspace, pinfo))) { fprintf(stderr, "Unable to unwind stack for process %llu: %s\n", (unsigned long long)pid, unw_strerror(ret)); goto cleanup; } if (*count > 0) { printf("\n"); } if (procname(pid, nbuf, sizeof(nbuf))) { printf("Stack trace for process %llu (%s):\n", (unsigned long long)pid, nbuf); } else { printf("Stack trace for process %llu:\n", (unsigned long long)pid); } while (unw_step(&cursor) > 0) { ip = sp = off = 0; unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off); if (ret != 0 && ret != -UNW_ENOMEM) { snprintf(nbuf, sizeof(nbuf), "<unknown symbol>"); } printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n", nbuf, (long long)off, (long long)ip, (long long)sp); } (*count)++; cleanup: if (aspace) { unw_destroy_addr_space(aspace); } if (pinfo) { _UPT_destroy(pinfo); } ptrace(PTRACE_DETACH, pid, NULL, NULL); }