mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
src/backtrace.c@0:158c61bb030f, 2015-03-25 (annotated)
- Committer:
- mzta
- Date:
- Wed Mar 25 17:36:16 2015 +0000
- Revision:
- 0:158c61bb030f
mirb_mbed initial commit;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzta | 0:158c61bb030f | 1 | /* |
mzta | 0:158c61bb030f | 2 | ** backtrace.c - |
mzta | 0:158c61bb030f | 3 | ** |
mzta | 0:158c61bb030f | 4 | ** See Copyright Notice in mruby.h |
mzta | 0:158c61bb030f | 5 | */ |
mzta | 0:158c61bb030f | 6 | |
mzta | 0:158c61bb030f | 7 | #include <stdarg.h> |
mzta | 0:158c61bb030f | 8 | #include "mruby.h" |
mzta | 0:158c61bb030f | 9 | #include "mruby/variable.h" |
mzta | 0:158c61bb030f | 10 | #include "mruby/proc.h" |
mzta | 0:158c61bb030f | 11 | #include "mruby/array.h" |
mzta | 0:158c61bb030f | 12 | #include "mruby/string.h" |
mzta | 0:158c61bb030f | 13 | #include "mruby/class.h" |
mzta | 0:158c61bb030f | 14 | #include "mruby/debug.h" |
mzta | 0:158c61bb030f | 15 | #include "mruby/error.h" |
mzta | 0:158c61bb030f | 16 | |
mzta | 0:158c61bb030f | 17 | #ifdef ENABLE_STDIO |
mzta | 0:158c61bb030f | 18 | |
mzta | 0:158c61bb030f | 19 | typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); |
mzta | 0:158c61bb030f | 20 | |
mzta | 0:158c61bb030f | 21 | static void |
mzta | 0:158c61bb030f | 22 | print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) |
mzta | 0:158c61bb030f | 23 | { |
mzta | 0:158c61bb030f | 24 | va_list ap; |
mzta | 0:158c61bb030f | 25 | |
mzta | 0:158c61bb030f | 26 | va_start(ap, format); |
mzta | 0:158c61bb030f | 27 | vfprintf((FILE*)stream, format, ap); |
mzta | 0:158c61bb030f | 28 | va_end(ap); |
mzta | 0:158c61bb030f | 29 | } |
mzta | 0:158c61bb030f | 30 | |
mzta | 0:158c61bb030f | 31 | |
mzta | 0:158c61bb030f | 32 | #define MIN_BUFSIZE 127 |
mzta | 0:158c61bb030f | 33 | |
mzta | 0:158c61bb030f | 34 | static void |
mzta | 0:158c61bb030f | 35 | get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) |
mzta | 0:158c61bb030f | 36 | { |
mzta | 0:158c61bb030f | 37 | va_list ap; |
mzta | 0:158c61bb030f | 38 | mrb_value ary, str; |
mzta | 0:158c61bb030f | 39 | int ai; |
mzta | 0:158c61bb030f | 40 | |
mzta | 0:158c61bb030f | 41 | if (level > 0) { |
mzta | 0:158c61bb030f | 42 | return; |
mzta | 0:158c61bb030f | 43 | } |
mzta | 0:158c61bb030f | 44 | |
mzta | 0:158c61bb030f | 45 | ai = mrb_gc_arena_save(mrb); |
mzta | 0:158c61bb030f | 46 | ary = mrb_obj_value((struct RArray*)stream); |
mzta | 0:158c61bb030f | 47 | |
mzta | 0:158c61bb030f | 48 | va_start(ap, format); |
mzta | 0:158c61bb030f | 49 | str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1); |
mzta | 0:158c61bb030f | 50 | va_end(ap); |
mzta | 0:158c61bb030f | 51 | |
mzta | 0:158c61bb030f | 52 | va_start(ap, format); |
mzta | 0:158c61bb030f | 53 | vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap); |
mzta | 0:158c61bb030f | 54 | va_end(ap); |
mzta | 0:158c61bb030f | 55 | |
mzta | 0:158c61bb030f | 56 | mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1); |
mzta | 0:158c61bb030f | 57 | mrb_ary_push(mrb, ary, str); |
mzta | 0:158c61bb030f | 58 | mrb_gc_arena_restore(mrb, ai); |
mzta | 0:158c61bb030f | 59 | } |
mzta | 0:158c61bb030f | 60 | |
mzta | 0:158c61bb030f | 61 | static void |
mzta | 0:158c61bb030f | 62 | output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream) |
mzta | 0:158c61bb030f | 63 | { |
mzta | 0:158c61bb030f | 64 | mrb_callinfo *ci; |
mzta | 0:158c61bb030f | 65 | const char *filename, *method, *sep; |
mzta | 0:158c61bb030f | 66 | int i, lineno, tracehead = 1; |
mzta | 0:158c61bb030f | 67 | |
mzta | 0:158c61bb030f | 68 | if (ciidx >= mrb->c->ciend - mrb->c->cibase) |
mzta | 0:158c61bb030f | 69 | ciidx = 10; /* ciidx is broken... */ |
mzta | 0:158c61bb030f | 70 | |
mzta | 0:158c61bb030f | 71 | for (i = ciidx; i >= 0; i--) { |
mzta | 0:158c61bb030f | 72 | ci = &mrb->c->cibase[i]; |
mzta | 0:158c61bb030f | 73 | filename = NULL; |
mzta | 0:158c61bb030f | 74 | |
mzta | 0:158c61bb030f | 75 | if (!ci->proc) continue; |
mzta | 0:158c61bb030f | 76 | if (MRB_PROC_CFUNC_P(ci->proc)) { |
mzta | 0:158c61bb030f | 77 | continue; |
mzta | 0:158c61bb030f | 78 | } |
mzta | 0:158c61bb030f | 79 | else { |
mzta | 0:158c61bb030f | 80 | mrb_irep *irep = ci->proc->body.irep; |
mzta | 0:158c61bb030f | 81 | mrb_code *pc; |
mzta | 0:158c61bb030f | 82 | |
mzta | 0:158c61bb030f | 83 | if (mrb->c->cibase[i].err) { |
mzta | 0:158c61bb030f | 84 | pc = mrb->c->cibase[i].err; |
mzta | 0:158c61bb030f | 85 | } |
mzta | 0:158c61bb030f | 86 | else if (i+1 <= ciidx) { |
mzta | 0:158c61bb030f | 87 | pc = mrb->c->cibase[i+1].pc - 1; |
mzta | 0:158c61bb030f | 88 | } |
mzta | 0:158c61bb030f | 89 | else { |
mzta | 0:158c61bb030f | 90 | pc = pc0; |
mzta | 0:158c61bb030f | 91 | } |
mzta | 0:158c61bb030f | 92 | filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); |
mzta | 0:158c61bb030f | 93 | lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); |
mzta | 0:158c61bb030f | 94 | } |
mzta | 0:158c61bb030f | 95 | if (lineno == -1) continue; |
mzta | 0:158c61bb030f | 96 | if (ci->target_class == ci->proc->target_class) |
mzta | 0:158c61bb030f | 97 | sep = "."; |
mzta | 0:158c61bb030f | 98 | else |
mzta | 0:158c61bb030f | 99 | sep = "#"; |
mzta | 0:158c61bb030f | 100 | |
mzta | 0:158c61bb030f | 101 | if (!filename) { |
mzta | 0:158c61bb030f | 102 | filename = "(unknown)"; |
mzta | 0:158c61bb030f | 103 | } |
mzta | 0:158c61bb030f | 104 | |
mzta | 0:158c61bb030f | 105 | if (tracehead) { |
mzta | 0:158c61bb030f | 106 | func(mrb, stream, 1, "trace:\n"); |
mzta | 0:158c61bb030f | 107 | tracehead = 0; |
mzta | 0:158c61bb030f | 108 | } |
mzta | 0:158c61bb030f | 109 | method = mrb_sym2name(mrb, ci->mid); |
mzta | 0:158c61bb030f | 110 | if (method) { |
mzta | 0:158c61bb030f | 111 | const char *cn = mrb_class_name(mrb, ci->proc->target_class); |
mzta | 0:158c61bb030f | 112 | |
mzta | 0:158c61bb030f | 113 | if (cn) { |
mzta | 0:158c61bb030f | 114 | func(mrb, stream, 1, "\t[%d] ", i); |
mzta | 0:158c61bb030f | 115 | func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method); |
mzta | 0:158c61bb030f | 116 | func(mrb, stream, 1, "\n"); |
mzta | 0:158c61bb030f | 117 | } |
mzta | 0:158c61bb030f | 118 | else { |
mzta | 0:158c61bb030f | 119 | func(mrb, stream, 1, "\t[%d] ", i); |
mzta | 0:158c61bb030f | 120 | func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method); |
mzta | 0:158c61bb030f | 121 | func(mrb, stream, 1, "\n"); |
mzta | 0:158c61bb030f | 122 | } |
mzta | 0:158c61bb030f | 123 | } |
mzta | 0:158c61bb030f | 124 | else { |
mzta | 0:158c61bb030f | 125 | func(mrb, stream, 1, "\t[%d] ", i); |
mzta | 0:158c61bb030f | 126 | func(mrb, stream, 0, "%s:%d", filename, lineno); |
mzta | 0:158c61bb030f | 127 | func(mrb, stream, 1, "\n"); |
mzta | 0:158c61bb030f | 128 | } |
mzta | 0:158c61bb030f | 129 | } |
mzta | 0:158c61bb030f | 130 | } |
mzta | 0:158c61bb030f | 131 | |
mzta | 0:158c61bb030f | 132 | static void |
mzta | 0:158c61bb030f | 133 | exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) |
mzta | 0:158c61bb030f | 134 | { |
mzta | 0:158c61bb030f | 135 | output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), |
mzta | 0:158c61bb030f | 136 | (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))), |
mzta | 0:158c61bb030f | 137 | func, stream); |
mzta | 0:158c61bb030f | 138 | } |
mzta | 0:158c61bb030f | 139 | |
mzta | 0:158c61bb030f | 140 | /* mrb_print_backtrace/mrb_get_backtrace: |
mzta | 0:158c61bb030f | 141 | |
mzta | 0:158c61bb030f | 142 | function to retrieve backtrace information from the exception. |
mzta | 0:158c61bb030f | 143 | note that if you call method after the exception, call stack will be |
mzta | 0:158c61bb030f | 144 | overwritten. So invoke these functions just after detecting exceptions. |
mzta | 0:158c61bb030f | 145 | */ |
mzta | 0:158c61bb030f | 146 | |
mzta | 0:158c61bb030f | 147 | MRB_API void |
mzta | 0:158c61bb030f | 148 | mrb_print_backtrace(mrb_state *mrb) |
mzta | 0:158c61bb030f | 149 | { |
mzta | 0:158c61bb030f | 150 | if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { |
mzta | 0:158c61bb030f | 151 | return; |
mzta | 0:158c61bb030f | 152 | } |
mzta | 0:158c61bb030f | 153 | exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); |
mzta | 0:158c61bb030f | 154 | } |
mzta | 0:158c61bb030f | 155 | |
mzta | 0:158c61bb030f | 156 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 157 | mrb_exc_backtrace(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 158 | { |
mzta | 0:158c61bb030f | 159 | mrb_value ary; |
mzta | 0:158c61bb030f | 160 | |
mzta | 0:158c61bb030f | 161 | ary = mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 162 | exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary)); |
mzta | 0:158c61bb030f | 163 | |
mzta | 0:158c61bb030f | 164 | return ary; |
mzta | 0:158c61bb030f | 165 | } |
mzta | 0:158c61bb030f | 166 | |
mzta | 0:158c61bb030f | 167 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 168 | mrb_get_backtrace(mrb_state *mrb) |
mzta | 0:158c61bb030f | 169 | { |
mzta | 0:158c61bb030f | 170 | mrb_value ary; |
mzta | 0:158c61bb030f | 171 | mrb_callinfo *ci = mrb->c->ci; |
mzta | 0:158c61bb030f | 172 | mrb_code *pc = ci->pc; |
mzta | 0:158c61bb030f | 173 | mrb_int ciidx = (mrb_int)(ci - mrb->c->cibase - 1); |
mzta | 0:158c61bb030f | 174 | |
mzta | 0:158c61bb030f | 175 | if (ciidx < 0) ciidx = 0; |
mzta | 0:158c61bb030f | 176 | ary = mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 177 | output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary)); |
mzta | 0:158c61bb030f | 178 | |
mzta | 0:158c61bb030f | 179 | return ary; |
mzta | 0:158c61bb030f | 180 | } |
mzta | 0:158c61bb030f | 181 | |
mzta | 0:158c61bb030f | 182 | #else |
mzta | 0:158c61bb030f | 183 | |
mzta | 0:158c61bb030f | 184 | MRB_API void |
mzta | 0:158c61bb030f | 185 | mrb_print_backtrace(mrb_state *mrb) |
mzta | 0:158c61bb030f | 186 | { |
mzta | 0:158c61bb030f | 187 | } |
mzta | 0:158c61bb030f | 188 | |
mzta | 0:158c61bb030f | 189 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 190 | mrb_exc_backtrace(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 191 | { |
mzta | 0:158c61bb030f | 192 | return mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 193 | } |
mzta | 0:158c61bb030f | 194 | |
mzta | 0:158c61bb030f | 195 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 196 | mrb_get_backtrace(mrb_state *mrb) |
mzta | 0:158c61bb030f | 197 | { |
mzta | 0:158c61bb030f | 198 | return mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 199 | } |
mzta | 0:158c61bb030f | 200 | |
mzta | 0:158c61bb030f | 201 | #endif |
mzta | 0:158c61bb030f | 202 |