gdb/python: add __repr__ for PendingFrame and UnwindInfo
Having a useful __repr__ method can make debugging Python code that little bit easier. This commit adds __repr__ for gdb.PendingFrame and gdb.UnwindInfo classes, along with some tests. Reviewed-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
parent
86b35b7116
commit
7e6af18d0c
@ -229,6 +229,38 @@ unwind_infopy_str (PyObject *self)
|
||||
return PyUnicode_FromString (stb.c_str ());
|
||||
}
|
||||
|
||||
/* Implement UnwindInfo.__repr__(). */
|
||||
|
||||
static PyObject *
|
||||
unwind_infopy_repr (PyObject *self)
|
||||
{
|
||||
unwind_info_object *unwind_info = (unwind_info_object *) self;
|
||||
pending_frame_object *pending_frame
|
||||
= (pending_frame_object *) (unwind_info->pending_frame);
|
||||
frame_info_ptr frame = pending_frame->frame_info;
|
||||
|
||||
if (frame == nullptr)
|
||||
return PyUnicode_FromFormat ("<%s for an invalid frame>",
|
||||
Py_TYPE (self)->tp_name);
|
||||
|
||||
std::string saved_reg_names;
|
||||
struct gdbarch *gdbarch = pending_frame->gdbarch;
|
||||
|
||||
for (const saved_reg ® : *unwind_info->saved_regs)
|
||||
{
|
||||
const char *name = gdbarch_register_name (gdbarch, reg.number);
|
||||
if (saved_reg_names.empty ())
|
||||
saved_reg_names = name;
|
||||
else
|
||||
saved_reg_names = (saved_reg_names + ", ") + name;
|
||||
}
|
||||
|
||||
return PyUnicode_FromFormat ("<%s frame #%d, saved_regs=(%s)>",
|
||||
Py_TYPE (self)->tp_name,
|
||||
frame_relative_level (frame),
|
||||
saved_reg_names.c_str ());
|
||||
}
|
||||
|
||||
/* Create UnwindInfo instance for given PendingFrame and frame ID.
|
||||
Sets Python error and returns NULL on error.
|
||||
|
||||
@ -372,6 +404,37 @@ pending_framepy_str (PyObject *self)
|
||||
return PyUnicode_FromFormat ("SP=%s,PC=%s", sp_str, pc_str);
|
||||
}
|
||||
|
||||
/* Implement PendingFrame.__repr__(). */
|
||||
|
||||
static PyObject *
|
||||
pending_framepy_repr (PyObject *self)
|
||||
{
|
||||
pending_frame_object *pending_frame = (pending_frame_object *) self;
|
||||
frame_info_ptr frame = pending_frame->frame_info;
|
||||
|
||||
if (frame == nullptr)
|
||||
return PyUnicode_FromFormat ("<%s (invalid)>", Py_TYPE (self)->tp_name);
|
||||
|
||||
const char *sp_str = nullptr;
|
||||
const char *pc_str = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
sp_str = core_addr_to_string_nz (get_frame_sp (frame));
|
||||
pc_str = core_addr_to_string_nz (get_frame_pc (frame));
|
||||
}
|
||||
catch (const gdb_exception &except)
|
||||
{
|
||||
GDB_PY_HANDLE_EXCEPTION (except);
|
||||
}
|
||||
|
||||
return PyUnicode_FromFormat ("<%s level=%d, sp=%s, pc=%s>",
|
||||
Py_TYPE (self)->tp_name,
|
||||
frame_relative_level (frame),
|
||||
sp_str,
|
||||
pc_str);
|
||||
}
|
||||
|
||||
/* Implementation of gdb.PendingFrame.read_register (self, reg) -> gdb.Value.
|
||||
Returns the value of register REG as gdb.Value instance. */
|
||||
|
||||
@ -974,7 +1037,7 @@ PyTypeObject pending_frame_object_type =
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
pending_framepy_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
@ -1024,7 +1087,7 @@ PyTypeObject unwind_info_object_type =
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
unwind_infopy_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
|
@ -152,6 +152,25 @@ check_for_broken_backtrace "backtrace to capture a PendingFrame object"
|
||||
# Check the captured PendingFrame is not valid.
|
||||
gdb_test "python print(captured_pending_frame.is_valid())" "False"
|
||||
|
||||
# Check the __repr__ of an invalid PendingFrame.
|
||||
gdb_test "python print(repr(captured_pending_frame))" \
|
||||
"<gdb.PendingFrame \\(invalid\\)>"
|
||||
|
||||
# Check the __repr__ of an UnwindInfo for an invalid PendingFrame.
|
||||
gdb_test "python print(captured_unwind_info)"
|
||||
gdb_test "python print(repr(captured_unwind_info))" \
|
||||
"<gdb.UnwindInfo for an invalid frame>"
|
||||
|
||||
# Check the repr of a PendingFrame that was copied (as a string) at a
|
||||
# time the PendingFrame was valid.
|
||||
gdb_test "python print(captured_pending_frame_repr)" \
|
||||
"<gdb.PendingFrame level=0, sp=$hex, pc=$hex>"
|
||||
|
||||
# Check the repr of an UnwindInfo that was copied (as a string) at a
|
||||
# time the UnwindInfo was valid.
|
||||
gdb_test "python print(captured_unwind_info_repr)" \
|
||||
"<gdb.UnwindInfo frame #0, saved_regs=\\(rip, rbp, rsp\\)>"
|
||||
|
||||
# Call methods on the captured gdb.PendingFrame and check we see the
|
||||
# expected error.
|
||||
gdb_test_no_output "python pf = captured_pending_frame"
|
||||
|
@ -133,8 +133,11 @@ class TestUnwinder(Unwinder):
|
||||
global_test_unwinder = TestUnwinder()
|
||||
gdb.unwinder.register_unwinder(None, global_test_unwinder, True)
|
||||
|
||||
# This is filled in by the simple_unwinder class.
|
||||
# These are filled in by the simple_unwinder class.
|
||||
captured_pending_frame = None
|
||||
captured_pending_frame_repr = None
|
||||
captured_unwind_info = None
|
||||
captured_unwind_info_repr = None
|
||||
|
||||
|
||||
class simple_unwinder(Unwinder):
|
||||
@ -143,11 +146,22 @@ class simple_unwinder(Unwinder):
|
||||
|
||||
def __call__(self, pending_frame):
|
||||
global captured_pending_frame
|
||||
global captured_pending_frame_repr
|
||||
global captured_unwind_info
|
||||
global captured_unwind_info_repr
|
||||
|
||||
assert pending_frame.is_valid()
|
||||
|
||||
if captured_pending_frame is None:
|
||||
captured_pending_frame = pending_frame
|
||||
captured_pending_frame_repr = repr(pending_frame)
|
||||
fid = FrameId(gdb.Value(0x123), gdb.Value(0x456))
|
||||
uw = pending_frame.create_unwind_info(fid)
|
||||
uw.add_saved_register("rip", gdb.Value(0x123))
|
||||
uw.add_saved_register("rbp", gdb.Value(0x456))
|
||||
uw.add_saved_register("rsp", gdb.Value(0x789))
|
||||
captured_unwind_info = uw
|
||||
captured_unwind_info_repr = repr(uw)
|
||||
return None
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user