This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: gdbserver extension
- To: Martin Rivers <rivers at lexmark dot com>
- Subject: Re: gdbserver extension
- From: Michael Snyder <msnyder at cygnus dot com>
- Date: Mon, 19 Feb 2001 18:44:09 -0800
- CC: gdb-patches at sourceware dot cygnus dot com
- Organization: Red Hat
- References: <200101260033.TAA16343@interlock2.lexmark.com>
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 *) ®isters[ 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 *) ®isters[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 *)®isters[ 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 *)®isters[ PC_REGNUM * 4];
> *pcreg -= sizeof( int );
> store_inferior_registers( PC_REGNUM );
> fetch_inferior_registers(0);
> #endif
> pcreg = (int *)®isters[ 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 *)®isters[ 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 (®isters[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