1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# 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 <http://www.gnu.org/licenses/>.
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")
|