NAME ^

src/trace.c - Tracing

DESCRIPTION ^

Tracing support for the runops_slow_core() function in src/runops_cores.c.

This is turned on with Parrot's -t option.

src/test_main.c

Functions ^

*/

#include "trace.h" #include "parrot/oplib/ops.h"

/* HEADERIZER HFILE: src/trace.h */

/* HEADERIZER BEGIN: static */

PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING* trace_class_name( NOTNULL(const PMC* pmc) ) __attribute__nonnull__(1);

/* HEADERIZER END: static */

/*

FUNCDOC: trace_pmc_dump

Prints a PMC to stderr.

*/

PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING* trace_class_name(NOTNULL(const PMC* pmc)) { STRING *class_name; if (PObj_is_class_TEST(pmc)) { SLOTTYPE * const class_array = (SLOTTYPE *)PMC_data(pmc); PMC * const class_name_pmc = get_attrib_num(class_array, PCD_CLASS_NAME); class_name = PMC_str_val(class_name_pmc); } else class_name = pmc->vtable->whoami; return class_name; }

void trace_pmc_dump(PARROT_INTERP, NOTNULL(PMC *pmc)) { Interp * const debugger = interp->debugger;

    if (!pmc) {
        PIO_eprintf(debugger, "(null)");
        return;
    }
    if ( PMC_IS_NULL(pmc) )  {
        PIO_eprintf(debugger, "PMCNULL");
        return;
    }
    if (!pmc->vtable || (UINTVAL)pmc->vtable == 0xdeadbeef) {
        PIO_eprintf(debugger, "<!!no vtable!!>");
        return;
    }
    if (PObj_on_free_list_TEST(pmc)) {
        PIO_eprintf(debugger, "**************** PMC is on free list *****\n");
    }
    if (pmc->vtable->pmc_class == pmc) {
        STRING * const name = trace_class_name(pmc);
        PIO_eprintf(debugger, "Class=%Ss:PMC(%#p)", name, pmc);
    }
    else if (pmc->vtable->base_type == enum_class_String) {
        const STRING * const s = VTABLE_get_string(interp, pmc);
        if (!s)
            PIO_eprintf(debugger, "%S=PMC(%#p Str:(NULL))",
                    VTABLE_name(interp, pmc), pmc);
        else {
            STRING* const escaped = string_escape_string_delimited(
                            interp, s, 20);
            if (escaped)
                PIO_eprintf(debugger, "%S=PMC(%#p Str:\"%Ss\")",
                    VTABLE_name(interp, pmc), pmc,
                    escaped);
            else
                PIO_eprintf(debugger, "%S=PMC(%#p Str:\"(null)\")",
                    VTABLE_name(interp, pmc), pmc);
        }
    }
    else if (pmc->vtable->base_type == enum_class_Boolean) {
        PIO_eprintf(debugger, "Boolean=PMC(%#p: %d)",
                pmc, PMC_int_val(pmc));
    }
    else if (pmc->vtable->base_type == enum_class_Integer) {
        PIO_eprintf(debugger, "Integer=PMC(%#p: %d)",
                pmc, PMC_int_val(pmc));
    }
    else if (pmc->vtable->base_type == enum_class_BigInt) {
        STRING * const s = VTABLE_get_string(interp, pmc);
        PIO_eprintf(debugger, "BigInt=PMC(%#p: %Ss)",
                pmc, s);
    }
    else if (pmc->vtable->base_type == enum_class_Complex) {
        STRING * const s = VTABLE_get_string(interp, pmc);
        PIO_eprintf(debugger, "Complex=PMC(%#p: %Ss)",
                pmc, s);
    }
    else if (pmc->vtable->base_type == enum_class_RetContinuation
            ||  pmc->vtable->base_type == enum_class_Continuation
            ||  pmc->vtable->base_type == enum_class_Sub) {
        PIO_eprintf(debugger, "%S=PMC(%#p pc:%d)",
                VTABLE_name(interp, pmc), pmc,
                PMC_sub(pmc)->start_offs);
    }
    else if (PObj_is_object_TEST(pmc)) {
        PIO_eprintf(debugger, "Object(%Ss)=PMC(%#p)",
                VTABLE_name(interp, pmc), pmc);
    }
    else if (pmc->vtable->base_type == enum_class_delegate) {
        PIO_eprintf(debugger, "delegate=PMC(%#p)", pmc);
    }
    else {
        PIO_eprintf(debugger, "%S=PMC(%#p)",
                VTABLE_name(interp, pmc), pmc);
    }
}

/*

FUNCDOC: trace_key_dump

Prints a key to stderr, returns the length of the output.

*/

int trace_key_dump(PARROT_INTERP, NOTNULL(const PMC *key)) { Interp * const debugger = interp->debugger;

    int len = PIO_eprintf(debugger, "[");

    while (key) {
        switch (PObj_get_FLAGS(key) & KEY_type_FLAGS) {
        case KEY_integer_FLAG:
            len += PIO_eprintf(debugger, "%vi", PMC_int_val(key));
            break;
        case KEY_number_FLAG:
            len += PIO_eprintf(debugger, "%vg", PMC_num_val(key));
            break;
        case KEY_string_FLAG:
            {
            const STRING * const s = PMC_str_val(key);
            STRING* const escaped = string_escape_string_delimited(
                            interp, s, 20);
            if (escaped)
                len += PIO_eprintf(debugger, "\"%Ss\"", escaped);
            else
                len += PIO_eprintf(debugger, "\"(null)\"");
            }
            break;
        case KEY_integer_FLAG|KEY_register_FLAG:
            len += PIO_eprintf(debugger, "I%vd=%vd", PMC_int_val(key),
                    REG_INT(interp, PMC_int_val(key)));
            break;
        case KEY_number_FLAG|KEY_register_FLAG:
            len += PIO_eprintf(debugger, "I%vd=%vd", PMC_int_val(key),
                    REG_NUM(interp, PMC_int_val(key)));
            break;
        case KEY_string_FLAG|KEY_register_FLAG:
            {
            const STRING * const s = REG_STR(interp, PMC_int_val(key));
            STRING* const escaped = string_escape_string_delimited(
                            interp, s, 20);
            if (escaped)
                len += PIO_eprintf(debugger, "S%vd=\"%Ss\"", PMC_int_val(key),
                        escaped);
            else
                len += PIO_eprintf(debugger, "S%vd=\"(null)\"",
                        PMC_int_val(key));
            }
            break;
        case KEY_pmc_FLAG|KEY_register_FLAG:
            len += PIO_eprintf(debugger, "P%vd=", PMC_int_val(key));
            trace_pmc_dump(debugger, REG_PMC(interp, PMC_int_val(key)));
            break;
        default:
            len += PIO_eprintf(debugger, "??");
            key = NULL;
            break;
        }

        if (key) {
            key = (PMC *)PMC_data(key);
            if (key)
                len += PIO_eprintf(debugger, ";");
        }
    } /* while */

    len += PIO_eprintf(debugger, "]");
    return len;
}

/*

FUNCDOC: trace_op_dump

TODO: This isn't really part of the API, but here's its documentation.

Prints the PC, OP and ARGS. Used by trace_op().

*/

void trace_op_dump(PARROT_INTERP, NOTNULL(const opcode_t *code_start), NOTNULL(const opcode_t *pc)) { INTVAL s, n; int more = 0, var_args; Interp * const debugger = interp->debugger; op_info_t * const info = &interp->op_info_table[*pc]; PMC *sig; int type; int len; #define ARGS_COLUMN 40

    PARROT_ASSERT(debugger);
    sig = NULL; /* silence compiler uninit warning */

    s = 1;
    len = PIO_eprintf(debugger, "%6vu ", (UINTVAL)(pc - code_start));
    if (strcmp(info->name, "infix") == 0) {
        /* this should rather be MMD_opcode_name, which doesn't
         * exit yet
         */
        len += PIO_eprintf(debugger, "%s",
                Parrot_MMD_method_name(interp, pc[1]) + 2);
        s = 2;
    }
    else if (strcmp(info->name, "n_infix") == 0) {
        len += PIO_eprintf(debugger, "n_%s",
                Parrot_MMD_method_name(interp, pc[1]) + 2);
        s = 2;
    }
    else
        len += PIO_eprintf(debugger, "%s", info->name);

    n = info->op_count;
    var_args = 0;

    if (*pc == PARROT_OP_set_args_pc ||
            *pc == PARROT_OP_get_results_pc ||
            *pc == PARROT_OP_get_params_pc ||
            *pc == PARROT_OP_set_returns_pc) {
        sig = interp->code->const_table->constants[pc[1]]->u.key;
        if (!sig) {
            real_exception(interp, NULL, 1,
                    "NULL sig PMC detected in trace_op_dump");
        }
        var_args = VTABLE_elements(interp, sig);
        n += var_args;
    }

    if (n > 1) {
        INTVAL i;
        len += PIO_eprintf(debugger, " ");
        /* pass 1 print arguments */
        for (i = s; i < n; i++) {
            const opcode_t o = pc[i];
            if (i < info->op_count) {
                type = info->types[i - 1];
            }
            else {
                if (!sig) {
                    real_exception(interp, NULL, 1,
                            "NULL sig PMC detected in trace_op_dump");
                }
                type = SIG_ITEM(sig, i - 2) &
                    (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
            }
            if (i > s &&
                    type != PARROT_ARG_KC &&
                    type != PARROT_ARG_KIC &&
                    type != PARROT_ARG_KI &&
                    type != PARROT_ARG_K) {
                len += PIO_eprintf(debugger, ", ");
            }
            switch (type) {
                case PARROT_ARG_IC:
                    len += PIO_eprintf(debugger, "%vd", o);
                    break;
                case PARROT_ARG_NC:
                    len += PIO_eprintf(debugger, "%vg", PCONST(o)->u.number);
                    break;
                case PARROT_ARG_PC:
                    if (var_args)
                        len += PIO_eprintf(debugger, "PC%d (%d)",
                                (int)o, var_args);
                    else
                        len += PIO_eprintf(debugger, "PC%d", (int)o);
                    break;
                case PARROT_ARG_SC:
                    {
                    STRING* const escaped = string_escape_string_delimited(
                            interp,
                            PCONST(o)->u.string, 20);
                    if (escaped)
                        len += PIO_eprintf(debugger, "\"%Ss\"", escaped);
                    else
                        len += PIO_eprintf(debugger, "\"(null)\"");
                    }
                    break;
                case PARROT_ARG_KC:
                    len += trace_key_dump(interp, PCONST(o)->u.key);
                    break;
                case PARROT_ARG_KIC:
                    len += PIO_eprintf(debugger, "[%vd]", o);
                    break;
                case PARROT_ARG_KI:
                    len += PIO_eprintf(debugger, "[I%vd]", o);
                    more = 1;
                    break;
                case PARROT_ARG_K:
                    len += PIO_eprintf(debugger, "[P%vd]",o);
                    more = 1;
                    break;
                case PARROT_ARG_I:
                    len += PIO_eprintf(debugger, "I%vd", o);
                    more = 1;
                    break;
                case PARROT_ARG_N:
                    len += PIO_eprintf(debugger, "N%vd", o);
                    more = 1;
                    break;
                case PARROT_ARG_P:
                    len += PIO_eprintf(debugger, "P%vd", o);
                    more = 1;
                    break;
                case PARROT_ARG_S:
                    len += PIO_eprintf(debugger, "S%vd", o);
                    more = 1;
                    break;
                default:
                    real_exception(interp, NULL, 1, "unhandled type in trace");
                    break;
            }
        }
        if (!more)
            goto done;
        if (len < ARGS_COLUMN)  {
            STRING * const fill = string_repeat(debugger,
                    const_string(debugger, " "),
                    ARGS_COLUMN - len, NULL);
            PIO_putps(debugger, PIO_STDERR(debugger), fill);
        }
        else {
            PIO_eprintf(debugger, "\t");
        }

        /* pass 2 print argument details if needed */
        for (i = 1; i < n; i++) {
            const opcode_t o = pc[i];
            if (i < info->op_count)
                type = info->types[i - 1];
            else
                type = SIG_ITEM(sig, i - 2) &
                    (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
            if (i > s) {
                PIO_eprintf(debugger, " ");
            }
            switch (type) {
                case PARROT_ARG_I:
                    PIO_eprintf(debugger, "I%vd=%vd", o, REG_INT(interp, o));
                    break;
                case PARROT_ARG_N:
                    PIO_eprintf(debugger, "N%vd=%vf", o, REG_NUM(interp, o));
                    break;
                case PARROT_ARG_PC:
                    PIO_eprintf(debugger, "PC%vd=", o);
                    trace_pmc_dump(interp, PCONST(o)->u.key);
                    break;
                case PARROT_ARG_P:
                    PIO_eprintf(debugger, "P%vd=", o);
                    trace_pmc_dump(interp, REG_PMC(interp, o));
                    break;
                case PARROT_ARG_S:
                    if (REG_STR(interp, o)) {
                        STRING* const escaped = string_escape_string_delimited(
                                interp, REG_STR(interp, o), 20);
                        PIO_eprintf(debugger, "S%vd=\"%Ss\"", o,
                                escaped);
                    }
                    else
                        PIO_eprintf(debugger, "S%vd=\"(null)\"", o);
                    break;
                case PARROT_ARG_K:
                    PIO_eprintf(debugger, "P%vd=", o);
                    trace_key_dump(interp, REG_PMC(interp, *(pc + i)));
                    break;
                case PARROT_ARG_KI:
                    PIO_eprintf(debugger, "I%vd=[%vd]", o, REG_INT(interp, o));
                    break;
                default:
                    break;
            }
        }
    }
done:
    PIO_eprintf(debugger, "\n");
}

/*

FUNCDOC: trace_op

TODO: This isn't really part of the API, but here's its documentation.

Prints the PC, OP and ARGS. Used by runops_trace(). With bounds checking.

*/

void trace_op(PARROT_INTERP, NOTNULL(const opcode_t *code_start), NOTNULL(const opcode_t *code_end), NULLOK(const opcode_t *pc)) { if (!pc) { return; }

    if (pc >= code_start && pc < code_end)
        trace_op_dump(interp, code_start, pc);
    else
        PIO_eprintf(interp, "PC=%ld; OP=<err>\n", (long)(pc - code_start));
}

/*

SEE ALSO ^

src/trace.h

*/

/* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */


parrot