diff options
| author | Simon Génier <[email protected]> | 2015-02-12 13:18:59 -0500 |
|---|---|---|
| committer | Simon Génier <[email protected]> | 2015-02-12 13:18:59 -0500 |
| commit | 40e4eb599cb993ed183a9e3043c4b2bb11ec2cd2 (patch) | |
| tree | 810812c749012e76d1e9e11a4bcec9f9dd3f586b /src/backtrace.c | |
| parent | 789177c8fe6c3bcb3833e76f95ecbd41b43b83fd (diff) | |
| download | mruby-40e4eb599cb993ed183a9e3043c4b2bb11ec2cd2.tar.gz mruby-40e4eb599cb993ed183a9e3043c4b2bb11ec2cd2.zip | |
DISABLE_STDIO does not disable backtraces.
Diffstat (limited to 'src/backtrace.c')
| -rw-r--r-- | src/backtrace.c | 201 |
1 files changed, 104 insertions, 97 deletions
diff --git a/src/backtrace.c b/src/backtrace.c index 9427c3c8d..a672a6c95 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -4,7 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <stdarg.h> #include "mruby.h" #include "mruby/variable.h" #include "mruby/proc.h" @@ -13,119 +12,132 @@ #include "mruby/class.h" #include "mruby/debug.h" #include "mruby/error.h" +#include "mruby/numeric.h" + +struct backtrace_location { + int i; + int lineno; + const char *filename; + const char *method; + const char *sep; + const char *class_name; +}; + +typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*); #ifdef ENABLE_STDIO -typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); +struct print_backtrace_args { + FILE *stream; + int tracehead; +}; static void -print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) +print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) { - va_list ap; + struct print_backtrace_args *args; - va_start(ap, format); - vfprintf((FILE*)stream, format, ap); - va_end(ap); -} + args = (struct print_backtrace_args*)data; + + if (args->tracehead) { + fprintf(args->stream, "trace:\n"); + args->tracehead = FALSE; + } + + fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno); + + if (loc->method) { + if (loc->class_name) { + fprintf(args->stream, ":in %s%s%s", loc->class_name, loc->sep, loc->method); + } + else { + fprintf(args->stream, ":in %s", loc->method); + } + } + fprintf(args->stream, "\n"); +} -#define MIN_BUFSIZE 127 +#endif static void -get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) +get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) { - va_list ap; mrb_value ary, str; int ai; - if (level > 0) { - return; - } - ai = mrb_gc_arena_save(mrb); - ary = mrb_obj_value((struct RArray*)stream); + ary = mrb_obj_value((struct RArray*)data); - va_start(ap, format); - str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1); - va_end(ap); + str = mrb_str_new_cstr(mrb, loc->filename); + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_fixnum_to_str(mrb, mrb_fixnum_value(loc->lineno), 10)); - va_start(ap, format); - vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap); - va_end(ap); + if (loc->method) { + mrb_str_cat_lit(mrb, str, ":in "); + + if (loc->class_name) { + mrb_str_cat_cstr(mrb, str, loc->class_name); + mrb_str_cat_cstr(mrb, str, loc->sep); + } + + mrb_str_cat_cstr(mrb, str, loc->method); + } - mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1); mrb_ary_push(mrb, ary, str); mrb_gc_arena_restore(mrb, ai); } static void -output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream) +output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data) { - mrb_callinfo *ci; - const char *filename, *method, *sep; - int i, lineno, tracehead = 1; + int i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ for (i = ciidx; i >= 0; i--) { + struct backtrace_location loc; + mrb_callinfo *ci; + mrb_irep *irep; + mrb_code *pc; + ci = &mrb->c->cibase[i]; - filename = NULL; if (!ci->proc) continue; - if (MRB_PROC_CFUNC_P(ci->proc)) { - continue; + if (MRB_PROC_CFUNC_P(ci->proc)) continue; + + irep = ci->proc->body.irep; + + if (mrb->c->cibase[i].err) { + pc = mrb->c->cibase[i].err; } - else { - mrb_irep *irep = ci->proc->body.irep; - mrb_code *pc; - - if (mrb->c->cibase[i].err) { - pc = mrb->c->cibase[i].err; - } - else if (i+1 <= ciidx) { - pc = mrb->c->cibase[i+1].pc - 1; - } - else { - pc = pc0; - } - filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); - lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); + else if (i+1 <= ciidx) { + pc = mrb->c->cibase[i+1].pc - 1; } - if (lineno == -1) continue; - if (ci->target_class == ci->proc->target_class) - sep = "."; - else - sep = "#"; - - if (!filename) { - filename = "(unknown)"; + else { + pc = pc0; } + loc.filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); + loc.lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); - if (tracehead) { - func(mrb, stream, 1, "trace:\n"); - tracehead = 0; - } - method = mrb_sym2name(mrb, ci->mid); - if (method) { - const char *cn = mrb_class_name(mrb, ci->proc->target_class); - - if (cn) { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method); - func(mrb, stream, 1, "\n"); - } - else { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method); - func(mrb, stream, 1, "\n"); - } + if (loc.lineno == -1) continue; + + if (ci->target_class == ci->proc->target_class) { + loc.sep = "."; } else { - func(mrb, stream, 1, "\t[%d] ", i); - func(mrb, stream, 0, "%s:%d", filename, lineno); - func(mrb, stream, 1, "\n"); + loc.sep = "#"; + } + + if (!loc.filename) { + loc.filename = "(unknown)"; } + + loc.method = mrb_sym2name(mrb, ci->mid); + loc.class_name = mrb_class_name(mrb, ci->proc->target_class); + loc.i = i; + func(mrb, &loc, data); } } @@ -134,7 +146,7 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun { mrb_value lastpc; mrb_code *code; - + lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc")); if (mrb_nil_p(lastpc)) { code = NULL; @@ -153,15 +165,31 @@ exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun overwritten. So invoke these functions just after detecting exceptions. */ +#ifdef ENABLE_STDIO + MRB_API void mrb_print_backtrace(mrb_state *mrb) { + struct print_backtrace_args args; + if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { return; } - exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); + + args.stream = stderr; + args.tracehead = TRUE; + exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args); +} + +#else + +MRB_API void +mrb_print_backtrace(mrb_state *mrb) +{ } +#endif + MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value self) { @@ -187,24 +215,3 @@ mrb_get_backtrace(mrb_state *mrb) return ary; } - -#else - -MRB_API void -mrb_print_backtrace(mrb_state *mrb) -{ -} - -MRB_API mrb_value -mrb_exc_backtrace(mrb_state *mrb, mrb_value self) -{ - return mrb_ary_new(mrb); -} - -MRB_API mrb_value -mrb_get_backtrace(mrb_state *mrb) -{ - return mrb_ary_new(mrb); -} - -#endif |
