source: EcnlProtoTool/trunk/mruby-1.3.0/src/backtrace.c@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 5.8 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#include <mruby/data.h>
17
18struct backtrace_location {
19 int lineno;
20 const char *filename;
21 mrb_sym method_id;
22};
23
24typedef void (*each_backtrace_func)(mrb_state*, int i, struct backtrace_location*, void*);
25
26static const mrb_data_type bt_type = { "Backtrace", mrb_free };
27
28static void
29each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func func, void *data)
30{
31 int i, j;
32
33 if (ciidx >= mrb->c->ciend - mrb->c->cibase)
34 ciidx = 10; /* ciidx is broken... */
35
36 for (i=ciidx, j=0; i >= 0; i--,j++) {
37 struct backtrace_location loc;
38 mrb_callinfo *ci;
39 mrb_irep *irep;
40 mrb_code *pc;
41
42 ci = &mrb->c->cibase[i];
43
44 if (!ci->proc) continue;
45 if (MRB_PROC_CFUNC_P(ci->proc)) continue;
46
47 irep = ci->proc->body.irep;
48 if (!irep) continue;
49
50 if (mrb->c->cibase[i].err) {
51 pc = mrb->c->cibase[i].err;
52 }
53 else if (i+1 <= ciidx) {
54 pc = mrb->c->cibase[i+1].pc - 1;
55 }
56 else {
57 pc = pc0;
58 }
59 loc.filename = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
60 loc.lineno = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
61
62 if (loc.lineno == -1) continue;
63
64 if (!loc.filename) {
65 loc.filename = "(unknown)";
66 }
67
68 loc.method_id = ci->mid;
69 func(mrb, j, &loc, data);
70 }
71}
72
73#ifndef MRB_DISABLE_STDIO
74
75static void
76print_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
94static void
95print_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.
127*/
128
129MRB_API void
130mrb_print_backtrace(mrb_state *mrb)
131{
132 mrb_value backtrace;
133
134 if (!mrb->exc) {
135 return;
136 }
137
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}
147#else
148
149MRB_API void
150mrb_print_backtrace(mrb_state *mrb)
151{
152}
153
154#endif
155
156static void
157pack_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
167static mrb_value
168packed_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
183void
184mrb_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
194mrb_value
195mrb_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
228MRB_API mrb_value
229mrb_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;
242}
243
244MRB_API mrb_value
245mrb_get_backtrace(mrb_state *mrb)
246{
247 return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
248}
Note: See TracBrowser for help on using the repository browser.