* t/op/lexicals-2.t (added), MANIFEST:
[parrot.git] / src / trace.c
blob82c6b4a9b1fa349780597f323933fbf5088a5be7
1 /*
2 Copyright (C) 2001-2007, The Perl 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 F<src/runops_cores.c>.
13 This is turned on with Parrot's C<-t> option.
15 src/test_main.c
17 =head2 Functions
19 =over 4
21 =cut
25 #include "trace.h"
26 #include "parrot/oplib/ops.h"
28 /* HEADERIZER HFILE: src/trace.h */
30 /* HEADERIZER BEGIN: static */
31 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
33 PARROT_WARN_UNUSED_RESULT
34 PARROT_CANNOT_RETURN_NULL
35 static STRING* trace_class_name(ARGIN(const PMC* pmc))
36 __attribute__nonnull__(1);
38 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
39 /* HEADERIZER END: static */
44 =item C<static STRING* trace_class_name>
46 Obtains the class name of the PMC.
48 =cut
52 PARROT_WARN_UNUSED_RESULT
53 PARROT_CANNOT_RETURN_NULL
54 static STRING*
55 trace_class_name(ARGIN(const PMC* pmc))
57 STRING *class_name;
58 if (PObj_is_class_TEST(pmc)) {
59 SLOTTYPE * const class_array = (SLOTTYPE *)PMC_data(pmc);
60 PMC * const class_name_pmc = get_attrib_num(class_array,
61 PCD_CLASS_NAME);
62 class_name = PMC_str_val(class_name_pmc);
64 else
65 class_name = pmc->vtable->whoami;
66 return class_name;
71 =item C<void trace_pmc_dump>
73 Prints a PMC to C<stderr>.
75 =cut
79 void
80 trace_pmc_dump(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc))
82 Interp * const debugger = interp->debugger;
84 if (!pmc) {
85 PIO_eprintf(debugger, "(null)");
86 return;
88 if (PMC_IS_NULL(pmc)) {
89 PIO_eprintf(debugger, "PMCNULL");
90 return;
92 if (!pmc->vtable || (UINTVAL)pmc->vtable == 0xdeadbeef) {
93 PIO_eprintf(debugger, "<!!no vtable!!>");
94 return;
96 if (PObj_on_free_list_TEST(pmc)) {
97 PIO_eprintf(debugger, "**************** PMC is on free list *****\n");
99 if (pmc->vtable->pmc_class == pmc) {
100 STRING * const name = trace_class_name(pmc);
101 PIO_eprintf(debugger, "Class=%Ss:PMC(%#p)", name, pmc);
103 else if (pmc->vtable->base_type == enum_class_String) {
104 const STRING * const s = VTABLE_get_string(interp, pmc);
105 if (!s)
106 PIO_eprintf(debugger, "%S=PMC(%#p Str:(NULL))",
107 VTABLE_name(interp, pmc), pmc);
108 else {
109 STRING* const escaped = string_escape_string_delimited(
110 interp, s, 20);
111 if (escaped)
112 PIO_eprintf(debugger, "%S=PMC(%#p Str:\"%Ss\")",
113 VTABLE_name(interp, pmc), pmc,
114 escaped);
115 else
116 PIO_eprintf(debugger, "%S=PMC(%#p Str:\"(null)\")",
117 VTABLE_name(interp, pmc), pmc);
120 else if (pmc->vtable->base_type == enum_class_Boolean) {
121 PIO_eprintf(debugger, "Boolean=PMC(%#p: %d)",
122 pmc, PMC_int_val(pmc));
124 else if (pmc->vtable->base_type == enum_class_Integer) {
125 PIO_eprintf(debugger, "Integer=PMC(%#p: %d)",
126 pmc, PMC_int_val(pmc));
128 else if (pmc->vtable->base_type == enum_class_BigInt) {
129 STRING * const s = VTABLE_get_string(interp, pmc);
130 PIO_eprintf(debugger, "BigInt=PMC(%#p: %Ss)",
131 pmc, s);
133 else if (pmc->vtable->base_type == enum_class_Complex) {
134 STRING * const s = VTABLE_get_string(interp, pmc);
135 PIO_eprintf(debugger, "Complex=PMC(%#p: %Ss)",
136 pmc, s);
138 else if (pmc->vtable->base_type == enum_class_RetContinuation
139 || pmc->vtable->base_type == enum_class_Continuation
140 || pmc->vtable->base_type == enum_class_Sub) {
141 PIO_eprintf(debugger, "%S=PMC(%#p pc:%d)",
142 VTABLE_name(interp, pmc), pmc,
143 PMC_sub(pmc)->start_offs);
145 else if (PObj_is_object_TEST(pmc)) {
146 PIO_eprintf(debugger, "Object(%Ss)=PMC(%#p)",
147 VTABLE_get_string(interp, VTABLE_get_class(interp, pmc)), pmc);
149 else if (pmc->vtable->base_type == enum_class_delegate) {
150 PIO_eprintf(debugger, "delegate=PMC(%#p)", pmc);
152 else {
153 PIO_eprintf(debugger, "%S=PMC(%#p)",
154 VTABLE_name(interp, pmc), pmc);
160 =item C<int trace_key_dump>
162 Prints a key to C<stderr>, returns the length of the output.
164 =cut
169 trace_key_dump(PARROT_INTERP, ARGIN(const PMC *key))
171 Interp * const debugger = interp->debugger;
173 int len = PIO_eprintf(debugger, "[");
175 while (key) {
176 switch (PObj_get_FLAGS(key) & KEY_type_FLAGS) {
177 case KEY_integer_FLAG:
178 len += PIO_eprintf(debugger, "%vi", PMC_int_val(key));
179 break;
180 case KEY_number_FLAG:
181 len += PIO_eprintf(debugger, "%vg", PMC_num_val(key));
182 break;
183 case KEY_string_FLAG:
185 const STRING * const s = PMC_str_val(key);
186 STRING* const escaped = string_escape_string_delimited(
187 interp, s, 20);
188 if (escaped)
189 len += PIO_eprintf(debugger, "\"%Ss\"", escaped);
190 else
191 len += PIO_eprintf(debugger, "\"(null)\"");
193 break;
194 case KEY_integer_FLAG|KEY_register_FLAG:
195 len += PIO_eprintf(debugger, "I%vd=%vd", PMC_int_val(key),
196 REG_INT(interp, PMC_int_val(key)));
197 break;
198 case KEY_number_FLAG|KEY_register_FLAG:
199 len += PIO_eprintf(debugger, "I%vd=%vd", PMC_int_val(key),
200 REG_NUM(interp, PMC_int_val(key)));
201 break;
202 case KEY_string_FLAG|KEY_register_FLAG:
204 const STRING * const s = REG_STR(interp, PMC_int_val(key));
205 STRING* const escaped = string_escape_string_delimited(
206 interp, s, 20);
207 if (escaped)
208 len += PIO_eprintf(debugger, "S%vd=\"%Ss\"", PMC_int_val(key),
209 escaped);
210 else
211 len += PIO_eprintf(debugger, "S%vd=\"(null)\"",
212 PMC_int_val(key));
214 break;
215 case KEY_pmc_FLAG|KEY_register_FLAG:
216 len += PIO_eprintf(debugger, "P%vd=", PMC_int_val(key));
217 trace_pmc_dump(debugger, REG_PMC(interp, PMC_int_val(key)));
218 break;
219 default:
220 len += PIO_eprintf(debugger, "??");
221 key = NULL;
222 break;
225 if (key) {
226 key = (PMC *)PMC_data(key);
227 if (key)
228 len += PIO_eprintf(debugger, ";");
230 } /* while */
232 len += PIO_eprintf(debugger, "]");
233 return len;
238 =item C<void trace_op_dump>
240 TODO: This isn't really part of the API, but here's its documentation.
242 Prints the PC, OP and ARGS. Used by C<trace_op()>.
244 =cut
248 void
249 trace_op_dump(PARROT_INTERP,
250 ARGIN(const opcode_t *code_start),
251 ARGIN(const opcode_t *pc))
253 INTVAL s, n;
254 int more = 0, var_args;
255 Interp * const debugger = interp->debugger;
256 op_info_t * const info = &interp->op_info_table[*pc];
257 PMC *sig;
258 int type;
259 int len;
260 #define ARGS_COLUMN 40
262 PARROT_ASSERT(debugger);
263 sig = NULL; /* silence compiler uninit warning */
265 s = 1;
266 len = PIO_eprintf(debugger, "%6vu ", (UINTVAL)(pc - code_start));
267 if (STREQ(info->name, "infix")) {
268 /* this should rather be MMD_opcode_name, which doesn't
269 * exit yet
271 len += PIO_eprintf(debugger, "%s",
272 Parrot_MMD_method_name(interp, pc[1]) + 2);
273 s = 2;
275 else if (STREQ(info->name, "n_infix")) {
276 len += PIO_eprintf(debugger, "n_%s",
277 Parrot_MMD_method_name(interp, pc[1]) + 2);
278 s = 2;
280 else
281 len += PIO_eprintf(debugger, "%s", info->name);
283 n = info->op_count;
284 var_args = 0;
286 if (*pc == PARROT_OP_set_args_pc ||
287 *pc == PARROT_OP_get_results_pc ||
288 *pc == PARROT_OP_get_params_pc ||
289 *pc == PARROT_OP_set_returns_pc) {
290 sig = interp->code->const_table->constants[pc[1]]->u.key;
291 if (!sig) {
292 real_exception(interp, NULL, 1,
293 "NULL sig PMC detected in trace_op_dump");
295 var_args = VTABLE_elements(interp, sig);
296 n += var_args;
299 if (n > 1) {
300 INTVAL i;
301 len += PIO_eprintf(debugger, " ");
302 /* pass 1 print arguments */
303 for (i = s; i < n; i++) {
304 const opcode_t o = pc[i];
305 if (i < info->op_count) {
306 type = info->types[i - 1];
308 else {
309 if (!sig) {
310 real_exception(interp, NULL, 1,
311 "NULL sig PMC detected in trace_op_dump");
313 type = SIG_ITEM(sig, i - 2) &
314 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
316 if (i > s &&
317 type != PARROT_ARG_KC &&
318 type != PARROT_ARG_KIC &&
319 type != PARROT_ARG_KI &&
320 type != PARROT_ARG_K) {
321 len += PIO_eprintf(debugger, ", ");
323 switch (type) {
324 case PARROT_ARG_IC:
325 len += PIO_eprintf(debugger, "%vd", o);
326 break;
327 case PARROT_ARG_NC:
328 len += PIO_eprintf(debugger, "%vg", PCONST(o)->u.number);
329 break;
330 case PARROT_ARG_PC:
331 if (var_args)
332 len += PIO_eprintf(debugger, "PC%d (%d)",
333 (int)o, var_args);
334 else
335 len += PIO_eprintf(debugger, "PC%d", (int)o);
336 break;
337 case PARROT_ARG_SC:
339 STRING* const escaped = string_escape_string_delimited(
340 interp,
341 PCONST(o)->u.string, 20);
342 if (escaped)
343 len += PIO_eprintf(debugger, "\"%Ss\"", escaped);
344 else
345 len += PIO_eprintf(debugger, "\"(null)\"");
347 break;
348 case PARROT_ARG_KC:
349 len += trace_key_dump(interp, PCONST(o)->u.key);
350 break;
351 case PARROT_ARG_KIC:
352 len += PIO_eprintf(debugger, "[%vd]", o);
353 break;
354 case PARROT_ARG_KI:
355 len += PIO_eprintf(debugger, "[I%vd]", o);
356 more = 1;
357 break;
358 case PARROT_ARG_K:
359 len += PIO_eprintf(debugger, "[P%vd]", o);
360 more = 1;
361 break;
362 case PARROT_ARG_I:
363 len += PIO_eprintf(debugger, "I%vd", o);
364 more = 1;
365 break;
366 case PARROT_ARG_N:
367 len += PIO_eprintf(debugger, "N%vd", o);
368 more = 1;
369 break;
370 case PARROT_ARG_P:
371 len += PIO_eprintf(debugger, "P%vd", o);
372 more = 1;
373 break;
374 case PARROT_ARG_S:
375 len += PIO_eprintf(debugger, "S%vd", o);
376 more = 1;
377 break;
378 default:
379 real_exception(interp, NULL, 1, "unhandled type in trace");
380 break;
383 if (!more)
384 goto done;
385 if (len < ARGS_COLUMN) {
386 STRING * const fill = string_repeat(debugger,
387 const_string(debugger, " "),
388 ARGS_COLUMN - len, NULL);
389 PIO_putps(debugger, PIO_STDERR(debugger), fill);
391 else {
392 PIO_eprintf(debugger, "\t");
395 /* pass 2 print argument details if needed */
396 for (i = 1; i < n; i++) {
397 const opcode_t o = pc[i];
398 if (i < info->op_count)
399 type = info->types[i - 1];
400 else
401 type = SIG_ITEM(sig, i - 2) &
402 (PARROT_ARG_TYPE_MASK|PARROT_ARG_CONSTANT);
403 if (i > s) {
404 PIO_eprintf(debugger, " ");
406 switch (type) {
407 case PARROT_ARG_I:
408 PIO_eprintf(debugger, "I%vd=%vd", o, REG_INT(interp, o));
409 break;
410 case PARROT_ARG_N:
411 PIO_eprintf(debugger, "N%vd=%vf", o, REG_NUM(interp, o));
412 break;
413 case PARROT_ARG_PC:
414 PIO_eprintf(debugger, "PC%vd=", o);
415 trace_pmc_dump(interp, PCONST(o)->u.key);
416 break;
417 case PARROT_ARG_P:
418 PIO_eprintf(debugger, "P%vd=", o);
419 trace_pmc_dump(interp, REG_PMC(interp, o));
420 break;
421 case PARROT_ARG_S:
422 if (REG_STR(interp, o)) {
423 STRING* const escaped = string_escape_string_delimited(
424 interp, REG_STR(interp, o), 20);
425 PIO_eprintf(debugger, "S%vd=\"%Ss\"", o,
426 escaped);
428 else
429 PIO_eprintf(debugger, "S%vd=\"(null)\"", o);
430 break;
431 case PARROT_ARG_K:
432 PIO_eprintf(debugger, "P%vd=", o);
433 trace_key_dump(interp, REG_PMC(interp, *(pc + i)));
434 break;
435 case PARROT_ARG_KI:
436 PIO_eprintf(debugger, "I%vd=[%vd]", o, REG_INT(interp, o));
437 break;
438 default:
439 break;
443 done:
444 PIO_eprintf(debugger, "\n");
449 =item C<void trace_op>
451 TODO: This isn't really part of the API, but here's its documentation.
453 Prints the PC, OP and ARGS. Used by C<runops_trace()>. With bounds
454 checking.
456 =cut
460 void
461 trace_op(PARROT_INTERP,
462 ARGIN(const opcode_t *code_start),
463 ARGIN(const opcode_t *code_end),
464 ARGIN_NULLOK(const opcode_t *pc))
466 if (!pc) {
467 return;
470 if (pc >= code_start && pc < code_end)
471 trace_op_dump(interp, code_start, pc);
472 else
473 PIO_eprintf(interp, "PC=%ld; OP=<err>\n", (long)(pc - code_start));
478 =back
480 =head1 SEE ALSO
482 F<src/trace.h>
484 =cut
490 * Local variables:
491 * c-file-style: "parrot"
492 * End:
493 * vim: expandtab shiftwidth=4: