
This commit ensures that the 'invalid' property of all components is either True, False, or a string. Additionally, this commit allows a component to have both a predicate and for the 'invalid' property to be a string. Removing the option for 'invalid' to be None allows us to simplify the algorithms in gdbarch.py a little. Allowing a component to have both a predicate and an 'invalid' string means that we can validate the value that a tdep sets into a field, but also allow a predicate to ensure that the field has changed from the default. This functionality isn't going to be used in this series, but I have tested it locally and believe that it would work, and this might make it easier for others to add new components in the future. In gdbarch_types.py, I've updated the type annotations to show that the 'invalid' field should not be None, and I've changed the default for this field from None to False. The change to using False as the default is temporary. Later in this series I'm going to change the default to True, but we need more fixes before that can be done. Additionally, in gdbarch_types.py I've removed an assert from Component.get_predicate. This assert ensured that we didn't have the predicate field set to True and the invalid field set to a string. However, no component currently uses this configuration, and after this commit, that combination is now supported, so the assert can be removed. As a consequence of the gdbarch_types.py changes we see some additional comments generated in gdbarch.c about verification being skipped due to the invalid field being False. This comment is inline with plenty of other getters that also have a similar comment. Plenty of the getters do have validation, so I think it is reasonable to have a comment noting that the validation has been skipped for a specific reason, rather than due to some bug. In gdbarch_components.py I've had to add 'invalid=True' for two components: gcore_bfd_target and max_insn_length, without this the validation in the gdbarch getter would disappear. And in gdbarch.py I've reworked the logic for generating the verify_gdbarch function, and for generating the getter functions. The logic for generating the getter functions is still not ideal, I ended up having to add this additional logic block: elif c.postdefault is not None and c.predefault is not None: print(" /* Check variable changed from pre-default. */", file=f) print(f" gdb_assert (gdbarch->{c.name} != {c.predefault});", file=f) which was needed to ensure we continued to generate the same code as before, without this the fact that invalid is now False when it would previously have been None, meant that we dropped the gdb_assert in favour of a comment like: print(f" /* Skip verify of {c.name}, invalid_p == 0 */", file=f) which is clearly not a good change. We could potentially look at improving this in a later commit, but I don't plan to do that in this series. Approved-By: Simon Marchi <simon.marchi@efficios.com>
183 lines
5.5 KiB
Python
Executable file
183 lines
5.5 KiB
Python
Executable file
# Architecture commands for GDB, the GNU debugger.
|
|
#
|
|
# Copyright (C) 1998-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/>.
|
|
|
|
from typing import List, Optional, Tuple, Union
|
|
|
|
|
|
def join_type_and_name(t: str, n: str):
|
|
"Combine the type T and the name N into a C declaration."
|
|
if t.endswith("*") or t.endswith("&"):
|
|
return t + n
|
|
else:
|
|
return t + " " + n
|
|
|
|
|
|
def join_params(params: List[Tuple[str, str]]):
|
|
"""Given a sequence of (TYPE, NAME) pairs, generate a comma-separated
|
|
list of declarations."""
|
|
return ", ".join([join_type_and_name(p[0], p[1]) for p in params])
|
|
|
|
|
|
class Component:
|
|
"Base class for all components."
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
type: str,
|
|
printer: Optional[str] = None,
|
|
comment: Optional[str] = None,
|
|
predicate: bool = False,
|
|
predefault: Optional[str] = None,
|
|
postdefault: Optional[str] = None,
|
|
invalid: Union[bool, str] = False,
|
|
params: Optional[List[Tuple[str, str]]] = None,
|
|
param_checks: Optional[List[str]] = None,
|
|
result_checks: Optional[List[str]] = None,
|
|
implement: bool = True,
|
|
):
|
|
self.name = name
|
|
self.type = type
|
|
self.printer = printer
|
|
self.comment = comment
|
|
self.predicate = predicate
|
|
self.predefault = predefault
|
|
self.postdefault = postdefault
|
|
self.invalid = invalid
|
|
self.params = params or []
|
|
self.param_checks = param_checks
|
|
self.result_checks = result_checks
|
|
self.implement = implement
|
|
|
|
components.append(self)
|
|
|
|
# It doesn't make sense to have a check of the result value
|
|
# for a function or method with void return type.
|
|
if self.type == "void" and self.result_checks:
|
|
raise Exception("can't have result checks with a void return type")
|
|
|
|
def get_predicate(self):
|
|
"Return the expression used for validity checking."
|
|
if self.predefault:
|
|
predicate = f"gdbarch->{self.name} != {self.predefault}"
|
|
else:
|
|
predicate = f"gdbarch->{self.name} != NULL"
|
|
return predicate
|
|
|
|
|
|
class Info(Component):
|
|
"An Info component is copied from the gdbarch_info."
|
|
|
|
|
|
class Value(Component):
|
|
"A Value component is just a data member."
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
name: str,
|
|
type: str,
|
|
comment: Optional[str] = None,
|
|
predicate: bool = False,
|
|
predefault: Optional[str] = None,
|
|
postdefault: Optional[str] = None,
|
|
invalid: Union[bool, str] = False,
|
|
printer: Optional[str] = None,
|
|
):
|
|
super().__init__(
|
|
comment=comment,
|
|
name=name,
|
|
type=type,
|
|
predicate=predicate,
|
|
predefault=predefault,
|
|
postdefault=postdefault,
|
|
invalid=invalid,
|
|
printer=printer,
|
|
)
|
|
|
|
|
|
class Function(Component):
|
|
"A Function component is a function pointer member."
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
name: str,
|
|
type: str,
|
|
params: List[Tuple[str, str]],
|
|
comment: Optional[str] = None,
|
|
predicate: bool = False,
|
|
predefault: Optional[str] = None,
|
|
postdefault: Optional[str] = None,
|
|
invalid: Union[bool, str] = False,
|
|
printer: Optional[str] = None,
|
|
param_checks: Optional[List[str]] = None,
|
|
result_checks: Optional[List[str]] = None,
|
|
implement: bool = True,
|
|
):
|
|
super().__init__(
|
|
comment=comment,
|
|
name=name,
|
|
type=type,
|
|
predicate=predicate,
|
|
predefault=predefault,
|
|
postdefault=postdefault,
|
|
invalid=invalid,
|
|
printer=printer,
|
|
params=params,
|
|
param_checks=param_checks,
|
|
result_checks=result_checks,
|
|
implement=implement,
|
|
)
|
|
|
|
def ftype(self):
|
|
"Return the name of the function typedef to use."
|
|
return f"gdbarch_{self.name}_ftype"
|
|
|
|
def param_list(self):
|
|
"Return the formal parameter list as a string."
|
|
return join_params(self.params)
|
|
|
|
def set_list(self):
|
|
"""Return the formal parameter list of the caller function,
|
|
as a string. This list includes the gdbarch."""
|
|
arch_arg = ("struct gdbarch *", "gdbarch")
|
|
arch_tuple = [arch_arg]
|
|
return join_params(arch_tuple + list(self.params))
|
|
|
|
def actuals(self):
|
|
"Return the actual parameters to forward, as a string."
|
|
return ", ".join([p[1] for p in self.params])
|
|
|
|
|
|
class Method(Function):
|
|
"A Method is like a Function but passes the gdbarch through."
|
|
|
|
def param_list(self):
|
|
"See superclass."
|
|
return self.set_list()
|
|
|
|
def actuals(self):
|
|
"See superclass."
|
|
result = ["gdbarch"] + [p[1] for p in self.params]
|
|
return ", ".join(result)
|
|
|
|
|
|
# All the components created in gdbarch-components.py.
|
|
components: List[Component] = []
|