Skip to content

Commit d734d02

Browse files
committed
Added static version of gdb's Python lib to frozen modules
This means the python module will be accessable without shared/file linking.
1 parent 91ccdd2 commit d734d02

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+20850
-203
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,6 @@ Python/frozen_modules/MANIFEST
156156
# Ignore ./python binary on Unix but still look into ./Python/ directory.
157157
/python
158158
!/Python/
159+
160+
# Ignore architecture dependent statically compiled build directories.
161+
build-*/

Lib/gdb/FrameDecorator.py

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
# Copyright (C) 2013-2024 Free Software Foundation, Inc.
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+
import gdb
17+
18+
19+
class _FrameDecoratorBase(object):
20+
"""Base class of frame decorators."""
21+
22+
# 'base' can refer to a gdb.Frame or another frame decorator. In
23+
# the latter case, the child class will have called the super
24+
# method and _base will be an object conforming to the Frame Filter
25+
# class.
26+
def __init__(self, base):
27+
self._base = base
28+
29+
@staticmethod
30+
def __is_limited_frame(frame):
31+
"""Internal utility to determine if the frame is special or
32+
limited."""
33+
sal = frame.find_sal()
34+
35+
if (
36+
not sal.symtab
37+
or not sal.symtab.filename
38+
or frame.type() == gdb.DUMMY_FRAME
39+
or frame.type() == gdb.SIGTRAMP_FRAME
40+
):
41+
return True
42+
43+
return False
44+
45+
def elided(self):
46+
"""Return any elided frames that this class might be
47+
wrapping, or None."""
48+
if hasattr(self._base, "elided"):
49+
return self._base.elided()
50+
51+
return None
52+
53+
def function(self):
54+
"""Return the name of the frame's function or an address of
55+
the function of the frame. First determine if this is a
56+
special frame. If not, try to determine filename from GDB's
57+
frame internal function API. Finally, if a name cannot be
58+
determined return the address. If this function returns an
59+
address, GDB will attempt to determine the function name from
60+
its internal minimal symbols store (for example, for inferiors
61+
without debug-info)."""
62+
63+
# Both gdb.Frame, and FrameDecorator have a method called
64+
# "function", so determine which object this is.
65+
if not isinstance(self._base, gdb.Frame):
66+
if hasattr(self._base, "function"):
67+
# If it is not a gdb.Frame, and there is already a
68+
# "function" method, use that.
69+
return self._base.function()
70+
71+
frame = self.inferior_frame()
72+
73+
if frame.type() == gdb.DUMMY_FRAME:
74+
return "<function called from gdb>"
75+
elif frame.type() == gdb.SIGTRAMP_FRAME:
76+
return "<signal handler called>"
77+
78+
func = frame.name()
79+
if not isinstance(func, str):
80+
func = "???"
81+
return func
82+
83+
def address(self):
84+
"""Return the address of the frame's pc"""
85+
86+
if hasattr(self._base, "address"):
87+
return self._base.address()
88+
89+
frame = self.inferior_frame()
90+
return frame.pc()
91+
92+
def frame_args(self):
93+
"""Return an iterable of frame arguments for this frame, if
94+
any. The iterable object contains objects conforming with the
95+
Symbol/Value interface. If there are no frame arguments, or
96+
if this frame is deemed to be a special case, return None."""
97+
98+
if hasattr(self._base, "frame_args"):
99+
return self._base.frame_args()
100+
101+
frame = self.inferior_frame()
102+
if self.__is_limited_frame(frame):
103+
return None
104+
105+
args = FrameVars(frame)
106+
return args.fetch_frame_args()
107+
108+
def frame_locals(self):
109+
"""Return an iterable of local variables for this frame, if
110+
any. The iterable object contains objects conforming with the
111+
Symbol/Value interface. If there are no frame locals, or if
112+
this frame is deemed to be a special case, return None."""
113+
114+
if hasattr(self._base, "frame_locals"):
115+
return self._base.frame_locals()
116+
117+
frame = self.inferior_frame()
118+
if self.__is_limited_frame(frame):
119+
return None
120+
121+
args = FrameVars(frame)
122+
return args.fetch_frame_locals()
123+
124+
def line(self):
125+
"""Return line number information associated with the frame's
126+
pc. If symbol table/line information does not exist, or if
127+
this frame is deemed to be a special case, return None"""
128+
129+
if hasattr(self._base, "line"):
130+
return self._base.line()
131+
132+
frame = self.inferior_frame()
133+
if self.__is_limited_frame(frame):
134+
return None
135+
136+
sal = frame.find_sal()
137+
if sal:
138+
return sal.line
139+
else:
140+
return None
141+
142+
def inferior_frame(self):
143+
"""Return the gdb.Frame underpinning this frame decorator."""
144+
145+
# If 'base' is a frame decorator, we want to call its inferior
146+
# frame method. If '_base' is a gdb.Frame, just return that.
147+
if hasattr(self._base, "inferior_frame"):
148+
return self._base.inferior_frame()
149+
return self._base
150+
151+
152+
class FrameDecorator(_FrameDecoratorBase):
153+
"""Basic implementation of a Frame Decorator
154+
155+
This base frame decorator decorates a frame or another frame
156+
decorator, and provides convenience methods. If this object is
157+
wrapping a frame decorator, defer to that wrapped object's method
158+
if it has one. This allows for frame decorators that have
159+
sub-classed FrameDecorator object, but also wrap other frame
160+
decorators on the same frame to correctly execute.
161+
162+
E.g
163+
164+
If the result of frame filters running means we have one gdb.Frame
165+
wrapped by multiple frame decorators, all sub-classed from
166+
FrameDecorator, the resulting hierarchy will be:
167+
168+
Decorator1
169+
-- (wraps) Decorator2
170+
-- (wraps) FrameDecorator
171+
-- (wraps) gdb.Frame
172+
173+
In this case we have two frame decorators, both of which are
174+
sub-classed from FrameDecorator. If Decorator1 just overrides the
175+
'function' method, then all of the other methods are carried out
176+
by the super-class FrameDecorator. But Decorator2 may have
177+
overriden other methods, so FrameDecorator will look at the
178+
'base' parameter and defer to that class's methods. And so on,
179+
down the chain."""
180+
181+
def filename(self):
182+
"""Return the filename associated with this frame, detecting
183+
and returning the appropriate library name is this is a shared
184+
library."""
185+
186+
if hasattr(self._base, "filename"):
187+
return self._base.filename()
188+
189+
frame = self.inferior_frame()
190+
sal = frame.find_sal()
191+
if not sal.symtab or not sal.symtab.filename:
192+
pc = frame.pc()
193+
return gdb.solib_name(pc)
194+
else:
195+
return sal.symtab.filename
196+
197+
198+
class DAPFrameDecorator(_FrameDecoratorBase):
199+
"""Like FrameDecorator, but has slightly different results
200+
for the "filename" method."""
201+
202+
def filename(self):
203+
"""Return the filename associated with this frame, detecting
204+
and returning the appropriate library name is this is a shared
205+
library."""
206+
207+
if hasattr(self._base, "filename"):
208+
return self._base.filename()
209+
210+
frame = self.inferior_frame()
211+
sal = frame.find_sal()
212+
if sal.symtab is not None:
213+
return sal.symtab.fullname()
214+
return None
215+
216+
def frame_locals(self):
217+
"""Return an iterable of local variables for this frame, if
218+
any. The iterable object contains objects conforming with the
219+
Symbol/Value interface. If there are no frame locals, or if
220+
this frame is deemed to be a special case, return None."""
221+
222+
if hasattr(self._base, "frame_locals"):
223+
return self._base.frame_locals()
224+
225+
frame = self.inferior_frame()
226+
args = FrameVars(frame)
227+
return args.fetch_frame_locals(True)
228+
229+
230+
class SymValueWrapper(object):
231+
"""A container class conforming to the Symbol/Value interface
232+
which holds frame locals or frame arguments."""
233+
234+
# The FRAME argument is needed here because gdb.Symbol doesn't
235+
# carry the block with it, and so read_var can't find symbols from
236+
# outer (static link) frames.
237+
def __init__(self, frame, symbol):
238+
self.frame = frame
239+
self.sym = symbol
240+
241+
def value(self):
242+
"""Return the value associated with this symbol, or None"""
243+
if self.frame is None:
244+
return None
245+
return self.frame.read_var(self.sym)
246+
247+
def symbol(self):
248+
"""Return the symbol, or Python text, associated with this
249+
symbol, or None"""
250+
return self.sym
251+
252+
253+
class FrameVars(object):
254+
"""Utility class to fetch and store frame local variables, or
255+
frame arguments."""
256+
257+
def __init__(self, frame):
258+
self.frame = frame
259+
260+
def fetch_frame_locals(self, follow_link=False):
261+
"""Public utility method to fetch frame local variables for
262+
the stored frame. Frame arguments are not fetched. If there
263+
are no frame local variables, return an empty list."""
264+
lvars = []
265+
266+
frame = self.frame
267+
try:
268+
block = frame.block()
269+
except RuntimeError:
270+
block = None
271+
272+
traversed_link = False
273+
while block is not None:
274+
if block.is_global or block.is_static:
275+
break
276+
for sym in block:
277+
# Exclude arguments from the innermost function, but
278+
# if we found and traversed a static link, just treat
279+
# all such variables as "local".
280+
if sym.is_argument:
281+
if not traversed_link:
282+
continue
283+
elif not sym.is_variable:
284+
# We use an 'elif' here because is_variable
285+
# returns False for arguments as well. Anyway,
286+
# don't include non-variables here.
287+
continue
288+
lvars.append(SymValueWrapper(frame, sym))
289+
290+
if block.function is not None:
291+
if not follow_link:
292+
break
293+
# If the frame has a static link, follow it here.
294+
traversed_link = True
295+
frame = frame.static_link()
296+
if frame is None:
297+
break
298+
try:
299+
block = frame.block()
300+
except RuntimeError:
301+
block = None
302+
else:
303+
block = block.superblock
304+
305+
return lvars
306+
307+
def fetch_frame_args(self):
308+
"""Public utility method to fetch frame arguments for the
309+
stored frame. Frame arguments are the only type fetched. If
310+
there are no frame argument variables, return an empty list."""
311+
312+
args = []
313+
314+
try:
315+
block = self.frame.block()
316+
except RuntimeError:
317+
block = None
318+
319+
while block is not None:
320+
if block.is_global or block.is_static:
321+
break
322+
for sym in block:
323+
if not sym.is_argument:
324+
continue
325+
args.append(SymValueWrapper(None, sym))
326+
327+
# Stop when the function itself is seen, to avoid showing
328+
# variables from outer functions in a nested function.
329+
# Note that we don't traverse the static link for
330+
# arguments, only for locals.
331+
if block.function is not None:
332+
break
333+
334+
block = block.superblock
335+
336+
return args

Lib/gdb/FrameIterator.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (C) 2013-2024 Free Software Foundation, Inc.
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+
17+
class FrameIterator(object):
18+
"""A gdb.Frame iterator. Iterates over gdb.Frames or objects that
19+
conform to that interface."""
20+
21+
def __init__(self, frame_obj):
22+
"""Initialize a FrameIterator.
23+
24+
Arguments:
25+
frame_obj the starting frame."""
26+
27+
super(FrameIterator, self).__init__()
28+
self.frame = frame_obj
29+
30+
def __iter__(self):
31+
return self
32+
33+
def __next__(self):
34+
"""next implementation.
35+
36+
Returns:
37+
The next oldest frame."""
38+
39+
result = self.frame
40+
if result is None:
41+
raise StopIteration
42+
self.frame = result.older()
43+
return result

0 commit comments

Comments
 (0)