# Copyright (C) 2013-2023 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 . # This file is part of the GDB testsuite. It tests Python-based # frame-filters. import gdb import itertools from gdb.FrameDecorator import FrameDecorator import copy class Reverse_Function(FrameDecorator): def __init__(self, fobj): super(Reverse_Function, self).__init__(fobj) self.fobj = fobj def function(self): fname = str(self.fobj.function()) if not fname: return None if fname == "end_func": extra = self.fobj.inferior_frame().read_var("str").string() else: extra = "" fname = fname[::-1] + extra return fname class Dummy(FrameDecorator): def __init__(self, fobj): super(Dummy, self).__init__(fobj) self.fobj = fobj def function(self): return "Dummy function" def address(self): return 0x123 def filename(self): return "Dummy filename" def frame_args(self): return [("Foo", gdb.Value(12)), ("Bar", "Stuff"), ("FooBar", 42)] def frame_locals(self): return [] def line(self): return 0 def elided(self): return None class FrameFilter: def __init__(self): self.name = "Reverse" self.priority = 100 self.enabled = True gdb.frame_filters[self.name] = self def filter(self, frame_iter): # Python 3.x moved the itertools.imap functionality to map(), # so check if it is available. if hasattr(itertools, "imap"): frame_iter = itertools.imap(Reverse_Function, frame_iter) else: frame_iter = map(Reverse_Function, frame_iter) return frame_iter class ElidingFrameDecorator(FrameDecorator): def __init__(self, frame, elided_frames): super(ElidingFrameDecorator, self).__init__(frame) self.elided_frames = elided_frames def elided(self): return iter(self.elided_frames) def address(self): # Regression test for an overflow in the python layer. bitsize = 8 * gdb.lookup_type("void").pointer().sizeof mask = (1 << bitsize) - 1 return 0xFFFFFFFFFFFFFFFF & mask class ElidingIterator: def __init__(self, ii): self.input_iterator = ii def __iter__(self): return self def next(self): frame = next(self.input_iterator) if str(frame.function()) != "func1": return frame # Suppose we want to return the 'func1' frame but elide the # next frame. E.g., if call in our interpreter language takes # two C frames to implement, and the first one we see is the # "sentinel". elided = next(self.input_iterator) return ElidingFrameDecorator(frame, [elided]) # Python 3.x requires __next__(self) while Python 2.x requires # next(self). Define next(self), and for Python 3.x create this # wrapper. def __next__(self): return self.next() class FrameElider: def __init__(self): self.name = "Elider" self.priority = 900 self.enabled = True gdb.frame_filters[self.name] = self def filter(self, frame_iter): return ElidingIterator(frame_iter) # This is here so the test can change the kind of error that is # thrown. name_error = RuntimeError # A simple decorator that gives an error when computing the function. class ErrorInName(FrameDecorator): def __init__(self, frame): FrameDecorator.__init__(self, frame) def function(self): raise name_error("whoops") # A filter that supplies buggy frames. Disabled by default. class ErrorFilter: def __init__(self): self.name = "Error" self.priority = 1 self.enabled = False gdb.frame_filters[self.name] = self def filter(self, frame_iter): # Python 3.x moved the itertools.imap functionality to map(), # so check if it is available. if hasattr(itertools, "imap"): return itertools.imap(ErrorInName, frame_iter) else: return map(ErrorInName, frame_iter) FrameFilter() FrameElider() ErrorFilter()