Example #1
0
static int frame_callback(Dwfl_Frame *frame, void *userdata) {
        struct stack_context *c = userdata;
        Dwarf_Addr pc, pc_adjusted, bias = 0;
        _cleanup_free_ Dwarf_Die *scopes = NULL;
        const char *fname = NULL, *symbol = NULL;
        Dwfl_Module *module;
        bool is_activation;

        assert(frame);
        assert(c);

        if (c->n_frame >= FRAMES_MAX)
                return DWARF_CB_ABORT;

        if (!dwfl_frame_pc(frame, &pc, &is_activation))
                return DWARF_CB_ABORT;

        pc_adjusted = pc - (is_activation ? 0 : 1);

        module = dwfl_addrmodule(c->dwfl, pc_adjusted);
        if (module) {
                Dwarf_Die *s, *cudie;
                int n;

                cudie = dwfl_module_addrdie(module, pc_adjusted, &bias);
                if (cudie) {
                        n = dwarf_getscopes(cudie, pc_adjusted - bias, &scopes);
                        for (s = scopes; s < scopes + n; s++) {
                                if (IN_SET(dwarf_tag(s), DW_TAG_subprogram, DW_TAG_inlined_subroutine, DW_TAG_entry_point)) {
                                        Dwarf_Attribute *a, space;

                                        a = dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space);
                                        if (!a)
                                                a = dwarf_attr_integrate(s, DW_AT_linkage_name, &space);
                                        if (a)
                                                symbol = dwarf_formstring(a);
                                        if (!symbol)
                                                symbol = dwarf_diename(s);

                                        if (symbol)
                                                break;
                                }
                        }
                }

                if (!symbol)
                        symbol = dwfl_module_addrname(module, pc_adjusted);

                fname = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        }

        fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname));
        c->n_frame ++;

        return DWARF_CB_OK;
}
Example #2
0
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;
}