The attached patch adds decoding of call/return registers to the disassembler, and also fixes a segfault; both are byproducts of a long and otherwise fruitless debugging session. Please let me know what you think.
-- Bob Rogers http://rgrjr.dyndns.org/
* src/debug.c: + (PDB_disassemble_op): Add special decoding for the signature used in args/returns. Needs better abstraction, may need better error checking. + (PDB_disassemble): Bug fix: Initialize pline->label, lest the caller segfault on output. Diffs between last version checked in and current workfile(s): Index: src/debug.c =================================================================== --- src/debug.c (revision 24244) +++ src/debug.c (working copy) @@ -1594,8 +1594,7 @@ /* If the opcode jumps and this is the last argument, that means this is a label */ if ((j == info->op_count - 1) && - (info->jump & PARROT_JUMP_RELATIVE)) - { + (info->jump & PARROT_JUMP_RELATIVE)) { if (file) { dest[size++] = 'L'; i = PDB_add_label(file, op, op[j]); @@ -1757,6 +1756,79 @@ dest[size++] = ','; } + /* Special decoding for the signature used in args/returns. Such ops have + one fixed parameter (the signature vector), plus a varying number of + registers/constants. For each value, we show the register and decode its + flags. */ + if (*(op) == PARROT_OP_set_args_pc || + *(op) == PARROT_OP_get_results_pc || + *(op) == PARROT_OP_get_params_pc || + *(op) == PARROT_OP_set_returns_pc) { + char buf[1000]; + PMC * const sig = interp->code->const_table->constants[op[1]]->u.key; + int n_values = SIG_ELEMS(sig); + const char *regs = "ISPN"; + /* This is from Call_bits_enum_t (with which it should probably be + colocated): + ' ' => ignore (this is the reg type, decoded elsewhere) + '!' => undefined + 'C' => constant + 'F' => :flat or :slurpy + 'O' => :optional + '?' => :opt_flag + 'N' => named param. + */ + const char *flag_chars = " !!CF!O?N"; + int sig_value; + + dest[size++] = '='; + dest[size++] = '('; + for (j = 0; j < n_values; j++) { + unsigned int idx = 0; + int sig_value = VTABLE_get_integer_keyed_int(interp, sig, j); + + /* Print the register name, e.g. P37. */ + if (j) + buf[idx++] = ','; + buf[idx++] = regs[sig_value & PARROT_ARG_TYPE_MASK]; + Parrot_snprintf(interp, &buf[idx], sizeof(buf)-idx, + INTVAL_FMT, op[j+2]); + idx = strlen(buf); + + /* Add flags, if we have any. */ + { + int flag_idx = 0; + int flag_p = 0; + int flags = sig_value; + + /* End when we run out of flags, off the end of flag_chars, or + get too close to the end of buf. */ + while (flags && idx < sizeof(buf)-10) { + char flag_char = flag_chars[flag_idx]; + if (! flag_char) + break; + if (flags & 1 && flag_char != ' ') { + if (! flag_p) { + buf[idx++] = '['; + flag_p = 1; + } + buf[idx++] = flag_char; + } + flags >>= 1; + flag_idx++; + } + if (flag_p) + buf[idx++] = ']'; + } + + /* Add it to dest. */ + buf[idx++] = '\0'; + strcpy(&dest[size], buf); + size += strlen(buf); + } + dest[size++] = ')'; + } + dest[size] = '\0'; return ++size; } @@ -1793,6 +1865,7 @@ PDB_free_file(interp); pline->number = 1; + pline->label = NULL; pfile->line = pline; pfile->label = NULL; pfile->size = 0; End of diffs.