fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / runcore / trace.c
blobcfdc7601d1ec869e768417d67a2d2bbff11620bd
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/trace.c - Tracing
9 =head1 DESCRIPTION
11 Tracing support for the C<runops_slow_core()> function in
12 F<src/runcore/cores.c>.
14 This is turned on with Parrot's C<-t> option.
16 src/test_main.c
18 =head2 Functions
20 =over 4
22 =cut
26 #include "parrot/runcore_trace.h"
27 #include "parrot/oplib/ops.h"
28 #include "parrot/context.h"
29 #include "pmc/pmc_sub.h"
30 #include "pmc/pmc_callcontext.h"
32 /* HEADERIZER HFILE: include/parrot/runcore_trace.h */
34 /* HEADERIZER BEGIN: static */
35 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
37 PARROT_CANNOT_RETURN_NULL
38 static Interp * debugger_or_interp(PARROT_INTERP)
39 __attribute__nonnull__(1);
41 PARROT_WARN_UNUSED_RESULT
42 PARROT_CANNOT_RETURN_NULL
43 static STRING* trace_class_name(PARROT_INTERP, ARGIN(const PMC* pmc))
44 __attribute__nonnull__(1)
45 __attribute__nonnull__(2);
47 #define ASSERT_ARGS_debugger_or_interp __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
48 PARROT_ASSERT_ARG(interp))
49 #define ASSERT_ARGS_trace_class_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
50 PARROT_ASSERT_ARG(interp) \
51 , PARROT_ASSERT_ARG(pmc))
52 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
53 /* HEADERIZER END: static */
57 =item C<static Interp * debugger_or_interp(PARROT_INTERP)>
59 Get debugger if available
61 =cut
64 PARROT_CANNOT_RETURN_NULL
65 static Interp *
66 debugger_or_interp(PARROT_INTERP)
68 ASSERT_ARGS(debugger_or_interp)
70 return interp->pdb && interp->pdb->debugger
71 ? interp->pdb->debugger
72 : interp;
77 =item C<static STRING* trace_class_name(PARROT_INTERP, const PMC* pmc)>
79 Obtains the class name of the PMC.
81 =cut
85 PARROT_WARN_UNUSED_RESULT
86 PARROT_CANNOT_RETURN_NULL
87 static STRING*
88 trace_class_name(PARROT_INTERP, ARGIN(const PMC* pmc))
90 ASSERT_ARGS(trace_class_name)
92 if (PObj_is_class_TEST(pmc)) {
93 SLOTTYPE * const class_array = PMC_data_typed(pmc, SLOTTYPE *);
94 PMC * const class_name_pmc = get_attrib_num(class_array,
95 PCD_CLASS_NAME);
96 return VTABLE_get_string(interp, class_name_pmc);
98 else
99 return pmc->vtable->whoami;
105 =item C<void trace_pmc_dump(PARROT_INTERP, PMC *pmc)>
107 Prints a PMC to C<stderr>.
109 =cut
113 void
114 trace_pmc_dump(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc))
116 ASSERT_ARGS(trace_pmc_dump)
117 Interp * const debugger = debugger_or_interp(interp);
118 Parrot_Sub_attributes *sub;
120 if (!pmc) {
121 Parrot_io_eprintf(debugger, "(null)");
122 return;
125 if (PMC_IS_NULL(pmc)) {
126 Parrot_io_eprintf(debugger, "PMCNULL");
127 return;
130 if (PObj_on_free_list_TEST(pmc))
131 Parrot_io_eprintf(debugger,
132 "**************** PMC is on free list *****\n");
134 if (!pmc->vtable) {
135 Parrot_io_eprintf(debugger, "<!!no vtable!!>");
136 return;
139 if (pmc->vtable->pmc_class == pmc) {
140 STRING * const name = trace_class_name(interp, pmc);
141 Parrot_io_eprintf(debugger, "Class=%Ss:PMC(%#p)", name, pmc);
143 else if (pmc->vtable->base_type == enum_class_String) {
144 const STRING * const s = VTABLE_get_string(interp, pmc);
145 if (!s)
146 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:(NULL))",
147 VTABLE_name(interp, pmc), pmc);
148 else {
149 STRING * const escaped = Parrot_str_escape_truncate(interp, s, 20);
150 if (escaped)
151 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:\"%Ss\")",
152 VTABLE_name(interp, pmc), pmc, escaped);
153 else
154 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:\"(null)\")",
155 VTABLE_name(interp, pmc), pmc);
158 else if (pmc->vtable->base_type == enum_class_Boolean)
159 Parrot_io_eprintf(debugger, "Boolean=PMC(%#p: %d)",
160 pmc, VTABLE_get_integer(interp, pmc));
162 else if (pmc->vtable->base_type == enum_class_Integer)
163 Parrot_io_eprintf(debugger, "Integer=PMC(%#p: %d)",
164 pmc, VTABLE_get_integer(interp, pmc));
166 else if (pmc->vtable->base_type == enum_class_BigInt) {
167 STRING * const s = VTABLE_get_string(interp, pmc);
168 Parrot_io_eprintf(debugger, "BigInt=PMC(%#p: %Ss)",
169 pmc, s);
171 else if (pmc->vtable->base_type == enum_class_Complex) {
172 STRING * const s = VTABLE_get_string(interp, pmc);
173 Parrot_io_eprintf(debugger, "Complex=PMC(%#p: %Ss)", pmc, s);
175 else if (pmc->vtable->base_type == enum_class_Sub) {
176 PMC_get_sub(interp, pmc, sub);
177 Parrot_io_eprintf(debugger, "%S=PMC(%#p pc:%d)",
178 VTABLE_name(interp, pmc), pmc, sub->start_offs);
180 else if (PObj_is_object_TEST(pmc)) {
181 Parrot_io_eprintf(debugger, "Object(%Ss)=PMC(%#p)",
182 VTABLE_get_string(interp, VTABLE_get_class(interp, pmc)), pmc);
184 else {
185 Parrot_io_eprintf(debugger, "%S=PMC(%#p)",
186 VTABLE_name(interp, pmc), pmc);
193 =item C<int trace_key_dump(PARROT_INTERP, PMC *key)>
195 Prints a key to C<stderr>, returns the length of the output.
197 =cut
202 trace_key_dump(PARROT_INTERP, ARGIN(PMC *key))
204 ASSERT_ARGS(trace_key_dump)
205 Interp * const debugger = debugger_or_interp(interp);
207 int len = Parrot_io_eprintf(debugger, "[");
209 while (key) {
210 switch (PObj_get_FLAGS(key) & KEY_type_FLAGS) {
211 case KEY_integer_FLAG:
212 len += Parrot_io_eprintf(debugger, "%vi",
213 VTABLE_get_integer(interp, key));
214 break;
215 case KEY_number_FLAG:
216 len += Parrot_io_eprintf(debugger, "%vg",
217 VTABLE_get_number(interp, key));
218 break;
219 case KEY_string_FLAG:
221 const STRING * const s = key_string(interp, key);
222 STRING * const escaped = Parrot_str_escape_truncate(interp, s, 20);
224 if (escaped)
225 len += Parrot_io_eprintf(debugger, "\"%Ss\"", escaped);
226 else
227 len += Parrot_io_eprintf(debugger, "\"(null)\"");
229 break;
230 case KEY_integer_FLAG|KEY_register_FLAG:
231 len += Parrot_io_eprintf(debugger, "I%vd=%vd",
232 VTABLE_get_integer(interp, key),
233 REG_INT(interp, VTABLE_get_integer(interp, key)));
234 break;
235 case KEY_number_FLAG|KEY_register_FLAG:
236 len += Parrot_io_eprintf(debugger, "I%vd=%vd",
237 VTABLE_get_integer(interp, key),
238 REG_NUM(interp, VTABLE_get_integer(interp, key)));
239 break;
240 case KEY_string_FLAG|KEY_register_FLAG:
242 const INTVAL keynum = VTABLE_get_integer(interp, key);
243 if (keynum < Parrot_pcc_get_regs_used(interp, CURRENT_CONTEXT(interp), REGNO_STR)) {
244 const STRING * const s = REG_STR(interp, keynum);
245 STRING * const escaped = Parrot_str_escape_truncate(interp, s, 20);
246 if (escaped)
247 len += Parrot_io_eprintf(debugger, "S%vd=\"%Ss\"",
248 keynum, escaped);
249 else
250 len += Parrot_io_eprintf(debugger, "S%vd=\"(null)\"", keynum);
252 else
253 len += Parrot_io_eprintf(debugger, "**WRONG KEY STRING REG %d**", keynum);
255 break;
256 case KEY_pmc_FLAG|KEY_register_FLAG:
257 len += Parrot_io_eprintf(debugger, "P%vd=",
258 VTABLE_get_integer(interp, key));
259 trace_pmc_dump(debugger, REG_PMC(interp,
260 VTABLE_get_integer(interp, key)));
261 break;
262 default:
263 len += Parrot_io_eprintf(debugger, "??");
264 key = NULL;
265 break;
268 if (key) {
269 key = VTABLE_shift_pmc(interp, key);
270 if (key)
271 len += Parrot_io_eprintf(debugger, ";");
275 len += Parrot_io_eprintf(debugger, "]");
276 return len;
282 =item C<void trace_op_dump(PARROT_INTERP, const opcode_t *code_start, const
283 opcode_t *pc)>
285 Prints the PC, OP and ARGS. Used by C<trace_op()>.
287 I<Not really part of the API.>
289 =cut
293 void
294 trace_op_dump(PARROT_INTERP,
295 ARGIN(const opcode_t *code_start),
296 ARGIN(const opcode_t *pc))
298 ASSERT_ARGS(trace_op_dump)
299 Interp * const debugger = debugger_or_interp(interp);
300 op_info_t * const info = interp->code->op_info_table[*pc];
301 PMC *sig = PMCNULL;
302 INTVAL n = info->op_count;
303 INTVAL s = 1;
304 int more = 0, type;
305 int var_args = 0;
307 int len = Parrot_io_eprintf(debugger, "%04vx ", (UINTVAL)(pc - code_start))
308 + Parrot_io_eprintf(debugger, "%s", info->name);
310 #define ARGS_COLUMN 40
312 if (*pc == PARROT_OP_set_args_pc
313 || *pc == PARROT_OP_get_results_pc
314 || *pc == PARROT_OP_get_params_pc
315 || *pc == PARROT_OP_set_returns_pc) {
316 sig = interp->code->const_table->constants[pc[1]].u.key;
318 if (!sig)
319 Parrot_ex_throw_from_c_args(interp, NULL, 1,
320 "NULL sig PMC detected in trace_op_dump");
322 var_args = VTABLE_elements(interp, sig);
323 n += var_args;
326 if (n > 1) {
327 INTVAL i;
328 len += Parrot_io_eprintf(debugger, " ");
329 /* pass 1 print arguments */
330 for (i = s; i < n; ++i) {
331 const opcode_t o = pc[i];
333 if (i < info->op_count)
334 type = info->types[i - 1];
335 else {
336 if (!sig)
337 Parrot_ex_throw_from_c_args(interp, NULL, 1,
338 "NULL sig PMC detected in trace_op_dump");
340 type = VTABLE_get_integer_keyed_int(interp, sig, i - 2) &
341 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
344 if (i > s
345 && type != PARROT_ARG_KC
346 && type != PARROT_ARG_KIC
347 && type != PARROT_ARG_KI
348 && type != PARROT_ARG_K)
349 len += Parrot_io_eprintf(debugger, ", ");
351 switch (type) {
352 case PARROT_ARG_IC:
353 len += Parrot_io_eprintf(debugger, "%vd", o);
354 break;
355 case PARROT_ARG_NC:
356 len += Parrot_io_eprintf(debugger, "%vg",
357 Parrot_pcc_get_num_constant(interp,
358 CURRENT_CONTEXT(interp), o));
359 break;
360 case PARROT_ARG_PC:
361 if (var_args)
362 len += Parrot_io_eprintf(debugger, "PC%d (%d)",
363 (int)o, var_args);
364 else
365 len += Parrot_io_eprintf(debugger, "PC%d", (int)o);
366 break;
367 case PARROT_ARG_SC:
369 STRING * const escaped = Parrot_str_escape_truncate(
370 interp, Parrot_pcc_get_string_constant(interp,
371 CURRENT_CONTEXT(interp), o), 20);
372 if (escaped)
373 len += Parrot_io_eprintf(debugger, "\"%Ss\"", escaped);
374 else
375 len += Parrot_io_eprintf(debugger, "\"(null)\"");
377 break;
378 case PARROT_ARG_KC:
379 len += trace_key_dump(interp,
380 Parrot_pcc_get_pmc_constant(interp,
381 CURRENT_CONTEXT(interp), o));
382 break;
383 case PARROT_ARG_KIC:
384 len += Parrot_io_eprintf(debugger, "[%vd]", o);
385 break;
386 case PARROT_ARG_KI:
387 len += Parrot_io_eprintf(debugger, "[I%vd]", o);
388 more = 1;
389 break;
390 case PARROT_ARG_K:
391 len += Parrot_io_eprintf(debugger, "[P%vd]", o);
392 more = 1;
393 break;
394 case PARROT_ARG_I:
395 len += Parrot_io_eprintf(debugger, "I%vd", o);
396 more = 1;
397 break;
398 case PARROT_ARG_N:
399 len += Parrot_io_eprintf(debugger, "N%vd", o);
400 more = 1;
401 break;
402 case PARROT_ARG_P:
403 len += Parrot_io_eprintf(debugger, "P%vd", o);
404 more = 1;
405 break;
406 case PARROT_ARG_S:
407 len += Parrot_io_eprintf(debugger, "S%vd", o);
408 more = 1;
409 break;
410 default:
411 Parrot_ex_throw_from_c_args(interp, NULL, 1,
412 "unhandled type in trace");
413 break;
417 if (!more)
418 goto done;
420 if (len < ARGS_COLUMN) {
421 STRING * const fill = Parrot_str_repeat(debugger,
422 Parrot_str_new_constant(debugger, " "), ARGS_COLUMN);
423 Parrot_io_putps(debugger, Parrot_io_STDERR(debugger), fill);
425 else
426 Parrot_io_eprintf(debugger, "\t");
428 /* pass 2 print argument details if needed */
429 for (i = 1; i < n; ++i) {
430 const opcode_t o = pc[i];
431 if (i < info->op_count)
432 type = info->types[i - 1];
433 else
434 type = VTABLE_get_integer_keyed_int(interp, sig, i - 2) &
435 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
437 if (i > s)
438 Parrot_io_eprintf(debugger, " ");
440 switch (type) {
441 case PARROT_ARG_I:
442 Parrot_io_eprintf(debugger, "I%vd=%vd", o, REG_INT(interp, o));
443 break;
444 case PARROT_ARG_N:
445 Parrot_io_eprintf(debugger, "N%vd=%vf", o, REG_NUM(interp, o));
446 break;
447 case PARROT_ARG_PC:
448 Parrot_io_eprintf(debugger, "PC%vd=", o);
449 trace_pmc_dump(interp, Parrot_pcc_get_pmc_constant(interp,
450 CURRENT_CONTEXT(interp), o));
451 break;
452 case PARROT_ARG_P:
453 Parrot_io_eprintf(debugger, "P%vd=", o);
454 trace_pmc_dump(interp, REG_PMC(interp, o));
455 break;
456 case PARROT_ARG_S:
457 if (REG_STR(interp, o)) {
458 STRING * const escaped = Parrot_str_escape_truncate(
459 interp, REG_STR(interp, o), 20);
460 Parrot_io_eprintf(debugger, "S%vd=\"%Ss\"", o, escaped);
462 else
463 Parrot_io_eprintf(debugger, "S%vd=\"(null)\"", o);
464 break;
465 case PARROT_ARG_K:
466 Parrot_io_eprintf(debugger, "P%vd=", o);
467 trace_key_dump(interp, REG_PMC(interp, *(pc + i)));
468 break;
469 case PARROT_ARG_KI:
470 Parrot_io_eprintf(debugger, "I%vd=[%vd]", o, REG_INT(interp, o));
471 break;
472 default:
473 break;
477 done:
479 if (interp->code->annotations) {
480 PMC * const annot = PackFile_Annotations_lookup(interp,
481 interp->code->annotations, pc - code_start + 1, NULL);
483 if (!PMC_IS_NULL(annot)) {
484 PMC * const pfile = VTABLE_get_pmc_keyed_str(interp, annot,
485 Parrot_str_new_constant(interp, "file"));
486 PMC * const pline = VTABLE_get_pmc_keyed_str(interp, annot,
487 Parrot_str_new_constant(interp, "line"));
489 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
490 /* The debugger interpreter may not be the same as
491 * the main interpreter, extract values from the
492 * PMC instad of passing them directly */
493 STRING * const file = VTABLE_get_string(interp, pfile);
494 const INTVAL line = VTABLE_get_integer(interp, pline);
495 Parrot_io_eprintf(debugger, " (%Ss:%li)", file, (long)line);
500 Parrot_io_eprintf(debugger, "\n");
506 =item C<void trace_op(PARROT_INTERP, const opcode_t *code_start, const opcode_t
507 *code_end, const opcode_t *pc)>
509 Prints the PC, OP and ARGS. Used by C<runops_trace()>. With bounds checking.
511 I<Not really part of the API.>
513 =cut
517 void
518 trace_op(PARROT_INTERP,
519 ARGIN(const opcode_t *code_start),
520 ARGIN(const opcode_t *code_end),
521 ARGIN_NULLOK(const opcode_t *pc))
523 ASSERT_ARGS(trace_op)
525 if (!pc)
526 return;
528 if (pc >= code_start && pc < code_end)
529 trace_op_dump(interp, code_start, pc);
530 else
531 Parrot_io_eprintf(interp, "PC=%ld; OP=<err>\n",
532 (long)(pc - code_start));
538 =back
540 =head1 SEE ALSO
542 F<src/trace.h>
544 =cut
550 * Local variables:
551 * c-file-style: "parrot"
552 * End:
553 * vim: expandtab shiftwidth=4: