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); }
unw_cursor_t UnwindContext::cursor() { unw_cursor_t cursor; if (process_ == nullptr || addressSpace_ == nullptr || unw_init_remote(&cursor, process_->unw_addr_space, this) != 0) xbt_die("UnwindContext not initialized"); return cursor; }
bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (context == nullptr) { BACK_LOGW("The context is needed for offline backtracing."); return false; } context_ = context; unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0); unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space, this); if (ret != 0) { BACK_LOGW("unw_init_remote failed %d", ret); unw_destroy_addr_space(addr_space); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames + 1); backtrace_frame_data_t* frame = &frames_[num_frames]; frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_[num_frames - 1]; prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); FillInMap(frame->pc, &frame->map); num_frames++; } else { num_ignore_frames--; } ret = unw_step(&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); unw_destroy_addr_space(addr_space); context_ = nullptr; return true; }
size_t arch_unwindStack(pid_t pid, funcs_t * funcs) { size_t num_frames = 0, mapsCnt = 0; procMap_t *mapsList = arch_parsePidMaps(pid, &mapsCnt); defer { free(mapsList); }; unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER); if (!as) { LOG_E("[pid='%d'] unw_create_addr_space failed", pid); return num_frames; } defer { unw_destroy_addr_space(as); }; void *ui = _UPT_create(pid); if (ui == NULL) { LOG_E("[pid='%d'] _UPT_create failed", pid); return num_frames; } defer { _UPT_destroy(ui); }; unw_cursor_t c; int ret = unw_init_remote(&c, as, ui); if (ret < 0) { LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]); return num_frames; } for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) { unw_word_t ip; char *mapName = NULL; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) { LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]); funcs[num_frames].pc = 0; } else { funcs[num_frames].pc = (void *)ip; } if (mapsCnt > 0 && (mapName = arch_searchMaps(ip, mapsCnt, mapsList)) != NULL) { memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName)); } else { strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName)); } } return num_frames; }
int main(void) { unw_addr_space_t addr_space; addr_space = unw_create_addr_space(&accessors, 0); if (addr_space) return 0; unw_init_remote(NULL, addr_space, NULL); dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); return 0; }
bool get_backtrace(ptrace_context *ctx) { trace_stack *pstk = &ctx->stk; unw_cursor_t cursor; pstk->depth = 0; if (unw_init_remote(&cursor, ctx->addr_space, ctx->unwind_rctx)) return false; do { unw_get_reg(&cursor, UNW_REG_IP, &pstk->ips[pstk->depth++]); } while (pstk->depth < MAX_STACK_DEPTH && unw_step(&cursor) > 0); return true; }
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; }
/*++ Function: PAL_VirtualUnwindOutOfProc Unwind the stack given the context for a "remote" target using the provided read memory callback. Assumes the IP is in the module of the base address provided (coreclr). Parameters: context - the start context in the target contextPointers - the context of the next frame baseAddress - base address of the module to find the unwind info readMemoryCallback - reads memory from the target --*/ BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback) { unw_addr_space_t addrSpace = 0; unw_cursor_t cursor; libunwindInfo info; BOOL result = FALSE; int st; info.BaseAddress = baseAddress; info.Context = context; info.ReadMemory = readMemoryCallback; addrSpace = unw_create_addr_space(&unwind_accessors, 0); st = unw_init_remote(&cursor, addrSpace, &info); if (st < 0) { result = FALSE; goto exit; } st = unw_step(&cursor); if (st < 0) { result = FALSE; goto exit; } UnwindContextToWinContext(&cursor, context); if (contextPointers != NULL) { GetContextPointers(&cursor, NULL, contextPointers); } result = TRUE; exit: if (addrSpace != 0) { unw_destroy_addr_space(addrSpace); } return result; }
int test_generic (void) { if (verbose) printf (__FILE__": funcs[0]=%p\n", funcs[0]); #ifndef UNW_REMOTE_ONLY { unw_context_t uc; unw_cursor_t c; unw_getcontext (&uc); unw_init_local (&c, &uc); unw_init_remote (&c, unw_local_addr_space, &uc); return unw_step (&c); } #else return 0; #endif }
BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, DWORD pid, ReadMemoryWordCallback readMemCallback) { // This function can be executed only by one thread at a time. // The reason for this is that we need to pass context and read mem function to libunwind callbacks // but "arg" is already used by the pointer returned from _UPT_create(). // So we resort to using global variables and a lock. struct Lock { CRITICAL_SECTION cs; Lock() { // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc) InitializeCriticalSection(&cs); } }; struct LockHolder { CRITICAL_SECTION *cs; LockHolder(CRITICAL_SECTION *cs) { this->cs = cs; EnterCriticalSection(cs); } ~LockHolder() { LeaveCriticalSection(cs); cs = NULL; } }; static Lock lock; LockHolder lockHolder(&lock.cs); int st; unw_context_t unwContext; unw_cursor_t cursor; unw_addr_space_t addrSpace = 0; void *libunwindUptPtr = NULL; BOOL result = FALSE; LibunwindCallbacksInfo.Context = context; LibunwindCallbacksInfo.readMemCallback = readMemCallback; WinContextToUnwindContext(context, &unwContext); addrSpace = unw_create_addr_space(&unwind_accessors, 0); libunwindUptPtr = _UPT_create(pid); st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr); if (st < 0) { result = FALSE; goto Exit; } st = unw_step(&cursor); if (st < 0) { result = FALSE; goto Exit; } UnwindContextToWinContext(&cursor, context); if (contextPointers != NULL) { GetContextPointers(&cursor, &unwContext, contextPointers); } result = TRUE; Exit: if (libunwindUptPtr != nullptr) { _UPT_destroy(libunwindUptPtr); } if (addrSpace != 0) { unw_destroy_addr_space(addrSpace); } return result; }
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); }
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; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); return false; } addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); if (NULL == map) { BACK_LOGW("GetMap before unwinding failed."); return false; } unw_map_set(addr_space_, map->GetMapCursor()); upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } unw_cursor_t cursor; if(num_ignore_frames==0xdeaddead) { cursor.opaque[0]=0xdeaddead; //add for tell libunwind to unwind for kernel unwind userspace backtrace,lhd BACK_LOGW(" K2U_bt call into UnwindPtrace::Unwind."); num_ignore_frames=0; } int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } std::vector<backtrace_frame_data_t>* frames = GetFrames(); frames->reserve(MAX_BACKTRACE_FRAMES); size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames->resize(num_frames+1); backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames->at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); frame->map = FindMap(frame->pc); num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
void output_right(enum tof type, struct process *proc, struct library_symbol *libsym, struct timedelta *spent) { assert(! options.summary); struct prototype *func = lookup_symbol_prototype(proc, libsym); if (func == NULL) return; if (current_proc != NULL && (current_proc != proc || current_depth != proc->callstack_depth)) { fprintf(options.output, " <unfinished ...>\n"); current_proc = NULL; } if (current_proc != proc) { begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1); #ifdef USE_DEMANGLE current_column += fprintf(options.output, "<... %s resumed> ", options.demangle ? my_demangle(libsym->name) : libsym->name); #else current_column += fprintf(options.output, "<... %s resumed> ", libsym->name); #endif } struct callstack_element *stel = &proc->callstack[proc->callstack_depth - 1]; struct fetch_context *context = stel->fetch_context; /* Fetch & enter into dictionary the retval first, so that * other values can use it in expressions. */ struct value retval; bool own_retval = false; if (context != NULL) { value_init(&retval, proc, NULL, func->return_info, 0); own_retval = true; if (fetch_retval(context, type, proc, func->return_info, &retval) < 0) value_set_type(&retval, NULL, 0); else if (stel->arguments != NULL && val_dict_push_named(stel->arguments, &retval, "retval", 0) == 0) own_retval = false; } if (stel->arguments != NULL) output_params(stel->arguments, stel->out.params_left, val_dict_count(stel->arguments), &stel->out.need_delim); current_column += fprintf(options.output, ") "); tabto(options.align - 1); fprintf(options.output, "= "); if (context != NULL && retval.type != NULL) { struct format_argument_data data = { &retval, stel->arguments }; format_argument_cb(options.output, &data); } if (own_retval) value_destroy(&retval); if (opt_T) { assert(spent != NULL); fprintf(options.output, " <%lu.%06d>", (unsigned long) spent->tm.tv_sec, (int) spent->tm.tv_usec); } fprintf(options.output, "\n"); #if defined(HAVE_LIBUNWIND) if (options.bt_depth > 0 && proc->unwind_priv != NULL && proc->unwind_as != NULL) { unw_cursor_t cursor; arch_addr_t ip, function_offset; struct library *lib = NULL; int unwind_depth = options.bt_depth; char fn_name[100]; const char *lib_name; size_t distance; /* Verify that we can safely cast arch_addr_t* to * unw_word_t*. */ (void)sizeof(char[1 - 2*(sizeof(unw_word_t) != sizeof(arch_addr_t))]); unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv); while (unwind_depth) { int rc = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip); if (rc < 0) { fprintf(options.output, " > Error: %s\n", unw_strerror(rc)); goto cont; } /* We are looking for the library with the base address * closest to the current ip. */ lib_name = "unmapped_area"; distance = (size_t) -1; lib = proc->libraries; while (lib != NULL) { /* N.B.: Assumes sizeof(size_t) == * sizeof(arch_addr_t). * Keyword: double cast. */ if ((ip >= lib->base) && ((size_t)(ip - lib->base) < distance)) { distance = ip - lib->base; lib_name = lib->pathname; } lib = lib->next; } rc = unw_get_proc_name(&cursor, fn_name, sizeof(fn_name), (unw_word_t *) &function_offset); if (rc == 0 || rc == -UNW_ENOMEM) fprintf(options.output, " > %s(%s+%p) [%p]\n", lib_name, fn_name, function_offset, ip); else fprintf(options.output, " > %s(??\?) [%p]\n", lib_name, ip); cont: if (unw_step(&cursor) <= 0) break; unwind_depth--; } fprintf(options.output, "\n"); } #endif /* defined(HAVE_LIBUNWIND) */ #if defined(HAVE_LIBDW) if (options.bt_depth > 0 && proc->leader->dwfl != NULL) { int frames = options.bt_depth; if (dwfl_getthread_frames(proc->leader->dwfl, proc->pid, frame_callback, &frames) < 0) { // Only print an error if we couldn't show anything. // Otherwise just show there might be more... if (frames == options.bt_depth) fprintf(stderr, "dwfl_getthread_frames tid %d: %s\n", proc->pid, dwfl_errmsg(-1)); else fprintf(options.output, " > [...]\n"); } fprintf(options.output, "\n"); } #endif /* defined(HAVE_LIBDW) */ current_proc = NULL; current_column = 0; }
bool InitFrameCallback::execute_real() { ret = unw_init_remote(cp_, as_, arg_); return true; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (GetMap() == nullptr) { // Without a map object, we can't do anything. return false; } if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); return false; } addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } UnwindMap* map = static_cast<UnwindMap*>(GetMap()); unw_map_set(addr_space_, map->GetMapCursor()); upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); FillInMap(frame->pc, &frame->map); num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
static struct sr_core_thread * unwind_thread(struct UCD_info *ui, unw_addr_space_t as, Dwfl *dwfl, int thread_no, char **error_msg) { int ret; unw_cursor_t c; struct sr_core_frame *trace = NULL; _UCD_select_thread(ui, thread_no); ret = unw_init_remote(&c, as, ui); if (ret < 0) { set_error("unw_init_remote failed: %s", unw_strerror(ret)); return NULL; } int count = 1000; while (--count > 0) { unw_word_t ip; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) warn("unw_get_reg(UNW_REG_IP) failed: %s", unw_strerror(ret)); /* Seen this happen when unwinding thread that did not start * in main(). */ if (ip == 0) break; struct sr_core_frame *entry = resolve_frame(dwfl, ip, false); if (!entry->function_name) { size_t funcname_len = 512; char *funcname = sr_malloc(funcname_len); if (unw_get_proc_name(&c, funcname, funcname_len, NULL) == 0) entry->function_name = funcname; else free(funcname); } trace = sr_core_frame_append(trace, entry); /* printf("%s 0x%llx %s %s -\n", (ip_seg && ip_seg->build_id) ? ip_seg->build_id : "-", (unsigned long long)(ip_seg ? ip - ip_seg->vaddr : ip), (entry->symbol ? entry->symbol : "-"), (ip_seg && ip_seg->filename) ? ip_seg->filename : "-"); */ /* Do not unwind below __libc_start_main. */ if (0 == sr_strcmp0(entry->function_name, "__libc_start_main")) break; ret = unw_step(&c); if (ret == 0) break; if (ret < 0) { warn("unw_step failed: %s", unw_strerror(ret)); break; } } if (error_msg && !*error_msg && !trace) { set_error("No frames found for thread %d", thread_no); } struct sr_core_thread *thread = sr_core_thread_new(); thread->frames = trace; return thread; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames) { addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); if (!addr_space_) { BACK_LOGW("unw_create_addr_space failed."); return false; } upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid())); if (!upt_info_) { BACK_LOGW("Failed to create upt info."); return false; } backtrace_t* backtrace = GetBacktraceData(); backtrace->num_frames = 0; unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); return false; } do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { size_t num_frames = backtrace->num_frames; backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; frame->map_name = NULL; frame->map_offset = 0; frame->func_name = NULL; frame->func_offset = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; prev->stack_size = frame->sp - prev->sp; } std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); if (!func_name.empty()) { frame->func_name = strdup(func_name.c_str()); } uintptr_t map_start; frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); if (frame->map_name) { frame->map_offset = frame->pc - map_start; } backtrace->num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); return true; }
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 int backtrace_thread(unw_accessors_t *accessors, void *arg) { unw_addr_space_t addr_space; unw_cursor_t cursor; int rc = 0, n = 0; if ((addr_space = unw_create_addr_space(accessors, 0)) == NULL) { fprintf(stderr, "failed to create address space for unwinding\n"); return -1; } if ((rc = unw_init_remote(&cursor, addr_space, arg)) < 0) { fprintf(stderr, "failed to init cursor for unwinding: rc=%d\n", rc); return -1; } do { unw_word_t ip, sp = -1, off; static char buf[512]; size_t len; if ((rc = unw_get_reg(&cursor, UNW_REG_IP, &ip)) < 0) { fprintf(stderr, "failed to get IP: rc=%d\n", rc); break; } buf[0] = '\0'; unw_get_proc_name(&cursor, buf, sizeof(buf), &off); if (buf[0] == '\0') { buf[0] = '?'; buf[1] = '\0'; len = 1; } else { len = strlen(buf); } if (len >= sizeof(buf) - 32) len = sizeof(buf) - 32; if (!ip) break; if (off) { sprintf(buf + len, " + 0x%lx", (unsigned long)off); } if (!opt_show_rsp) { printf(" %016lx %s\n", (long)ip, buf); } else { unw_get_reg(&cursor, UNW_REG_SP, &sp); printf(" %016lx %016lx %s\n", (long)ip, (long)sp, buf); } if ((rc = unw_step(&cursor)) < 0) { if (!opt_show_rsp) printf(" ???????????????? <stack breaks here>\n"); else printf(" ???????????????? ???????????????? <stack breaks here>\n"); if (opt_verbose) { fprintf(stderr, "unwind step failed: n=%d rc=%d\n", n, rc); } break; } if (++n == 64 && rc) { puts(" ???????????????? <stack is too long>\n"); break; } } while (rc > 0); unw_destroy_addr_space(addr_space); return rc; }
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; }
/* Benefit from maps being sorted by address */ if (addr < mapsList[i].start) { break; } } return NULL; } #ifndef __ANDROID__ size_t arch_unwindStack(pid_t pid, funcs_t * funcs) { size_t num_frames = 0, mapsCnt = 0; procMap_t *mapsList = arch_parsePidMaps(pid, &mapsCnt); defer { free(mapsList); }; unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER); if (!as) { LOG_E("[pid='%d'] unw_create_addr_space failed", pid); return num_frames; } defer { unw_destroy_addr_space(as); }; void *ui = _UPT_create(pid); if (ui == NULL) { LOG_E("[pid='%d'] _UPT_create failed", pid); return num_frames; } defer { _UPT_destroy(ui); }; unw_cursor_t c; int ret = unw_init_remote(&c, as, ui); if (ret < 0) { LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]); return num_frames; } for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) { unw_word_t ip; char *mapName = NULL; ret = unw_get_reg(&c, UNW_REG_IP, &ip); if (ret < 0) { LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]); funcs[num_frames].pc = 0; } else { funcs[num_frames].pc = (void *)ip; } if (mapsCnt > 0 && (mapName = arch_searchMaps(ip, mapsCnt, mapsList)) != NULL) { memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName)); } else { strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName)); } } return num_frames; } #else /* !defined(__ANDROID__) */ size_t arch_unwindStack(pid_t pid, funcs_t * funcs) { size_t num_frames = 0, mapsCnt = 0; procMap_t *mapsList = arch_parsePidMaps(pid, &mapsCnt); defer { free(mapsList); } unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER); if (!as) { LOG_E("[pid='%d'] unw_create_addr_space failed", pid); return num_frames; } defer { unw_destroy_addr_space(as); }; struct UPT_info *ui = (struct UPT_info *)_UPT_create(pid); if (ui == NULL) { LOG_E("[pid='%d'] _UPT_create failed", pid); return num_frames; } defer { _UPT_destroy(ui); }; unw_cursor_t cursor; int ret = unw_init_remote(&cursor, as, ui); if (ret < 0) { LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]); return num_frames; } do { char *mapName = NULL; unw_word_t pc = 0, offset = 0; char buf[_HF_FUNC_NAME_SZ] = { 0 }; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]); // We don't want to try to extract info from an arbitrary IP // TODO: Maybe abort completely (goto out)) goto skip_frame_info; } unw_proc_info_t frameInfo; ret = unw_get_proc_info(&cursor, &frameInfo); if (ret < 0) { LOG_D("[pid='%d'] [%zd] unw_get_proc_info (%s)", pid, num_frames, UNW_ER[-ret]); // Not safe to keep parsing frameInfo goto skip_frame_info; } ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset); if (ret < 0) { LOG_D("[pid='%d'] [%zd] unw_get_proc_name() failed (%s)", pid, num_frames, UNW_ER[-ret]); buf[0] = '\0'; } skip_frame_info: // Compared to bfd, line var plays the role of offset from func_name // Reports format is adjusted accordingly to reflect in saved file funcs[num_frames].line = offset; funcs[num_frames].pc = (void *)pc; memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func)); if (mapsCnt > 0 && (mapName = arch_searchMaps(pc, mapsCnt, mapsList)) != NULL) { memcpy(funcs[num_frames].mapName, mapName, sizeof(funcs[num_frames].mapName)); } else { strncpy(funcs[num_frames].mapName, "UNKNOWN", sizeof(funcs[num_frames].mapName)); } num_frames++; ret = unw_step(&cursor); } while (ret > 0 && num_frames < _HF_MAX_FUNCS); return num_frames; }
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { if (GetMap() == nullptr) { // Without a map object, we can't do anything. error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING; return false; } error_ = BACKTRACE_UNWIND_NO_ERROR; if (ucontext) { BACK_LOGW("Unwinding from a specified context not supported yet."); error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION; return false; } if (!Init()) { return false; } unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { BACK_LOGW("unw_init_remote failed %d", ret); error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; return false; } size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); if (ret < 0) { BACK_LOGW("Failed to read IP %d", ret); break; } unw_word_t sp; ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); if (ret < 0) { BACK_LOGW("Failed to read SP %d", ret); break; } if (num_ignore_frames == 0) { frames_.resize(num_frames+1); backtrace_frame_data_t* frame = &frames_.at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; if (num_frames > 0) { backtrace_frame_data_t* prev = &frames_.at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } FillInMap(frame->pc, &frame->map); if (BacktraceMap::IsValid(frame->map)) { frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias; } else { frame->rel_pc = frame->pc; } frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map); num_frames++; // If the pc is in a device map, then don't try to step. if (frame->map.flags & PROT_DEVICE_MAP) { break; } } else { // If the pc is in a device map, then don't try to step. backtrace_map_t map; FillInMap(pc, &map); if (map.flags & PROT_DEVICE_MAP) { break; } num_ignore_frames--; } // Verify the sp is not in a device map. backtrace_map_t map; FillInMap(sp, &map); if (map.flags & PROT_DEVICE_MAP) { break; } ret = unw_step (&cursor); } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; }
void do_backtrace(void) { unw_word_t ip, sp, start_ip = 0, off; int n = 0, ret; unw_proc_info_t pi; unw_cursor_t c; char buf[512]; size_t len; ret = unw_init_remote(&c, as, ui); if (ret < 0) panic ("unw_init_remote() failed: ret=%d\n", ret); do { if ((ret = unw_get_reg(&c, UNW_REG_IP, &ip)) < 0 || (ret = unw_get_reg(&c, UNW_REG_SP, &sp)) < 0) panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret); if (n == 0) start_ip = ip; buf[0] = '\0'; if (print_names) unw_get_proc_name(&c, buf, sizeof(buf), &off); if (verbose) { if (off) { len = strlen(buf); if (len >= sizeof(buf) - 32) len = sizeof(buf) - 32; sprintf(buf + len, "+0x%lx", (unsigned long) off); } printf("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp); } if ((ret = unw_get_proc_info(&c, &pi)) < 0) panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret); else if (verbose) printf("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx", (long) pi.start_ip, (long) pi.end_ip, (long) pi.handler, (long) pi.lsda); if (verbose) printf("\n"); ret = unw_step(&c); if (ret < 0) { unw_get_reg(&c, UNW_REG_IP, &ip); panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n", ret, (long) ip, (long) start_ip); } if (++n > 64) { /* guard against bad unwind info in old libraries... */ panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n", (long) start_ip); break; } if (nerrors > nerrors_max) { panic ("Too many errors (%d)!\n", nerrors); break; } } while (ret > 0); if (ret < 0) panic ("unwind failed with ret=%d\n", ret); if (verbose) printf("================\n\n"); }
size_t StackCorkscrewLibunwind::Unwind (pid_t ppid, pid_t tid, size_t ignoreDepth, size_t maxDepth) { assert (ppid > 0); assert (tid >= ppid); (void) ignoreDepth; m_frames.clear (); if (maxDepth == 0) { return 0; } static unw_addr_space_t addr_space; (void) addr_space; #if UNWIND_SUPPORTED && UNWIND_REMOTE_SUPPORTED addr_space = unw_create_addr_space (&_UPT_accessors, 0); if (!addr_space) { fprintf (stderr, "unw_create_addr_space failed.\n"); fflush (stderr); return 0; } #endif #if UNWIND_MAP_SUPPORTED && UNWIND_FUNCTION_NAME unw_map_cursor_t map_cursor; if (unw_map_cursor_create (&map_cursor, tid) < 0) { fprintf (stderr, "Failed to create map cursor.\n"); fflush (stderr); return 0; } unw_map_set (addr_space, &map_cursor); #endif #if UNWIND_REMOTE_SUPPORTED struct UPT_info* upt_info = reinterpret_cast<struct UPT_info*> (_UPT_create (tid)); if (!upt_info) { fprintf (stderr, "Failed to create upt info.\n"); fflush (stderr); return 0; } unw_cursor_t cursor; { int error = unw_init_remote (&cursor, addr_space, upt_info); if (error < 0) { fprintf (stderr, "unw_init_remote failed (%d)\n", error); fflush (stderr); return 0; } } #endif bool shouldContinue = false; size_t numFrames = 0; do { // // Evaluate instruction pointer / program counter address. // #if UNWIND_REMOTE_SUPPORTED uint64_t pc = 0; { unw_word_t unwound_pc; int error = unw_get_reg (&cursor, UNW_REG_IP, &unwound_pc); if (error < 0) { fprintf (stderr, "Failed to read IP (%d)\n", error); fflush (stderr); break; } pc = unwound_pc; } #if UNWIND_STACK_POINTER uint64_t sp = 0; { unw_word_t unwound_sp; int error = unw_get_reg (&cursor, UNW_REG_SP, &unwound_sp); if (error < 0) { fprintf (stderr, "Failed to read SP (%d)\n", error); fflush (stderr); break; } sp = unwound_sp; } #endif if (ignoreDepth == 0) { const char *function = "??"; #if UNWIND_FUNCTION_NAME uintptr_t offset = 0; char buffer [128]; unw_word_t value; const int result = unw_get_proc_name_by_ip (addr_space, pc, buffer, sizeof (buffer), &value, upt_info); if (result >= 0 && buffer [0] != '\0') { function = buffer; offset = static_cast<uintptr_t>(value); } #endif StackFrame frame; frame.m_level = numFrames; frame.m_pc = pc; #if UNWIND_STACK_POINTER frame.m_sp = sp; #endif strncpy (frame.m_function, function, sizeof (frame.m_function)); m_frames.push_back (frame); numFrames++; } else { ignoreDepth--; } shouldContinue = (unw_step (&cursor) > 0); #endif } while (shouldContinue && numFrames < maxDepth); #if UNWIND_REMOTE_SUPPORTED _UPT_destroy (upt_info); #endif #if UNWIND_MAP_SUPPORTED && UNWIND_FUNCTION_NAME unw_map_cursor_destroy (&map_cursor); unw_map_cursor_clear (&map_cursor); #endif return m_frames.size (); }