[njs] Added native function symbolizer for function tracing in debug.

Dmitry Volyntsev xeioex at nginx.com
Wed Jun 29 06:05:38 UTC 2022


details:   https://hg.nginx.org/njs/rev/8fe7d9723477
branches:  
changeset: 1899:8fe7d9723477
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Jun 28 22:36:30 2022 -0700
description:
Added native function symbolizer for function tracing in debug.

diffstat:

 auto/cc                  |    4 +
 auto/help                |    4 +
 auto/libbfd              |   35 ++++++
 auto/link                |   31 +++++
 auto/openssl             |    1 +
 auto/options             |    9 +
 auto/pcre                |    3 +
 auto/sources             |    4 +
 configure                |   15 +-
 src/njs.h                |    3 +
 src/njs_addr2line.c      |  265 +++++++++++++++++++++++++++++++++++++++++++++++
 src/njs_addr2line.h      |   22 +++
 src/njs_function.c       |   25 +++-
 src/njs_main.h           |    1 +
 src/njs_shell.c          |   13 ++
 src/njs_sprintf.c        |    6 +
 src/njs_vmcode.c         |    6 +-
 src/njs_vmcode.h         |    4 +-
 src/test/njs_unit_test.c |   43 +++++++-
 19 files changed, 474 insertions(+), 20 deletions(-)

diffs (736 lines):

diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/cc
--- a/auto/cc	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/cc	Tue Jun 28 22:36:30 2022 -0700
@@ -177,6 +177,10 @@ if [ "$NJS_DEBUG_MEMORY" = "YES" ]; then
         njs_define=NJS_DEBUG_MEMORY . auto/define
 fi
 
+if [ "$NJS_DEBUG_OPCODE" = "YES" ]; then
+        njs_define=NJS_DEBUG_OPCODE . auto/define
+fi
+
 if [ "$NJS_TEST262" = "YES" ]; then
         njs_define=NJS_TEST262 . auto/define
 fi
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/help
--- a/auto/help	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/help	Tue Jun 28 22:36:30 2022 -0700
@@ -33,10 +33,14 @@ default: "$NJS_LD_OPT"
 
   --address-sanitizer=YES   enables build with address sanitizer, \
 default: "$NJS_ADDRESS_SANITIZER"
+  --addr2line=YES           enables native function symbolization, \
+default: "$NJS_ADDR2LINE"
   --debug=YES               enables additional runtime checks, \
 default: "$NJS_DEBUG"
   --debug-memory=YES        enables memory alloc debug, \
 default: "$NJS_DEBUG_MEMORY"
+  --debug-opcode=YES        enables runtime function tracing, \
+default: "$NJS_DEBUG_OPCODE"
   --test262=YES             enables test262 extentions, \
 default: "$NJS_TEST262"
 END
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/libbfd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/auto/libbfd	Tue Jun 28 22:36:30 2022 -0700
@@ -0,0 +1,35 @@
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+
+NJS_HAVE_LIBBFD=NO
+
+if [ $NJS_ADDR2LINE = YES ]; then
+    njs_found=no
+
+    njs_feature="BFD library"
+    njs_feature_name=NJS_HAVE_LIBBFD
+    njs_feature_run=yes
+    njs_feature_incs=
+    njs_feature_libs="-lbfd"
+    njs_feature_test="#include <bfd.h>
+
+                      int main() {
+                          bfd_init();
+                          return 0;
+                     }"
+    . auto/feature
+
+    if [ $njs_found = no ]; then
+        njs_feature="OpenSSL library -lcrypto"
+        njs_feature_libs="-lcrypto"
+
+        . auto/feature
+    fi
+
+
+    if [ $njs_found = yes ]; then
+        NJS_HAVE_LIBBFD=YES
+        NJS_LIB_AUX_LIBS="$NJS_LIB_AUX_LIBS $njs_feature_libs"
+    fi
+fi
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/link
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/auto/link	Tue Jun 28 22:36:30 2022 -0700
@@ -0,0 +1,31 @@
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+
+NJS_HAVE_DL_ITERATE_PHDR=NO
+
+if [ $NJS_ADDR2LINE = YES ]; then
+    njs_feature="dl_iterate_phdr()"
+    njs_feature_name=NJS_HAVE_DL_ITERATE_PHDR
+    njs_feature_run=yes
+    njs_feature_incs=
+    njs_feature_libs=
+    njs_feature_test="#define _GNU_SOURCE
+                      #include <link.h>
+
+                      static int
+                      cb(struct dl_phdr_info *info, size_t size, void *data) {
+                          return 0;
+                      }
+
+                      int main() {
+                          dl_iterate_phdr(cb, 0);
+                          return 0;
+                      }"
+    . auto/feature
+
+    if [ $njs_found = yes ]; then
+        NJS_HAVE_DL_ITERATE_PHDR=YES
+    fi
+fi
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/openssl
--- a/auto/openssl	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/openssl	Tue Jun 28 22:36:30 2022 -0700
@@ -46,6 +46,7 @@ if [ $NJS_OPENSSL = YES ]; then
 
         NJS_HAVE_OPENSSL=YES
         NJS_OPENSSL_LIB="$njs_feature_libs"
+        NJS_LIB_AUX_LIBS="$NJS_LIB_AUX_LIBS $njs_feature_libs"
     fi
 
 fi
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/options
--- a/auto/options	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/options	Tue Jun 28 22:36:30 2022 -0700
@@ -8,7 +8,10 @@ NJS_LD_OPT=${NJS_CC_OPT:--O}
 
 NJS_DEBUG=NO
 NJS_DEBUG_MEMORY=NO
+NJS_DEBUG_OPCODE=NO
+
 NJS_ADDRESS_SANITIZER=NO
+NJS_ADDR2LINE=NO
 NJS_TEST262=YES
 
 NJS_OPENSSL=YES
@@ -34,8 +37,10 @@ do
         --build-dir=*)                   NJS_BUILD_DIR="$value"              ;;
 
         --address-sanitizer=*)           NJS_ADDRESS_SANITIZER="$value"      ;;
+        --addr2line=*)                   NJS_ADDR2LINE="$value"              ;;
         --debug=*)                       NJS_DEBUG="$value"                  ;;
         --debug-memory=*)                NJS_DEBUG_MEMORY="$value"           ;;
+        --debug-opcode=*)                NJS_DEBUG_OPCODE="$value"           ;;
         --test262=*)                     NJS_TEST262="$value"                ;;
 
         --no-openssl)                    NJS_OPENSSL=NO                      ;;
@@ -66,3 +71,7 @@ done
 if [ "$NJS_DEBUG_MEMORY" = "YES" ]; then
     NJS_DEBUG=YES
 fi
+
+if [ "$NJS_DEBUG_OPCODE" = "YES" ]; then
+    NJS_ADDR2LINE=YES
+fi
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/pcre
--- a/auto/pcre	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/pcre	Tue Jun 28 22:36:30 2022 -0700
@@ -134,3 +134,6 @@ if [ $NJS_PCRE = YES ]; then
     fi
 
 fi
+
+NJS_LIB_AUX_CFLAGS="$NJS_LIB_AUX_CFLAGS $NJS_PCRE_CFLAGS"
+NJS_LIB_AUX_LIBS="$NJS_LIB_AUX_LIBS $NJS_PCRE_LIB"
diff -r 20ee5213e3c4 -r 8fe7d9723477 auto/sources
--- a/auto/sources	Wed Jun 22 23:37:27 2022 -0700
+++ b/auto/sources	Tue Jun 28 22:36:30 2022 -0700
@@ -75,6 +75,10 @@ if [ "$NJS_PCRE" = "YES" ]; then
 	NJS_LIB_SRCS="$NJS_LIB_SRCS external/njs_regex.c"
 fi
 
+if [ "$NJS_HAVE_LIBBFD" = "YES" -a "$NJS_HAVE_DL_ITERATE_PHDR" = "YES" ]; then
+	NJS_LIB_SRCS="$NJS_LIB_SRCS src/njs_addr2line.c"
+fi
+
 NJS_TS_SRCS=$(find ts/ -name "*.d.ts" -o -name "*.json")
 
 NJS_TEST_TS_SRCS=$(find test/ts/ -name "*.ts" -o -name "*.json")
diff -r 20ee5213e3c4 -r 8fe7d9723477 configure
--- a/configure	Wed Jun 22 23:37:27 2022 -0700
+++ b/configure	Tue Jun 28 22:36:30 2022 -0700
@@ -33,6 +33,10 @@ cat << END > $NJS_AUTO_CONFIG_H
 
 END
 
+NJS_LIBS="$NJS_LIBRT"
+NJS_LIB_AUX_CFLAGS=
+NJS_LIB_AUX_LIBS=
+
 . auto/os
 . auto/cc
 . auto/types
@@ -46,16 +50,11 @@ END
 . auto/pcre
 . auto/readline
 . auto/openssl
-. auto/sources
-
-NJS_LIB_AUX_CFLAGS="$NJS_PCRE_CFLAGS"
+. auto/libbfd
+. auto/link
 
-NJS_LIBS="$NJS_LIBRT"
-NJS_LIB_AUX_LIBS="$NJS_PCRE_LIB $NJS_OPENSSL_LIB"
-
+. auto/sources
 . auto/modules
 . auto/make
-
 . auto/expect
-
 . auto/summary
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs.h
--- a/src/njs.h	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs.h	Tue Jun 28 22:36:30 2022 -0700
@@ -250,6 +250,9 @@ typedef struct {
     uint8_t                         unsafe;          /* 1 bit */
     uint8_t                         module;          /* 1 bit */
     uint8_t                         ast;             /* 1 bit */
+#ifdef NJS_DEBUG_OPCODE
+    uint8_t                         opcode_debug;    /* 1 bit */
+#endif
     uint8_t                         unhandled_rejection;
 } njs_vm_opt_t;
 
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_addr2line.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/njs_addr2line.c	Tue Jun 28 22:36:30 2022 -0700
@@ -0,0 +1,265 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ *
+ * addr2line impementaton based upon the work by Jeff Muizelaar.
+ *
+ * A hacky replacement for backtrace_symbols in glibc
+ *
+ * backtrace_symbols in glibc looks up symbols using dladdr which is limited in
+ * the symbols that it sees. libbacktracesymbols opens the executable and
+ * shared libraries using libbfd and will look up backtrace information using
+ * the symbol table and the dwarf line information.
+ *
+ * Derived from addr2line.c from GNU Binutils by Jeff Muizelaar
+ *
+ * Copyright 2007 Jeff Muizelaar
+ *
+ * addr2line.c -- convert addresses to line number and function name
+ * Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Contributed by Ulrich Lauther <Ulrich.Lauther at mchp.siemens.de>
+ *
+ * This file was part of GNU Binutils.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <njs_main.h>
+#include <njs_addr2line.h>
+
+#include <bfd.h>
+#include <link.h>
+
+
+typedef struct {
+    const char    *file;
+    ElfW(Addr)    address;
+    ElfW(Addr)    base;
+    void          *hdr;
+} njs_file_match_t;
+
+
+typedef struct {
+    bfd_vma       pc;
+    const char    *filename;
+    const char    *functionname;
+    unsigned int  line;
+    njs_bool_t    found;
+    asymbol       **syms;
+} njs_translate_address_t;
+
+
+static u_char *njs_process_file(u_char *buf, u_char *end, bfd_vma *addr,
+    const char *file_name);
+static long njs_read_symtab(bfd *abfd, asymbol ***syms);
+static u_char *njs_translate_address(u_char *buf, u_char *end, bfd_vma *addr,
+    bfd *abfd, asymbol **syms);
+static void njs_find_address_in_section(bfd *abfd, asection *section,
+    void *data);
+static int njs_find_matching_file(struct dl_phdr_info *info, size_t size,
+    void *data);
+
+
+u_char *
+_njs_addr2line(u_char *buf, u_char *end, void *address)
+{
+    bfd_vma           addr;
+    const char        *fname;
+
+    njs_file_match_t  match = { .address = (ElfW(Addr)) address };
+
+    bfd_init();
+
+    dl_iterate_phdr(njs_find_matching_file, &match);
+
+    fname = "/proc/self/exe";
+    if (match.file != NULL && njs_strlen(match.file)) {
+        fname = match.file;
+    }
+
+    addr = (ElfW(Addr)) address - match.base;
+
+    return njs_process_file(buf, end, &addr, fname);
+}
+
+
+static u_char *
+njs_process_file(u_char *buf, u_char *end, bfd_vma *addr, const char *file_name)
+{
+    bfd     *abfd;
+    char    **matching;
+    u_char  *p;
+    asymbol **syms;
+
+    abfd = bfd_openr(file_name, NULL);
+    if (abfd == NULL) {
+        njs_stderror("%s: failed to open while looking for addr2line",
+                     file_name);
+        return NULL;
+    }
+
+    if (bfd_check_format(abfd, bfd_archive)) {
+        njs_stderror("%s: can not get addresses from archive", file_name);
+        return NULL;
+    }
+
+    if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
+        njs_stderror("%s: bfd_check_format_matches() failed",
+                     bfd_get_filename(abfd));
+        return NULL;
+    }
+
+    if (njs_read_symtab(abfd, &syms) <= 0) {
+        njs_stderror("%s: njs_read_symtab() failed",
+                     bfd_get_filename(abfd));
+        return NULL;
+    }
+
+    p = njs_translate_address(buf, end, addr, abfd, syms);
+
+    if (syms != NULL) {
+        free(syms);
+        syms = NULL;
+    }
+
+    bfd_close(abfd);
+
+    return p;
+}
+
+
+static long
+njs_read_symtab(bfd *abfd, asymbol ***syms)
+{
+    long      symcount;
+    unsigned  size;
+
+    if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) {
+        return 0;
+    }
+
+    symcount = bfd_read_minisymbols(abfd, 0, (PTR) syms, &size);
+    if (symcount == 0) {
+        symcount = bfd_read_minisymbols(abfd, 1 /* dynamic */,
+                                        (PTR) syms, &size);
+    }
+
+    return symcount;
+}
+
+
+static u_char *
+njs_translate_address(u_char *buf, u_char *end, bfd_vma *addr, bfd *abfd,
+    asymbol **syms)
+{
+    char                     *h;
+    const char               *name;
+    njs_translate_address_t  ctx;
+
+    ctx.pc = *addr;
+    ctx.found = 0;
+    ctx.syms = syms;
+
+    bfd_map_over_sections(abfd, njs_find_address_in_section, &ctx);
+
+    if (!ctx.found) {
+        return njs_sprintf(buf, end, "\?\? \t\?\?:0 [0x%p]", addr);
+    }
+
+    name = ctx.functionname;
+
+    if (name == NULL || *name == '\0') {
+        name = "??";
+    }
+
+    if (ctx.filename != NULL) {
+        h = strrchr(ctx.filename, '/');
+        if (h != NULL) {
+            ctx.filename = h + 1;
+        }
+    }
+
+    return njs_sprintf(buf, end, "%s() %s:%ud [0x%p]", name,
+                       ctx.filename ? ctx.filename : "??", ctx.line, addr);
+}
+
+
+static void
+njs_find_address_in_section(bfd *abfd, asection *section, void *data)
+{
+    bfd_vma                  vma;
+    bfd_size_type            size;
+    njs_translate_address_t  *ctx;
+
+    ctx = data;
+
+    if (ctx->found) {
+        return;
+    }
+
+    if ((bfd_section_flags(section) & SEC_ALLOC) == 0) {
+        return;
+    }
+
+    vma = bfd_section_vma(section);
+    if (ctx->pc < vma) {
+        return;
+    }
+
+    size = bfd_section_size(section);
+    if (ctx->pc >= vma + size) {
+        return;
+    }
+
+    ctx->found = bfd_find_nearest_line(abfd, section, ctx->syms, ctx->pc - vma,
+                                       &ctx->filename, &ctx->functionname,
+                                       &ctx->line);
+}
+
+
+static int
+njs_find_matching_file(struct dl_phdr_info *info, size_t size, void *data)
+{
+    long              n;
+    const ElfW(Phdr)  *phdr;
+
+    ElfW(Addr)        load_base = info->dlpi_addr;
+    njs_file_match_t  *match = data;
+
+    /*
+     * This code is modeled from Gfind_proc_info-lsb.c:callback()
+     * from libunwind.
+     */
+
+    phdr = info->dlpi_phdr;
+
+    for (n = info->dlpi_phnum; --n >= 0; phdr++) {
+        if (phdr->p_type == PT_LOAD) {
+            ElfW(Addr) vaddr = phdr->p_vaddr + load_base;
+
+            if (match->address >= vaddr
+                && match->address < vaddr + phdr->p_memsz)
+            {
+                /* we found a match */
+                match->file = info->dlpi_name;
+                match->base = info->dlpi_addr;
+            }
+        }
+    }
+
+    return 0;
+}
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_addr2line.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/njs_addr2line.h	Tue Jun 28 22:36:30 2022 -0700
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) Nginx, Inc.
+ */
+
+#ifndef _NJS_ADDR2LINE_H_INCLUDED_
+#define _NJS_ADDR2LINE_H_INCLUDED_
+
+
+ u_char *_njs_addr2line(u_char *buf, u_char *end, void *address);
+
+
+#if defined(NJS_HAVE_LIBBFD) && defined(NJS_HAVE_DL_ITERATE_PHDR)
+#define NJS_HAVE_ADDR2LINE            1
+#define njs_addr2line(buf, end, addr) _njs_addr2line(buf, end, addr)
+#else
+#define njs_addr2line(buf, end, addr) \
+                      njs_sprintf(buf, end, "\?\?() \?\?:0 [0x%p]", addr)
+#endif
+
+#endif /* _NJS_ADDR2LINE_H_INCLUDED_ */
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_function.c
--- a/src/njs_function.c	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_function.c	Tue Jun 28 22:36:30 2022 -0700
@@ -711,15 +711,18 @@ njs_function_native_call(njs_vm_t *vm)
     native = vm->top_frame;
     function = native->function;
 
-#ifdef NJS_OPCODE_DEBUG
-	njs_str_t              name;
+#ifdef NJS_DEBUG_OPCODE
+    njs_str_t              name;
+
+    if (vm->options.opcode_debug) {
 
-	ret = njs_builtin_match_native_function(vm, function, &name);
-	if (ret != NJS_OK) {
-		name = njs_entry_unknown;
-	}
+        ret = njs_builtin_match_native_function(vm, function, &name);
+        if (ret != NJS_OK) {
+           name = njs_str_value("unmapped");
+        }
 
-	njs_printf("CALL NATIVE %V\n", &name);
+        njs_printf("CALL NATIVE %V %P\n", &name, function->u.native);
+    }
 #endif
 
     if (njs_fast_path(function->bound == NULL)) {
@@ -737,6 +740,14 @@ njs_function_native_call(njs_vm_t *vm)
     }
 
     ret = call(vm, native->arguments, native->nargs, function->magic8);
+
+#ifdef NJS_DEBUG_OPCODE
+    if (vm->options.opcode_debug) {
+        njs_printf("CALL NATIVE RETCODE: %i %V %P\n", ret, &name,
+                   function->u.native);
+    }
+#endif
+
     if (njs_slow_path(ret == NJS_ERROR)) {
         return ret;
     }
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_main.h
--- a/src/njs_main.h	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_main.h	Tue Jun 28 22:36:30 2022 -0700
@@ -37,6 +37,7 @@
 #include <njs_utils.h>
 #include <njs_sprintf.h>
 #include <njs_assert.h>
+#include <njs_addr2line.h>
 
 #include <njs_regex.h>
 
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_shell.c
--- a/src/njs_shell.c	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_shell.c	Tue Jun 28 22:36:30 2022 -0700
@@ -36,6 +36,7 @@ typedef struct {
     uint8_t                 version;
     uint8_t                 ast;
     uint8_t                 unhandled_rejection;
+    uint8_t                 opcode_debug;
     int                     exit_code;
 
     char                    *file;
@@ -272,6 +273,9 @@ main(int argc, char **argv)
     vm_options.sandbox = opts.sandbox;
     vm_options.unsafe = !opts.safe;
     vm_options.module = opts.module;
+#ifdef NJS_DEBUG_OPCODE
+    vm_options.opcode_debug = opts.opcode_debug;
+#endif
 
     vm_options.ops = &njs_console_ops;
     vm_options.addons = njs_console_addon_modules;
@@ -334,6 +338,9 @@ njs_options_parse(njs_opts_t *opts, int 
         "  -d                print disassembled code.\n"
         "  -e                set failure exit code.\n"
         "  -f                disabled denormals mode.\n"
+#ifdef NJS_DEBUG_OPCODE
+        "  -o                enable opcode debug.\n"
+#endif
         "  -p                set path prefix for modules.\n"
         "  -q                disable interactive introduction prompt.\n"
         "  -r                ignore unhandled promise rejection.\n"
@@ -410,6 +417,12 @@ njs_options_parse(njs_opts_t *opts, int 
             opts->denormals = 0;
             break;
 
+#ifdef NJS_DEBUG_OPCODE
+        case 'o':
+            opts->opcode_debug = 1;
+            break;
+#endif
+
         case 'p':
             if (++i < argc) {
                 opts->n_paths++;
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_sprintf.c
--- a/src/njs_sprintf.c	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_sprintf.c	Tue Jun 28 22:36:30 2022 -0700
@@ -27,6 +27,7 @@
  *    %*s                       length and string
  *
  *    %p                        void *
+ *    %P                        symbolized function address
  *    %b                        njs_bool_t
  *    %V                        njs_str_t *
  *    %Z                        '\0'
@@ -372,6 +373,11 @@ njs_vsprintf(u_char *buf, u_char *end, c
              */
             goto number;
 
+        case 'P':
+            buf = njs_addr2line(buf, end, va_arg(args, void *));
+            fmt++;
+            continue;
+
         case 'c':
             d = va_arg(args, int);
             *buf++ = (u_char) (d & 0xFF);
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_vmcode.c
--- a/src/njs_vmcode.c	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_vmcode.c	Tue Jun 28 22:36:30 2022 -0700
@@ -165,8 +165,10 @@ next:
          * as a single unsigned comparision.
          */
 
-#ifdef NJS_OPCODE_DEBUG
-        njs_disassemble(pc, NULL, 1, NULL);
+#ifdef NJS_DEBUG_OPCODE
+        if (vm->options.opcode_debug) {
+            njs_disassemble(pc, NULL, 1, NULL);
+        }
 #endif
 
         if (op > NJS_VMCODE_NORET) {
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/njs_vmcode.h
--- a/src/njs_vmcode.h	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/njs_vmcode.h	Tue Jun 28 22:36:30 2022 -0700
@@ -450,9 +450,9 @@ njs_int_t njs_vmcode_interpreter(njs_vm_
 
 njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *constructor);
 
-#ifdef NJS_OPCODE_DEBUG
+#ifdef NJS_DEBUG_OPCODE
 #define njs_vmcode_debug(vm, pc, prefix) {                                    \
-        do {                                                                  \
+        if (vm->options.opcode_debug) do {                                    \
             njs_vm_code_t  *code;                                             \
                                                                               \
             code = njs_lookup_code(vm, pc);                                   \
diff -r 20ee5213e3c4 -r 8fe7d9723477 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed Jun 22 23:37:27 2022 -0700
+++ b/src/test/njs_unit_test.c	Tue Jun 28 22:36:30 2022 -0700
@@ -13269,7 +13269,7 @@ static njs_unit_test_t  njs_test[] =
       njs_str("5") },
 
     { njs_str("var a = (new Function('return [' + ','.repeat(2**16) + ']'))();"
-			  "njs.dump(a)"),
+              "njs.dump(a)"),
       njs_str("[<65536 empty items>]") },
 
     { njs_str("(new Function('var a = 7; return a' + '= a'.repeat(2**13)))()"),
@@ -23415,6 +23415,43 @@ njs_to_int32_test(njs_vm_t *vm, njs_opts
 }
 
 
+#ifdef NJS_HAVE_ADDR2LINE
+static njs_int_t
+njs_addr2line_test(njs_vm_t *vm, njs_opts_t *opts, njs_stat_t *stat)
+{
+    njs_str_t   v;
+    njs_uint_t  i;
+    u_char      buf[512];
+
+    static const struct {
+        void         *fp;
+        const char   *name;
+    } tests[] = {
+        { njs_addr2line_test, njs_stringify(njs_addr2line_test) },
+        { njs_to_int32_test, njs_stringify(njs_to_int32_test) },
+    };
+
+    for (i = 0; i < njs_nitems(tests); i++) {
+        v.start = buf;
+        v.length = njs_sprintf(buf, &buf[512], "%P", tests[i].fp) - buf;
+
+        if (memcmp(buf, tests[i].name, njs_strlen(tests[i].name))) {
+            njs_printf("njs_addr2line_test(%p):\n"
+                       "expected: %s\n     got: %V\n",
+                       tests[i].fp, tests[i].name, &v);
+
+            stat->failed++;
+            continue;
+        }
+
+        stat->passed++;
+    }
+
+    return NJS_OK;
+}
+#endif
+
+
 static njs_int_t
 njs_vm_internal_api_test(njs_unit_test_t unused[], size_t num, njs_str_t *name,
     njs_opts_t *opts, njs_stat_t *stat)
@@ -23443,6 +23480,10 @@ njs_vm_internal_api_test(njs_unit_test_t
           njs_str("njs_string_to_index_test") },
         { njs_to_int32_test,
           njs_str("njs_to_int32_test") },
+#ifdef NJS_HAVE_ADDR2LINE
+        { njs_addr2line_test,
+          njs_str("njs_addr2line_test") },
+#endif
     };
 
     vm = NULL;



More information about the nginx-devel mailing list