Age | Commit message (Collapse) | Author | Files | Lines |
|
Change-Id: I849d10d69c254342bf01e955ffe62a2b60f9de4b
|
|
Update the two gdb.PendingFrame methods gdb.PendingFrame.read_register
and gdb.PendingFrame.create_unwind_info to accept keyword arguments.
There's no huge benefit for making this change, both of these methods
only take a single argument, so it is (maybe) less likely that a user
will take advantage of the keyword arguments in these cases, but I
think it's nice to be consistent, and I don't see any particular draw
backs to making this change.
For PendingFrame.read_register I've changed the argument name from
'reg' to 'register' in the documentation and used 'register' as the
argument name in GDB. My preference for APIs is to use full words
where possible, and given we didn't support named arguments before
this change should not break any existing code.
There should be no user visible changes (for existing code) after this
commit.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Update gdb.UnwindInfo.add_saved_register to accept named keyword
arguments.
As part of this update we now use gdb_PyArg_ParseTupleAndKeywords
instead of PyArg_UnpackTuple to parse the function arguments.
By switching to gdb_PyArg_ParseTupleAndKeywords, we can now use 'O!'
as the argument format for the function's value argument. This means
that we can check the argument type (is gdb.Value) as part of the
argument processing rather than manually performing the check later in
the function. One result of this is that we now get a better error
message (at least, I think so). Previously we would get something
like:
ValueError: Bad register value
Now we get:
TypeError: argument 2 must be gdb.Value, not XXXX
It's unfortunate that the exception type changed, but I think the new
exception type actually makes more sense.
My preference for argument names is to use full words where that's not
too excessive. As such, I've updated the name of the argument from
'reg' to 'register' in the documentation, which is the argument name
I've made GDB look for here.
For existing unwinder code that doesn't throw any exceptions nothing
should change with this commit. It is possible that a user has some
code that throws and catches the ValueError, and this code will break
after this commit, but I think this is going to be sufficiently rare
that we can take the risk here.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
When writing an unwinder it is necessary to create a new class to act
as a frame-id. This new class is almost certainly just going to set a
'sp' and 'pc' attribute within the instance.
This commit adds a little helper class gdb.unwinder.FrameId that does
this job. Users can make use of this to avoid having to write out
standard boilerplate code any time they write an unwinder.
Of course, if the user wants their FrameId class to be more
complicated in some way, then they can still write their own class,
just like they could before.
I've simplified the example code in the documentation to now use the
new helper class, and I've also made use of this helper within the
testsuite.
Any existing user code will continue to work just as it did before
after this change.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Currently when creating a gdb.UnwindInfo object a user must call
gdb.PendingFrame.create_unwind_info and pass a frame-id object.
The frame-id object should have at least a 'sp' attribute, and
probably a 'pc' attribute too (it can also, in some cases have a
'special' attribute).
Currently all of these frame-id attributes need to be gdb.Value
objects, but the only reason for that requirement is that we have some
code in py-unwind.c that only handles gdb.Value objects.
If instead we switch to using get_addr_from_python in py-utils.c then
we will support both gdb.Value objects and also raw numbers, which
might make things simpler in some cases.
So, I started rewriting pyuw_object_attribute_to_pointer (in
py-unwind.c) to use get_addr_from_python. However, while looking at
the code I noticed a problem.
The pyuw_object_attribute_to_pointer function returns a boolean flag,
if everything goes OK we return true, but we return false in two
cases, (1) when the attribute is not present, which might be
acceptable, or might be an error, and (2) when we get an error trying
to extract the attribute value, in which case a Python error will have
been set.
Now in pending_framepy_create_unwind_info we have this code:
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp))
{
PyErr_SetString (PyExc_ValueError,
_("frame_id should have 'sp' attribute."));
return NULL;
}
Notice how we always set an error. This will override any error that
is already set.
So, if you create a frame-id object that has an 'sp' attribute, but
the attribute is not a gdb.Value, then currently we fail to extract
the attribute value (it's not a gdb.Value) and set this error in
pyuw_object_attribute_to_pointer:
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);
Then we return to pending_framepy_create_unwind_info and immediately
override this error with the error about 'sp' being missing.
This all feels very confused.
Here's my proposed solution: pyuw_object_attribute_to_pointer will now
return a tri-state enum, with states OK, MISSING, or ERROR. The
meanings of these states are:
OK - Attribute exists and was extracted fine,
MISSING - Attribute doesn't exist, no Python error was set.
ERROR - Attribute does exist, but there was an error while
extracting it, a Python error was set.
We need to update pending_framepy_create_unwind_info, the only user of
pyuw_object_attribute_to_pointer, but now I think things are much
clearer. Errors from lower levels are not blindly overridden with the
generic meaningless error message, but we still get the "missing 'sp'
attribute" error when appropriate.
This change also includes the switch to get_addr_from_python which was
what started this whole journey.
For well behaving user code there should be no visible changes after
this commit.
For user code that hits an error, hopefully the new errors should be
more helpful in figuring out what's gone wrong.
Additionally, users can now use integers for the 'sp' and 'pc'
attributes in their frame-id objects if that is useful.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
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>
|
|
The gdb.Frame class has far more methods than gdb.PendingFrame. Given
that a PendingFrame hasn't yet been claimed by an unwinder, there is a
limit to which methods we can add to it, but many of the methods that
the Frame class has, the PendingFrame class could also support.
In this commit I've added those methods to PendingFrame that I believe
are safe.
In terms of implementation: if I was starting from scratch then I
would implement many of these (or most of these) as attributes rather
than methods. However, given both Frame and PendingFrame are just
different representation of a frame, I think there is value in keeping
the interface for the two classes the same. For this reason
everything here is a method -- that's what the Frame class does.
The new methods I've added are:
- gdb.PendingFrame.is_valid: Return True if the pending frame
object is valid.
- gdb.PendingFrame.name: Return the name for the frame's function,
or None.
- gdb.PendingFrame.pc: Return the $pc register value for this
frame.
- gdb.PendingFrame.language: Return a string containing the
language for this frame, or None.
- gdb.PendingFrame.find_sal: Return a gdb.Symtab_and_line object
for the current location within the pending frame, or None.
- gdb.PendingFrame.block: Return a gdb.Block for the current
pending frame, or None.
- gdb.PendingFrame.function: Return a gdb.Symbol for the current
pending frame, or None.
In every case I've just copied the implementation over from gdb.Frame
and cleaned the code slightly e.g. NULL to nullptr. Additionally each
function required a small update to reflect the PendingFrame type, but
that's pretty minor.
There are tests for all the new methods.
For more extensive testing, I added the following code to the file
gdb/python/lib/command/unwinders.py:
from gdb.unwinder import Unwinder
class TestUnwinder(Unwinder):
def __init__(self):
super().__init__("XXX_TestUnwinder_XXX")
def __call__(self,pending_frame):
lang = pending_frame.language()
try:
block = pending_frame.block()
assert isinstance(block, gdb.Block)
except RuntimeError as rte:
assert str(rte) == "Cannot locate block for frame."
function = pending_frame.function()
arch = pending_frame.architecture()
assert arch is None or isinstance(arch, gdb.Architecture)
name = pending_frame.name()
assert name is None or isinstance(name, str)
valid = pending_frame.is_valid()
pc = pending_frame.pc()
sal = pending_frame.find_sal()
assert sal is None or isinstance(sal, gdb.Symtab_and_line)
return None
gdb.unwinder.register_unwinder(None, TestUnwinder())
This registers a global unwinder that calls each of the new
PendingFrame methods and checks the result is of an acceptable type.
The unwinder never claims any frames though, so shouldn't change how
GDB actually behaves.
I then ran the testsuite. There was only a single regression, a test
that uses 'disable unwinder' and expects a single unwinder to be
disabled -- the extra unwinder is now disabled too, which changes the
test output. So I'm reasonably confident that the new methods are not
going to crash GDB.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit copies the pattern that is present in many other py-*.c
files: having a single macro to check that the Python object is still
valid.
This cleans up the code a little throughout the py-unwind.c file.
Some of the exception messages will change slightly with this commit,
though the type of the exceptions is still ValueError in all cases.
I started writing some tests for this change and immediately ran into
a problem: GDB would crash. It turns out that the PendingFrame
objects are not being marked as invalid!
In pyuw_sniffer where the pending frames are created, we make use of a
scoped_restore to invalidate the pending frame objects. However, this
only restores the pending_frame_object::frame_info field to its
previous value -- and it turns out we never actually give this field
an initial value, it's left undefined.
So, when the scoped_restore (called invalidate_frame) performs its
cleanup, it actually restores the frame_info field to an undefined
value. If this undefined value is not nullptr then any future
accesses to the PendingFrame object result in undefined behaviour and
most likely, a crash.
As part of this commit I now initialize the frame_info field, which
ensures all the new tests now pass.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit makes a few related changes to the gdb.unwinder.Unwinder
class attributes:
1. The 'name' attribute is now a read-only attribute. This prevents
user code from changing the name after registering the unwinder. It
seems very unlikely that any user is actually trying to do this in
the wild, so I'm not very worried that this will upset anyone,
2. We now validate that the name is a string in the
Unwinder.__init__ method, and throw an error if this is not the
case. Hopefully nobody was doing this in the wild. This should
make it easier to ensure the 'info unwinder' command shows sane
output (how to display a non-string name for an unwinder?),
3. The 'enabled' attribute is now implemented with a getter and
setter. In the setter we ensure that the new value is a boolean,
but the real important change is that we call
'gdb.invalidate_cached_frames()'. This means that the backtrace
will be updated if a user manually disables an unwinder (rather than
calling the 'disable unwinder' command). It is not unreasonable to
think that a user might register multiple unwinders (relating to
some project) and have one command that disables/enables all the
related unwinders. This command might operate by poking the enabled
attribute of each unwinder object directly, after this commit, this
would now work correctly.
There's tests for all the changes, and lots of documentation updates
that both cover the new changes, but also further improve (I think)
the general documentation for GDB's Unwinder API.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit is the result of running the gdb/copyright.py script,
which automated the update of the copyright year range for all
source files managed by the GDB project to be updated to include
year 2023.
|
|
I noticed that gdbpy_parse_register_id would assert if passed a Python
object of a type it was not expecting. The included test case shows
this crash. This patch fixes the problem and also changes
gdbpy_parse_register_id to be more "Python-like" -- it always ensures
the Python error is set when it fails, and the callers now simply
propagate the existing exception.
|
|
This commit brings all the changes made by running gdb/copyright.py
as per GDB's Start of New Year Procedure.
For the avoidance of doubt, all changes in this commits were
performed by the script.
|
|
Re-format all Python files using black [1] version 21.4b0. The goal is
that from now on, we keep all Python files formatted using black. And
that we never have to discuss formatting during review (for these files
at least) ever again.
One change is needed in gdb.python/py-prettyprint.exp, because it
matches the string representation of an exception, which shows source
code. So the change in formatting must be replicated in the expected
regexp.
To document our usage of black I plan on adding this to the "GDB Python
Coding Standards" wiki page [2]:
--8<--
All Python source files under the `gdb/` directory must be formatted
using black version 21.4b0.
This specific version can be installed using:
$ pip3 install 'black == 21.4b0'
All you need to do to re-format files is run `black <file/directory>`,
and black will re-format any Python file it finds in there. It runs
quite fast, so the simplest is to do:
$ black gdb/
from the top-level.
If you notice that black produces changes unrelated to your patch, it's
probably because someone forgot to run it before you. In this case,
don't include unrelated hunks in your patch. Push an obvious patch
fixing the formatting and rebase your work on top of that.
-->8--
Once this is merged, I plan on setting a up an `ignoreRevsFile`
config so that git-blame ignores this commit, as described here:
https://github.com/psf/black#migrating-your-code-style-without-ruining-git-blame
I also plan on working on a git commit hook (checked in the repo) to
automatically check the formatting of the Python files on commit.
[1] https://pypi.org/project/black/
[2] https://sourceware.org/gdb/wiki/Internals%20GDB-Python-Coding-Standards
gdb/ChangeLog:
* Re-format all Python files using black.
gdb/testsuite/ChangeLog:
* Re-format all Python files using black.
* gdb.python/py-prettyprint.exp (run_lang_tests): Adjust.
Change-Id: I28588a22c2406afd6bc2703774ddfff47cd61919
|
|
This commits the result of running gdb/copyright.py as per our Start
of New Year procedure...
gdb/ChangeLog
Update copyright year range in copyright header of all GDB files.
|
|
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.
|
|
It could be useful to determine the architecture of a frame being
unwound during the frame unwind process, that is, before we have a
gdb.Frame, but when we only have a gdb.PendingFrame.
The PendingFrame already has a pointer to the gdbarch internally, this
commit just exposes an 'architecture' method to Python, and has this
return a gdb.Architecture object (list gdb.Frame.architecture does).
gdb/ChangeLog:
* NEWS: Mention new Python API method.
* python/py-unwind.c (pending_framepy_architecture): New function.
(pending_frame_object_methods): Add architecture method.
gdb/testsuite/ChangeLog:
* gdb.python/py-unwind.py (TestUnwinder::__call__): Add test for
gdb.PendingFrame.architecture method.
gdb/doc/ChangeLog:
* python.texi (Unwinding Frames in Python): Document
PendingFrame.architecture method.
|
|
gdb/ChangeLog:
Update copyright year range in all GDB files.
|
|
This commit applies all changes made after running the gdb/copyright.py
script.
Note that one file was flagged by the script, due to an invalid
copyright header
(gdb/unittests/basic_string_view/element_access/char/empty.cc).
As the file was copied from GCC's libstdc++-v3 testsuite, this commit
leaves this file untouched for the time being; a patch to fix the header
was sent to gcc-patches first.
gdb/ChangeLog:
Update copyright year range in all GDB files.
|
|
gdb/ChangeLog:
Update copyright year range in all GDB files
|
|
This applies the second part of GDB's End of Year Procedure, which
updates the copyright year range in all of GDB's files.
gdb/ChangeLog:
Update copyright year range in all GDB files.
|
|
gdb/ChangeLog:
Update year range in copyright notice of all files.
|
|
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.
|