Re: libgdb.a

J.T. Conklin
1999-04-01T00:00:00Z

>>>>> "cagney" == Andrew Cagney <ac131313@cygnus.com> writes:
cagney> Andris Pavenis wrote:
>> Maybe it would be usefull to implement init functions of higher
>> priority that are executed before ones which names begins with
>> _initialize_. So we would be able to avoid gcc related extensions
>> such as __attribute__((constructor)).
>>
>> For that we should use a different name prefix (eg. _preinit_ or
>> something like) and require that these functions are independent
>> one from another one (should not use results of other similar init
>> functions).

cagney> This has been discussed before (but on another list) and on
cagney> the last occasion it was actually me suggested something along
cagney> similar lines to your proposal. I lost the the discussion :-)

cagney> The consensus was that if GDB started down the path of having
cagney> two initialization levels it could quickly find itself heading
cagney> for a situtation where there were N initialization levels and
cagney> a really confused startup sequence. It was thought that, if
cagney> anything, we should be trying to discourage additional
cagney> complexity being introduced during startup.

I'd have to agree that adding another layer of initialization starts
down a slippery slope. But taken to its logical conclusion, perhaps
its a slope worth sliding down.

GDB is built from a "core" set of code which is common to all hosts
and targets, and assorted modules that may or may not be bound into
the image. Neither the core nor the modules have any knowledge of
each other.

Module initialization functions are identified by a script (embedded
in the Makefile) that extracts names of functions with names of the
form `_initialize_*' from the objects that will be linked into GDB.
These names are used to construct a C file, init.c. When compiled and
linked with the rest of the objects, GDB iterates through the array of
init functions calling each in sequence. That sequence is essentially
random -- it depends on which order the objects are processed.

But what if instead of collecting the names of init functions, init.c
was constructed by collecting the names of module identifiers. A
module identifier struct might look something like follows:

struct module_id {
int magic;
char *module_name;
char *req;
char *pre;
void (*func)(void);
};

A module instance might be something like this:

struct module_id _module_ser_tcp = {
MODULE_MAGIC,
"ser_tcp",
"ser, foo, bar, baz",
"ser",
_initialize_ser_tcp
};

To explain, this defines a module "ser_tcp", it requires the modules
"ser", "foo", "bar", and "baz" to be present in the image; and it
requires from the constructor for the module "ser" be run before it's
own constructor. A simple dependency engine could 1) determine that
all required modules are present; 2) determine that there are no
circular dependencies; and then 3) execute the init functions in the
desired order.

There are obvious avenues for improvement for this idea (e.g, you
might want some way to indicate a module is optional, but if it is
present its init function must be run first; a mechanism for
dynamically loading GDB modules; versioning modules; etc).

I've worked on systems with a similar mechanism, and believe that it
could be made to work for GDB if someone wanted to go down this path.
IMO it is much superior to simply adding another layer (or layers) of
init functions.

cagney> As an example, consider the idea (that was recently floated)
cagney> of GDB suporting several target-architectures. Instead of
cagney> fully initializing the code for all the target-architectures
cagney> during startup, it would probably be more prudent to leave
cagney> most of that task until the point where GDB knew exactly which
cagney> architecture was being debugged.

--jtc

--
J.T. Conklin
RedBack Networks