add test for Struct.new(0).
[ruby-svn.git] / vm_dump.c
blobd3e1e423a5ee70dfc6d1928c4eacf6de34573a17
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 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 = "-";
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 = (unsigned int)cfp->lfp;
38 lfp_in_heap = 'p';
40 if (dfp < 0 || dfp > th->stack_size) {
41 dfp = (unsigned int)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 FRAME_MAGIC_TOP:
50 magic = "TOP";
51 break;
52 case FRAME_MAGIC_METHOD:
53 magic = "METHOD";
54 break;
55 case FRAME_MAGIC_CLASS:
56 magic = "CLASS";
57 break;
58 case FRAME_MAGIC_BLOCK:
59 magic = "BLOCK";
60 break;
61 case FRAME_MAGIC_FINISH:
62 magic = "FINISH";
63 break;
64 case FRAME_MAGIC_CFUNC:
65 magic = "CFUNC";
66 break;
67 case FRAME_MAGIC_PROC:
68 magic = "PROC";
69 break;
70 case FRAME_MAGIC_LAMBDA:
71 magic = "LAMBDA";
72 break;
73 case FRAME_MAGIC_IFUNC:
74 magic = "IFUNC";
75 break;
76 case 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 pc = cfp->pc - cfp->iseq->iseq_encoded;
101 iseq_name = RSTRING_PTR(cfp->iseq->name);
102 line = vm_get_sourceline(cfp);
103 if (line) {
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));
113 line = -1;
116 fprintf(stderr, "c:%04d ",
117 (rb_control_frame_t *)(th->stack + th->stack_size) - cfp);
118 if (pc == -1) {
119 fprintf(stderr, "p:---- ");
121 else {
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);
128 if (line) {
129 fprintf(stderr, "%s", posbuf);
131 if (0) {
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");
140 void
141 vm_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp)
143 #if 0
144 VALUE *sp = cfp->sp, *bp = cfp->bp;
145 VALUE *lfp = cfp->lfp;
146 VALUE *dfp = cfp->dfp;
147 VALUE *p, *st, *t;
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);
153 t = (VALUE *)*p;
154 if (th->stack <= t && t < sp) {
155 fprintf(stderr, " (= %ld)", (VALUE *)GC_GUARDED_PTR_REF(t) - th->stack);
158 if (p == lfp)
159 fprintf(stderr, " <- lfp");
160 if (p == dfp)
161 fprintf(stderr, " <- dfp");
162 if (p == bp)
163 fprintf(stderr, " <- bp"); /* should not be */
165 fprintf(stderr, "\n");
167 #endif
169 fprintf(stderr, "-- control frame ----------\n");
170 while ((void *)cfp < (void *)(th->stack + th->stack_size)) {
171 control_frame_dump(th, cfp);
172 cfp++;
174 fprintf(stderr, "---------------------------\n");
177 void
178 env_dump_raw(rb_env_t *env, VALUE *lfp, VALUE *dfp)
180 int i;
181 fprintf(stderr, "-- env --------------------\n");
183 while (env) {
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],
187 &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);
198 else {
199 env = 0;
202 fprintf(stderr, "---------------------------\n");
205 void
206 proc_dump_raw(rb_proc_t *proc)
208 rb_env_t *env;
209 char *selfstr;
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);
219 void
220 stack_dump_th(VALUE thval)
222 rb_thread_t *th;
223 GetThreadPtr(thval, th);
224 vm_stack_dump_raw(th, th->cfp);
227 void
228 stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
230 int i;
232 VALUE rstr;
233 VALUE *sp = cfp->sp;
234 VALUE *lfp = cfp->lfp;
235 VALUE *dfp = cfp->dfp;
237 int argc = 0, local_size;
238 const char *name;
239 rb_iseq_t *iseq = cfp->iseq;
241 if (iseq == 0) {
242 if (RUBYVM_CFUNC_FRAME_P(cfp)) {
243 argc = 0;
244 local_size = 0;
245 name = rb_id2name(cfp->method_id);
247 else {
248 name = "?";
249 local_size = 0;
252 else if (RUBY_VM_IFUNC_P(iseq)) {
253 argc = 0;
254 local_size = 0;
255 name = "<ifunc>";
257 else {
258 argc = iseq->argc;
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);
280 if (lfp != dfp) {
281 local_size++;
283 for (i = 0; i < argc; i++) {
284 rstr = rb_inspect(*ptr);
285 fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr),
286 ptr++);
288 for (; i < local_size - 1; i++) {
289 rstr = rb_inspect(*ptr);
290 fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr),
291 ptr++);
294 ptr = cfp->bp;
295 for (; ptr < sp; ptr++, i++) {
296 if (*ptr == Qundef) {
297 rstr = rb_str_new2("undef");
299 else {
300 rstr = rb_inspect(*ptr);
302 fprintf(stderr, " stack %2d: %8s (%d)\n", i, StringValueCStr(rstr),
303 ptr - th->stack);
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);
310 else {
311 /* SDR(); */
314 else {
315 rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp));
320 void
321 debug_print_register(rb_thread_t *th)
323 rb_control_frame_t *cfp = th->cfp;
324 int pc = -1;
325 int lfp = cfp->lfp - th->stack;
326 int dfp = cfp->dfp - th->stack;
327 int cfpi;
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)
334 lfp = -1;
335 if (dfp < 0 || dfp > th->stack_size)
336 dfp = -1;
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);
343 void
344 thread_dump_regs(VALUE thval)
346 rb_thread_t *th;
347 GetThreadPtr(thval, th);
348 debug_print_register(th);
351 void
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);
364 #if VMDEBUG > 3
365 fprintf(stderr, " (1)");
366 debug_print_register(th);
367 #endif
370 void
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
374 #endif
377 #if VMDEBUG > 9
378 SDR2(cfp);
379 #endif
381 #if VMDEBUG > 3
382 fprintf(stderr, " (2)");
383 debug_print_register(th);
384 #endif
385 /* stack_dump_raw(th, cfp); */
387 #if VMDEBUG > 2
388 /* stack_dump_thobj(th); */
389 stack_dump_each(th, th->cfp);
390 #if OPT_STACK_CACHING
392 VALUE rstr;
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));
398 #endif
399 printf
400 ("--------------------------------------------------------------\n");
401 #endif
404 #ifdef COLLECT_USAGE_ANALYSIS
405 /* uh = {
406 * insn(Fixnum) => ihash(Hash)
408 * ihash = {
409 * -1(Fixnum) => count, # insn usage
410 * 0(Fixnum) => ophash, # operand usage
412 * ophash = {
413 * val(interned string) => count(Fixnum)
416 void
417 vm_analysis_insn(int insn)
419 static ID usage_hash;
420 static ID bigram_hash;
421 static int prev_insn = -1;
423 VALUE uh;
424 VALUE ihash;
425 VALUE cv;
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) {
437 cv = INT2FIX(0);
439 rb_hash_aset(ihash, INT2FIX(-1), INT2FIX(FIX2INT(cv) + 1));
441 /* calc bigram */
442 if (prev_insn != -1) {
443 VALUE bi;
444 VALUE ary[2];
445 VALUE cv;
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) {
453 cv = INT2FIX(0);
455 rb_hash_aset(uh, bi, INT2FIX(FIX2INT(cv) + 1));
457 prev_insn = insn;
460 /* from disasm.c */
461 extern VALUE insn_operand_intern(int insn, int op_no, VALUE op,
462 int len, int pos, VALUE child);
464 void
465 vm_analysis_operand(int insn, int n, VALUE op)
467 static ID usage_hash;
469 VALUE uh;
470 VALUE ihash;
471 VALUE ophash;
472 VALUE valstr;
473 VALUE cv;
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);
488 /* intern */
489 valstr = insn_operand_intern(insn, n, op, 0, 0, 0);
491 /* set count */
492 if ((cv = rb_hash_aref(ophash, valstr)) == Qnil) {
493 cv = INT2FIX(0);
495 rb_hash_aset(ophash, valstr, INT2FIX(FIX2INT(cv) + 1));
498 void
499 vm_analysis_register(int reg, int isset)
501 static ID usage_hash;
502 VALUE uh;
503 VALUE rhash;
504 VALUE valstr;
505 char *regstrs[] = {
506 "pc", /* 0 */
507 "sp", /* 1 */
508 "cfp", /* 2 */
509 "lfp", /* 3 */
510 "dfp", /* 4 */
511 "self", /* 5 */
512 "iseq", /* 6 */
514 char *getsetstr[] = {
515 "get",
516 "set",
518 static VALUE syms[sizeof(regstrs) / sizeof(regstrs[0])][2];
520 VALUE cv;
522 if (usage_hash == 0) {
523 char buff[0x10];
524 int i;
526 usage_hash = rb_intern("USAGE_ANALYSIS_REGS");
528 for (i = 0; i < sizeof(regstrs) / sizeof(regstrs[0]); i++) {
529 int j;
530 for (j = 0; j < 2; j++) {
531 snfprintf(stderr, buff, 0x10, "%d %s %-4s", i, getsetstr[j],
532 regstrs[i]);
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) {
541 cv = INT2FIX(0);
543 rb_hash_aset(uh, valstr, INT2FIX(FIX2INT(cv) + 1));
547 #endif
550 VALUE
551 thread_dump_state(VALUE self)
553 rb_thread_t *th;
554 rb_control_frame_t *cfp;
555 GetThreadPtr(self, th);
556 cfp = th->cfp;
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);
562 return Qnil;
565 void
566 rb_vm_bugreport(void)
568 rb_thread_t *th = GET_THREAD();
569 VALUE bt;
571 if (GET_THREAD()->vm) {
572 int i;
573 SDR();
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]);
582 #if HAVE_BACKTRACE
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);
588 int i;
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");
596 #endif