Changeset 331 for EcnlProtoTool/trunk/mruby-1.3.0/src/backtrace.c
- Timestamp:
- Jan 21, 2018, 12:10:09 AM (6 years ago)
- Location:
- EcnlProtoTool/trunk/mruby-1.3.0
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
EcnlProtoTool/trunk/mruby-1.3.0/src/backtrace.c
r321 r331 5 5 */ 6 6 7 #include "mruby.h" 8 #include "mruby/variable.h" 9 #include "mruby/proc.h" 10 #include "mruby/array.h" 11 #include "mruby/string.h" 12 #include "mruby/class.h" 13 #include "mruby/debug.h" 14 #include "mruby/error.h" 15 #include "mruby/numeric.h" 7 #include <mruby.h> 8 #include <mruby/variable.h> 9 #include <mruby/proc.h> 10 #include <mruby/array.h> 11 #include <mruby/string.h> 12 #include <mruby/class.h> 13 #include <mruby/debug.h> 14 #include <mruby/error.h> 15 #include <mruby/numeric.h> 16 #include <mruby/data.h> 16 17 17 18 struct backtrace_location { 18 int i;19 19 int lineno; 20 20 const char *filename; 21 const char *method; 22 const char *sep; 23 const char *class_name; 21 mrb_sym method_id; 24 22 }; 25 23 26 typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*); 27 28 #ifndef MRB_DISABLE_STDIO 29 30 struct print_backtrace_args { 31 FILE *stream; 32 int tracehead; 33 }; 34 35 static void 36 print_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) 37 { 38 struct print_backtrace_args *args; 39 40 args = (struct print_backtrace_args*)data; 41 42 if (args->tracehead) { 43 fprintf(args->stream, "trace:\n"); 44 args->tracehead = FALSE; 45 } 46 47 fprintf(args->stream, "\t[%d] %s:%d", loc->i, loc->filename, loc->lineno); 48 49 if (loc->method) { 50 if (loc->class_name) { 51 fprintf(args->stream, ":in %s%s%s", loc->class_name, loc->sep, loc->method); 52 } 53 else { 54 fprintf(args->stream, ":in %s", loc->method); 55 } 56 } 57 58 fprintf(args->stream, "\n"); 59 } 60 61 #endif 62 63 static void 64 get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data) 65 { 66 mrb_value ary, str; 67 int ai; 68 69 ai = mrb_gc_arena_save(mrb); 70 ary = mrb_obj_value((struct RArray*)data); 71 72 str = mrb_str_new_cstr(mrb, loc->filename); 73 mrb_str_cat_lit(mrb, str, ":"); 74 mrb_str_concat(mrb, str, mrb_fixnum_to_str(mrb, mrb_fixnum_value(loc->lineno), 10)); 75 76 if (loc->method) { 77 mrb_str_cat_lit(mrb, str, ":in "); 78 79 if (loc->class_name) { 80 mrb_str_cat_cstr(mrb, str, loc->class_name); 81 mrb_str_cat_cstr(mrb, str, loc->sep); 82 } 83 84 mrb_str_cat_cstr(mrb, str, loc->method); 85 } 86 87 mrb_ary_push(mrb, ary, str); 88 mrb_gc_arena_restore(mrb, ai); 89 } 90 91 static void 92 output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data) 93 { 94 int i; 24 typedef void (*each_backtrace_func)(mrb_state*, int i, struct backtrace_location*, void*); 25 26 static const mrb_data_type bt_type = { "Backtrace", mrb_free }; 27 28 static void 29 each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data) 30 { 31 int i, j; 95 32 96 33 if (ciidx >= mrb->c->ciend - mrb->c->cibase) 97 34 ciidx = 10; /* ciidx is broken... */ 98 35 99 for (i = ciidx; i >= 0; i--) {36 for (i=ciidx, j=0; i >= 0; i--,j++) { 100 37 struct backtrace_location loc; 101 38 mrb_callinfo *ci; … … 109 46 110 47 irep = ci->proc->body.irep; 48 if (!irep) continue; 111 49 112 50 if (mrb->c->cibase[i].err) { … … 124 62 if (loc.lineno == -1) continue; 125 63 126 if (ci->target_class == ci->proc->target_class) {127 loc.sep = ".";128 }129 else {130 loc.sep = "#";131 }132 133 64 if (!loc.filename) { 134 65 loc.filename = "(unknown)"; 135 66 } 136 67 137 loc.method = mrb_sym2name(mrb, ci->mid); 138 loc.class_name = mrb_class_name(mrb, ci->proc->target_class); 139 loc.i = i; 140 func(mrb, &loc, data); 141 } 142 } 143 144 static void 145 exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) 146 { 147 mrb_value lastpc; 148 mrb_code *code; 149 150 lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc")); 151 if (mrb_nil_p(lastpc)) { 152 code = NULL; 153 } else { 154 code = (mrb_code*)mrb_cptr(lastpc); 155 } 156 157 output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), 158 code, func, stream); 159 } 160 161 /* mrb_print_backtrace/mrb_get_backtrace: 162 163 function to retrieve backtrace information from the exception. 164 note that if you call method after the exception, call stack will be 165 overwritten. So invoke these functions just after detecting exceptions. 68 loc.method_id = ci->mid; 69 func(mrb, j, &loc, data); 70 } 71 } 72 73 #ifndef MRB_DISABLE_STDIO 74 75 static void 76 print_backtrace(mrb_state *mrb, mrb_value backtrace) 77 { 78 int i, n; 79 FILE *stream = stderr; 80 81 if (!mrb_array_p(backtrace)) return; 82 fprintf(stream, "trace:\n"); 83 84 n = RARRAY_LEN(backtrace); 85 for (i=0; n--; i++) { 86 mrb_value entry = RARRAY_PTR(backtrace)[n]; 87 88 if (mrb_string_p(entry)) { 89 fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); 90 } 91 } 92 } 93 94 static void 95 print_packed_backtrace(mrb_state *mrb, mrb_value packed) 96 { 97 FILE *stream = stderr; 98 struct backtrace_location *bt; 99 int n, i; 100 101 bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type); 102 if (bt == NULL) { 103 mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace"); 104 } 105 n = (mrb_int)RDATA(packed)->flags; 106 107 fprintf(stream, "trace:\n"); 108 for (i = 0; n--; i++) { 109 int ai = mrb_gc_arena_save(mrb); 110 struct backtrace_location *entry = &bt[n]; 111 if (entry->filename == NULL) continue; 112 fprintf(stream, "\t[%d] %s:%d", (int)i, entry->filename, entry->lineno); 113 if (entry->method_id != 0) { 114 const char *method_name; 115 116 method_name = mrb_sym2name(mrb, entry->method_id); 117 fprintf(stream, ":in %s", method_name); 118 mrb_gc_arena_restore(mrb, ai); 119 } 120 fprintf(stream, "\n"); 121 } 122 } 123 124 /* mrb_print_backtrace 125 126 function to retrieve backtrace information from the last exception. 166 127 */ 167 168 #ifndef MRB_DISABLE_STDIO169 128 170 129 MRB_API void 171 130 mrb_print_backtrace(mrb_state *mrb) 172 131 { 173 struct print_backtrace_args args;174 175 if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) {132 mrb_value backtrace; 133 134 if (!mrb->exc) { 176 135 return; 177 136 } 178 137 179 args.stream = stderr; 180 args.tracehead = TRUE; 181 exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args); 182 } 183 138 backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace")); 139 if (mrb_nil_p(backtrace)) return; 140 if (mrb_array_p(backtrace)) { 141 print_backtrace(mrb, backtrace); 142 } 143 else { 144 print_packed_backtrace(mrb, backtrace); 145 } 146 } 184 147 #else 185 148 … … 191 154 #endif 192 155 156 static void 157 pack_backtrace_i(mrb_state *mrb, 158 int i, 159 struct backtrace_location *loc, 160 void *data) 161 { 162 struct backtrace_location *entry = (struct backtrace_location*)data; 163 164 entry[i] = *loc; 165 } 166 167 static mrb_value 168 packed_backtrace(mrb_state *mrb) 169 { 170 struct RData *backtrace; 171 ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase; 172 mrb_int len = (ciidx+1)*sizeof(struct backtrace_location); 173 void *ptr; 174 175 ptr = mrb_malloc(mrb, len); 176 memset(ptr, 0, len); 177 backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); 178 backtrace->flags = (unsigned int)ciidx+1; 179 each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, ptr); 180 return mrb_obj_value(backtrace); 181 } 182 183 void 184 mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) 185 { 186 mrb_value backtrace; 187 int ai = mrb_gc_arena_save(mrb); 188 189 backtrace = packed_backtrace(mrb); 190 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); 191 mrb_gc_arena_restore(mrb, ai); 192 } 193 194 mrb_value 195 mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) 196 { 197 struct backtrace_location *bt; 198 mrb_int n, i; 199 200 if (mrb_nil_p(backtrace)) return mrb_ary_new_capa(mrb, 0); 201 if (mrb_array_p(backtrace)) return backtrace; 202 bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type); 203 if (bt == NULL) { 204 mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace"); 205 } 206 n = (mrb_int)RDATA(backtrace)->flags; 207 backtrace = mrb_ary_new_capa(mrb, n); 208 for (i = 0; i < n; i++) { 209 int ai = mrb_gc_arena_save(mrb); 210 struct backtrace_location *entry = &bt[i]; 211 mrb_value btline; 212 213 if (entry->filename == NULL) continue; 214 btline = mrb_format(mrb, "%S:%S", 215 mrb_str_new_cstr(mrb, entry->filename), 216 mrb_fixnum_value(entry->lineno)); 217 if (entry->method_id != 0) { 218 mrb_str_cat_lit(mrb, btline, ":in "); 219 mrb_str_cat_cstr(mrb, btline, mrb_sym2name(mrb, entry->method_id)); 220 } 221 mrb_ary_push(mrb, backtrace, btline); 222 mrb_gc_arena_restore(mrb, ai); 223 } 224 225 return backtrace; 226 } 227 193 228 MRB_API mrb_value 194 mrb_exc_backtrace(mrb_state *mrb, mrb_value self) 195 { 196 mrb_value ary; 197 198 ary = mrb_ary_new(mrb); 199 exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary)); 200 201 return ary; 229 mrb_exc_backtrace(mrb_state *mrb, mrb_value exc) 230 { 231 mrb_sym attr_name; 232 mrb_value backtrace; 233 234 attr_name = mrb_intern_lit(mrb, "backtrace"); 235 backtrace = mrb_iv_get(mrb, exc, attr_name); 236 if (mrb_nil_p(backtrace) || mrb_array_p(backtrace)) { 237 return backtrace; 238 } 239 backtrace = mrb_unpack_backtrace(mrb, backtrace); 240 mrb_iv_set(mrb, exc, attr_name, backtrace); 241 return backtrace; 202 242 } 203 243 … … 205 245 mrb_get_backtrace(mrb_state *mrb) 206 246 { 207 mrb_value ary; 208 mrb_callinfo *ci = mrb->c->ci; 209 mrb_code *pc = ci->pc; 210 mrb_int ciidx = (mrb_int)(ci - mrb->c->cibase - 1); 211 212 if (ciidx < 0) ciidx = 0; 213 ary = mrb_ary_new(mrb); 214 output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary)); 215 216 return ary; 217 } 247 return mrb_unpack_backtrace(mrb, packed_backtrace(mrb)); 248 }
Note:
See TracChangeset
for help on using the changeset viewer.