gdb/python: Add new gdb.unwinder.FrameId class
authorAndrew Burgess <aburgess@redhat.com>
Fri, 10 Mar 2023 12:29:58 +0000 (12:29 +0000)
committerAndrew Burgess <aburgess@redhat.com>
Thu, 30 Mar 2023 09:25:46 +0000 (10:25 +0100)
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>
gdb/NEWS
gdb/doc/python.texi
gdb/python/lib/gdb/unwinder.py
gdb/testsuite/gdb.python/py-unwind.py

index 043847f6ed63a32116903acd020a3671f99b3a79..ba5ae520112efa8603a04daa092fed9203966dcd 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -144,6 +144,11 @@ show always-read-ctf
      now use either an integer or a gdb.Value object for each of its
      'sp', 'pc', and 'special' attributes.
 
+  ** A new class gdb.unwinder.FrameId has been added.  Instances of
+     this class are constructed with 'sp' (stack-pointer) and 'pc'
+     (program-counter) values, and can be used as the frame-id when
+     calling gdb.PendingFrame.create_unwind_info.
+
 *** Changes in GDB 13
 
 * MI version 1 is deprecated, and will be removed in GDB 14.
index b41432ae3cfa3f4c3e72a7e78a56e556bee06776..c74d586ef39c95f095f45c82c2e613f697e99162 100644 (file)
@@ -2782,6 +2782,7 @@ pointer, pointer-to-function, floating point or vector types.
 It also provides a factory method to create a @code{gdb.UnwindInfo}
 instance to be returned to @value{GDBN}:
 
+@anchor{gdb.PendingFrame.create_unwind_info}
 @defun PendingFrame.create_unwind_info (frame_id)
 Returns a new @code{gdb.UnwindInfo} instance identified by given
 @var{frame_id}.  The @var{frame_id} is used internally by @value{GDBN}
@@ -2818,6 +2819,10 @@ this.
 Each attribute value should either be an instance of @code{gdb.Value}
 or an integer.
 
+A helper class is provided in the @code{gdb.unwinder} module that can
+be used to represent a frame-id
+(@pxref{gdb.unwinder.FrameId}).
+
 @end defun
 
 @defun PendingFrame.architecture ()
@@ -2886,7 +2891,7 @@ values see @ref{gdbpy_frame_read_register,,Frame.read_register}.
 @subheading The @code{gdb.unwinder} Module
 
 @value{GDBN} comes with a @code{gdb.unwinder} module which contains
-the following class:
+the following classes:
 
 @deftp {class} gdb.unwinder.Unwinder
 The @code{Unwinder} class is a base class from which user created
@@ -2910,6 +2915,40 @@ unwinder is enabled, and will be used by @value{GDBN}.  When
 @end defvar
 @end deftp
 
+@anchor{gdb.unwinder.FrameId}
+@deftp {class} gdb.unwinder.FrameId
+This is a class suitable for being used as the frame-id when calling
+@code{gdb.PendingFrame.create_unwind_info}.  It is not required to use
+this class, any class with the required attribute
+(@pxref{gdb.PendingFrame.create_unwind_info}) will be accepted, but in
+most cases this class will be sufficient.
+
+@code{gdb.unwinder.FrameId} has the following method:
+
+@defun gdb.unwinder.FrameId.__init__(@var{sp}, @var{pc}, @var{special} = @code{None})
+The @var{sp} and @var{pc} arguments are required and should be either
+a @code{gdb.Value} object, or an integer.
+
+The @var{special} argument is optional; if specified, it should be a
+@code{gdb.Value} object, or an integer.
+@end defun
+
+@code{gdb.unwinder.FrameId} has the following read-only attributes:
+
+@defvar gdb.unwinder.sp
+The @var{sp} value passed to the constructor.
+@end defvar
+
+@defvar gdb.unwinder.pc
+The @var{pc} value passed to the constructor.
+@end defvar
+
+@defvar gdb.unwinder.special
+The @var{special} value passed to the constructor, or @code{None} if
+no such value was passed.
+@end defvar
+@end deftp
+
 @subheading Registering an Unwinder
 
 Object files and program spaces can have unwinders registered with
@@ -2941,13 +2980,7 @@ builtin to @value{GDBN}.
 Here is an example of how to structure a user created unwinder:
 
 @smallexample
-from gdb.unwinder import Unwinder
-
-class FrameId(object):
-    def __init__(self, sp, pc):
-        self.sp = sp
-        self.pc = pc
-
+from gdb.unwinder import Unwinder, FrameId
 
 class MyUnwinder(Unwinder):
     def __init__(self):
index 1303245c05457629b67d908a6049c490fa512557..140b84d33748def6fc28993aba8fee8fabb955f7 100644 (file)
@@ -69,6 +69,32 @@ class Unwinder(object):
         raise NotImplementedError("Unwinder __call__.")
 
 
+class FrameId(object):
+    """A Frame-ID class for use when creating gdb.UnwindInfo objects.
+
+    Attributes (all read-only):
+        pc: Program counter value.
+        sp: The stack-pointer value.
+        special: An alternative stack-pointer value, can be None."""
+
+    def __init__(self, sp, pc, special=None):
+        self._sp = sp
+        self._pc = pc
+        self._special = special
+
+    @property
+    def sp(self):
+        return self._sp
+
+    @property
+    def pc(self):
+        return self._pc
+
+    @property
+    def special(self):
+        return self._special
+
+
 def register_unwinder(locus, unwinder, replace=False):
     """Register unwinder in given locus.
 
index dbabb006e4b1181ce27a3800a9ea5d18d1d0be31..4e110c51e3b3f756ea73b165233c4accfe234306 100644 (file)
@@ -14,7 +14,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import gdb
-from gdb.unwinder import Unwinder
+from gdb.unwinder import Unwinder, FrameId
 
 
 # These are set to test whether invalid register names cause an error.
@@ -22,20 +22,6 @@ add_saved_register_error = False
 read_register_error = False
 
 
-class FrameId(object):
-    def __init__(self, sp, pc):
-        self._sp = sp
-        self._pc = pc
-
-    @property
-    def sp(self):
-        return self._sp
-
-    @property
-    def pc(self):
-        return self._pc
-
-
 class TestUnwinder(Unwinder):
     AMD64_RBP = 6
     AMD64_RSP = 7