/** * This is used to obtain the list of symbols using a ucontext_t structure. * So, it is used by both the HaltedStacktrace and the SuspendedStacktrace. * Since this method is pure implementation, it's */ int thread_unwind(ucontext_t* uc, void** iparray, StackTrace& stacktrace) { assert(iparray != nullptr); assert(&stacktrace != nullptr); unw_cursor_t cursor; // Effective ucontext_t. If uc not supplied, use unw_getcontext locally. This is appropriate inside signal handlers. #if defined(__APPLE__) unw_context_t thisctx; unw_getcontext(&thisctx); #else ucontext_t thisctx; if (uc == nullptr) { unw_getcontext(&thisctx); uc = &thisctx; } #endif const int BUFR_SZ = 1000; char procbuffer[BUFR_SZ]; stacktrace.clear(); stacktrace.reserve(120); /* * Note: documentation seems to indicate that uc_link contains a pointer to a "successor" context * that is to be resumed after the current one (as you might expect in a signal handler). * In practice however, the Linux OS seems to re-use the existing context of a thread, and so this approach * does not work. The uc_link is sometimes non-NULL however, but I do not know what the relation is to the * target context (uc). * while (uc->uc_link) { uc = uc->uc_link; LOG_L(L_DEBUG, "Dereferencing uc_link"); } */ #if defined(__APPLE__) int err = unw_init_local(&cursor, &thisctx); #else int err = unw_init_local(&cursor, uc); #endif if (err) { LOG_L(L_ERROR, "unw_init_local returned %d", err); return 0; } int i=0; while (i < MAX_STACKTRACE_DEPTH && unw_step(&cursor)) { StackFrame frame; unw_word_t ip; unw_word_t offp; unw_get_reg(&cursor, UNW_REG_IP, &ip); frame.ip = reinterpret_cast<void*>(ip); frame.level = i; iparray[i] = frame.ip; if (!unw_get_proc_name(&cursor, procbuffer, BUFR_SZ-1, &offp)) { frame.mangled = std::string(procbuffer); } else { frame.mangled = std::string("UNW_ENOINFO"); } stacktrace.push_back(frame); i++; } stacktrace.resize(i); LOG_L(L_DEBUG, "thread_unwind returned %d frames", i); return i; }