binutils-gdb/gdb/reggroups.c

273 lines
7.2 KiB
C

/* 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;
/* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
(gdbarch), as not all architectures are multi-arch. */
raw_p = regnum < NUM_REGS;
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;
extern initialize_file_ftype _initialize_reggroup; /* -Wmissing-prototypes */
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);
}