mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
backtrace.c
00001 /* 00002 ** backtrace.c - 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include <stdarg.h> 00008 #include "mruby.h" 00009 #include "mruby/variable.h" 00010 #include "mruby/proc.h" 00011 #include "mruby/array.h" 00012 #include "mruby/string.h" 00013 #include "mruby/class.h" 00014 #include "mruby/debug.h" 00015 #include "mruby/error.h" 00016 00017 #ifdef ENABLE_STDIO 00018 00019 typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...); 00020 00021 static void 00022 print_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) 00023 { 00024 va_list ap; 00025 00026 va_start(ap, format); 00027 vfprintf((FILE*)stream, format, ap); 00028 va_end(ap); 00029 } 00030 00031 00032 #define MIN_BUFSIZE 127 00033 00034 static void 00035 get_backtrace_i(mrb_state *mrb, void *stream, int level, const char *format, ...) 00036 { 00037 va_list ap; 00038 mrb_value ary, str; 00039 int ai; 00040 00041 if (level > 0) { 00042 return; 00043 } 00044 00045 ai = mrb_gc_arena_save(mrb); 00046 ary = mrb_obj_value((struct RArray*)stream); 00047 00048 va_start(ap, format); 00049 str = mrb_str_new(mrb, 0, vsnprintf(NULL, 0, format, ap) + 1); 00050 va_end(ap); 00051 00052 va_start(ap, format); 00053 vsnprintf(RSTRING_PTR(str), RSTRING_LEN(str), format, ap); 00054 va_end(ap); 00055 00056 mrb_str_resize(mrb, str, RSTRING_LEN(str) - 1); 00057 mrb_ary_push(mrb, ary, str); 00058 mrb_gc_arena_restore(mrb, ai); 00059 } 00060 00061 static void 00062 output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *stream) 00063 { 00064 mrb_callinfo *ci; 00065 const char *filename, *method, *sep; 00066 int i, lineno, tracehead = 1; 00067 00068 if (ciidx >= mrb->c->ciend - mrb->c->cibase) 00069 ciidx = 10; /* ciidx is broken... */ 00070 00071 for (i = ciidx; i >= 0; i--) { 00072 ci = &mrb->c->cibase[i]; 00073 filename = NULL; 00074 00075 if (!ci->proc) continue; 00076 if (MRB_PROC_CFUNC_P(ci->proc)) { 00077 continue; 00078 } 00079 else { 00080 mrb_irep *irep = ci->proc->body.irep; 00081 mrb_code *pc; 00082 00083 if (mrb->c->cibase[i].err) { 00084 pc = mrb->c->cibase[i].err; 00085 } 00086 else if (i+1 <= ciidx) { 00087 pc = mrb->c->cibase[i+1].pc - 1; 00088 } 00089 else { 00090 pc = pc0; 00091 } 00092 filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq)); 00093 lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq)); 00094 } 00095 if (lineno == -1) continue; 00096 if (ci->target_class == ci->proc->target_class) 00097 sep = "."; 00098 else 00099 sep = "#"; 00100 00101 if (!filename) { 00102 filename = "(unknown)"; 00103 } 00104 00105 if (tracehead) { 00106 func(mrb, stream, 1, "trace:\n"); 00107 tracehead = 0; 00108 } 00109 method = mrb_sym2name(mrb, ci->mid); 00110 if (method) { 00111 const char *cn = mrb_class_name(mrb, ci->proc->target_class); 00112 00113 if (cn) { 00114 func(mrb, stream, 1, "\t[%d] ", i); 00115 func(mrb, stream, 0, "%s:%d:in %s%s%s", filename, lineno, cn, sep, method); 00116 func(mrb, stream, 1, "\n"); 00117 } 00118 else { 00119 func(mrb, stream, 1, "\t[%d] ", i); 00120 func(mrb, stream, 0, "%s:%d:in %s", filename, lineno, method); 00121 func(mrb, stream, 1, "\n"); 00122 } 00123 } 00124 else { 00125 func(mrb, stream, 1, "\t[%d] ", i); 00126 func(mrb, stream, 0, "%s:%d", filename, lineno); 00127 func(mrb, stream, 1, "\n"); 00128 } 00129 } 00130 } 00131 00132 static void 00133 exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) 00134 { 00135 output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), 00136 (mrb_code*)mrb_cptr(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc"))), 00137 func, stream); 00138 } 00139 00140 /* mrb_print_backtrace/mrb_get_backtrace: 00141 00142 function to retrieve backtrace information from the exception. 00143 note that if you call method after the exception, call stack will be 00144 overwritten. So invoke these functions just after detecting exceptions. 00145 */ 00146 00147 MRB_API void 00148 mrb_print_backtrace(mrb_state *mrb) 00149 { 00150 if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { 00151 return; 00152 } 00153 exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)stderr); 00154 } 00155 00156 MRB_API mrb_value 00157 mrb_exc_backtrace(mrb_state *mrb, mrb_value self) 00158 { 00159 mrb_value ary; 00160 00161 ary = mrb_ary_new(mrb); 00162 exc_output_backtrace(mrb, mrb_obj_ptr(self), get_backtrace_i, (void*)mrb_ary_ptr(ary)); 00163 00164 return ary; 00165 } 00166 00167 MRB_API mrb_value 00168 mrb_get_backtrace(mrb_state *mrb) 00169 { 00170 mrb_value ary; 00171 mrb_callinfo *ci = mrb->c->ci; 00172 mrb_code *pc = ci->pc; 00173 mrb_int ciidx = (mrb_int)(ci - mrb->c->cibase - 1); 00174 00175 if (ciidx < 0) ciidx = 0; 00176 ary = mrb_ary_new(mrb); 00177 output_backtrace(mrb, ciidx, pc, get_backtrace_i, (void*)mrb_ary_ptr(ary)); 00178 00179 return ary; 00180 } 00181 00182 #else 00183 00184 MRB_API void 00185 mrb_print_backtrace(mrb_state *mrb) 00186 { 00187 } 00188 00189 MRB_API mrb_value 00190 mrb_exc_backtrace(mrb_state *mrb, mrb_value self) 00191 { 00192 return mrb_ary_new(mrb); 00193 } 00194 00195 MRB_API mrb_value 00196 mrb_get_backtrace(mrb_state *mrb) 00197 { 00198 return mrb_ary_new(mrb); 00199 } 00200 00201 #endif 00202
Generated on Tue Jul 12 2022 18:00:34 by 1.7.2