[njs] Introduced function level backtrace.
Dmitry Volyntsev
xeioex at nginx.com
Tue Aug 29 11:29:01 UTC 2017
details: http://hg.nginx.org/njs/rev/82dc332cb4c8
branches:
changeset: 400:82dc332cb4c8
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Aug 29 14:06:23 2017 +0300
description:
Introduced function level backtrace.
diffstat:
njs/njs.c | 40 +++++++++++-
njs/njs_builtin.c | 133 ++++++++++++++++++++++++++++++++++++++++
njs/njs_generator.c | 48 ++++++++++++++-
njs/njs_parser.c | 2 +
njs/njs_vm.c | 77 +++++++++++++++++++++++
njs/njs_vm.h | 12 +++
njs/njscript.c | 38 +++++++++++
njs/njscript.h | 8 ++
njs/test/njs_interactive_test.c | 102 ++++++++++++++++++++++++++++++-
9 files changed, 454 insertions(+), 6 deletions(-)
diffs (731 lines):
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs.c
--- a/njs/njs.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs.c Tue Aug 29 14:06:23 2017 +0300
@@ -59,6 +59,7 @@ static nxt_int_t njs_interactive_shell(n
static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts,
const nxt_str_t *script, nxt_str_t *out);
+static void njs_print_backtrace(nxt_array_t *backtrace);
static nxt_int_t njs_editline_init(njs_vm_t *vm);
static char **njs_completion_handler(const char *text, int start, int end);
static char *njs_completion_generator(const char *text, int state);
@@ -93,6 +94,7 @@ main(int argc, char **argv)
vm_options.mcp = mcp;
vm_options.accumulative = 1;
+ vm_options.backtrace = 1;
if (opts.interactive) {
ret = njs_interactive_shell(&opts, &vm_options);
@@ -150,9 +152,10 @@ njs_get_options(njs_opts_t *opts, int ar
static nxt_int_t
njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options)
{
- njs_vm_t *vm;
- nxt_int_t ret;
- nxt_str_t line, out;
+ njs_vm_t *vm;
+ nxt_int_t ret;
+ nxt_str_t line, out;
+ nxt_array_t *backtrace;
vm = njs_vm_create(vm_options);
if (vm == NULL) {
@@ -188,6 +191,11 @@ njs_interactive_shell(njs_opts_t *opts,
printf("%.*s\n", (int) out.length, out.start);
+ backtrace = njs_vm_backtrace(vm);
+ if (backtrace != NULL) {
+ njs_print_backtrace(backtrace);
+ }
+
/* editline allocs a new buffer every time. */
free(line.start);
}
@@ -208,6 +216,7 @@ njs_process_file(njs_opts_t *opts, njs_v
nxt_int_t ret;
nxt_str_t out, script;
struct stat sb;
+ nxt_array_t *backtrace;
file = opts->file;
@@ -287,6 +296,11 @@ njs_process_file(njs_opts_t *opts, njs_v
if (!opts->disassemble) {
printf("%.*s\n", (int) out.length, out.start);
+
+ backtrace = njs_vm_backtrace(vm);
+ if (backtrace != NULL) {
+ njs_print_backtrace(backtrace);
+ }
}
return NXT_OK;
@@ -329,6 +343,26 @@ njs_process_script(njs_vm_t *vm, njs_opt
}
+static void
+njs_print_backtrace(nxt_array_t *backtrace)
+{
+ nxt_uint_t i;
+ njs_backtrace_entry_t *be;
+
+ be = backtrace->start;
+
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ printf("at %.*s (:%d)\n", (int) be[i].name.length, be[i].name.start,
+ be[i].line);
+
+ } else {
+ printf("at %.*s\n", (int) be[i].name.length, be[i].name.start);
+ }
+ }
+}
+
+
static nxt_int_t
njs_editline_init(njs_vm_t *vm)
{
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs_builtin.c
--- a/njs/njs_builtin.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs_builtin.c Tue Aug 29 14:06:23 2017 +0300
@@ -514,3 +514,136 @@ njs_builtin_completions(njs_vm_t *vm, si
return NXT_OK;
}
+
+
+nxt_int_t
+njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function,
+ nxt_str_t *name)
+{
+ char *buf;
+ size_t len;
+ nxt_str_t string;
+ nxt_uint_t i;
+ njs_object_t *objects;
+ njs_function_t *constructors;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_each_t lhe;
+ njs_object_prototype_t *prototypes;
+
+ objects = vm->shared->objects;
+
+ for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) {
+ if (object_init[i] == NULL) {
+ continue;
+ }
+
+ nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
+
+ for ( ;; ) {
+ prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe);
+
+ if (prop == NULL) {
+ break;
+ }
+
+ if (!njs_is_function(&prop->value)) {
+ continue;
+ }
+
+ if (function == prop->value.data.u.function) {
+ njs_string_get(&prop->name, &string);
+ len = object_init[i]->name.length + string.length
+ + sizeof(".");
+
+ buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ snprintf(buf, len, "%s.%s", object_init[i]->name.start,
+ string.start);
+
+ name->length = len;
+ name->start = (u_char *) buf;
+
+ return NXT_OK;
+ }
+ }
+ }
+
+ prototypes = vm->shared->prototypes;
+
+ for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) {
+ nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
+
+ for ( ;; ) {
+ prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe);
+
+ if (prop == NULL) {
+ break;
+ }
+
+ if (!njs_is_function(&prop->value)) {
+ continue;
+ }
+
+ if (function == prop->value.data.u.function) {
+ njs_string_get(&prop->name, &string);
+ len = prototype_init[i]->name.length + string.length
+ + sizeof(".prototype.");
+
+ buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ snprintf(buf, len, "%s.prototype.%s",
+ prototype_init[i]->name.start, string.start);
+
+ name->length = len;
+ name->start = (u_char *) buf;
+
+ return NXT_OK;
+ }
+ }
+ }
+
+ constructors = vm->shared->constructors;
+
+ for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) {
+ nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
+
+ for ( ;; ) {
+ prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe);
+
+ if (prop == NULL) {
+ break;
+ }
+
+ if (!njs_is_function(&prop->value)) {
+ continue;
+ }
+
+ if (function == prop->value.data.u.function) {
+ njs_string_get(&prop->name, &string);
+ len = constructor_init[i]->name.length + string.length
+ + sizeof(".");
+
+ buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
+ if (buf == NULL) {
+ return NXT_ERROR;
+ }
+
+ snprintf(buf, len, "%s.%s", constructor_init[i]->name.start,
+ string.start);
+
+ name->length = len;
+ name->start = (u_char *) buf;
+
+ return NXT_OK;
+ }
+ }
+ }
+
+ return NXT_DECLINED;
+}
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs_generator.c
--- a/njs/njs_generator.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs_generator.c Tue Aug 29 14:06:23 2017 +0300
@@ -123,6 +123,9 @@ static nxt_noinline nxt_int_t njs_genera
static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm,
njs_parser_t *parser, njs_index_t index);
+static nxt_int_t njs_generate_function_debug(njs_vm_t *vm, nxt_str_t *name,
+ njs_function_lambda_t *lambda, uint32_t line);
+
static const nxt_str_t no_label = { 0, NULL };
@@ -1609,6 +1612,13 @@ njs_generate_function(njs_vm_t *vm, njs_
return ret;
}
+ if (vm->debug != NULL) {
+ ret = njs_generate_function_debug(vm, NULL, lambda, node->token_line);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+ }
+
njs_generate_code(parser, njs_vmcode_function_t, function);
function->code.operation = njs_vmcode_function;
function->code.operands = NJS_VMCODE_1OPERAND;
@@ -1964,6 +1974,7 @@ static nxt_int_t
njs_generate_function_declaration(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *node)
{
+ nxt_int_t ret;
njs_variable_t *var;
njs_function_lambda_t *lambda;
@@ -1974,7 +1985,17 @@ njs_generate_function_declaration(njs_vm
lambda = var->value.data.u.function->u.lambda;
- return njs_generate_function_scope(vm, lambda, node);
+ ret = njs_generate_function_scope(vm, lambda, node);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ if (vm->debug != NULL) {
+ ret = njs_generate_function_debug(vm, &var->name, lambda,
+ node->token_line);
+ }
+
+ return ret;
}
@@ -2628,3 +2649,28 @@ njs_generator_index_release(njs_vm_t *vm
return NXT_ERROR;
}
+
+
+static nxt_int_t
+njs_generate_function_debug(njs_vm_t *vm, nxt_str_t *name,
+ njs_function_lambda_t *lambda, uint32_t line)
+{
+ njs_function_debug_t *debug;
+
+ debug = nxt_array_add(vm->debug, &njs_array_mem_proto, vm->mem_cache_pool);
+ if (nxt_slow_path(debug == NULL)) {
+ return NXT_ERROR;
+ }
+
+ if (name != NULL) {
+ debug->name = *name;
+
+ } else {
+ debug->name = no_label;
+ }
+
+ debug->lambda = lambda;
+ debug->line = line;
+
+ return NXT_OK;
+}
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs_parser.c
--- a/njs/njs_parser.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs_parser.c Tue Aug 29 14:06:23 2017 +0300
@@ -465,6 +465,7 @@ njs_parser_function_declaration(njs_vm_t
}
node->token = NJS_TOKEN_FUNCTION;
+ node->token_line = parser->lexer->token_line;
token = njs_parser_token(parser);
if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
@@ -532,6 +533,7 @@ njs_parser_function_expression(njs_vm_t
}
node->token = NJS_TOKEN_FUNCTION_EXPRESSION;
+ node->token_line = parser->lexer->token_line;
node->scope = parser->scope;
parser->node = node;
parser->code_size += sizeof(njs_vmcode_function_t);
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs_vm.c
--- a/njs/njs_vm.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs_vm.c Tue Aug 29 14:06:23 2017 +0300
@@ -113,6 +113,8 @@ static njs_ret_t njs_object_value_to_str
static njs_ret_t njs_vmcode_value_to_string(njs_vm_t *vm, njs_value_t *invld1,
njs_value_t *invld2);
+static njs_ret_t njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame);
+
void njs_debug(njs_index_t index, njs_value_t *value);
@@ -264,9 +266,20 @@ start:
if (catch != NULL) {
vm->current = catch;
+
+ if (vm->debug != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
goto start;
}
+ if (vm->debug != NULL
+ && njs_vm_add_backtrace_entry(vm, frame) != NXT_OK)
+ {
+ return NXT_ERROR;
+ }
+
previous = frame->native.previous;
if (previous == NULL) {
return NXT_ERROR;
@@ -3433,6 +3446,70 @@ njs_vm_throw_exception(njs_vm_t *vm, con
}
+static njs_ret_t
+njs_vm_add_backtrace_entry(njs_vm_t *vm, njs_frame_t *frame)
+{
+ nxt_int_t ret;
+ nxt_uint_t i;
+ njs_function_t *function;
+ njs_native_frame_t *native_frame;
+ njs_function_debug_t *debug_entry;
+ njs_function_lambda_t *lambda;
+ njs_backtrace_entry_t *be;
+
+ static const nxt_str_t entry_main = nxt_string("main");
+ static const nxt_str_t entry_native = nxt_string("native");
+ static const nxt_str_t entry_unknown = nxt_string("unknown");
+ static const nxt_str_t entry_anonymous = nxt_string("anonymous");
+
+ native_frame = &frame->native;
+ function = native_frame->function;
+
+ be = nxt_array_add(vm->backtrace, &njs_array_mem_proto, vm->mem_cache_pool);
+ if (nxt_slow_path(be == NULL)) {
+ return NXT_ERROR;
+ }
+
+ be->line = 0;
+
+ if (function == NULL) {
+ be->name = entry_main;
+ return NXT_OK;
+ }
+
+ if (function->native) {
+ ret = njs_builtin_match_native_function(vm, function, &be->name);
+ if (ret != NXT_OK) {
+ be->name = entry_native;
+ }
+
+ return NXT_OK;
+ }
+
+ lambda = function->u.lambda;
+ debug_entry = vm->debug->start;
+
+ for (i = 0; i < vm->debug->items; i++) {
+ if (lambda == debug_entry[i].lambda) {
+ if (debug_entry[i].name.length != 0) {
+ be->name = debug_entry[i].name;
+
+ } else {
+ be->name = entry_anonymous;
+ }
+
+ be->line = debug_entry[i].line;
+
+ return NXT_OK;
+ }
+ }
+
+ be->name = entry_unknown;
+
+ return NXT_OK;
+}
+
+
void
njs_debug(njs_index_t index, njs_value_t *value)
{
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njs_vm.h
--- a/njs/njs_vm.h Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njs_vm.h Tue Aug 29 14:06:23 2017 +0300
@@ -853,6 +853,13 @@ typedef struct {
} njs_vm_trap_t;
+typedef struct {
+ uint32_t line;
+ nxt_str_t name;
+ njs_function_lambda_t *lambda;
+} njs_function_debug_t;
+
+
struct njs_vm_s {
/* njs_vm_t must be aligned to njs_value_t due to scratch value. */
njs_value_t retval;
@@ -903,6 +910,9 @@ struct njs_vm_s {
nxt_trace_t trace;
nxt_random_t random;
+ nxt_array_t *debug;
+ nxt_array_t *backtrace;
+
uint8_t trailer; /* 1 bit */
uint8_t accumulative; /* 1 bit */
};
@@ -1080,6 +1090,8 @@ void njs_vm_throw_exception(njs_vm_t *vm
nxt_int_t njs_builtin_objects_create(njs_vm_t *vm);
nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm);
+nxt_int_t njs_builtin_match_native_function(njs_vm_t *vm,
+ njs_function_t *function, nxt_str_t *name);
void *njs_lvlhsh_alloc(void *data, size_t size, nxt_uint_t nalloc);
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njscript.c
--- a/njs/njscript.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njscript.c Tue Aug 29 14:06:23 2017 +0300
@@ -106,6 +106,7 @@ njs_vm_create(njs_vm_opt_t *options)
{
njs_vm_t *vm;
nxt_int_t ret;
+ nxt_array_t *debug;
nxt_mem_cache_pool_t *mcp;
njs_regexp_pattern_t *pattern;
@@ -176,6 +177,17 @@ njs_vm_create(njs_vm_opt_t *options)
vm->trailer = options->trailer;
+ if (options->backtrace) {
+ debug = nxt_array_create(4, sizeof(njs_function_debug_t),
+ &njs_array_mem_proto,
+ vm->mem_cache_pool);
+ if (nxt_slow_path(debug == NULL)) {
+ return NULL;
+ }
+
+ vm->debug = debug;
+ }
+
vm->accumulative = options->accumulative;
if (vm->accumulative) {
ret = njs_vm_init(vm);
@@ -248,6 +260,10 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
*/
vm->code = NULL;
+ if (vm->backtrace != NULL) {
+ nxt_array_reset(vm->backtrace);
+ }
+
ret = njs_generate_scope(vm, parser, node);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
@@ -334,6 +350,7 @@ njs_vm_init(njs_vm_t *vm)
u_char *values;
nxt_int_t ret;
njs_frame_t *frame;
+ nxt_array_t *backtrace;
scope_size = vm->scope_size + NJS_INDEX_GLOBAL_OFFSET;
@@ -371,6 +388,16 @@ njs_vm_init(njs_vm_t *vm)
return NXT_ERROR;
}
+ if (vm->debug != NULL) {
+ backtrace = nxt_array_create(4, sizeof(njs_backtrace_entry_t),
+ &njs_array_mem_proto, vm->mem_cache_pool);
+ if (nxt_slow_path(backtrace == NULL)) {
+ return NXT_ERROR;
+ }
+
+ vm->backtrace = backtrace;
+ }
+
vm->retval = njs_value_void;
vm->trace.level = NXT_LEVEL_TRACE;
@@ -493,3 +520,14 @@ njs_vm_exception(njs_vm_t *vm, nxt_str_t
{
return njs_value_to_ext_string(vm, retval, vm->exception);
}
+
+
+nxt_array_t *
+njs_vm_backtrace(njs_vm_t *vm)
+{
+ if (!nxt_array_is_empty(vm->backtrace)) {
+ return vm->backtrace;
+ }
+
+ return NULL;
+}
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/njscript.h
--- a/njs/njscript.h Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/njscript.h Tue Aug 29 14:06:23 2017 +0300
@@ -72,9 +72,16 @@ typedef struct {
uint8_t trailer; /* 1 bit */
uint8_t accumulative; /* 1 bit */
+ uint8_t backtrace; /* 1 bit */
} njs_vm_opt_t;
+typedef struct {
+ nxt_str_t name;
+ uint32_t line;
+} njs_backtrace_entry_t;
+
+
#define NJS_OK NXT_OK
#define NJS_ERROR NXT_ERROR
#define NJS_AGAIN NXT_AGAIN
@@ -103,6 +110,7 @@ NXT_EXPORT njs_ret_t njs_vm_return_strin
size_t size);
NXT_EXPORT nxt_int_t njs_vm_retval(njs_vm_t *vm, nxt_str_t *retval);
NXT_EXPORT nxt_int_t njs_vm_exception(njs_vm_t *vm, nxt_str_t *retval);
+NXT_EXPORT nxt_array_t *njs_vm_backtrace(njs_vm_t *vm);
NXT_EXPORT void njs_disassembler(njs_vm_t *vm);
diff -r 746c49e6c195 -r 82dc332cb4c8 njs/test/njs_interactive_test.c
--- a/njs/test/njs_interactive_test.c Thu Aug 24 16:16:37 2017 +0300
+++ b/njs/test/njs_interactive_test.c Tue Aug 29 14:06:23 2017 +0300
@@ -110,17 +110,80 @@ static njs_interactive_test_t njs_test[
nxt_string("4") },
{ nxt_string("function ff(o) {return o.a.a}" ENTER
+ "function f(o) {try {return ff(o)} "
+ "finally {return 1}}" ENTER
+ "f({})" ENTER),
+ nxt_string("1") },
+
+ /* Backtraces */
+
+ { nxt_string("function ff(o) {return o.a.a}" ENTER
"function f(o) {return ff(o)}" ENTER
"f({})" ENTER),
- nxt_string("TypeError") },
+ nxt_string("TypeError\n"
+ "at ff (:1)\n"
+ "at f (:1)\n"
+ "at main\n") },
+
+ { nxt_string("function ff(o) {return o.a.a}" ENTER
+ "function f(o) {try {return ff(o)} "
+ "finally {return o.a.a}}" ENTER
+ "f({})" ENTER),
+ nxt_string("TypeError\n"
+ "at f (:1)\n"
+ "at main\n") },
{ nxt_string("function f(ff, o) {return ff(o)}" ENTER
"f(function (o) {return o.a.a}, {})" ENTER),
- nxt_string("TypeError") },
+ nxt_string("TypeError\n"
+ "at anonymous (:1)\n"
+ "at f (:1)\n"
+ "at main\n") },
+
+ { nxt_string("'str'.replace(/t/g,"
+ " function(m) {return m.a.a})" ENTER),
+ nxt_string("TypeError\n"
+ "at anonymous (:1)\n"
+ "at String.prototype.replace\n"
+ "at main\n") },
+
+ { nxt_string("function f(o) {return Object.keys(o)}" ENTER
+ "f()" ENTER),
+ nxt_string("TypeError\n"
+ "at Object.keys\n"
+ "at f (:1)\n"
+ "at main\n") },
+
+ { nxt_string("String.fromCharCode(3.14)" ENTER),
+ nxt_string("RangeError\n"
+ "at String.fromCharCode\n"
+ "at main\n") },
+
+ { nxt_string("Math.log({}.a.a)" ENTER),
+ nxt_string("TypeError\n"
+ "at Math.log\n"
+ "at main\n") },
+
+ { nxt_string("function f(o) {function f_in(o) {return o.a.a};"
+ " return f_in(o)}; f({})" ENTER),
+ nxt_string("TypeError\n"
+ "at f_in (:1)\n"
+ "at f (:1)\n"
+ "at main\n") },
+
+ { nxt_string("function f(o) {var ff = function (o) {return o.a.a};"
+ " return ff(o)}; f({})" ENTER),
+ nxt_string("TypeError\n"
+ "at anonymous (:1)\n"
+ "at f (:1)\n"
+ "at main\n") },
};
+static void njs_report_backtrace(nxt_array_t *backtrace, nxt_str_t *s);
+
+
static nxt_int_t
njs_interactive_test(void)
{
@@ -130,6 +193,7 @@ njs_interactive_test(void)
nxt_str_t s;
nxt_uint_t i;
nxt_bool_t success;
+ nxt_array_t *backtrace;
njs_vm_opt_t options;
nxt_mem_cache_pool_t *mcp;
njs_interactive_test_t *test;
@@ -153,6 +217,7 @@ njs_interactive_test(void)
options.mcp = mcp;
options.accumulative = 1;
+ options.backtrace = 1;
vm = njs_vm_create(&options);
if (vm == NULL) {
@@ -184,6 +249,11 @@ njs_interactive_test(void)
} else {
njs_vm_exception(vm, &s);
+
+ backtrace = njs_vm_backtrace(vm);
+ if (backtrace != NULL) {
+ njs_report_backtrace(backtrace, &s);
+ }
}
success = nxt_strstr_eq(&test->ret, &s);
@@ -211,6 +281,34 @@ fail:
}
+static void
+njs_report_backtrace(nxt_array_t *backtrace, nxt_str_t *s)
+{
+ char *p;
+ nxt_uint_t i;
+ njs_backtrace_entry_t *be;
+
+ static char buf[4096];
+
+ p = buf + sprintf(buf, "%.*s\n", (int) s->length, s->start);
+
+ be = backtrace->start;
+ for (i = 0; i < backtrace->items; i++) {
+ if (be[i].line != 0) {
+ p += sprintf(p, "at %.*s (:%d)\n", (int) be[i].name.length,
+ be[i].name.start, be[i].line);
+
+ } else {
+ p += sprintf(p, "at %.*s\n", (int) be[i].name.length,
+ be[i].name.start);
+ }
+ }
+
+ s->length = strlen(buf);
+ s->start = (u_char *) buf;
+}
+
+
int nxt_cdecl
main(int argc, char **argv)
{
More information about the nginx-devel
mailing list