* reggroups.h, reggroups.c: New files.
* regcache.c: Include "reggroups.h".
(enum regcache_dump_what): Add `regcache_dump_groups'.
(regcache_dump): Contract size of the "Type" column. When
specified, dump the register's groups.
(maintenance_print_register_groups): New function.
(_initialize_regcache): Add command `maint print register-groups'.
* Makefile.in (COMMON_OBS): Add reggroups.o
(SFILES): Add reggroups.c.
(reggroups_h): Define.
(regcache.o, gdbarch.o): Update dependencies.
(reggroups.o): Specify dependencies.
* gdbarch.sh (register_reggroup_p): Add pure multi-arch method.
Add opaque declaration for `struct reggroup' in generated .h file.
Include "reggroups.h" in generated .c file.
gdbarch.h, gdbarch.c: Re-generate.
+2002-11-02 Andrew Cagney <cagney@redhat.com>
+
+ * reggroups.h, reggroups.c: New files.
+ * regcache.c: Include "reggroups.h".
+ (enum regcache_dump_what): Add `regcache_dump_groups'.
+ (regcache_dump): Contract size of the "Type" column. When
+ specified, dump the register's groups.
+ (maintenance_print_register_groups): New function.
+ (_initialize_regcache): Add command `maint print register-groups'.
+ * Makefile.in (COMMON_OBS): Add reggroups.o
+ (SFILES): Add reggroups.c.
+ (reggroups_h): Define.
+ (regcache.o, gdbarch.o): Update dependencies.
+ (reggroups.o): Specify dependencies.
+ * gdbarch.sh (register_reggroup_p): Add pure multi-arch method.
+ Add opaque declaration for `struct reggroup' in generated .h file.
+ Include "reggroups.h" in generated .c file.
+ gdbarch.h, gdbarch.c: Re-generate.
+
2002-11-02 Andrew Cagney <cagney@redhat.com>
* regcache.h (deprecated_read_register_gen): Rename
nlmread.c \
objfiles.c osabi.c \
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
- regcache.c remote.c \
+ regcache.c reggroups.c remote.c \
scm-exp.c scm-lang.c scm-valprint.c serial.c ser-unix.c source.c \
stabsread.c stack.c std-regs.c symfile.c symmisc.c symtab.c \
target.c thread.c top.c tracepoint.c typeprint.c \
ppcnbsd_tdep_h = ppcnbsd-tdep.h
proc_utils_h = proc-utils.h
regcache_h = regcache.h
+reggroups_h = reggroups.h
remote_utils_h = remote-utils.h $(target_h)
remote_h = remote.h
scm_lang_h = scm-lang.h $(scm_tags_h)
nlmread.o serial.o mdebugread.o top.o utils.o \
ui-file.o \
frame.o doublest.o \
- gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o
+ gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
+ reggroups.o
OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
$(gdb_string_h) $(symtab_h) $(frame_h) $(inferior_h) $(breakpoint_h) \
$(gdb_wait_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(gdbthread_h) \
$(annotate_h) $(symfile_h) $(value_h) $(symcat_h) $(floatformat_h) \
- $(gdb_assert_h) $(gdb_string_h) $(gdb_events_h)
+ $(gdb_assert_h) $(gdb_string_h) $(gdb_events_h) $(reggroups_h)
gdbtypes.o: gdbtypes.c $(defs_h) $(gdb_string_h) $(bfd_h) $(symtab_h) \
$(symfile_h) $(objfiles_h) $(gdbtypes_h) $(expression_h) \
$(language_h) $(target_h) $(value_h) $(demangle_h) $(complaints_h) \
ptx4-nat.o: ptx4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(regcache_h) \
$(gregset_h)
regcache.o: regcache.c $(defs_h) $(inferior_h) $(target_h) $(gdbarch_h) \
- $(gdbcmd_h) $(regcache_h) $(gdb_assert_h) $(gdb_string_h) \
- $(gdbcmd_h)
+ $(gdbcmd_h) $(regcache_h) $(reggroups_h) $(gdb_assert_h) \
+ $(gdb_string_h) $(gdbcmd_h)
+reggroups.o: reggroups.c $(defs_h) $(reggroups_h) $(gdbtypes_h) \
+ $(gdb_assert_h) $(regcache_h) $(command_h) $(gdbcmd_h)
remote-array.o: remote-array.c $(defs_h) $(gdbcore_h) $(target_h) \
$(gdb_string_h) $(command_h) $(serial_h) $(monitor_h) \
$(remote_utils_h) $(inferior_h) $(version_h) $(regcache_h)
#include "gdb_assert.h"
#include "gdb_string.h"
#include "gdb-events.h"
+#include "reggroups.h"
/* Static function declarations */
gdbarch_address_class_type_flags_ftype *address_class_type_flags;
gdbarch_address_class_type_flags_to_name_ftype *address_class_type_flags_to_name;
gdbarch_address_class_name_to_type_flags_ftype *address_class_name_to_type_flags;
+ gdbarch_register_reggroup_p_ftype *register_reggroup_p;
};
0,
0,
0,
+ default_register_reggroup_p,
/* startup_gdbarch() */
};
current_gdbarch->elf_make_msymbol_special = default_elf_make_msymbol_special;
current_gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special;
current_gdbarch->name_of_malloc = "malloc";
+ current_gdbarch->register_reggroup_p = default_register_reggroup_p;
/* gdbarch_alloc() */
return current_gdbarch;
/* Skip verify of address_class_type_flags, has predicate */
/* Skip verify of address_class_type_flags_to_name, has predicate */
/* Skip verify of address_class_name_to_type_flags, has predicate */
+ if ((GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+ && (gdbarch->register_reggroup_p == default_register_reggroup_p))
+ fprintf_unfiltered (log, "\n\tregister_reggroup_p");
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
fprintf_unfiltered (file,
"gdbarch_dump: in_function_epilogue_p = 0x%08lx\n",
(long) current_gdbarch->in_function_epilogue_p);
+ if (GDB_MULTI_ARCH)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: register_reggroup_p = 0x%08lx\n",
+ (long) current_gdbarch->register_reggroup_p);
if (GDB_MULTI_ARCH)
fprintf_unfiltered (file,
"gdbarch_dump: pseudo_register_read = 0x%08lx\n",
gdbarch->address_class_name_to_type_flags = address_class_name_to_type_flags;
}
+int
+gdbarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup)
+{
+ gdb_assert (gdbarch != NULL);
+ if (gdbarch->register_reggroup_p == 0)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: gdbarch_register_reggroup_p invalid");
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_register_reggroup_p called\n");
+ return gdbarch->register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
+void
+set_gdbarch_register_reggroup_p (struct gdbarch *gdbarch,
+ gdbarch_register_reggroup_p_ftype register_reggroup_p)
+{
+ gdbarch->register_reggroup_p = register_reggroup_p;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
struct objfile;
struct minimal_symbol;
struct regcache;
+struct reggroup;
extern struct gdbarch *current_gdbarch;
extern int gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch, char *name, int *type_flags_ptr);
extern void set_gdbarch_address_class_name_to_type_flags (struct gdbarch *gdbarch, gdbarch_address_class_name_to_type_flags_ftype *address_class_name_to_type_flags);
+/* Is a register in a group */
+
+typedef int (gdbarch_register_reggroup_p_ftype) (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup);
+extern int gdbarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *reggroup);
+extern void set_gdbarch_register_reggroup_p (struct gdbarch *gdbarch, gdbarch_register_reggroup_p_ftype *register_reggroup_p);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
F:2:ADDRESS_CLASS_TYPE_FLAGS:int:address_class_type_flags:int byte_size, int dwarf2_addr_class:byte_size, dwarf2_addr_class
M:2:ADDRESS_CLASS_TYPE_FLAGS_TO_NAME:char *:address_class_type_flags_to_name:int type_flags:type_flags:
M:2:ADDRESS_CLASS_NAME_TO_TYPE_FLAGS:int:address_class_name_to_type_flags:char *name, int *type_flags_ptr:name, type_flags_ptr
+# Is a register in a group
+m:::int:register_reggroup_p:int regnum, struct reggroup *reggroup:regnum, reggroup:::default_register_reggroup_p
EOF
}
struct objfile;
struct minimal_symbol;
struct regcache;
+struct reggroup;
extern struct gdbarch *current_gdbarch;
#include "gdb_assert.h"
#include "gdb_string.h"
#include "gdb-events.h"
+#include "reggroups.h"
/* Static function declarations */
#include "gdbarch.h"
#include "gdbcmd.h"
#include "regcache.h"
+#include "reggroups.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "gdbcmd.h" /* For maintenanceprintlist. */
enum regcache_dump_what
{
- regcache_dump_none, regcache_dump_raw, regcache_dump_cooked
+ regcache_dump_none, regcache_dump_raw, regcache_dump_cooked, regcache_dump_groups
};
static void
enum regcache_dump_what what_to_dump)
{
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ struct gdbarch *gdbarch = regcache->descr->gdbarch;
+ struct reggroup *const *groups = reggroups (gdbarch);
int regnum;
int footnote_nr = 0;
int footnote_register_size = 0;
}
/* Type. */
- if (regnum < 0)
- fprintf_unfiltered (file, " %-20s", "Type");
- else
- {
- static const char blt[] = "builtin_type";
- const char *t = TYPE_NAME (register_type (regcache->descr->gdbarch,
- regnum));
- if (t == NULL)
- {
- char *n;
- if (!footnote_register_type_name_null)
- footnote_register_type_name_null = ++footnote_nr;
- xasprintf (&n, "*%d", footnote_register_type_name_null);
- make_cleanup (xfree, n);
- t = n;
- }
- /* Chop a leading builtin_type. */
- if (strncmp (t, blt, strlen (blt)) == 0)
- t += strlen (blt);
- fprintf_unfiltered (file, " %-20s", t);
- }
+ {
+ const char *t;
+ if (regnum < 0)
+ t = "Type";
+ else
+ {
+ static const char blt[] = "builtin_type";
+ t = TYPE_NAME (register_type (regcache->descr->gdbarch, regnum));
+ if (t == NULL)
+ {
+ char *n;
+ if (!footnote_register_type_name_null)
+ footnote_register_type_name_null = ++footnote_nr;
+ xasprintf (&n, "*%d", footnote_register_type_name_null);
+ make_cleanup (xfree, n);
+ t = n;
+ }
+ /* Chop a leading builtin_type. */
+ if (strncmp (t, blt, strlen (blt)) == 0)
+ t += strlen (blt);
+ }
+ fprintf_unfiltered (file, " %-15s", t);
+ }
+
+ /* Leading space always present. */
+ fprintf_unfiltered (file, " ");
/* Value, raw. */
if (what_to_dump == regcache_dump_raw)
}
}
+ /* Group members. */
+ if (what_to_dump == regcache_dump_groups)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Groups");
+ else
+ {
+ int i;
+ const char *sep = "";
+ for (i = 0; groups[i] != NULL; i++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, groups[i]))
+ {
+ fprintf_unfiltered (file, "%s%s", sep, reggroup_name (groups[i]));
+ sep = ",";
+ }
+ }
+ }
+ }
+
fprintf_unfiltered (file, "\n");
}
regcache_print (args, regcache_dump_cooked);
}
+static void
+maintenance_print_register_groups (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_groups);
+}
+
void
_initialize_regcache (void)
{
add_cmd ("cooked-registers", class_maintenance,
maintenance_print_cooked_registers,
"Print the internal register configuration including cooked values.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("register-groups", class_maintenance,
+ maintenance_print_register_groups,
+ "Print the internal register configuration including each register's group.\
Takes an optional file parameter.",
&maintenanceprintlist);
--- /dev/null
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "reggroups.h"
+#include "gdbtypes.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "command.h"
+#include "gdbcmd.h" /* For maintenanceprintlist. */
+
+/* Individual register groups. */
+
+struct reggroup
+{
+ const char *name;
+ enum reggroup_type type;
+};
+
+struct reggroup *
+reggroup_new (const char *name, enum reggroup_type type)
+{
+ struct reggroup *group = XMALLOC (struct reggroup);
+ group->name = name;
+ group->type = type;
+ return group;
+}
+
+/* Register group attributes. */
+
+const char *
+reggroup_name (struct reggroup *group)
+{
+ return group->name;
+}
+
+enum reggroup_type
+reggroup_type (struct reggroup *group)
+{
+ return group->type;
+}
+
+/* All the groups for a given architecture. */
+
+struct reggroups
+{
+ int nr_group;
+ struct reggroup **group;
+};
+
+static struct gdbarch_data *reggroups_data;
+
+static void *
+reggroups_init (struct gdbarch *gdbarch)
+{
+ struct reggroups *groups = XMALLOC (struct reggroups);
+ groups->nr_group = 0;
+ groups->group = NULL;
+ return groups;
+}
+
+static void
+reggroups_free (struct gdbarch *gdbarch, void *data)
+{
+ struct reggroups *groups = data;
+ xfree (groups->group);
+ xfree (groups);
+}
+
+/* Add a register group (with attribute values) to the pre-defined
+ list. This function can be called during architecture
+ initialization and hence needs to handle NULL architecture groups. */
+
+static void
+add_group (struct reggroups *groups, struct reggroup *group)
+{
+ gdb_assert (group != NULL);
+ groups->nr_group++;
+ groups->group = xrealloc (groups->group, (sizeof (struct reggroup *)
+ * (groups->nr_group + 1)));
+ groups->group[groups->nr_group - 1] = group;
+ groups->group[groups->nr_group] = NULL;
+}
+
+void
+reggroup_add (struct gdbarch *gdbarch, struct reggroup *group)
+{
+ struct reggroups *groups = gdbarch_data (gdbarch, reggroups_data);
+ if (groups == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ groups = reggroups_init (gdbarch);
+ set_gdbarch_data (gdbarch, reggroups_data, groups);
+ }
+ add_group (groups, group);
+}
+
+/* The register groups for the current architecture. Mumble something
+ about the lifetime of the buffer.... */
+
+static struct reggroups *default_groups;
+
+struct reggroup * const*
+reggroups (struct gdbarch *gdbarch)
+{
+ struct reggroups *groups = gdbarch_data (gdbarch, reggroups_data);
+ /* Don't allow this function to be called during architecture
+ creation. */
+ gdb_assert (groups != NULL);
+ if (groups->group == NULL)
+ return default_groups->group;
+ else
+ return groups->group;
+}
+
+/* Is REGNUM a member of REGGROUP? */
+int
+default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ int vector_p;
+ int float_p;
+ int raw_p;
+ if (REGISTER_NAME (regnum) == NULL
+ || *REGISTER_NAME (regnum) == '\0')
+ return 0;
+ if (group == all_reggroup)
+ return 1;
+ vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
+ float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
+ raw_p = regnum < gdbarch_num_regs (gdbarch);
+ if (group == float_reggroup)
+ return float_p;
+ if (group == vector_reggroup)
+ return vector_p;
+ if (group == general_reggroup)
+ return (!vector_p && !float_p);
+ if (group == save_reggroup || group == restore_reggroup)
+ return raw_p;
+ return 0;
+}
+
+/* Dump out a table of register groups for the current architecture. */
+
+static void
+reggroups_dump (struct gdbarch *gdbarch, struct ui_file *file)
+{
+ struct reggroup *const *groups = reggroups (gdbarch);
+ int i = -1;
+ do
+ {
+ /* Group name. */
+ {
+ const char *name;
+ if (i < 0)
+ name = "Group";
+ else
+ name = reggroup_name (groups[i]);
+ fprintf_unfiltered (file, " %-10s", name);
+ }
+
+ /* Group type. */
+ {
+ const char *type;
+ if (i < 0)
+ type = "Type";
+ else
+ {
+ switch (reggroup_type (groups[i]))
+ {
+ case USER_REGGROUP:
+ type = "user";
+ break;
+ case INTERNAL_REGGROUP:
+ type = "internal";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+ fprintf_unfiltered (file, " %-10s", type);
+ }
+
+ /* Note: If you change this, be sure to also update the
+ documentation. */
+
+ fprintf_unfiltered (file, "\n");
+ i++;
+ }
+ while (groups[i] != NULL);
+}
+
+static void
+maintenance_print_reggroups (char *args, int from_tty)
+{
+ if (args == NULL)
+ reggroups_dump (current_gdbarch, gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print reggroups");
+ reggroups_dump (current_gdbarch, file);
+ ui_file_delete (file);
+ }
+}
+
+/* Pre-defined register groups. */
+static struct reggroup general_group = { "general", USER_REGGROUP };
+static struct reggroup float_group = { "float", USER_REGGROUP };
+static struct reggroup system_group = { "system", USER_REGGROUP };
+static struct reggroup vector_group = { "vector", USER_REGGROUP };
+static struct reggroup all_group = { "all", USER_REGGROUP };
+static struct reggroup save_group = { "save", INTERNAL_REGGROUP };
+static struct reggroup restore_group = { "restore", INTERNAL_REGGROUP };
+
+struct reggroup *const general_reggroup = &general_group;
+struct reggroup *const float_reggroup = &float_group;
+struct reggroup *const system_reggroup = &system_group;
+struct reggroup *const vector_reggroup = &vector_group;
+struct reggroup *const all_reggroup = &all_group;
+struct reggroup *const save_reggroup = &save_group;
+struct reggroup *const restore_reggroup = &restore_group;
+
+void
+_initialize_reggroup (void)
+{
+ reggroups_data = register_gdbarch_data (reggroups_init, reggroups_free);
+
+ /* The pre-defined list of groups. */
+ default_groups = reggroups_init (NULL);
+ add_group (default_groups, general_reggroup);
+ add_group (default_groups, float_reggroup);
+ add_group (default_groups, system_reggroup);
+ add_group (default_groups, vector_reggroup);
+ add_group (default_groups, all_reggroup);
+ add_group (default_groups, save_reggroup);
+ add_group (default_groups, restore_reggroup);
+
+
+ add_cmd ("reggroups", class_maintenance,
+ maintenance_print_reggroups, "\
+Print the internal register group names.\n\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
+}
--- /dev/null
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef REGGROUPS_H
+#define REGGROUPS_H
+
+struct gdbarch;
+struct reggroup;
+
+enum reggroup_type { USER_REGGROUP, INTERNAL_REGGROUP };
+
+/* Pre-defined, user visible, register groups. */
+extern struct reggroup *const general_reggroup;
+extern struct reggroup *const float_reggroup;
+extern struct reggroup *const system_reggroup;
+extern struct reggroup *const vector_reggroup;
+extern struct reggroup *const all_reggroup;
+
+/* Pre-defined, internal, register groups. */
+extern struct reggroup *const save_reggroup;
+extern struct reggroup *const restore_reggroup;
+
+/* Create a new local register group. */
+extern struct reggroup *reggroup_new (const char *name,
+ enum reggroup_type type);
+
+/* Add a register group (with attribute values) to the pre-defined list. */
+extern void reggroup_add (struct gdbarch *gdbarch, struct reggroup *group);
+
+/* Register group attributes. */
+extern const char *reggroup_name (struct reggroup *reggroup);
+extern enum reggroup_type reggroup_type (struct reggroup *reggroup);
+
+/* The register groups for the current architecture. */
+extern struct reggroup *const *reggroups (struct gdbarch *gdbarch);
+
+/* Is REGNUM a member of REGGROUP? */
+extern int default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *reggroup);
+
+#endif