2 Copyright (C) 2001-2007, The Perl Foundation.
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.
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.
52 PARROT_WARN_UNUSED_RESULT
53 PARROT_CANNOT_RETURN_NULL
55 trace_class_name(ARGIN(const PMC
* pmc
))
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
,
62 class_name
= PMC_str_val(class_name_pmc
);
65 class_name
= pmc
->vtable
->whoami
;
71 =item C<void trace_pmc_dump>
73 Prints a PMC to C<stderr>.
80 trace_pmc_dump(PARROT_INTERP
, ARGIN_NULLOK(PMC
*pmc
))
82 Interp
* const debugger
= interp
->debugger
;
85 PIO_eprintf(debugger
, "(null)");
88 if (PMC_IS_NULL(pmc
)) {
89 PIO_eprintf(debugger
, "PMCNULL");
92 if (!pmc
->vtable
|| (UINTVAL
)pmc
->vtable
== 0xdeadbeef) {
93 PIO_eprintf(debugger
, "<!!no vtable!!>");
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
);
106 PIO_eprintf(debugger
, "%S=PMC(%#p Str:(NULL))",
107 VTABLE_name(interp
, pmc
), pmc
);
109 STRING
* const escaped
= string_escape_string_delimited(
112 PIO_eprintf(debugger
, "%S=PMC(%#p Str:\"%Ss\")",
113 VTABLE_name(interp
, pmc
), pmc
,
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)",
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)",
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
);
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.
169 trace_key_dump(PARROT_INTERP
, ARGIN(const PMC
*key
))
171 Interp
* const debugger
= interp
->debugger
;
173 int len
= PIO_eprintf(debugger
, "[");
176 switch (PObj_get_FLAGS(key
) & KEY_type_FLAGS
) {
177 case KEY_integer_FLAG
:
178 len
+= PIO_eprintf(debugger
, "%vi", PMC_int_val(key
));
180 case KEY_number_FLAG
:
181 len
+= PIO_eprintf(debugger
, "%vg", PMC_num_val(key
));
183 case KEY_string_FLAG
:
185 const STRING
* const s
= PMC_str_val(key
);
186 STRING
* const escaped
= string_escape_string_delimited(
189 len
+= PIO_eprintf(debugger
, "\"%Ss\"", escaped
);
191 len
+= PIO_eprintf(debugger
, "\"(null)\"");
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
)));
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
)));
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(
208 len
+= PIO_eprintf(debugger
, "S%vd=\"%Ss\"", PMC_int_val(key
),
211 len
+= PIO_eprintf(debugger
, "S%vd=\"(null)\"",
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
)));
220 len
+= PIO_eprintf(debugger
, "??");
226 key
= (PMC
*)PMC_data(key
);
228 len
+= PIO_eprintf(debugger
, ";");
232 len
+= PIO_eprintf(debugger
, "]");
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()>.
249 trace_op_dump(PARROT_INTERP
,
250 ARGIN(const opcode_t
*code_start
),
251 ARGIN(const opcode_t
*pc
))
254 int more
= 0, var_args
;
255 Interp
* const debugger
= interp
->debugger
;
256 op_info_t
* const info
= &interp
->op_info_table
[*pc
];
260 #define ARGS_COLUMN 40
262 PARROT_ASSERT(debugger
);
263 sig
= NULL
; /* silence compiler uninit warning */
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
271 len
+= PIO_eprintf(debugger
, "%s",
272 Parrot_MMD_method_name(interp
, pc
[1]) + 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);
281 len
+= PIO_eprintf(debugger
, "%s", info
->name
);
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
;
292 real_exception(interp
, NULL
, 1,
293 "NULL sig PMC detected in trace_op_dump");
295 var_args
= VTABLE_elements(interp
, sig
);
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];
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
);
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
, ", ");
325 len
+= PIO_eprintf(debugger
, "%vd", o
);
328 len
+= PIO_eprintf(debugger
, "%vg", PCONST(o
)->u
.number
);
332 len
+= PIO_eprintf(debugger
, "PC%d (%d)",
335 len
+= PIO_eprintf(debugger
, "PC%d", (int)o
);
339 STRING
* const escaped
= string_escape_string_delimited(
341 PCONST(o
)->u
.string
, 20);
343 len
+= PIO_eprintf(debugger
, "\"%Ss\"", escaped
);
345 len
+= PIO_eprintf(debugger
, "\"(null)\"");
349 len
+= trace_key_dump(interp
, PCONST(o
)->u
.key
);
352 len
+= PIO_eprintf(debugger
, "[%vd]", o
);
355 len
+= PIO_eprintf(debugger
, "[I%vd]", o
);
359 len
+= PIO_eprintf(debugger
, "[P%vd]", o
);
363 len
+= PIO_eprintf(debugger
, "I%vd", o
);
367 len
+= PIO_eprintf(debugger
, "N%vd", o
);
371 len
+= PIO_eprintf(debugger
, "P%vd", o
);
375 len
+= PIO_eprintf(debugger
, "S%vd", o
);
379 real_exception(interp
, NULL
, 1, "unhandled type in trace");
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
);
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];
401 type
= SIG_ITEM(sig
, i
- 2) &
402 (PARROT_ARG_TYPE_MASK
|PARROT_ARG_CONSTANT
);
404 PIO_eprintf(debugger
, " ");
408 PIO_eprintf(debugger
, "I%vd=%vd", o
, REG_INT(interp
, o
));
411 PIO_eprintf(debugger
, "N%vd=%vf", o
, REG_NUM(interp
, o
));
414 PIO_eprintf(debugger
, "PC%vd=", o
);
415 trace_pmc_dump(interp
, PCONST(o
)->u
.key
);
418 PIO_eprintf(debugger
, "P%vd=", o
);
419 trace_pmc_dump(interp
, REG_PMC(interp
, o
));
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
,
429 PIO_eprintf(debugger
, "S%vd=\"(null)\"", o
);
432 PIO_eprintf(debugger
, "P%vd=", o
);
433 trace_key_dump(interp
, REG_PMC(interp
, *(pc
+ i
)));
436 PIO_eprintf(debugger
, "I%vd=[%vd]", o
, REG_INT(interp
, o
));
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
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
))
470 if (pc
>= code_start
&& pc
< code_end
)
471 trace_op_dump(interp
, code_start
, pc
);
473 PIO_eprintf(interp
, "PC=%ld; OP=<err>\n", (long)(pc
- code_start
));
491 * c-file-style: "parrot"
493 * vim: expandtab shiftwidth=4: