In addition to getting the syntax right, there's the little question of semantics. Some things are done in certain ways in GDB because long experience has shown that the more obvious ways caused various kinds of trouble. In particular:
SWAP_TARGET_AND_HOST
in GDB,
or one of the swap routines defined in `bfd.h', such as bfd_get_32
.
target_ops
vector.
#ifdef
's will be frowned upon. It's much better
to write the code portably than to conditionalize it for various systems.
#ifdef
's which test for specific compilers or manufacturers
or operating systems are unacceptable. All #ifdef
's should test
for features. The information about which configurations contain which
features should be segregated into the configuration files. Experience
has proven far too often that a feature unique to one particular system
often creeps into other systems; and that a conditional based on
some predefined macro for your current system will become worthless
over time, as new versions of your system come out that behave differently
with regard to this feature.
#ifdef WRANGLE_SIGNALS WRANGLE_SIGNALS (signo); #endifIn your host, target, or native configuration file, as appropriate, define
WRANGLE_SIGNALS
to do the machine-dependent thing. Take
a bit of care in defining the hook, so that it can be used by other
ports in the future, if they need a hook in the same place.
If the hook is not defined, the code should do whatever "most" machines
want. Using #ifdef
, as above, is the preferred way to do this,
but sometimes that gets convoluted, in which case use
#ifndef SPECIAL_FOO_HANDLING #define SPECIAL_FOO_HANDLING(pc, sp) (0) #endifwhere the macro is used or in an appropriate header file. Whether to include a small hook, a hook around the exact pieces of code which are system-dependent, or whether to replace a whole function with a hook depends on the case. A good example of this dilemma can be found in
get_saved_register
. All machines that GDB 2.8 ran on
just needed the FRAME_FIND_SAVED_REGS
hook to find the saved
registers. Then the SPARC and Pyramid came along, and
HAVE_REGISTER_WINDOWS
and REGISTER_IN_WINDOW_P
were
introduced. Then the 29k and 88k required the GET_SAVED_REGISTER
hook. The first three are examples of small hooks; the latter replaces
a whole function. In this specific case, it is useful to have both
kinds; it would be a bad idea to replace all the uses of the small hooks
with GET_SAVED_REGISTER
, since that would result in much
duplicated code. Other times, duplicating a few lines of code here or
there is much cleaner than introducing a large number of small hooks.
Another way to generalize GDB along a particular interface is with an
attribute struct. For example, GDB has been generalized to handle
multiple kinds of remote interfaces -- not by #ifdef's everywhere, but
by defining the "target_ops" structure and having a current target (as
well as a stack of targets below it, for memory references). Whenever
something needs to be done that depends on which remote interface we are
using, a flag in the current target_ops structure is tested (e.g.
`target_has_stack'), or a function is called through a pointer in the
current target_ops structure. In this way, when a new remote interface
is added, only one module needs to be touched -- the one that actually
implements the new remote interface. Other examples of
attribute-structs are BFD access to multiple kinds of object file
formats, or GDB's access to multiple source languages.
Please avoid duplicating code. For example, in GDB 3.x all the code
interfacing between ptrace
and the rest of GDB was duplicated in
`*-dep.c', and so changing something was very painful. In GDB 4.x,
these have all been consolidated into `infptrace.c'.
`infptrace.c' can deal with variations between systems the same way
any system-independent file would (hooks, #if defined, etc.), and
machines which are radically different don't need to use infptrace.c at
all.