Add support for writing unwinders in Python.
gdb/ChangeLog: * Makefile.in (SUBDIR_PYTHON_OBJS): Add py-unwind.o. (SUBDIR_PYTHON_SRCS): Add py-unwind.c. (py-unwind.o): New recipe. * NEWS: mention Python frame unwinding. * data-directory/Makefile.in (PYTHON_FILE_LIST): Add gdb/unwinder.py and gdb/command/unwinder.py * python/lib/gdb/__init__.py (packages): Add frame_unwinders list. (execute_unwinders): New function. * python/lib/gdb/command/unwinders.py: New file. * python/lib/gdb/unwinder.py: New file. * python/py-objfile.c (objfile_object): Add frame_unwinders field. (objfpy_dealloc): Decrement frame_unwinders reference count. (objfpy_initialize): Create frame_unwinders list. (objfpy_get_frame_unwinders): New function. (objfpy_set_frame_unwinders): Ditto. (objfile_getset): Add frame_unwinders attribute to Objfile. * python/py-progspace.c (pspace_object): Add frame_unwinders field. (pspy_dealloc): Decrement frame_unwinders reference count. (pspy_initialize): Create frame_unwinders list. (pspy_get_frame_unwinders): New function. (pspy_set_frame_unwinders): Ditto. (pspy_getset): Add frame_unwinders attribute to gdb.Progspace. * python/py-unwind.c: New file. * python/python-internal.h (pspy_get_name_unwinders): New prototype. (objpy_get_frame_unwinders): New prototype. (gdbpy_initialize_unwind): New prototype. * python/python.c (gdbpy_apply_type_printers): Call gdbpy_initialize_unwind. gdb/doc/ChangeLog: * doc/python.texi (Writing a Frame Unwinder in Python): Add section. gdb/testsuite/ChangeLog: * gdb.python/py-unwind-maint.c: New file. * gdb.python/py-unwind-maint.exp: New test. * gdb.python/py-unwind-maint.py: New file. * gdb.python/py-unwind.c: New file. * gdb.python/py-unwind.exp: New test. * gdb.python/py-unwind.py: New test.
This commit is contained in:
parent
79730a3b26
commit
d11916aa89
21 changed files with 1808 additions and 2 deletions
|
@ -28,7 +28,7 @@ class _GdbFile (object):
|
|||
# These two are needed in Python 3
|
||||
encoding = "UTF-8"
|
||||
errors = "strict"
|
||||
|
||||
|
||||
def close(self):
|
||||
# Do nothing.
|
||||
return None
|
||||
|
@ -71,6 +71,42 @@ type_printers = []
|
|||
xmethods = []
|
||||
# Initial frame filters.
|
||||
frame_filters = {}
|
||||
# Initial frame unwinders.
|
||||
frame_unwinders = []
|
||||
|
||||
def execute_unwinders(pending_frame):
|
||||
"""Internal function called from GDB to execute all unwinders.
|
||||
|
||||
Runs each currently enabled unwinder until it finds the one that
|
||||
can unwind given frame.
|
||||
|
||||
Arguments:
|
||||
pending_frame: gdb.PendingFrame instance.
|
||||
Returns:
|
||||
gdb.UnwindInfo instance or None.
|
||||
"""
|
||||
for objfile in _gdb.objfiles():
|
||||
for unwinder in objfile.frame_unwinders:
|
||||
if unwinder.enabled:
|
||||
unwind_info = unwinder(pending_frame)
|
||||
if unwind_info is not None:
|
||||
return unwind_info
|
||||
|
||||
current_progspace = _gdb.current_progspace()
|
||||
for unwinder in current_progspace.frame_unwinders:
|
||||
if unwinder.enabled:
|
||||
unwind_info = unwinder(pending_frame)
|
||||
if unwind_info is not None:
|
||||
return unwind_info
|
||||
|
||||
for unwinder in frame_unwinders:
|
||||
if unwinder.enabled:
|
||||
unwind_info = unwinder(pending_frame)
|
||||
if unwind_info is not None:
|
||||
return unwind_info
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# Convenience variable to GDB's python directory
|
||||
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
|
198
gdb/python/lib/gdb/command/unwinders.py
Normal file
198
gdb/python/lib/gdb/command/unwinders.py
Normal file
|
@ -0,0 +1,198 @@
|
|||
# Unwinder commands.
|
||||
# Copyright 2015 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
import gdb
|
||||
import re
|
||||
|
||||
|
||||
def validate_regexp(exp, idstring):
|
||||
try:
|
||||
return re.compile(exp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp))
|
||||
|
||||
|
||||
def parse_unwinder_command_args(arg):
|
||||
"""Internal utility to parse unwinder command argv.
|
||||
|
||||
Arguments:
|
||||
arg: The arguments to the command. The format is:
|
||||
[locus-regexp [name-regexp]]
|
||||
|
||||
Returns:
|
||||
A 2-tuple of compiled regular expressions.
|
||||
|
||||
Raises:
|
||||
SyntaxError: an error processing ARG
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg)
|
||||
argc = len(argv)
|
||||
if argc > 2:
|
||||
raise SyntaxError("Too many arguments.")
|
||||
locus_regexp = ""
|
||||
name_regexp = ""
|
||||
if argc >= 1:
|
||||
locus_regexp = argv[0]
|
||||
if argc >= 2:
|
||||
name_regexp = argv[1]
|
||||
return (validate_regexp(locus_regexp, "locus"),
|
||||
validate_regexp(name_regexp, "unwinder"))
|
||||
|
||||
|
||||
class InfoUnwinder(gdb.Command):
|
||||
"""GDB command to list unwinders.
|
||||
|
||||
Usage: info unwinder [locus-regexp [name-regexp]]
|
||||
|
||||
LOCUS-REGEXP is a regular expression matching the location of the
|
||||
unwinder. If it is omitted, all registered unwinders from all
|
||||
loci are listed. A locus can be 'global', 'progspace' to list
|
||||
the unwinders from the current progspace, or a regular expression
|
||||
matching filenames of objfiles.
|
||||
|
||||
NAME-REGEXP is a regular expression to filter unwinder names. If
|
||||
this omitted for a specified locus, then all registered unwinders
|
||||
in the locus are listed.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(InfoUnwinder, self).__init__("info unwinder",
|
||||
gdb.COMMAND_STACK)
|
||||
|
||||
def list_unwinders(self, title, unwinders, name_re):
|
||||
"""Lists the unwinders whose name matches regexp.
|
||||
|
||||
Arguments:
|
||||
title: The line to print before the list.
|
||||
unwinders: The list of the unwinders.
|
||||
name_re: unwinder name filter.
|
||||
"""
|
||||
if not unwinders:
|
||||
return
|
||||
print title
|
||||
for unwinder in unwinders:
|
||||
if name_re.match(unwinder.name):
|
||||
print(" %s%s" % (unwinder.name,
|
||||
"" if unwinder.enabled else " [disabled]"))
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
locus_re, name_re = parse_unwinder_command_args(arg)
|
||||
if locus_re.match("global"):
|
||||
self.list_unwinders("Global:", gdb.frame_unwinders,
|
||||
name_re)
|
||||
if locus_re.match("progspace"):
|
||||
cp = gdb.current_progspace()
|
||||
self.list_unwinders("Progspace %s:" % cp.filename,
|
||||
cp.frame_unwinders, name_re)
|
||||
for objfile in gdb.objfiles():
|
||||
if locus_re.match(objfile.filename):
|
||||
self.list_unwinders("Objfile %s:" % objfile.filename,
|
||||
objfile.frame_unwinders, name_re)
|
||||
|
||||
|
||||
def do_enable_unwinder1(unwinders, name_re, flag):
|
||||
"""Enable/disable unwinders whose names match given regex.
|
||||
|
||||
Arguments:
|
||||
unwinders: The list of unwinders.
|
||||
name_re: Unwinder name filter.
|
||||
flag: Enable/disable.
|
||||
|
||||
Returns:
|
||||
The number of unwinders affected.
|
||||
"""
|
||||
total = 0
|
||||
for unwinder in unwinders:
|
||||
if name_re.match(unwinder.name):
|
||||
unwinder.enabled = flag
|
||||
total += 1
|
||||
return total
|
||||
|
||||
|
||||
def do_enable_unwinder(arg, flag):
|
||||
"""Enable/disable unwinder(s)."""
|
||||
(locus_re, name_re) = parse_unwinder_command_args(arg)
|
||||
total = 0
|
||||
if locus_re.match("global"):
|
||||
total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag)
|
||||
if locus_re.match("progspace"):
|
||||
total += do_enable_unwinder1(gdb.current_progspace().frame_unwinders,
|
||||
name_re, flag)
|
||||
for objfile in gdb.objfiles():
|
||||
if locus_re.match(objfile.filename):
|
||||
total += do_enable_unwinder1(objfile.frame_unwinders, name_re,
|
||||
flag)
|
||||
print("%d unwinder%s %s" % (total, "" if total == 1 else "s",
|
||||
"enabled" if flag else "disabled"))
|
||||
|
||||
|
||||
class EnableUnwinder(gdb.Command):
|
||||
"""GDB command to enable unwinders.
|
||||
|
||||
Usage: enable unwinder [locus-regexp [name-regexp]]
|
||||
|
||||
LOCUS-REGEXP is a regular expression specifying the unwinders to
|
||||
enable. It can 'global', 'progspace', or the name of an objfile
|
||||
within that progspace.
|
||||
|
||||
NAME_REGEXP is a regular expression to filter unwinder names. If
|
||||
this omitted for a specified locus, then all registered unwinders
|
||||
in the locus are affected.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(EnableUnwinder, self).__init__("enable unwinder",
|
||||
gdb.COMMAND_STACK)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_unwinder(arg, True)
|
||||
|
||||
|
||||
class DisableUnwinder(gdb.Command):
|
||||
"""GDB command to disable the specified unwinder.
|
||||
|
||||
Usage: disable unwinder [locus-regexp [name-regexp]]
|
||||
|
||||
LOCUS-REGEXP is a regular expression specifying the unwinders to
|
||||
disable. It can 'global', 'progspace', or the name of an objfile
|
||||
within that progspace.
|
||||
|
||||
NAME_REGEXP is a regular expression to filter unwinder names. If
|
||||
this omitted for a specified locus, then all registered unwinders
|
||||
in the locus are affected.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(DisableUnwinder, self).__init__("disable unwinder",
|
||||
gdb.COMMAND_STACK)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_unwinder(arg, False)
|
||||
|
||||
|
||||
def register_unwinder_commands():
|
||||
"""Installs the unwinder commands."""
|
||||
InfoUnwinder()
|
||||
EnableUnwinder()
|
||||
DisableUnwinder()
|
||||
|
||||
|
||||
register_unwinder_commands()
|
94
gdb/python/lib/gdb/unwinder.py
Normal file
94
gdb/python/lib/gdb/unwinder.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
# Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
"""Unwinder class and register_unwinder function."""
|
||||
|
||||
import gdb
|
||||
|
||||
|
||||
class Unwinder(object):
|
||||
"""Base class (or a template) for frame unwinders written in Python.
|
||||
|
||||
An unwinder has a single method __call__ and the attributes
|
||||
described below.
|
||||
|
||||
Attributes:
|
||||
name: The name of the unwinder.
|
||||
enabled: A boolean indicating whether the unwinder is enabled.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
name: An identifying name for the unwinder.
|
||||
"""
|
||||
self.name = name
|
||||
self.enabled = True
|
||||
|
||||
def __call__(self, pending_frame):
|
||||
"""GDB calls this method to unwind a frame.
|
||||
|
||||
Arguments:
|
||||
pending_frame: gdb.PendingFrame instance.
|
||||
|
||||
Returns:
|
||||
gdb.UnwindInfo instance.
|
||||
"""
|
||||
raise NotImplementedError("Unwinder __call__.")
|
||||
|
||||
|
||||
def register_unwinder(locus, unwinder, replace=False):
|
||||
"""Register unwinder in given locus.
|
||||
|
||||
The unwinder is prepended to the locus's unwinders list. Unwinder
|
||||
name should be unique.
|
||||
|
||||
Arguments:
|
||||
locus: Either an objfile, progspace, or None (in which case
|
||||
the unwinder is registered globally).
|
||||
unwinder: An object of a gdb.Unwinder subclass
|
||||
replace: If True, replaces existing unwinder with the same name.
|
||||
Otherwise, raises exception if unwinder with the same
|
||||
name already exists.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
|
||||
Raises:
|
||||
RuntimeError: Unwinder name is not unique
|
||||
TypeError: Bad locus type
|
||||
"""
|
||||
if locus is None:
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering global %s unwinder ...\n" % unwinder.name)
|
||||
locus = gdb
|
||||
elif isinstance(locus, gdb.Objfile) or isinstance(locus, gdb.Progspace):
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering %s unwinder for %s ...\n" %
|
||||
(unwinder.name, locus.filename))
|
||||
else:
|
||||
raise TypeError("locus should be gdb.Objfile or gdb.Progspace or None")
|
||||
|
||||
i = 0
|
||||
for needle in locus.frame_unwinders:
|
||||
if needle.name == unwinder.name:
|
||||
if replace:
|
||||
del locus.frame_unwinders[i]
|
||||
else:
|
||||
raise RuntimeError("Unwinder %s already exists." %
|
||||
unwinder.name)
|
||||
i += 1
|
||||
locus.frame_unwinders.insert(0, unwinder)
|
|
@ -42,6 +42,10 @@ typedef struct
|
|||
|
||||
/* The frame filter list of functions. */
|
||||
PyObject *frame_filters;
|
||||
|
||||
/* The list of frame unwinders. */
|
||||
PyObject *frame_unwinders;
|
||||
|
||||
/* The type-printer list. */
|
||||
PyObject *type_printers;
|
||||
|
||||
|
@ -184,6 +188,7 @@ objfpy_dealloc (PyObject *o)
|
|||
Py_XDECREF (self->dict);
|
||||
Py_XDECREF (self->printers);
|
||||
Py_XDECREF (self->frame_filters);
|
||||
Py_XDECREF (self->frame_unwinders);
|
||||
Py_XDECREF (self->type_printers);
|
||||
Py_XDECREF (self->xmethods);
|
||||
Py_TYPE (self)->tp_free (self);
|
||||
|
@ -206,6 +211,10 @@ objfpy_initialize (objfile_object *self)
|
|||
if (self->frame_filters == NULL)
|
||||
return 0;
|
||||
|
||||
self->frame_unwinders = PyList_New (0);
|
||||
if (self->frame_unwinders == NULL)
|
||||
return 0;
|
||||
|
||||
self->type_printers = PyList_New (0);
|
||||
if (self->type_printers == NULL)
|
||||
return 0;
|
||||
|
@ -313,6 +322,48 @@ objfpy_set_frame_filters (PyObject *o, PyObject *filters, void *ignore)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return the frame unwinders attribute for this object file. */
|
||||
|
||||
PyObject *
|
||||
objfpy_get_frame_unwinders (PyObject *o, void *ignore)
|
||||
{
|
||||
objfile_object *self = (objfile_object *) o;
|
||||
|
||||
Py_INCREF (self->frame_unwinders);
|
||||
return self->frame_unwinders;
|
||||
}
|
||||
|
||||
/* Set this object file's frame unwinders list to UNWINDERS. */
|
||||
|
||||
static int
|
||||
objfpy_set_frame_unwinders (PyObject *o, PyObject *unwinders, void *ignore)
|
||||
{
|
||||
PyObject *tmp;
|
||||
objfile_object *self = (objfile_object *) o;
|
||||
|
||||
if (!unwinders)
|
||||
{
|
||||
PyErr_SetString (PyExc_TypeError,
|
||||
_("Cannot delete the frame unwinders attribute."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyList_Check (unwinders))
|
||||
{
|
||||
PyErr_SetString (PyExc_TypeError,
|
||||
_("The frame_unwinders attribute must be a list."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Take care in case the LHS and RHS are related somehow. */
|
||||
tmp = self->frame_unwinders;
|
||||
Py_INCREF (unwinders);
|
||||
self->frame_unwinders = unwinders;
|
||||
Py_XDECREF (tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the 'type_printers' attribute. */
|
||||
|
||||
static PyObject *
|
||||
|
@ -651,6 +702,8 @@ static PyGetSetDef objfile_getset[] =
|
|||
"Pretty printers.", NULL },
|
||||
{ "frame_filters", objfpy_get_frame_filters,
|
||||
objfpy_set_frame_filters, "Frame Filters.", NULL },
|
||||
{ "frame_unwinders", objfpy_get_frame_unwinders,
|
||||
objfpy_set_frame_unwinders, "Frame Unwinders", NULL },
|
||||
{ "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
|
||||
"Type printers.", NULL },
|
||||
{ "xmethods", objfpy_get_xmethods, NULL,
|
||||
|
|
|
@ -41,6 +41,10 @@ typedef struct
|
|||
|
||||
/* The frame filter list of functions. */
|
||||
PyObject *frame_filters;
|
||||
|
||||
/* The frame unwinder list. */
|
||||
PyObject *frame_unwinders;
|
||||
|
||||
/* The type-printer list. */
|
||||
PyObject *type_printers;
|
||||
|
||||
|
@ -82,6 +86,7 @@ pspy_dealloc (PyObject *self)
|
|||
Py_XDECREF (ps_self->dict);
|
||||
Py_XDECREF (ps_self->printers);
|
||||
Py_XDECREF (ps_self->frame_filters);
|
||||
Py_XDECREF (ps_self->frame_unwinders);
|
||||
Py_XDECREF (ps_self->type_printers);
|
||||
Py_XDECREF (ps_self->xmethods);
|
||||
Py_TYPE (self)->tp_free (self);
|
||||
|
@ -104,6 +109,10 @@ pspy_initialize (pspace_object *self)
|
|||
if (self->frame_filters == NULL)
|
||||
return 0;
|
||||
|
||||
self->frame_unwinders = PyList_New (0);
|
||||
if (self->frame_unwinders == NULL)
|
||||
return 0;
|
||||
|
||||
self->type_printers = PyList_New (0);
|
||||
if (self->type_printers == NULL)
|
||||
return 0;
|
||||
|
@ -211,6 +220,48 @@ pspy_set_frame_filters (PyObject *o, PyObject *frame, void *ignore)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return the list of the frame unwinders for this program space. */
|
||||
|
||||
PyObject *
|
||||
pspy_get_frame_unwinders (PyObject *o, void *ignore)
|
||||
{
|
||||
pspace_object *self = (pspace_object *) o;
|
||||
|
||||
Py_INCREF (self->frame_unwinders);
|
||||
return self->frame_unwinders;
|
||||
}
|
||||
|
||||
/* Set this program space's list of the unwinders to UNWINDERS. */
|
||||
|
||||
static int
|
||||
pspy_set_frame_unwinders (PyObject *o, PyObject *unwinders, void *ignore)
|
||||
{
|
||||
PyObject *tmp;
|
||||
pspace_object *self = (pspace_object *) o;
|
||||
|
||||
if (!unwinders)
|
||||
{
|
||||
PyErr_SetString (PyExc_TypeError,
|
||||
"cannot delete the frame unwinders list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyList_Check (unwinders))
|
||||
{
|
||||
PyErr_SetString (PyExc_TypeError,
|
||||
"the frame unwinders attribute must be a list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Take care in case the LHS and RHS are related somehow. */
|
||||
tmp = self->frame_unwinders;
|
||||
Py_INCREF (unwinders);
|
||||
self->frame_unwinders = unwinders;
|
||||
Py_XDECREF (tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the 'type_printers' attribute. */
|
||||
|
||||
static PyObject *
|
||||
|
@ -345,6 +396,8 @@ static PyGetSetDef pspace_getset[] =
|
|||
"Pretty printers.", NULL },
|
||||
{ "frame_filters", pspy_get_frame_filters, pspy_set_frame_filters,
|
||||
"Frame filters.", NULL },
|
||||
{ "frame_unwinders", pspy_get_frame_unwinders, pspy_set_frame_unwinders,
|
||||
"Frame unwinders.", NULL },
|
||||
{ "type_printers", pspy_get_type_printers, pspy_set_type_printers,
|
||||
"Type printers.", NULL },
|
||||
{ "xmethods", pspy_get_xmethods, NULL,
|
||||
|
|
788
gdb/python/py-unwind.c
Normal file
788
gdb/python/py-unwind.c
Normal file
|
@ -0,0 +1,788 @@
|
|||
/* Python frame unwinder interface.
|
||||
|
||||
Copyright (C) 2015 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 "observer.h"
|
||||
#include "python-internal.h"
|
||||
#include "regcache.h"
|
||||
#include "valprint.h"
|
||||
#include "user-regs.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. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int number;
|
||||
PyObject *value;
|
||||
} saved_reg;
|
||||
DEF_VEC_O (saved_reg);
|
||||
|
||||
/* 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. */
|
||||
VEC (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;
|
||||
|
||||
struct reg_info
|
||||
{
|
||||
/* Register number. */
|
||||
int number;
|
||||
|
||||
/* Register data bytes pointer. */
|
||||
gdb_byte data[MAX_REGISTER_SIZE];
|
||||
} reg[];
|
||||
} cached_frame_info;
|
||||
|
||||
static PyTypeObject pending_frame_object_type
|
||||
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pending_frame_object");
|
||||
|
||||
static 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))
|
||||
{
|
||||
const 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,
|
||||
strlen (reg_name));
|
||||
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. */
|
||||
|
||||
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 (except, RETURN_MASK_ALL)
|
||||
{
|
||||
gdbpy_convert_exception (except);
|
||||
}
|
||||
END_CATCH
|
||||
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))
|
||||
{
|
||||
PyObject *pyo_value = PyObject_GetAttrString (pyo, attr_name);
|
||||
struct value *value;
|
||||
|
||||
if (pyo_value != NULL && pyo_value != Py_None)
|
||||
{
|
||||
rc = pyuw_value_obj_to_pointer (pyo_value, addr);
|
||||
if (!rc)
|
||||
PyErr_Format (
|
||||
PyExc_ValueError,
|
||||
_("The value of the '%s' attribute is not a pointer."),
|
||||
attr_name);
|
||||
}
|
||||
Py_XDECREF (pyo_value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Called by the Python interpreter to obtain string representation
|
||||
of the UnwindInfo object. */
|
||||
|
||||
static PyObject *
|
||||
unwind_infopy_str (PyObject *self)
|
||||
{
|
||||
struct ui_file *strfile = mem_fileopen ();
|
||||
unwind_info_object *unwind_info = (unwind_info_object *) self;
|
||||
pending_frame_object *pending_frame
|
||||
= (pending_frame_object *) (unwind_info->pending_frame);
|
||||
PyObject *result;
|
||||
|
||||
fprintf_unfiltered (strfile, "Frame ID: ");
|
||||
fprint_frame_id (strfile, unwind_info->frame_id);
|
||||
{
|
||||
char *sep = "";
|
||||
int i;
|
||||
struct value_print_options opts;
|
||||
saved_reg *reg;
|
||||
|
||||
get_user_print_options (&opts);
|
||||
fprintf_unfiltered (strfile, "\nSaved registers: (");
|
||||
for (i = 0;
|
||||
i < VEC_iterate (saved_reg, unwind_info->saved_regs, i, reg);
|
||||
i++)
|
||||
{
|
||||
struct value *value = value_object_to_value (reg->value);
|
||||
|
||||
fprintf_unfiltered (strfile, "%s(%d, ", sep, reg->number);
|
||||
if (value != NULL)
|
||||
{
|
||||
TRY
|
||||
{
|
||||
value_print (value, strfile, &opts);
|
||||
fprintf_unfiltered (strfile, ")");
|
||||
}
|
||||
CATCH (except, RETURN_MASK_ALL)
|
||||
{
|
||||
GDB_PY_HANDLE_EXCEPTION (except);
|
||||
}
|
||||
END_CATCH
|
||||
}
|
||||
else
|
||||
fprintf_unfiltered (strfile, "<BAD>)");
|
||||
sep = ", ";
|
||||
}
|
||||
fprintf_unfiltered (strfile, ")");
|
||||
}
|
||||
{
|
||||
char *s = ui_file_xstrdup (strfile, NULL);
|
||||
|
||||
result = PyString_FromString (s);
|
||||
xfree (s);
|
||||
}
|
||||
ui_file_delete (strfile);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 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 = VEC_alloc (saved_reg, 4);
|
||||
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 (!pyuw_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;
|
||||
}
|
||||
}
|
||||
{
|
||||
int i;
|
||||
saved_reg *reg;
|
||||
|
||||
for (i = 0; VEC_iterate (saved_reg, unwind_info->saved_regs, i, reg); i++)
|
||||
{
|
||||
if (regnum == reg->number)
|
||||
{
|
||||
Py_DECREF (reg->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reg == NULL)
|
||||
{
|
||||
reg = VEC_safe_push (saved_reg, unwind_info->saved_regs, NULL);
|
||||
reg->number = regnum;
|
||||
}
|
||||
Py_INCREF (pyo_reg_value);
|
||||
reg->value = pyo_reg_value;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* UnwindInfo cleanup. */
|
||||
|
||||
static void
|
||||
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);
|
||||
for (i = 0; VEC_iterate (saved_reg, unwind_info->saved_regs, i, reg); i++)
|
||||
Py_DECREF (reg->value);
|
||||
VEC_free (saved_reg, 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 (except, RETURN_MASK_ALL)
|
||||
{
|
||||
GDB_PY_HANDLE_EXCEPTION (except);
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
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 (!pyuw_parse_register_id (pending_frame->gdbarch, pyo_reg_id, ®num))
|
||||
{
|
||||
PyErr_SetString (PyExc_ValueError, "Bad register");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRY
|
||||
{
|
||||
val = get_frame_register_value (pending_frame->frame_info, regnum);
|
||||
if (val == NULL)
|
||||
PyErr_Format (PyExc_ValueError,
|
||||
"Cannot read register %d from frame.",
|
||||
regnum);
|
||||
}
|
||||
CATCH (except, RETURN_MASK_ALL)
|
||||
{
|
||||
GDB_PY_HANDLE_EXCEPTION (except);
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/* Invalidate PendingFrame instance. */
|
||||
|
||||
static void
|
||||
pending_frame_invalidate (void *pyo_pending_frame)
|
||||
{
|
||||
if (pyo_pending_frame != NULL)
|
||||
((pending_frame_object *) pyo_pending_frame)->frame_info = NULL;
|
||||
}
|
||||
|
||||
/* 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 = *cache_ptr;
|
||||
struct reg_info *reg_info = cached_frame->reg;
|
||||
struct reg_info *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->number)
|
||||
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);
|
||||
struct cleanup *cleanups = ensure_python_env (gdbarch, current_language);
|
||||
PyObject *pyo_execute;
|
||||
PyObject *pyo_pending_frame;
|
||||
PyObject *pyo_unwind_info;
|
||||
cached_frame_info *cached_frame;
|
||||
|
||||
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. */
|
||||
pyo_pending_frame = (PyObject *) PyObject_New (pending_frame_object,
|
||||
&pending_frame_object_type);
|
||||
if (pyo_pending_frame == NULL)
|
||||
goto error;
|
||||
((pending_frame_object *) pyo_pending_frame)->gdbarch = gdbarch;
|
||||
((pending_frame_object *) pyo_pending_frame)->frame_info = this_frame;
|
||||
make_cleanup (pending_frame_invalidate, (void *) pyo_pending_frame);
|
||||
make_cleanup_py_decref (pyo_pending_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");
|
||||
goto error;
|
||||
}
|
||||
pyo_execute = PyObject_GetAttrString (gdb_python_module, "execute_unwinders");
|
||||
if (pyo_execute == NULL)
|
||||
goto error;
|
||||
make_cleanup_py_decref (pyo_execute);
|
||||
pyo_unwind_info
|
||||
= PyObject_CallFunctionObjArgs (pyo_execute, pyo_pending_frame, NULL);
|
||||
if (pyo_unwind_info == NULL)
|
||||
goto error;
|
||||
make_cleanup_py_decref (pyo_unwind_info);
|
||||
if (pyo_unwind_info == Py_None)
|
||||
goto cannot_unwind;
|
||||
|
||||
/* Received UnwindInfo, cache data. */
|
||||
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;
|
||||
int reg_count = VEC_length (saved_reg, unwind_info->saved_regs);
|
||||
saved_reg *reg;
|
||||
int i;
|
||||
|
||||
cached_frame = 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 (i = 0; VEC_iterate (saved_reg, unwind_info->saved_regs, i, reg); i++)
|
||||
{
|
||||
struct value *value = value_object_to_value (reg->value);
|
||||
size_t data_size = register_size (gdbarch, reg->number);
|
||||
|
||||
cached_frame->reg[i].number = reg->number;
|
||||
|
||||
/* `value' validation was done before, just assert. */
|
||||
gdb_assert (value != NULL);
|
||||
gdb_assert (data_size == TYPE_LENGTH (value_type (value)));
|
||||
gdb_assert (data_size <= MAX_REGISTER_SIZE);
|
||||
|
||||
memcpy (cached_frame->reg[i].data, value_contents (value), data_size);
|
||||
}
|
||||
}
|
||||
|
||||
*cache_ptr = cached_frame;
|
||||
do_cleanups (cleanups);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
gdbpy_print_stack ();
|
||||
/* Fallthrough. */
|
||||
cannot_unwind:
|
||||
do_cleanups (cleanups);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Frame cache release shim. */
|
||||
|
||||
static void
|
||||
pyuw_dealloc_cache (struct frame_info *this_frame, void *cache)
|
||||
{
|
||||
TRACE_PY_UNWIND (3, "%s: enter", __FUNCTION__);
|
||||
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 =
|
||||
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 = (void *) 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);
|
||||
observer_attach_architecture_changed (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." },
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static 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 */
|
||||
};
|
||||
|
||||
static 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 */
|
||||
};
|
|
@ -391,12 +391,14 @@ PyObject *pspace_to_pspace_object (struct program_space *)
|
|||
CPYCHECKER_RETURNS_BORROWED_REF;
|
||||
PyObject *pspy_get_printers (PyObject *, void *);
|
||||
PyObject *pspy_get_frame_filters (PyObject *, void *);
|
||||
PyObject *pspy_get_frame_unwinders (PyObject *, void *);
|
||||
PyObject *pspy_get_xmethods (PyObject *, void *);
|
||||
|
||||
PyObject *objfile_to_objfile_object (struct objfile *)
|
||||
CPYCHECKER_RETURNS_BORROWED_REF;
|
||||
PyObject *objfpy_get_printers (PyObject *, void *);
|
||||
PyObject *objfpy_get_frame_filters (PyObject *, void *);
|
||||
PyObject *objfpy_get_frame_unwinders (PyObject *, void *);
|
||||
PyObject *objfpy_get_xmethods (PyObject *, void *);
|
||||
PyObject *gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw);
|
||||
|
||||
|
@ -491,6 +493,8 @@ int gdbpy_initialize_arch (void)
|
|||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_xmethods (void)
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_unwind (void)
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
|
||||
struct cleanup *make_cleanup_py_decref (PyObject *py);
|
||||
struct cleanup *make_cleanup_py_xdecref (PyObject *py);
|
||||
|
|
|
@ -1821,7 +1821,8 @@ message == an error message without a stack will be printed."),
|
|||
|| gdbpy_initialize_new_objfile_event () < 0
|
||||
|| gdbpy_initialize_clear_objfiles_event () < 0
|
||||
|| gdbpy_initialize_arch () < 0
|
||||
|| gdbpy_initialize_xmethods () < 0)
|
||||
|| gdbpy_initialize_xmethods () < 0
|
||||
|| gdbpy_initialize_unwind () < 0)
|
||||
goto fail;
|
||||
|
||||
gdbpy_to_string_cst = PyString_FromString ("to_string");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue