@@ -6612,14 +6612,15 @@ static const char *get_func_name(JSContext *ctx, JSValue func)
6612
6612
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6613
6613
/* only taken into account if filename is provided */
6614
6614
#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
6615
+ #define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2)
6615
6616
6616
6617
/* if filename != NULL, an additional level is added with the filename
6617
6618
and line number information (used for parse error). */
6618
- static void build_backtrace(JSContext *ctx, JSValue error_obj,
6619
+ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_func,
6619
6620
const char *filename, int line_num, int col_num,
6620
6621
int backtrace_flags)
6621
6622
{
6622
- JSStackFrame *sf;
6623
+ JSStackFrame *sf, *sf_start ;
6623
6624
JSValue stack, prepare, saved_exception;
6624
6625
DynBuf dbuf;
6625
6626
const char *func_name_str;
@@ -6668,7 +6669,20 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj,
6668
6669
if (filename && (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL))
6669
6670
goto done;
6670
6671
6671
- for (sf = rt->current_stack_frame; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
6672
+ sf_start = rt->current_stack_frame;
6673
+
6674
+ /* Find the frame we want to start from. Note that when a filter is used the filter
6675
+ function will be the first, but we also specify we want to skip the first one. */
6676
+ if (backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC) {
6677
+ for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
6678
+ if (js_same_value(ctx, sf->cur_func, filter_func)) {
6679
+ sf_start = sf;
6680
+ break;
6681
+ }
6682
+ }
6683
+ }
6684
+
6685
+ for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
6672
6686
if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
6673
6687
backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
6674
6688
continue;
@@ -6811,7 +6825,7 @@ static JSValue JS_MakeError(JSContext *ctx, JSErrorEnum error_num,
6811
6825
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6812
6826
}
6813
6827
if (add_backtrace)
6814
- build_backtrace(ctx, obj, NULL, 0, 0, 0);
6828
+ build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, 0);
6815
6829
return obj;
6816
6830
}
6817
6831
@@ -17380,7 +17394,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
17380
17394
before if the exception happens in a bytecode
17381
17395
operation */
17382
17396
sf->cur_pc = pc;
17383
- build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0);
17397
+ build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0);
17384
17398
}
17385
17399
if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
17386
17400
while (sp > stack_buf) {
@@ -18968,7 +18982,7 @@ int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const
18968
18982
backtrace_flags = 0;
18969
18983
if (s->cur_func && s->cur_func->backtrace_barrier)
18970
18984
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
18971
- build_backtrace(ctx, ctx->rt->current_exception, s->filename,
18985
+ build_backtrace(ctx, ctx->rt->current_exception, JS_UNDEFINED, s->filename,
18972
18986
s->line_num, s->col_num, backtrace_flags);
18973
18987
return -1;
18974
18988
}
@@ -23470,7 +23484,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
23470
23484
backtrace_flags = 0;
23471
23485
if (s->cur_func && s->cur_func->backtrace_barrier)
23472
23486
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
23473
- build_backtrace(s->ctx, s->ctx->rt->current_exception,
23487
+ build_backtrace(s->ctx, s->ctx->rt->current_exception, JS_UNDEFINED,
23474
23488
s->filename,
23475
23489
s->token.line_num,
23476
23490
s->token.col_num,
@@ -37909,7 +37923,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValue new_target,
37909
37923
}
37910
37924
37911
37925
/* skip the Error() function in the backtrace */
37912
- build_backtrace(ctx, obj, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
37926
+ build_backtrace(ctx, obj, JS_UNDEFINED, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
37913
37927
return obj;
37914
37928
exception:
37915
37929
JS_FreeValue(ctx, obj);
@@ -37999,8 +38013,19 @@ static JSValue js_error_set_prepareStackTrace(JSContext *ctx, JSValue this_val,
37999
38013
return JS_UNDEFINED;
38000
38014
}
38001
38015
38016
+ static JSValue js_error_capture_stack_trace(JSContext *ctx, JSValue this_val,
38017
+ int argc, JSValue *argv)
38018
+ {
38019
+ JSValue v = argv[0];
38020
+ if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
38021
+ return JS_ThrowTypeErrorNotAnObject(ctx);
38022
+ build_backtrace(ctx, v, argv[1], NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL|JS_BACKTRACE_FLAG_FILTER_FUNC);
38023
+ return JS_UNDEFINED;
38024
+ }
38025
+
38002
38026
static const JSCFunctionListEntry js_error_funcs[] = {
38003
38027
JS_CFUNC_DEF("isError", 1, js_error_isError ),
38028
+ JS_CFUNC_DEF("captureStackTrace", 2, js_error_capture_stack_trace),
38004
38029
JS_CGETSET_DEF("stackTraceLimit", js_error_get_stackTraceLimit, js_error_set_stackTraceLimit ),
38005
38030
JS_CGETSET_DEF("prepareStackTrace", js_error_get_prepareStackTrace, js_error_set_prepareStackTrace ),
38006
38031
};
0 commit comments