示例#1
0
	/**
	 * 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;
	}