mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-24 02:24:46 +08:00
213516ef31
This commit is the result of running the gdb/copyright.py script, which automated the update of the copyright year range for all source files managed by the GDB project to be updated to include year 2023.
341 lines
11 KiB
Python
Executable File
341 lines
11 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright (C) 2013-2023 Free Software Foundation, Inc.
|
|
#
|
|
# This file is part of GDB.
|
|
#
|
|
# 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/>.
|
|
|
|
# Usage:
|
|
# make-target-delegates.py
|
|
|
|
import re
|
|
import gdbcopyright
|
|
|
|
|
|
# The line we search for in target.h that marks where we should start
|
|
# looking for methods.
|
|
TRIGGER = re.compile(r"^struct target_ops$")
|
|
# The end of the methods part.
|
|
ENDER = re.compile(r"^\s*};$")
|
|
|
|
# Match a C symbol.
|
|
SYMBOL = "[a-zA-Z_][a-zA-Z0-9_]*"
|
|
# Match the name part of a method in struct target_ops.
|
|
NAME_PART = r"(?P<name>" + SYMBOL + ")\s"
|
|
# Match the arguments to a method.
|
|
ARGS_PART = r"(?P<args>\(.*\))"
|
|
# We strip the indentation so here we only need the caret.
|
|
INTRO_PART = r"^"
|
|
|
|
POINTER_PART = r"\s*(\*)?\s*"
|
|
|
|
# Match a C++ symbol, including scope operators and template
|
|
# parameters. E.g., 'std::vector<something>'.
|
|
CP_SYMBOL = r"[a-zA-Z_][a-zA-Z0-9_<>:]*"
|
|
# Match the return type when it is "ordinary".
|
|
SIMPLE_RETURN_PART = r"((struct|class|enum|union)\s+)?" + CP_SYMBOL
|
|
|
|
# Match a return type.
|
|
RETURN_PART = r"((const|volatile)\s+)?(" + SIMPLE_RETURN_PART + ")" + POINTER_PART
|
|
|
|
# Match "virtual".
|
|
VIRTUAL_PART = r"virtual\s"
|
|
|
|
# Match the TARGET_DEFAULT_* attribute for a method.
|
|
TARGET_DEFAULT_PART = r"TARGET_DEFAULT_(?P<style>[A-Z_]+)\s*\((?P<default_arg>.*)\)"
|
|
|
|
# Match the arguments and trailing attribute of a method definition.
|
|
# Note we don't match the trailing ";".
|
|
METHOD_TRAILER = r"\s*" + TARGET_DEFAULT_PART + "$"
|
|
|
|
# Match an entire method definition.
|
|
METHOD = re.compile(
|
|
INTRO_PART
|
|
+ VIRTUAL_PART
|
|
+ "(?P<return_type>"
|
|
+ RETURN_PART
|
|
+ ")"
|
|
+ NAME_PART
|
|
+ ARGS_PART
|
|
+ METHOD_TRAILER
|
|
)
|
|
|
|
# Regular expression used to dissect argument types.
|
|
ARGTYPES = re.compile(
|
|
"^("
|
|
+ r"(?P<E>enum\s+"
|
|
+ SYMBOL
|
|
+ r"\s*)("
|
|
+ SYMBOL
|
|
+ ")?"
|
|
+ r"|(?P<T>.*(enum\s+)?"
|
|
+ SYMBOL
|
|
+ r".*(\s|\*|&))"
|
|
+ SYMBOL
|
|
+ ")$"
|
|
)
|
|
|
|
# Match TARGET_DEBUG_PRINTER in an argument type.
|
|
# This must match the whole "sub-expression" including the parens.
|
|
TARGET_DEBUG_PRINTER = r"\s*TARGET_DEBUG_PRINTER\s*\((?P<arg>[^)]*)\)\s*"
|
|
|
|
|
|
def scan_target_h():
|
|
found_trigger = False
|
|
all_the_text = ""
|
|
with open("target.h", "r") as target_h:
|
|
for line in target_h:
|
|
line = line.strip()
|
|
if not found_trigger:
|
|
if TRIGGER.match(line):
|
|
found_trigger = True
|
|
elif "{" in line:
|
|
# Skip the open brace.
|
|
pass
|
|
elif ENDER.match(line):
|
|
break
|
|
else:
|
|
# Strip // comments.
|
|
line = re.split("//", line)[0]
|
|
all_the_text = all_the_text + " " + line
|
|
if not found_trigger:
|
|
raise "Could not find trigger line"
|
|
# Now strip out the C comments.
|
|
all_the_text = re.sub(r"/\*(.*?)\*/", "", all_the_text)
|
|
# Replace sequences whitespace with a single space character.
|
|
# We need the space because the method may have been split
|
|
# between multiple lines, like e.g.:
|
|
#
|
|
# virtual std::vector<long_type_name>
|
|
# my_long_method_name ()
|
|
# TARGET_DEFAULT_IGNORE ();
|
|
#
|
|
# If we didn't preserve the space, then we'd end up with:
|
|
#
|
|
# virtual std::vector<long_type_name>my_long_method_name ()TARGET_DEFAULT_IGNORE ()
|
|
#
|
|
# ... which wouldn't later be parsed correctly.
|
|
all_the_text = re.sub(r"\s+", " ", all_the_text)
|
|
return all_the_text.split(";")
|
|
|
|
|
|
# Parse arguments into a list.
|
|
def parse_argtypes(typestr):
|
|
# Remove the outer parens.
|
|
typestr = re.sub(r"^\((.*)\)$", r"\1", typestr)
|
|
result = []
|
|
for item in re.split(r",\s*", typestr):
|
|
if item == "void" or item == "":
|
|
continue
|
|
m = ARGTYPES.match(item)
|
|
if m:
|
|
if m.group("E"):
|
|
onetype = m.group("E")
|
|
else:
|
|
onetype = m.group("T")
|
|
else:
|
|
onetype = item
|
|
result.append(onetype.strip())
|
|
return result
|
|
|
|
|
|
# Write function header given name, return type, and argtypes.
|
|
# Returns a list of actual argument names.
|
|
def write_function_header(f, decl, name, return_type, argtypes):
|
|
print(return_type, file=f, end="")
|
|
if decl:
|
|
if not return_type.endswith("*"):
|
|
print(" ", file=f, end="")
|
|
else:
|
|
print("", file=f)
|
|
print(name + " (", file=f, end="")
|
|
argdecls = []
|
|
actuals = []
|
|
for i in range(len(argtypes)):
|
|
val = re.sub(TARGET_DEBUG_PRINTER, "", argtypes[i])
|
|
if not val.endswith("*") and not val.endswith("&"):
|
|
val = val + " "
|
|
vname = "arg" + str(i)
|
|
val = val + vname
|
|
argdecls.append(val)
|
|
actuals.append(vname)
|
|
print(", ".join(argdecls) + ")", file=f, end="")
|
|
if decl:
|
|
print(" override;", file=f)
|
|
else:
|
|
print("\n{", file=f)
|
|
return actuals
|
|
|
|
|
|
# Write out a declaration.
|
|
def write_declaration(f, name, return_type, argtypes):
|
|
write_function_header(f, True, name, return_type, argtypes)
|
|
|
|
|
|
# Write out a delegation function.
|
|
def write_delegator(f, name, return_type, argtypes):
|
|
names = write_function_header(
|
|
f, False, "target_ops::" + name, return_type, argtypes
|
|
)
|
|
print(" ", file=f, end="")
|
|
if return_type != "void":
|
|
print("return ", file=f, end="")
|
|
print("this->beneath ()->" + name + " (", file=f, end="")
|
|
print(", ".join(names), file=f, end="")
|
|
print(");", file=f)
|
|
print("}\n", file=f)
|
|
|
|
|
|
# Write out a default function.
|
|
def write_tdefault(f, content, style, name, return_type, argtypes):
|
|
name = "dummy_target::" + name
|
|
names = write_function_header(f, False, name, return_type, argtypes)
|
|
if style == "FUNC":
|
|
print(" ", file=f, end="")
|
|
if return_type != "void":
|
|
print("return ", file=f, end="")
|
|
print(content + " (", file=f, end="")
|
|
names.insert(0, "this")
|
|
print(", ".join(names) + ");", file=f)
|
|
elif style == "RETURN":
|
|
print(" return " + content + ";", file=f)
|
|
elif style == "NORETURN":
|
|
print(" " + content + ";", file=f)
|
|
elif style == "IGNORE":
|
|
# Nothing.
|
|
pass
|
|
else:
|
|
raise "unrecognized style: " + style
|
|
print("}\n", file=f)
|
|
|
|
|
|
def munge_type(typename):
|
|
m = re.search(TARGET_DEBUG_PRINTER, typename)
|
|
if m:
|
|
return m.group("arg")
|
|
typename = typename.rstrip()
|
|
typename = re.sub("[ ()<>:]", "_", typename)
|
|
typename = re.sub("[*]", "p", typename)
|
|
typename = re.sub("&", "r", typename)
|
|
# Identifers with double underscores are reserved to the C++
|
|
# implementation.
|
|
typename = re.sub("_+", "_", typename)
|
|
# Avoid ending the function name with underscore, for
|
|
# cosmetics. Trailing underscores appear after munging types
|
|
# with template parameters, like e.g. "foo<int>".
|
|
typename = re.sub("_+$", "", typename)
|
|
return "target_debug_print_" + typename
|
|
|
|
|
|
# Write out a debug method.
|
|
def write_debugmethod(f, content, name, return_type, argtypes):
|
|
debugname = "debug_target::" + name
|
|
names = write_function_header(f, False, debugname, return_type, argtypes)
|
|
if return_type != "void":
|
|
print(" " + return_type + " result;", file=f)
|
|
print(
|
|
' gdb_printf (gdb_stdlog, "-> %s->'
|
|
+ name
|
|
+ ' (...)\\n", this->beneath ()->shortname ());',
|
|
file=f,
|
|
)
|
|
|
|
# Delegate to the beneath target.
|
|
print(" ", file=f, end="")
|
|
if return_type != "void":
|
|
print("result = ", file=f, end="")
|
|
print("this->beneath ()->" + name + " (", file=f, end="")
|
|
print(", ".join(names), file=f, end="")
|
|
print(");", file=f)
|
|
|
|
# Now print the arguments.
|
|
print(
|
|
' gdb_printf (gdb_stdlog, "<- %s->'
|
|
+ name
|
|
+ ' (", this->beneath ()->shortname ());',
|
|
file=f,
|
|
)
|
|
for i in range(len(argtypes)):
|
|
if i > 0:
|
|
print(' gdb_puts (", ", gdb_stdlog);', file=f)
|
|
printer = munge_type(argtypes[i])
|
|
print(" " + printer + " (" + names[i] + ");", file=f)
|
|
if return_type != "void":
|
|
print(' gdb_puts (") = ", gdb_stdlog);', file=f)
|
|
printer = munge_type(return_type)
|
|
print(" " + printer + " (result);", file=f)
|
|
print(' gdb_puts ("\\n", gdb_stdlog);', file=f)
|
|
else:
|
|
print(' gdb_puts (")\\n", gdb_stdlog);', file=f)
|
|
|
|
if return_type != "void":
|
|
print(" return result;", file=f)
|
|
|
|
print("}\n", file=f)
|
|
|
|
|
|
def print_class(f, class_name, delegators, entries):
|
|
print("struct " + class_name + " : public target_ops", file=f)
|
|
print("{", file=f)
|
|
print(" const target_info &info () const override;", file=f)
|
|
print("", file=f)
|
|
print(" strata stratum () const override;", file=f)
|
|
print("", file=f)
|
|
|
|
for name in delegators:
|
|
return_type = entries[name]["return_type"]
|
|
argtypes = entries[name]["argtypes"]
|
|
print(" ", file=f, end="")
|
|
write_declaration(f, name, return_type, argtypes)
|
|
|
|
print("};\n", file=f)
|
|
|
|
|
|
delegators = []
|
|
entries = {}
|
|
for current_line in scan_target_h():
|
|
# See comments in scan_target_h. Here we strip away the leading
|
|
# and trailing whitespace.
|
|
current_line = current_line.strip()
|
|
m = METHOD.match(current_line)
|
|
if not m:
|
|
continue
|
|
data = m.groupdict()
|
|
data["argtypes"] = parse_argtypes(data["args"])
|
|
data["return_type"] = data["return_type"].strip()
|
|
entries[data["name"]] = data
|
|
|
|
delegators.append(data["name"])
|
|
|
|
with open("target-delegates.c", "w") as f:
|
|
print(
|
|
gdbcopyright.copyright(
|
|
"make-target-delegates.py", "Boilerplate target methods for GDB"
|
|
),
|
|
file=f,
|
|
)
|
|
print_class(f, "dummy_target", delegators, entries)
|
|
print_class(f, "debug_target", delegators, entries)
|
|
|
|
for name in delegators:
|
|
tdefault = entries[name]["default_arg"]
|
|
return_type = entries[name]["return_type"]
|
|
style = entries[name]["style"]
|
|
argtypes = entries[name]["argtypes"]
|
|
|
|
write_delegator(f, name, return_type, argtypes)
|
|
write_tdefault(f, tdefault, style, name, return_type, argtypes)
|
|
write_debugmethod(f, tdefault, name, return_type, argtypes)
|