This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: gdbserver extension



Did we ever get a copyright assignment for this?
Be a pity to let the work go to waste...


Martin Rivers wrote:
> 
> Not sure if anyone is interested but I've got a version of gdbserver
> which supports debugging mips cpu's on linux, at least 43xx and 52xx
> flavors of mips.  I've attached source.  You can include or ignore as
> you see fit.  I'm sure the normal "gnu" programmers will look at this
> and have a fit as normal coding styles aren't incorporated.  However,
> the changes to low-linux.c incorporate appropriate information to
> understand the mips architecture appropriately to allow remote debugging
> (which is what I needed). I've used this with both gdb-4.18 and gdb-5.0
> successfully.
> 
> Martin Rivers
> Lexmark International, Inc.
> 
>   ----------------------------------------------------------------------------------------------------
> /* Basic, host-specific, and target-specific definitions for GDB.
>    Copyright (C) 1986, 89, 91, 92, 93, 94, 95, 96, 98, 1999
>    Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
> 
> #ifndef DEFS_H
> #define DEFS_H
> 
> #include "config.h"             /* Generated by configure */
> #include <stdio.h>
> #include <errno.h>              /* System call error return status */
> #include <limits.h>
> 
> #ifdef HAVE_STDDEF_H
> #  include <stddef.h>
> #else
> #  include <sys/types.h>   /* for size_t */
> #endif
> 
> /* Just in case they're not defined in stdio.h. */
> 
> #ifndef SEEK_SET
> #define SEEK_SET 0
> #endif
> #ifndef SEEK_CUR
> #define SEEK_CUR 1
> #endif
> 
> /* First include ansidecl.h so we can use the various macro definitions
>    here and in all subsequent file inclusions.  */
> 
> #include "ansidecl.h"
> 
> #ifdef ANSI_PROTOTYPES
> #include <stdarg.h>
> #else
> #include <varargs.h>
> #endif
> 
> #include "libiberty.h"
> 
> /* libiberty.h can't declare this one, but evidently we can.  */
> extern char *strsignal PARAMS ((int));
> 
> #include "progress.h"
> 
> #ifdef USE_MMALLOC
> #include "mmalloc.h"
> #endif
> 
> /* For BFD64 and bfd_vma.  */
> #include "bfd.h"
> 
> /* An address in the program being debugged.  Host byte order.  Rather
>    than duplicate all the logic in BFD which figures out what type
>    this is (long, long long, etc.) and whether it needs to be 64
>    bits (the host/target interactions are subtle), we just use
>    bfd_vma.  */
> 
> typedef unsigned int CORE_ADDR;
> 
> #ifndef min
> #define min(a, b) ((a) < (b) ? (a) : (b))
> #endif
> #ifndef max
> #define max(a, b) ((a) > (b) ? (a) : (b))
> #endif
> 
> /* Gdb does *lots* of string compares.  Use macros to speed them up by
>    avoiding function calls if the first characters are not the same. */
> 
> #define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b))
> #define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0)
> #define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0)
> 
> /* The character GNU C++ uses to build identifiers that must be unique from
>    the program's identifiers (such as $this and $$vptr).  */
> #define CPLUS_MARKER '$'        /* May be overridden to '.' for SysV */
> 
> /* Check if a character is one of the commonly used C++ marker characters.  */
> extern int is_cplus_marker PARAMS ((int));
> 
> /* use tui interface if non-zero */
> extern int tui_version;
> 
> #if defined(TUI)
> /* all invocations of TUIDO should have two sets of parens */
> #define TUIDO(x)        tuiDo x
> #else
> #define TUIDO(x)
> #endif
> 
> /* enable xdb commands if set */
> extern int xdb_commands;
> 
> /* enable dbx commands if set */
> extern int dbx_commands;
> 
> extern int quit_flag;
> extern int immediate_quit;
> extern int sevenbit_strings;
> 
> extern void quit PARAMS ((void));
> 
> #ifdef QUIT
> /* do twice to force compiler warning */
> #define QUIT_FIXME "FIXME"
> #define QUIT_FIXME "ignoring redefinition of QUIT"
> #else
> #define QUIT { \
>   if (quit_flag) quit (); \
>   if (interactive_hook) interactive_hook (); \
>   PROGRESS (1); \
> }
> #endif
> 
> /* Command classes are top-level categories into which commands are broken
>    down for "help" purposes.
>    Notes on classes: class_alias is for alias commands which are not
>    abbreviations of the original command.  class-pseudo is for commands
>    which are not really commands nor help topics ("stop").  */
> 
> enum command_class
> {
>   /* Special args to help_list */
>   all_classes = -2, all_commands = -1,
>   /* Classes of commands */
>   no_class = -1, class_run = 0, class_vars, class_stack,
>   class_files, class_support, class_info, class_breakpoint, class_trace,
>   class_alias, class_obscure, class_user, class_maintenance,
>   class_pseudo, class_tui, class_xdb
> };
> 
> /* Languages represented in the symbol table and elsewhere.
>    This should probably be in language.h, but since enum's can't
>    be forward declared to satisfy opaque references before their
>    actual definition, needs to be here. */
> 
> enum language
> {
>    language_unknown,            /* Language not known */
>    language_auto,               /* Placeholder for automatic setting */
>    language_c,                  /* C */
>    language_cplus,              /* C++ */
>    language_java,               /* Java */
>    language_chill,              /* Chill */
>    language_fortran,            /* Fortran */
>    language_m2,                 /* Modula-2 */
>    language_asm,                /* Assembly language */
>    language_scm                 /* Scheme / Guile */
> };
> 
> enum precision_type
> {
>   single_precision,
>   double_precision,
>   unspecified_precision
> };
> 
> /* the cleanup list records things that have to be undone
>    if an error happens (descriptors to be closed, memory to be freed, etc.)
>    Each link in the chain records a function to call and an
>    argument to give it.
> 
>    Use make_cleanup to add an element to the cleanup chain.
>    Use do_cleanups to do all cleanup actions back to a given
>    point in the chain.  Use discard_cleanups to remove cleanups
>    from the chain back to a given point, not doing them.  */
> 
> struct cleanup
> {
>   struct cleanup *next;
>   void (*function) PARAMS ((PTR));
>   PTR arg;
> };
> 
> /* The ability to declare that a function never returns is useful, but
>    not really required to compile GDB successfully, so the NORETURN and
>    ATTR_NORETURN macros normally expand into nothing.  */
> 
> /* If compiling with older versions of GCC, a function may be declared
>    "volatile" to indicate that it does not return.  */
> 
> #ifndef NORETURN
> # if defined(__GNUC__) \
>      && (__GNUC__ == 1 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7))
> #  define NORETURN volatile
> # else
> #  define NORETURN /* nothing */
> # endif
> #endif
> 
> /* GCC 2.5 and later versions define a function attribute "noreturn",
>    which is the preferred way to declare that a function never returns.
>    However GCC 2.7 appears to be the first version in which this fully
>    works everywhere we use it. */
> 
> #ifndef ATTR_NORETURN
> # if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 7
> #  define ATTR_NORETURN __attribute__ ((noreturn))
> # else
> #  define ATTR_NORETURN /* nothing */
> # endif
> #endif
> 
> #ifndef ATTR_FORMAT
> # if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 4 && defined (__ANSI_PROTOTYPES)
> #  define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
> # else
> #  define ATTR_FORMAT(type, x, y) /* nothing */
> # endif
> #endif
> 
> /* Needed for various prototypes */
> 
> #ifdef __STDC__
> struct symtab;
> struct breakpoint;
> #endif
> 
> /* From blockframe.c */
> 
> extern int inside_entry_func PARAMS ((CORE_ADDR));
> 
> extern int inside_entry_file PARAMS ((CORE_ADDR addr));
> 
> extern int inside_main_func PARAMS ((CORE_ADDR pc));
> 
> /* From ch-lang.c, for the moment. (FIXME) */
> 
> extern char *chill_demangle PARAMS ((const char *));
> 
> /* From utils.c */
> 
> extern void notice_quit PARAMS ((void));
> 
> extern int strcmp_iw PARAMS ((const char *, const char *));
> 
> extern char *safe_strerror PARAMS ((int));
> 
> extern char *safe_strsignal PARAMS ((int));
> 
> extern void init_malloc PARAMS ((void *));
> 
> extern void request_quit PARAMS ((int));
> 
> extern void do_cleanups PARAMS ((struct cleanup *));
> extern void do_final_cleanups PARAMS ((struct cleanup *));
> extern void do_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
> extern void do_run_cleanups PARAMS ((struct cleanup *));
> 
> extern void discard_cleanups PARAMS ((struct cleanup *));
> extern void discard_final_cleanups PARAMS ((struct cleanup *));
> extern void discard_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
> 
> typedef void (*make_cleanup_func) PARAMS ((void *));
> 
> extern struct cleanup *make_cleanup PARAMS ((make_cleanup_func, void *));
> 
> extern struct cleanup *make_final_cleanup PARAMS ((make_cleanup_func, void *));
> 
> extern struct cleanup *make_my_cleanup PARAMS ((struct cleanup **,
>                                                 make_cleanup_func, void *));
> 
> extern struct cleanup *make_run_cleanup PARAMS ((make_cleanup_func, void *));
> 
> extern struct cleanup *save_cleanups PARAMS ((void));
> extern struct cleanup *save_final_cleanups PARAMS ((void));
> extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup **));
> 
> extern void restore_cleanups PARAMS ((struct cleanup *));
> extern void restore_final_cleanups PARAMS ((struct cleanup *));
> extern void restore_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
> 
> extern void free_current_contents PARAMS ((char **));
> 
> extern void null_cleanup PARAMS ((PTR));
> 
> extern int myread PARAMS ((int, char *, int));
> 
> extern int query PARAMS((char *, ...))
>      ATTR_FORMAT(printf, 1, 2);
> 
> #if !defined (USE_MMALLOC)
> extern PTR mmalloc PARAMS ((PTR, size_t));
> extern PTR mrealloc PARAMS ((PTR, PTR, size_t));
> extern void mfree PARAMS ((PTR, PTR));
> #endif
> 
> /* From demangle.c */
> 
> extern void set_demangling_style PARAMS ((char *));
> 
> /* From tm.h */
> 
> struct type;
> typedef int (use_struct_convention_fn) PARAMS ((int gcc_p, struct type *value_type));
> extern use_struct_convention_fn generic_use_struct_convention;
> 
> typedef unsigned char *(breakpoint_from_pc_fn) PARAMS ((CORE_ADDR *pcptr, int *lenptr));
> 
> /* Annotation stuff.  */
> 
> extern int annotation_level; /* in stack.c */
> 
> extern void begin_line PARAMS ((void));
> 
> extern void wrap_here PARAMS ((char *));
> 
> extern void reinitialize_more_filter PARAMS ((void));
> 
> /* new */
> enum streamtype
> {
>   afile,
>   astring
> };
> 
> /* new */
> typedef struct tui_stream
> {
>   enum streamtype ts_streamtype;
>   FILE *ts_filestream;
>   char *ts_strbuf;
>   int ts_buflen;
> } GDB_FILE;
> 
> extern GDB_FILE *gdb_stdout;
> extern GDB_FILE *gdb_stderr;
> 
> #if 0
> typedef FILE GDB_FILE;
> #define gdb_stdout stdout
> #define gdb_stderr stderr
> #endif
> 
> #if defined(TUI)
> #include "tui.h"
> #include "tuiCommand.h"
> #include "tuiData.h"
> #include "tuiIO.h"
> #include "tuiLayout.h"
> #include "tuiWin.h"
> #endif
> 
> extern void gdb_fclose PARAMS ((GDB_FILE **));
> 
> extern void gdb_flush PARAMS ((GDB_FILE *));
> 
> extern GDB_FILE *gdb_fopen PARAMS ((char * name, char * mode));
> 
> extern void fputs_filtered PARAMS ((const char *, GDB_FILE *));
> 
> extern void fputs_unfiltered PARAMS ((const char *, GDB_FILE *));
> 
> extern int fputc_filtered PARAMS ((int c, GDB_FILE *));
> 
> extern int fputc_unfiltered PARAMS ((int c, GDB_FILE *));
> 
> extern int putchar_unfiltered PARAMS ((int c));
> 
> extern void puts_filtered PARAMS ((const char *));
> 
> extern void puts_unfiltered PARAMS ((const char *));
> 
> extern void puts_debug PARAMS ((char *prefix, char *string, char *suffix));
> 
> extern void vprintf_filtered PARAMS ((const char *, va_list))
>      ATTR_FORMAT(printf, 1, 0);
> 
> extern void vfprintf_filtered PARAMS ((GDB_FILE *, const char *, va_list))
>      ATTR_FORMAT(printf, 2, 0);
> 
> extern void fprintf_filtered PARAMS ((GDB_FILE *, const char *, ...))
>      ATTR_FORMAT(printf, 2, 3);
> 
> extern void fprintfi_filtered PARAMS ((int, GDB_FILE *, const char *, ...))
>      ATTR_FORMAT(printf, 3, 4);
> 
> extern void printf_filtered PARAMS ((const char *, ...))
>      ATTR_FORMAT(printf, 1, 2);
> 
> extern void printfi_filtered PARAMS ((int, const char *, ...))
>      ATTR_FORMAT(printf, 2, 3);
> 
> extern void vprintf_unfiltered PARAMS ((const char *, va_list))
>      ATTR_FORMAT(printf, 1, 0);
> 
> extern void vfprintf_unfiltered PARAMS ((GDB_FILE *, const char *, va_list))
>      ATTR_FORMAT(printf, 2, 0);
> 
> extern void fprintf_unfiltered PARAMS ((GDB_FILE *, const char *, ...))
>      ATTR_FORMAT(printf, 2, 3);
> 
> extern void printf_unfiltered PARAMS ((const char *, ...))
>      ATTR_FORMAT(printf, 1, 2);
> 
> extern int gdb_file_isatty PARAMS ((GDB_FILE *));
> 
> extern GDB_FILE *gdb_file_init_astring PARAMS ((int));
> 
> extern void gdb_file_deallocate PARAMS ((GDB_FILE **));
> 
> extern char *gdb_file_get_strbuf PARAMS ((GDB_FILE *));
> 
> extern void gdb_file_adjust_strbuf PARAMS ((int, GDB_FILE *));
> 
> extern void print_spaces PARAMS ((int, GDB_FILE *));
> 
> extern void print_spaces_filtered PARAMS ((int, GDB_FILE *));
> 
> extern char *n_spaces PARAMS ((int));
> 
> extern void gdb_printchar PARAMS ((int, GDB_FILE *, int));
> 
> extern void gdb_print_address PARAMS ((void *, GDB_FILE *));
> 
> typedef bfd_vma t_addr;
> typedef bfd_vma t_reg;
> extern char* paddr PARAMS ((t_addr addr));
> 
> extern char* preg PARAMS ((t_reg reg));
> 
> extern char* paddr_nz PARAMS ((t_addr addr));
> 
> extern char* preg_nz PARAMS ((t_reg reg));
> 
> extern void fprintf_symbol_filtered PARAMS ((GDB_FILE *, char *,
>                                              enum language, int));
> 
> extern NORETURN void perror_with_name PARAMS ((char *)) ATTR_NORETURN;
> 
> extern void print_sys_errmsg PARAMS ((char *, int));
> 
> /* From regex.c or libc.  BSD 4.4 declares this with the argument type as
>    "const char *" in unistd.h, so we can't declare the argument
>    as "char *".  */
> 
> extern char *re_comp PARAMS ((const char *));
> 
> /* From symfile.c */
> 
> extern void symbol_file_command PARAMS ((char *, int));
> 
> /* From top.c */
> 
> extern char *skip_quoted PARAMS ((char *));
> 
> extern char *gdb_readline PARAMS ((char *));
> 
> extern char *command_line_input PARAMS ((char *, int, char *));
> 
> extern void print_prompt PARAMS ((void));
> 
> extern int input_from_terminal_p PARAMS ((void));
> 
> extern int info_verbose;
> 
> /* From printcmd.c */
> 
> extern void set_next_address PARAMS ((CORE_ADDR));
> 
> extern void print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int,
>                                             char *));
> 
> extern void print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *));
> 
> extern void print_address PARAMS ((CORE_ADDR, GDB_FILE *));
> 
> /* From source.c */
> 
> extern int openp PARAMS ((char *, int, char *, int, int, char **));
> 
> extern int source_full_path_of PARAMS ((char *, char **));
> 
> extern void mod_path PARAMS ((char *, char **));
> 
> extern void directory_command PARAMS ((char *, int));
> 
> extern void init_source_path PARAMS ((void));
> 
> extern char *symtab_to_filename PARAMS ((struct symtab *));
> 
> /* From findvar.c */
> 
> extern int read_relative_register_raw_bytes PARAMS ((int, char *));
> 
> /* From readline (but not in any readline .h files).  */
> 
> extern char *tilde_expand PARAMS ((char *));
> 
> /* Control types for commands */
> 
> enum misc_command_type
> {
>   ok_command,
>   end_command,
>   else_command,
>   nop_command
> };
> 
> enum command_control_type
> {
>   simple_control,
>   break_control,
>   continue_control,
>   while_control,
>   if_control,
>   invalid_control
> };
> 
> /* Structure for saved commands lines
>    (for breakpoints, defined commands, etc).  */
> 
> struct command_line
> {
>   struct command_line *next;
>   char *line;
>   enum command_control_type control_type;
>   int body_count;
>   struct command_line **body_list;
> };
> 
> extern struct command_line *read_command_lines PARAMS ((char *, int));
> 
> extern void free_command_lines PARAMS ((struct command_line **));
> 
> /* String containing the current directory (what getwd would return).  */
> 
> extern char *current_directory;
> 
> /* Default radixes for input and output.  Only some values supported.  */
> extern unsigned input_radix;
> extern unsigned output_radix;
> 
> /* Possibilities for prettyprint parameters to routines which print
>    things.  Like enum language, this should be in value.h, but needs
>    to be here for the same reason.  FIXME:  If we can eliminate this
>    as an arg to LA_VAL_PRINT, then we can probably move it back to
>    value.h. */
> 
> enum val_prettyprint
> {
>   Val_no_prettyprint = 0,
>   Val_prettyprint,
>   /* Use the default setting which the user has specified.  */
>   Val_pretty_default
> };
> 
> /* Host machine definition.  This will be a symlink to one of the
>    xm-*.h files, built by the `configure' script.  */
> 
> #include "xm.h"
> 
> /* Native machine support.  This will be a symlink to one of the
>    nm-*.h files, built by the `configure' script.  */
> 
> #include "nm.h"
> 
> /* Target machine definition.  This will be a symlink to one of the
>    tm-*.h files, built by the `configure' script.  */
> 
> #include "tm.h"
> 
> /* If the xm.h file did not define the mode string used to open the
>    files, assume that binary files are opened the same way as text
>    files */
> #ifndef FOPEN_RB
> #include "fopen-same.h"
> #endif
> 
> /* Microsoft C can't deal with const pointers */
> 
> #ifdef _MSC_VER
> #define CONST_PTR
> #else
> #define CONST_PTR const
> #endif
> 
> /*
>  * Allow things in gdb to be declared "volatile".  If compiling ANSI, it
>  * just works.  If compiling with gcc but non-ansi, redefine to __volatile__.
>  * If non-ansi, non-gcc, then eliminate "volatile" entirely, making those
>  * objects be read-write rather than read-only.
>  */
> 
> #ifndef volatile
> #ifndef __STDC__
> # ifdef __GNUC__
> #  define volatile __volatile__
> # else
> #  define volatile /*nothing*/
> # endif /* GNUC */
> #endif /* STDC */
> #endif /* volatile */
> 
> /* Defaults for system-wide constants (if not defined by xm.h, we fake it).
>    FIXME: Assumes 2's complement arithmetic */
> 
> #if !defined (UINT_MAX)
> #define UINT_MAX ((unsigned int)(~0))           /* 0xFFFFFFFF for 32-bits */
> #endif
> 
> #if !defined (INT_MAX)
> #define INT_MAX ((int)(UINT_MAX >> 1))          /* 0x7FFFFFFF for 32-bits */
> #endif
> 
> #if !defined (INT_MIN)
> #define INT_MIN ((int)((int) ~0 ^ INT_MAX))     /* 0x80000000 for 32-bits */
> #endif
> 
> #if !defined (ULONG_MAX)
> #define ULONG_MAX ((unsigned long)(~0L))        /* 0xFFFFFFFF for 32-bits */
> #endif
> 
> #if !defined (LONG_MAX)
> #define LONG_MAX ((long)(ULONG_MAX >> 1))       /* 0x7FFFFFFF for 32-bits */
> #endif
> 
> #ifndef LONGEST
> 
> #ifdef BFD64
> 
> /* This is to make sure that LONGEST is at least as big as CORE_ADDR.  */
> 
> #define LONGEST BFD_HOST_64_BIT
> #define ULONGEST BFD_HOST_U_64_BIT
> 
> #else /* No BFD64 */
> 
> #  ifdef CC_HAS_LONG_LONG
> #    define LONGEST long long
> #    define ULONGEST unsigned long long
> #  else
> /* BFD_HOST_64_BIT is defined for some hosts that don't have long long
>    (e.g. i386-windows) so try it.  */
> #    ifdef BFD_HOST_64_BIT
> #      define LONGEST BFD_HOST_64_BIT
> #      define ULONGEST BFD_HOST_U_64_BIT
> #    else
> #      define LONGEST long
> #      define ULONGEST unsigned long
> #    endif
> #  endif
> 
> #endif /* No BFD64 */
> 
> #endif /* ! LONGEST */
> 
> /* Convert a LONGEST to an int.  This is used in contexts (e.g. number of
>    arguments to a function, number in a value history, register number, etc.)
>    where the value must not be larger than can fit in an int.  */
> 
> extern int longest_to_int PARAMS ((LONGEST));
> 
> /* Assorted functions we can declare, now that const and volatile are
>    defined.  */
> 
> extern char *savestring PARAMS ((const char *, int));
> 
> extern char *msavestring PARAMS ((void *, const char *, int));
> 
> extern char *strsave PARAMS ((const char *));
> 
> extern char *mstrsave PARAMS ((void *, const char *));
> 
> #ifdef _MSC_VER /* FIXME; was long, but this causes compile errors in msvc if already defined */
> extern PTR xmmalloc PARAMS ((PTR, size_t));
> 
> extern PTR xmrealloc PARAMS ((PTR, PTR, size_t));
> #else
> extern PTR xmmalloc PARAMS ((PTR, long));
> 
> extern PTR xmrealloc PARAMS ((PTR, PTR, long));
> #endif
> 
> extern int parse_escape PARAMS ((char **));
> 
> /* compat - handle old targets that just define REGISTER_NAMES */
> #ifndef REGISTER_NAME
> extern char *gdb_register_names[];
> #define REGISTER_NAME(i) gdb_register_names[i]
> #endif
> 
> /* Message to be printed before the error message, when an error occurs.  */
> 
> extern char *error_pre_print;
> 
> /* Message to be printed before the error message, when an error occurs.  */
> 
> extern char *quit_pre_print;
> 
> /* Message to be printed before the warning message, when a warning occurs.  */
> 
> extern char *warning_pre_print;
> 
> extern NORETURN void error PARAMS((const char *, ...)) ATTR_NORETURN;
> 
> extern void error_begin PARAMS ((void));
> 
> extern NORETURN void fatal PARAMS((char *, ...)) ATTR_NORETURN;
> 
> extern NORETURN void nomem PARAMS ((long)) ATTR_NORETURN;
> 
> /* Reasons for calling return_to_top_level.  */
> enum return_reason {
>   /* User interrupt.  */
>   RETURN_QUIT,
> 
>   /* Any other error.  */
>   RETURN_ERROR
> };
> 
> #define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT)
> #define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR)
> #define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
> typedef int return_mask;
> 
> extern NORETURN void
> return_to_top_level PARAMS ((enum return_reason)) ATTR_NORETURN;
> 
> typedef int (catch_errors_ftype) PARAMS ((PTR));
> extern int catch_errors PARAMS ((catch_errors_ftype *, PTR, char *, return_mask));
> 
> extern void warning_begin PARAMS ((void));
> 
> extern void warning PARAMS ((const char *, ...))
>      ATTR_FORMAT(printf, 1, 2);
> 
> /* Global functions from other, non-gdb GNU thingies.
>    Libiberty thingies are no longer declared here.  We include libiberty.h
>    above, instead.  */
> 
> #ifndef GETENV_PROVIDED
> extern char *getenv PARAMS ((const char *));
> #endif
> 
> /* From other system libraries */
> 
> #ifdef HAVE_STDDEF_H
> #include <stddef.h>
> #endif
> 
> #ifdef HAVE_STDLIB_H
> #if defined(_MSC_VER) && !defined(__cplusplus)
> /* msvc defines these in stdlib.h for c code */
> #undef min
> #undef max
> #endif
> #include <stdlib.h>
> #endif
> #ifndef min
> #define min(a, b) ((a) < (b) ? (a) : (b))
> #endif
> #ifndef max
> #define max(a, b) ((a) > (b) ? (a) : (b))
> #endif
> 
> /* We take the address of fclose later, but some stdio's forget
>    to declare this.  We can't always declare it since there's
>    no way to declare the parameters without upsetting some compiler
>    somewhere. */
> 
> #ifndef FCLOSE_PROVIDED
> extern int fclose PARAMS ((FILE *));
> #endif
> 
> #ifndef atof
> extern double atof PARAMS ((const char *));     /* X3.159-1989  4.10.1.1 */
> #endif
> 
> #ifndef MALLOC_INCOMPATIBLE
> 
> #ifdef NEED_DECLARATION_MALLOC
> extern PTR malloc ();
> #endif
> 
> #ifdef NEED_DECLARATION_REALLOC
> extern PTR realloc ();
> #endif
> 
> #ifdef NEED_DECLARATION_FREE
> extern void free ();
> #endif
> 
> #endif /* MALLOC_INCOMPATIBLE */
> 
> /* Various possibilities for alloca.  */
> #ifndef alloca
> # ifdef __GNUC__
> #  define alloca __builtin_alloca
> # else /* Not GNU C */
> #  ifdef HAVE_ALLOCA_H
> #   include <alloca.h>
> #  else
> #   ifdef _AIX
>  #pragma alloca
> #   else
> 
> /* We need to be careful not to declare this in a way which conflicts with
>    bison.  Bison never declares it as char *, but under various circumstances
>    (like __hpux) we need to use void *.  */
> #    if defined (__STDC__) || defined (__hpux)
>    extern void *alloca ();
> #    else /* Don't use void *.  */
>    extern char *alloca ();
> #    endif /* Don't use void *.  */
> #   endif /* Not _AIX */
> #  endif /* Not HAVE_ALLOCA_H */
> # endif /* Not GNU C */
> #endif /* alloca not defined */
> 
> /* HOST_BYTE_ORDER must be defined to one of these.  */
> 
> #ifdef HAVE_ENDIAN_H
> #include <endian.h>
> #endif
> 
> #if !defined (BIG_ENDIAN)
> #define BIG_ENDIAN 4321
> #endif
> 
> #if !defined (LITTLE_ENDIAN)
> #define LITTLE_ENDIAN 1234
> #endif
> 
> /* Dynamic target-system-dependent parameters for GDB. */
> #include "gdbarch.h"
> 
> /* Static target-system-dependent parameters for GDB. */
> 
> /* Number of bits in a char or unsigned char for the target machine.
>    Just like CHAR_BIT in <limits.h> but describes the target machine.  */
> #if !defined (TARGET_CHAR_BIT)
> #define TARGET_CHAR_BIT 8
> #endif
> 
> /* Number of bits in a short or unsigned short for the target machine. */
> #if !defined (TARGET_SHORT_BIT)
> #define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT)
> #endif
> 
> /* Number of bits in an int or unsigned int for the target machine. */
> #if !defined (TARGET_INT_BIT)
> #define TARGET_INT_BIT (4 * TARGET_CHAR_BIT)
> #endif
> 
> /* Number of bits in a long or unsigned long for the target machine. */
> #if !defined (TARGET_LONG_BIT)
> #define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT)
> #endif
> 
> /* Number of bits in a long long or unsigned long long for the target machine. */
> #if !defined (TARGET_LONG_LONG_BIT)
> #define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT)
> #endif
> 
> /* Number of bits in a float for the target machine. */
> #if !defined (TARGET_FLOAT_BIT)
> #define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT)
> #endif
> 
> /* Number of bits in a double for the target machine. */
> #if !defined (TARGET_DOUBLE_BIT)
> #define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT)
> #endif
> 
> /* Number of bits in a long double for the target machine.  */
> #if !defined (TARGET_LONG_DOUBLE_BIT)
> #define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT)
> #endif
> 
> /* Number of bits in a pointer for the target machine */
> #if !defined (TARGET_PTR_BIT)
> #define TARGET_PTR_BIT TARGET_INT_BIT
> #endif
> 
> /* If we picked up a copy of CHAR_BIT from a configuration file
>    (which may get it by including <limits.h>) then use it to set
>    the number of bits in a host char.  If not, use the same size
>    as the target. */
> 
> #if defined (CHAR_BIT)
> #define HOST_CHAR_BIT CHAR_BIT
> #else
> #define HOST_CHAR_BIT TARGET_CHAR_BIT
> #endif
> 
> /* The bit byte-order has to do just with numbering of bits in
>    debugging symbols and such.  Conceptually, it's quite separate
>    from byte/word byte order.  */
> 
> #if !defined (BITS_BIG_ENDIAN)
> #define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BIG_ENDIAN)
> #endif
> 
> /* In findvar.c.  */
> 
> extern LONGEST extract_signed_integer PARAMS ((void *, int));
> 
> extern ULONGEST extract_unsigned_integer PARAMS ((void *, int));
> 
> extern int extract_long_unsigned_integer PARAMS ((void *, int, LONGEST *));
> 
> extern CORE_ADDR extract_address PARAMS ((void *, int));
> 
> extern void store_signed_integer PARAMS ((PTR, int, LONGEST));
> 
> extern void store_unsigned_integer PARAMS ((PTR, int, ULONGEST));
> 
> extern void store_address PARAMS ((PTR, int, LONGEST));
> 
> /* Setup definitions for host and target floating point formats.  We need to
>    consider the format for `float', `double', and `long double' for both target
>    and host.  We need to do this so that we know what kind of conversions need
>    to be done when converting target numbers to and from the hosts DOUBLEST
>    data type.  */
> 
> /* This is used to indicate that we don't know the format of the floating point
>    number.  Typically, this is useful for native ports, where the actual format
>    is irrelevant, since no conversions will be taking place.  */
> 
> extern const struct floatformat floatformat_unknown;
> 
> #if HOST_BYTE_ORDER == BIG_ENDIAN
> #  ifndef HOST_FLOAT_FORMAT
> #    define HOST_FLOAT_FORMAT &floatformat_ieee_single_big
> #  endif
> #  ifndef HOST_DOUBLE_FORMAT
> #    define HOST_DOUBLE_FORMAT &floatformat_ieee_double_big
> #  endif
> #else                           /* LITTLE_ENDIAN */
> #  ifndef HOST_FLOAT_FORMAT
> #    define HOST_FLOAT_FORMAT &floatformat_ieee_single_little
> #  endif
> #  ifndef HOST_DOUBLE_FORMAT
> #    define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little
> #  endif
> #endif
> 
> #ifndef HOST_LONG_DOUBLE_FORMAT
> #define HOST_LONG_DOUBLE_FORMAT &floatformat_unknown
> #endif
> 
> #ifndef TARGET_FLOAT_FORMAT
> #define TARGET_FLOAT_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \
>                              ? &floatformat_ieee_single_big \
>                              : &floatformat_ieee_single_little)
> #endif
> #ifndef TARGET_DOUBLE_FORMAT
> #define TARGET_DOUBLE_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \
>                               ? &floatformat_ieee_double_big \
>                               : &floatformat_ieee_double_little)
> #endif
> 
> #ifndef TARGET_LONG_DOUBLE_FORMAT
> #  define TARGET_LONG_DOUBLE_FORMAT &floatformat_unknown
> #endif
> 
> /* Use `long double' if the host compiler supports it.  (Note that this is not
>    necessarily any longer than `double'.  On SunOS/gcc, it's the same as
>    double.)  This is necessary because GDB internally converts all floating
>    point values to the widest type supported by the host.
> 
>    There are problems however, when the target `long double' is longer than the
>    host's `long double'.  In general, we'll probably reduce the precision of
>    any such values and print a warning.  */
> 
> #ifdef HAVE_LONG_DOUBLE
> typedef long double DOUBLEST;
> #else
> typedef double DOUBLEST;
> #endif
> 
> extern void floatformat_to_doublest PARAMS ((const struct floatformat *,
>                                              char *, DOUBLEST *));
> extern void floatformat_from_doublest PARAMS ((const struct floatformat *,
>                                                DOUBLEST *, char *));
> extern DOUBLEST extract_floating PARAMS ((void *, int));
> 
> extern void store_floating PARAMS ((void *, int, DOUBLEST));
> 
> /* On some machines there are bits in addresses which are not really
>    part of the address, but are used by the kernel, the hardware, etc.
>    for special purposes.  ADDR_BITS_REMOVE takes out any such bits
>    so we get a "real" address such as one would find in a symbol
>    table.  This is used only for addresses of instructions, and even then
>    I'm not sure it's used in all contexts.  It exists to deal with there
>    being a few stray bits in the PC which would mislead us, not as some sort
>    of generic thing to handle alignment or segmentation (it's possible it
>    should be in TARGET_READ_PC instead).  */
> #if !defined (ADDR_BITS_REMOVE)
> #define ADDR_BITS_REMOVE(addr) (addr)
> #endif /* No ADDR_BITS_REMOVE.  */
> 
> /* From valops.c */
> 
> extern CORE_ADDR push_bytes PARAMS ((CORE_ADDR, char *, int));
> 
> extern CORE_ADDR push_word PARAMS ((CORE_ADDR, ULONGEST));
> 
> /* Some parts of gdb might be considered optional, in the sense that they
>    are not essential for being able to build a working, usable debugger
>    for a specific environment.  For example, the maintenance commands
>    are there for the benefit of gdb maintainers.  As another example,
>    some environments really don't need gdb's that are able to read N
>    different object file formats.  In order to make it possible (but
>    not necessarily recommended) to build "stripped down" versions of
>    gdb, the following defines control selective compilation of those
>    parts of gdb which can be safely left out when necessary.  Note that
>    the default is to include everything. */
> 
> #ifndef MAINTENANCE_CMDS
> #define MAINTENANCE_CMDS 1
> #endif
> 
> #ifdef MAINTENANCE_CMDS
> extern int watchdog;
> #endif
> 
> /* Hooks for alternate command interfaces.  */
> 
> #ifdef __STDC__
> struct target_waitstatus;
> struct cmd_list_element;
> #endif
> 
> extern void (*init_ui_hook) PARAMS ((char *argv0));
> extern void (*command_loop_hook) PARAMS ((void));
> extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer,
>                                               GDB_FILE *stream));
> extern void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s,
>                                                       int line, int stopline,
>                                                       int noerror));
> extern struct frame_info *parse_frame_specification PARAMS ((char *frame_exp));
> extern int  (*query_hook) PARAMS ((const char *, va_list));
> extern void (*warning_hook) PARAMS ((const char *, va_list));
> extern void (*flush_hook) PARAMS ((GDB_FILE *stream));
> extern void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b));
> extern void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
> extern void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
> extern void (*target_output_hook) PARAMS ((char *));
> extern void (*interactive_hook) PARAMS ((void));
> extern void (*registers_changed_hook) PARAMS ((void));
> extern void (*readline_begin_hook) PARAMS ((char *, ...));
> extern char * (*readline_hook) PARAMS ((char *));
> extern void (*readline_end_hook) PARAMS ((void));
> extern void (*register_changed_hook) PARAMS ((int regno));
> extern void (*memory_changed_hook) PARAMS ((CORE_ADDR addr, int len));
> extern void (*context_hook) PARAMS ((int));
> extern int (*target_wait_hook) PARAMS ((int pid,
>                                         struct target_waitstatus *status));
> 
> extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c,
>                                           char *cmd, int from_tty));
> 
> extern NORETURN void (*error_hook) PARAMS ((void)) ATTR_NORETURN;
> 
> extern void (*error_begin_hook) PARAMS ((void));
> 
> /* Inhibit window interface if non-zero. */
> 
> extern int use_windows;
> 
> /* Symbolic definitions of filename-related things.  */
> /* FIXME, this doesn't work very well if host and executable
>    filesystems conventions are different.  */
> 
> #ifndef DIRNAME_SEPARATOR
> #define DIRNAME_SEPARATOR ':'
> #endif
> 
> #ifndef SLASH_P
> #if defined(__GO32__)||defined(_WIN32)
> #define SLASH_P(X) ((X)=='\\')
> #else
> #define SLASH_P(X) ((X)=='/')
> #endif
> #endif
> 
> #ifndef SLASH_CHAR
> #if defined(__GO32__)||defined(_WIN32)
> #define SLASH_CHAR '\\'
> #else
> #define SLASH_CHAR '/'
> #endif
> #endif
> 
> #ifndef SLASH_STRING
> #if defined(__GO32__)||defined(_WIN32)
> #define SLASH_STRING "\\"
> #else
> #define SLASH_STRING "/"
> #endif
> #endif
> 
> #ifndef ROOTED_P
> #define ROOTED_P(X) (SLASH_P((X)[0]))
> #endif
> 
> /* On some systems, PIDGET is defined to extract the inferior pid from
>    an internal pid that has the thread id and pid in seperate bit
>    fields.  If not defined, then just use the entire internal pid as
>    the actual pid. */
> 
> #ifndef PIDGET
> #define PIDGET(pid) (pid)
> #endif
> 
> /* If under Cygwin, provide backwards compatibility with older
>    Cygwin compilers that don't define the current cpp define. */
> #ifdef __CYGWIN32__
> #ifndef __CYGWIN__
> #define __CYGWIN__
> #endif
> #endif
> 
> #endif /* #ifndef DEFS_H */
> 
>   ----------------------------------------------------------------------------------------------------
> /* $Id$
> 
> Low level interface to ptrace, for the remote server for GDB.
>    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> 
> 23-jan-2000     rivers  In unsinglestep, don't remove breakpoints if we didn't
>                         hit one (because of signal).
> 28-dec-2000     rivers  Added ability to "trace" calls to ptrace (ptracex).
>                         Added more debug output controlled via 'verbose'.
>                         Don't allow storing to any but gpr/fpr/epc registers.
>                         When single stepping, if branch target == instruction after
>                         delay slot, then only one breakpoint.
> 22-march-2000   rivers  Added support to attach to a process
> 
>  */
> 
> #include "defs.h"
> #include <sys/wait.h>
> #include "frame.h"
> #include "inferior.h"
> 
> #include <stdio.h>
> #include <sys/param.h>
> #include <sys/dir.h>
> #include <sys/user.h>
> #include <signal.h>
> #include <sys/ioctl.h>
> #include <fcntl.h>
> 
> /*
>  * These are the various branch types
>  */
> 
> #define NOBRANCH 0
> #define OFFSET_16 1
> #define OFFSET_24 2
> #define REG_TARGET 3
> 
> extern int verbose;
> 
> struct singlestep
> {
>     unsigned int opcode;
>     unsigned int pc;
> };
> 
> struct singlestep tracebp;      /* Next instruction (or after delay slot) trace info */
> struct singlestep tracebpbt;    /* Branch target trace information */
> 
> /***************Begin MY defs*********************/
> int quit_flag = 0;
> char registers[REGISTER_BYTES];
> 
> /* Index within `registers' of the first byte of the space for
>    register N.  */
> 
> char buf2[MAX_REGISTER_RAW_SIZE];
> /***************End MY defs*********************/
> 
> /*#include <sys/ptrace.h>*/
> 
> #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
> #include <sys/reg.h>
> #endif
> 
> extern char **environ;
> extern int errno;
> extern int inferior_pid;
> void quit (), perror_with_name ();
> int query ();
> int is_branch( int );
> int branch_target_address( int, int );
> void single_step( void );
> int unsingle_step( void );
> 
> /* Start an inferior process and returns its pid.
>    ALLARGS is a vector of program-name and args.
>    ENV is the environment vector to pass.  */
> 
> int
> create_inferior (program, allargs)
>   char *program;
>   char **allargs;
> {
>     int pid;
> 
>     pid = fork ();
>     if (pid < 0)
>         perror_with_name ("fork");
> 
>     if (pid == 0)
>     {
>         ptracex (PTRACE_TRACEME, 0, 0, 0);
> 
>         execv (program, allargs);
> 
>         fprintf (stderr, "Cannot exec %s: %s.\n", program,
>                  errno < sys_nerr ? sys_errlist[errno] : "unknown error");
>         fflush (stderr);
>         _exit (0177);
>     }
> 
>     return pid;
> }
> 
> void
> attach_inferior()
> {
>     if( ptracex( PTRACE_ATTACH, inferior_pid, 0, 0 ) < 0 )
>         perror_with_name( "ptrace" );
> }
> 
> /* Kill the inferior process.  Make us have no inferior.  */
> 
> void
> kill_inferior ()
> {
>     if (inferior_pid == 0)
>         return;
>     ptracex (PTRACE_KILL, inferior_pid, 0, 0);
>     wait (0);
>   /*************inferior_died ();****VK**************/
> }
> 
> /* Return nonzero if the given thread is still alive.  */
> int
> mythread_alive (pid)
>   int pid;
> {
>     return 1;
> }
> 
> /* Wait for process, returns status */
> 
> unsigned char
> mywait (status)
>   char *status;
> {
>     int pid;
>     int w;
> 
>     if( verbose )
>         printf( "about to mywait\n" );
> 
>     pid = wait (&w);
>     if (pid != inferior_pid)
>         perror_with_name ("wait");
> 
>     if( verbose )
>         printf( "wait status %08x\n", w );
> 
>     if (WIFEXITED (w))
>     {
>         fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
>         *status = 'W';
>         return ((unsigned char) WEXITSTATUS (w));
>     }
>     else if (!WIFSTOPPED (w))
>     {
>         fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
>         *status = 'X';
>         return ((unsigned char) WTERMSIG (w));
>     }
> 
>     fetch_inferior_registers (0);
> 
>     *status = 'T';
>     return ((unsigned char) WSTOPSIG (w));
> }
> 
> /* Resume execution of the inferior process.
>    If STEP is nonzero, single-step it.
>    If SIGNAL is nonzero, give it that signal.  */
> 
> void
> myresume (step, signal)
>      int step;
>      int signal;
> {
>     errno = 0;
>     ptracex (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
>     if (errno)
>         perror_with_name ("ptrace");
> }
> 
> #if !defined (offsetof)
> #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
> #endif
> 
> /* U_REGS_OFFSET is the offset of the registers within the u area.  */
> #if !defined (U_REGS_OFFSET)
> #define U_REGS_OFFSET \
>   ptracex (PT_READ_U, inferior_pid, \
>           (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
>     - KERNEL_U_ADDR
> #endif
> 
> CORE_ADDR
> register_addr (regno, blockend)
>      int regno;
>      CORE_ADDR blockend;
> {
>     CORE_ADDR addr;
> 
>     if (regno < 0 || regno >= ARCH_NUM_REGS)
>         error ("Invalid register number %d.", regno);
> 
>     if( regno < 32 )
>         return( regno );                /* gpr's */
>     else if( ( regno >= 38 ) && ( regno < 70 ) )
>         return( regno - 38 + 32 ); /* fpr's */
>     else if( regno == 32 )      /* sr unsupported */
>         return( -1 );
>     else if( regno == 33 )      /* lo */
>         return( 67 );
>     else if( regno == 34 )      /* hi */
>         return( 68 );
>     else if( regno == 35 )      /* bad */
>         return( 66 );
>     else if( regno == 36 )      /* cause */
>         return( 65 );
>     else if( regno == 37 )      /* (e)pc */
>         return( 64 );
>     else if( regno == 70 )      /* fsr */
>         return( 69 );
>     else
>         return( -1 );
> 
>     return addr;
> }
> 
> /* Fetch one register.  */
> 
> static void
> fetch_register (regno)
>      int regno;
> {
>     register unsigned int regaddr;
>     register int i;
> 
>     /* Offset of registers within the u area.  */
>     unsigned int offset;
> 
>     offset = 0;
> 
>     regaddr = register_addr (regno, offset);
>     if( regaddr == -1 )
>         return;
> 
>     for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
>     {
>         errno = 0;
>         *(int *) &registers[ regno * 4 + i] = ptracex (PTRACE_PEEKUSR, inferior_pid,
>                                                        (PTRACE_ARG3_TYPE) regaddr, 0);
>         regaddr++;
>         if (errno != 0)
>         {
>             /* Warning, not error, in case we are attached; sometimes the
>                kernel doesn't let us at the registers.  */
>             char *err = strerror (errno);
>             char *msg = alloca (strlen (err) + 128);
>             sprintf (msg, "reading register %d: %s", regno, err);
>             error (msg);
>             goto error_exit;
>         }
>     }
>  error_exit:;
> }
> 
> /* Fetch all registers, or just one, from the child process.  */
> 
> void
> fetch_inferior_registers (regno)
>      int regno;
> {
>     if (regno == -1 || regno == 0)
>         for (regno = 0; regno < NUM_REGS; regno++)
>             fetch_register (regno);
>     else
>         fetch_register (regno);
> }
> 
> /* Store our register values back into the inferior.
>    If REGNO is -1, do this for all registers.
>    Otherwise, REGNO specifies which register (so we can save time).  */
> 
> void
> store_inferior_registers (regno)
>      int regno;
> {
>     register unsigned int regaddr;
>     register int i;
>     unsigned int offset = 0;
> 
>     if( verbose )
>         printf( "store_inferior_register; %d\n", regno );
> 
>     if (regno >= 0)
>     {
>         errno = 0;
> 
>         regaddr = register_addr (regno, offset);
> 
>         if( regaddr > 64 )
>         {
>             /*
>              * Only allow writing to gpr's, fpr's and pc, no other register
>              */
> 
>             return;
>         }
> 
>         if( regaddr == -1 )
>             return;
> 
>         for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
>         {
>             errno = 0;
>             ptracex (PTRACE_POKEUSR, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
>                      *(int *) &registers[REGISTER_BYTE (regno) + i]);
> #if 0
>             if (errno != 0)
>             {
>                 /* Warning, not error, in case we are attached; sometimes the
>                    kernel doesn't let us at the registers.  */
>                 char *err = strerror (errno);
>                 char *msg = alloca (strlen (err) + 128);
>                 sprintf (msg, "writing register %d: %s",
>                          regno, err);
>                 error (msg);
>                 return;
>             }
> #endif
>             regaddr++;
>         }
>     }
>     else
>         for (regno = 0; regno < NUM_REGS; regno++)
>             store_inferior_registers (regno);
> }
> 
> /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
>    in the NEW_SUN_PTRACE case.
>    It ought to be straightforward.  But it appears that writing did
>    not write the data that I specified.  I cannot understand where
>    it got the data that it actually did write.  */
> 
> /* Copy LEN bytes from inferior's memory starting at MEMADDR
>    to debugger memory starting at MYADDR.  */
> 
> void
> read_inferior_memory (memaddr, myaddr, len)
>      CORE_ADDR memaddr;
>      char *myaddr;
>      int len;
> {
>     register int i;
>     /* Round starting address down to longword boundary.  */
>     register CORE_ADDR addr = memaddr & -sizeof (int);
>     /* Round ending address up; get number of longwords that makes.  */
>     register int count
>         = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
>     /* Allocate buffer of that many longwords.  */
>     register int *buffer = (int *) alloca (count * sizeof (int));
> 
>     /* Read all the longwords */
>     for (i = 0; i < count; i++, addr += sizeof (int))
>     {
>         buffer[i] = ptracex (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
>     }
> 
>     /* Copy appropriate bytes out of the buffer.  */
>     memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
> }
> 
> /* Copy LEN bytes of data from debugger memory at MYADDR
>    to inferior's memory at MEMADDR.
>    On failure (cannot write the inferior)
>    returns the value of errno.  */
> 
> int
> write_inferior_memory (memaddr, myaddr, len)
>      CORE_ADDR memaddr;
>      char *myaddr;
>      int len;
> {
>     register int i;
>     /* Round starting address down to longword boundary.  */
>     register CORE_ADDR addr = memaddr & -sizeof (int);
>     /* Round ending address up; get number of longwords that makes.  */
>     register int count
>         = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
>     /* Allocate buffer of that many longwords.  */
>     register int *buffer = (int *) alloca (count * sizeof (int));
>     extern int errno;
> 
>     /* Fill start and end extra bytes of buffer with existing memory data.  */
> 
>     buffer[0] = ptracex (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
> 
>     if (count > 1)
>     {
>         buffer[count - 1]
>             = ptracex (PTRACE_PEEKTEXT, inferior_pid,
>                        addr + (count - 1) * sizeof (int), 0);
>     }
> 
>     /* Copy data to be written over corresponding part of buffer */
> 
>     memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
> 
>     /* Write the entire buffer.  */
> 
>     for (i = 0; i < count; i++, addr += sizeof (int))
>     {
>         errno = 0;
>         ptracex (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]);
>         if (errno)
>             return errno;
>     }
> 
>     return 0;
> }
> 
> void
> initialize ()
> {
>     inferior_pid = 0;
> }
> 
> int
> have_inferior_p ()
> {
>     return inferior_pid != 0;
> }
> 
> void single_step( void )
> 
> /*
>  * We're being told to do a single step command ('s').  Put
>  * a break instruction at the next instruction.  A special case
>  * exists when the current instruction is a branch.  In this
>  * special case, the break point is placed at the target of
>  * the branch as well as instruction following the delay slot
>  * of the branch.
>  */
> 
> {
>     int bkpt = 0x0005000d;      /* bpt instruction for mips */
>     int branch_type;            /* Return from is_branch() */
>     unsigned int pcregval;      /* current pc value */
> 
>     pcregval = *(int *)&registers[ PC_REGNUM * 4];
> 
>     tracebpbt.pc = 0;           /* By default, we set the trace bp branch target pc to 0 */
> 
>     branch_type = is_branch( pcregval );
>     if( branch_type != NOBRANCH )
>     {
>         /*
>          * Current instruction is a branch.  Put a breakpoint
>          * after delay slot as well as target of the branch.
>          */
> 
>         pcregval += sizeof( int ) * 2;
>         read_inferior_memory( pcregval, &tracebp.opcode, sizeof(int) );
>         tracebp.pc = pcregval;
>         write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );
> 
>         if( pcregval != branch_target_address( pcregval - sizeof( int ) * 2, branch_type ) )
>         {
>             /*
>              * It's possible we're jumping to the instruction after the delay
>              * slot.  Only put one bpt in if this is the case.
>              */
> 
>             pcregval = branch_target_address( pcregval - sizeof( int ) * 2, branch_type );
>             read_inferior_memory( pcregval, &tracebpbt.opcode, sizeof(int) );
>             tracebpbt.pc = pcregval;
>             write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );
>         }
>     }
>     else
>     {
>         /*
>          * Current instruction isn't a branch.  Set the breakpoint
>          * at the next instruction.
>          */
> 
>         pcregval += sizeof( int );
>         read_inferior_memory( pcregval, &tracebp.opcode, sizeof(int) );
>         tracebp.pc = pcregval;
>         write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );
>     }
> 
> }
> 
> int unsingle_step( void )
> 
> /*
>  * This routine is called to undo the setting of breakpoints
>  * for single stepping.  It knows enough to undo both breakpoints
>  * if previous instruction was a branch (for delay slot and target).
>  * It also knows to adjust the pc back by a word since the pc is
>  * left pointing past breakpoint instruction.
>  */
> 
> {
>     int *pcreg;                 /* Pointer to local copy of pc register */
>     int ret;
> 
>     ret = 1;
>     if( tracebpbt.pc || tracebp.pc )
>     {
> #if 0
>         /*
>          * Back up the pc by a word since bpt instruction
>          * leaves pc pointing past the bpt instruction.
>          */
> 
>         pcreg = (int *)&registers[ PC_REGNUM * 4];
>         *pcreg -= sizeof( int );
>         store_inferior_registers( PC_REGNUM );
>         fetch_inferior_registers(0);
> #endif
>         pcreg = (int *)&registers[ PC_REGNUM * 4];
>         if( ( *pcreg != tracebpbt.pc ) && ( *pcreg != tracebp.pc ) )
>         {
>             /*
>              * Stopped before we should have (could have been a signal).
>              * Ignore and try again.
>              */
> 
>             ret = 0;
>         }
>         else
>         {
>             if( tracebpbt.pc )
>                 write_inferior_memory( tracebpbt.pc, &tracebpbt.opcode, sizeof(int) );
>             if( tracebp.pc )
>                 write_inferior_memory( tracebp.pc, &tracebp.opcode, sizeof(int) );
> 
>             tracebp.pc = 0;
>             tracebpbt.pc = 0;
>         }
>     }
>     else
>     {
>         printf( "Got to unsingle_step and tracebp and tracebpbt were null\n" );
>         exit( 0 );
>     }
> 
>     return( ret );
> }
> 
> int is_branch( int adr )
> 
> /*
>  * This routine is called to determine if the current instruction is a
>  * branch type instruction.  We're called when we're being told to do
>  * an 's' command.  If it is a branch we need to put the 'break' instruction
>  * at the target of the branch as well past the delay slot of the branch.
>  */
> 
> {
>     union
>     {
>         unsigned int opcode;
>         struct
>         {
>             unsigned bits_29_31:3;
>             unsigned bits_26_28:3;
>             unsigned bits_24_25:2;
>             unsigned bits_21_23:3;
>             unsigned bits_19_20:2;
>             unsigned bits_16_18:3;
>             unsigned unused_bits:10;
>             unsigned bits_3_5:3;
>             unsigned bits_0_2:3;
>         } fields;
>     } code;                     /* opcode and bits within for decoding. */
>     int branch_type;            /* Type of branch */
> 
>     read_inferior_memory( adr, &code.opcode, sizeof(code.opcode) );
> 
>     branch_type = NOBRANCH;
> 
>     switch( code.fields.bits_29_31 )
>     {
>     case 0:
>         switch( code.fields.bits_26_28 )
>         {
>         case 0:
>             /* SPECIAL */
>             switch( code.fields.bits_3_5 )
>             {
>             case 1:
>                 switch( code.fields.bits_0_2 )
>                 {
>                 case 0:
>                 case 1:
>                     /* JR, JALR */
>                     branch_type = REG_TARGET;
>                     break;
> 
>                 default:
>                     break;
>                 }
>                 break;
> 
>             default:
>                 break;
>             }
>             break;
> 
>         case 1:
>             /* REGIMM */
>             switch( code.fields.bits_19_20 )
>             {
>             case 0:
>             case 2:
>                 switch( code.fields.bits_16_18 )
>                 {
>                 case 0:
>                 case 1:
>                 case 2:
>                 case 3:
>                     /* BLTZ, BGEZ, BLTZL, BGEZL, BLTZAL, BGEZAL, BLTZALL, BGEZALL */
>                     branch_type = OFFSET_16;
>                     break;
> 
>                 default:
>                     break;
>                 }
> 
>             default:
>                 break;
>             }
>             break;
> 
>         case 2:
>         case 3:
>             /* J, JAL */
>             branch_type = OFFSET_24;
>             break;
> 
>         case 4:
>         case 5:
>         case 6:
>         case 7:
>             /* BEQ, BNE, BLEZ, BGTZ */
>             branch_type = OFFSET_16;
>             break;
>         }
>         break;
> 
>     case 2:
>         switch( code.fields.bits_26_28 )
>         {
>         case 0:
>         case 1:
>         case 2:
>         case 3:
>             /* COPx */
>             if( ( code.fields.bits_24_25 == 1 ) && ( code.fields.bits_21_23 == 0 ) )
>                 branch_type = OFFSET_16;
>             break;
> 
>         case 4:
>         case 5:
>         case 6:
>         case 7:
>             /* BEQL, BNEL, BLEZL, BGTZL */
>             branch_type = OFFSET_16;
>             break;
>         }
>         break;
> 
>     default:
>         break;
>     }
> 
>     return( branch_type );
> }
> 
> int branch_target_address( int adr, int branch_type )
> 
> /*
>  * We're doing single step and we want to find the address of the target of
>  * the branch.  The is_branch() routine has already decoded the kind of
>  * branch.  This helps us out.
>  */
> 
> {
>     unsigned int opcode;        /* Opcode (which should be a branch */
>     int offset;                 /* 16 or 26 bit offset */
>     int target;                 /* Target of branch */
>     int reg;                    /* Register number of JR/JALR */
> 
>     read_inferior_memory( adr, &opcode, sizeof(opcode) );
> 
>     switch( branch_type )
>     {
>     case OFFSET_16:
>         offset = ( opcode & 0xffff ) << 16;
>         offset >>= 14;          /* Sign extends and shifts offset up by 2 */
>         target = (int)adr + sizeof( int ) + offset;
>         break;
> 
>     case OFFSET_24:
>         offset = ( opcode & 0x3ffffff ) << 2;
>         target = ( ( adr + sizeof( int ) ) & 0xf0000000 ) + offset;
>         break;
> 
>     case REG_TARGET:
>         reg = ( opcode >> 21 ) & 0x1f;
>         fetch_inferior_registers( reg );
>         target =  *(int *)&registers[ reg * 4];
>         break;
> 
>     default:
>         fprintf( stderr, "Unknown branch type %d\n", branch_type );
>         exit( 1 );
>     }
> 
>     return( target );
> }
> 
> ptracex( int a, int b, int c, int d )
> {
>     int ret;
> 
>     if( verbose )
>         printf( "(%x) %d %x %x -- ", a, b, c, d );
>     ret = ptrace( a, b, c, d );
>     if( verbose )
>         printf( "returning %x\n", ret );
> 
>     return( ret );
> }
> 
>   ----------------------------------------------------------------------------------------------------
> /* $Id$
> 
> Main code for remote server for GDB.
>    Copyright (C) 1989, 1993 Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> 
> 23-jan-2001     rivers  Don't subtract 4 from epc as linux kernel now doing
>                         proper thing.
>                         Stick in single step until we've actually gotten to
>                         single step instruction (ignore signals coming in).
> 28-dec-2000     rivers  Added -v option for more verbose debug output.
>                         Move 'S' handling to 's' (I really don't know what the
>                         difference is but there isn't a PTRACE_SINGLESTEP
>                         in OS support).
> 22-march-2000   rivers  Added support to attach to a process
> 
>   */
> 
> #include "server.h"
> 
> int cont_thread;
> int general_thread;
> int thread_from_wait;
> int old_thread_from_wait;
> int extended_protocol;
> jmp_buf toplevel;
> int inferior_pid;
> 
> int verbose = 0;
> 
> static unsigned char
> start_inferior (argv, statusptr)
>      char *argv[];
>      char *statusptr;
> {
>   inferior_pid = create_inferior (argv[0], argv);
>   fprintf (stderr, "Process %s created; pid = %d\n", argv[0], inferior_pid);
> 
>   /* Wait till we are at 1st instruction in program, return signal number.  */
>   return mywait (statusptr);
> }
> 
> extern int remote_debug;
> 
> int waitcheck = 0;
> 
> int
> main (argc, argv)
>      int argc;
>      char *argv[];
> {
>   char ch, status, own_buf[2000], mem_buf[2000];
>   int i = 0;
>   unsigned char signal;
>   unsigned int len;
>   CORE_ADDR mem_addr;
>   int *pcreg;
> 
>   if (setjmp(toplevel))
>     {
>       fprintf(stderr, "Exiting\n");
>       exit(1);
>     }
> 
>   while( waitcheck )
>       sleep( 1 );
> 
>   if (argc < 3)
>     error("Usage: gdbserver [-v] -a tty prog [args ...]");
> 
>   if( ( strcmp( argv[1], "-v" ) == 0 ) )
>   {
>       argv++;
>       argc--;
>       verbose = 1;
>   }
> 
>   if( ( strcmp( argv[1], "-a" ) == 0 ) && ( argc < 4 ) )
>     error("Usage: gdbserver -a tty prog [args ...]");
> 
>   if( strcmp( argv[1], "-a" ) == 0 )
>   {
>       inferior_pid = atoi( argv[3] );
> 
>       attach_inferior( );
> 
>       signal = mywait( &status );
> 
>       fprintf( stderr, "Attached to process pid = %d\n", inferior_pid );
> 
>       argv[1] = argv[0];
>       argv++;
>   }
>   else
>   {
>       /* Wait till we are at first instruction in program.  */
>       signal = start_inferior (&argv[2], &status);
>   }
> 
>   /* We are now stopped at the first instruction of the target process */
> 
>   while (1)
>     {
>         remote_open (argv[1]);
> restart:
>       setjmp(toplevel);
> 
>       while (getpkt (own_buf) > 0)
>         {
>           unsigned char sig;
> 
>           i = 0;
>           ch = own_buf[i++];
>           if( verbose )
>               printf( "Command '%c'\n", ch );
> 
>           switch (ch)
>             {
>             case 'd':
>               remote_debug = !remote_debug;
>               break;
>             case '!':
>               extended_protocol = 1;
>               prepare_resume_reply (own_buf, status, signal);
>               break;
>             case '?':
>               prepare_resume_reply (own_buf, status, signal);
>               break;
>             case 'H':
>               switch (own_buf[1])
>                 {
>                 case 'g':
>                   general_thread = strtol (&own_buf[2], NULL, 16);
>                   write_ok (own_buf);
>                   fetch_inferior_registers (0);
>                   break;
>                 case 'c':
>                   cont_thread = strtol (&own_buf[2], NULL, 16);
>                   write_ok (own_buf);
>                   break;
>                 default:
>                   /* Silently ignore it so that gdb can extend the protocol
>                      without compatibility headaches.  */
>                   own_buf[0] = '\0';
>                   break;
>                 }
>               break;
>             case 'g':
>               convert_int_to_ascii (registers, own_buf, REGISTER_BYTES);
>               break;
>             case 'G':
>               convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES);
>               store_inferior_registers (-1);
>               write_ok (own_buf);
>               break;
>             case 'm':
>               decode_m_packet (&own_buf[1], &mem_addr, &len);
>               read_inferior_memory (mem_addr, mem_buf, len);
>               convert_int_to_ascii (mem_buf, own_buf, len);
>               break;
>             case 'M':
>               decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
>               if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
>                 write_ok (own_buf);
>               else
>                 write_enn (own_buf);
>               break;
>             case 'C':
>               convert_ascii_to_int (own_buf + 1, &sig, 1);
>               myresume (0, sig);
>               signal = mywait (&status);
>               prepare_resume_reply (own_buf, status, signal);
>               break;
> #if 0
>             case 'S':
>               convert_ascii_to_int (own_buf + 1, &sig, 1);
>               myresume (1, sig);
>               signal = mywait (&status);
>               prepare_resume_reply (own_buf, status, signal);
>               break;
> #endif
>             case 'c':
>               /*
>                * 'Continue' until breakpoint (or signal) occurs.
>                * Must back pc up by a word as on breakpoint the
>                * epc points past the bpt instruction.
>                */
>               myresume (0, 0);
>               signal = mywait (&status);
> 
>               if( status == 'T' )
>               {
>                 fetch_inferior_registers(0);
>               }
> 
>               prepare_resume_reply (own_buf, status, signal);
>               break;
> 
>             case 's':
>             case 'S':
>               /*
>                * Single step target.  Fake this by reading next word
>                * past the pc, inserting a breakpoint, continuing and
>                * then restoring that word.  Also, make sure we stay
>                * until we've hit either next instruction or branch
>                * target (we might get fooled by signals).
>                */
> 
>               single_step();
>               signal = 0;
>               while( 1 )
>               {
>                   myresume (0, signal);
>                   signal = mywait (&status);
>                   if( unsingle_step() )
>                       break;
>               }
> 
>               prepare_resume_reply (own_buf, status, signal);
>               break;
> 
>             case 'k':
>               fprintf (stderr, "Killing inferior\n");
>               kill_inferior ();
>               /* When using the extended protocol, we start up a new
>                  debugging session.   The traditional protocol will
>                  exit instead.  */
>               if (extended_protocol)
>                 {
>                   write_ok (own_buf);
>                   fprintf (stderr, "GDBserver restarting\n");
> 
>                   /* Wait till we are at 1st instruction in prog.  */
>                   signal = start_inferior (&argv[2], &status);
>                   goto restart;
>                   break;
>                 }
>               else
>                 {
>                   exit (0);
>                   break;
>                 }
>             case 'T':
>               if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
>                 write_ok (own_buf);
>               else
>                 write_enn (own_buf);
>               break;
>             case 'R':
>               /* Restarting the inferior is only supported in the
>                  extended protocol.  */
>               if (extended_protocol)
>                 {
>                   kill_inferior ();
>                   write_ok (own_buf);
>                   fprintf (stderr, "GDBserver restarting\n");
> 
>                   /* Wait till we are at 1st instruction in prog.  */
>                   signal = start_inferior (&argv[2], &status);
>                   goto restart;
>                   break;
>                 }
>               else
>                 {
>                   /* It is a request we don't understand.  Respond with an
>                      empty packet so that gdb knows that we don't support this
>                      request.  */
>                   own_buf[0] = '\0';
>                   break;
>                 }
>             default:
>               /* It is a request we don't understand.  Respond with an
>                  empty packet so that gdb knows that we don't support this
>                  request.  */
>               own_buf[0] = '\0';
>               break;
>             }
> 
>           putpkt (own_buf);
> 
>           if (status == 'W')
>             fprintf (stderr,
>                      "\nChild exited with status %d\n", sig);
>           if (status == 'X')
>             fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig);
>           if (status == 'W' || status == 'X')
>             {
>               if (extended_protocol)
>                 {
>                   fprintf (stderr, "Killing inferior\n");
>                   kill_inferior ();
>                   write_ok (own_buf);
>                   fprintf (stderr, "GDBserver restarting\n");
> 
>                   /* Wait till we are at 1st instruction in prog.  */
>                   signal = start_inferior (&argv[2], &status);
>                   goto restart;
>                   break;
>                 }
>               else
>                 {
>                   fprintf (stderr, "GDBserver exiting\n");
>                   exit (0);
>                 }
>             }
>         }
> 
>       /* We come here when getpkt fails.
> 
>          For the extended remote protocol we exit (and this is the only
>          way we gracefully exit!).
> 
>          For the traditional remote protocol close the connection,
>          and re-open it at the top of the loop.  */
>       if (extended_protocol)
>         {
>           remote_close ();
>           exit (0);
>         }
>       else
>         {
>           fprintf (stderr, "Remote side has terminated connection.  GDBserver will reopen the connection.\n");
> 
>           remote_close ();
>         }
>     }
> }
> 
>   ----------------------------------------------------------------------------------------------------
> /* This is just a dummy file to symlink to when GDB is configured as a
>    cross-only debugger.  */
> 
>   ----------------------------------------------------------------------------------------------------
> /* Remote utility routines for the remote server for GDB.
>    Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
> 
> #include "server.h"
> #include "terminal.h"
> #include <stdio.h>
> #include <string.h>
> #include <sys/ioctl.h>
> #include <sys/file.h>
> #include <netinet/in.h>
> #include <sys/socket.h>
> #include <netdb.h>
> #include <netinet/tcp.h>
> #include <sys/ioctl.h>
> #include <signal.h>
> #include <fcntl.h>
> 
> int remote_debug = 0;
> 
> static int remote_desc;
> 
> /* Open a connection to a remote debugger.
>    NAME is the filename used for communication.  */
> 
> void
> remote_open (name)
>      char *name;
> {
>   int save_fcntl_flags;
> 
> /*  eeprodbg( 100 );*/
> 
>   if (!strchr (name, ':'))
>     {
>       remote_desc = open (name, O_RDWR);
>       if (remote_desc < 0)
>         perror_with_name ("Could not open remote device");
> 
> #ifdef HAVE_TERMIOS
>       {
>         struct termios termios;
>         tcgetattr(remote_desc, &termios);
> 
>         termios.c_iflag = 0;
>         termios.c_oflag = 0;
>         termios.c_lflag = 0;
>         termios.c_cflag &= ~(CSIZE|PARENB);
>         termios.c_cflag |= CLOCAL | CS8;
>         termios.c_cc[VMIN] = 0;
>         termios.c_cc[VTIME] = 0;
> 
>         tcsetattr(remote_desc, TCSANOW, &termios);
>       }
> #endif
> 
> #ifdef HAVE_TERMIO
>       {
>         struct termio termio;
>         ioctl (remote_desc, TCGETA, &termio);
> 
>         termio.c_iflag = 0;
>         termio.c_oflag = 0;
>         termio.c_lflag = 0;
>         termio.c_cflag &= ~(CSIZE|PARENB);
>         termio.c_cflag |= CLOCAL | CS8;
>         termio.c_cc[VMIN] = 0;
>         termio.c_cc[VTIME] = 0;
> 
>         ioctl (remote_desc, TCSETA, &termio);
>       }
> #endif
> 
> #ifdef HAVE_SGTTY
>       {
>         struct sgttyb sg;
> 
>         ioctl (remote_desc, TIOCGETP, &sg);
>         sg.sg_flags = RAW;
>         ioctl (remote_desc, TIOCSETP, &sg);
>       }
> #endif
> 
>     }
>   else
>     {
>       char *port_str;
>       int port;
>       struct sockaddr_in sockaddr;
>       int tmp;
>       struct protoent *protoent;
>       int tmp_desc;
> 
>       port_str = strchr (name, ':');
> 
>       port = atoi (port_str + 1);
> 
>       tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
>       if (tmp_desc < 0)
>         perror_with_name ("Can't open socket");
> 
>       /* Allow rapid reuse of this port. */
>       tmp = 1;
>       setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
>                   sizeof(tmp));
> 
>       sockaddr.sin_family = PF_INET;
>       sockaddr.sin_port = htons(port);
>       sockaddr.sin_addr.s_addr = INADDR_ANY;
> 
>       if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr))
>           || listen (tmp_desc, 1))
>         perror_with_name ("Can't bind address");
> 
>       tmp = sizeof (sockaddr);
>       remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp);
>       if (remote_desc == -1)
>         perror_with_name ("Accept failed");
> 
>       protoent = getprotobyname ("tcp");
>       if (!protoent)
>         perror_with_name ("getprotobyname");
> 
>       /* Enable TCP keep alive process. */
>       tmp = 1;
>       setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
> 
>       /* Tell TCP not to delay small packets.  This greatly speeds up
>          interactive response. */
>       tmp = 1;
>       setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY,
>                   (char *)&tmp, sizeof(tmp));
> 
>       close (tmp_desc);         /* No longer need this */
> 
>       signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply
>                                     exits when the remote side dies.  */
>     }
> 
> #if defined(F_SETFL) && defined (FASYNC)
>   save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
>   fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
>   disable_async_io ();
> #endif /* FASYNC */
>   fprintf (stderr, "Remote debugging using %s\n", name);
> }
> 
> void
> remote_close()
> {
>   close (remote_desc);
> }
> 
> /* Convert hex digit A to a number.  */
> 
> static int
> fromhex (a)
>      int a;
> {
>   if (a >= '0' && a <= '9')
>     return a - '0';
>   else if (a >= 'a' && a <= 'f')
>     return a - 'a' + 10;
>   else
>     error ("Reply contains invalid hex digit");
> }
> 
> /* Convert number NIB to a hex digit.  */
> 
> static int
> tohex (nib)
>      int nib;
> {
>   if (nib < 10)
>     return '0' + nib;
>   else
>     return 'a' + nib - 10;
> }
> 
> /* Send a packet to the remote machine, with error checking.
>    The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */
> 
> int
> putpkt (buf)
>      char *buf;
> {
>   int i;
>   unsigned char csum = 0;
>   char buf2[2000];
>   char buf3[1];
>   int cnt = strlen (buf);
>   char *p;
>   static int putpktcnt = 0;
> 
>   putpktcnt++;
>   /* Copy the packet into buffer BUF2, encapsulating it
>      and giving it a checksum.  */
> 
>   p = buf2;
>   *p++ = '$';
> 
>   for (i = 0; i < cnt; i++)
>     {
>       csum += buf[i];
>       *p++ = buf[i];
>     }
>   *p++ = '#';
>   *p++ = tohex ((csum >> 4) & 0xf);
>   *p++ = tohex (csum & 0xf);
> 
>   *p = '\0';
> 
>   /* Send it over and over until we get a positive ack.  */
> 
>   do
>     {
>       int cc;
> 
>       if (write (remote_desc, buf2, p - buf2) != p - buf2)
>         {
>           perror ("putpkt(write)");
>           return -1;
>         }
> 
>       if (remote_debug)
>         printf ("putpkt %d (\"%s\"); [looking for ack]\n", putpktcnt, buf2);
>       cc = read (remote_desc, buf3, 1);
>       if (remote_debug)
>         printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
>       if (cc <= 0)
>         {
>           if (cc == 0)
>             fprintf (stderr, "putpkt(read): Got EOF\n");
>           else
>             perror ("putpkt(read)");
> 
>           return -1;
>         }
>     }
>   while (buf3[0] != '+');
> 
>   return 1;                     /* Success! */
> }
> 
> /* Come here when we get an input interrupt from the remote side.  This
>    interrupt should only be active while we are waiting for the child to do
>    something.  About the only thing that should come through is a ^C, which
>    will cause us to send a SIGINT to the child.  */
> 
> static void
> input_interrupt()
> {
>   int cc;
>   char c;
> 
>   cc = read (remote_desc, &c, 1);
> 
>   if (cc != 1 || c != '\003')
>     {
>       fprintf(stderr, "input_interrupt, cc = %d c = %d\n", cc, c);
>       return;
>     }
> 
>   kill (inferior_pid, SIGINT);
> }
> 
> void
> enable_async_io()
> {
>   signal (SIGIO, input_interrupt);
> }
> 
> void
> disable_async_io()
> {
>   signal (SIGIO, SIG_IGN);
> }
> 
> /* Returns next char from remote GDB.  -1 if error.  */
> 
> static int
> readchar ()
> {
>   static char buf[BUFSIZ];
>   static int bufcnt = 0;
>   static char *bufp;
> 
>   if (bufcnt-- > 0)
>     return *bufp++ & 0x7f;
> 
>   bufcnt = read (remote_desc, buf, sizeof (buf));
> 
>   if (bufcnt <= 0)
>     {
>       if (bufcnt == 0)
>         fprintf (stderr, "readchar: Got EOF\n");
>       else
>         perror ("readchar");
> 
>       return -1;
>     }
> 
>   bufp = buf;
>   bufcnt--;
>   return *bufp++ & 0x7f;
> }
> 
> /* Read a packet from the remote machine, with error checking,
>    and store it in BUF.  Returns length of packet, or negative if error. */
> 
> int
> getpkt (buf)
>      char *buf;
> {
>   char *bp;
>   unsigned char csum, c1, c2;
>   int c;
>   static int getpktcnt = 0;
> 
>   getpktcnt++;
>   while (1)
>     {
>       csum = 0;
> 
>       while (1)
>         {
>           c = readchar ();
>           if (c == '$')
>             break;
>           if (remote_debug)
>             printf ("[getpkt: discarding char '%c']\n", c);
>           if (c < 0)
>             return -1;
>         }
> 
>       bp = buf;
>       while (1)
>         {
>           c = readchar ();
>           if (c < 0)
>             return -1;
>           if (c == '#')
>             break;
>           *bp++ = c;
>           csum += c;
>         }
>       *bp = 0;
> 
>       c1 = fromhex (readchar ());
>       c2 = fromhex (readchar ());
> 
>       if (csum == (c1 << 4) + c2)
>         break;
> 
>       fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
>                (c1 << 4) + c2, csum, buf);
>       write (remote_desc, "-", 1);
>     }
> 
>   if (remote_debug)
>     printf ("getpkt %d (\"%s\");  [sending ack] \n", getpktcnt, buf);
> 
>   write (remote_desc, "+", 1);
> 
>   if (remote_debug)
>     printf ("[sent ack]\n");
>   return bp - buf;
> }
> 
> void
> write_ok (buf)
>      char *buf;
> {
>   buf[0] = 'O';
>   buf[1] = 'K';
>   buf[2] = '\0';
> }
> 
> void
> write_enn (buf)
>      char *buf;
> {
>   buf[0] = 'E';
>   buf[1] = 'N';
>   buf[2] = 'N';
>   buf[3] = '\0';
> }
> 
> void
> convert_int_to_ascii (from, to, n)
>      char *from, *to;
>      int n;
> {
>   int nib;
>   char ch;
>   while (n--)
>     {
>       ch = *from++;
>       nib = ((ch & 0xf0) >> 4) & 0x0f;
>       *to++ = tohex (nib);
>       nib = ch & 0x0f;
>       *to++ = tohex (nib);
>     }
>   *to++ = 0;
> }
> 
> void
> convert_ascii_to_int (from, to, n)
>      char *from, *to;
>      int n;
> {
>   int nib1, nib2;
>   while (n--)
>     {
>       nib1 = fromhex (*from++);
>       nib2 = fromhex (*from++);
>       *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
>     }
> }
> 
> static char *
> outreg(regno, buf)
>      int regno;
>      char *buf;
> {
>   extern char registers[];
>   int regsize = REGISTER_RAW_SIZE (regno);
> 
>   *buf++ = tohex (regno >> 4);
>   *buf++ = tohex (regno & 0xf);
>   *buf++ = ':';
>   convert_int_to_ascii (&registers[REGISTER_BYTE (regno)], buf, regsize);
>   buf += 2 * regsize;
>   *buf++ = ';';
> 
>   return buf;
> }
> 
> void
> prepare_resume_reply (buf, status, signo)
>      char *buf;
>      char status;
>      unsigned char signo;
> {
>   int nib;
> 
>   *buf++ = status;
> 
>   /* FIXME!  Should be converting this signal number (numbered
>      according to the signal numbering of the system we are running on)
>      to the signal numbers used by the gdb protocol (see enum target_signal
>      in gdb/target.h).  */
>   nib = ((signo & 0xf0) >> 4);
>   *buf++ = tohex (nib);
>   nib = signo & 0x0f;
>   *buf++ = tohex (nib);
> 
>   if (status == 'T')
>     {
>       buf = outreg (PC_REGNUM, buf);
>       buf = outreg (FP_REGNUM, buf);
>       buf = outreg (SP_REGNUM, buf);
> #ifdef NPC_REGNUM
>       buf = outreg (NPC_REGNUM, buf);
> #endif
> #ifdef O7_REGNUM
>       buf = outreg (O7_REGNUM, buf);
> #endif
> 
>       /* If the debugger hasn't used any thread features, don't burden it with
>          threads.  If we didn't check this, GDB 4.13 and older would choke.  */
>       if (cont_thread != 0)
>         {
>           if (old_thread_from_wait != thread_from_wait)
>             {
>               sprintf (buf, "thread:%x;", thread_from_wait);
>               buf += strlen (buf);
>               old_thread_from_wait = thread_from_wait;
>             }
>         }
>     }
>   /* For W and X, we're done.  */
>   *buf++ = 0;
> }
> 
> void
> decode_m_packet (from, mem_addr_ptr, len_ptr)
>      char *from;
>      CORE_ADDR *mem_addr_ptr;
>      unsigned int *len_ptr;
> {
>   int i = 0, j = 0;
>   char ch;
>   *mem_addr_ptr = *len_ptr = 0;
> 
>   while ((ch = from[i++]) != ',')
>     {
>       *mem_addr_ptr = *mem_addr_ptr << 4;
>       *mem_addr_ptr |= fromhex (ch) & 0x0f;
>     }
> 
>   for (j = 0; j < 4; j++)
>     {
>       if ((ch = from[i++]) == 0)
>         break;
>       *len_ptr = *len_ptr << 4;
>       *len_ptr |= fromhex (ch) & 0x0f;
>     }
> }
> 
> void
> decode_M_packet (from, mem_addr_ptr, len_ptr, to)
>      char *from, *to;
>      CORE_ADDR *mem_addr_ptr;
>      unsigned int *len_ptr;
> {
>   int i = 0;
>   char ch;
>   *mem_addr_ptr = *len_ptr = 0;
> 
>   while ((ch = from[i++]) != ',')
>     {
>       *mem_addr_ptr = *mem_addr_ptr << 4;
>       *mem_addr_ptr |= fromhex (ch) & 0x0f;
>     }
> 
>   while ((ch = from[i++]) != ':')
>     {
>       *len_ptr = *len_ptr << 4;
>       *len_ptr |= fromhex (ch) & 0x0f;
>     }
> 
>   convert_ascii_to_int (&from[i++], to, *len_ptr);
> }
> 
>   ----------------------------------------------------------------------------------------------------
> /* $Id$ Common definitions for remote server for GDB.
>    Copyright (C) 1993 Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
> 
> #include "defs.h"
> #include <setjmp.h>
> 
> /* Target-specific functions */
> 
> int create_inferior PARAMS ((char *program, char **allargs));
> void kill_inferior PARAMS ((void));
> void attach_inferior PARAMS ((void));
> void fetch_inferior_registers PARAMS ((int regno));
> void store_inferior_registers PARAMS ((int regno));
> int mythread_alive PARAMS ((int pid));
> void myresume PARAMS ((int step, int signo));
> unsigned char mywait PARAMS ((char *status));
> void read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
> int write_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
> int create_inferior ();
> void single_step( void );
> int unsingle_step( void );
> 
> /* Target-specific variables */
> 
> extern char registers[];
> 
> /* Public variables in server.c */
> 
> extern int cont_thread;
> extern int general_thread;
> extern int thread_from_wait;
> extern int old_thread_from_wait;
> 
> extern jmp_buf toplevel;
> extern int inferior_pid;
> 
> /* Functions from remote-utils.c */
> 
> int putpkt PARAMS ((char *buf));
> int getpkt PARAMS ((char *buf));
> void remote_open PARAMS ((char *name));
> void remote_close PARAMS ((void));
> void write_ok PARAMS ((char *buf));
> void write_enn PARAMS ((char *buf));
> void enable_async_io PARAMS ((void));
> void disable_async_io PARAMS ((void));
> void convert_ascii_to_int PARAMS ((char *from, char *to, int n));
> void convert_int_to_ascii PARAMS ((char *from, char *to, int n));
> void prepare_resume_reply PARAMS ((char *buf, char status, unsigned char sig));
> 
> void decode_m_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
>                              unsigned int *len_ptr));
> void decode_M_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
>                              unsigned int *len_ptr, char *to));
> 
> /* Functions from utils.c */
> 
> /*void perror_with_name PARAMS ((char *string));*/
> 
>   ----------------------------------------------------------------------------------------------------
> /* $Id$
> 
> Definitions to make GDB run on a mips box under 4.3bsd.
>    Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
>    Free Software Foundation, Inc.
>    Contributed by Per Bothner (bothner@cs.wisc.edu) at U.Wisconsin
>    and by Alessandro Forin (af@cs.cmu.edu) at CMU..
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> 
> 28-dec-2000     rivers  All registers are 4 bytes, even floating point.
> 
>  */
> 
> #ifndef TM_MIPS_H
> #define TM_MIPS_H 1
> 
> #ifdef __STDC__
> struct frame_info;
> struct symbol;
> struct type;
> struct value;
> #endif
> 
> #include <bfd.h>
> #include "coff/sym.h"           /* Needed for PDR below.  */
> #include "coff/symconst.h"
> 
> #if !defined (TARGET_BYTE_ORDER_DEFAULT)
> #define TARGET_BYTE_ORDER_DEFAULT LITTLE_ENDIAN
> #endif
> 
> #if !defined (GDB_TARGET_IS_MIPS64)
> #define GDB_TARGET_IS_MIPS64 0
> #endif
> 
> #if !defined (MIPS_EABI)
> #define MIPS_EABI 0
> #endif
> 
> #if !defined (TARGET_MONITOR_PROMPT)
> #define TARGET_MONITOR_PROMPT "<IDT>"
> #endif
> 
> /* PC should be masked to remove possible MIPS16 flag */
> #if !defined (GDB_TARGET_MASK_DISAS_PC)
> #define GDB_TARGET_MASK_DISAS_PC(addr) UNMAKE_MIPS16_ADDR(addr)
> #endif
> #if !defined (GDB_TARGET_UNMASK_DISAS_PC)
> #define GDB_TARGET_UNMASK_DISAS_PC(addr) MAKE_MIPS16_ADDR(addr)
> #endif
> 
> /* Floating point is IEEE compliant */
> #define IEEE_FLOAT
> 
> /* The name of the usual type of MIPS processor that is in the target
>    system.  */
> 
> #define DEFAULT_MIPS_TYPE "generic"
> 
> /* Remove useless bits from an instruction address.  */
> 
> #define ADDR_BITS_REMOVE(addr) mips_addr_bits_remove(addr)
> CORE_ADDR mips_addr_bits_remove PARAMS ((CORE_ADDR addr));
> 
> /* Remove useless bits from the stack pointer.  */
> 
> #define TARGET_READ_SP() ADDR_BITS_REMOVE (read_register (SP_REGNUM))
> 
> /* Offset from address of function to start of its code.
>    Zero on most machines.  */
> 
> #define FUNCTION_START_OFFSET 0
> 
> /* Advance PC across any function entry prologue instructions
>    to reach some "real" code.  */
> 
> #define SKIP_PROLOGUE(pc)       pc = mips_skip_prologue (pc, 0)
> extern CORE_ADDR mips_skip_prologue PARAMS ((CORE_ADDR addr, int lenient));
> 
> /* Return non-zero if PC points to an instruction which will cause a step
>    to execute both the instruction at PC and an instruction at PC+4.  */
> extern int mips_step_skips_delay PARAMS ((CORE_ADDR));
> #define STEP_SKIPS_DELAY_P (1)
> #define STEP_SKIPS_DELAY(pc) (mips_step_skips_delay (pc))
> 
> /* Immediately after a function call, return the saved pc.
>    Can't always go through the frames for this because on some machines
>    the new frame is not set up until the new function executes
>    some instructions.  */
> 
> #define SAVED_PC_AFTER_CALL(frame)      read_register(RA_REGNUM)
> 
> /* Are we currently handling a signal */
> 
> extern int in_sigtramp PARAMS ((CORE_ADDR, char *));
> #define IN_SIGTRAMP(pc, name)   in_sigtramp(pc, name)
> 
> /* Stack grows downward.  */
> 
> #define INNER_THAN(lhs,rhs) ((lhs) < (rhs))
> 
> #define BIG_ENDIAN 4321
> 
> /* BREAKPOINT_FROM_PC uses the program counter value to determine whether a
>    16- or 32-bit breakpoint should be used.  It returns a pointer
>    to a string of bytes that encode a breakpoint instruction, stores
>    the length of the string to *lenptr, and adjusts the pc (if necessary) to
>    point to the actual memory location where the breakpoint should be
>    inserted.  */
> 
> extern breakpoint_from_pc_fn mips_breakpoint_from_pc;
> #define BREAKPOINT_FROM_PC(pcptr, lenptr) mips_breakpoint_from_pc(pcptr, lenptr)
> 
> /* Amount PC must be decremented by after a breakpoint.
>    This is often the number of bytes in BREAKPOINT
>    but not always.  */
> 
> #define DECR_PC_AFTER_BREAK 0
> 
> /* Say how long (ordinary) registers are.  This is a piece of bogosity
>    used in push_word and a few other places; REGISTER_RAW_SIZE is the
>    real way to know how big a register is.  */
> 
> #define REGISTER_SIZE 4
> 
> /* The size of a register.  This is predefined in tm-mips64.h.  We
>    can't use REGISTER_SIZE because that is used for various other
>    things.  */
> 
> #ifndef MIPS_REGSIZE
> #define MIPS_REGSIZE 4
> #endif
> 
> /* The sizes of floating point registers.  */
> 
> #define MIPS_FPU_SINGLE_REGSIZE 4
> #define MIPS_FPU_DOUBLE_REGSIZE 8
> 
> /* Number of machine registers */
> 
> #ifndef NUM_REGS
> #define NUM_REGS 90
> #endif
> 
> /* Initializer for an array of names of registers.
>    There should be NUM_REGS strings in this initializer.  */
> 
> #ifndef REGISTER_NAMES
> #define REGISTER_NAMES  \
>     {   "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3", \
>         "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7", \
>         "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7", \
>         "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra", \
>         "sr",   "lo",   "hi",   "bad",  "cause","pc",    \
>         "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7", \
>         "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15", \
>         "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",\
>         "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",\
>         "fsr",  "fir",  "fp",   "", \
>         "",     "",     "",     "",     "",     "",     "",     "", \
>         "",     "",     "",     "",     "",     "",     "",     "", \
>     }
> #endif
> 
> /* Register numbers of various important registers.
>    Note that some of these values are "real" register numbers,
>    and correspond to the general registers of the machine,
>    and some are "phony" register numbers which are too large
>    to be actual register numbers as far as the user is concerned
>    but do serve to get the desired values when passed to read_register.  */
> 
> #define ZERO_REGNUM 0           /* read-only register, always 0 */
> #define V0_REGNUM 2             /* Function integer return value */
> #define A0_REGNUM 4             /* Loc of first arg during a subr call */
> #if MIPS_EABI
> #  define MIPS_LAST_ARG_REGNUM 11 /* EABI uses R4 through R11 for args */
> #  define MIPS_NUM_ARG_REGS 8
> #else
> #  define MIPS_LAST_ARG_REGNUM 7  /* old ABI uses R4 through R7 for args */
> #  define MIPS_NUM_ARG_REGS 4
> #endif
> #define T9_REGNUM 25            /* Contains address of callee in PIC */
> #define SP_REGNUM 29            /* Contains address of top of stack */
> #define RA_REGNUM 31            /* Contains return address value */
> #define PS_REGNUM 32            /* Contains processor status */
> #define HI_REGNUM 34            /* Multiple/divide temp */
> #define LO_REGNUM 33            /* ... */
> #define BADVADDR_REGNUM 35      /* bad vaddr for addressing exception */
> #define CAUSE_REGNUM 36         /* describes last exception */
> #define PC_REGNUM 37            /* Contains program counter */
> #define FP0_REGNUM 38           /* Floating point register 0 (single float) */
> #define FPA0_REGNUM (FP0_REGNUM+12) /* First float argument register */
> #if MIPS_EABI                   /* EABI uses F12 through F19 for args */
> #  define MIPS_LAST_FP_ARG_REGNUM (FP0_REGNUM+19)
> #  define MIPS_NUM_FP_ARG_REGS 8
> #else                           /* old ABI uses F12 through F15 for args */
> #  define MIPS_LAST_FP_ARG_REGNUM (FP0_REGNUM+15)
> #  define MIPS_NUM_FP_ARG_REGS 4
> #endif
> #define FCRCS_REGNUM 70         /* FP control/status */
> #define FCRIR_REGNUM 71         /* FP implementation/revision */
> #define FP_REGNUM 72            /* Pseudo register that contains true address of executing stack frame */
> #define UNUSED_REGNUM 73        /* Never used, FIXME */
> #define FIRST_EMBED_REGNUM 74   /* First CP0 register for embedded use */
> #define PRID_REGNUM 89          /* Processor ID */
> #define LAST_EMBED_REGNUM 89    /* Last one */
> 
> /* Define DO_REGISTERS_INFO() to do machine-specific formatting
>    of register dumps. */
> 
> #define DO_REGISTERS_INFO(_regnum, fp) mips_do_registers_info(_regnum, fp)
> extern void mips_do_registers_info PARAMS ((int, int));
> 
> /* Total amount of space needed to store our copies of the machine's
>    register state, the array `registers'.  */
> 
> #define REGISTER_BYTES (NUM_REGS*MIPS_REGSIZE)
> 
> /* Index within `registers' of the first byte of the space for
>    register N.  */
> 
> #define REGISTER_BYTE(N) ((N) * MIPS_REGSIZE)
> 
> /* Number of bytes of storage in the actual machine representation
>    for register N. */
> 
> #define REGISTER_RAW_SIZE(N) REGISTER_VIRTUAL_SIZE(N)
> 
> /* Number of bytes of storage in the program's representation
>    for register N. */
> 
> #define REGISTER_VIRTUAL_SIZE(N) (REGISTER_VIRTUAL_TYPE (N))
> 
> /* Largest value REGISTER_RAW_SIZE can have.  */
> 
> #define MAX_REGISTER_RAW_SIZE 4
> 
> /* Largest value REGISTER_VIRTUAL_SIZE can have.  */
> 
> #define MAX_REGISTER_VIRTUAL_SIZE 4
> 
> /* Return the GDB type object for the "standard" data type of data in
>    register N.  */
> 
> #ifndef REGISTER_VIRTUAL_TYPE
> #define REGISTER_VIRTUAL_TYPE(N) \
>         (((N) >= FP0_REGNUM && (N) < FP0_REGNUM+32) ? 4 \
>          : ((N) == 32 /*SR*/) ? 4 \
>          : ((N) >= 70 && (N) <= 89) ? 4 \
>          : 4)
> #endif
> 
> /* All mips targets store doubles in a register pair with the least
>    significant register in the lower numbered register.
>    If the target is big endian, double register values need conversion
>    between memory and register formats.  */
> 
> #define REGISTER_CONVERT_TO_TYPE(n, type, buffer)                       \
>   do {if (TARGET_BYTE_ORDER == BIG_ENDIAN                               \
>           && REGISTER_RAW_SIZE (n) == 4                                 \
>           && (n) >= FP0_REGNUM && (n) < FP0_REGNUM + 32                 \
>           && TYPE_CODE(type) == TYPE_CODE_FLT                           \
>           && TYPE_LENGTH(type) == 4) {                                  \
>         char __temp[4];                                                 \
>         memcpy (__temp, ((char *)(buffer))+4, 4);                       \
>         memcpy (((char *)(buffer))+4, (buffer), 4);                     \
>         memcpy (((char *)(buffer)), __temp, 4); }} while (0)
> 
> #define REGISTER_CONVERT_FROM_TYPE(n, type, buffer)                     \
>   do {if (TARGET_BYTE_ORDER == BIG_ENDIAN                               \
>           && REGISTER_RAW_SIZE (n) == 4                                 \
>           && (n) >= FP0_REGNUM && (n) < FP0_REGNUM + 32                 \
>           && TYPE_CODE(type) == TYPE_CODE_FLT                           \
>           && TYPE_LENGTH(type) == 4) {                                  \
>         char __temp[4];                                                 \
>         memcpy (__temp, ((char *)(buffer))+4, 4);                       \
>         memcpy (((char *)(buffer))+4, (buffer), 4);                     \
>         memcpy (((char *)(buffer)), __temp, 4); }} while (0)
> 
> /* Store the address of the place in which to copy the structure the
>    subroutine will return.  Handled by mips_push_arguments.  */
> 
> #define STORE_STRUCT_RETURN(addr, sp)   /**/
> 
> /* Extract from an array REGBUF containing the (raw) register state
>    a function return value of type TYPE, and copy that, in virtual format,
>    into VALBUF.  XXX floats */
> 
> #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
>   mips_extract_return_value(TYPE, REGBUF, VALBUF)
> extern void
> mips_extract_return_value PARAMS ((struct type *, char [], char *));
> 
> /* Write into appropriate registers a function return value
>    of type TYPE, given in virtual format.  */
> 
> #define STORE_RETURN_VALUE(TYPE,VALBUF) \
>   mips_store_return_value(TYPE, VALBUF)
> extern void mips_store_return_value PARAMS ((struct type *, char *));
> 
> /* Extract from an array REGBUF containing the (raw) register state
>    the address in which a function should return its structure value,
>    as a CORE_ADDR (or an expression that can be used as one).  */
> /* The address is passed in a0 upon entry to the function, but when
>    the function exits, the compiler has copied the value to v0.  This
>    convention is specified by the System V ABI, so I think we can rely
>    on it.  */
> 
> #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
>   (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \
>                     REGISTER_RAW_SIZE (V0_REGNUM)))
> 
> extern use_struct_convention_fn mips_use_struct_convention;
> #define USE_STRUCT_CONVENTION(gcc_p, type) mips_use_struct_convention (gcc_p, type)
> 
> /* Describe the pointer in each stack frame to the previous stack frame
>    (its caller).  */
> 
> /* FRAME_CHAIN takes a frame's nominal address
>    and produces the frame's chain-pointer. */
> 
> #define FRAME_CHAIN(thisframe) (CORE_ADDR) mips_frame_chain (thisframe)
> extern CORE_ADDR mips_frame_chain PARAMS ((struct frame_info *));
> 
> /* Define other aspects of the stack frame.  */
> 
> /* A macro that tells us whether the function invocation represented
>    by FI does not have a frame on the stack associated with it.  If it
>    does not, FRAMELESS is set to 1, else 0.  */
> /* We handle this differently for mips, and maybe we should not */
> 
> #define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS)  {(FRAMELESS) = 0;}
> 
> /* Saved Pc.  */
> 
> #define FRAME_SAVED_PC(FRAME)   (mips_frame_saved_pc(FRAME))
> extern CORE_ADDR mips_frame_saved_pc PARAMS ((struct frame_info *));
> 
> #define FRAME_ARGS_ADDRESS(fi)  (fi)->frame
> 
> #define FRAME_LOCALS_ADDRESS(fi) (fi)->frame
> 
> /* Return number of args passed to a frame.
>    Can return -1, meaning no way to tell.  */
> 
> #define FRAME_NUM_ARGS(num, fi) (num = mips_frame_num_args(fi))
> extern int mips_frame_num_args PARAMS ((struct frame_info *));
> 
> /* Return number of bytes at start of arglist that are not really args.  */
> 
> #define FRAME_ARGS_SKIP 0
> 
> /* Put here the code to store, into a struct frame_saved_regs,
>    the addresses of the saved registers of frame described by FRAME_INFO.
>    This includes special registers such as pc and fp saved in special
>    ways in the stack frame.  sp is even more special:
>    the address we return for it IS the sp for the next frame.  */
> 
> #define FRAME_INIT_SAVED_REGS(frame_info) \
>   do { \
>     if ((frame_info)->saved_regs == NULL) \
>       mips_find_saved_regs (frame_info); \
>     (frame_info)->saved_regs[SP_REGNUM] = (frame_info)->frame; \
>   } while (0)
> extern void mips_find_saved_regs PARAMS ((struct frame_info *));
> 
> /* Things needed for making the inferior call functions.  */
> 
> /* Stack must be aligned on 32-bit boundaries when synthesizing
>    function calls.  We don't need STACK_ALIGN, PUSH_ARGUMENTS will
>    handle it. */
> 
> #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
>     sp = mips_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr))
> extern CORE_ADDR
> mips_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR));
> 
> /* Push an empty stack frame, to record the current PC, etc.  */
> 
> #define PUSH_DUMMY_FRAME        mips_push_dummy_frame()
> extern void mips_push_dummy_frame PARAMS ((void));
> 
> /* Discard from the stack the innermost frame, restoring all registers.  */
> 
> #define POP_FRAME               mips_pop_frame()
> extern void mips_pop_frame PARAMS ((void));
> 
> #define CALL_DUMMY { 0 }
> 
> #define CALL_DUMMY_START_OFFSET (0)
> 
> #define CALL_DUMMY_BREAKPOINT_OFFSET (0)
> 
> /* On Irix, $t9 ($25) contains the address of the callee (used for PIC).
>    It doesn't hurt to do this on other systems; $t9 will be ignored.  */
> #define FIX_CALL_DUMMY(dummyname, start_sp, fun, nargs, args, rettype, gcc_p) \
>     write_register(T9_REGNUM, fun)
> 
> #define CALL_DUMMY_LOCATION AT_ENTRY_POINT
> 
> #define CALL_DUMMY_ADDRESS() (mips_call_dummy_address ())
> extern CORE_ADDR mips_call_dummy_address PARAMS ((void));
> 
> /* There's a mess in stack frame creation.  See comments in blockframe.c
>    near reference to INIT_FRAME_PC_FIRST.  */
> 
> #define INIT_FRAME_PC(fromleaf, prev) /* nada */
> 
> #define INIT_FRAME_PC_FIRST(fromleaf, prev) \
>    mips_init_frame_pc_first(fromleaf, prev)
> extern void mips_init_frame_pc_first PARAMS ((int, struct frame_info *));
> 
> /* Special symbol found in blocks associated with routines.  We can hang
>    mips_extra_func_info_t's off of this.  */
> 
> #define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
> extern void ecoff_relocate_efi PARAMS ((struct symbol *, CORE_ADDR));
> 
> /* Specific information about a procedure.
>    This overlays the MIPS's PDR records,
>    mipsread.c (ab)uses this to save memory */
> 
> typedef struct mips_extra_func_info {
>         long    numargs;        /* number of args to procedure (was iopt) */
>         bfd_vma high_addr;      /* upper address bound */
>         long    frame_adjust;   /* offset of FP from SP (used on MIPS16) */
>         PDR     pdr;            /* Procedure descriptor record */
> } *mips_extra_func_info_t;
> 
> #define EXTRA_FRAME_INFO \
>   mips_extra_func_info_t proc_desc; \
>   int num_args;
> 
> #define INIT_EXTRA_FRAME_INFO(fromleaf, fci) init_extra_frame_info(fci)
> extern void init_extra_frame_info PARAMS ((struct frame_info *));
> 
> #define PRINT_EXTRA_FRAME_INFO(fi) \
>   { \
>     if (fi && fi->proc_desc && fi->proc_desc->pdr.framereg < NUM_REGS) \
>       printf_filtered (" frame pointer is at %s+%d\n", \
>                        REGISTER_NAME (fi->proc_desc->pdr.framereg), \
>                                  fi->proc_desc->pdr.frameoffset); \
>   }
> 
> /* It takes two values to specify a frame on the MIPS.
> 
>    In fact, the *PC* is the primary value that sets up a frame.  The
>    PC is looked up to see what function it's in; symbol information
>    from that function tells us which register is the frame pointer
>    base, and what offset from there is the "virtual frame pointer".
>    (This is usually an offset from SP.)  On most non-MIPS machines,
>    the primary value is the SP, and the PC, if needed, disambiguates
>    multiple functions with the same SP.  But on the MIPS we can't do
>    that since the PC is not stored in the same part of the frame every
>    time.  This does not seem to be a very clever way to set up frames,
>    but there is nothing we can do about that).  */
> 
> #define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv)
> extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *));
> 
> /* Convert a dbx stab register number (from `r' declaration) to a gdb REGNUM */
> 
> #define STAB_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-38)
> 
> /* Convert a ecoff register number to a gdb REGNUM */
> 
> #define ECOFF_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-32)
> 
> /* If the current gcc for for this target does not produce correct debugging
>    information for float parameters, both prototyped and unprototyped, then
>    define this macro.  This forces gdb to  always assume that floats are
>    passed as doubles and then converted in the callee.
> 
>    For the mips chip, it appears that the debug info marks the parameters as
>    floats regardless of whether the function is prototyped, but the actual
>    values are passed as doubles for the non-prototyped case and floats for
>    the prototyped case.  Thus we choose to make the non-prototyped case work
>    for C and break the prototyped case, since the non-prototyped case is
>    probably much more common.  (FIXME). */
> 
> #define COERCE_FLOAT_TO_DOUBLE (current_language -> la_language == language_c)
> 
> /* Select the default mips disassembler */
> 
> #define TM_PRINT_INSN_MACH 0
> 
> /* These are defined in mdebugread.c and are used in mips-tdep.c  */
> extern CORE_ADDR sigtramp_address, sigtramp_end;
> extern void fixup_sigtramp PARAMS ((void));
> 
> /* Defined in mips-tdep.c and used in remote-mips.c */
> extern char *mips_read_processor_type PARAMS ((void));
> 
> /* Functions for dealing with MIPS16 call and return stubs.  */
> #define IN_SOLIB_CALL_TRAMPOLINE(pc, name)      mips_in_call_stub (pc, name)
> #define IN_SOLIB_RETURN_TRAMPOLINE(pc, name)    mips_in_return_stub (pc, name)
> #define SKIP_TRAMPOLINE_CODE(pc)                mips_skip_stub (pc)
> #define IGNORE_HELPER_CALL(pc)                  mips_ignore_helper (pc)
> extern int mips_in_call_stub PARAMS ((CORE_ADDR pc,  char *name));
> extern int mips_in_return_stub PARAMS ((CORE_ADDR pc,  char *name));
> extern CORE_ADDR mips_skip_stub PARAMS ((CORE_ADDR pc));
> extern int mips_ignore_helper PARAMS ((CORE_ADDR pc));
> 
> #ifndef TARGET_MIPS
> #define TARGET_MIPS
> #endif
> 
> /* Definitions and declarations used by mips-tdep.c and remote-mips.c  */
> #define MIPS_INSTLEN 4          /* Length of an instruction */
> #define MIPS16_INSTLEN 2        /* Length of an instruction on MIPS16*/
> #define MIPS_NUMREGS 32         /* Number of integer or float registers */
> typedef unsigned long t_inst;   /* Integer big enough to hold an instruction */
> 
> /* MIPS16 function addresses are odd (bit 0 is set).  Here are some
>    macros to test, set, or clear bit 0 of addresses.  */
> #define IS_MIPS16_ADDR(addr)     ((addr) & 1)
> #define MAKE_MIPS16_ADDR(addr)   ((addr) | 1)
> #define UNMAKE_MIPS16_ADDR(addr) ((addr) & ~1)
> 
> #endif  /* TM_MIPS_H */
> 
> /* Macros for setting and testing a bit in a minimal symbol that
>    marks it as 16-bit function.  The MSB of the minimal symbol's
>    "info" field is used for this purpose. This field is already
>    being used to store the symbol size, so the assumption is
>    that the symbol size cannot exceed 2^31.
> 
>    ELF_MAKE_MSYMBOL_SPECIAL
>                         tests whether an ELF symbol is "special", i.e. refers
>                         to a 16-bit function, and sets a "special" bit in a
>                         minimal symbol to mark it as a 16-bit function
>    MSYMBOL_IS_SPECIAL   tests the "special" bit in a minimal symbol
>    MSYMBOL_SIZE         returns the size of the minimal symbol, i.e.
>                         the "info" field with the "special" bit masked out
> */
> 
> #define ELF_MAKE_MSYMBOL_SPECIAL(sym,msym) \
>  { \
>   if (((elf_symbol_type *)(sym))->internal_elf_sym.st_other == STO_MIPS16) { \
>     MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) | 0x80000000); \
>     SYMBOL_VALUE_ADDRESS (msym) |= 1; \
>   } \
>  }
> 
> #define MSYMBOL_IS_SPECIAL(msym) \
>   (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
> #define MSYMBOL_SIZE(msym) \
>   ((long) MSYMBOL_INFO (msym) & 0x7fffffff)
> 
>   ----------------------------------------------------------------------------------------------------
> /* General utility routines for the remote server for GDB.
>    Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
> 
> #include "server.h"
> #include <stdio.h>
> #include <string.h>
> 
> /* Generally useful subroutines used throughout the program.  */
> 
> /* Print the system error message for errno, and also mention STRING
>    as the file name for which the error was encountered.
>    Then return to command level.  */
> 
> void
> perror_with_name (string)
>      char *string;
> {
>   extern int sys_nerr;
> /*  extern char *sys_errlist[];*/
>   extern int errno;
>   char *err;
>   char *combined;
> 
>   if (errno < sys_nerr)
>     err = sys_errlist[errno];
>   else
>     err = "unknown error";
> 
>   combined = (char *) alloca (strlen (err) + strlen (string) + 3);
>   strcpy (combined, string);
>   strcat (combined, ": ");
>   strcat (combined, err);
> 
>   error ("%s.", combined);
> }
> 
> /* Print an error message and return to command level.
>    STRING is the error message, used as a fprintf string,
>    and ARG is passed as an argument to it.  */
> 
> #ifdef ANSI_PROTOTYPES
> NORETURN void
> error (const char *string, ...)
> #else
> void
> error (va_alist)
>      va_dcl
> #endif
> {
>   extern jmp_buf toplevel;
>   va_list args;
> #ifdef ANSI_PROTOTYPES
>   va_start (args, string);
> #else
>   va_start (args);
> #endif
>   fflush (stdout);
> #ifdef ANSI_PROTOTYPES
>   vfprintf (stderr, string, args);
> #else
>   {
>     char *string1;
> 
>     string1 = va_arg (args, char *);
>     vfprintf (stderr, string1, args);
>   }
> #endif
>   fprintf (stderr, "\n");
>   longjmp(toplevel, 1);
> }
> 
> /* Print an error message and exit reporting failure.
>    This is for a error that we cannot continue from.
>    STRING and ARG are passed to fprintf.  */
> 
> /* VARARGS */
> NORETURN void
> #ifdef ANSI_PROTOTYPES
> fatal (char *string, ...)
> #else
> fatal (va_alist)
>      va_dcl
> #endif
> {
>   va_list args;
> #ifdef ANSI_PROTOTYPES
>   va_start (args, string);
> #else
>   char *string;
>   va_start (args);
>   string = va_arg (args, char *);
> #endif
>   fprintf (stderr, "gdb: ");
>   vfprintf (stderr, string, args);
>   fprintf (stderr, "\n");
>   va_end (args);
>   exit (1);
> }
> 
>   ----------------------------------------------------------------------------------------------------
> /* Definitions to make GDB run on a mips box under 4.3bsd.
>    Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
>    Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
>    and by Alessandro Forin(af@cs.cmu.edu) at CMU
> 
> This file is part of GDB.
> 
> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.
> 
> This program is distributed in the hope that it will be useful,
> but WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU General Public License for more details.
> 
> You should have received a copy of the GNU General Public License
> along with this program; if not, write to the Free Software
> Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
> 
> #if !defined (HOST_BYTE_ORDER)
> #define HOST_BYTE_ORDER LITTLE_ENDIAN
> #endif
> 
> #ifdef ultrix
> /* Needed for DECstation core files.  */
> #include <machine/param.h>
> #define KERNEL_U_ADDR UADDR
> 
> /* Native Ultrix cc has broken long long support.  */
> #ifndef __GNUC__
> #undef CC_HAS_LONG_LONG
> #endif
> #endif
> 
> #if ! defined (__STDC__) && ! defined (offsetof)
> # define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
> #endif
> 
> /* Only used for core files on DECstations.
>    First four registers at u.u_ar0 are saved arguments, and
>    there is no r0 saved.   Float registers are saved
>    in u_pcb.pcb_fpregs, not relative to u.u_ar0.  */
> 
> #define REGISTER_U_ADDR(addr, blockend, regno)          \
>         { \
>           if (regno < FP0_REGNUM) \
>             addr = blockend + sizeof(int) * (4 + regno - 1); \
>           else \
>             addr = offsetof (struct user, u_pcb.pcb_fpregs[0]) + \
>                    sizeof (int) * (regno - FP0_REGNUM); \
>         }
> 
> /* Kernel is a bit tenacious about sharing text segments, disallowing bpts.  */
> #define ONE_PROCESS_WRITETEXT
> 
> /* HAVE_SGTTY also works, last we tried.
> 
>    But we have termios, at least as of Ultrix 4.2A, so use it.  */
> #define HAVE_TERMIOS


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]