| # Copyright (C) 2023-2024 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 os | |
| from enum import Enum | |
| import gdb | |
| from gdb.missing_debug import MissingDebugHandler | |
| # A global log that is filled in by instances of the LOG_HANDLER class | |
| # when they are called. | |
| handler_call_log = [] | |
| class Mode(Enum): | |
| RETURN_NONE = 0 | |
| RETURN_TRUE = 1 | |
| RETURN_FALSE = 2 | |
| RETURN_STRING = 3 | |
| class handler(MissingDebugHandler): | |
| def __init__(self): | |
| super().__init__("handler") | |
| self._call_count = 0 | |
| self._mode = Mode.RETURN_NONE | |
| def __call__(self, objfile): | |
| global handler_call_log | |
| handler_call_log.append(self.name) | |
| self._call_count += 1 | |
| if self._mode == Mode.RETURN_NONE: | |
| return None | |
| if self._mode == Mode.RETURN_TRUE: | |
| os.rename(self._src, self._dest) | |
| return True | |
| if self._mode == Mode.RETURN_FALSE: | |
| return False | |
| if self._mode == Mode.RETURN_STRING: | |
| return self._dest | |
| assert False | |
| @property | |
| def call_count(self): | |
| """Return a count, the number of calls to __call__ since the last | |
| call to set_mode. | |
| """ | |
| return self._call_count | |
| def set_mode(self, mode, *args): | |
| self._call_count = 0 | |
| self._mode = mode | |
| if mode == Mode.RETURN_NONE: | |
| assert len(args) == 0 | |
| return | |
| if mode == Mode.RETURN_TRUE: | |
| assert len(args) == 2 | |
| self._src = args[0] | |
| self._dest = args[1] | |
| return | |
| if mode == Mode.RETURN_FALSE: | |
| assert len(args) == 0 | |
| return | |
| if mode == Mode.RETURN_STRING: | |
| assert len(args) == 1 | |
| self._dest = args[0] | |
| return | |
| assert False | |
| class exception_handler(MissingDebugHandler): | |
| def __init__(self): | |
| super().__init__("exception_handler") | |
| self.exception_type = None | |
| def __call__(self, objfile): | |
| global handler_call_log | |
| handler_call_log.append(self.name) | |
| assert self.exception_type is not None | |
| raise self.exception_type("message") | |
| class log_handler(MissingDebugHandler): | |
| def __call__(self, objfile): | |
| global handler_call_log | |
| handler_call_log.append(self.name) | |
| return None | |
| # A basic helper function, this keeps lines shorter in the TCL script. | |
| def register(name, locus=None): | |
| gdb.missing_debug.register_handler(locus, log_handler(name)) | |
| # Create instances of the handlers, but don't install any. We install | |
| # these as needed from the TCL script. | |
| rhandler = exception_handler() | |
| handler_obj = handler() | |
| print("Success") |