2 Copyright (C) 2001-2009, Parrot Foundation.
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.
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
56 PARROT_CANNOT_RETURN_NULL
58 debugger_or_interp(PARROT_INTERP
) {
59 ASSERT_ARGS(debugger_or_interp
)
61 return interp
->pdb
&& interp
->pdb
->debugger
62 ? interp
->pdb
->debugger
68 =item C<static STRING* trace_class_name(PARROT_INTERP, const PMC* pmc)>
70 Obtains the class name of the PMC.
76 PARROT_WARN_UNUSED_RESULT
77 PARROT_CANNOT_RETURN_NULL
79 trace_class_name(PARROT_INTERP
, ARGIN(const PMC
* pmc
))
81 ASSERT_ARGS(trace_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
,
87 class_name
= VTABLE_get_string(interp
, class_name_pmc
);
90 class_name
= pmc
->vtable
->whoami
;
96 =item C<void trace_pmc_dump(PARROT_INTERP, PMC *pmc)>
98 Prints a PMC to C<stderr>.
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
;
112 Parrot_io_eprintf(debugger
, "(null)");
115 if (PMC_IS_NULL(pmc
)) {
116 Parrot_io_eprintf(debugger
, "PMCNULL");
119 if (!pmc
->vtable
|| (UINTVAL
)pmc
->vtable
== 0xdeadbeef) {
120 Parrot_io_eprintf(debugger
, "<!!no vtable!!>");
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
);
133 Parrot_io_eprintf(debugger
, "%S=PMC(%#p Str:(NULL))",
134 VTABLE_name(interp
, pmc
), pmc
);
136 STRING
* const escaped
= Parrot_str_escape_truncate(
139 Parrot_io_eprintf(debugger
, "%S=PMC(%#p Str:\"%Ss\")",
140 VTABLE_name(interp
, pmc
), pmc
,
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)",
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)",
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
);
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.
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
, "[");
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
));
203 case KEY_number_FLAG
:
204 len
+= Parrot_io_eprintf(debugger
, "%vg", VTABLE_get_number(interp
, key
));
206 case KEY_string_FLAG
:
208 const STRING
* const s
= key_string(interp
, key
);
209 STRING
* const escaped
= Parrot_str_escape_truncate(
212 len
+= Parrot_io_eprintf(debugger
, "\"%Ss\"", escaped
);
214 len
+= Parrot_io_eprintf(debugger
, "\"(null)\"");
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
)));
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
)));
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(
231 len
+= Parrot_io_eprintf(debugger
, "S%vd=\"%Ss\"", VTABLE_get_integer(interp
, key
),
234 len
+= Parrot_io_eprintf(debugger
, "S%vd=\"(null)\"",
235 VTABLE_get_integer(interp
, key
));
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
)));
243 len
+= Parrot_io_eprintf(debugger
, "??");
249 key
= VTABLE_shift_pmc(interp
, key
);
251 len
+= Parrot_io_eprintf(debugger
, ";");
255 len
+= Parrot_io_eprintf(debugger
, "]");
261 =item C<void trace_op_dump(PARROT_INTERP, const opcode_t *code_start, const
264 Prints the PC, OP and ARGS. Used by C<trace_op()>.
266 I<Not really part of the API.>
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
)
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
];
285 #define ARGS_COLUMN 40
287 PARROT_ASSERT(debugger
);
288 sig
= NULL
; /* silence compiler uninit warning */
291 len
= Parrot_io_eprintf(debugger
, "%6vu ", (UINTVAL
)(pc
- code_start
));
292 len
+= Parrot_io_eprintf(debugger
, "%s", info
->name
);
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
;
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
);
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];
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
);
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
, ", ");
337 len
+= Parrot_io_eprintf(debugger
, "%vd", o
);
340 len
+= Parrot_io_eprintf(debugger
, "%vg", PCONST(o
)->u
.number
);
344 len
+= Parrot_io_eprintf(debugger
, "PC%d (%d)",
347 len
+= Parrot_io_eprintf(debugger
, "PC%d", (int)o
);
351 STRING
* const escaped
= Parrot_str_escape_truncate(
353 PCONST(o
)->u
.string
, 20);
355 len
+= Parrot_io_eprintf(debugger
, "\"%Ss\"", escaped
);
357 len
+= Parrot_io_eprintf(debugger
, "\"(null)\"");
361 len
+= trace_key_dump(interp
, PCONST(o
)->u
.key
);
364 len
+= Parrot_io_eprintf(debugger
, "[%vd]", o
);
367 len
+= Parrot_io_eprintf(debugger
, "[I%vd]", o
);
371 len
+= Parrot_io_eprintf(debugger
, "[P%vd]", o
);
375 len
+= Parrot_io_eprintf(debugger
, "I%vd", o
);
379 len
+= Parrot_io_eprintf(debugger
, "N%vd", o
);
383 len
+= Parrot_io_eprintf(debugger
, "P%vd", o
);
387 len
+= Parrot_io_eprintf(debugger
, "S%vd", o
);
391 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
392 "unhandled type in trace");
398 if (len
< ARGS_COLUMN
) {
399 STRING
* const fill
= Parrot_str_repeat(debugger
,
400 Parrot_str_new_constant(debugger
, " "),
402 Parrot_io_putps(debugger
, Parrot_io_STDERR(debugger
), fill
);
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];
414 type
= VTABLE_get_integer_keyed_int(interp
, sig
, i
- 2) &
415 (PARROT_ARG_TYPE_MASK
|PARROT_ARG_CONSTANT
);
417 Parrot_io_eprintf(debugger
, " ");
421 Parrot_io_eprintf(debugger
, "I%vd=%vd", o
, REG_INT(interp
, o
));
424 Parrot_io_eprintf(debugger
, "N%vd=%vf", o
, REG_NUM(interp
, o
));
427 Parrot_io_eprintf(debugger
, "PC%vd=", o
);
428 trace_pmc_dump(interp
, PCONST(o
)->u
.key
);
431 Parrot_io_eprintf(debugger
, "P%vd=", o
);
432 trace_pmc_dump(interp
, REG_PMC(interp
, o
));
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
,
442 Parrot_io_eprintf(debugger
, "S%vd=\"(null)\"", o
);
445 Parrot_io_eprintf(debugger
, "P%vd=", o
);
446 trace_key_dump(interp
, REG_PMC(interp
, *(pc
+ i
)));
449 Parrot_io_eprintf(debugger
, "I%vd=[%vd]", o
, REG_INT(interp
, o
));
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
489 I<Not really part of the API.>
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
)
506 if (pc
>= code_start
&& pc
< code_end
)
507 trace_op_dump(interp
, code_start
, pc
);
509 Parrot_io_eprintf(interp
, "PC=%ld; OP=<err>\n", (long)(pc
- code_start
));
527 * c-file-style: "parrot"
529 * vim: expandtab shiftwidth=4: