extend - extend the crash command set

  extend [shared-object ...] | [-u [shared-object ...]]

  This command dynamically loads or unloads crash extension shared object

    shared-object     load the specified shared object file; more than one
                      one object file may be entered.
    -u shared-object  unload the specified shared object file; if no file
                      arguments are specified, unload all objects.

  If no arguments are entered, the current set of shared object files and 
  a list of their commands will be displayed.  The registered commands
  contained in each shared object file will appear automatically in the 
  "help" command screen.

  An example of a shared object prototype file, and how to compile it
  into a shared object, is appended below.

  Load two shared object files:

    crash> extend
    ./ shared object loaded
    ./ shared object loaded

  Display the current set of shared object files and their commands:

    crash> extend
    ./   echo util bin
    ./   smp show

  Unload one of the shared object files:

    crash> extend -u
    ./ shared object unloaded

  Unload all currently-loaded object files:

    crash> extend -u
    ./ shared object unloaded

  The extend command loads shared object files using dlopen(3), which in
  turn calls the shared object's _init() function.  The shared object's _init()
  function should register its command set by calling register_extension(),
  passing it a pointer to an array of one or more structures of the
  following type:
    struct command_table_entry {
            char *name;
            cmd_func_t func;
            char **help_data,
            ulong flags;
  Each command_table_entry structure contains the ASCII name of a command,
  the command's function address, a pointer to an array of help data strings,
  and a flags field.  The help_data field is optional; if it is non-NULL, it
  should point to an array of character strings used by the "help"
  command, and during command failures.  The flags field currently has one
  available bit setting, REFRESH_TASK_TABLE, which should be set if it is 
  preferable to reload the current set of running processes just prior to 
  executing the command (on a live system).  Terminate the array of 
  command_table_entry structures with an entry with a NULL command name.  
  Below is an example shared object file consisting of just one command, 
  called "echo", which simply echoes back all arguments passed to it.
  Note the comments contained within it for further details.  Cut and paste
  the following output into a file, and call it, for example, "echo.c".
  Then compiled in either of two manners.  Either manually like so:
  gcc -nostartfiles -shared -rdynamic -o echo.c -fPIC -D<machine-type> $(TARGET_CFLAGS)
  where <machine-type> must be one of the MACHINE_TYPE #define's in defs.h,
  and where $(TARGET_CFLAGS) is the same as it is declared in the top-level
  Makefile after a build is completed.  Or alternatively, the "echo.c" file
  can be copied into the "extensions" subdirectory, and compiled automatically
  like so:
  make extensions
  The file may be dynamically linked into crash during runtime, or
  during initialization by putting "extend" into a .crashrc file
  located in the current directory, or in the user's $HOME directory.
---------------------------------- cut here ----------------------------------
#include "defs.h"    /* From the crash source top-level directory */

void cmd_echo();     /* Declare the commands and their help data. */
char *help_echo[];

static struct command_table_entry command_table[] = {
        "echo", cmd_echo, help_echo, 0,           /* One or more commands, */
        NULL,                                     /* terminated by NULL, */

_init() /* Register the command set. */
 *  The _fini() function is called if the shared object is unloaded. 
 *  If desired, perform any cleanups here. 
_fini() { }

 *  Arguments are passed to the command functions in the global args[argcnt]
 *  array.  See getopt(3) for info on dash arguments.  Check out defs.h and
 *  other crash commands for usage of the myriad of utility routines available
 *  to accomplish what your task.
        int c;

        while ((c = getopt(argcnt, args, "")) != EOF) {

        if (argerrs)
                cmd_usage(pc->curcmd, SYNOPSIS);

        while (args[optind]) 
                fprintf(fp, "%s ", args[optind++]);

        fprintf(fp, "\n");

 *  The optional help data is simply an array of strings in a defined format.
 *  For example, the "help echo" command will use the help_echo[] string
 *  array below to create a help page that looks like this:
 *    NAME
 *      echo - echoes back its arguments
 *      echo arg ...
 *      This command simply echoes back its arguments.
 *      Echo back all command arguments:
 *        crash> echo hello, world
 *        hello, world
char *help_echo[] = {
        "echo",                        /* command name */
        "echoes back its arguments",   /* short description */
        "arg ...",                     /* argument synopsis, or " " if none */
        "  This command simply echoes back its arguments.",
        "  Echo back all command arguments:\n",
        "    crash> echo hello, world",
        "    hello, world",