Skip to content

Commit 75c507b

Browse files
author
Magne Hov
committed
add py-eval command for evaluating expressions in the inferior
The py-eval command allows you to evaluate Python expressions at any Python frame.
1 parent 76581d4 commit 75c507b

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

Diff for: libpython_extensions.py

+41
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,44 @@ def open(cls, path_bytes: bytes, *args):
440440
PythonSubstitutePath()
441441
# Define a customised open implementation in the libpython module to substitute filename paths.
442442
setattr(libpython, "open", PythonSubstitutePath.open)
443+
444+
445+
class PyEval(gdb.Command):
446+
"""
447+
Evaluate a Python expression in the context of the inferior Python process at the currently
448+
selected Python frame.
449+
"""
450+
451+
def __init__(self):
452+
super().__init__("py-eval", gdb.COMMAND_RUNNING)
453+
454+
def invoke(self, arg, from_tty):
455+
eval_expression = arg.replace("\"", "\\\"")
456+
try:
457+
# First, find the frame of the currently selected Python frame. We need this to find the
458+
# correct locals and globals. The PyEval_GetLocals and PyEval_GetGlobals functions are
459+
# available but these provide the environment of the currently executing frame, not the
460+
# selected frame.
461+
frame_pointer = int(libpython.Frame.get_selected_python_frame().get_pyop()._gdbval)
462+
except AttributeError:
463+
print("Unable to locate python frame")
464+
return
465+
frame_var = "$_python_frame"
466+
frame_expr = f"((struct _frame *){frame_var})"
467+
# Set the frame
468+
gdb.execute(f"set {frame_var}={frame_pointer}")
469+
run_arguments = [
470+
f'"{eval_expression}"',
471+
# Py_eval_input
472+
"258",
473+
f"{frame_expr}->f_globals",
474+
# PyFrame_FastToLocalsWithError must be called to populate the locals object in the
475+
# frame. We use the comma operator to let us do this in the same inferior call as
476+
# PyRun_String.
477+
f"(PyFrame_FastToLocalsWithError({frame_var}), {frame_expr}->f_locals)",
478+
]
479+
run_command = f"p PyRun_String({', '.join(run_arguments)})"
480+
gdb.execute(run_command, from_tty=True)
481+
482+
PyEval()
483+
gdb.execute("alias -a pe = py-eval")

0 commit comments

Comments
 (0)