diff options
Diffstat (limited to 'gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py')
-rw-r--r-- | gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py new file mode 100644 index 0000000..99c571f --- /dev/null +++ b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py @@ -0,0 +1,85 @@ +# Copyright (C) 2021 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 <http://www.gnu.org/licenses/>. + +import gdb +from gdb.unwinder import Unwinder + +# Set this to the stack level the backtrace should be corrupted at. +# This will only work for frame 1, 3, or 5 in the test this unwinder +# was written for. +stop_at_level = None + +# Set this to the stack frame size of frames 1, 3, and 5. These +# frames will all have the same stack frame size as they are the same +# function called recursively. +stack_adjust = None + + +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): + def __init__(self): + Unwinder.__init__(self, "stop at level") + + def __call__(self, pending_frame): + global stop_at_level + global stack_adjust + + if stop_at_level is None or pending_frame.level() != stop_at_level: + return None + + if stack_adjust is None: + raise gdb.GdbError("invalid stack_adjust") + + if not stop_at_level in [1, 3, 5]: + raise gdb.GdbError("invalid stop_at_level") + + sp_desc = pending_frame.architecture().registers().find("sp") + sp = pending_frame.read_register(sp_desc) + stack_adjust + pc = (gdb.lookup_symbol("normal_func"))[0].value().address + unwinder = pending_frame.create_unwind_info(FrameId(sp, pc)) + + for reg in pending_frame.architecture().registers("general"): + val = pending_frame.read_register(reg) + unwinder.add_saved_register(reg, val) + return unwinder + + +gdb.unwinder.register_unwinder(None, TestUnwinder(), True) + +# When loaded, it is expected that the stack looks like: +# +# main -> normal_func -> inline_func -> normal_func -> inline_func -> normal_func -> inline_func +# +# Compute the stack frame size of normal_func, which has inline_func +# inlined within it. +f0 = gdb.newest_frame() +f1 = f0.older() +f2 = f1.older() +f0_sp = f0.read_register("sp") +f2_sp = f2.read_register("sp") +stack_adjust = f2_sp - f0_sp |