Exemplo n.º 1
0
/*
 * 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);
	}
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
void collectStackRoots(TraceStack *stack) {
    unw_cursor_t cursor;
    unw_context_t uc;
    unw_word_t ip, sp, bp;

    // force callee-save registers onto the stack:
    // Actually, I feel like this is pretty brittle:
    // collectStackRoots itself is allowed to save the callee-save registers
    // on its own stack.
    jmp_buf registers __attribute__((aligned(sizeof(void*))));

#ifndef NVALGRIND
    if (RUNNING_ON_VALGRIND) {
        memset(&registers, 0, sizeof(registers));
        memset(&cursor, 0, sizeof(cursor));
        memset(&uc, 0, sizeof(uc));
        memset(&ip, 0, sizeof(ip));
        memset(&sp, 0, sizeof(sp));
        memset(&bp, 0, sizeof(bp));
    }
#endif

    setjmp(registers);

    assert(sizeof(registers) % 8 == 0);
    //void* stack_bottom = __builtin_frame_address(0);
    collectRoots(&registers, &registers + 1, stack);

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    TraceStackGCVisitor visitor(stack);

    int code;
    while (true) {
        int code = unw_step(&cursor);
        // Negative codes are errors, zero means that there isn't a new frame.
        ASSERT(code >= 0 && "something broke unwinding!", "%d '%s'", code, unw_strerror(code));
        assert(code != 0 && "didn't get to the top of the stack!");

        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);
        unw_get_reg(&cursor, UNW_TDEP_BP, &bp);

        void* cur_sp = (void*)sp;
        void* cur_bp = (void*)bp;

        //std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)ip, true);
        //if (VERBOSITY()) printf("ip = %lx (%s), stack = [%p, %p)\n", (long) ip, name.c_str(), cur_sp, cur_bp);

        unw_proc_info_t pip;
        unw_get_proc_info(&cursor, &pip);

        if (pip.start_ip == (uintptr_t)&__libc_start_main) {
            break;
        }

        if (pip.start_ip == (intptr_t)interpretFunction) {
            // TODO Do we still need to crawl the interpreter itself?
            gatherInterpreterRootsForFrame(&visitor, cur_bp);
        }

        collectRoots(cur_sp, (char*)cur_bp, stack);
    }
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
void
xorg_backtrace(void)
{
    unw_cursor_t cursor;
    unw_context_t context;
    unw_word_t off;
    unw_proc_info_t pip;
    int ret, i = 0;
    char procname[256];
    const char *filename;
    Dl_info dlinfo;

    pip.unwind_info = NULL;
    ret = unw_getcontext(&context);
    if (ret) {
        ErrorFSigSafe("unw_getcontext failed: %s [%d]\n", unw_strerror(ret),
                      ret);
        return;
    }

    ret = unw_init_local(&cursor, &context);
    if (ret) {
        ErrorFSigSafe("unw_init_local failed: %s [%d]\n", unw_strerror(ret),
                      ret);
        return;
    }

    ErrorFSigSafe("\n");
    ErrorFSigSafe("Backtrace:\n");
    ret = unw_step(&cursor);
    while (ret > 0) {
        ret = unw_get_proc_info(&cursor, &pip);
        if (ret) {
            ErrorFSigSafe("unw_get_proc_info failed: %s [%d]\n",
                          unw_strerror(ret), ret);
            break;
        }

        ret = unw_get_proc_name(&cursor, procname, 256, &off);
        if (ret && ret != -UNW_ENOMEM) {
            if (ret != -UNW_EUNSPEC)
                ErrorFSigSafe("unw_get_proc_name failed: %s [%d]\n",
                              unw_strerror(ret), ret);
            procname[0] = '?';
            procname[1] = 0;
        }

        if (dladdr((void *)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
                *dlinfo.dli_fname)
            filename = dlinfo.dli_fname;
        else
            filename = "?";

        ErrorFSigSafe("%u: %s (%s%s+0x%x) [%p]\n", i++, filename, procname,
                      ret == -UNW_ENOMEM ? "..." : "", (int)off,
                      (void *)(pip.start_ip + off));

        ret = unw_step(&cursor);
        if (ret < 0)
            ErrorFSigSafe("unw_step failed: %s [%d]\n", unw_strerror(ret), ret);
    }
    ErrorFSigSafe("\n");
}
Exemplo n.º 6
0
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;
}