2 Copyright (C) 2001-2010, 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 "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
64 PARROT_CANNOT_RETURN_NULL
66 debugger_or_interp(PARROT_INTERP
)
68 ASSERT_ARGS(debugger_or_interp
)
70 return interp
->pdb
&& interp
->pdb
->debugger
71 ? interp
->pdb
->debugger
77 =item C<static STRING* trace_class_name(PARROT_INTERP, const PMC* pmc)>
79 Obtains the class name of the PMC.
85 PARROT_WARN_UNUSED_RESULT
86 PARROT_CANNOT_RETURN_NULL
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
,
96 return VTABLE_get_string(interp
, class_name_pmc
);
99 return pmc
->vtable
->whoami
;
105 =item C<void trace_pmc_dump(PARROT_INTERP, PMC *pmc)>
107 Prints a PMC to C<stderr>.
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
;
121 Parrot_io_eprintf(debugger
, "(null)");
125 if (PMC_IS_NULL(pmc
)) {
126 Parrot_io_eprintf(debugger
, "PMCNULL");
130 if (PObj_on_free_list_TEST(pmc
))
131 Parrot_io_eprintf(debugger
,
132 "**************** PMC is on free list *****\n");
135 Parrot_io_eprintf(debugger
, "<!!no vtable!!>");
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
);
146 Parrot_io_eprintf(debugger
, "%S=PMC(%#p Str:(NULL))",
147 VTABLE_name(interp
, pmc
), pmc
);
149 STRING
* const escaped
= Parrot_str_escape_truncate(interp
, s
, 20);
151 Parrot_io_eprintf(debugger
, "%S=PMC(%#p Str:\"%Ss\")",
152 VTABLE_name(interp
, pmc
), pmc
, escaped
);
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)",
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
);
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.
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
, "[");
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
));
215 case KEY_number_FLAG
:
216 len
+= Parrot_io_eprintf(debugger
, "%vg",
217 VTABLE_get_number(interp
, key
));
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);
225 len
+= Parrot_io_eprintf(debugger
, "\"%Ss\"", escaped
);
227 len
+= Parrot_io_eprintf(debugger
, "\"(null)\"");
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
)));
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
)));
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);
247 len
+= Parrot_io_eprintf(debugger
, "S%vd=\"%Ss\"",
250 len
+= Parrot_io_eprintf(debugger
, "S%vd=\"(null)\"", keynum
);
253 len
+= Parrot_io_eprintf(debugger
, "**WRONG KEY STRING REG %d**", keynum
);
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
)));
263 len
+= Parrot_io_eprintf(debugger
, "??");
269 key
= VTABLE_shift_pmc(interp
, key
);
271 len
+= Parrot_io_eprintf(debugger
, ";");
275 len
+= Parrot_io_eprintf(debugger
, "]");
282 =item C<void trace_op_dump(PARROT_INTERP, const opcode_t *code_start, const
285 Prints the PC, OP and ARGS. Used by C<trace_op()>.
287 I<Not really part of the API.>
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
];
302 INTVAL n
= info
->op_count
;
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
;
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
);
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];
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
);
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
, ", ");
353 len
+= Parrot_io_eprintf(debugger
, "%vd", o
);
356 len
+= Parrot_io_eprintf(debugger
, "%vg",
357 Parrot_pcc_get_num_constant(interp
,
358 CURRENT_CONTEXT(interp
), o
));
362 len
+= Parrot_io_eprintf(debugger
, "PC%d (%d)",
365 len
+= Parrot_io_eprintf(debugger
, "PC%d", (int)o
);
369 STRING
* const escaped
= Parrot_str_escape_truncate(
370 interp
, Parrot_pcc_get_string_constant(interp
,
371 CURRENT_CONTEXT(interp
), o
), 20);
373 len
+= Parrot_io_eprintf(debugger
, "\"%Ss\"", escaped
);
375 len
+= Parrot_io_eprintf(debugger
, "\"(null)\"");
379 len
+= trace_key_dump(interp
,
380 Parrot_pcc_get_pmc_constant(interp
,
381 CURRENT_CONTEXT(interp
), o
));
384 len
+= Parrot_io_eprintf(debugger
, "[%vd]", o
);
387 len
+= Parrot_io_eprintf(debugger
, "[I%vd]", o
);
391 len
+= Parrot_io_eprintf(debugger
, "[P%vd]", o
);
395 len
+= Parrot_io_eprintf(debugger
, "I%vd", o
);
399 len
+= Parrot_io_eprintf(debugger
, "N%vd", o
);
403 len
+= Parrot_io_eprintf(debugger
, "P%vd", o
);
407 len
+= Parrot_io_eprintf(debugger
, "S%vd", o
);
411 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
412 "unhandled type in trace");
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
);
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];
434 type
= VTABLE_get_integer_keyed_int(interp
, sig
, i
- 2) &
435 (PARROT_ARG_TYPE_MASK
|PARROT_ARG_CONSTANT
);
438 Parrot_io_eprintf(debugger
, " ");
442 Parrot_io_eprintf(debugger
, "I%vd=%vd", o
, REG_INT(interp
, o
));
445 Parrot_io_eprintf(debugger
, "N%vd=%vf", o
, REG_NUM(interp
, o
));
448 Parrot_io_eprintf(debugger
, "PC%vd=", o
);
449 trace_pmc_dump(interp
, Parrot_pcc_get_pmc_constant(interp
,
450 CURRENT_CONTEXT(interp
), o
));
453 Parrot_io_eprintf(debugger
, "P%vd=", o
);
454 trace_pmc_dump(interp
, REG_PMC(interp
, o
));
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
);
463 Parrot_io_eprintf(debugger
, "S%vd=\"(null)\"", o
);
466 Parrot_io_eprintf(debugger
, "P%vd=", o
);
467 trace_key_dump(interp
, REG_PMC(interp
, *(pc
+ i
)));
470 Parrot_io_eprintf(debugger
, "I%vd=[%vd]", o
, REG_INT(interp
, o
));
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.>
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
)
528 if (pc
>= code_start
&& pc
< code_end
)
529 trace_op_dump(interp
, code_start
, pc
);
531 Parrot_io_eprintf(interp
, "PC=%ld; OP=<err>\n",
532 (long)(pc
- code_start
));
551 * c-file-style: "parrot"
553 * vim: expandtab shiftwidth=4: