feat(debug): add Python debug visualizer and enhance gdb integration
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
/target
|
||||
/cpp/list_example_cpp
|
||||
__pycache__
|
||||
|
||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -32,7 +32,7 @@
|
||||
},
|
||||
{
|
||||
"description": "Load the generic $debug_graph(...) Debug Visualizer helper",
|
||||
"text": "source ${workspaceFolder}/gdb/debug_graph.py",
|
||||
"text": "source ${workspaceFolder}/debuggers/gdb_debug_graph.py",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
]
|
||||
@@ -43,6 +43,9 @@
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/python/main.py",
|
||||
"cwd": "${workspaceFolder}/python",
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceFolder}/debuggers"
|
||||
},
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
},
|
||||
@@ -77,7 +80,7 @@
|
||||
},
|
||||
{
|
||||
"description": "Load the generic $debug_graph(...) Debug Visualizer helper",
|
||||
"text": "source ${workspaceFolder}/gdb/debug_graph.py",
|
||||
"text": "source ${workspaceFolder}/debuggers/gdb_debug_graph.py",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
]
|
||||
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -7,7 +7,7 @@
|
||||
"expressionTemplate": "$debug_graph(${expr})"
|
||||
},
|
||||
"debugpy": {
|
||||
"expressionTemplate": "__import__('debug_graph').debug_graph(${expr})"
|
||||
"expressionTemplate": "__import__('py_debug_graph').debug_graph(${expr})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Generic "reference-graph" -> Debug Visualizer JSON walker, the debugpy
|
||||
analog of gdb/debug_graph.py.
|
||||
analog of debuggers/gdb_debug_graph.py.
|
||||
|
||||
Works on any plain Python object reachable from an expression, purely by
|
||||
walking `vars(obj)` -- no changes to the debuggee's source are required.
|
||||
@@ -23,7 +23,7 @@ walks and labels, as additional roots:
|
||||
- every other local variable visible in the caller's frame -- kind "local"
|
||||
- every module-level global visible from the caller's frame, skipping
|
||||
dunders, modules, classes and functions -- kind "global"
|
||||
This mirrors gdb/debug_graph.py's auto-discovery: it's what lets
|
||||
This mirrors debuggers/gdb_debug_graph.py's auto-discovery: it's what lets
|
||||
`debug_graph(top)` -- a bare int with no object graph of its own -- still
|
||||
show the whole list, because `lst` (a sibling local) gets auto-walked too.
|
||||
"""
|
||||
Binary file not shown.
Binary file not shown.
@@ -28,13 +28,13 @@ gdb has no way to know it's secretly interior to a `Node<int>`). VS Code's
|
||||
whatever you type in the Watch box as $debug_graph(${expr}), so typing
|
||||
plain `top` evaluates $debug_graph(top) -- not $debug_graph(list, ...): we
|
||||
replay that exact call and verify it still delves into the full list. This
|
||||
relies on gdb/debug_graph.py's auto-discovery of sibling locals (here,
|
||||
relies on debuggers/gdb_debug_graph.py's auto-discovery of sibling locals (here,
|
||||
`list`, a struct type it *can* walk) merging into the same node graph as
|
||||
`top`'s address, rather than requiring `top` to be passed as an explicit
|
||||
watched root.
|
||||
|
||||
The Python build has no pointers -- `top` there is just a plain int, not a
|
||||
value interior to any struct -- but python/debug_graph.py's own
|
||||
value interior to any struct -- but debuggers/py_debug_graph.py's own
|
||||
auto-discovery of sibling locals (here `lst`) means evaluating
|
||||
debug_graph(top) still delves into the whole list for the same underlying
|
||||
reason: verify_top_delves_into_list_py exercises that.
|
||||
@@ -57,7 +57,7 @@ def run_gdb(gdb_bin, binary, break_file, break_line, expr="$debug_graph(list)"):
|
||||
commands = [
|
||||
"-gdb-set print elements 0",
|
||||
"-gdb-set print characters 0",
|
||||
"source %s" % (REPO / "gdb" / "debug_graph.py"),
|
||||
"source %s" % (REPO / "debuggers" / "gdb_debug_graph.py"),
|
||||
"-break-insert %s:%d" % (break_file, break_line),
|
||||
"-exec-run",
|
||||
'-data-evaluate-expression "%s"' % expr.replace('"', '\\"'),
|
||||
@@ -199,9 +199,11 @@ def run_debugpy(python_bin, script_path, break_line, expr):
|
||||
probe.bind(("127.0.0.1", 0))
|
||||
port = probe.getsockname()[1]
|
||||
|
||||
env = dict(os.environ, PYTHONPATH=str(REPO / "debuggers"))
|
||||
proc = subprocess.Popen(
|
||||
[python_bin, "-m", "debugpy", "--listen", "127.0.0.1:%d" % port, "--wait-for-client", str(script_path)],
|
||||
cwd=str(Path(script_path).parent),
|
||||
env=env,
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||
)
|
||||
try:
|
||||
@@ -380,7 +382,7 @@ def dump(label, gdb_bin, binary, break_file, break_line, out_dir, expr="$debug_g
|
||||
|
||||
|
||||
def dump_python(label, python_bin, script_path, break_line, out_dir,
|
||||
expr="__import__('debug_graph').debug_graph(lst)", verify=None):
|
||||
expr="__import__('py_debug_graph').debug_graph(lst)", verify=None):
|
||||
ok = True
|
||||
try:
|
||||
raw_result = run_debugpy(python_bin, script_path, break_line, expr)
|
||||
@@ -423,7 +425,7 @@ def main():
|
||||
ok_python = dump_python("python", python_bin, python_script, 54, out_dir)
|
||||
ok_python_top = dump_python(
|
||||
"python_top", python_bin, python_script, 54, out_dir,
|
||||
expr="__import__('debug_graph').debug_graph(top)",
|
||||
expr="__import__('py_debug_graph').debug_graph(top)",
|
||||
verify=verify_top_delves_into_list_py,
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// Registered via the "debugVisualizer.customVisualizerScriptPaths" setting;
|
||||
// the extension hot-reloads this file on save, no debug session restart needed.
|
||||
//
|
||||
// Data shape produced by gdb/debug_graph.py's $debug_graph(...):
|
||||
// Data shape produced by debuggers/gdb_debug_graph.py's $debug_graph(...):
|
||||
// nodes: [{ id: "0x...", fields: [{ name, value, isPointer? }, ...] }]
|
||||
// edges: [{ from: "0x...", to: "0x...", label? }]
|
||||
// roots: [{ name: "top", value: "0x...", kind? }] -- external pointer
|
||||
|
||||
Reference in New Issue
Block a user