source: EcnlProtoTool/trunk/mruby-1.2.0/src/backtrace.c@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 4.7 KB
Line 
1/*
2** backtrace.c -
3**
4** See Copyright Notice in mruby.h
5*/
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"
16
17struct backtrace_location {
18 int i;
19 int lineno;
20 const char *filename;
21 const char *method;
22 const char *sep;
23 const char *class_name;
24};
25
26typedef void (*output_stream_func)(mrb_state*, struct backtrace_location*, void*);
27
28#ifndef MRB_DISABLE_STDIO
29
30struct print_backtrace_args {
31 FILE *stream;
32 int tracehead;
33};
34
35static void
36print_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
63static void
64get_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
91static void
92output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_func func, void *data)
93{
94 int i;
95
96 if (ciidx >= mrb->c->ciend - mrb->c->cibase)
97 ciidx = 10; /* ciidx is broken... */
98
99 for (i = ciidx; i >= 0; i--) {
100 struct backtrace_location loc;
101 mrb_callinfo *ci;
102 mrb_irep *irep;
103 mrb_code *pc;
104
105 ci = &mrb->c->cibase[i];
106
107 if (!ci->proc) continue;
108 if (MRB_PROC_CFUNC_P(ci->proc)) continue;
109
110 irep = ci->proc->body.irep;
111
112 if (mrb->c->cibase[i].err) {
113 pc = mrb->c->cibase[i].err;
114 }
115 else if (i+1 <= ciidx) {
116 pc = mrb->c->cibase[i+1].pc - 1;
117 }
118 else {
119 pc = pc0;
120 }
121 loc.filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
122 loc.lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
123
124 if (loc.lineno == -1) continue;
125
126 if (ci->target_class == ci->proc->target_class) {
127 loc.sep = ".";
128 }
129 else {
130 loc.sep = "#";
131 }
132
133 if (!loc.filename) {
134 loc.filename = "(unknown)";
135 }
136
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
144static void
145exc_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.
166*/
167
168#ifndef MRB_DISABLE_STDIO
169
170MRB_API void
171mrb_print_backtrace(mrb_state *mrb)
172{
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)) {
176 return;
177 }
178
179 args.stream = stderr;
180 args.tracehead = TRUE;
181 exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args);
182}
183
184#else
185
186MRB_API void
187mrb_print_backtrace(mrb_state *mrb)
188{
189}
190
191#endif
192
193MRB_API mrb_value
194mrb_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;
202}
203
204MRB_API mrb_value
205mrb_get_backtrace(mrb_state *mrb)
206{
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}
Note: See TracBrowser for help on using the repository browser.