(gdbint.info)Clean Design

Next: Submitting Patches Prev: Coding Style Up: Top

Clean Design

   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:

     You can't assume the byte order of anything that comes from a
     target (including VALUEs, object files, and instructions).  Such
     things must be byte-swapped using `SWAP_TARGET_AND_HOST' in GDB,
     or one of the swap routines defined in `bfd.h', such as

     You can't assume that you know what interface is being used to
     talk to the target system.  All references to the target must go
     through the current `target_ops' vector.

     You can't assume that the host and target machines are the same
     machine (except in the "native" support modules).  In particular,
     you can't assume that the target machine's header files will be
     available on the host machine.  Target code must bring along its
     own header files - written from scratch or explicitly donated by
     their owner, to avoid copyright problems.

     Insertion of new `#ifdef''s will be frowned upon.  It's much better
     to write the code portably than to conditionalize it for various

     New `#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.

     Adding code that handles specific architectures, operating
     systems, target interfaces, or hosts, is not acceptable in generic
     code.  If a hook is needed at that point, invent a generic hook
     and define it for your configuration, with something like:

          #ifdef	WRANGLE_SIGNALS
             WRANGLE_SIGNALS (signo);

     In 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)

     where 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,
     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.

     *Do* write code that doesn't depend on the sizes of C data types,
     the format of the host's floating point numbers, the alignment of
     anything, or the order of evaluation of expressions.  In short,
     follow good programming practices for writing portable C code.

automatically generated by info2www