1 /**********************************************************************
7 Copyright (C) 2004-2007 Koichi Sasada
9 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include "ruby/node.h"
18 #define MAX_POSBUF 128
21 control_frame_dump(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
23 int pc
= -1, bp
= -1, line
= 0;
24 ptrdiff_t lfp
= cfp
->lfp
- th
->stack
;
25 ptrdiff_t dfp
= cfp
->dfp
- th
->stack
;
26 char lfp_in_heap
= ' ', dfp_in_heap
= ' ';
27 char posbuf
[MAX_POSBUF
+1];
29 const char *magic
, *iseq_name
= "-", *selfstr
= "-", *biseq_name
= "-";
32 if (cfp
->block_iseq
!= 0 && BUILTIN_TYPE(cfp
->block_iseq
) != T_NODE
) {
33 biseq_name
= ""; /* RSTRING(cfp->block_iseq->name)->ptr; */
36 if (lfp
< 0 || lfp
> th
->stack_size
) {
37 lfp
= (ptrdiff_t)cfp
->lfp
;
40 if (dfp
< 0 || dfp
> th
->stack_size
) {
41 dfp
= (ptrdiff_t)cfp
->dfp
;
45 bp
= cfp
->bp
- th
->stack
;
48 switch (VM_FRAME_TYPE(cfp
)) {
49 case VM_FRAME_MAGIC_TOP
:
52 case VM_FRAME_MAGIC_METHOD
:
55 case VM_FRAME_MAGIC_CLASS
:
58 case VM_FRAME_MAGIC_BLOCK
:
61 case VM_FRAME_MAGIC_FINISH
:
64 case VM_FRAME_MAGIC_CFUNC
:
67 case VM_FRAME_MAGIC_PROC
:
70 case VM_FRAME_MAGIC_LAMBDA
:
73 case VM_FRAME_MAGIC_IFUNC
:
76 case VM_FRAME_MAGIC_EVAL
:
88 tmp
= rb_inspect(cfp
->self
);
89 selfstr
= StringValueCStr(tmp
);
96 if (RUBY_VM_IFUNC_P(cfp
->iseq
)) {
97 iseq_name
= "<ifunc>";
100 int vm_get_sourceline(rb_control_frame_t
*);
102 pc
= cfp
->pc
- cfp
->iseq
->iseq_encoded
;
103 iseq_name
= RSTRING_PTR(cfp
->iseq
->name
);
104 line
= vm_get_sourceline(cfp
);
106 char fn
[MAX_POSBUF
+1];
107 snprintf(fn
, MAX_POSBUF
, "%s", RSTRING_PTR(cfp
->iseq
->filename
));
108 snprintf(posbuf
, MAX_POSBUF
, "%s:%d", fn
, line
);
112 else if (cfp
->method_id
) {
113 iseq_name
= rb_id2name(cfp
->method_id
);
114 snprintf(posbuf
, MAX_POSBUF
, ":%s", rb_id2name(cfp
->method_id
));
118 fprintf(stderr
, "c:%04"PRIdPTRDIFF
" ",
119 ((rb_control_frame_t
*)(th
->stack
+ th
->stack_size
) - cfp
));
121 fprintf(stderr
, "p:---- ");
124 fprintf(stderr
, "p:%04d ", pc
);
126 fprintf(stderr
, "s:%04"PRIdPTRDIFF
" b:%04d ", (cfp
->sp
- th
->stack
), bp
);
127 fprintf(stderr
, lfp_in_heap
== ' ' ? "l:%06"PRIdPTRDIFF
" " : "l:%06"PRIxPTRDIFF
" ", lfp
% 10000);
128 fprintf(stderr
, dfp_in_heap
== ' ' ? "d:%06"PRIdPTRDIFF
" " : "d:%06"PRIxPTRDIFF
" ", dfp
% 10000);
129 fprintf(stderr
, "%-6s ", magic
);
131 fprintf(stderr
, "%s", posbuf
);
134 fprintf(stderr
, " \t");
135 fprintf(stderr
, "iseq: %-24s ", iseq_name
);
136 fprintf(stderr
, "self: %-24s ", selfstr
);
137 fprintf(stderr
, "%-1s ", biseq_name
);
139 fprintf(stderr
, "\n");
143 vm_stack_dump_raw(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
146 VALUE
*sp
= cfp
->sp
, *bp
= cfp
->bp
;
147 VALUE
*lfp
= cfp
->lfp
;
148 VALUE
*dfp
= cfp
->dfp
;
151 fprintf(stderr
, "-- stack frame ------------\n");
152 for (p
= st
= th
->stack
; p
< sp
; p
++) {
153 fprintf(stderr
, "%04ld (%p): %08"PRIxVALUE
, (long)(p
- st
), p
, *p
);
156 if (th
->stack
<= t
&& t
< sp
) {
157 fprintf(stderr
, " (= %ld)", (long)((VALUE
*)GC_GUARDED_PTR_REF(t
) - th
->stack
));
161 fprintf(stderr
, " <- lfp");
163 fprintf(stderr
, " <- dfp");
165 fprintf(stderr
, " <- bp"); /* should not be */
167 fprintf(stderr
, "\n");
171 fprintf(stderr
, "-- control frame ----------\n");
172 while ((void *)cfp
< (void *)(th
->stack
+ th
->stack_size
)) {
173 control_frame_dump(th
, cfp
);
176 fprintf(stderr
, "---------------------------\n");
180 vm_stack_dump_raw_current(void)
182 rb_thread_t
*th
= GET_THREAD();
183 vm_stack_dump_raw(th
, th
->cfp
);
187 env_dump_raw(rb_env_t
*env
, VALUE
*lfp
, VALUE
*dfp
)
190 fprintf(stderr
, "-- env --------------------\n");
193 fprintf(stderr
, "--\n");
194 for (i
= 0; i
< env
->env_size
; i
++) {
195 fprintf(stderr
, "%04d: %08lx (%p)", -env
->local_size
+ i
, env
->env
[i
],
197 if (&env
->env
[i
] == lfp
)
198 fprintf(stderr
, " <- lfp");
199 if (&env
->env
[i
] == dfp
)
200 fprintf(stderr
, " <- dfp");
201 fprintf(stderr
, "\n");
204 if (env
->prev_envval
!= 0) {
205 GetEnvPtr(env
->prev_envval
, env
);
211 fprintf(stderr
, "---------------------------\n");
215 proc_dump_raw(rb_proc_t
*proc
)
219 VALUE val
= rb_inspect(proc
->block
.self
);
220 selfstr
= StringValueCStr(val
);
222 fprintf(stderr
, "-- proc -------------------\n");
223 fprintf(stderr
, "self: %s\n", selfstr
);
224 GetEnvPtr(proc
->envval
, env
);
225 env_dump_raw(env
, proc
->block
.lfp
, proc
->block
.dfp
);
229 stack_dump_th(VALUE thval
)
232 GetThreadPtr(thval
, th
);
233 vm_stack_dump_raw(th
, th
->cfp
);
237 stack_dump_each(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
243 VALUE
*lfp
= cfp
->lfp
;
244 VALUE
*dfp
= cfp
->dfp
;
246 int argc
= 0, local_size
;
248 rb_iseq_t
*iseq
= cfp
->iseq
;
251 if (RUBYVM_CFUNC_FRAME_P(cfp
)) {
254 name
= rb_id2name(cfp
->method_id
);
261 else if (RUBY_VM_IFUNC_P(iseq
)) {
268 local_size
= iseq
->local_size
;
269 name
= RSTRING_PTR(iseq
->name
);
272 /* stack trace header */
274 if (VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_METHOD
||
275 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_TOP
||
276 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_BLOCK
||
277 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_CLASS
||
278 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_PROC
||
279 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_LAMBDA
||
280 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_CFUNC
||
281 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_IFUNC
||
282 VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_EVAL
) {
284 VALUE
*ptr
= dfp
- local_size
;
286 stack_dump_each(th
, cfp
+ 1);
287 control_frame_dump(th
, cfp
);
292 for (i
= 0; i
< argc
; i
++) {
293 rstr
= rb_inspect(*ptr
);
294 fprintf(stderr
, " arg %2d: %8s (%p)\n", i
, StringValueCStr(rstr
),
297 for (; i
< local_size
- 1; i
++) {
298 rstr
= rb_inspect(*ptr
);
299 fprintf(stderr
, " local %2d: %8s (%p)\n", i
, StringValueCStr(rstr
),
304 for (; ptr
< sp
; ptr
++, i
++) {
305 if (*ptr
== Qundef
) {
306 rstr
= rb_str_new2("undef");
309 rstr
= rb_inspect(*ptr
);
311 fprintf(stderr
, " stack %2d: %8s (%"PRIdPTRDIFF
")\n", i
, StringValueCStr(rstr
),
315 else if (VM_FRAME_TYPE(cfp
) == VM_FRAME_MAGIC_FINISH
) {
316 if ((th
)->stack
+ (th
)->stack_size
> (VALUE
*)(cfp
+ 2)) {
317 stack_dump_each(th
, cfp
+ 1);
324 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp
));
330 debug_print_register(rb_thread_t
*th
)
332 rb_control_frame_t
*cfp
= th
->cfp
;
334 int lfp
= cfp
->lfp
- th
->stack
;
335 int dfp
= cfp
->dfp
- th
->stack
;
338 if (RUBY_VM_NORMAL_ISEQ_P(cfp
->iseq
)) {
339 pc
= cfp
->pc
- cfp
->iseq
->iseq_encoded
;
342 if (lfp
< 0 || lfp
> th
->stack_size
)
344 if (dfp
< 0 || dfp
> th
->stack_size
)
347 cfpi
= ((rb_control_frame_t
*)(th
->stack
+ th
->stack_size
)) - cfp
;
348 fprintf(stderr
, " [PC] %04d, [SP] %04"PRIdPTRDIFF
", [LFP] %04d, [DFP] %04d, [CFP] %04d\n",
349 pc
, (cfp
->sp
- th
->stack
), lfp
, dfp
, cfpi
);
353 thread_dump_regs(VALUE thval
)
356 GetThreadPtr(thval
, th
);
357 debug_print_register(th
);
361 debug_print_pre(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
363 rb_iseq_t
*iseq
= cfp
->iseq
;
365 if (iseq
!= 0 && VM_FRAME_TYPE(cfp
) != VM_FRAME_MAGIC_FINISH
) {
366 VALUE
*seq
= iseq
->iseq
;
367 int pc
= cfp
->pc
- iseq
->iseq_encoded
;
369 printf("%3"PRIdPTRDIFF
" ", VM_CFP_CNT(th
, cfp
));
370 ruby_iseq_disasm_insn(0, seq
, pc
, iseq
, 0);
374 fprintf(stderr
, " (1)");
375 debug_print_register(th
);
380 debug_print_post(rb_thread_t
*th
, rb_control_frame_t
*cfp
381 #if OPT_STACK_CACHING
382 , VALUE reg_a
, VALUE reg_b
391 fprintf(stderr
, " (2)");
392 debug_print_register(th
);
394 /* stack_dump_raw(th, cfp); */
397 /* stack_dump_thobj(th); */
398 stack_dump_each(th
, th
->cfp
);
399 #if OPT_STACK_CACHING
402 rstr
= rb_inspect(reg_a
);
403 fprintf(stderr
, " sc reg A: %s\n", StringValueCStr(rstr
));
404 rstr
= rb_inspect(reg_b
);
405 fprintf(stderr
, " sc reg B: %s\n", StringValueCStr(rstr
));
409 ("--------------------------------------------------------------\n");
413 #ifdef COLLECT_USAGE_ANALYSIS
415 * insn(Fixnum) => ihash(Hash)
418 * -1(Fixnum) => count, # insn usage
419 * 0(Fixnum) => ophash, # operand usage
422 * val(interned string) => count(Fixnum)
426 vm_analysis_insn(int insn
)
430 static int prev_insn
= -1;
436 CONST_ID(usage_hash
, "USAGE_ANALYSIS_INSN");
437 CONST_ID(bigram_hash
, "USAGE_ANALYSIS_INSN_BIGRAM");
438 uh
= rb_const_get(rb_cRubyVM
, usage_hash
);
439 if ((ihash
= rb_hash_aref(uh
, INT2FIX(insn
))) == Qnil
) {
440 ihash
= rb_hash_new();
441 rb_hash_aset(uh
, INT2FIX(insn
), ihash
);
443 if ((cv
= rb_hash_aref(ihash
, INT2FIX(-1))) == Qnil
) {
446 rb_hash_aset(ihash
, INT2FIX(-1), INT2FIX(FIX2INT(cv
) + 1));
449 if (prev_insn
!= -1) {
454 ary
[0] = INT2FIX(prev_insn
);
455 ary
[1] = INT2FIX(insn
);
456 bi
= rb_ary_new4(2, &ary
[0]);
458 uh
= rb_const_get(rb_cRubyVM
, bigram_hash
);
459 if ((cv
= rb_hash_aref(uh
, bi
)) == Qnil
) {
462 rb_hash_aset(uh
, bi
, INT2FIX(FIX2INT(cv
) + 1));
468 extern VALUE
insn_operand_intern(int insn
, int op_no
, VALUE op
,
469 int len
, int pos
, VALUE child
);
472 vm_analysis_operand(int insn
, int n
, VALUE op
)
482 CONST_ID(usage_hash
, "USAGE_ANALYSIS_INSN");
484 uh
= rb_const_get(rb_cRubyVM
, usage_hash
);
485 if ((ihash
= rb_hash_aref(uh
, INT2FIX(insn
))) == Qnil
) {
486 ihash
= rb_hash_new();
487 rb_hash_aset(uh
, INT2FIX(insn
), ihash
);
489 if ((ophash
= rb_hash_aref(ihash
, INT2FIX(n
))) == Qnil
) {
490 ophash
= rb_hash_new();
491 rb_hash_aset(ihash
, INT2FIX(n
), ophash
);
494 valstr
= insn_operand_intern(insn
, n
, op
, 0, 0, 0);
497 if ((cv
= rb_hash_aref(ophash
, valstr
)) == Qnil
) {
500 rb_hash_aset(ophash
, valstr
, INT2FIX(FIX2INT(cv
) + 1));
504 vm_analysis_register(int reg
, int isset
)
510 static const char regstrs
[][5] = {
519 static const char getsetstr
[][4] = {
523 static VALUE syms
[sizeof(regstrs
) / sizeof(regstrs
[0])][2];
527 CONST_ID(usage_hash
, "USAGE_ANALYSIS_REGS");
532 for (i
= 0; i
< sizeof(regstrs
) / sizeof(regstrs
[0]); i
++) {
534 for (j
= 0; j
< 2; j
++) {
535 snfprintf(stderr
, buff
, 0x10, "%d %s %-4s", i
, getsetstr
[j
],
537 syms
[i
][j
] = ID2SYM(rb_intern(buff
));
541 valstr
= syms
[reg
][isset
];
543 uh
= rb_const_get(rb_cRubyVM
, usage_hash
);
544 if ((cv
= rb_hash_aref(uh
, valstr
)) == Qnil
) {
547 rb_hash_aset(uh
, valstr
, INT2FIX(FIX2INT(cv
) + 1));
555 thread_dump_state(VALUE self
)
558 rb_control_frame_t
*cfp
;
559 GetThreadPtr(self
, th
);
562 fprintf(stderr
, "Thread state dump:\n");
563 fprintf(stderr
, "pc : %p, sp : %p\n", cfp
->pc
, cfp
->sp
);
564 fprintf(stderr
, "cfp: %p, lfp: %p, dfp: %p\n", cfp
, cfp
->lfp
, cfp
->dfp
);
569 VALUE
rb_make_backtrace(void);
572 rb_vm_bugreport(void)
576 if (GET_THREAD()->vm
) {
580 bt
= rb_make_backtrace();
581 if (TYPE(bt
) == T_ARRAY
)
582 for (i
= 0; i
< RARRAY_LEN(bt
); i
++) {
583 dp(RARRAY_PTR(bt
)[i
]);
588 #include <execinfo.h>
589 #define MAX_NATIVE_TRACE 1024
591 static void *trace
[MAX_NATIVE_TRACE
];
592 int n
= backtrace(trace
, MAX_NATIVE_TRACE
);
595 fprintf(stderr
, "-- backtrace of native function call (Use addr2line) --\n");
596 for (i
=0; i
<n
; i
++) {
597 fprintf(stderr
, "%p\n", trace
[i
]);
599 fprintf(stderr
, "-------------------------------------------------------\n");