From: Nobuyoshi Nakada Date: 2008-12-09T02:33:53+09:00 Subject: [ruby-core:20432] Re: [Feature #839] Add code on each line of a backtrace output to the screen Hi, At Mon, 8 Dec 2008 18:23:04 +0900, Roger Pack wrote in [ruby-core:20416]: > This patch adds output to unrescued exceptions' output to the command line: Rereading from scripts would have problems: * they can be removed or changed * -e and stdin are N/A * slow. Instead, isn't it enough only when debugging? $ ./ruby -rtracer -e 'def foo;raise;end' -e foo -e:1:in `foo': unhandled exception foo from -e:2:in `
' Index: error.c =================================================================== --- error.c (revision 20580) +++ error.c (working copy) @@ -510,16 +510,31 @@ rb_check_backtrace(VALUE bt) long i; static const char err[] = "backtrace must be Array of String"; + extern VALUE rb_cBacktrace; if (!NIL_P(bt)) { - int t = TYPE(bt); - - if (t == T_STRING) return rb_ary_new3(1, bt); - if (t != T_ARRAY) { + if (IMMEDIATE_P(bt)) { + rb_raise(rb_eTypeError, err); + } + switch (BUILTIN_TYPE(bt)) { + case T_STRING: + return rb_ary_new3(1, bt); + case T_ARRAY: + break; + case T_STRUCT: + if (CLASS_OF(bt) == rb_cBacktrace) + return rb_ary_new3(1, bt); + default: rb_raise(rb_eTypeError, err); } for (i=0;i TRACE_MAX) { Index: vm.c =================================================================== --- vm.c (revision 20580) +++ vm.c (working copy) @@ -33,4 +33,5 @@ VALUE rb_cThread; VALUE rb_cEnv; VALUE rb_mRubyVMFrozenCore; +VALUE rb_cBacktrace; VALUE ruby_vm_global_state_version = 1; @@ -629,4 +630,22 @@ rb_lastline_set(VALUE val) /* backtrace */ +static VALUE +backtrace_to_str(VALUE self) +{ + VALUE *p = RSTRUCT_PTR(self); + VALUE file = p[0], line = p[1], name = p[2]; + VALUE str = p[3]; + if (NIL_P(str)) { + str = rb_sprintf("%s:%d:in `%s'", + NIL_P(file) ? "" : StringValueCStr(file), + NUM2INT(line), StringValueCStr(name)); + if (!OBJ_FROZEN(self) && + (OBJ_UNTRUSTED(self) || rb_safe_level() < 4)) { + p[3] = str; + } + } + return str; +} + int vm_get_sourceline(const rb_control_frame_t *cfp) @@ -654,10 +673,10 @@ static VALUE vm_backtrace_each(rb_thread_t *th, const rb_control_frame_t *limit_cfp, const rb_control_frame_t *cfp, - const char * file, int line_no, VALUE ary) + VALUE ary) { - VALUE str; + VALUE bt, b[3]; + int line_no; while (cfp > limit_cfp) { - str = 0; if (cfp->iseq != 0) { if (cfp->pc != 0) { @@ -665,15 +684,17 @@ vm_backtrace_each(rb_thread_t *th, line_no = vm_get_sourceline(cfp); - file = RSTRING_PTR(iseq->filename); - str = rb_sprintf("%s:%d:in `%s'", - file, line_no, RSTRING_PTR(iseq->name)); - rb_ary_push(ary, str); + b[0] = iseq->filename; + b[1] = INT2NUM(line_no); + b[2] = iseq->name; + bt = rb_class_new_instance(sizeof(b) / sizeof(*b), b, rb_cBacktrace); + rb_ary_push(ary, bt); } } else if (RUBYVM_CFUNC_FRAME_P(cfp)) { - str = rb_sprintf("%s:%d:in `%s'", - file, line_no, - rb_id2name(cfp->method_id)); - rb_ary_push(ary, str); + b[0] = Qnil; + b[1] = INT2FIX(0); + b[2] = rb_id2str(cfp->method_id); + bt = rb_class_new_instance(sizeof(b) / sizeof(*b), b, rb_cBacktrace); + rb_ary_push(ary, bt); } cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp); @@ -704,6 +725,5 @@ vm_backtrace(rb_thread_t *th, int lev) } - ary = vm_backtrace_each(th, RUBY_VM_NEXT_CONTROL_FRAME(cfp), - top_of_cfp, "", 0, ary); + ary = vm_backtrace_each(th, RUBY_VM_NEXT_CONTROL_FRAME(cfp), top_of_cfp, ary); return ary; } @@ -1847,4 +1867,9 @@ Init_VM(void) rb_define_const(rb_cRubyVM, "INSTRUCTION_NAMES", ruby_insns_name_array()); + rb_cBacktrace = rb_struct_define((char*)0, "file", "line", "name", "str", (char*)0); + rb_define_const(rb_cRubyVM, "Backtrace", rb_cBacktrace); + rb_define_method(rb_cBacktrace, "to_str", backtrace_to_str, 0); + rb_define_method(rb_cBacktrace, "inspect", backtrace_to_str, 0); + /* debug functions ::VM::SDR(), ::VM::NSDR() */ #if VMDEBUG -- Nobu Nakada