[PATCHv3,3/9] gdb/gdbarch: split postdefault setup from invalid check in gdbarch.py

Message ID fa37c12a5e33ddcf1e1eb7848657e3eeab787521.1678473293.git.aburgess@redhat.com
State New
Headers
Series Add new gdbarch::displaced_step_buffer_length field |

Commit Message

Andrew Burgess March 10, 2023, 6:43 p.m. UTC
  Restructure how gdbarch.py generates the verify_gdbarch function.
Previously the postdefault handling was bundled together with the
validation.  This means that a field can't have both a postdefault,
and set its invalid attribute to a string.

This doesn't seem reasonable to me, I see no reason why a field can't
have both a postdefault (used when the tdep doesn't set the field),
and an invalid expression, which can be used to validate the value
that a tdep might set.

In this commit I restructure the verify_gdbarch generation code to
allow the above, there is no change in the actual generated code in
this commit, that will come in later commit.
---
 gdb/gdbarch.py            | 42 +++++++++++++++++++++++++--------------
 gdb/gdbarch_components.py | 40 ++++++++++++++++---------------------
 2 files changed, 44 insertions(+), 38 deletions(-)
  

Patch

diff --git a/gdb/gdbarch.py b/gdb/gdbarch.py
index 93b1e8bf84e..5437c827f34 100755
--- a/gdb/gdbarch.py
+++ b/gdb/gdbarch.py
@@ -203,35 +203,47 @@  with open("gdbarch.c", "w") as f:
         file=f,
     )
     for c in filter(not_info, components):
+        # An opportunity to write in the 'postdefault' value.  We
+        # change field's value to the postdefault if its current value
+        # is not different to the initial value of the field.
+        if c.postdefault is not None:
+            init_value = c.predefault or "0"
+            print(f"  if (gdbarch->{c.name} == {init_value})", file=f)
+            print(f"    gdbarch->{c.name} = {c.postdefault};", file=f)
+
+        # Now validate the value.
         if c.invalid is False:
             print(f"  /* Skip verify of {c.name}, invalid_p == 0 */", file=f)
         elif c.predicate:
             print(f"  /* Skip verify of {c.name}, has predicate.  */", file=f)
-        elif isinstance(c.invalid, str) and c.postdefault is not None:
-            print(f"  if ({c.invalid})", file=f)
-            print(f"    gdbarch->{c.name} = {c.postdefault};", file=f)
-        elif c.predefault is not None and c.postdefault is not None:
-            print(f"  if (gdbarch->{c.name} == {c.predefault})", file=f)
-            print(f"    gdbarch->{c.name} = {c.postdefault};", file=f)
-        elif c.postdefault is not None:
-            print(f"  if (gdbarch->{c.name} == 0)", file=f)
-            print(f"    gdbarch->{c.name} = {c.postdefault};", file=f)
+        elif c.invalid is None:
+            # No validation has been requested for this component.
+            pass
         elif isinstance(c.invalid, str):
             print(f"  if ({c.invalid})", file=f)
             print(f"""    log.puts ("\\n\\t{c.name}");""", file=f)
-        elif c.predefault is not None:
-            print(f"  if (gdbarch->{c.name} == {c.predefault})", file=f)
-            print(f"""    log.puts ("\\n\\t{c.name}");""", file=f)
         elif c.invalid is True:
-            print(f"  if (gdbarch->{c.name} == 0)", file=f)
-            print(f"""    log.puts ("\\n\\t{c.name}");""", file=f)
+            if c.postdefault is not None:
+                # This component has its 'invalid' field set to True, but
+                # also has a postdefault.  This makes no sense, the
+                # postdefault will have been applied above, so this field
+                # will not have a zero value.
+                raise Exception(
+                    f"component {c.name} has postdefault and invalid set to True"
+                )
+            else:
+                init_value = c.predefault or "0"
+                print(f"  if (gdbarch->{c.name} == {init_value})", file=f)
+                print(f"""    log.puts ("\\n\\t{c.name}");""", file=f)
         else:
             # We should not allow ourselves to simply do nothing here
             # because no other case applies.  If we end up here then
             # either the input data needs adjusting so one of the
             # above cases matches, or we need additional cases adding
             # here.
-            raise Exception("unhandled case when generating gdbarch validation")
+            raise Exception(
+                f"unhandled case when generating gdbarch validation: {c.name}"
+            )
     print("  if (!log.empty ())", file=f)
     print(
         """    internal_error (_("verify_gdbarch: the following are invalid ...%s"),""",
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index d3dfcfc806f..1f217123216 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -63,34 +63,28 @@ 
 # * "predefault", "postdefault", and "invalid" - These are used for
 # the initialization and verification steps:
 #
-# A gdbarch is zero-initialized.  Then, if a field has a pre-default,
-# the field is set to that value.  After initialization is complete
-# (that is, after the tdep code has a chance to change the settings),
-# the post-initialization step is done.
+# A gdbarch is zero-initialized.  Then, if a field has a "predefault",
+# the field is set to that value.  This becomes the field's initial
+# value.
 #
-# There is a generic algorithm to generate a "validation function" for
-# all fields.  If the field has an "invalid" attribute with a string
-# value, then this string is the expression (note that a string-valued
-# "invalid" and "predicate" are mutually exclusive; and the case where
-# invalid is True means to ignore this field and instead use the
-# default checking that is about to be described).  Otherwise, if
-# there is a "predefault", then the field is valid if it differs from
-# the predefault.  Otherwise, the check is done against 0 (really NULL
-# for function pointers, but same idea).
-#
-# In post-initialization / validation, there are several cases.
+# After initialization is complete (that is, after the tdep code has a
+# chance to change the settings), the post-initialization step is
+# done.
 #
-# * If "invalid" is False, or if the field specifies "predicate",
-# validation is skipped.  Otherwise, a validation step is emitted.
+# If the field still has its initial value (see above), and the field
+# has a "postdefault", then the field is set to this value.
 #
-# * Otherwise, the validity is checked using the usual validation
-# function (see above).  If the field is considered valid, nothing is
-# done.
+# After the possible "postdefault" assignment, validation is
+# performed for fields that don't have a "predicate".
 #
-# * Otherwise, the field's value is invalid.  If there is a
-# "postdefault", then the field is assigned that value.
+# If the field has an "invalid" attribute with a string value, then
+# this string is the expression that should evaluate to true when the
+# field is invalid.
 #
-# * Otherwise, the gdbarch will fail validation and gdb will crash.
+# Otherwise, if "invalid" is True, then the generic validation
+# function is used: the field is considered invalid it still contains
+# its default value.  This validation is what is used within the _p
+# predicate function if the field has "predicate" set to True.
 #
 # Function and Method share:
 #