update comment.
[ruby-svn.git] / vm_dump.c
blobc88396d36f404099f7e05b4355c2d06f97757dfe
1 /**********************************************************************
3 vm_dump.c -
5 $Author$
7 Copyright (C) 2004-2007 Koichi Sasada
9 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include "ruby/node.h"
15 #include "vm_core.h"
16 #include "vm.h"
18 #define MAX_POSBUF 128
20 static void
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 = "-";
30 VALUE tmp;
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;
38 lfp_in_heap = 'p';
40 if (dfp < 0 || dfp > th->stack_size) {
41 dfp = (ptrdiff_t)cfp->dfp;
42 dfp_in_heap = 'p';
44 if (cfp->bp) {
45 bp = cfp->bp - th->stack;
48 switch (VM_FRAME_TYPE(cfp)) {
49 case VM_FRAME_MAGIC_TOP:
50 magic = "TOP";
51 break;
52 case VM_FRAME_MAGIC_METHOD:
53 magic = "METHOD";
54 break;
55 case VM_FRAME_MAGIC_CLASS:
56 magic = "CLASS";
57 break;
58 case VM_FRAME_MAGIC_BLOCK:
59 magic = "BLOCK";
60 break;
61 case VM_FRAME_MAGIC_FINISH:
62 magic = "FINISH";
63 break;
64 case VM_FRAME_MAGIC_CFUNC:
65 magic = "CFUNC";
66 break;
67 case VM_FRAME_MAGIC_PROC:
68 magic = "PROC";
69 break;
70 case VM_FRAME_MAGIC_LAMBDA:
71 magic = "LAMBDA";
72 break;
73 case VM_FRAME_MAGIC_IFUNC:
74 magic = "IFUNC";
75 break;
76 case VM_FRAME_MAGIC_EVAL:
77 magic = "EVAL";
78 break;
79 case 0:
80 magic = "------";
81 break;
82 default:
83 magic = "(none)";
84 break;
87 if (0) {
88 tmp = rb_inspect(cfp->self);
89 selfstr = StringValueCStr(tmp);
91 else {
92 selfstr = "";
95 if (cfp->iseq != 0) {
96 if (RUBY_VM_IFUNC_P(cfp->iseq)) {
97 iseq_name = "<ifunc>";
99 else {
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);
105 if (line) {
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));
115 line = -1;
118 fprintf(stderr, "c:%04"PRIdPTRDIFF" ",
119 ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp));
120 if (pc == -1) {
121 fprintf(stderr, "p:---- ");
123 else {
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);
130 if (line) {
131 fprintf(stderr, "%s", posbuf);
133 if (0) {
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");
142 void
143 vm_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
145 #if 0
146 VALUE *sp = cfp->sp, *bp = cfp->bp;
147 VALUE *lfp = cfp->lfp;
148 VALUE *dfp = cfp->dfp;
149 VALUE *p, *st, *t;
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);
155 t = (VALUE *)*p;
156 if (th->stack <= t && t < sp) {
157 fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack));
160 if (p == lfp)
161 fprintf(stderr, " <- lfp");
162 if (p == dfp)
163 fprintf(stderr, " <- dfp");
164 if (p == bp)
165 fprintf(stderr, " <- bp"); /* should not be */
167 fprintf(stderr, "\n");
169 #endif
171 fprintf(stderr, "-- control frame ----------\n");
172 while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
173 control_frame_dump(th, cfp);
174 cfp++;
176 fprintf(stderr, "---------------------------\n");
179 void
180 vm_stack_dump_raw_current(void)
182 rb_thread_t *th = GET_THREAD();
183 vm_stack_dump_raw(th, th->cfp);
186 void
187 env_dump_raw(rb_env_t *env, VALUE *lfp, VALUE *dfp)
189 int i;
190 fprintf(stderr, "-- env --------------------\n");
192 while (env) {
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],
196 &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);
207 else {
208 env = 0;
211 fprintf(stderr, "---------------------------\n");
214 void
215 proc_dump_raw(rb_proc_t *proc)
217 rb_env_t *env;
218 char *selfstr;
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);
228 void
229 stack_dump_th(VALUE thval)
231 rb_thread_t *th;
232 GetThreadPtr(thval, th);
233 vm_stack_dump_raw(th, th->cfp);
236 void
237 stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
239 int i;
241 VALUE rstr;
242 VALUE *sp = cfp->sp;
243 VALUE *lfp = cfp->lfp;
244 VALUE *dfp = cfp->dfp;
246 int argc = 0, local_size;
247 const char *name;
248 rb_iseq_t *iseq = cfp->iseq;
250 if (iseq == 0) {
251 if (RUBYVM_CFUNC_FRAME_P(cfp)) {
252 argc = 0;
253 local_size = 0;
254 name = rb_id2name(cfp->method_id);
256 else {
257 name = "?";
258 local_size = 0;
261 else if (RUBY_VM_IFUNC_P(iseq)) {
262 argc = 0;
263 local_size = 0;
264 name = "<ifunc>";
266 else {
267 argc = iseq->argc;
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);
289 if (lfp != dfp) {
290 local_size++;
292 for (i = 0; i < argc; i++) {
293 rstr = rb_inspect(*ptr);
294 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
295 ptr++);
297 for (; i < local_size - 1; i++) {
298 rstr = rb_inspect(*ptr);
299 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
300 ptr++);
303 ptr = cfp->bp;
304 for (; ptr < sp; ptr++, i++) {
305 if (*ptr == Qundef) {
306 rstr = rb_str_new2("undef");
308 else {
309 rstr = rb_inspect(*ptr);
311 fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr),
312 (ptr - th->stack));
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);
319 else {
320 /* SDR(); */
323 else {
324 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
329 void
330 debug_print_register(rb_thread_t *th)
332 rb_control_frame_t *cfp = th->cfp;
333 int pc = -1;
334 int lfp = cfp->lfp - th->stack;
335 int dfp = cfp->dfp - th->stack;
336 int cfpi;
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)
343 lfp = -1;
344 if (dfp < 0 || dfp > th->stack_size)
345 dfp = -1;
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);
352 void
353 thread_dump_regs(VALUE thval)
355 rb_thread_t *th;
356 GetThreadPtr(thval, th);
357 debug_print_register(th);
360 void
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);
373 #if VMDEBUG > 3
374 fprintf(stderr, " (1)");
375 debug_print_register(th);
376 #endif
379 void
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
383 #endif
386 #if VMDEBUG > 9
387 SDR2(cfp);
388 #endif
390 #if VMDEBUG > 3
391 fprintf(stderr, " (2)");
392 debug_print_register(th);
393 #endif
394 /* stack_dump_raw(th, cfp); */
396 #if VMDEBUG > 2
397 /* stack_dump_thobj(th); */
398 stack_dump_each(th, th->cfp);
399 #if OPT_STACK_CACHING
401 VALUE rstr;
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));
407 #endif
408 printf
409 ("--------------------------------------------------------------\n");
410 #endif
413 #ifdef COLLECT_USAGE_ANALYSIS
414 /* uh = {
415 * insn(Fixnum) => ihash(Hash)
417 * ihash = {
418 * -1(Fixnum) => count, # insn usage
419 * 0(Fixnum) => ophash, # operand usage
421 * ophash = {
422 * val(interned string) => count(Fixnum)
425 void
426 vm_analysis_insn(int insn)
428 ID usage_hash;
429 ID bigram_hash;
430 static int prev_insn = -1;
432 VALUE uh;
433 VALUE ihash;
434 VALUE cv;
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) {
444 cv = INT2FIX(0);
446 rb_hash_aset(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1));
448 /* calc bigram */
449 if (prev_insn != -1) {
450 VALUE bi;
451 VALUE ary[2];
452 VALUE cv;
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) {
460 cv = INT2FIX(0);
462 rb_hash_aset(uh, bi, INT2FIX(FIX2INT(cv) + 1));
464 prev_insn = insn;
467 /* from disasm.c */
468 extern VALUE insn_operand_intern(int insn, int op_no, VALUE op,
469 int len, int pos, VALUE child);
471 void
472 vm_analysis_operand(int insn, int n, VALUE op)
474 ID usage_hash;
476 VALUE uh;
477 VALUE ihash;
478 VALUE ophash;
479 VALUE valstr;
480 VALUE cv;
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);
493 /* intern */
494 valstr = insn_operand_intern(insn, n, op, 0, 0, 0);
496 /* set count */
497 if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) {
498 cv = INT2FIX(0);
500 rb_hash_aset(ophash, valstr, INT2FIX(FIX2INT(cv) + 1));
503 void
504 vm_analysis_register(int reg, int isset)
506 ID usage_hash;
507 VALUE uh;
508 VALUE rhash;
509 VALUE valstr;
510 static const char regstrs[][5] = {
511 "pc", /* 0 */
512 "sp", /* 1 */
513 "cfp", /* 2 */
514 "lfp", /* 3 */
515 "dfp", /* 4 */
516 "self", /* 5 */
517 "iseq", /* 6 */
519 static const char getsetstr[][4] = {
520 "get",
521 "set",
523 static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2];
525 VALUE cv;
527 CONST_ID(usage_hash, "USAGE_ANALYSIS_REGS");
528 if (syms[0] == 0) {
529 char buff[0x10];
530 int i;
532 for (i = 0; i < sizeof(regstrs) / sizeof(regstrs[0]); i++) {
533 int j;
534 for (j = 0; j < 2; j++) {
535 snfprintf(stderr, buff, 0x10, "%d %s %-4s", i, getsetstr[j],
536 regstrs[i]);
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) {
545 cv = INT2FIX(0);
547 rb_hash_aset(uh, valstr, INT2FIX(FIX2INT(cv) + 1));
551 #endif
554 VALUE
555 thread_dump_state(VALUE self)
557 rb_thread_t *th;
558 rb_control_frame_t *cfp;
559 GetThreadPtr(self, th);
560 cfp = th->cfp;
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);
566 return Qnil;
569 VALUE rb_make_backtrace(void);
571 void
572 rb_vm_bugreport(void)
574 VALUE bt;
576 if (GET_THREAD()->vm) {
577 int i;
578 SDR();
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]);
587 #if HAVE_BACKTRACE
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);
593 int i;
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");
601 #endif