3 # Copyright (C) 2013-2023 Free Software Foundation, Inc.
5 # This file is part of GDB.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 # make-target-delegates.py
27 # The line we search for in target.h that marks where we should start
28 # looking for methods.
29 TRIGGER
= re
.compile(r
"^struct target_ops$")
30 # The end of the methods part.
31 ENDER
= re
.compile(r
"^\s*};$")
34 SYMBOL
= "[a-zA-Z_][a-zA-Z0-9_]*"
35 # Match the name part of a method in struct target_ops.
36 NAME_PART
= r
"(?P<name>" + SYMBOL
+ ")\s"
37 # Match the arguments to a method.
38 ARGS_PART
= r
"(?P<args>\(.*\))"
39 # We strip the indentation so here we only need the caret.
42 POINTER_PART
= r
"\s*(\*)?\s*"
44 # Match a C++ symbol, including scope operators and template
45 # parameters. E.g., 'std::vector<something>'.
46 CP_SYMBOL
= r
"[a-zA-Z_][a-zA-Z0-9_<>:]*"
47 # Match the return type when it is "ordinary".
48 SIMPLE_RETURN_PART
= r
"((struct|class|enum|union)\s+)?" + CP_SYMBOL
50 # Match a return type.
51 RETURN_PART
= r
"((const|volatile)\s+)?(" + SIMPLE_RETURN_PART
+ ")" + POINTER_PART
54 VIRTUAL_PART
= r
"virtual\s"
56 # Match the TARGET_DEFAULT_* attribute for a method.
57 TARGET_DEFAULT_PART
= r
"TARGET_DEFAULT_(?P<style>[A-Z_]+)\s*\((?P<default_arg>.*)\)"
59 # Match the arguments and trailing attribute of a method definition.
60 # Note we don't match the trailing ";".
61 METHOD_TRAILER
= r
"\s*" + TARGET_DEFAULT_PART
+ "$"
63 # Match an entire method definition.
75 # Regular expression used to dissect argument types.
76 ARGTYPES
= re
.compile(
83 + r
"|(?P<T>.*(enum\s+)?"
90 # Match TARGET_DEBUG_PRINTER in an argument type.
91 # This must match the whole "sub-expression" including the parens.
92 TARGET_DEBUG_PRINTER
= r
"\s*TARGET_DEBUG_PRINTER\s*\((?P<arg>[^)]*)\)\s*"
98 with
open("target.h", "r") as target_h
:
101 if not found_trigger
:
102 if TRIGGER
.match(line
):
105 # Skip the open brace.
107 elif ENDER
.match(line
):
111 line
= re
.split("//", line
)[0]
112 all_the_text
= all_the_text
+ " " + line
113 if not found_trigger
:
114 raise "Could not find trigger line"
115 # Now strip out the C comments.
116 all_the_text
= re
.sub(r
"/\*(.*?)\*/", "", all_the_text
)
117 # Replace sequences whitespace with a single space character.
118 # We need the space because the method may have been split
119 # between multiple lines, like e.g.:
121 # virtual std::vector<long_type_name>
122 # my_long_method_name ()
123 # TARGET_DEFAULT_IGNORE ();
125 # If we didn't preserve the space, then we'd end up with:
127 # virtual std::vector<long_type_name>my_long_method_name ()TARGET_DEFAULT_IGNORE ()
129 # ... which wouldn't later be parsed correctly.
130 all_the_text
= re
.sub(r
"\s+", " ", all_the_text
)
131 return all_the_text
.split(";")
134 # Parse arguments into a list.
135 def parse_argtypes(typestr
):
136 # Remove the outer parens.
137 typestr
= re
.sub(r
"^\((.*)\)$", r
"\1", typestr
)
139 for item
in re
.split(r
",\s*", typestr
):
140 if item
== "void" or item
== "":
142 m
= ARGTYPES
.match(item
)
145 onetype
= m
.group("E")
147 onetype
= m
.group("T")
150 result
.append(onetype
.strip())
154 # Write function header given name, return type, and argtypes.
155 # Returns a list of actual argument names.
156 def write_function_header(f
, decl
, name
, return_type
, argtypes
):
157 print(return_type
, file=f
, end
="")
159 if not return_type
.endswith("*"):
160 print(" ", file=f
, end
="")
163 print(name
+ " (", file=f
, end
="")
166 for i
in range(len(argtypes
)):
167 val
= re
.sub(TARGET_DEBUG_PRINTER
, "", argtypes
[i
])
168 if not val
.endswith("*") and not val
.endswith("&"):
170 vname
= "arg" + str(i
)
173 actuals
.append(vname
)
174 print(", ".join(argdecls
) + ")", file=f
, end
="")
176 print(" override;", file=f
)
182 # Write out a declaration.
183 def write_declaration(f
, name
, return_type
, argtypes
):
184 write_function_header(f
, True, name
, return_type
, argtypes
)
187 # Write out a delegation function.
188 def write_delegator(f
, name
, return_type
, argtypes
):
189 names
= write_function_header(
190 f
, False, "target_ops::" + name
, return_type
, argtypes
192 print(" ", file=f
, end
="")
193 if return_type
!= "void":
194 print("return ", file=f
, end
="")
195 print("this->beneath ()->" + name
+ " (", file=f
, end
="")
196 print(", ".join(names
), file=f
, end
="")
201 # Write out a default function.
202 def write_tdefault(f
, content
, style
, name
, return_type
, argtypes
):
203 name
= "dummy_target::" + name
204 names
= write_function_header(f
, False, name
, return_type
, argtypes
)
206 print(" ", file=f
, end
="")
207 if return_type
!= "void":
208 print("return ", file=f
, end
="")
209 print(content
+ " (", file=f
, end
="")
210 names
.insert(0, "this")
211 print(", ".join(names
) + ");", file=f
)
212 elif style
== "RETURN":
213 print(" return " + content
+ ";", file=f
)
214 elif style
== "NORETURN":
215 print(" " + content
+ ";", file=f
)
216 elif style
== "IGNORE":
220 raise "unrecognized style: " + style
224 def munge_type(typename
):
225 m
= re
.search(TARGET_DEBUG_PRINTER
, typename
)
227 return m
.group("arg")
228 typename
= typename
.rstrip()
229 typename
= re
.sub("[ ()<>:]", "_", typename
)
230 typename
= re
.sub("[*]", "p", typename
)
231 typename
= re
.sub("&", "r", typename
)
232 # Identifers with double underscores are reserved to the C++
234 typename
= re
.sub("_+", "_", typename
)
235 # Avoid ending the function name with underscore, for
236 # cosmetics. Trailing underscores appear after munging types
237 # with template parameters, like e.g. "foo<int>".
238 typename
= re
.sub("_+$", "", typename
)
239 return "target_debug_print_" + typename
242 # Write out a debug method.
243 def write_debugmethod(f
, content
, name
, return_type
, argtypes
):
244 debugname
= "debug_target::" + name
245 names
= write_function_header(f
, False, debugname
, return_type
, argtypes
)
246 if return_type
!= "void":
247 print(" " + return_type
+ " result;", file=f
)
249 ' gdb_printf (gdb_stdlog, "-> %s->'
251 + ' (...)\\n", this->beneath ()->shortname ());',
255 # Delegate to the beneath target.
256 print(" ", file=f
, end
="")
257 if return_type
!= "void":
258 print("result = ", file=f
, end
="")
259 print("this->beneath ()->" + name
+ " (", file=f
, end
="")
260 print(", ".join(names
), file=f
, end
="")
263 # Now print the arguments.
265 ' gdb_printf (gdb_stdlog, "<- %s->'
267 + ' (", this->beneath ()->shortname ());',
270 for i
in range(len(argtypes
)):
272 print(' gdb_puts (", ", gdb_stdlog);', file=f
)
273 printer
= munge_type(argtypes
[i
])
274 print(" " + printer
+ " (" + names
[i
] + ");", file=f
)
275 if return_type
!= "void":
276 print(' gdb_puts (") = ", gdb_stdlog);', file=f
)
277 printer
= munge_type(return_type
)
278 print(" " + printer
+ " (result);", file=f
)
279 print(' gdb_puts ("\\n", gdb_stdlog);', file=f
)
281 print(' gdb_puts (")\\n", gdb_stdlog);', file=f
)
283 if return_type
!= "void":
284 print(" return result;", file=f
)
289 def print_class(f
, class_name
, delegators
, entries
):
290 print("struct " + class_name
+ " : public target_ops", file=f
)
292 print(" const target_info &info () const override;", file=f
)
294 print(" strata stratum () const override;", file=f
)
297 for name
in delegators
:
298 return_type
= entries
[name
]["return_type"]
299 argtypes
= entries
[name
]["argtypes"]
300 print(" ", file=f
, end
="")
301 write_declaration(f
, name
, return_type
, argtypes
)
303 print("};\n", file=f
)
308 for current_line
in scan_target_h():
309 # See comments in scan_target_h. Here we strip away the leading
310 # and trailing whitespace.
311 current_line
= current_line
.strip()
312 m
= METHOD
.match(current_line
)
316 data
["argtypes"] = parse_argtypes(data
["args"])
317 data
["return_type"] = data
["return_type"].strip()
318 entries
[data
["name"]] = data
320 delegators
.append(data
["name"])
322 with
open("target-delegates.c", "w") as f
:
324 gdbcopyright
.copyright(
325 "make-target-delegates.py", "Boilerplate target methods for GDB"
329 print_class(f
, "dummy_target", delegators
, entries
)
330 print_class(f
, "debug_target", delegators
, entries
)
332 for name
in delegators
:
333 tdefault
= entries
[name
]["default_arg"]
334 return_type
= entries
[name
]["return_type"]
335 style
= entries
[name
]["style"]
336 argtypes
= entries
[name
]["argtypes"]
338 write_delegator(f
, name
, return_type
, argtypes
)
339 write_tdefault(f
, tdefault
, style
, name
, return_type
, argtypes
)
340 write_debugmethod(f
, tdefault
, name
, return_type
, argtypes
)