From 29ecc3840a6df57deba9b22d917aee37f66ffc4f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 17 Dec 2019 23:16:20 +0900 Subject: Refine output of `mrb_print_error()` The following improvements are made according to Ruby's behavior: - Match location number to index. - Remove duplicate most recent call output. - Fix that first call is not output when array (unpacked) backtrace. ### Example ```ruby def a; raise "error!" end def b; a end begin b rescue => e e.backtrace if ARGV[0] == "unpack" # unpack backtrace raise e end ``` #### Before this patch: ``` $ bin/mruby example.rb unpack trace (most recent call last): [0] example.rb:2:in b [1] example.rb:1:in a example.rb:1: error! (RuntimeError) ``` #### After this patch: ``` $ bin/mruby example.rb unpack trace (most recent call last): [2] example.rb:4 [1] example.rb:2:in b example.rb:1:in a: error! (RuntimeError) ``` --- src/backtrace.c | 71 +++++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 43 deletions(-) (limited to 'src/backtrace.c') diff --git a/src/backtrace.c b/src/backtrace.c index 4ae2bc89d..a25a5adad 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -25,6 +25,10 @@ typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location* static const mrb_data_type bt_type = { "Backtrace", mrb_free }; +mrb_value mrb_exc_to_s(mrb_state *mrb, mrb_value exc); +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass); +mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace); + static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtrace_func func, void *data) { @@ -74,50 +78,35 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, const mrb_code *pc0, each_backtr #ifndef MRB_DISABLE_STDIO static void -print_backtrace(mrb_state *mrb, mrb_value backtrace) +print_backtrace(mrb_state *mrb, struct RObject *exc, mrb_value backtrace) { int i; - mrb_int n; + mrb_int n = RARRAY_LEN(backtrace); + mrb_value *loc, mesg, cname; FILE *stream = stderr; - n = RARRAY_LEN(backtrace) - 1; - if (n == 0) return; - - fprintf(stream, "trace (most recent call last):\n"); - for (i=0; i0; i--,loc--) { + if (mrb_string_p(*loc)) { + fprintf(stream, "\t[%d] %.*s\n", + i, (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); + } } } -} -static void -print_packed_backtrace(mrb_state *mrb, mrb_value packed) -{ - FILE *stream = stderr; - const struct backtrace_location *bt; - int n, i; - int ai = mrb_gc_arena_save(mrb); - - bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type); - if (bt == NULL) return; - n = (int)RDATA(packed)->flags; - if (n == 0) return; - - fprintf(stream, "trace (most recent call last):\n"); - for (i = 0; ifilename, (int)entry->lineno); - if (entry->method_id != 0) { - const char *method_name; - - method_name = mrb_sym_name(mrb, entry->method_id); - fprintf(stream, ":in %s", method_name); - mrb_gc_arena_restore(mrb, ai); - } - fprintf(stream, "\n"); + if (n != 0) { + fprintf(stream, "%.*s: ", (int)RSTRING_LEN(*loc), RSTRING_PTR(*loc)); + } + mesg = mrb_exc_to_s(mrb, mrb_obj_value(exc)); + cname = mrb_mod_to_s(mrb, mrb_obj_value(exc->c)); + if (RSTRING_LEN(mesg) == 0) { + fprintf(stream, "%.*s \n", (int)RSTRING_LEN(cname), RSTRING_PTR(cname)); + } + else { + fprintf(stream, "%.*s (%.*s)\n", + (int)RSTRING_LEN(mesg), RSTRING_PTR(mesg), + (int)RSTRING_LEN(cname), RSTRING_PTR(cname)); } } @@ -137,12 +126,8 @@ mrb_print_backtrace(mrb_state *mrb) backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace")); if (mrb_nil_p(backtrace)) return; - if (mrb_array_p(backtrace)) { - print_backtrace(mrb, backtrace); - } - else { - print_packed_backtrace(mrb, backtrace); - } + if (!mrb_array_p(backtrace)) backtrace = mrb_unpack_backtrace(mrb, backtrace); + print_backtrace(mrb, mrb->exc, backtrace); } #else -- cgit v1.2.3