123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- #!/usr/bin/env python3
- # Architecture commands for GDB, the GNU debugger.
- #
- # Copyright (C) 1998-2022 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/>.
- import textwrap
- import gdbcopyright
- # All the components created in gdbarch-components.py.
- components = []
- def join_type_and_name(t, n):
- "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):
- """Given a sequence of (TYPE, NAME) pairs, generate a comma-separated
- list of declarations."""
- params = [join_type_and_name(p[0], p[1]) for p in params]
- return ", ".join(params)
- class _Component:
- "Base class for all components."
- def __init__(self, **kwargs):
- for key in kwargs:
- setattr(self, key, kwargs[key])
- components.append(self)
- def get_predicate(self):
- "Return the expression used for validity checking."
- assert self.predicate and not isinstance(self.invalid, str)
- if self.predefault:
- predicate = f"gdbarch->{self.name} != {self.predefault}"
- elif isinstance(c, Value):
- predicate = f"gdbarch->{self.name} != 0"
- else:
- predicate = f"gdbarch->{self.name} != NULL"
- return predicate
- class Info(_Component):
- "An Info component is copied from the gdbarch_info."
- def __init__(self, *, name, type, printer=None):
- super().__init__(name=name, type=type, printer=printer)
- # This little hack makes the generator a bit simpler.
- self.predicate = None
- class Value(_Component):
- "A Value component is just a data member."
- def __init__(
- self,
- *,
- name,
- type,
- comment=None,
- predicate=None,
- predefault=None,
- postdefault=None,
- invalid=None,
- printer=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,
- type,
- params,
- comment=None,
- predicate=None,
- predefault=None,
- postdefault=None,
- invalid=None,
- printer=None,
- ):
- super().__init__(
- comment=comment,
- name=name,
- type=type,
- predicate=predicate,
- predefault=predefault,
- postdefault=postdefault,
- invalid=invalid,
- printer=printer,
- params=params,
- )
- 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)
- # Read the components.
- with open("gdbarch-components.py") as fd:
- exec(fd.read())
- copyright = gdbcopyright.copyright(
- "gdbarch.py", "Dynamic architecture support for GDB, the GNU debugger."
- )
- def info(c):
- "Filter function to only allow Info components."
- return type(c) is Info
- def not_info(c):
- "Filter function to omit Info components."
- return type(c) is not Info
- with open("gdbarch-gen.h", "w") as f:
- print(copyright, file=f)
- print(file=f)
- print(file=f)
- print("/* The following are pre-initialized by GDBARCH. */", file=f)
- # Do Info components first.
- for c in filter(info, components):
- print(file=f)
- print(
- f"""extern {c.type} gdbarch_{c.name} (struct gdbarch *gdbarch);
- /* set_gdbarch_{c.name}() - not applicable - pre-initialized. */""",
- file=f,
- )
- print(file=f)
- print(file=f)
- print("/* The following are initialized by the target dependent code. */", file=f)
- # Generate decls for accessors, setters, and predicates for all
- # non-Info components.
- for c in filter(not_info, components):
- if c.comment:
- print(file=f)
- comment = c.comment.split("\n")
- if comment[0] == "":
- comment = comment[1:]
- if comment[-1] == "":
- comment = comment[:-1]
- print("/* ", file=f, end="")
- print(comment[0], file=f, end="")
- if len(comment) > 1:
- print(file=f)
- print(
- textwrap.indent("\n".join(comment[1:]), prefix=" "),
- end="",
- file=f,
- )
- print(" */", file=f)
- if c.predicate:
- print(file=f)
- print(f"extern bool gdbarch_{c.name}_p (struct gdbarch *gdbarch);", file=f)
- print(file=f)
- if isinstance(c, Value):
- print(
- f"extern {c.type} gdbarch_{c.name} (struct gdbarch *gdbarch);",
- file=f,
- )
- print(
- f"extern void set_gdbarch_{c.name} (struct gdbarch *gdbarch, {c.type} {c.name});",
- file=f,
- )
- else:
- assert isinstance(c, Function)
- print(
- f"typedef {c.type} ({c.ftype()}) ({c.param_list()});",
- file=f,
- )
- print(
- f"extern {c.type} gdbarch_{c.name} ({c.set_list()});",
- file=f,
- )
- print(
- f"extern void set_gdbarch_{c.name} (struct gdbarch *gdbarch, {c.ftype()} *{c.name});",
- file=f,
- )
- with open("gdbarch.c", "w") as f:
- print(copyright, file=f)
- print(file=f)
- print("/* Maintain the struct gdbarch object. */", file=f)
- print(file=f)
- #
- # The struct definition body.
- #
- print("struct gdbarch", file=f)
- print("{", file=f)
- print(" /* Has this architecture been fully initialized? */", file=f)
- print(" int initialized_p;", file=f)
- print(file=f)
- print(" /* An obstack bound to the lifetime of the architecture. */", file=f)
- print(" struct obstack *obstack;", file=f)
- print(file=f)
- print(" /* basic architectural information. */", file=f)
- for c in filter(info, components):
- print(f" {c.type} {c.name};", file=f)
- print(file=f)
- print(" /* target specific vector. */", file=f)
- print(" struct gdbarch_tdep *tdep;", file=f)
- print(" gdbarch_dump_tdep_ftype *dump_tdep;", file=f)
- print(file=f)
- print(" /* per-architecture data-pointers. */", file=f)
- print(" unsigned nr_data;", file=f)
- print(" void **data;", file=f)
- print(file=f)
- for c in filter(not_info, components):
- if isinstance(c, Value):
- print(f" {c.type} {c.name};", file=f)
- else:
- assert isinstance(c, Function)
- print(f" gdbarch_{c.name}_ftype *{c.name};", file=f)
- print("};", file=f)
- print(file=f)
- #
- # Initialization.
- #
- print("/* Create a new ``struct gdbarch'' based on information provided by", file=f)
- print(" ``struct gdbarch_info''. */", file=f)
- print(file=f)
- print("struct gdbarch *", file=f)
- print("gdbarch_alloc (const struct gdbarch_info *info,", file=f)
- print(" struct gdbarch_tdep *tdep)", file=f)
- print("{", file=f)
- print(" struct gdbarch *gdbarch;", file=f)
- print("", file=f)
- print(
- " /* Create an obstack for allocating all the per-architecture memory,", file=f
- )
- print(" then use that to allocate the architecture vector. */", file=f)
- print(" struct obstack *obstack = XNEW (struct obstack);", file=f)
- print(" obstack_init (obstack);", file=f)
- print(" gdbarch = XOBNEW (obstack, struct gdbarch);", file=f)
- print(" memset (gdbarch, 0, sizeof (*gdbarch));", file=f)
- print(" gdbarch->obstack = obstack;", file=f)
- print(file=f)
- print(" alloc_gdbarch_data (gdbarch);", file=f)
- print(file=f)
- print(" gdbarch->tdep = tdep;", file=f)
- print(file=f)
- for c in filter(info, components):
- print(f" gdbarch->{c.name} = info->{c.name};", file=f)
- print(file=f)
- print(" /* Force the explicit initialization of these. */", file=f)
- for c in filter(not_info, components):
- if c.predefault and c.predefault != "0":
- print(f" gdbarch->{c.name} = {c.predefault};", file=f)
- print(" /* gdbarch_alloc() */", file=f)
- print(file=f)
- print(" return gdbarch;", file=f)
- print("}", file=f)
- print(file=f)
- print(file=f)
- print(file=f)
- #
- # Post-initialization validation and updating
- #
- print("/* Ensure that all values in a GDBARCH are reasonable. */", file=f)
- print(file=f)
- print("static void", file=f)
- print("verify_gdbarch (struct gdbarch *gdbarch)", file=f)
- print("{", file=f)
- print(" string_file log;", file=f)
- print(file=f)
- print(" /* fundamental */", file=f)
- print(" if (gdbarch->byte_order == BFD_ENDIAN_UNKNOWN)", file=f)
- print(""" log.puts ("\\n\\tbyte-order");""", file=f)
- print(" if (gdbarch->bfd_arch_info == NULL)", file=f)
- print(""" log.puts ("\\n\\tbfd_arch_info");""", file=f)
- print(
- " /* Check those that need to be defined for the given multi-arch level. */",
- file=f,
- )
- for c in filter(not_info, components):
- 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 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)
- 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")
- print(" if (!log.empty ())", file=f)
- print(" internal_error (__FILE__, __LINE__,", file=f)
- print(""" _("verify_gdbarch: the following are invalid ...%s"),""", file=f)
- print(" log.c_str ());", file=f)
- print("}", file=f)
- print(file=f)
- print(file=f)
- #
- # Dumping.
- #
- print("/* Print out the details of the current architecture. */", file=f)
- print(file=f)
- print("void", file=f)
- print("gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)", file=f)
- print("{", file=f)
- print(""" const char *gdb_nm_file = "<not-defined>";""", file=f)
- print(file=f)
- print("#if defined (GDB_NM_FILE)", file=f)
- print(" gdb_nm_file = GDB_NM_FILE;", file=f)
- print("#endif", file=f)
- print(" gdb_printf (file,", file=f)
- print(""" "gdbarch_dump: GDB_NM_FILE = %s\\n",""", file=f)
- print(" gdb_nm_file);", file=f)
- for c in components:
- if c.predicate:
- print(" gdb_printf (file,", file=f)
- print(
- f""" "gdbarch_dump: gdbarch_{c.name}_p() = %d\\n",""",
- file=f,
- )
- print(f" gdbarch_{c.name}_p (gdbarch));", file=f)
- if isinstance(c, Function):
- print(" gdb_printf (file,", file=f)
- print(
- f""" "gdbarch_dump: {c.name} = <%s>\\n",""", file=f
- )
- print(
- f" host_address_to_string (gdbarch->{c.name}));",
- file=f,
- )
- else:
- if c.printer:
- printer = c.printer
- elif c.type == "CORE_ADDR":
- printer = f"core_addr_to_string_nz (gdbarch->{c.name})"
- else:
- printer = f"plongest (gdbarch->{c.name})"
- print(" gdb_printf (file,", file=f)
- print(
- f""" "gdbarch_dump: {c.name} = %s\\n",""", file=f
- )
- print(f" {printer});", file=f)
- print(" if (gdbarch->dump_tdep != NULL)", file=f)
- print(" gdbarch->dump_tdep (gdbarch, file);", file=f)
- print("}", file=f)
- print(file=f)
- #
- # Bodies of setter, accessor, and predicate functions.
- #
- for c in components:
- if c.predicate:
- print(file=f)
- print("bool", file=f)
- print(f"gdbarch_{c.name}_p (struct gdbarch *gdbarch)", file=f)
- print("{", file=f)
- print(" gdb_assert (gdbarch != NULL);", file=f)
- print(f" return {c.get_predicate()};", file=f)
- print("}", file=f)
- if isinstance(c, Function):
- print(file=f)
- print(f"{c.type}", file=f)
- print(f"gdbarch_{c.name} ({c.set_list()})", file=f)
- print("{", file=f)
- print(" gdb_assert (gdbarch != NULL);", file=f)
- print(f" gdb_assert (gdbarch->{c.name} != NULL);", file=f)
- if c.predicate and c.predefault:
- # Allow a call to a function with a predicate.
- print(
- f" /* Do not check predicate: {c.get_predicate()}, allow call. */",
- file=f,
- )
- print(" if (gdbarch_debug >= 2)", file=f)
- print(
- f""" gdb_printf (gdb_stdlog, "gdbarch_{c.name} called\\n");""",
- file=f,
- )
- print(" ", file=f, end="")
- if c.type != "void":
- print("return ", file=f, end="")
- print(f"gdbarch->{c.name} ({c.actuals()});", file=f)
- print("}", file=f)
- print(file=f)
- print("void", file=f)
- print(f"set_gdbarch_{c.name} (struct gdbarch *gdbarch,", file=f)
- print(
- f" {' ' * len(c.name)} gdbarch_{c.name}_ftype {c.name})",
- file=f,
- )
- print("{", file=f)
- print(f" gdbarch->{c.name} = {c.name};", file=f)
- print("}", file=f)
- elif isinstance(c, Value):
- print(file=f)
- print(f"{c.type}", file=f)
- print(f"gdbarch_{c.name} (struct gdbarch *gdbarch)", file=f)
- print("{", file=f)
- print(" gdb_assert (gdbarch != NULL);", file=f)
- if c.invalid is False:
- print(f" /* Skip verify of {c.name}, invalid_p == 0 */", file=f)
- elif isinstance(c.invalid, str):
- print(" /* Check variable is valid. */", file=f)
- print(f" gdb_assert (!({c.invalid}));", file=f)
- elif c.predefault:
- print(" /* Check variable changed from pre-default. */", file=f)
- print(f" gdb_assert (gdbarch->{c.name} != {c.predefault});", file=f)
- print(" if (gdbarch_debug >= 2)", file=f)
- print(
- f""" gdb_printf (gdb_stdlog, "gdbarch_{c.name} called\\n");""",
- file=f,
- )
- print(f" return gdbarch->{c.name};", file=f)
- print("}", file=f)
- print(file=f)
- print("void", file=f)
- print(f"set_gdbarch_{c.name} (struct gdbarch *gdbarch,", file=f)
- print(f" {' ' * len(c.name)} {c.type} {c.name})", file=f)
- print("{", file=f)
- print(f" gdbarch->{c.name} = {c.name};", file=f)
- print("}", file=f)
- else:
- assert isinstance(c, Info)
- print(file=f)
- print(f"{c.type}", file=f)
- print(f"gdbarch_{c.name} (struct gdbarch *gdbarch)", file=f)
- print("{", file=f)
- print(" gdb_assert (gdbarch != NULL);", file=f)
- print(" if (gdbarch_debug >= 2)", file=f)
- print(
- f""" gdb_printf (gdb_stdlog, "gdbarch_{c.name} called\\n");""",
- file=f,
- )
- print(f" return gdbarch->{c.name};", file=f)
- print("}", file=f)
|