示例#1
0
static int
get_signal_number_libunwind(struct UCD_info *ui)
{
    int tnum, nthreads = _UCD_get_num_threads(ui);
    for (tnum = 0; tnum < nthreads; ++tnum)
    {
        _UCD_select_thread(ui, tnum);
        int signo = _UCD_get_cursig(ui);

        /* Return first nonzero signal, gdb/bfd seem to work this way. */
        if (signo)
            return signo;
    }

    return 0;
}
示例#2
0
文件: stack.c 项目: mmilata/seecore
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;
}
示例#3
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;
}