mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-18 12:24:38 +08:00
43d5901ded
This commit unifies all of the Python register lookup code (used by Frame.read_register, PendingFrame.read_register, and gdb.UnwindInfo.add_saved_register), and adds support for using a gdb.RegisterDescriptor for register lookup. Currently the register unwind code (PendingFrame and UnwindInfo) allow registers to be looked up either by name, or by GDB's internal number. I suspect the number was added for performance reasons, when unwinding we don't want to repeatedly map from name to number for every unwind. However, this kind-of sucks, it means Python scripts could include GDB's internal register numbers, and if we ever change this numbering in the future users scripts will break in unexpected ways. Meanwhile, the Frame.read_register method only supports accessing registers using a string, the register name. This commit unifies all of the register to register-number lookup code in our Python bindings, and adds a third choice into the mix, the use of gdb.RegisterDescriptor. The register descriptors can be looked up by name, but once looked up, they contain GDB's register number, and so provide all of the performance benefits of using a register number directly. However, as they are looked up by name we are no longer tightly binding the Python API to GDB's internal numbering scheme. As we may already have scripts in the wild that are using the register numbers directly I have kept support for this in the API, but I have listed this method last in the manual, and I have tried to stress that this is NOT a good method to use and that users should use either a string or register descriptor approach. After this commit all existing Python code should function as before, but users now have new options for how to identify registers. gdb/ChangeLog: * python/py-frame.c: Remove 'user-regs.h' include. (frapy_read_register): Rewrite to make use of gdbpy_parse_register_id. * python/py-registers.c (gdbpy_parse_register_id): New function, moved here from python/py-unwind.c. Updated the return type, and also accepts register descriptor objects. * python/py-unwind.c: Remove 'user-regs.h' include. (pyuw_parse_register_id): Moved to python/py-registers.c. (unwind_infopy_add_saved_register): Update to use gdbpy_parse_register_id. (pending_framepy_read_register): Likewise. * python/python-internal.h (gdbpy_parse_register_id): Declare. gdb/testsuite/ChangeLog: * gdb.python/py-unwind.py: Update to make use of a register descriptor. gdb/doc/ChangeLog: * python.texi (Unwinding Frames in Python): Update descriptions for PendingFrame.read_register and gdb.UnwindInfo.add_saved_register. (Frames In Python): Update description of Frame.read_register.
755 lines
23 KiB
C
755 lines
23 KiB
C
/* Python frame unwinder interface.
|
|
|
|
Copyright (C) 2015-2020 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "arch-utils.h"
|
|
#include "frame-unwind.h"
|
|
#include "gdb_obstack.h"
|
|
#include "gdbcmd.h"
|
|
#include "language.h"
|
|
#include "observable.h"
|
|
#include "python-internal.h"
|
|
#include "regcache.h"
|
|
#include "valprint.h"
|
|
|
|
#define TRACE_PY_UNWIND(level, args...) if (pyuw_debug >= level) \
|
|
{ fprintf_unfiltered (gdb_stdlog, args); }
|
|
|
|
typedef struct
|
|
{
|
|
PyObject_HEAD
|
|
|
|
/* Frame we are unwinding. */
|
|
struct frame_info *frame_info;
|
|
|
|
/* Its architecture, passed by the sniffer caller. */
|
|
struct gdbarch *gdbarch;
|
|
} pending_frame_object;
|
|
|
|
/* Saved registers array item. */
|
|
|
|
struct saved_reg
|
|
{
|
|
saved_reg (int n, gdbpy_ref<> &&v)
|
|
: number (n),
|
|
value (std::move (v))
|
|
{
|
|
}
|
|
|
|
int number;
|
|
gdbpy_ref<> value;
|
|
};
|
|
|
|
/* The data we keep for the PyUnwindInfo: pending_frame, saved registers
|
|
and frame ID. */
|
|
|
|
typedef struct
|
|
{
|
|
PyObject_HEAD
|
|
|
|
/* gdb.PendingFrame for the frame we are unwinding. */
|
|
PyObject *pending_frame;
|
|
|
|
/* Its ID. */
|
|
struct frame_id frame_id;
|
|
|
|
/* 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
|
|
{
|
|
/* Frame ID. */
|
|
struct frame_id frame_id;
|
|
|
|
/* GDB Architecture. */
|
|
struct gdbarch *gdbarch;
|
|
|
|
/* Length of the `reg' array below. */
|
|
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;
|
|
|
|
/* Convert gdb.Value instance to inferior's pointer. Return 1 on success,
|
|
0 on failure. */
|
|
|
|
static int
|
|
pyuw_value_obj_to_pointer (PyObject *pyo_value, CORE_ADDR *addr)
|
|
{
|
|
int rc = 0;
|
|
struct value *value;
|
|
|
|
try
|
|
{
|
|
if ((value = value_object_to_value (pyo_value)) != NULL)
|
|
{
|
|
*addr = unpack_pointer (value_type (value),
|
|
value_contents (value));
|
|
rc = 1;
|
|
}
|
|
}
|
|
catch (const gdb_exception &except)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* Get attribute from an object and convert it to the inferior's
|
|
pointer value. Return 1 if attribute exists and its value can be
|
|
converted. Otherwise, if attribute does not exist or its value is
|
|
None, return 0. In all other cases set Python error and return
|
|
0. */
|
|
|
|
static int
|
|
pyuw_object_attribute_to_pointer (PyObject *pyo, const char *attr_name,
|
|
CORE_ADDR *addr)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (PyObject_HasAttrString (pyo, attr_name))
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* Called by the Python interpreter to obtain string representation
|
|
of the UnwindInfo object. */
|
|
|
|
static PyObject *
|
|
unwind_infopy_str (PyObject *self)
|
|
{
|
|
unwind_info_object *unwind_info = (unwind_info_object *) self;
|
|
string_file stb;
|
|
|
|
stb.puts ("Frame ID: ");
|
|
fprint_frame_id (&stb, unwind_info->frame_id);
|
|
{
|
|
const char *sep = "";
|
|
struct value_print_options opts;
|
|
|
|
get_user_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 (const gdb_exception &except)
|
|
{
|
|
GDB_PY_HANDLE_EXCEPTION (except);
|
|
}
|
|
}
|
|
else
|
|
stb.puts ("<BAD>)");
|
|
sep = ", ";
|
|
}
|
|
stb.puts (")");
|
|
}
|
|
|
|
return PyString_FromString (stb.c_str ());
|
|
}
|
|
|
|
/* Create UnwindInfo instance for given PendingFrame and frame ID.
|
|
Sets Python error and returns NULL on error. */
|
|
|
|
static PyObject *
|
|
pyuw_create_unwind_info (PyObject *pyo_pending_frame,
|
|
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");
|
|
return NULL;
|
|
}
|
|
unwind_info->frame_id = frame_id;
|
|
Py_INCREF (pyo_pending_frame);
|
|
unwind_info->pending_frame = pyo_pending_frame;
|
|
unwind_info->saved_regs = new std::vector<saved_reg>;
|
|
return (PyObject *) unwind_info;
|
|
}
|
|
|
|
/* The implementation of
|
|
gdb.UnwindInfo.add_saved_register (REG, VALUE) -> None. */
|
|
|
|
static PyObject *
|
|
unwind_infopy_add_saved_register (PyObject *self, PyObject *args)
|
|
{
|
|
unwind_info_object *unwind_info = (unwind_info_object *) self;
|
|
pending_frame_object *pending_frame
|
|
= (pending_frame_object *) (unwind_info->pending_frame);
|
|
PyObject *pyo_reg_id;
|
|
PyObject *pyo_reg_value;
|
|
int regnum;
|
|
|
|
if (pending_frame->frame_info == NULL)
|
|
{
|
|
PyErr_SetString (PyExc_ValueError,
|
|
"UnwindInfo instance refers to a stale PendingFrame");
|
|
return NULL;
|
|
}
|
|
if (!PyArg_UnpackTuple (args, "previous_frame_register", 2, 2,
|
|
&pyo_reg_id, &pyo_reg_value))
|
|
return NULL;
|
|
if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
|
|
{
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
{
|
|
gdbpy_ref<> new_value = gdbpy_ref<>::new_reference (pyo_reg_value);
|
|
bool found = false;
|
|
for (saved_reg ® : *unwind_info->saved_regs)
|
|
{
|
|
if (regnum == reg.number)
|
|
{
|
|
found = true;
|
|
reg.value = std::move (new_value);
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
unwind_info->saved_regs->emplace_back (regnum, std::move (new_value));
|
|
}
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
/* UnwindInfo cleanup. */
|
|
|
|
static void
|
|
unwind_infopy_dealloc (PyObject *self)
|
|
{
|
|
unwind_info_object *unwind_info = (unwind_info_object *) self;
|
|
|
|
Py_XDECREF (unwind_info->pending_frame);
|
|
delete unwind_info->saved_regs;
|
|
Py_TYPE (self)->tp_free (self);
|
|
}
|
|
|
|
/* Called by the Python interpreter to obtain string representation
|
|
of the PendingFrame object. */
|
|
|
|
static PyObject *
|
|
pending_framepy_str (PyObject *self)
|
|
{
|
|
struct frame_info *frame = ((pending_frame_object *) self)->frame_info;
|
|
const char *sp_str = NULL;
|
|
const char *pc_str = NULL;
|
|
|
|
if (frame == NULL)
|
|
return PyString_FromString ("Stale PendingFrame instance");
|
|
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 PyString_FromFormat ("SP=%s,PC=%s", sp_str, pc_str);
|
|
}
|
|
|
|
/* Implementation of gdb.PendingFrame.read_register (self, reg) -> gdb.Value.
|
|
Returns the value of register REG as gdb.Value instance. */
|
|
|
|
static PyObject *
|
|
pending_framepy_read_register (PyObject *self, PyObject *args)
|
|
{
|
|
pending_frame_object *pending_frame = (pending_frame_object *) self;
|
|
struct value *val = NULL;
|
|
int regnum;
|
|
PyObject *pyo_reg_id;
|
|
|
|
if (pending_frame->frame_info == NULL)
|
|
{
|
|
PyErr_SetString (PyExc_ValueError,
|
|
"Attempting to read register from stale PendingFrame");
|
|
return NULL;
|
|
}
|
|
if (!PyArg_UnpackTuple (args, "read_register", 1, 1, &pyo_reg_id))
|
|
return NULL;
|
|
if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
|
|
{
|
|
PyErr_SetString (PyExc_ValueError, "Bad register");
|
|
return NULL;
|
|
}
|
|
|
|
try
|
|
{
|
|
/* Fetch the value associated with a register, whether it's
|
|
a real register or a so called "user" register, like "pc",
|
|
which maps to a real register. In the past,
|
|
get_frame_register_value() was used here, which did not
|
|
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);
|
|
}
|
|
catch (const gdb_exception &except)
|
|
{
|
|
GDB_PY_HANDLE_EXCEPTION (except);
|
|
}
|
|
|
|
return val == NULL ? NULL : value_to_value_object (val);
|
|
}
|
|
|
|
/* Implementation of
|
|
PendingFrame.create_unwind_info (self, frameId) -> UnwindInfo. */
|
|
|
|
static PyObject *
|
|
pending_framepy_create_unwind_info (PyObject *self, PyObject *args)
|
|
{
|
|
PyObject *pyo_frame_id;
|
|
CORE_ADDR sp;
|
|
CORE_ADDR pc;
|
|
CORE_ADDR special;
|
|
|
|
if (!PyArg_ParseTuple (args, "O:create_unwind_info", &pyo_frame_id))
|
|
return NULL;
|
|
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp))
|
|
{
|
|
PyErr_SetString (PyExc_ValueError,
|
|
_("frame_id should have 'sp' attribute."));
|
|
return NULL;
|
|
}
|
|
|
|
/* The logic of building frame_id depending on the attributes of
|
|
the frame_id object:
|
|
Has Has Has Function to call
|
|
'sp'? 'pc'? 'special'?
|
|
------|------|--------------|-------------------------
|
|
Y N * frame_id_build_wild (sp)
|
|
Y Y N frame_id_build (sp, pc)
|
|
Y Y Y frame_id_build_special (sp, pc, special)
|
|
*/
|
|
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "pc", &pc))
|
|
return pyuw_create_unwind_info (self, frame_id_build_wild (sp));
|
|
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "special", &special))
|
|
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));
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* frame_unwind.this_id method. */
|
|
|
|
static void
|
|
pyuw_this_id (struct frame_info *this_frame, void **cache_ptr,
|
|
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");
|
|
}
|
|
}
|
|
|
|
/* frame_unwind.prev_register. */
|
|
|
|
static struct value *
|
|
pyuw_prev_register (struct frame_info *this_frame, void **cache_ptr,
|
|
int regnum)
|
|
{
|
|
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);
|
|
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_optimized (this_frame, regnum);
|
|
}
|
|
|
|
/* Frame sniffer dispatch. */
|
|
|
|
static int
|
|
pyuw_sniffer (const struct frame_unwind *self, struct frame_info *this_frame,
|
|
void **cache_ptr)
|
|
{
|
|
struct gdbarch *gdbarch = (struct gdbarch *) (self->unwind_data);
|
|
cached_frame_info *cached_frame;
|
|
|
|
gdbpy_enter enter_py (gdbarch, current_language);
|
|
|
|
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)));
|
|
|
|
/* Create PendingFrame instance to pass to sniffers. */
|
|
pending_frame_object *pfo = PyObject_New (pending_frame_object,
|
|
&pending_frame_object_type);
|
|
gdbpy_ref<> pyo_pending_frame ((PyObject *) pfo);
|
|
if (pyo_pending_frame == NULL)
|
|
{
|
|
gdbpy_print_stack ();
|
|
return 0;
|
|
}
|
|
pfo->gdbarch = gdbarch;
|
|
scoped_restore invalidate_frame = make_scoped_restore (&pfo->frame_info,
|
|
this_frame);
|
|
|
|
/* Run unwinders. */
|
|
if (gdb_python_module == NULL
|
|
|| ! PyObject_HasAttrString (gdb_python_module, "_execute_unwinders"))
|
|
{
|
|
PyErr_SetString (PyExc_NameError,
|
|
"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)
|
|
{
|
|
gdbpy_print_stack ();
|
|
return 0;
|
|
}
|
|
|
|
gdbpy_ref<> pyo_unwind_info
|
|
(PyObject_CallFunctionObjArgs (pyo_execute.get (),
|
|
pyo_pending_frame.get (), NULL));
|
|
if (pyo_unwind_info == NULL)
|
|
{
|
|
/* If the unwinder is cancelled due to a Ctrl-C, then propagate
|
|
the Ctrl-C as a GDB exception instead of swallowing it. */
|
|
gdbpy_print_stack_or_quit ();
|
|
return 0;
|
|
}
|
|
if (pyo_unwind_info == Py_None)
|
|
return 0;
|
|
|
|
/* Received UnwindInfo, cache data. */
|
|
if (PyObject_IsInstance (pyo_unwind_info.get (),
|
|
(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 ();
|
|
int reg_count = unwind_info->saved_regs->size ();
|
|
|
|
cached_frame
|
|
= ((cached_frame_info *)
|
|
xmalloc (sizeof (*cached_frame)
|
|
+ reg_count * sizeof (cached_frame->reg[0])));
|
|
cached_frame->gdbarch = gdbarch;
|
|
cached_frame->frame_id = unwind_info->frame_id;
|
|
cached_frame->reg_count = reg_count;
|
|
|
|
/* Populate registers array. */
|
|
for (int i = 0; i < unwind_info->saved_regs->size (); ++i)
|
|
{
|
|
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);
|
|
|
|
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)));
|
|
|
|
cached_frame->reg[i].data = (gdb_byte *) xmalloc (data_size);
|
|
memcpy (cached_frame->reg[i].data, value_contents (value), data_size);
|
|
}
|
|
}
|
|
|
|
*cache_ptr = cached_frame;
|
|
return 1;
|
|
}
|
|
|
|
/* Frame cache release shim. */
|
|
|
|
static void
|
|
pyuw_dealloc_cache (struct frame_info *this_frame, void *cache)
|
|
{
|
|
TRACE_PY_UNWIND (3, "%s: enter", __FUNCTION__);
|
|
cached_frame_info *cached_frame = (cached_frame_info *) cache;
|
|
|
|
for (int i = 0; i < cached_frame->reg_count; i++)
|
|
xfree (cached_frame->reg[i].data);
|
|
|
|
xfree (cache);
|
|
}
|
|
|
|
struct pyuw_gdbarch_data_type
|
|
{
|
|
/* Has the unwinder shim been prepended? */
|
|
int unwinder_registered;
|
|
};
|
|
|
|
static void *
|
|
pyuw_gdbarch_data_init (struct gdbarch *gdbarch)
|
|
{
|
|
return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct pyuw_gdbarch_data_type);
|
|
}
|
|
|
|
/* New inferior architecture callback: register the Python unwinders
|
|
intermediary. */
|
|
|
|
static void
|
|
pyuw_on_new_gdbarch (struct gdbarch *newarch)
|
|
{
|
|
struct pyuw_gdbarch_data_type *data
|
|
= (struct pyuw_gdbarch_data_type *) gdbarch_data (newarch,
|
|
pyuw_gdbarch_data);
|
|
|
|
if (!data->unwinder_registered)
|
|
{
|
|
struct frame_unwind *unwinder
|
|
= GDBARCH_OBSTACK_ZALLOC (newarch, struct frame_unwind);
|
|
|
|
unwinder->type = NORMAL_FRAME;
|
|
unwinder->stop_reason = default_frame_unwind_stop_reason;
|
|
unwinder->this_id = pyuw_this_id;
|
|
unwinder->prev_register = pyuw_prev_register;
|
|
unwinder->unwind_data = (const struct frame_data *) newarch;
|
|
unwinder->sniffer = pyuw_sniffer;
|
|
unwinder->dealloc_cache = pyuw_dealloc_cache;
|
|
frame_unwind_prepend_unwinder (newarch, unwinder);
|
|
data->unwinder_registered = 1;
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
|
|
if (PyType_Ready (&pending_frame_object_type) < 0)
|
|
return -1;
|
|
rc = gdb_pymodule_addobject (gdb_module, "PendingFrame",
|
|
(PyObject *) &pending_frame_object_type);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (PyType_Ready (&unwind_info_object_type) < 0)
|
|
return -1;
|
|
return gdb_pymodule_addobject (gdb_module, "UnwindInfo",
|
|
(PyObject *) &unwind_info_object_type);
|
|
}
|
|
|
|
static PyMethodDef pending_frame_object_methods[] =
|
|
{
|
|
{ "read_register", pending_framepy_read_register, METH_VARARGS,
|
|
"read_register (REG) -> gdb.Value\n"
|
|
"Return the value of the REG in the frame." },
|
|
{ "create_unwind_info",
|
|
pending_framepy_create_unwind_info, METH_VARARGS,
|
|
"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." },
|
|
{NULL} /* Sentinel */
|
|
};
|
|
|
|
PyTypeObject pending_frame_object_type =
|
|
{
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
|
"gdb.PendingFrame", /* tp_name */
|
|
sizeof (pending_frame_object), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
0, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
pending_framepy_str, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
"GDB PendingFrame object", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
pending_frame_object_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
};
|
|
|
|
static PyMethodDef unwind_info_object_methods[] =
|
|
{
|
|
{ "add_saved_register",
|
|
unwind_infopy_add_saved_register, METH_VARARGS,
|
|
"add_saved_register (REG, VALUE) -> None\n"
|
|
"Set the value of the REG in the previous frame to VALUE." },
|
|
{ NULL } /* Sentinel */
|
|
};
|
|
|
|
PyTypeObject unwind_info_object_type =
|
|
{
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
|
"gdb.UnwindInfo", /* tp_name */
|
|
sizeof (unwind_info_object), /* tp_basicsize */
|
|
0, /* tp_itemsize */
|
|
unwind_infopy_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
0, /* tp_as_mapping */
|
|
0, /* tp_hash */
|
|
0, /* tp_call */
|
|
unwind_infopy_str, /* tp_str */
|
|
0, /* tp_getattro */
|
|
0, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
"GDB UnwindInfo object", /* tp_doc */
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
unwind_info_object_methods, /* tp_methods */
|
|
0, /* tp_members */
|
|
0, /* tp_getset */
|
|
0, /* tp_base */
|
|
0, /* tp_dict */
|
|
0, /* tp_descr_get */
|
|
0, /* tp_descr_set */
|
|
0, /* tp_dictoffset */
|
|
0, /* tp_init */
|
|
0, /* tp_alloc */
|
|
};
|