Home | History | Annotate | Line # | Download | only in gdb.python
      1 # Copyright (C) 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 os
     17 import shutil
     18 from enum import Enum
     19 
     20 import gdb
     21 from gdb.missing_objfile import MissingObjfileHandler
     22 
     23 # A global log that is filled in by instances of the LOG_HANDLER class
     24 # when they are called.
     25 handler_call_log = []
     26 
     27 # A global holding a string, the build-id of the last missing objfile
     28 # which triggered the 'handler' class below.  This is set in the
     29 # __call__ method of the 'handler' class and then checked from the
     30 # expect script.
     31 handler_last_buildid = None
     32 
     33 
     34 # A global holding a string, the filename of the last missing objfile
     35 # which triggered the 'handler' class below.  This is set in the
     36 # __call__ method of the 'handler' class and then checked from the
     37 # expect script.
     38 handler_last_filename = None
     39 
     40 
     41 # A helper function that makes some assertions about the arguments
     42 # passed to a MissingObjfileHandler.__call__() method.
     43 def check_args(pspace, buildid, filename):
     44     assert type(filename) == str
     45     assert filename != ""
     46     assert type(pspace) == gdb.Progspace
     47     assert type(buildid) == str
     48     assert buildid != ""
     49 
     50 
     51 # Enum used to configure the 'handler' class from the test script.
     52 class Mode(Enum):
     53     RETURN_NONE = 0
     54     RETURN_TRUE = 1
     55     RETURN_FALSE = 2
     56     RETURN_STRING = 3
     57 
     58 
     59 # A missing objfile handler which can be configured to return each of
     60 # the different possible return types.
     61 class handler(MissingObjfileHandler):
     62     def __init__(self):
     63         super().__init__("handler")
     64         self._call_count = 0
     65         self._mode = Mode.RETURN_NONE
     66 
     67     def __call__(self, pspace, buildid, filename):
     68         global handler_call_log, handler_last_buildid, handler_last_filename
     69         check_args(pspace, buildid, filename)
     70         handler_call_log.append(self.name)
     71         handler_last_buildid = buildid
     72         handler_last_filename = filename
     73         self._call_count += 1
     74         if self._mode == Mode.RETURN_NONE:
     75             return None
     76 
     77         if self._mode == Mode.RETURN_TRUE:
     78             shutil.copy(self._src, self._dest)
     79 
     80             # If we're using the fission-dwp board then there will
     81             # also be a .dwp file that needs to be copied.
     82             dwp_src = self._src + ".dwp"
     83             if os.path.exists(dwp_src):
     84                 dwp_dest = self._dest + ".dwp"
     85                 shutil.copy(dwp_src, dwp_dest)
     86 
     87             return True
     88 
     89         if self._mode == Mode.RETURN_FALSE:
     90             return False
     91 
     92         if self._mode == Mode.RETURN_STRING:
     93             return self._dest
     94 
     95         assert False
     96 
     97     @property
     98     def call_count(self):
     99         """Return a count, the number of calls to __call__ since the last
    100         call to set_mode.
    101         """
    102         return self._call_count
    103 
    104     def set_mode(self, mode, *args):
    105         self._call_count = 0
    106         self._mode = mode
    107 
    108         if mode == Mode.RETURN_NONE:
    109             assert len(args) == 0
    110             return
    111 
    112         if mode == Mode.RETURN_TRUE:
    113             assert len(args) == 2
    114             self._src = args[0]
    115             self._dest = args[1]
    116             return
    117 
    118         if mode == Mode.RETURN_FALSE:
    119             assert len(args) == 0
    120             return
    121 
    122         if mode == Mode.RETURN_STRING:
    123             assert len(args) == 1
    124             self._dest = args[0]
    125             return
    126 
    127         assert False
    128 
    129 
    130 # A missing objfile handler which raises an exception.  The type of
    131 # exception to be raised is configured from the test script.
    132 class exception_handler(MissingObjfileHandler):
    133     def __init__(self):
    134         super().__init__("exception_handler")
    135         self.exception_type = None
    136 
    137     def __call__(self, pspace, buildid, filename):
    138         global handler_call_log
    139         check_args(pspace, buildid, filename)
    140         handler_call_log.append(self.name)
    141         assert self.exception_type is not None
    142         raise self.exception_type("message")
    143 
    144 
    145 # A very simple logging missing objfile handler.  Always returns None
    146 # so that GDB will try any other registered handlers, but first logs
    147 # the name of this handler into the global HANDLER_CALL_LOG, which can
    148 # then be checked from the test script.
    149 class log_handler(MissingObjfileHandler):
    150     def __call__(self, pspace, buildid, filename):
    151         global handler_call_log
    152         check_args(pspace, buildid, filename)
    153         handler_call_log.append(self.name)
    154         return None
    155 
    156 
    157 # A basic helper function, this keeps lines shorter in the TCL script.
    158 def register(name, locus=None):
    159     gdb.missing_objfile.register_handler(locus, log_handler(name))
    160 
    161 
    162 # Create instances of the handlers, but don't install any.  We install
    163 # these as needed from the TCL script.
    164 rhandler = exception_handler()
    165 handler_obj = handler()
    166 
    167 print("Success")
    168