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 unsigned int lfp
= cfp
->lfp
- th
->stack
;
25 unsigned int 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
= (unsigned int)cfp
->lfp
;
40 if (dfp
< 0 || dfp
> th
->stack_size
) {
41 dfp
= (unsigned int)cfp
->dfp
;
45 bp
= cfp
->bp
- th
->stack
;
48 switch (VM_FRAME_TYPE(cfp
)) {
52 case FRAME_MAGIC_METHOD
:
55 case FRAME_MAGIC_CLASS
:
58 case FRAME_MAGIC_BLOCK
:
61 case FRAME_MAGIC_FINISH
:
64 case FRAME_MAGIC_CFUNC
:
67 case FRAME_MAGIC_PROC
:
70 case FRAME_MAGIC_LAMBDA
:
73 case FRAME_MAGIC_IFUNC
:
76 case 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 pc
= cfp
->pc
- cfp
->iseq
->iseq_encoded
;
101 iseq_name
= RSTRING_PTR(cfp
->iseq
->name
);
102 line
= vm_get_sourceline(cfp
);
104 char fn
[MAX_POSBUF
+1];
105 snprintf(fn
, MAX_POSBUF
, "%s", RSTRING_PTR(cfp
->iseq
->filename
));
106 snprintf(posbuf
, MAX_POSBUF
, "%s:%d", fn
, line
);
110 else if (cfp
->method_id
) {
111 iseq_name
= rb_id2name(cfp
->method_id
);
112 snprintf(posbuf
, MAX_POSBUF
, ":%s", rb_id2name(cfp
->method_id
));
116 fprintf(stderr
, "c:%04d ",
117 (rb_control_frame_t
*)(th
->stack
+ th
->stack_size
) - cfp
);
119 fprintf(stderr
, "p:---- ");
122 fprintf(stderr
, "p:%04d ", pc
);
124 fprintf(stderr
, "s:%04d b:%04d ", cfp
->sp
- th
->stack
, bp
);
125 fprintf(stderr
, lfp_in_heap
== ' ' ? "l:%06d " : "l:%06x ", lfp
% 10000);
126 fprintf(stderr
, dfp_in_heap
== ' ' ? "d:%06d " : "d:%06x ", dfp
% 10000);
127 fprintf(stderr
, "%-6s ", magic
);
129 fprintf(stderr
, "%s", posbuf
);
132 fprintf(stderr
, " \t");
133 fprintf(stderr
, "iseq: %-24s ", iseq_name
);
134 fprintf(stderr
, "self: %-24s ", selfstr
);
135 fprintf(stderr
, "%-1s ", biseq_name
);
137 fprintf(stderr
, "\n");
141 vm_stack_dump_raw(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
144 VALUE
*sp
= cfp
->sp
, *bp
= cfp
->bp
;
145 VALUE
*lfp
= cfp
->lfp
;
146 VALUE
*dfp
= cfp
->dfp
;
149 fprintf(stderr
, "-- stack frame ------------\n");
150 for (p
= st
= th
->stack
; p
< sp
; p
++) {
151 fprintf(stderr
, "%04ld (%p): %08lx", p
- st
, p
, *p
);
154 if (th
->stack
<= t
&& t
< sp
) {
155 fprintf(stderr
, " (= %ld)", (VALUE
*)GC_GUARDED_PTR_REF(t
) - th
->stack
);
159 fprintf(stderr
, " <- lfp");
161 fprintf(stderr
, " <- dfp");
163 fprintf(stderr
, " <- bp"); /* should not be */
165 fprintf(stderr
, "\n");
169 fprintf(stderr
, "-- control frame ----------\n");
170 while ((void *)cfp
< (void *)(th
->stack
+ th
->stack_size
)) {
171 control_frame_dump(th
, cfp
);
174 fprintf(stderr
, "---------------------------\n");
178 env_dump_raw(rb_env_t
*env
, VALUE
*lfp
, VALUE
*dfp
)
181 fprintf(stderr
, "-- env --------------------\n");
184 fprintf(stderr
, "--\n");
185 for (i
= 0; i
< env
->env_size
; i
++) {
186 fprintf(stderr
, "%04d: %08lx (%p)", -env
->local_size
+ i
, env
->env
[i
],
188 if (&env
->env
[i
] == lfp
)
189 fprintf(stderr
, " <- lfp");
190 if (&env
->env
[i
] == dfp
)
191 fprintf(stderr
, " <- dfp");
192 fprintf(stderr
, "\n");
195 if (env
->prev_envval
!= 0) {
196 GetEnvPtr(env
->prev_envval
, env
);
202 fprintf(stderr
, "---------------------------\n");
206 proc_dump_raw(rb_proc_t
*proc
)
210 VALUE val
= rb_inspect(proc
->block
.self
);
211 selfstr
= StringValueCStr(val
);
213 fprintf(stderr
, "-- proc -------------------\n");
214 fprintf(stderr
, "self: %s\n", selfstr
);
215 GetEnvPtr(proc
->envval
, env
);
216 env_dump_raw(env
, proc
->block
.lfp
, proc
->block
.dfp
);
220 stack_dump_th(VALUE thval
)
223 GetThreadPtr(thval
, th
);
224 vm_stack_dump_raw(th
, th
->cfp
);
228 stack_dump_each(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
234 VALUE
*lfp
= cfp
->lfp
;
235 VALUE
*dfp
= cfp
->dfp
;
237 int argc
= 0, local_size
;
239 rb_iseq_t
*iseq
= cfp
->iseq
;
242 if (RUBYVM_CFUNC_FRAME_P(cfp
)) {
245 name
= rb_id2name(cfp
->method_id
);
252 else if (RUBY_VM_IFUNC_P(iseq
)) {
259 local_size
= iseq
->local_size
;
260 name
= RSTRING_PTR(iseq
->name
);
263 /* stack trace header */
265 if (VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_METHOD
||
266 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_TOP
||
267 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_BLOCK
||
268 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_CLASS
||
269 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_PROC
||
270 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_LAMBDA
||
271 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_CFUNC
||
272 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_IFUNC
||
273 VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_EVAL
) {
275 VALUE
*ptr
= dfp
- local_size
;
277 stack_dump_each(th
, cfp
+ 1);
278 control_frame_dump(th
, cfp
);
283 for (i
= 0; i
< argc
; i
++) {
284 rstr
= rb_inspect(*ptr
);
285 fprintf(stderr
, " arg %2d: %8s (%p)\n", i
, StringValueCStr(rstr
),
288 for (; i
< local_size
- 1; i
++) {
289 rstr
= rb_inspect(*ptr
);
290 fprintf(stderr
, " local %2d: %8s (%p)\n", i
, StringValueCStr(rstr
),
295 for (; ptr
< sp
; ptr
++, i
++) {
296 if (*ptr
== Qundef
) {
297 rstr
= rb_str_new2("undef");
300 rstr
= rb_inspect(*ptr
);
302 fprintf(stderr
, " stack %2d: %8s (%d)\n", i
, StringValueCStr(rstr
),
306 else if (VM_FRAME_TYPE(cfp
) == FRAME_MAGIC_FINISH
) {
307 if ((th
)->stack
+ (th
)->stack_size
> (VALUE
*)(cfp
+ 2)) {
308 stack_dump_each(th
, cfp
+ 1);
315 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp
));
321 debug_print_register(rb_thread_t
*th
)
323 rb_control_frame_t
*cfp
= th
->cfp
;
325 int lfp
= cfp
->lfp
- th
->stack
;
326 int dfp
= cfp
->dfp
- th
->stack
;
329 if (RUBY_VM_NORMAL_ISEQ_P(cfp
->iseq
)) {
330 pc
= cfp
->pc
- cfp
->iseq
->iseq_encoded
;
333 if (lfp
< 0 || lfp
> th
->stack_size
)
335 if (dfp
< 0 || dfp
> th
->stack_size
)
338 cfpi
= ((rb_control_frame_t
*)(th
->stack
+ th
->stack_size
)) - cfp
;
339 fprintf(stderr
, " [PC] %04d, [SP] %04d, [LFP] %04d, [DFP] %04d, [CFP] %04d\n",
340 pc
, cfp
->sp
- th
->stack
, lfp
, dfp
, cfpi
);
344 thread_dump_regs(VALUE thval
)
347 GetThreadPtr(thval
, th
);
348 debug_print_register(th
);
352 debug_print_pre(rb_thread_t
*th
, rb_control_frame_t
*cfp
)
354 rb_iseq_t
*iseq
= cfp
->iseq
;
356 if (iseq
!= 0 && VM_FRAME_TYPE(cfp
) != FRAME_MAGIC_FINISH
) {
357 VALUE
*seq
= iseq
->iseq
;
358 int pc
= cfp
->pc
- iseq
->iseq_encoded
;
360 printf("%3d ", VM_CFP_CNT(th
, cfp
));
361 ruby_iseq_disasm_insn(0, seq
, pc
, iseq
, 0);
365 fprintf(stderr
, " (1)");
366 debug_print_register(th
);
371 debug_print_post(rb_thread_t
*th
, rb_control_frame_t
*cfp
372 #if OPT_STACK_CACHING
373 , VALUE reg_a
, VALUE reg_b
382 fprintf(stderr
, " (2)");
383 debug_print_register(th
);
385 /* stack_dump_raw(th, cfp); */
388 /* stack_dump_thobj(th); */
389 stack_dump_each(th
, th
->cfp
);
390 #if OPT_STACK_CACHING
393 rstr
= rb_inspect(reg_a
);
394 fprintf(stderr
, " sc reg A: %s\n", StringValueCStr(rstr
));
395 rstr
= rb_inspect(reg_b
);
396 fprintf(stderr
, " sc reg B: %s\n", StringValueCStr(rstr
));
400 ("--------------------------------------------------------------\n");
404 #ifdef COLLECT_USAGE_ANALYSIS
406 * insn(Fixnum) => ihash(Hash)
409 * -1(Fixnum) => count, # insn usage
410 * 0(Fixnum) => ophash, # operand usage
413 * val(interned string) => count(Fixnum)
417 vm_analysis_insn(int insn
)
419 static ID usage_hash
;
420 static ID bigram_hash
;
421 static int prev_insn
= -1;
427 if (usage_hash
== 0) {
428 usage_hash
= rb_intern("USAGE_ANALYSIS_INSN");
429 bigram_hash
= rb_intern("USAGE_ANALYSIS_INSN_BIGRAM");
431 uh
= rb_const_get(rb_cVM
, usage_hash
);
432 if ((ihash
= rb_hash_aref(uh
, INT2FIX(insn
))) == Qnil
) {
433 ihash
= rb_hash_new();
434 rb_hash_aset(uh
, INT2FIX(insn
), ihash
);
436 if ((cv
= rb_hash_aref(ihash
, INT2FIX(-1))) == Qnil
) {
439 rb_hash_aset(ihash
, INT2FIX(-1), INT2FIX(FIX2INT(cv
) + 1));
442 if (prev_insn
!= -1) {
447 ary
[0] = INT2FIX(prev_insn
);
448 ary
[1] = INT2FIX(insn
);
449 bi
= rb_ary_new4(2, &ary
[0]);
451 uh
= rb_const_get(rb_cVM
, bigram_hash
);
452 if ((cv
= rb_hash_aref(uh
, bi
)) == Qnil
) {
455 rb_hash_aset(uh
, bi
, INT2FIX(FIX2INT(cv
) + 1));
461 extern VALUE
insn_operand_intern(int insn
, int op_no
, VALUE op
,
462 int len
, int pos
, VALUE child
);
465 vm_analysis_operand(int insn
, int n
, VALUE op
)
467 static ID usage_hash
;
475 if (usage_hash
== 0) {
476 usage_hash
= rb_intern("USAGE_ANALYSIS_INSN");
479 uh
= rb_const_get(rb_cVM
, usage_hash
);
480 if ((ihash
= rb_hash_aref(uh
, INT2FIX(insn
))) == Qnil
) {
481 ihash
= rb_hash_new();
482 rb_hash_aset(uh
, INT2FIX(insn
), ihash
);
484 if ((ophash
= rb_hash_aref(ihash
, INT2FIX(n
))) == Qnil
) {
485 ophash
= rb_hash_new();
486 rb_hash_aset(ihash
, INT2FIX(n
), ophash
);
489 valstr
= insn_operand_intern(insn
, n
, op
, 0, 0, 0);
492 if ((cv
= rb_hash_aref(ophash
, valstr
)) == Qnil
) {
495 rb_hash_aset(ophash
, valstr
, INT2FIX(FIX2INT(cv
) + 1));
499 vm_analysis_register(int reg
, int isset
)
501 static ID usage_hash
;
514 char *getsetstr
[] = {
518 static VALUE syms
[sizeof(regstrs
) / sizeof(regstrs
[0])][2];
522 if (usage_hash
== 0) {
526 usage_hash
= rb_intern("USAGE_ANALYSIS_REGS");
528 for (i
= 0; i
< sizeof(regstrs
) / sizeof(regstrs
[0]); i
++) {
530 for (j
= 0; j
< 2; j
++) {
531 snfprintf(stderr
, buff
, 0x10, "%d %s %-4s", i
, getsetstr
[j
],
533 syms
[i
][j
] = ID2SYM(rb_intern(buff
));
537 valstr
= syms
[reg
][isset
];
539 uh
= rb_const_get(rb_cVM
, usage_hash
);
540 if ((cv
= rb_hash_aref(uh
, valstr
)) == Qnil
) {
543 rb_hash_aset(uh
, valstr
, INT2FIX(FIX2INT(cv
) + 1));
551 thread_dump_state(VALUE self
)
554 rb_control_frame_t
*cfp
;
555 GetThreadPtr(self
, th
);
558 fprintf(stderr
, "Thread state dump:\n");
559 fprintf(stderr
, "pc : %p, sp : %p\n", cfp
->pc
, cfp
->sp
);
560 fprintf(stderr
, "cfp: %p, lfp: %p, dfp: %p\n", cfp
, cfp
->lfp
, cfp
->dfp
);
566 rb_vm_bugreport(void)
568 rb_thread_t
*th
= GET_THREAD();
571 if (GET_THREAD()->vm
) {
575 bt
= vm_backtrace(th
, 0);
576 if (TYPE(bt
) == T_ARRAY
)
577 for (i
= 0; i
< RARRAY_LEN(bt
); i
++) {
578 dp(RARRAY_PTR(bt
)[i
]);
583 #include <execinfo.h>
584 #define MAX_NATIVE_TRACE 1024
586 static void *trace
[MAX_NATIVE_TRACE
];
587 int n
= backtrace(trace
, MAX_NATIVE_TRACE
);
590 fprintf(stderr
, "-- backtrace of native function call (Use addr2line) --\n");
591 for (i
=0; i
<n
; i
++) {
592 fprintf(stderr
, "%p\n", trace
[i
]);
594 fprintf(stderr
, "-------------------------------------------------------\n");