Previously `v8 args` only shows arguments of the functions in the stack
frames. This patch makes GetStackFrame in the debug helper forward the
context local information stored in ScopeInfo in the returned
properties, so the plugins can recover the parameter names in `bt` and
allow `v8 inspect` to resolve by parameter names.
The previews show the arguments as passed at the call site. Only the
names captured in the closures can be recovered, the rest still gets
positional [N] names. For example:
function outer(a, b, c) {
function capture() {
return a + c; // captures a and c, not b
}
}
(gdb) bt
#6 ... [outer @ captured-args.js:9:15]
(this=0x..., a=<Smi: 1>, [1]=<Smi: 2>, c=<Smi: 3>)
(gdb) v8 args 6
#6 outer @ captured-args.js:9:15
this = 0x... <JSGlobalProxy>
a = <Smi: 1>
[1] = <Smi: 2>
c = <Smi: 3>
(gdb) v8 inspect c
<Smi: 3>
To implement this, we expose the ScopeInfo::VariableProperties bitfield
aliases for the helper.
In order to support builds without pointer compression/cages, this also
includes isolate pointer in HeapAddresses in order to fill the
read_only_space_first_page and old_space_first_page of a HeapAddress
from the isolate root table, since without pointer compression, the
helper cannot derive these pages by itself.
Change-Id: Ie12b1e4e159836f30071cb009aadb46117064865
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8545535
Reviewed-by: Paolo Severini <paolosev@microsoft.com>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/main@{#111626}
220 lines
8.0 KiB
Makefile
220 lines
8.0 KiB
Makefile
PYTHON ?= python3
|
|
GDB ?= gdb
|
|
LLDB ?= lldb
|
|
|
|
# Default to the most common build output directories generated by
|
|
# gm.py for convenience, but allow overriding for custom setups.
|
|
ifeq ($(shell uname -s),Darwin)
|
|
OUT_DIR ?= ../../../out/arm64.release
|
|
DEBUG_HELPER_LIB ?= $(OUT_DIR)/libv8_debug_helper.dylib
|
|
else
|
|
OUT_DIR ?= ../../../out/x64.release
|
|
DEBUG_HELPER_LIB ?= $(OUT_DIR)/libv8_debug_helper.so
|
|
endif
|
|
|
|
D8 ?= $(dir $(DEBUG_HELPER_LIB))d8
|
|
CORRUPTION_BIN ?= $(dir $(DEBUG_HELPER_LIB))corruption_harness
|
|
TEST_DIR ?= ./test
|
|
FIXTURES_DIR ?= $(TEST_DIR)/fixtures
|
|
BACKTRACE_SCRIPT ?= $(FIXTURES_DIR)/throw.js
|
|
INSPECT_SCRIPT ?= $(FIXTURES_DIR)/inspect-fixture.js
|
|
ARGS_MISMATCH_SCRIPT ?= $(FIXTURES_DIR)/args-mismatch.js
|
|
CAPTURED_ARGS_SCRIPT ?= $(FIXTURES_DIR)/captured-args.js
|
|
CORRUPTION_SCRIPT ?= $(FIXTURES_DIR)/invalid-script-source.js
|
|
# d8 enables --sandbox-prohibit-insecure-mode on macOS/Linux, which makes
|
|
# sandbox initialization abort with a fatal OOM when launched under a debugger
|
|
# that disables ASLR by default.
|
|
D8_ARGS ?= --no-sandbox-prohibit-insecure-mode
|
|
GDBINIT ?= ../../gdbinit
|
|
GDB_PLUGIN ?= ./gdb_plugin.py
|
|
LLDB_PLUGIN ?= ./lldb_plugin.py
|
|
TEST_PACKAGE ?= test
|
|
CORE_DIR ?= $(OUT_DIR)/debug_helper.cores
|
|
BACKTRACE_CORE ?= $(CORE_DIR)/throw.core
|
|
INSPECT_CORE ?= $(CORE_DIR)/inspect-fixture.core
|
|
ARGS_MISMATCH_CORE ?= $(CORE_DIR)/args-mismatch.core
|
|
CAPTURED_ARGS_CORE ?= $(CORE_DIR)/captured-args.core
|
|
CORRUPTION_CORE ?= $(CORE_DIR)/$(basename $(notdir $(CORRUPTION_SCRIPT))).core
|
|
CORRUPTION_CORE_CASES := invalid-script-source invalid-shared-function-info corrupted-map
|
|
CORRUPTION_CORES := $(foreach case,$(CORRUPTION_CORE_CASES),$(CORE_DIR)/$(case).core)
|
|
|
|
# Without pointer compression d8 remaps the embedded builtins to a second,
|
|
# file-backed mapping of the binary at a high address. Those pages are clean and
|
|
# file-backed, so the default coredump_filter (0x33) leaves them out of the core
|
|
# (they are recorded only as an NT_FILE note), and lldb cannot read them back to
|
|
# unwind the JS frames running in those builtins. Adding bit 2 (file-backed
|
|
# private, 0x3f = 0x33 | file-backed) allows gdb to capture those
|
|
# pages. The value is read when the core is written, so setting it on the
|
|
# stopped inferior after `run` and before `generate-core-file` is enough.
|
|
define generate_core_gdb
|
|
mkdir -p "$(dir $(3))"
|
|
rm -f "$(3)"
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(GDB) -nx -q -batch \
|
|
-iex 'set debuginfod enabled off' \
|
|
-ex 'file "$(1)"' \
|
|
-ex 'run $(2)' \
|
|
-ex 'python open("/proc/%d/coredump_filter" % gdb.selected_inferior().pid, "w").write("0x3f")' \
|
|
-ex 'generate-core-file $(3)' \
|
|
-ex 'quit'
|
|
endef
|
|
|
|
define generate_core_lldb
|
|
mkdir -p "$(dir $(3))"
|
|
rm -f "$(3)"
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(LLDB) -b \
|
|
-O 'target create "$(1)"' \
|
|
-O 'settings set -- target.run-args $(2)' \
|
|
-O 'run' \
|
|
-k 'process save-core --style full "$(3)"' \
|
|
-k 'quit'
|
|
endef
|
|
|
|
ifeq ($(shell uname -s),Darwin)
|
|
define generate_core
|
|
$(call generate_core_lldb,$(1),$(2),$(3))
|
|
endef
|
|
else
|
|
define generate_core
|
|
$(call generate_core_gdb,$(1),$(2),$(3))
|
|
endef
|
|
endif
|
|
|
|
define run_gdb_live
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(GDB) -nx -q -batch \
|
|
-iex 'set debuginfod enabled off' \
|
|
-iex 'source $(abspath $(GDBINIT))' \
|
|
-iex 'source $(abspath $(GDB_PLUGIN))' \
|
|
-ex 'file "$(1)"' \
|
|
-ex 'run $(2)' \
|
|
-ex 'bt' \
|
|
-ex 'quit'
|
|
endef
|
|
|
|
define run_lldb_live
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(LLDB) -b \
|
|
-O 'command script import "$(abspath $(LLDB_PLUGIN))"' \
|
|
-O 'target create "$(1)"' \
|
|
-O 'settings set -- target.run-args $(2)' \
|
|
-O 'run' \
|
|
-k 'bt' \
|
|
-k 'quit'
|
|
endef
|
|
|
|
define run_gdb_core
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(GDB) -nx -q -batch \
|
|
-iex 'set debuginfod enabled off' \
|
|
-iex 'source $(abspath $(GDBINIT))' \
|
|
-iex 'source $(abspath $(GDB_PLUGIN))' \
|
|
-ex 'file "$(1)"' \
|
|
-ex 'core-file $(2)' \
|
|
-ex 'bt' \
|
|
-ex 'quit'
|
|
endef
|
|
|
|
define run_lldb_core
|
|
V8_DEBUG_HELPER_LIB_PATH="$(abspath $(DEBUG_HELPER_LIB))" \
|
|
$(LLDB) -b \
|
|
-O 'command script import "$(abspath $(LLDB_PLUGIN))"' \
|
|
-O 'target create --core "$(2)" "$(1)"' \
|
|
-O 'bt' \
|
|
-O 'quit'
|
|
endef
|
|
|
|
# Runs one unittest spec ($(1) = module or module.Class) with the full environment.
|
|
define run_test
|
|
GDB='$(GDB)' \
|
|
GDB_PLUGIN='$(abspath $(GDB_PLUGIN))' \
|
|
GDBINIT='$(abspath $(GDBINIT))' \
|
|
LLDB='$(LLDB)' \
|
|
LLDB_PLUGIN='$(abspath $(LLDB_PLUGIN))' \
|
|
D8='$(abspath $(D8))' \
|
|
D8_ARGS='$(D8_ARGS)' \
|
|
CORRUPTION_BIN='$(abspath $(CORRUPTION_BIN))' \
|
|
DEBUG_HELPER_LIB='$(abspath $(DEBUG_HELPER_LIB))' \
|
|
CORE_DIR='$(abspath $(CORE_DIR))' \
|
|
$(PYTHON) -m unittest -v $(TEST_PACKAGE).$(1)
|
|
endef
|
|
|
|
.PHONY: run-live-gdb run-live-backtrace-gdb run-live-corruption-gdb run-live-lldb run-live-backtrace-lldb run-live-corruption-lldb run-live run-core-gdb run-core-backtrace-gdb run-core-corruption-gdb run-core-lldb run-core-backtrace-lldb run-core-corruption-lldb run-core run prepare-cores clean-cores clean-pyc test-live test-core test test-gdb test-lldb
|
|
|
|
$(BACKTRACE_CORE): $(BACKTRACE_SCRIPT) $(D8)
|
|
$(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(BACKTRACE_SCRIPT))",$(abspath $@))
|
|
|
|
$(INSPECT_CORE): $(INSPECT_SCRIPT) $(D8)
|
|
$(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(INSPECT_SCRIPT))",$(abspath $@))
|
|
|
|
$(ARGS_MISMATCH_CORE): $(ARGS_MISMATCH_SCRIPT) $(D8)
|
|
$(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(ARGS_MISMATCH_SCRIPT))",$(abspath $@))
|
|
|
|
$(CAPTURED_ARGS_CORE): $(CAPTURED_ARGS_SCRIPT) $(D8)
|
|
$(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(CAPTURED_ARGS_SCRIPT))",$(abspath $@))
|
|
|
|
# The corruption cores depend on the harness binary too, so they get
|
|
# regenerated whenever the harness changes.
|
|
$(CORE_DIR)/%.core: $(FIXTURES_DIR)/%.js $(CORRUPTION_BIN)
|
|
$(call generate_core,$(abspath $(CORRUPTION_BIN)),"$(abspath $(FIXTURES_DIR))/$*.js",$(abspath $@))
|
|
|
|
run-live-gdb: run-live-backtrace-gdb run-live-corruption-gdb
|
|
|
|
run-live-backtrace-gdb:
|
|
$(call run_gdb_live,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(BACKTRACE_SCRIPT))")
|
|
|
|
run-live-lldb: run-live-backtrace-lldb run-live-corruption-lldb
|
|
|
|
run-live-backtrace-lldb:
|
|
$(call run_lldb_live,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(BACKTRACE_SCRIPT))")
|
|
|
|
run-live-corruption-gdb:
|
|
$(call run_gdb_live,$(abspath $(CORRUPTION_BIN)),"$(abspath $(CORRUPTION_SCRIPT))")
|
|
|
|
run-live-corruption-lldb:
|
|
$(call run_lldb_live,$(abspath $(CORRUPTION_BIN)),"$(abspath $(CORRUPTION_SCRIPT))")
|
|
|
|
run-core-gdb: run-core-backtrace-gdb run-core-corruption-gdb
|
|
|
|
run-core-backtrace-gdb: $(BACKTRACE_CORE)
|
|
$(call run_gdb_core,$(abspath $(D8)),$(abspath $(BACKTRACE_CORE)))
|
|
|
|
run-core-corruption-gdb: $(CORRUPTION_CORE)
|
|
$(call run_gdb_core,$(abspath $(CORRUPTION_BIN)),$(abspath $(CORRUPTION_CORE)))
|
|
|
|
run-core-lldb: run-core-backtrace-lldb run-core-corruption-lldb
|
|
|
|
run-core-backtrace-lldb: $(BACKTRACE_CORE)
|
|
$(call run_lldb_core,$(abspath $(D8)),$(abspath $(BACKTRACE_CORE)))
|
|
|
|
run-core-corruption-lldb: $(CORRUPTION_CORE)
|
|
$(call run_lldb_core,$(abspath $(CORRUPTION_BIN)),$(abspath $(CORRUPTION_CORE)))
|
|
|
|
run-core: run-core-gdb run-core-lldb
|
|
|
|
prepare-cores: $(BACKTRACE_CORE) $(INSPECT_CORE) $(ARGS_MISMATCH_CORE) $(CAPTURED_ARGS_CORE) $(CORRUPTION_CORES)
|
|
|
|
clean-cores:
|
|
rm -rf "$(CORE_DIR)"
|
|
|
|
clean-pyc:
|
|
find . -type d -name __pycache__ -prune -exec rm -rf {} +
|
|
|
|
.SECONDEXPANSION:
|
|
|
|
# Run any unittest spec directly. The target name is the spec, e.g.
|
|
# make test_gdb_live
|
|
# make test_gdb_live.GdbBacktraceTest
|
|
# make test_gdb_core.GdbInspectCoreTest
|
|
# Specs for the coredump tests (name contains "core") depend on prepared cores.
|
|
test_%: $$(if $$(findstring core,$$*),prepare-cores)
|
|
$(call run_test,$@)
|
|
|
|
# Convenience helpers for common test groups
|
|
test-live: test_gdb_live test_lldb_live
|
|
test-core: test_gdb_core test_lldb_core
|
|
test-gdb: test_gdb_live test_gdb_core
|
|
test-lldb: test_lldb_live test_lldb_core
|
|
test: test-live test-core
|