/* Python frame unwinder interface.
- Copyright (C) 2015-2018 Free Software Foundation, Inc.
+ Copyright (C) 2015-2022 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "arch-utils.h"
#include "frame-unwind.h"
-#include "gdb_obstack.h"
+#include "gdbsupport/gdb_obstack.h"
#include "gdbcmd.h"
#include "language.h"
#include "observable.h"
#include "regcache.h"
#include "valprint.h"
#include "user-regs.h"
-#include "py-ref.h"
-#define TRACE_PY_UNWIND(level, args...) if (pyuw_debug >= level) \
- { fprintf_unfiltered (gdb_stdlog, args); }
+/* Debugging of Python unwinders. */
-typedef struct
+static bool pyuw_debug;
+
+/* Implementation of "show debug py-unwind". */
+
+static void
+show_pyuw_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Python unwinder debugging is %s.\n"), value);
+}
+
+/* Print a "py-unwind" debug statement. */
+
+#define pyuw_debug_printf(fmt, ...) \
+ debug_prefixed_printf_cond (pyuw_debug, "py-unwind", fmt, ##__VA_ARGS__)
+
+/* Print "py-unwind" enter/exit debug statements. */
+
+#define PYUW_SCOPED_DEBUG_ENTER_EXIT \
+ scoped_debug_enter_exit (pyuw_debug, "py-unwind")
+
+struct pending_frame_object
{
PyObject_HEAD
/* Its architecture, passed by the sniffer caller. */
struct gdbarch *gdbarch;
-} pending_frame_object;
+};
/* Saved registers array item. */
/* The data we keep for the PyUnwindInfo: pending_frame, saved registers
and frame ID. */
-typedef struct
+struct unwind_info_object
{
PyObject_HEAD
/* Saved registers array. */
std::vector<saved_reg> *saved_regs;
-} unwind_info_object;
+};
/* The data we keep for a frame we can unwind: frame ID and an array of
(register_number, register_value) pairs. */
-typedef struct
+struct cached_frame_info
{
/* Frame ID. */
struct frame_id frame_id;
int reg_count;
cached_reg_t reg[];
-} cached_frame_info;
+};
extern PyTypeObject pending_frame_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pending_frame_object");
extern PyTypeObject unwind_info_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("unwind_info_object");
-static unsigned int pyuw_debug = 0;
-
static struct gdbarch_data *pyuw_gdbarch_data;
-/* Parses register id, which can be either a number or a name.
- Returns 1 on success, 0 otherwise. */
-
-static int
-pyuw_parse_register_id (struct gdbarch *gdbarch, PyObject *pyo_reg_id,
- int *reg_num)
-{
- if (pyo_reg_id == NULL)
- return 0;
- if (gdbpy_is_string (pyo_reg_id))
- {
- gdb::unique_xmalloc_ptr<char> reg_name (gdbpy_obj_to_string (pyo_reg_id));
-
- if (reg_name == NULL)
- return 0;
- *reg_num = user_reg_map_name_to_regnum (gdbarch, reg_name.get (),
- strlen (reg_name.get ()));
- return *reg_num >= 0;
- }
- else if (PyInt_Check (pyo_reg_id))
- {
- long value;
- if (gdb_py_int_as_long (pyo_reg_id, &value) && (int) value == value)
- {
- *reg_num = (int) value;
- return user_reg_map_regnum_to_name (gdbarch, *reg_num) != NULL;
- }
- }
- return 0;
-}
-
/* Convert gdb.Value instance to inferior's pointer. Return 1 on success,
0 on failure. */
int rc = 0;
struct value *value;
- TRY
+ try
{
if ((value = value_object_to_value (pyo_value)) != NULL)
- {
- *addr = unpack_pointer (value_type (value),
- value_contents (value));
- rc = 1;
- }
+ {
+ *addr = unpack_pointer (value_type (value),
+ value_contents (value).data ());
+ rc = 1;
+ }
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
gdbpy_convert_exception (except);
}
- END_CATCH
return rc;
}
static int
pyuw_object_attribute_to_pointer (PyObject *pyo, const char *attr_name,
- CORE_ADDR *addr)
+ CORE_ADDR *addr)
{
int rc = 0;
gdbpy_ref<> pyo_value (PyObject_GetAttrString (pyo, attr_name));
if (pyo_value != NULL && pyo_value != Py_None)
- {
- rc = pyuw_value_obj_to_pointer (pyo_value.get (), addr);
- if (!rc)
- PyErr_Format (
- PyExc_ValueError,
- _("The value of the '%s' attribute is not a pointer."),
- attr_name);
- }
+ {
+ rc = pyuw_value_obj_to_pointer (pyo_value.get (), addr);
+ if (!rc)
+ PyErr_Format (
+ PyExc_ValueError,
+ _("The value of the '%s' attribute is not a pointer."),
+ attr_name);
+ }
}
return rc;
}
unwind_info_object *unwind_info = (unwind_info_object *) self;
string_file stb;
- stb.puts ("Frame ID: ");
- fprint_frame_id (&stb, unwind_info->frame_id);
+ stb.printf ("Frame ID: %s", unwind_info->frame_id.to_string ().c_str ());
{
const char *sep = "";
struct value_print_options opts;
stb.printf ("\nSaved registers: (");
for (const saved_reg ® : *unwind_info->saved_regs)
{
- struct value *value = value_object_to_value (reg.value.get ());
-
- stb.printf ("%s(%d, ", sep, reg.number);
- if (value != NULL)
- {
- TRY
- {
- value_print (value, &stb, &opts);
- stb.puts (")");
- }
- CATCH (except, RETURN_MASK_ALL)
- {
- GDB_PY_HANDLE_EXCEPTION (except);
- }
- END_CATCH
- }
- else
- stb.puts ("<BAD>)");
- sep = ", ";
+ struct value *value = value_object_to_value (reg.value.get ());
+
+ stb.printf ("%s(%d, ", sep, reg.number);
+ if (value != NULL)
+ {
+ try
+ {
+ value_print (value, &stb, &opts);
+ stb.puts (")");
+ }
+ catch (const gdb_exception &except)
+ {
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+ }
+ else
+ stb.puts ("<BAD>)");
+ sep = ", ";
}
stb.puts (")");
}
static PyObject *
pyuw_create_unwind_info (PyObject *pyo_pending_frame,
- struct frame_id frame_id)
+ struct frame_id frame_id)
{
unwind_info_object *unwind_info
= PyObject_New (unwind_info_object, &unwind_info_object_type);
if (((pending_frame_object *) pyo_pending_frame)->frame_info == NULL)
{
PyErr_SetString (PyExc_ValueError,
- "Attempting to use stale PendingFrame");
+ "Attempting to use stale PendingFrame");
return NULL;
}
unwind_info->frame_id = frame_id;
if (pending_frame->frame_info == NULL)
{
PyErr_SetString (PyExc_ValueError,
- "UnwindInfo instance refers to a stale PendingFrame");
+ "UnwindInfo instance refers to a stale PendingFrame");
return NULL;
}
if (!PyArg_UnpackTuple (args, "previous_frame_register", 2, 2,
- &pyo_reg_id, &pyo_reg_value))
+ &pyo_reg_id, &pyo_reg_value))
return NULL;
- if (!pyuw_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
+ if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
{
PyErr_SetString (PyExc_ValueError, "Bad register");
return NULL;
}
+
+ /* If REGNUM identifies a user register then *maybe* we can convert this
+ to a real (i.e. non-user) register. The maybe qualifier is because we
+ don't know what user registers each target might add, however, the
+ following logic should work for the usual style of user registers,
+ where the read function just forwards the register read on to some
+ other register with no adjusting the value. */
+ if (regnum >= gdbarch_num_cooked_regs (pending_frame->gdbarch))
+ {
+ struct value *user_reg_value
+ = value_of_user_reg (regnum, pending_frame->frame_info);
+ if (VALUE_LVAL (user_reg_value) == lval_register)
+ regnum = VALUE_REGNUM (user_reg_value);
+ if (regnum >= gdbarch_num_cooked_regs (pending_frame->gdbarch))
+ {
+ PyErr_SetString (PyExc_ValueError, "Bad register");
+ return NULL;
+ }
+ }
+
{
struct value *value;
size_t data_size;
if (pyo_reg_value == NULL
|| (value = value_object_to_value (pyo_reg_value)) == NULL)
{
- PyErr_SetString (PyExc_ValueError, "Bad register value");
- return NULL;
+ PyErr_SetString (PyExc_ValueError, "Bad register value");
+ return NULL;
}
data_size = register_size (pending_frame->gdbarch, regnum);
if (data_size != TYPE_LENGTH (value_type (value)))
{
- PyErr_Format (
- PyExc_ValueError,
- "The value of the register returned by the Python "
- "sniffer has unexpected size: %u instead of %u.",
- (unsigned) TYPE_LENGTH (value_type (value)),
- (unsigned) data_size);
- return NULL;
+ PyErr_Format (
+ PyExc_ValueError,
+ "The value of the register returned by the Python "
+ "sniffer has unexpected size: %u instead of %u.",
+ (unsigned) TYPE_LENGTH (value_type (value)),
+ (unsigned) data_size);
+ return NULL;
}
}
{
bool found = false;
for (saved_reg ® : *unwind_info->saved_regs)
{
- if (regnum == reg.number)
- {
+ if (regnum == reg.number)
+ {
found = true;
reg.value = std::move (new_value);
- break;
- }
+ break;
+ }
}
if (!found)
unwind_info->saved_regs->emplace_back (regnum, std::move (new_value));
unwind_infopy_dealloc (PyObject *self)
{
unwind_info_object *unwind_info = (unwind_info_object *) self;
- int i;
- saved_reg *reg;
Py_XDECREF (unwind_info->pending_frame);
delete unwind_info->saved_regs;
if (frame == NULL)
return PyString_FromString ("Stale PendingFrame instance");
- TRY
+ try
{
sp_str = core_addr_to_string_nz (get_frame_sp (frame));
pc_str = core_addr_to_string_nz (get_frame_pc (frame));
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
return PyString_FromFormat ("SP=%s,PC=%s", sp_str, pc_str);
}
if (pending_frame->frame_info == NULL)
{
PyErr_SetString (PyExc_ValueError,
- "Attempting to read register from stale PendingFrame");
+ "Attempting to read register from stale PendingFrame");
return NULL;
}
if (!PyArg_UnpackTuple (args, "read_register", 1, 1, &pyo_reg_id))
return NULL;
- if (!pyuw_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
+ if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
{
PyErr_SetString (PyExc_ValueError, "Bad register");
return NULL;
}
- TRY
+ try
{
/* Fetch the value associated with a register, whether it's
a real register or a so called "user" register, like "pc",
handle the user register case. */
val = value_of_register (regnum, pending_frame->frame_info);
if (val == NULL)
- PyErr_Format (PyExc_ValueError,
- "Cannot read register %d from frame.",
- regnum);
+ PyErr_Format (PyExc_ValueError,
+ "Cannot read register %d from frame.",
+ regnum);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
GDB_PY_HANDLE_EXCEPTION (except);
}
- END_CATCH
return val == NULL ? NULL : value_to_value_object (val);
}
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp))
{
PyErr_SetString (PyExc_ValueError,
- _("frame_id should have 'sp' attribute."));
+ _("frame_id should have 'sp' attribute."));
return NULL;
}
return pyuw_create_unwind_info (self, frame_id_build (sp, pc));
else
return pyuw_create_unwind_info (self,
- frame_id_build_special (sp, pc, special));
+ frame_id_build_special (sp, pc, special));
+}
+
+/* Implementation of PendingFrame.architecture (self) -> gdb.Architecture. */
+
+static PyObject *
+pending_framepy_architecture (PyObject *self, PyObject *args)
+{
+ pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+ if (pending_frame->frame_info == NULL)
+ {
+ PyErr_SetString (PyExc_ValueError,
+ "Attempting to read register from stale PendingFrame");
+ return NULL;
+ }
+ return gdbarch_to_arch_object (pending_frame->gdbarch);
+}
+
+/* Implementation of PendingFrame.level (self) -> Integer. */
+
+static PyObject *
+pending_framepy_level (PyObject *self, PyObject *args)
+{
+ pending_frame_object *pending_frame = (pending_frame_object *) self;
+
+ if (pending_frame->frame_info == NULL)
+ {
+ PyErr_SetString (PyExc_ValueError,
+ "Attempting to read stack level from stale PendingFrame");
+ return NULL;
+ }
+ int level = frame_relative_level (pending_frame->frame_info);
+ return gdb_py_object_from_longest (level).release ();
}
/* frame_unwind.this_id method. */
static void
pyuw_this_id (struct frame_info *this_frame, void **cache_ptr,
- struct frame_id *this_id)
+ struct frame_id *this_id)
{
*this_id = ((cached_frame_info *) *cache_ptr)->frame_id;
- if (pyuw_debug >= 1)
- {
- fprintf_unfiltered (gdb_stdlog, "%s: frame_id: ", __FUNCTION__);
- fprint_frame_id (gdb_stdlog, *this_id);
- fprintf_unfiltered (gdb_stdlog, "\n");
- }
+ pyuw_debug_printf ("frame_id: %s", this_id->to_string ().c_str ());
}
/* frame_unwind.prev_register. */
static struct value *
pyuw_prev_register (struct frame_info *this_frame, void **cache_ptr,
- int regnum)
+ int regnum)
{
+ PYUW_SCOPED_DEBUG_ENTER_EXIT;
+
cached_frame_info *cached_frame = (cached_frame_info *) *cache_ptr;
cached_reg_t *reg_info = cached_frame->reg;
cached_reg_t *reg_info_end = reg_info + cached_frame->reg_count;
- TRACE_PY_UNWIND (1, "%s (frame=%p,...,reg=%d)\n", __FUNCTION__, this_frame,
- regnum);
+ pyuw_debug_printf ("frame=%d, reg=%d",
+ frame_relative_level (this_frame), regnum);
for (; reg_info < reg_info_end; ++reg_info)
{
if (regnum == reg_info->num)
- return frame_unwind_got_bytes (this_frame, regnum, reg_info->data);
+ return frame_unwind_got_bytes (this_frame, regnum, reg_info->data);
}
return frame_unwind_got_optimized (this_frame, regnum);
static int
pyuw_sniffer (const struct frame_unwind *self, struct frame_info *this_frame,
- void **cache_ptr)
+ void **cache_ptr)
{
+ PYUW_SCOPED_DEBUG_ENTER_EXIT;
+
struct gdbarch *gdbarch = (struct gdbarch *) (self->unwind_data);
cached_frame_info *cached_frame;
- gdbpy_enter enter_py (gdbarch, current_language);
+ gdbpy_enter enter_py (gdbarch);
- TRACE_PY_UNWIND (3, "%s (SP=%s, PC=%s)\n", __FUNCTION__,
- paddress (gdbarch, get_frame_sp (this_frame)),
- paddress (gdbarch, get_frame_pc (this_frame)));
+ pyuw_debug_printf ("frame=%d, sp=%s, pc=%s",
+ frame_relative_level (this_frame),
+ paddress (gdbarch, get_frame_sp (this_frame)),
+ paddress (gdbarch, get_frame_pc (this_frame)));
/* Create PendingFrame instance to pass to sniffers. */
pending_frame_object *pfo = PyObject_New (pending_frame_object,
/* Run unwinders. */
if (gdb_python_module == NULL
- || ! PyObject_HasAttrString (gdb_python_module, "execute_unwinders"))
+ || ! PyObject_HasAttrString (gdb_python_module, "_execute_unwinders"))
{
PyErr_SetString (PyExc_NameError,
- "Installation error: gdb.execute_unwinders function "
- "is missing");
+ "Installation error: gdb._execute_unwinders function "
+ "is missing");
gdbpy_print_stack ();
return 0;
}
gdbpy_ref<> pyo_execute (PyObject_GetAttrString (gdb_python_module,
- "execute_unwinders"));
- if (pyo_execute == NULL)
+ "_execute_unwinders"));
+ if (pyo_execute == nullptr)
{
gdbpy_print_stack ();
return 0;
}
- gdbpy_ref<> pyo_unwind_info
+ /* A (gdb.UnwindInfo, str) tuple, or None. */
+ gdbpy_ref<> pyo_execute_ret
(PyObject_CallFunctionObjArgs (pyo_execute.get (),
pyo_pending_frame.get (), NULL));
- if (pyo_unwind_info == NULL)
+ if (pyo_execute_ret == nullptr)
{
/* If the unwinder is cancelled due to a Ctrl-C, then propagate
the Ctrl-C as a GDB exception instead of swallowing it. */
- if (PyErr_ExceptionMatches (PyExc_KeyboardInterrupt))
- {
- PyErr_Clear ();
- quit ();
- }
- gdbpy_print_stack ();
+ gdbpy_print_stack_or_quit ();
return 0;
}
- if (pyo_unwind_info == Py_None)
+ if (pyo_execute_ret == Py_None)
return 0;
+ /* Verify the return value of _execute_unwinders is a tuple of size 2. */
+ gdb_assert (PyTuple_Check (pyo_execute_ret.get ()));
+ gdb_assert (PyTuple_GET_SIZE (pyo_execute_ret.get ()) == 2);
+
+ if (pyuw_debug)
+ {
+ PyObject *pyo_unwinder_name = PyTuple_GET_ITEM (pyo_execute_ret.get (), 1);
+ gdb::unique_xmalloc_ptr<char> name
+ = python_string_to_host_string (pyo_unwinder_name);
+
+ /* This could happen if the user passed something else than a string
+ as the unwinder's name. */
+ if (name == nullptr)
+ {
+ gdbpy_print_stack ();
+ name = make_unique_xstrdup ("<failed to get unwinder name>");
+ }
+
+ pyuw_debug_printf ("frame claimed by unwinder %s", name.get ());
+ }
+
/* Received UnwindInfo, cache data. */
- if (PyObject_IsInstance (pyo_unwind_info.get (),
- (PyObject *) &unwind_info_object_type) <= 0)
+ PyObject *pyo_unwind_info = PyTuple_GET_ITEM (pyo_execute_ret.get (), 0);
+ if (PyObject_IsInstance (pyo_unwind_info,
+ (PyObject *) &unwind_info_object_type) <= 0)
error (_("A Unwinder should return gdb.UnwindInfo instance."));
{
unwind_info_object *unwind_info =
- (unwind_info_object *) pyo_unwind_info.get ();
+ (unwind_info_object *) pyo_unwind_info;
int reg_count = unwind_info->saved_regs->size ();
cached_frame
{
saved_reg *reg = &(*unwind_info->saved_regs)[i];
- struct value *value = value_object_to_value (reg->value.get ());
- size_t data_size = register_size (gdbarch, reg->number);
+ struct value *value = value_object_to_value (reg->value.get ());
+ size_t data_size = register_size (gdbarch, reg->number);
cached_frame->reg[i].num = reg->number;
- /* `value' validation was done before, just assert. */
- gdb_assert (value != NULL);
- gdb_assert (data_size == TYPE_LENGTH (value_type (value)));
+ /* `value' validation was done before, just assert. */
+ gdb_assert (value != NULL);
+ gdb_assert (data_size == TYPE_LENGTH (value_type (value)));
cached_frame->reg[i].data = (gdb_byte *) xmalloc (data_size);
- memcpy (cached_frame->reg[i].data, value_contents (value), data_size);
+ memcpy (cached_frame->reg[i].data,
+ value_contents (value).data (), data_size);
}
}
static void
pyuw_dealloc_cache (struct frame_info *this_frame, void *cache)
{
- TRACE_PY_UNWIND (3, "%s: enter", __FUNCTION__);
+ PYUW_SCOPED_DEBUG_ENTER_EXIT;
cached_frame_info *cached_frame = (cached_frame_info *) cache;
for (int i = 0; i < cached_frame->reg_count; i++)
if (!data->unwinder_registered)
{
struct frame_unwind *unwinder
- = GDBARCH_OBSTACK_ZALLOC (newarch, struct frame_unwind);
+ = GDBARCH_OBSTACK_ZALLOC (newarch, struct frame_unwind);
+ unwinder->name = "python";
unwinder->type = NORMAL_FRAME;
unwinder->stop_reason = default_frame_unwind_stop_reason;
unwinder->this_id = pyuw_this_id;
}
}
+void _initialize_py_unwind ();
+void
+_initialize_py_unwind ()
+{
+ add_setshow_boolean_cmd
+ ("py-unwind", class_maintenance, &pyuw_debug,
+ _("Set Python unwinder debugging."),
+ _("Show Python unwinder debugging."),
+ _("When on, Python unwinder debugging is enabled."),
+ NULL,
+ show_pyuw_debug,
+ &setdebuglist, &showdebuglist);
+ pyuw_gdbarch_data
+ = gdbarch_data_register_post_init (pyuw_gdbarch_data_init);
+}
+
/* Initialize unwind machinery. */
int
gdbpy_initialize_unwind (void)
{
- int rc;
- add_setshow_zuinteger_cmd
- ("py-unwind", class_maintenance, &pyuw_debug,
- _("Set Python unwinder debugging."),
- _("Show Python unwinder debugging."),
- _("When non-zero, Python unwinder debugging is enabled."),
- NULL,
- NULL,
- &setdebuglist, &showdebuglist);
- pyuw_gdbarch_data
- = gdbarch_data_register_post_init (pyuw_gdbarch_data_init);
- gdb::observers::architecture_changed.attach (pyuw_on_new_gdbarch);
+ gdb::observers::architecture_changed.attach (pyuw_on_new_gdbarch,
+ "py-unwind");
if (PyType_Ready (&pending_frame_object_type) < 0)
return -1;
- rc = gdb_pymodule_addobject (gdb_module, "PendingFrame",
- (PyObject *) &pending_frame_object_type);
- if (rc)
+ int rc = gdb_pymodule_addobject (gdb_module, "PendingFrame",
+ (PyObject *) &pending_frame_object_type);
+ if (rc != 0)
return rc;
if (PyType_Ready (&unwind_info_object_type) < 0)
"create_unwind_info (FRAME_ID) -> gdb.UnwindInfo\n"
"Construct UnwindInfo for this PendingFrame, using FRAME_ID\n"
"to identify it." },
+ { "architecture",
+ pending_framepy_architecture, METH_NOARGS,
+ "architecture () -> gdb.Architecture\n"
+ "The architecture for this PendingFrame." },
+ { "level", pending_framepy_level, METH_NOARGS,
+ "The stack level of this frame." },
{NULL} /* Sentinel */
};