From 4fe78febf4269228db383f10365fef425eda3feb Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Thu, 3 Sep 2026 15:36:59 -0400 Subject: [PATCH] build: enable V8 gdb/lldb plugin support Build `v8_debug_helper.{so|dylib}` to enable V8 gdb/lldb postmortem plugin support for the V8 version that Node.js built with. Signed-off-by: Chengzhong Wu --- common.gypi | 5 +- configure.py | 10 ++ node.gypi | 3 + tools/v8_gypfiles/v8.gyp | 4 +- tools/v8_gypfiles/v8_debug_helper.gyp | 177 ++++++++++++++++++++++++++ tools/v8_gypfiles/v8windbg.gyp | 135 +------------------- 6 files changed, 198 insertions(+), 136 deletions(-) create mode 100644 tools/v8_gypfiles/v8_debug_helper.gyp diff --git a/common.gypi b/common.gypi index 5aef7768323c..d65ab8ee5f3f 100644 --- a/common.gypi +++ b/common.gypi @@ -17,6 +17,7 @@ 'emulator%': [], 'node_shared%': 'false', + 'node_enable_v8debughelper%': 'false', 'node_enable_experimentals%': 'false', 'force_dynamic_crt%': 0, 'node_use_v8_platform%': 'true', @@ -654,7 +655,9 @@ 'cflags!': [ '-pthread' ], 'ldflags!': [ '-pthread' ], }], - [ 'node_shared=="true"', { + # The V8 static libraries get linked into libv8_debug_helper, so they + # have to be position independent too. + [ 'node_shared=="true" or node_enable_v8debughelper=="true"', { 'cflags': [ '-fPIC' ], 'ldflags': [ '-fPIC' ], }], diff --git a/configure.py b/configure.py index 99ce9326dc93..d48a80ea127c 100755 --- a/configure.py +++ b/configure.py @@ -850,6 +850,13 @@ default=None, help=argparse.SUPPRESS) # Undocumented. +parser.add_argument('--enable-v8debughelper', + action='store_true', + dest='enable_v8debughelper', + default=None, + help='Build V8\'s debug helper as a shared library, loadable by a debugger ' + 'extension.') + parser.add_argument('--enable-trace-maps', action='store_true', dest='trace_maps', @@ -2248,6 +2255,7 @@ def configure_v8(o, configs): o['variables']['force_dynamic_crt'] = 1 if options.shared else 0 o['variables']['node_enable_d8'] = b(options.enable_d8) o['variables']['node_enable_v8windbg'] = b(options.enable_v8windbg) + o['variables']['node_enable_v8debughelper'] = b(options.enable_v8debughelper) if options.enable_d8: o['variables']['test_isolation_mode'] = 'noop' # Needed by d8.gyp. if options.without_bundled_v8: @@ -2255,6 +2263,8 @@ def configure_v8(o, configs): raise Exception('--enable-d8 is incompatible with --without-bundled-v8.') if options.enable_v8windbg: raise Exception('--enable-v8windbg is incompatible with --without-bundled-v8.') + if options.enable_v8debughelper: + raise Exception('--enable-v8debughelper is incompatible with --without-bundled-v8.') (pkg_libs, pkg_cflags, pkg_libpath, _) = pkg_config("v8") if pkg_libs and pkg_libpath: output['libraries'] += [pkg_libpath] + pkg_libs.split() diff --git a/node.gypi b/node.gypi index 104e884e6614..bfe2d00ad929 100644 --- a/node.gypi +++ b/node.gypi @@ -99,6 +99,9 @@ [ 'node_enable_v8windbg=="true"', { 'dependencies': [ 'tools/v8_gypfiles/v8windbg.gyp:build_v8windbg' ], }], + [ 'node_enable_v8debughelper=="true"', { + 'dependencies': [ 'tools/v8_gypfiles/v8_debug_helper.gyp:build_v8_debug_helper' ], + }], [ 'node_use_bundled_v8=="true"', { 'dependencies': [ 'tools/v8_gypfiles/v8.gyp:v8_snapshot', diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index a976148ddab0..c4738e206bd0 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -62,7 +62,9 @@ 'BUILDING_V8_PLATFORM_SHARED', # Make V8_PLATFORM_EXPORT visible. ] }], - ['node_shared=="true"', { + # The V8 static libraries get linked into libv8_debug_helper too, and + # the local-exec TLS model is only valid in an executable. + ['node_shared=="true" or node_enable_v8debughelper=="true"', { 'defines': [ 'V8_TLS_USED_IN_LIBRARY', # Enable V8_TLS_LIBRARY_MODE. ], diff --git a/tools/v8_gypfiles/v8_debug_helper.gyp b/tools/v8_gypfiles/v8_debug_helper.gyp new file mode 100644 index 000000000000..e869cb4f9771 --- /dev/null +++ b/tools/v8_gypfiles/v8_debug_helper.gyp @@ -0,0 +1,177 @@ +{ + 'variables': { + 'V8_ROOT': '../../deps/v8', + 'v8_code': 1, + # v8windbg links the helper statically. When the helper is the requested + # artifact it is built as a shared library instead, so a debugger + # extension can load it on its own. + 'v8_debug_helper_type%': 'static_library', + 'conditions': [ + [ 'node_enable_v8debughelper=="true"', { + 'v8_debug_helper_type': 'shared_library', + }], + ], + }, + 'includes': ['toolchain.gypi', 'features.gypi'], + 'targets': [ + { + # Intermediate target to build the debug helper. dependencies_traverse + # stops gyp from propagating the library up to node.gypi as a link + # input. The library is only supposed to be loaded by a debugger. + 'target_name': 'build_v8_debug_helper', + 'type': 'none', + 'dependencies_traverse': 0, + 'hard_dependency': 1, + 'dependencies': [ + 'v8_debug_helper', + ], + }, # build_v8_debug_helper + { + 'target_name': 'v8_debug_helper', + 'type': '<(v8_debug_helper_type)', + 'include_dirs': [ + '<(V8_ROOT)', + '<(V8_ROOT)/include', + ], + 'dependencies': [ + 'gen_heap_constants', + + 'v8.gyp:generate_bytecode_builtins_list', + 'v8.gyp:run_torque', + 'v8.gyp:v8_maybe_icu', + 'v8.gyp:fp16', + 'v8.gyp:v8_libbase', + 'v8.gyp:v8_snapshot', + ], + 'sources': [ + '