This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[patch/rfa:doc] Make gdbarch_data() on-demand
- From: Andrew Cagney <ac131313 at cygnus dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Sat, 01 Jun 2002 15:41:42 -0400
- Subject: [patch/rfa:doc] Make gdbarch_data() on-demand
Hello,
At present each per-architecture data-pointer is inititalized during
architecture creation. Unfortunatly, due to inter-module dependencies,
the initialization sequence has to be carefully ordered (by tweaking
Makefile.in or other code).
The attached patch alters the behavour of the function gdbarch_data() so
that it, instead, inititalizes the per-architecture data-pointer on-demand.
[Eli, I revised the doco to match this behavour]
Comments? I'll look to check it in, in a few days.
Andrew
PS: This is the start of the merge of the ``struct regcache'' branch.
2002-05-31 Andrew Cagney <ac131313@redhat.com>
* gdbarch.sh (struct gdbarch_data): Add field init_p.
(register_gdbarch_data): Initialize init_p.
(gdbarch_data): Initialize data pointer using the init function.
(init_gdbarch_data): Delete function.
(gdbarch_update_p): Update.
(initialize_non_multiarch): Update.
(struct gdbarch): Add field initialized_p.
* gdbarch.h, gdbarch.c: Re-generate.
Index: doc/ChangeLog
2002-05-31 Andrew Cagney <ac131313@redhat.com>
* gdbint.texinfo (Coding): Add section ``Per-architecture module
data''.
Index: gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.140
diff -u -r1.140 gdbarch.sh
--- gdbarch.sh 29 May 2002 16:39:55 -0000 1.140
+++ gdbarch.sh 1 Jun 2002 19:13:37 -0000
@@ -1082,20 +1082,15 @@
for the reserved data-pointer is returned. That identifer should
be saved in a local static variable.
- The per-architecture data-pointer can be initialized in one of two
- ways: The value can be set explicitly using a call to
- set_gdbarch_data(); the value can be set implicitly using the value
- returned by a non-NULL INIT() callback. INIT(), when non-NULL is
- called after the basic architecture vector has been created.
+ The per-architecture data-pointer is either initialized explicitly
+ (set_gdbarch_data()) or implicitly (by INIT() via a call to
+ gdbarch_data()). FREE() is called to delete either an existing
+ data-poitner overridden by set_gdbarch_data() or when the
+ architecture object is being deleted.
When a previously created architecture is re-selected, the
per-architecture data-pointer for that previous architecture is
- restored. INIT() is not called.
-
- During initialization, multiple assignments of the data-pointer are
- allowed, non-NULL values are deleted by calling FREE(). If the
- architecture is deleted using gdbarch_free() all non-NULL data
- pointers are also deleted using FREE().
+ restored. INIT() is not re-called.
Multiple registrarants for any architecture are allowed (and
strongly encouraged). */
@@ -1249,7 +1244,6 @@
static void verify_gdbarch (struct gdbarch *gdbarch);
static void alloc_gdbarch_data (struct gdbarch *);
-static void init_gdbarch_data (struct gdbarch *);
static void free_gdbarch_data (struct gdbarch *);
static void init_gdbarch_swap (struct gdbarch *);
static void clear_gdbarch_swap (struct gdbarch *);
@@ -1271,6 +1265,8 @@
printf "\n"
printf "struct gdbarch\n"
printf "{\n"
+printf " /* Has this architecture been fully initialized? */\n"
+printf " int initialized_p;\n"
printf " /* basic architectural information */\n"
function_list | while do_read
do
@@ -1343,6 +1339,7 @@
printf "\n"
printf "struct gdbarch startup_gdbarch =\n"
printf "{\n"
+printf " 1, /* Always initialized. */\n"
printf " /* basic architecture information */\n"
function_list | while do_read
do
@@ -1381,7 +1378,6 @@
they are starting from scratch. */
clear_gdbarch_swap (&startup_gdbarch);
init_gdbarch_swap (&startup_gdbarch);
- init_gdbarch_data (&startup_gdbarch);
}
EOF
@@ -1747,6 +1743,7 @@
struct gdbarch_data
{
unsigned index;
+ int init_p;
gdbarch_data_init_ftype *init;
gdbarch_data_free_ftype *free;
};
@@ -1773,6 +1770,7 @@
gdbarch_data_free_ftype *free)
{
struct gdbarch_data_registration **curr;
+ /* Append the new registraration. */
for (curr = &gdbarch_data_registry.registrations;
(*curr) != NULL;
curr = &(*curr)->next);
@@ -1781,31 +1779,12 @@
(*curr)->data = XMALLOC (struct gdbarch_data);
(*curr)->data->index = gdbarch_data_registry.nr++;
(*curr)->data->init = init;
+ (*curr)->data->init_p = 1;
(*curr)->data->free = free;
return (*curr)->data;
}
-/* Walk through all the registered users initializing each in turn. */
-
-static void
-init_gdbarch_data (struct gdbarch *gdbarch)
-{
- struct gdbarch_data_registration *rego;
- for (rego = gdbarch_data_registry.registrations;
- rego != NULL;
- rego = rego->next)
- {
- struct gdbarch_data *data = rego->data;
- gdb_assert (data->index < gdbarch->nr_data);
- if (data->init != NULL)
- {
- void *pointer = data->init (gdbarch);
- set_gdbarch_data (gdbarch, data, pointer);
- }
- }
-}
-
/* Create/delete the gdbarch data vector. */
static void
@@ -1838,7 +1817,7 @@
}
-/* Initialize the current value of thee specified per-architecture
+/* Initialize the current value of the specified per-architecture
data-pointer. */
void
@@ -1847,8 +1826,11 @@
void *pointer)
{
gdb_assert (data->index < gdbarch->nr_data);
- if (data->free != NULL && gdbarch->data[data->index] != NULL)
- data->free (gdbarch, gdbarch->data[data->index]);
+ if (gdbarch->data[data->index] != NULL)
+ {
+ gdb_assert (data->free != NULL);
+ data->free (gdbarch, gdbarch->data[data->index]);
+ }
gdbarch->data[data->index] = pointer;
}
@@ -1859,6 +1841,20 @@
gdbarch_data (struct gdbarch *gdbarch, struct gdbarch_data *data)
{
gdb_assert (data->index < gdbarch->nr_data);
+ /* The data-pointer isn't initialized, call init() to get a value but
+ only if the architecture initializaiton has completed. Otherwise
+ punt - hope that the caller knows what they are doing. */
+ if (gdbarch->data[data->index] == NULL
+ && gdbarch->initialized_p)
+ {
+ /* Be careful to detect an initialization cycle. */
+ gdb_assert (data->init_p);
+ data->init_p = 0;
+ gdb_assert (data->init != NULL);
+ gdbarch->data[data->index] = data->init (gdbarch);
+ data->init_p = 1;
+ gdb_assert (gdbarch->data[data->index] != NULL);
+ }
return gdbarch->data[data->index];
}
@@ -2252,8 +2248,9 @@
rego->arches = this;
}
- /* Switch to this new architecture. Dump it out. */
+ /* Switch to this new architecture marking it initialized. */
current_gdbarch = new_gdbarch;
+ current_gdbarch->initialized_p = 1;
if (gdbarch_debug)
{
fprintf_unfiltered (gdb_stdlog,
@@ -2272,10 +2269,8 @@
called. */
init_gdbarch_swap (new_gdbarch);
- /* Initialize the per-architecture data-pointer of all parties that
- registered an interest in this architecture. CURRENT_GDBARCH
+ /* Initialize the per-architecture data. CURRENT_GDBARCH
must be updated before these modules are called. */
- init_gdbarch_data (new_gdbarch);
architecture_changed_event ();
if (gdbarch_debug)
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v
retrieving revision 1.86
diff -u -r1.86 gdbint.texinfo
--- doc/gdbint.texinfo 31 May 2002 01:36:16 -0000 1.86
+++ doc/gdbint.texinfo 1 Jun 2002 19:13:56 -0000
@@ -4446,6 +4446,107 @@
functions, since they might never return to your code (they
@samp{longjmp} instead).
+@section Per-architecture module data
+@cindex per-architecture module data
+@cindex multi-arch data
+@cindex data-pointer, per-architecture/per-module
+
+The multi-arch framework includes a mechanism for adding module specific
+per-architecture data-pointers to the @code{struct gdbarch} architecture
+object.
+
+A module registers one or more per-architecture data-pointers using the
+function @code{register_gdbarch_data}:
+
+@deftypefun struct gdbarch_data *register_gdbarch_data (gdbarch_data_init_ftype *@var{init}, gdbarch_data_free_ftype *@var{free})
+
+The @var{init} function is used to obtain an initial value for a
+per-architecture data-pointer. The function is called, after the
+architecture has been created, when the data-pointer is still
+uninitialized (@code{NULL}) and its value has been requested via a call
+to @code{gdbarch_data}. A data-pointer can also be initialize
+explicitly using @code{set_gdbarch_data}.
+
+The @var{free} function is called when a data-pointer needs to be
+destroyed. This occurs when either the corresponding @code{struct
+gdbarch} object is being destroyed or when @code{set_gdbarch_data} is
+overriding a non-@code{NULL} data-pointer value.
+
+The function @code{register_gdbarch_data} returns a @code{struct
+gdbarch_data} that is used to identify the data-pointer that was added
+to the module.
+
+@end deftypefun
+
+A typical module has @code{init} and @code{free} functions of the form:
+
+@smallexample
+static struct gdbarch_data *nozle_data_handle;
+static void *
+nozel_data_init (struct gdbarch *gdbarch)
+@{
+ struct nozel_data *data = XMALLOC (struct nozel_data);
+ @dots{}
+ return data;
+@}
+@dots{}
+static void
+nozel_data_free (struct gdbarch *gdbarch, void *data)
+@{
+ xfree (data);
+@}
+@end smallexample
+
+Since uninitialized (@code{NULL}) data-pointers are initialized
+on-demand, an @code{init} function is free to call other modules that
+use data-pointers. Those modules data-pointers will be initialized as
+needed. Care should be taken to ensure that the @code{init} call graph
+does not contain cycles.
+
+The data-pointer is registered with the call:
+
+@smallexample
+void
+_initialize_nozel (void)
+@{
+ nozel_data_handle =
+ register_gdbarch_data (nozel_data_init, nozel_data_free);
+@dots{}
+@end smallexample
+
+The per-architecture data-pointer is accessed using the function:
+
+@deftypefun void *gdbarch_data (struct gdbarch *@var{gdbarch}, struct gdbarch_data *@var{data_handle})
+Given the architecture @var{arch} and module data handle
+@var{data_handle} (returned by @code{register_gdbarch_data}, this
+function returns the current value of the per-architecture data-pointer.
+@end deftypefun
+
+The non-@code{NULL} data-pointer returned by @code{gdbarch_data} should
+be saved in a local variable and then used directly:
+
+@smallexample
+int
+nozel_total (struct gdbarch *gdbarch)
+@{
+ int total;
+ struct nozel_data *data = gdbarch_data (gdbarch, nozel_data_handle);
+ @dots{}
+ return total;
+@}
+@end smallexample
+
+It is also possible to explicitly initialize the data-pointer using:
+
+@deftypefun void set_gdbarch_data (struct gdbarch *@var{gdbarch}, struct gdbarch_data *handle, void *@var{pointer})
+Update the data-pointer corresponding to @var{handle} with the value of
+@var{pointer}. If the previous data-pointer value is non-NULL, then it
+is freed using data-pointers @var{free} function.
+@end deftypefun
+
+This function is used by modules that need to save explicitly selected
+per-architecture configuration information during architecture creation.
+
@section Wrapping Output Lines
@cindex line wrap in output