# Copyright (C) 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 . import os import shutil from enum import Enum import gdb from gdb.missing_objfile import MissingObjfileHandler # A global log that is filled in by instances of the LOG_HANDLER class # when they are called. handler_call_log = [] # A global holding a string, the build-id of the last missing objfile # which triggered the 'handler' class below. This is set in the # __call__ method of the 'handler' class and then checked from the # expect script. handler_last_buildid = None # A global holding a string, the filename of the last missing objfile # which triggered the 'handler' class below. This is set in the # __call__ method of the 'handler' class and then checked from the # expect script. handler_last_filename = None # A helper function that makes some assertions about the arguments # passed to a MissingObjfileHandler.__call__() method. def check_args(pspace, buildid, filename): assert type(filename) == str assert filename != "" assert type(pspace) == gdb.Progspace assert type(buildid) == str assert buildid != "" # Enum used to configure the 'handler' class from the test script. class Mode(Enum): RETURN_NONE = 0 RETURN_TRUE = 1 RETURN_FALSE = 2 RETURN_STRING = 3 # A missing objfile handler which can be configured to return each of # the different possible return types. class handler(MissingObjfileHandler): def __init__(self): super().__init__("handler") self._call_count = 0 self._mode = Mode.RETURN_NONE def __call__(self, pspace, buildid, filename): global handler_call_log, handler_last_buildid, handler_last_filename check_args(pspace, buildid, filename) handler_call_log.append(self.name) handler_last_buildid = buildid handler_last_filename = filename self._call_count += 1 if self._mode == Mode.RETURN_NONE: return None if self._mode == Mode.RETURN_TRUE: shutil.copy(self._src, self._dest) # If we're using the fission-dwp board then there will # also be a .dwp file that needs to be copied. dwp_src = self._src + ".dwp" if os.path.exists(dwp_src): dwp_dest = self._dest + ".dwp" shutil.copy(dwp_src, dwp_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 # A missing objfile handler which raises an exception. The type of # exception to be raised is configured from the test script. class exception_handler(MissingObjfileHandler): def __init__(self): super().__init__("exception_handler") self.exception_type = None def __call__(self, pspace, buildid, filename): global handler_call_log check_args(pspace, buildid, filename) handler_call_log.append(self.name) assert self.exception_type is not None raise self.exception_type("message") # A very simple logging missing objfile handler. Always returns None # so that GDB will try any other registered handlers, but first logs # the name of this handler into the global HANDLER_CALL_LOG, which can # then be checked from the test script. class log_handler(MissingObjfileHandler): def __call__(self, pspace, buildid, filename): global handler_call_log check_args(pspace, buildid, filename) 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_objfile.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")