[t][TT #1119] Convert t/op/bitwise.t to PIR
[parrot.git] / src / runcore / trace.c
blobc42a9ff816400a6650bb538bb208b8f9fbf33837
1 /*
2 Copyright (C) 2001-2009, 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 "pmc/pmc_sub.h"
29 #include "pmc/pmc_context.h"
31 /* HEADERIZER HFILE: include/parrot/runcore_trace.h */
33 /* HEADERIZER BEGIN: static */
34 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
36 PARROT_WARN_UNUSED_RESULT
37 PARROT_CANNOT_RETURN_NULL
38 static STRING* trace_class_name(PARROT_INTERP, ARGIN(const PMC* pmc))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(2);
42 #define ASSERT_ARGS_trace_class_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
43 PARROT_ASSERT_ARG(interp) \
44 , PARROT_ASSERT_ARG(pmc))
45 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
46 /* HEADERIZER END: static */
50 =item C<Interp * debugger_or_interp(PARROT_INTERP)>
52 Get debugger if available
54 =cut
56 PARROT_CANNOT_RETURN_NULL
57 Interp *
58 debugger_or_interp(PARROT_INTERP) {
59 ASSERT_ARGS(debugger_or_interp)
61 return interp->pdb && interp->pdb->debugger
62 ? interp->pdb->debugger
63 : interp;
68 =item C<static STRING* trace_class_name(PARROT_INTERP, const PMC* pmc)>
70 Obtains the class name of the PMC.
72 =cut
76 PARROT_WARN_UNUSED_RESULT
77 PARROT_CANNOT_RETURN_NULL
78 static STRING*
79 trace_class_name(PARROT_INTERP, ARGIN(const PMC* pmc))
81 ASSERT_ARGS(trace_class_name)
82 STRING *class_name;
83 if (PObj_is_class_TEST(pmc)) {
84 SLOTTYPE * const class_array = (SLOTTYPE *)PMC_data(pmc);
85 PMC * const class_name_pmc = get_attrib_num(class_array,
86 PCD_CLASS_NAME);
87 class_name = VTABLE_get_string(interp, class_name_pmc);
89 else
90 class_name = pmc->vtable->whoami;
91 return class_name;
96 =item C<void trace_pmc_dump(PARROT_INTERP, PMC *pmc)>
98 Prints a PMC to C<stderr>.
100 =cut
104 void
105 trace_pmc_dump(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc))
107 ASSERT_ARGS(trace_pmc_dump)
108 Interp * const debugger = debugger_or_interp(interp);
109 Parrot_Sub_attributes *sub;
111 if (!pmc) {
112 Parrot_io_eprintf(debugger, "(null)");
113 return;
115 if (PMC_IS_NULL(pmc)) {
116 Parrot_io_eprintf(debugger, "PMCNULL");
117 return;
119 if (!pmc->vtable || (UINTVAL)pmc->vtable == 0xdeadbeef) {
120 Parrot_io_eprintf(debugger, "<!!no vtable!!>");
121 return;
123 if (PObj_on_free_list_TEST(pmc)) {
124 Parrot_io_eprintf(debugger, "**************** PMC is on free list *****\n");
126 if (pmc->vtable->pmc_class == pmc) {
127 STRING * const name = trace_class_name(interp, pmc);
128 Parrot_io_eprintf(debugger, "Class=%Ss:PMC(%#p)", name, pmc);
130 else if (pmc->vtable->base_type == enum_class_String) {
131 const STRING * const s = VTABLE_get_string(interp, pmc);
132 if (!s)
133 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:(NULL))",
134 VTABLE_name(interp, pmc), pmc);
135 else {
136 STRING* const escaped = Parrot_str_escape_truncate(
137 interp, s, 20);
138 if (escaped)
139 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:\"%Ss\")",
140 VTABLE_name(interp, pmc), pmc,
141 escaped);
142 else
143 Parrot_io_eprintf(debugger, "%S=PMC(%#p Str:\"(null)\")",
144 VTABLE_name(interp, pmc), pmc);
147 else if (pmc->vtable->base_type == enum_class_Boolean) {
148 Parrot_io_eprintf(debugger, "Boolean=PMC(%#p: %d)",
149 pmc, VTABLE_get_integer(interp, pmc));
151 else if (pmc->vtable->base_type == enum_class_Integer) {
152 Parrot_io_eprintf(debugger, "Integer=PMC(%#p: %d)",
153 pmc, VTABLE_get_integer(interp, pmc));
155 else if (pmc->vtable->base_type == enum_class_BigInt) {
156 STRING * const s = VTABLE_get_string(interp, pmc);
157 Parrot_io_eprintf(debugger, "BigInt=PMC(%#p: %Ss)",
158 pmc, s);
160 else if (pmc->vtable->base_type == enum_class_Complex) {
161 STRING * const s = VTABLE_get_string(interp, pmc);
162 Parrot_io_eprintf(debugger, "Complex=PMC(%#p: %Ss)",
163 pmc, s);
165 else if (pmc->vtable->base_type == enum_class_Sub) {
166 PMC_get_sub(interp, pmc, sub);
167 Parrot_io_eprintf(debugger, "%S=PMC(%#p pc:%d)",
168 VTABLE_name(interp, pmc), pmc, sub->start_offs);
170 else if (PObj_is_object_TEST(pmc)) {
171 Parrot_io_eprintf(debugger, "Object(%Ss)=PMC(%#p)",
172 VTABLE_get_string(interp, VTABLE_get_class(interp, pmc)), pmc);
174 else {
175 Parrot_io_eprintf(debugger, "%S=PMC(%#p)",
176 VTABLE_name(interp, pmc), pmc);
182 =item C<int trace_key_dump(PARROT_INTERP, PMC *key)>
184 Prints a key to C<stderr>, returns the length of the output.
186 =cut
191 trace_key_dump(PARROT_INTERP, ARGIN(PMC *key))
193 ASSERT_ARGS(trace_key_dump)
194 Interp * const debugger = debugger_or_interp(interp);
196 int len = Parrot_io_eprintf(debugger, "[");
198 while (key) {
199 switch (PObj_get_FLAGS(key) & KEY_type_FLAGS) {
200 case KEY_integer_FLAG:
201 len += Parrot_io_eprintf(debugger, "%vi", VTABLE_get_integer(interp, key));
202 break;
203 case KEY_number_FLAG:
204 len += Parrot_io_eprintf(debugger, "%vg", VTABLE_get_number(interp, key));
205 break;
206 case KEY_string_FLAG:
208 const STRING * const s = key_string(interp, key);
209 STRING* const escaped = Parrot_str_escape_truncate(
210 interp, s, 20);
211 if (escaped)
212 len += Parrot_io_eprintf(debugger, "\"%Ss\"", escaped);
213 else
214 len += Parrot_io_eprintf(debugger, "\"(null)\"");
216 break;
217 case KEY_integer_FLAG|KEY_register_FLAG:
218 len += Parrot_io_eprintf(debugger, "I%vd=%vd", VTABLE_get_integer(interp, key),
219 REG_INT(interp, VTABLE_get_integer(interp, key)));
220 break;
221 case KEY_number_FLAG|KEY_register_FLAG:
222 len += Parrot_io_eprintf(debugger, "I%vd=%vd", VTABLE_get_integer(interp, key),
223 REG_NUM(interp, VTABLE_get_integer(interp, key)));
224 break;
225 case KEY_string_FLAG|KEY_register_FLAG:
227 const STRING * const s = REG_STR(interp, VTABLE_get_integer(interp, key));
228 STRING* const escaped = Parrot_str_escape_truncate(
229 interp, s, 20);
230 if (escaped)
231 len += Parrot_io_eprintf(debugger, "S%vd=\"%Ss\"", VTABLE_get_integer(interp, key),
232 escaped);
233 else
234 len += Parrot_io_eprintf(debugger, "S%vd=\"(null)\"",
235 VTABLE_get_integer(interp, key));
237 break;
238 case KEY_pmc_FLAG|KEY_register_FLAG:
239 len += Parrot_io_eprintf(debugger, "P%vd=", VTABLE_get_integer(interp, key));
240 trace_pmc_dump(debugger, REG_PMC(interp, VTABLE_get_integer(interp, key)));
241 break;
242 default:
243 len += Parrot_io_eprintf(debugger, "??");
244 key = NULL;
245 break;
248 if (key) {
249 key = VTABLE_shift_pmc(interp, key);
250 if (key)
251 len += Parrot_io_eprintf(debugger, ";");
253 } /* while */
255 len += Parrot_io_eprintf(debugger, "]");
256 return len;
261 =item C<void trace_op_dump(PARROT_INTERP, const opcode_t *code_start, const
262 opcode_t *pc)>
264 Prints the PC, OP and ARGS. Used by C<trace_op()>.
266 I<Not really part of the API.>
268 =cut
272 void
273 trace_op_dump(PARROT_INTERP,
274 ARGIN(const opcode_t *code_start),
275 ARGIN(const opcode_t *pc))
277 ASSERT_ARGS(trace_op_dump)
278 INTVAL s, n;
279 int more = 0, var_args;
280 Interp * const debugger = debugger_or_interp(interp);
281 op_info_t * const info = &interp->op_info_table[*pc];
282 PMC *sig;
283 int type;
284 int len;
285 #define ARGS_COLUMN 40
287 PARROT_ASSERT(debugger);
288 sig = NULL; /* silence compiler uninit warning */
290 s = 1;
291 len = Parrot_io_eprintf(debugger, "%6vu ", (UINTVAL)(pc - code_start));
292 len += Parrot_io_eprintf(debugger, "%s", info->name);
294 n = info->op_count;
295 var_args = 0;
297 if (*pc == PARROT_OP_set_args_pc ||
298 *pc == PARROT_OP_get_results_pc ||
299 *pc == PARROT_OP_get_params_pc ||
300 *pc == PARROT_OP_set_returns_pc) {
301 sig = interp->code->const_table->constants[pc[1]]->u.key;
303 if (!sig)
304 Parrot_ex_throw_from_c_args(interp, NULL, 1,
305 "NULL sig PMC detected in trace_op_dump");
307 var_args = VTABLE_elements(interp, sig);
308 n += var_args;
311 if (n > 1) {
312 INTVAL i;
313 len += Parrot_io_eprintf(debugger, " ");
314 /* pass 1 print arguments */
315 for (i = s; i < n; i++) {
316 const opcode_t o = pc[i];
317 if (i < info->op_count) {
318 type = info->types[i - 1];
320 else {
321 if (!sig)
322 Parrot_ex_throw_from_c_args(interp, NULL, 1,
323 "NULL sig PMC detected in trace_op_dump");
325 type = VTABLE_get_integer_keyed_int(interp, sig, i - 2) &
326 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
328 if (i > s &&
329 type != PARROT_ARG_KC &&
330 type != PARROT_ARG_KIC &&
331 type != PARROT_ARG_KI &&
332 type != PARROT_ARG_K) {
333 len += Parrot_io_eprintf(debugger, ", ");
335 switch (type) {
336 case PARROT_ARG_IC:
337 len += Parrot_io_eprintf(debugger, "%vd", o);
338 break;
339 case PARROT_ARG_NC:
340 len += Parrot_io_eprintf(debugger, "%vg", PCONST(o)->u.number);
341 break;
342 case PARROT_ARG_PC:
343 if (var_args)
344 len += Parrot_io_eprintf(debugger, "PC%d (%d)",
345 (int)o, var_args);
346 else
347 len += Parrot_io_eprintf(debugger, "PC%d", (int)o);
348 break;
349 case PARROT_ARG_SC:
351 STRING* const escaped = Parrot_str_escape_truncate(
352 interp,
353 PCONST(o)->u.string, 20);
354 if (escaped)
355 len += Parrot_io_eprintf(debugger, "\"%Ss\"", escaped);
356 else
357 len += Parrot_io_eprintf(debugger, "\"(null)\"");
359 break;
360 case PARROT_ARG_KC:
361 len += trace_key_dump(interp, PCONST(o)->u.key);
362 break;
363 case PARROT_ARG_KIC:
364 len += Parrot_io_eprintf(debugger, "[%vd]", o);
365 break;
366 case PARROT_ARG_KI:
367 len += Parrot_io_eprintf(debugger, "[I%vd]", o);
368 more = 1;
369 break;
370 case PARROT_ARG_K:
371 len += Parrot_io_eprintf(debugger, "[P%vd]", o);
372 more = 1;
373 break;
374 case PARROT_ARG_I:
375 len += Parrot_io_eprintf(debugger, "I%vd", o);
376 more = 1;
377 break;
378 case PARROT_ARG_N:
379 len += Parrot_io_eprintf(debugger, "N%vd", o);
380 more = 1;
381 break;
382 case PARROT_ARG_P:
383 len += Parrot_io_eprintf(debugger, "P%vd", o);
384 more = 1;
385 break;
386 case PARROT_ARG_S:
387 len += Parrot_io_eprintf(debugger, "S%vd", o);
388 more = 1;
389 break;
390 default:
391 Parrot_ex_throw_from_c_args(interp, NULL, 1,
392 "unhandled type in trace");
393 break;
396 if (!more)
397 goto done;
398 if (len < ARGS_COLUMN) {
399 STRING * const fill = Parrot_str_repeat(debugger,
400 Parrot_str_new_constant(debugger, " "),
401 ARGS_COLUMN);
402 Parrot_io_putps(debugger, Parrot_io_STDERR(debugger), fill);
404 else {
405 Parrot_io_eprintf(debugger, "\t");
408 /* pass 2 print argument details if needed */
409 for (i = 1; i < n; i++) {
410 const opcode_t o = pc[i];
411 if (i < info->op_count)
412 type = info->types[i - 1];
413 else
414 type = VTABLE_get_integer_keyed_int(interp, sig, i - 2) &
415 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
416 if (i > s) {
417 Parrot_io_eprintf(debugger, " ");
419 switch (type) {
420 case PARROT_ARG_I:
421 Parrot_io_eprintf(debugger, "I%vd=%vd", o, REG_INT(interp, o));
422 break;
423 case PARROT_ARG_N:
424 Parrot_io_eprintf(debugger, "N%vd=%vf", o, REG_NUM(interp, o));
425 break;
426 case PARROT_ARG_PC:
427 Parrot_io_eprintf(debugger, "PC%vd=", o);
428 trace_pmc_dump(interp, PCONST(o)->u.key);
429 break;
430 case PARROT_ARG_P:
431 Parrot_io_eprintf(debugger, "P%vd=", o);
432 trace_pmc_dump(interp, REG_PMC(interp, o));
433 break;
434 case PARROT_ARG_S:
435 if (REG_STR(interp, o)) {
436 STRING* const escaped = Parrot_str_escape_truncate(
437 interp, REG_STR(interp, o), 20);
438 Parrot_io_eprintf(debugger, "S%vd=\"%Ss\"", o,
439 escaped);
441 else
442 Parrot_io_eprintf(debugger, "S%vd=\"(null)\"", o);
443 break;
444 case PARROT_ARG_K:
445 Parrot_io_eprintf(debugger, "P%vd=", o);
446 trace_key_dump(interp, REG_PMC(interp, *(pc + i)));
447 break;
448 case PARROT_ARG_KI:
449 Parrot_io_eprintf(debugger, "I%vd=[%vd]", o, REG_INT(interp, o));
450 break;
451 default:
452 break;
456 done:
458 if (interp->code->annotations) {
459 PMC * const annot = PackFile_Annotations_lookup(interp, interp->code->annotations,
460 pc - code_start + 1, NULL);
461 if (!PMC_IS_NULL(annot)) {
462 PMC * const pfile = VTABLE_get_pmc_keyed_str(interp, annot,
463 Parrot_str_new_constant(interp, "file"));
464 PMC * const pline = VTABLE_get_pmc_keyed_str(interp, annot,
465 Parrot_str_new_constant(interp, "line"));
466 if ((!PMC_IS_NULL(pfile)) && (!PMC_IS_NULL(pline))) {
467 /* The debugger interpreter may not be the same as
468 * the main interpreter, extract values from the
469 * PMC instad of passing them directly
471 STRING * const file = VTABLE_get_string(interp, pfile);
472 const INTVAL line = VTABLE_get_integer(interp, pline);
473 Parrot_io_eprintf(debugger, " (%Ss:%li)", file, (long)line);
478 Parrot_io_eprintf(debugger, "\n");
483 =item C<void trace_op(PARROT_INTERP, const opcode_t *code_start, const opcode_t
484 *code_end, const opcode_t *pc)>
486 Prints the PC, OP and ARGS. Used by C<runops_trace()>. With bounds
487 checking.
489 I<Not really part of the API.>
491 =cut
495 void
496 trace_op(PARROT_INTERP,
497 ARGIN(const opcode_t *code_start),
498 ARGIN(const opcode_t *code_end),
499 ARGIN_NULLOK(const opcode_t *pc))
501 ASSERT_ARGS(trace_op)
502 if (!pc) {
503 return;
506 if (pc >= code_start && pc < code_end)
507 trace_op_dump(interp, code_start, pc);
508 else
509 Parrot_io_eprintf(interp, "PC=%ld; OP=<err>\n", (long)(pc - code_start));
514 =back
516 =head1 SEE ALSO
518 F<src/trace.h>
520 =cut
526 * Local variables:
527 * c-file-style: "parrot"
528 * End:
529 * vim: expandtab shiftwidth=4: