]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | # Copyright (C) 2015-2024 Free Software Foundation, Inc. |
d11916aa SS |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation; either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | """Unwinder class and register_unwinder function.""" | |
17 | ||
18 | import gdb | |
19 | ||
20 | ||
21 | class Unwinder(object): | |
22 | """Base class (or a template) for frame unwinders written in Python. | |
23 | ||
24 | An unwinder has a single method __call__ and the attributes | |
25 | described below. | |
26 | ||
27 | Attributes: | |
28 | name: The name of the unwinder. | |
29 | enabled: A boolean indicating whether the unwinder is enabled. | |
30 | """ | |
31 | ||
32 | def __init__(self, name): | |
33 | """Constructor. | |
34 | ||
35 | Args: | |
36 | name: An identifying name for the unwinder. | |
37 | """ | |
6bf5f25b AB |
38 | |
39 | if not isinstance(name, str): | |
40 | raise TypeError("incorrect type for name: %s" % type(name)) | |
41 | ||
42 | self._name = name | |
43 | self._enabled = True | |
44 | ||
45 | @property | |
46 | def name(self): | |
47 | return self._name | |
48 | ||
49 | @property | |
50 | def enabled(self): | |
51 | return self._enabled | |
52 | ||
53 | @enabled.setter | |
54 | def enabled(self, value): | |
55 | if not isinstance(value, bool): | |
56 | raise TypeError("incorrect type for enabled attribute: %s" % type(value)) | |
57 | self._enabled = value | |
58 | gdb.invalidate_cached_frames() | |
d11916aa SS |
59 | |
60 | def __call__(self, pending_frame): | |
61 | """GDB calls this method to unwind a frame. | |
62 | ||
63 | Arguments: | |
64 | pending_frame: gdb.PendingFrame instance. | |
65 | ||
66 | Returns: | |
67 | gdb.UnwindInfo instance. | |
68 | """ | |
69 | raise NotImplementedError("Unwinder __call__.") | |
70 | ||
71 | ||
3712e78c AB |
72 | class FrameId(object): |
73 | """A Frame-ID class for use when creating gdb.UnwindInfo objects. | |
74 | ||
75 | Attributes (all read-only): | |
76 | pc: Program counter value. | |
77 | sp: The stack-pointer value. | |
78 | special: An alternative stack-pointer value, can be None.""" | |
79 | ||
80 | def __init__(self, sp, pc, special=None): | |
81 | self._sp = sp | |
82 | self._pc = pc | |
83 | self._special = special | |
84 | ||
85 | @property | |
86 | def sp(self): | |
87 | return self._sp | |
88 | ||
89 | @property | |
90 | def pc(self): | |
91 | return self._pc | |
92 | ||
93 | @property | |
94 | def special(self): | |
95 | return self._special | |
96 | ||
97 | ||
d11916aa SS |
98 | def register_unwinder(locus, unwinder, replace=False): |
99 | """Register unwinder in given locus. | |
100 | ||
101 | The unwinder is prepended to the locus's unwinders list. Unwinder | |
102 | name should be unique. | |
103 | ||
104 | Arguments: | |
105 | locus: Either an objfile, progspace, or None (in which case | |
106 | the unwinder is registered globally). | |
107 | unwinder: An object of a gdb.Unwinder subclass | |
108 | replace: If True, replaces existing unwinder with the same name. | |
109 | Otherwise, raises exception if unwinder with the same | |
110 | name already exists. | |
111 | ||
112 | Returns: | |
113 | Nothing. | |
114 | ||
115 | Raises: | |
116 | RuntimeError: Unwinder name is not unique | |
117 | TypeError: Bad locus type | |
118 | """ | |
119 | if locus is None: | |
120 | if gdb.parameter("verbose"): | |
121 | gdb.write("Registering global %s unwinder ...\n" % unwinder.name) | |
122 | locus = gdb | |
123 | elif isinstance(locus, gdb.Objfile) or isinstance(locus, gdb.Progspace): | |
124 | if gdb.parameter("verbose"): | |
13123da8 SM |
125 | gdb.write( |
126 | "Registering %s unwinder for %s ...\n" % (unwinder.name, locus.filename) | |
127 | ) | |
d11916aa SS |
128 | else: |
129 | raise TypeError("locus should be gdb.Objfile or gdb.Progspace or None") | |
130 | ||
131 | i = 0 | |
132 | for needle in locus.frame_unwinders: | |
133 | if needle.name == unwinder.name: | |
134 | if replace: | |
135 | del locus.frame_unwinders[i] | |
136 | else: | |
13123da8 | 137 | raise RuntimeError("Unwinder %s already exists." % unwinder.name) |
d11916aa SS |
138 | i += 1 |
139 | locus.frame_unwinders.insert(0, unwinder) | |
e0f3fd7c | 140 | gdb.invalidate_cached_frames() |