| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "backtrace.h" |
|
2
|
|
|
|
|
|
|
#include |
|
3
|
|
|
|
|
|
|
#include |
|
4
|
|
|
|
|
|
|
#include |
|
5
|
|
|
|
|
|
|
#include "PerlTrace.h" |
|
6
|
|
|
|
|
|
|
#include |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
using namespace panda; |
|
9
|
|
|
|
|
|
|
using panda::Backtrace; |
|
10
|
|
|
|
|
|
|
using xs::my_perl; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#ifndef CvHASGV |
|
13
|
|
|
|
|
|
|
// for perls < 5.22 |
|
14
|
|
|
|
|
|
|
#define CvHASGV(cv) cBOOL(SvANY(cv)->xcv_gv_u.xcv_gv) |
|
15
|
|
|
|
|
|
|
#endif |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
namespace xs { |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
using PerlTraceSP = iptr; |
|
21
|
|
|
|
|
|
|
|
|
22
|
106
|
|
|
|
|
|
static string stringize_arg(SV* it) { |
|
23
|
106
|
|
|
|
|
|
string value; |
|
24
|
106
|
50
|
|
|
|
|
if (SvIS_FREED(it)) { value = "n/a"; } // already freed |
|
|
|
0
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
else { |
|
26
|
212
|
|
|
|
|
|
Sv sv(it); |
|
27
|
106
|
|
|
|
|
|
bool escape = false; |
|
28
|
106
|
100
|
|
|
|
|
if (!sv.defined()) { value += "undef"; } |
|
|
|
50
|
|
|
|
|
|
|
29
|
104
|
100
|
|
|
|
|
else if (sv.is_simple()) { |
|
30
|
100
|
50
|
|
|
|
|
Simple simple(sv); |
|
31
|
50
|
50
|
|
|
|
|
value = simple.as_string(); |
|
|
|
50
|
|
|
|
|
|
|
32
|
50
|
50
|
|
|
|
|
escape = !simple.is_like_number(); |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
else { |
|
35
|
|
|
|
|
|
|
char buff[32]; |
|
36
|
54
|
50
|
|
|
|
|
auto res = to_chars(buff, buff+32, uint64_t(it), 16); |
|
37
|
54
|
50
|
|
|
|
|
if (!res.ec) { |
|
38
|
54
|
|
|
|
|
|
escape = true; |
|
39
|
54
|
|
|
|
|
|
auto size = res.ptr - buff; |
|
40
|
108
|
50
|
|
|
|
|
string addr = string("(0x") + string(buff, static_cast(size)) + ")"; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
108
|
|
|
|
|
|
string type = "UNKNOWN"; |
|
43
|
54
|
50
|
|
|
|
|
if (sv.is_io_ref()) { type = "IO"; } |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
44
|
54
|
50
|
|
|
|
|
else if(sv.is_sub_ref()) { type = "CODE"; } |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
45
|
9
|
50
|
|
|
|
|
else if(sv.is_array_ref()) { type = "ARRAY"; } |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
46
|
7
|
50
|
|
|
|
|
else if(sv.is_hash_ref()) { type = "HASH"; } |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
47
|
2
|
50
|
|
|
|
|
else if(sv.is_stash()) { type = "STASH"; } |
|
|
|
0
|
|
|
|
|
|
|
48
|
2
|
50
|
|
|
|
|
else if(sv.is_ref()) { type = "SCALAR"; } |
|
|
|
50
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
|
50
|
54
|
100
|
|
|
|
|
if(sv.is_object_ref()) { |
|
51
|
3
|
50
|
|
|
|
|
addr = string("=") + type + addr; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
52
|
6
|
50
|
|
|
|
|
Object obj(sv); |
|
53
|
3
|
50
|
|
|
|
|
type = obj.stash().effective_name(); |
|
|
|
50
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
} |
|
55
|
54
|
50
|
|
|
|
|
value = type + addr; |
|
|
|
50
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
} |
|
57
|
54
|
0
|
|
|
|
|
else { value = "*ERROR*"; } |
|
58
|
|
|
|
|
|
|
} |
|
59
|
106
|
100
|
|
|
|
|
value = (escape ? "'" : "") + value + (escape ? "'" : ""); |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
} |
|
61
|
106
|
|
|
|
|
|
return value; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
139
|
|
|
|
|
|
static std::vector get_args(const PERL_CONTEXT* cx) { |
|
65
|
139
|
|
|
|
|
|
std::vector r; |
|
66
|
139
|
100
|
|
|
|
|
if (CxTYPE(cx) == CXt_SUB && CxHASARGS(cx)) { |
|
|
|
50
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
/* slot 0 of the pad contains the original @_ */ |
|
68
|
91
|
|
|
|
|
|
AV * const ary = MUTABLE_AV(AvARRAY(MUTABLE_AV(PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[cx->blk_sub.olddepth+1]))[0]); |
|
69
|
91
|
50
|
|
|
|
|
auto args_count = av_top_index(ary); |
|
70
|
|
|
|
|
|
|
//auto off = AvARRAY(ary) - AvALLOC(ary); |
|
71
|
91
|
|
|
|
|
|
auto off = 0; |
|
72
|
91
|
|
|
|
|
|
auto arr = AvARRAY(ary); |
|
73
|
91
|
|
|
|
|
|
auto last = args_count + off; |
|
74
|
197
|
100
|
|
|
|
|
for(decltype(off) i = off; i <= last; ++i) { |
|
75
|
106
|
|
|
|
|
|
auto it = arr[i]; |
|
76
|
106
|
50
|
|
|
|
|
r.emplace_back(stringize_arg(it)); |
|
|
|
50
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
} |
|
79
|
139
|
|
|
|
|
|
return r; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
25
|
|
|
|
|
|
static PerlTraceSP get_trace() noexcept { |
|
83
|
|
|
|
|
|
|
dTHX; |
|
84
|
50
|
|
|
|
|
|
std::vector frames; |
|
85
|
25
|
|
|
|
|
|
I32 level = 0; |
|
86
|
25
|
|
|
|
|
|
const PERL_CONTEXT *dbcx = nullptr; |
|
87
|
25
|
|
|
|
|
|
const PERL_CONTEXT* cx = caller_cx(level, &dbcx); |
|
88
|
164
|
100
|
|
|
|
|
while (cx) { |
|
89
|
139
|
50
|
|
|
|
|
auto pv_raw = CopSTASHPV(cx->blk_oldcop); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
90
|
139
|
50
|
|
|
|
|
auto file = CopFILE(cx->blk_oldcop); |
|
91
|
139
|
|
|
|
|
|
auto line = CopLINE(cx->blk_oldcop); |
|
92
|
|
|
|
|
|
|
|
|
93
|
278
|
|
|
|
|
|
xs::Sub sub; |
|
94
|
278
|
|
|
|
|
|
string name; |
|
95
|
278
|
|
|
|
|
|
string library; |
|
96
|
139
|
100
|
|
|
|
|
if ((CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)) { |
|
|
|
50
|
|
|
|
|
|
|
97
|
91
|
50
|
|
|
|
|
if (CvHASGV(dbcx->blk_sub.cv)) { |
|
98
|
182
|
|
|
|
|
|
xs::Sub sub(dbcx->blk_sub.cv); |
|
99
|
91
|
|
|
|
|
|
name = sub.name(); |
|
100
|
|
|
|
|
|
|
// just sub.stash().name() can't be called, as it omits |
|
101
|
|
|
|
|
|
|
// the effects of Sub::Name |
|
102
|
91
|
|
|
|
|
|
library = sub.glob().effective_stash().name(); |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} else { |
|
105
|
0
|
|
|
|
|
|
name = "(unknown)"; |
|
106
|
91
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
} else { |
|
108
|
48
|
|
|
|
|
|
name = "(eval)"; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
139
|
100
|
|
|
|
|
if (!library && pv_raw) { library = pv_raw; }; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
|
113
|
278
|
|
|
|
|
|
auto args = get_args(cx); |
|
114
|
|
|
|
|
|
|
|
|
115
|
278
|
|
|
|
|
|
StackframeSP frame(new Stackframe()); |
|
116
|
139
|
|
|
|
|
|
frame->library = library; |
|
117
|
139
|
|
|
|
|
|
frame->file = file; |
|
118
|
139
|
|
|
|
|
|
frame->line_no = line; |
|
119
|
139
|
|
|
|
|
|
frame->name = name; |
|
120
|
139
|
|
|
|
|
|
frame->args = std::move(args); |
|
121
|
139
|
|
|
|
|
|
frames.emplace_back(std::move(frame)); |
|
122
|
|
|
|
|
|
|
|
|
123
|
139
|
|
|
|
|
|
++level; |
|
124
|
139
|
|
|
|
|
|
cx = caller_cx(level, &dbcx); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
25
|
|
|
|
|
|
return new PerlTrace(std::move(frames)); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Sv::payload_marker_t backtrace_c_marker{}; |
|
132
|
|
|
|
|
|
|
Sv::payload_marker_t backtrace_perl_marker{}; |
|
133
|
|
|
|
|
|
|
|
|
134
|
17
|
|
|
|
|
|
int payload_backtrace_c_free(pTHX_ SV*, MAGIC* mg) { |
|
135
|
17
|
50
|
|
|
|
|
if (mg->mg_virtual == &backtrace_c_marker) { |
|
136
|
17
|
|
|
|
|
|
auto* payload = static_cast((void*)mg->mg_ptr); |
|
137
|
17
|
50
|
|
|
|
|
delete payload; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
17
|
|
|
|
|
|
return 0; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
13
|
|
|
|
|
|
string _get_backtrace_string(Ref except, bool include_c_trace) { |
|
143
|
13
|
|
|
|
|
|
string result; |
|
144
|
26
|
|
|
|
|
|
auto it = except.value(); |
|
145
|
13
|
100
|
|
|
|
|
if (include_c_trace) { |
|
146
|
24
|
|
|
|
|
|
string c_trace; |
|
147
|
12
|
100
|
|
|
|
|
if (it.payload_exists(&backtrace_c_marker)) { |
|
148
|
11
|
|
|
|
|
|
auto payload = it.payload(&backtrace_c_marker); |
|
149
|
11
|
|
|
|
|
|
auto bt = static_cast(payload.ptr); |
|
150
|
22
|
|
|
|
|
|
auto bt_info = bt->get_backtrace_info(); |
|
151
|
11
|
50
|
|
|
|
|
if (bt_info) { |
|
152
|
11
|
50
|
|
|
|
|
c_trace += "C backtrace:\n"; |
|
153
|
11
|
50
|
|
|
|
|
c_trace += bt_info->to_string(); |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
} |
|
156
|
12
|
100
|
|
|
|
|
if (!c_trace) { result = "\n"; } |
|
|
|
50
|
|
|
|
|
|
|
157
|
11
|
50
|
|
|
|
|
else { result = c_trace; } |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
13
|
100
|
|
|
|
|
if (it.payload_exists(&backtrace_perl_marker)) { |
|
161
|
12
|
50
|
|
|
|
|
result += "Perl backtrace:\n"; |
|
162
|
12
|
|
|
|
|
|
auto payload = it.payload(&backtrace_perl_marker); |
|
163
|
12
|
50
|
|
|
|
|
auto bt = xs::in(payload.obj); |
|
164
|
83
|
100
|
|
|
|
|
for (const auto& frame : bt->get_frames() ) { |
|
165
|
71
|
50
|
|
|
|
|
result += frame->library + "::" + frame->name + " at " + frame->file + ":" + string::from_number(frame->line_no, 10) + "\n"; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
else { |
|
169
|
1
|
50
|
|
|
|
|
result += ""; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
26
|
|
|
|
|
|
return result; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
12
|
50
|
|
|
|
|
string get_backtrace_string(Ref except) { return _get_backtrace_string(except, true); } |
|
175
|
1
|
50
|
|
|
|
|
string get_backtrace_string_pp(Ref except) { return _get_backtrace_string(except, false); } |
|
176
|
|
|
|
|
|
|
|
|
177
|
2
|
|
|
|
|
|
panda::iptr get_backtrace(Ref except) { |
|
178
|
2
|
|
|
|
|
|
panda::iptr r; |
|
179
|
4
|
|
|
|
|
|
auto it = except.value(); |
|
180
|
2
|
50
|
|
|
|
|
if (it.payload_exists(&backtrace_perl_marker)) { |
|
181
|
2
|
50
|
|
|
|
|
r = new DualTrace(); |
|
|
|
50
|
|
|
|
|
|
|
182
|
2
|
|
|
|
|
|
auto payload = it.payload(&backtrace_perl_marker); |
|
183
|
2
|
50
|
|
|
|
|
auto bt = xs::in(payload.obj); |
|
184
|
2
|
|
|
|
|
|
r->perl_trace = bt; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
2
|
50
|
|
|
|
|
if (r && it.payload_exists(&backtrace_c_marker)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
187
|
2
|
|
|
|
|
|
auto payload = it.payload(&backtrace_c_marker); |
|
188
|
2
|
|
|
|
|
|
auto bt = static_cast(payload.ptr); |
|
189
|
2
|
|
|
|
|
|
r->c_trace = bt->get_backtrace_info(); |
|
190
|
|
|
|
|
|
|
} |
|
191
|
4
|
|
|
|
|
|
return r; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
1
|
|
|
|
|
|
panda::iptr create_backtrace() { |
|
195
|
1
|
50
|
|
|
|
|
panda::iptr r(new DualTrace()); |
|
|
|
50
|
|
|
|
|
|
|
196
|
2
|
|
|
|
|
|
Backtrace bt; |
|
197
|
1
|
|
|
|
|
|
r->c_trace = bt.get_backtrace_info(); |
|
198
|
1
|
|
|
|
|
|
r->perl_trace = get_trace(); |
|
199
|
2
|
|
|
|
|
|
return r; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
26
|
|
|
|
|
|
Ref _is_safe_to_wrap(Sv& ex, bool add_frame_info) { |
|
203
|
26
|
|
|
|
|
|
Ref ref; |
|
204
|
26
|
100
|
|
|
|
|
if (!ex.is_ref()) { |
|
205
|
|
|
|
|
|
|
/* try to mimic perl string error, i.e. "my-error at t/06-c-exceptions.t line 10." |
|
206
|
|
|
|
|
|
|
* we need that as when an exception is thrown from C-code, we wrap it into object |
|
207
|
|
|
|
|
|
|
* and frame info isn't addeded by Perl. |
|
208
|
|
|
|
|
|
|
* |
|
209
|
|
|
|
|
|
|
* When an exception is thrown from Perl, Perl already added frame info. |
|
210
|
|
|
|
|
|
|
*/ |
|
211
|
13
|
100
|
|
|
|
|
if (add_frame_info && ex.is_simple()) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
|
213
|
8
|
50
|
|
|
|
|
auto str = Simple(ex).as_string(); |
|
|
|
50
|
|
|
|
|
|
|
214
|
4
|
50
|
|
|
|
|
bool ends_with_newline = str.size() && str[str.size() - 1] == '\n'; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
215
|
4
|
100
|
|
|
|
|
if (!ends_with_newline) { |
|
216
|
3
|
50
|
|
|
|
|
auto messed = Perl_mess_sv(aTHX_ ex, false); |
|
217
|
3
|
50
|
|
|
|
|
ref = Stash("Exception::Backtrace").call("new", Simple(messed)); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
} |
|
220
|
13
|
100
|
|
|
|
|
if (!ref) { |
|
221
|
13
|
50
|
|
|
|
|
ref = Stash("Exception::Backtrace").call("new", ex); |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
else { |
|
225
|
26
|
50
|
|
|
|
|
Ref tmp_ref(ex); |
|
226
|
26
|
|
|
|
|
|
auto it = tmp_ref.value(); |
|
227
|
13
|
50
|
|
|
|
|
if (!(it.is_scalar() && it.readonly())) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
228
|
12
|
50
|
|
|
|
|
ref = tmp_ref; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
} |
|
231
|
26
|
|
|
|
|
|
return ref; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
}; |
|
234
|
|
|
|
|
|
|
|
|
235
|
19
|
|
|
|
|
|
static void attach_backtraces(Ref except, const PerlTraceSP& perl_trace) { |
|
236
|
38
|
|
|
|
|
|
auto it = except.value(); |
|
237
|
19
|
100
|
|
|
|
|
if (!it.payload_exists(&backtrace_c_marker)) { |
|
238
|
13
|
50
|
|
|
|
|
auto bt = new Backtrace(); |
|
239
|
13
|
50
|
|
|
|
|
it.payload_attach(bt, &backtrace_c_marker); |
|
240
|
|
|
|
|
|
|
} |
|
241
|
19
|
100
|
|
|
|
|
if (!it.payload_exists(&backtrace_perl_marker)) { |
|
242
|
13
|
50
|
|
|
|
|
it.payload_attach(xs::out(perl_trace.get()), &backtrace_perl_marker); |
|
|
|
50
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
} |
|
244
|
19
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
21
|
|
|
|
|
|
Sv safe_wrap_exception(Sv ex) { |
|
247
|
42
|
50
|
|
|
|
|
auto ref = _is_safe_to_wrap(ex, false); |
|
248
|
21
|
100
|
|
|
|
|
if (ref) { |
|
249
|
40
|
|
|
|
|
|
auto perl_traces = get_trace(); |
|
250
|
20
|
|
|
|
|
|
auto& frames = perl_traces->get_frames(); |
|
251
|
238
|
50
|
|
|
|
|
bool in_destroy = std::any_of(frames.begin(), frames.end(), [](auto& frame) { return frame->name == "DESTROY"; } ); |
|
252
|
20
|
100
|
|
|
|
|
if (in_destroy) { |
|
253
|
|
|
|
|
|
|
// we don't want to corrupt Perl's warning with Exception::Backtrace handler, instead let it warns |
|
254
|
|
|
|
|
|
|
// to the origin of the exception |
|
255
|
1
|
50
|
|
|
|
|
return Simple::undef; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
19
|
50
|
|
|
|
|
attach_backtraces(ref, perl_traces); |
|
|
|
50
|
|
|
|
|
|
|
258
|
19
|
50
|
|
|
|
|
return Sv(ref); |
|
259
|
|
|
|
|
|
|
} |
|
260
|
1
|
50
|
|
|
|
|
return Simple::undef; |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
|
264
|
6
|
|
|
|
|
|
void install_exception_processor() { |
|
265
|
17
|
50
|
|
|
|
|
add_exception_processor([](Sv& ex) -> Sv { |
|
266
|
14
|
50
|
|
|
|
|
auto ref = _is_safe_to_wrap(ex, true); |
|
|
|
100
|
|
|
|
|
|
|
267
|
5
|
50
|
|
|
|
|
if (ref) { |
|
268
|
10
|
|
|
|
|
|
auto it = ref.value(); |
|
269
|
5
|
100
|
|
|
|
|
if (!it.payload_exists(&backtrace_c_marker)) { |
|
270
|
8
|
|
|
|
|
|
try { throw; } |
|
271
|
4
|
50
|
|
|
|
|
catch (const panda::Backtrace& err) { |
|
272
|
|
|
|
|
|
|
// reuse existing c trace |
|
273
|
2
|
50
|
|
|
|
|
it.payload_attach(new Backtrace(err), &backtrace_c_marker); |
|
|
|
50
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
} |
|
275
|
4
|
50
|
|
|
|
|
catch (...) { |
|
276
|
|
|
|
|
|
|
// add new c trace |
|
277
|
2
|
50
|
|
|
|
|
it.payload_attach(new Backtrace(), &backtrace_c_marker); |
|
|
|
50
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
} |
|
280
|
5
|
100
|
|
|
|
|
if (!it.payload_exists(&backtrace_perl_marker)) { |
|
281
|
8
|
|
|
|
|
|
auto bt = get_trace(); |
|
282
|
4
|
50
|
|
|
|
|
it.payload_attach(xs::out(bt), &backtrace_perl_marker); |
|
|
|
50
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
} |
|
284
|
5
|
50
|
|
|
|
|
return Sv(ref); |
|
285
|
|
|
|
|
|
|
} |
|
286
|
0
|
0
|
|
|
|
|
return ex; |
|
287
|
6
|
50
|
|
|
|
|
}); |
|
288
|
6
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
24
|
50
|
|
|
|
|
} |
|
|
|
50
|
|
|
|
|
|