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


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

gdbserver extension


Not sure if anyone is interested but I've got a version of gdbserver
which supports debugging mips cpu's on linux, at least 43xx and 52xx
flavors of mips.  I've attached source.  You can include or ignore as
you see fit.  I'm sure the normal "gnu" programmers will look at this
and have a fit as normal coding styles aren't incorporated.  However,
the changes to low-linux.c incorporate appropriate information to
understand the mips architecture appropriately to allow remote debugging
(which is what I needed). I've used this with both gdb-4.18 and gdb-5.0
successfully.

Martin Rivers
Lexmark International, Inc.
/* Basic, host-specific, and target-specific definitions for GDB.
   Copyright (C) 1986, 89, 91, 92, 93, 94, 95, 96, 98, 1999
   Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#ifndef DEFS_H
#define DEFS_H

#include "config.h"		/* Generated by configure */
#include <stdio.h>
#include <errno.h>		/* System call error return status */
#include <limits.h>

#ifdef HAVE_STDDEF_H
#  include <stddef.h>
#else
#  include <sys/types.h>   /* for size_t */
#endif

/* Just in case they're not defined in stdio.h. */

#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif

/* First include ansidecl.h so we can use the various macro definitions
   here and in all subsequent file inclusions.  */

#include "ansidecl.h"

#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include "libiberty.h"

/* libiberty.h can't declare this one, but evidently we can.  */
extern char *strsignal PARAMS ((int));

#include "progress.h"

#ifdef USE_MMALLOC
#include "mmalloc.h"
#endif

/* For BFD64 and bfd_vma.  */
#include "bfd.h"

/* An address in the program being debugged.  Host byte order.  Rather
   than duplicate all the logic in BFD which figures out what type
   this is (long, long long, etc.) and whether it needs to be 64
   bits (the host/target interactions are subtle), we just use
   bfd_vma.  */

typedef unsigned int CORE_ADDR;

#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif

/* Gdb does *lots* of string compares.  Use macros to speed them up by
   avoiding function calls if the first characters are not the same. */

#define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b))
#define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0)
#define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0)

/* The character GNU C++ uses to build identifiers that must be unique from
   the program's identifiers (such as $this and $$vptr).  */
#define CPLUS_MARKER '$'	/* May be overridden to '.' for SysV */

/* Check if a character is one of the commonly used C++ marker characters.  */
extern int is_cplus_marker PARAMS ((int));

/* use tui interface if non-zero */
extern int tui_version;

#if defined(TUI)
/* all invocations of TUIDO should have two sets of parens */
#define TUIDO(x)	tuiDo x
#else
#define TUIDO(x)
#endif

/* enable xdb commands if set */
extern int xdb_commands;

/* enable dbx commands if set */
extern int dbx_commands;

extern int quit_flag;
extern int immediate_quit;
extern int sevenbit_strings;

extern void quit PARAMS ((void));

#ifdef QUIT
/* do twice to force compiler warning */
#define QUIT_FIXME "FIXME"
#define QUIT_FIXME "ignoring redefinition of QUIT"
#else
#define QUIT { \
  if (quit_flag) quit (); \
  if (interactive_hook) interactive_hook (); \
  PROGRESS (1); \
}
#endif

/* Command classes are top-level categories into which commands are broken
   down for "help" purposes.  
   Notes on classes: class_alias is for alias commands which are not
   abbreviations of the original command.  class-pseudo is for commands
   which are not really commands nor help topics ("stop").  */

enum command_class
{
  /* Special args to help_list */
  all_classes = -2, all_commands = -1,
  /* Classes of commands */
  no_class = -1, class_run = 0, class_vars, class_stack,
  class_files, class_support, class_info, class_breakpoint, class_trace,
  class_alias, class_obscure, class_user, class_maintenance,
  class_pseudo, class_tui, class_xdb
};

/* Languages represented in the symbol table and elsewhere.
   This should probably be in language.h, but since enum's can't
   be forward declared to satisfy opaque references before their
   actual definition, needs to be here. */

enum language 
{
   language_unknown, 		/* Language not known */
   language_auto,		/* Placeholder for automatic setting */
   language_c, 			/* C */
   language_cplus, 		/* C++ */
   language_java,		/* Java */
   language_chill,		/* Chill */
   language_fortran,		/* Fortran */
   language_m2,			/* Modula-2 */
   language_asm,		/* Assembly language */
   language_scm			/* Scheme / Guile */
};

enum precision_type
{
  single_precision,
  double_precision,
  unspecified_precision
};
   
/* the cleanup list records things that have to be undone
   if an error happens (descriptors to be closed, memory to be freed, etc.)
   Each link in the chain records a function to call and an
   argument to give it.

   Use make_cleanup to add an element to the cleanup chain.
   Use do_cleanups to do all cleanup actions back to a given
   point in the chain.  Use discard_cleanups to remove cleanups
   from the chain back to a given point, not doing them.  */

struct cleanup
{
  struct cleanup *next;
  void (*function) PARAMS ((PTR));
  PTR arg;
};


/* The ability to declare that a function never returns is useful, but
   not really required to compile GDB successfully, so the NORETURN and
   ATTR_NORETURN macros normally expand into nothing.  */

/* If compiling with older versions of GCC, a function may be declared
   "volatile" to indicate that it does not return.  */

#ifndef NORETURN
# if defined(__GNUC__) \
     && (__GNUC__ == 1 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7))
#  define NORETURN volatile
# else
#  define NORETURN /* nothing */
# endif
#endif

/* GCC 2.5 and later versions define a function attribute "noreturn",
   which is the preferred way to declare that a function never returns.
   However GCC 2.7 appears to be the first version in which this fully
   works everywhere we use it. */

#ifndef ATTR_NORETURN
# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 7
#  define ATTR_NORETURN __attribute__ ((noreturn))
# else
#  define ATTR_NORETURN /* nothing */
# endif
#endif

#ifndef ATTR_FORMAT
# if defined(__GNUC__) && __GNUC__ >= 2 && __GNUC_MINOR__ >= 4 && defined (__ANSI_PROTOTYPES)
#  define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
# else
#  define ATTR_FORMAT(type, x, y) /* nothing */
# endif
#endif

/* Needed for various prototypes */

#ifdef __STDC__
struct symtab;
struct breakpoint;
#endif

/* From blockframe.c */

extern int inside_entry_func PARAMS ((CORE_ADDR));

extern int inside_entry_file PARAMS ((CORE_ADDR addr));

extern int inside_main_func PARAMS ((CORE_ADDR pc));

/* From ch-lang.c, for the moment. (FIXME) */

extern char *chill_demangle PARAMS ((const char *));

/* From utils.c */

extern void notice_quit PARAMS ((void));

extern int strcmp_iw PARAMS ((const char *, const char *));

extern char *safe_strerror PARAMS ((int));

extern char *safe_strsignal PARAMS ((int));

extern void init_malloc PARAMS ((void *));

extern void request_quit PARAMS ((int));

extern void do_cleanups PARAMS ((struct cleanup *));
extern void do_final_cleanups PARAMS ((struct cleanup *));
extern void do_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
extern void do_run_cleanups PARAMS ((struct cleanup *));

extern void discard_cleanups PARAMS ((struct cleanup *));
extern void discard_final_cleanups PARAMS ((struct cleanup *));
extern void discard_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));

typedef void (*make_cleanup_func) PARAMS ((void *));

extern struct cleanup *make_cleanup PARAMS ((make_cleanup_func, void *));

extern struct cleanup *make_final_cleanup PARAMS ((make_cleanup_func, void *));

extern struct cleanup *make_my_cleanup PARAMS ((struct cleanup **, 
                                                make_cleanup_func, void *));

extern struct cleanup *make_run_cleanup PARAMS ((make_cleanup_func, void *));

extern struct cleanup *save_cleanups PARAMS ((void));
extern struct cleanup *save_final_cleanups PARAMS ((void));
extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup **));

extern void restore_cleanups PARAMS ((struct cleanup *));
extern void restore_final_cleanups PARAMS ((struct cleanup *));
extern void restore_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));

extern void free_current_contents PARAMS ((char **));

extern void null_cleanup PARAMS ((PTR));

extern int myread PARAMS ((int, char *, int));

extern int query PARAMS((char *, ...))
     ATTR_FORMAT(printf, 1, 2);

#if !defined (USE_MMALLOC)
extern PTR mmalloc PARAMS ((PTR, size_t));
extern PTR mrealloc PARAMS ((PTR, PTR, size_t));
extern void mfree PARAMS ((PTR, PTR));
#endif

/* From demangle.c */

extern void set_demangling_style PARAMS ((char *));

/* From tm.h */

struct type;
typedef int (use_struct_convention_fn) PARAMS ((int gcc_p, struct type *value_type));
extern use_struct_convention_fn generic_use_struct_convention;

typedef unsigned char *(breakpoint_from_pc_fn) PARAMS ((CORE_ADDR *pcptr, int *lenptr));



/* Annotation stuff.  */

extern int annotation_level; /* in stack.c */

extern void begin_line PARAMS ((void));

extern void wrap_here PARAMS ((char *));

extern void reinitialize_more_filter PARAMS ((void));

/* new */
enum streamtype
{
  afile,
  astring
};

/* new */
typedef struct tui_stream
{
  enum streamtype ts_streamtype;
  FILE *ts_filestream;
  char *ts_strbuf;
  int ts_buflen;
} GDB_FILE;

extern GDB_FILE *gdb_stdout;
extern GDB_FILE *gdb_stderr;

#if 0
typedef FILE GDB_FILE;
#define gdb_stdout stdout
#define gdb_stderr stderr
#endif

#if defined(TUI)
#include "tui.h"
#include "tuiCommand.h"
#include "tuiData.h"
#include "tuiIO.h"
#include "tuiLayout.h"
#include "tuiWin.h"
#endif

extern void gdb_fclose PARAMS ((GDB_FILE **));

extern void gdb_flush PARAMS ((GDB_FILE *));

extern GDB_FILE *gdb_fopen PARAMS ((char * name, char * mode));

extern void fputs_filtered PARAMS ((const char *, GDB_FILE *));

extern void fputs_unfiltered PARAMS ((const char *, GDB_FILE *));

extern int fputc_filtered PARAMS ((int c, GDB_FILE *));

extern int fputc_unfiltered PARAMS ((int c, GDB_FILE *));

extern int putchar_unfiltered PARAMS ((int c));

extern void puts_filtered PARAMS ((const char *));

extern void puts_unfiltered PARAMS ((const char *));

extern void puts_debug PARAMS ((char *prefix, char *string, char *suffix));

extern void vprintf_filtered PARAMS ((const char *, va_list))
     ATTR_FORMAT(printf, 1, 0);

extern void vfprintf_filtered PARAMS ((GDB_FILE *, const char *, va_list))
     ATTR_FORMAT(printf, 2, 0);

extern void fprintf_filtered PARAMS ((GDB_FILE *, const char *, ...))
     ATTR_FORMAT(printf, 2, 3);

extern void fprintfi_filtered PARAMS ((int, GDB_FILE *, const char *, ...))
     ATTR_FORMAT(printf, 3, 4);

extern void printf_filtered PARAMS ((const char *, ...))
     ATTR_FORMAT(printf, 1, 2);

extern void printfi_filtered PARAMS ((int, const char *, ...))
     ATTR_FORMAT(printf, 2, 3);

extern void vprintf_unfiltered PARAMS ((const char *, va_list))
     ATTR_FORMAT(printf, 1, 0);

extern void vfprintf_unfiltered PARAMS ((GDB_FILE *, const char *, va_list))
     ATTR_FORMAT(printf, 2, 0);

extern void fprintf_unfiltered PARAMS ((GDB_FILE *, const char *, ...))
     ATTR_FORMAT(printf, 2, 3);

extern void printf_unfiltered PARAMS ((const char *, ...))
     ATTR_FORMAT(printf, 1, 2);

extern int gdb_file_isatty PARAMS ((GDB_FILE *));

extern GDB_FILE *gdb_file_init_astring PARAMS ((int));

extern void gdb_file_deallocate PARAMS ((GDB_FILE **));

extern char *gdb_file_get_strbuf PARAMS ((GDB_FILE *));

extern void gdb_file_adjust_strbuf PARAMS ((int, GDB_FILE *));

extern void print_spaces PARAMS ((int, GDB_FILE *));

extern void print_spaces_filtered PARAMS ((int, GDB_FILE *));

extern char *n_spaces PARAMS ((int));

extern void gdb_printchar PARAMS ((int, GDB_FILE *, int));

extern void gdb_print_address PARAMS ((void *, GDB_FILE *));

typedef bfd_vma t_addr;
typedef bfd_vma t_reg;
extern char* paddr PARAMS ((t_addr addr));

extern char* preg PARAMS ((t_reg reg));

extern char* paddr_nz PARAMS ((t_addr addr));

extern char* preg_nz PARAMS ((t_reg reg));

extern void fprintf_symbol_filtered PARAMS ((GDB_FILE *, char *,
					     enum language, int));

extern NORETURN void perror_with_name PARAMS ((char *)) ATTR_NORETURN;

extern void print_sys_errmsg PARAMS ((char *, int));

/* From regex.c or libc.  BSD 4.4 declares this with the argument type as
   "const char *" in unistd.h, so we can't declare the argument
   as "char *".  */

extern char *re_comp PARAMS ((const char *));

/* From symfile.c */

extern void symbol_file_command PARAMS ((char *, int));

/* From top.c */

extern char *skip_quoted PARAMS ((char *));

extern char *gdb_readline PARAMS ((char *));

extern char *command_line_input PARAMS ((char *, int, char *));

extern void print_prompt PARAMS ((void));

extern int input_from_terminal_p PARAMS ((void));

extern int info_verbose;

/* From printcmd.c */

extern void set_next_address PARAMS ((CORE_ADDR));

extern void print_address_symbolic PARAMS ((CORE_ADDR, GDB_FILE *, int,
					    char *));

extern void print_address_numeric PARAMS ((CORE_ADDR, int, GDB_FILE *));

extern void print_address PARAMS ((CORE_ADDR, GDB_FILE *));

/* From source.c */

extern int openp PARAMS ((char *, int, char *, int, int, char **));

extern int source_full_path_of PARAMS ((char *, char **));

extern void mod_path PARAMS ((char *, char **));

extern void directory_command PARAMS ((char *, int));

extern void init_source_path PARAMS ((void));

extern char *symtab_to_filename PARAMS ((struct symtab *));

/* From findvar.c */

extern int read_relative_register_raw_bytes PARAMS ((int, char *));

/* From readline (but not in any readline .h files).  */

extern char *tilde_expand PARAMS ((char *));

/* Control types for commands */

enum misc_command_type
{
  ok_command,
  end_command,
  else_command,
  nop_command
};

enum command_control_type
{
  simple_control,
  break_control,
  continue_control,
  while_control,
  if_control,
  invalid_control
};

/* Structure for saved commands lines
   (for breakpoints, defined commands, etc).  */

struct command_line
{
  struct command_line *next;
  char *line;
  enum command_control_type control_type;
  int body_count;
  struct command_line **body_list;
};

extern struct command_line *read_command_lines PARAMS ((char *, int));

extern void free_command_lines PARAMS ((struct command_line **));

/* String containing the current directory (what getwd would return).  */

extern char *current_directory;

/* Default radixes for input and output.  Only some values supported.  */
extern unsigned input_radix;
extern unsigned output_radix;

/* Possibilities for prettyprint parameters to routines which print
   things.  Like enum language, this should be in value.h, but needs
   to be here for the same reason.  FIXME:  If we can eliminate this
   as an arg to LA_VAL_PRINT, then we can probably move it back to
   value.h. */

enum val_prettyprint
{
  Val_no_prettyprint = 0,
  Val_prettyprint,
  /* Use the default setting which the user has specified.  */
  Val_pretty_default
};


/* Host machine definition.  This will be a symlink to one of the
   xm-*.h files, built by the `configure' script.  */

#include "xm.h"

/* Native machine support.  This will be a symlink to one of the
   nm-*.h files, built by the `configure' script.  */

#include "nm.h"

/* Target machine definition.  This will be a symlink to one of the
   tm-*.h files, built by the `configure' script.  */

#include "tm.h"

/* If the xm.h file did not define the mode string used to open the
   files, assume that binary files are opened the same way as text
   files */
#ifndef FOPEN_RB
#include "fopen-same.h"
#endif

/* Microsoft C can't deal with const pointers */

#ifdef _MSC_VER
#define CONST_PTR
#else
#define CONST_PTR const
#endif

/*
 * Allow things in gdb to be declared "volatile".  If compiling ANSI, it
 * just works.  If compiling with gcc but non-ansi, redefine to __volatile__.
 * If non-ansi, non-gcc, then eliminate "volatile" entirely, making those
 * objects be read-write rather than read-only.
 */

#ifndef volatile
#ifndef __STDC__
# ifdef __GNUC__
#  define volatile __volatile__
# else
#  define volatile /*nothing*/
# endif /* GNUC */
#endif /* STDC */
#endif /* volatile */

/* Defaults for system-wide constants (if not defined by xm.h, we fake it).
   FIXME: Assumes 2's complement arithmetic */

#if !defined (UINT_MAX)
#define	UINT_MAX ((unsigned int)(~0))		/* 0xFFFFFFFF for 32-bits */
#endif

#if !defined (INT_MAX)
#define	INT_MAX ((int)(UINT_MAX >> 1))		/* 0x7FFFFFFF for 32-bits */
#endif

#if !defined (INT_MIN)
#define INT_MIN ((int)((int) ~0 ^ INT_MAX))	/* 0x80000000 for 32-bits */
#endif

#if !defined (ULONG_MAX)
#define	ULONG_MAX ((unsigned long)(~0L))	/* 0xFFFFFFFF for 32-bits */
#endif

#if !defined (LONG_MAX)
#define	LONG_MAX ((long)(ULONG_MAX >> 1))	/* 0x7FFFFFFF for 32-bits */
#endif

#ifndef LONGEST

#ifdef BFD64

/* This is to make sure that LONGEST is at least as big as CORE_ADDR.  */

#define LONGEST BFD_HOST_64_BIT
#define ULONGEST BFD_HOST_U_64_BIT

#else /* No BFD64 */

#  ifdef CC_HAS_LONG_LONG
#    define LONGEST long long
#    define ULONGEST unsigned long long
#  else
/* BFD_HOST_64_BIT is defined for some hosts that don't have long long
   (e.g. i386-windows) so try it.  */
#    ifdef BFD_HOST_64_BIT
#      define LONGEST BFD_HOST_64_BIT
#      define ULONGEST BFD_HOST_U_64_BIT
#    else
#      define LONGEST long
#      define ULONGEST unsigned long
#    endif
#  endif

#endif /* No BFD64 */

#endif /* ! LONGEST */

/* Convert a LONGEST to an int.  This is used in contexts (e.g. number of
   arguments to a function, number in a value history, register number, etc.)
   where the value must not be larger than can fit in an int.  */

extern int longest_to_int PARAMS ((LONGEST));

/* Assorted functions we can declare, now that const and volatile are 
   defined.  */

extern char *savestring PARAMS ((const char *, int));

extern char *msavestring PARAMS ((void *, const char *, int));

extern char *strsave PARAMS ((const char *));

extern char *mstrsave PARAMS ((void *, const char *));

#ifdef _MSC_VER /* FIXME; was long, but this causes compile errors in msvc if already defined */
extern PTR xmmalloc PARAMS ((PTR, size_t));

extern PTR xmrealloc PARAMS ((PTR, PTR, size_t));
#else
extern PTR xmmalloc PARAMS ((PTR, long));

extern PTR xmrealloc PARAMS ((PTR, PTR, long));
#endif

extern int parse_escape PARAMS ((char **));

/* compat - handle old targets that just define REGISTER_NAMES */
#ifndef REGISTER_NAME
extern char *gdb_register_names[];
#define REGISTER_NAME(i) gdb_register_names[i]
#endif

/* Message to be printed before the error message, when an error occurs.  */

extern char *error_pre_print;

/* Message to be printed before the error message, when an error occurs.  */

extern char *quit_pre_print;

/* Message to be printed before the warning message, when a warning occurs.  */

extern char *warning_pre_print;

extern NORETURN void error PARAMS((const char *, ...)) ATTR_NORETURN;

extern void error_begin PARAMS ((void));

extern NORETURN void fatal PARAMS((char *, ...)) ATTR_NORETURN;

extern NORETURN void nomem PARAMS ((long)) ATTR_NORETURN;

/* Reasons for calling return_to_top_level.  */
enum return_reason {
  /* User interrupt.  */
  RETURN_QUIT,

  /* Any other error.  */
  RETURN_ERROR
};

#define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT)
#define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR)
#define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
typedef int return_mask;

extern NORETURN void
return_to_top_level PARAMS ((enum return_reason)) ATTR_NORETURN;

typedef int (catch_errors_ftype) PARAMS ((PTR));
extern int catch_errors PARAMS ((catch_errors_ftype *, PTR, char *, return_mask));

extern void warning_begin PARAMS ((void));

extern void warning PARAMS ((const char *, ...))
     ATTR_FORMAT(printf, 1, 2);

/* Global functions from other, non-gdb GNU thingies.
   Libiberty thingies are no longer declared here.  We include libiberty.h
   above, instead.  */

#ifndef GETENV_PROVIDED
extern char *getenv PARAMS ((const char *));
#endif

/* From other system libraries */

#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif

#ifdef HAVE_STDLIB_H
#if defined(_MSC_VER) && !defined(__cplusplus)
/* msvc defines these in stdlib.h for c code */
#undef min
#undef max
#endif
#include <stdlib.h>
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif


/* We take the address of fclose later, but some stdio's forget
   to declare this.  We can't always declare it since there's
   no way to declare the parameters without upsetting some compiler
   somewhere. */

#ifndef FCLOSE_PROVIDED
extern int fclose PARAMS ((FILE *));
#endif

#ifndef atof
extern double atof PARAMS ((const char *));	/* X3.159-1989  4.10.1.1 */
#endif

#ifndef MALLOC_INCOMPATIBLE

#ifdef NEED_DECLARATION_MALLOC
extern PTR malloc ();
#endif

#ifdef NEED_DECLARATION_REALLOC
extern PTR realloc ();
#endif

#ifdef NEED_DECLARATION_FREE
extern void free ();
#endif

#endif /* MALLOC_INCOMPATIBLE */

/* Various possibilities for alloca.  */
#ifndef alloca
# ifdef __GNUC__
#  define alloca __builtin_alloca
# else /* Not GNU C */
#  ifdef HAVE_ALLOCA_H
#   include <alloca.h>
#  else
#   ifdef _AIX
 #pragma alloca
#   else

/* We need to be careful not to declare this in a way which conflicts with
   bison.  Bison never declares it as char *, but under various circumstances
   (like __hpux) we need to use void *.  */
#    if defined (__STDC__) || defined (__hpux)
   extern void *alloca ();
#    else /* Don't use void *.  */
   extern char *alloca ();
#    endif /* Don't use void *.  */
#   endif /* Not _AIX */
#  endif /* Not HAVE_ALLOCA_H */
# endif /* Not GNU C */
#endif /* alloca not defined */

/* HOST_BYTE_ORDER must be defined to one of these.  */

#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif

#if !defined (BIG_ENDIAN)
#define BIG_ENDIAN 4321
#endif

#if !defined (LITTLE_ENDIAN)
#define LITTLE_ENDIAN 1234
#endif

/* Dynamic target-system-dependent parameters for GDB. */
#include "gdbarch.h"

/* Static target-system-dependent parameters for GDB. */

/* Number of bits in a char or unsigned char for the target machine.
   Just like CHAR_BIT in <limits.h> but describes the target machine.  */
#if !defined (TARGET_CHAR_BIT)
#define TARGET_CHAR_BIT 8
#endif

/* Number of bits in a short or unsigned short for the target machine. */
#if !defined (TARGET_SHORT_BIT)
#define TARGET_SHORT_BIT (2 * TARGET_CHAR_BIT)
#endif

/* Number of bits in an int or unsigned int for the target machine. */
#if !defined (TARGET_INT_BIT)
#define TARGET_INT_BIT (4 * TARGET_CHAR_BIT)
#endif

/* Number of bits in a long or unsigned long for the target machine. */
#if !defined (TARGET_LONG_BIT)
#define TARGET_LONG_BIT (4 * TARGET_CHAR_BIT)
#endif

/* Number of bits in a long long or unsigned long long for the target machine. */
#if !defined (TARGET_LONG_LONG_BIT)
#define TARGET_LONG_LONG_BIT (2 * TARGET_LONG_BIT)
#endif

/* Number of bits in a float for the target machine. */
#if !defined (TARGET_FLOAT_BIT)
#define TARGET_FLOAT_BIT (4 * TARGET_CHAR_BIT)
#endif

/* Number of bits in a double for the target machine. */
#if !defined (TARGET_DOUBLE_BIT)
#define TARGET_DOUBLE_BIT (8 * TARGET_CHAR_BIT)
#endif

/* Number of bits in a long double for the target machine.  */
#if !defined (TARGET_LONG_DOUBLE_BIT)
#define TARGET_LONG_DOUBLE_BIT (2 * TARGET_DOUBLE_BIT)
#endif

/* Number of bits in a pointer for the target machine */
#if !defined (TARGET_PTR_BIT)
#define TARGET_PTR_BIT TARGET_INT_BIT
#endif

/* If we picked up a copy of CHAR_BIT from a configuration file
   (which may get it by including <limits.h>) then use it to set
   the number of bits in a host char.  If not, use the same size
   as the target. */

#if defined (CHAR_BIT)
#define HOST_CHAR_BIT CHAR_BIT
#else
#define HOST_CHAR_BIT TARGET_CHAR_BIT
#endif

/* The bit byte-order has to do just with numbering of bits in
   debugging symbols and such.  Conceptually, it's quite separate
   from byte/word byte order.  */

#if !defined (BITS_BIG_ENDIAN)
#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BIG_ENDIAN)
#endif

/* In findvar.c.  */

extern LONGEST extract_signed_integer PARAMS ((void *, int));

extern ULONGEST extract_unsigned_integer PARAMS ((void *, int));

extern int extract_long_unsigned_integer PARAMS ((void *, int, LONGEST *));

extern CORE_ADDR extract_address PARAMS ((void *, int));

extern void store_signed_integer PARAMS ((PTR, int, LONGEST));

extern void store_unsigned_integer PARAMS ((PTR, int, ULONGEST));

extern void store_address PARAMS ((PTR, int, LONGEST));

/* Setup definitions for host and target floating point formats.  We need to
   consider the format for `float', `double', and `long double' for both target
   and host.  We need to do this so that we know what kind of conversions need
   to be done when converting target numbers to and from the hosts DOUBLEST
   data type.  */

/* This is used to indicate that we don't know the format of the floating point
   number.  Typically, this is useful for native ports, where the actual format
   is irrelevant, since no conversions will be taking place.  */

extern const struct floatformat floatformat_unknown;

#if HOST_BYTE_ORDER == BIG_ENDIAN
#  ifndef HOST_FLOAT_FORMAT
#    define HOST_FLOAT_FORMAT &floatformat_ieee_single_big
#  endif
#  ifndef HOST_DOUBLE_FORMAT
#    define HOST_DOUBLE_FORMAT &floatformat_ieee_double_big
#  endif
#else				/* LITTLE_ENDIAN */
#  ifndef HOST_FLOAT_FORMAT
#    define HOST_FLOAT_FORMAT &floatformat_ieee_single_little
#  endif
#  ifndef HOST_DOUBLE_FORMAT
#    define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little
#  endif
#endif

#ifndef HOST_LONG_DOUBLE_FORMAT
#define HOST_LONG_DOUBLE_FORMAT &floatformat_unknown
#endif

#ifndef TARGET_FLOAT_FORMAT
#define TARGET_FLOAT_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \
			     ? &floatformat_ieee_single_big \
			     : &floatformat_ieee_single_little)
#endif
#ifndef TARGET_DOUBLE_FORMAT
#define TARGET_DOUBLE_FORMAT (TARGET_BYTE_ORDER == BIG_ENDIAN \
			      ? &floatformat_ieee_double_big \
			      : &floatformat_ieee_double_little)
#endif

#ifndef TARGET_LONG_DOUBLE_FORMAT
#  define TARGET_LONG_DOUBLE_FORMAT &floatformat_unknown
#endif

/* Use `long double' if the host compiler supports it.  (Note that this is not
   necessarily any longer than `double'.  On SunOS/gcc, it's the same as
   double.)  This is necessary because GDB internally converts all floating
   point values to the widest type supported by the host.

   There are problems however, when the target `long double' is longer than the
   host's `long double'.  In general, we'll probably reduce the precision of
   any such values and print a warning.  */

#ifdef HAVE_LONG_DOUBLE
typedef long double DOUBLEST;
#else
typedef double DOUBLEST;
#endif

extern void floatformat_to_doublest PARAMS ((const struct floatformat *,
					     char *, DOUBLEST *));
extern void floatformat_from_doublest PARAMS ((const struct floatformat *,
					       DOUBLEST *, char *));
extern DOUBLEST extract_floating PARAMS ((void *, int));

extern void store_floating PARAMS ((void *, int, DOUBLEST));

/* On some machines there are bits in addresses which are not really
   part of the address, but are used by the kernel, the hardware, etc.
   for special purposes.  ADDR_BITS_REMOVE takes out any such bits
   so we get a "real" address such as one would find in a symbol
   table.  This is used only for addresses of instructions, and even then
   I'm not sure it's used in all contexts.  It exists to deal with there
   being a few stray bits in the PC which would mislead us, not as some sort
   of generic thing to handle alignment or segmentation (it's possible it
   should be in TARGET_READ_PC instead).  */
#if !defined (ADDR_BITS_REMOVE)
#define ADDR_BITS_REMOVE(addr) (addr)
#endif /* No ADDR_BITS_REMOVE.  */

/* From valops.c */

extern CORE_ADDR push_bytes PARAMS ((CORE_ADDR, char *, int));

extern CORE_ADDR push_word PARAMS ((CORE_ADDR, ULONGEST));

/* Some parts of gdb might be considered optional, in the sense that they
   are not essential for being able to build a working, usable debugger
   for a specific environment.  For example, the maintenance commands
   are there for the benefit of gdb maintainers.  As another example,
   some environments really don't need gdb's that are able to read N
   different object file formats.  In order to make it possible (but
   not necessarily recommended) to build "stripped down" versions of
   gdb, the following defines control selective compilation of those
   parts of gdb which can be safely left out when necessary.  Note that
   the default is to include everything. */

#ifndef MAINTENANCE_CMDS
#define MAINTENANCE_CMDS 1
#endif

#ifdef MAINTENANCE_CMDS
extern int watchdog;
#endif

/* Hooks for alternate command interfaces.  */

#ifdef __STDC__
struct target_waitstatus;
struct cmd_list_element;
#endif

extern void (*init_ui_hook) PARAMS ((char *argv0));
extern void (*command_loop_hook) PARAMS ((void));
extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer,
					      GDB_FILE *stream));
extern void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s,
						      int line, int stopline,
						      int noerror));
extern struct frame_info *parse_frame_specification PARAMS ((char *frame_exp));
extern int  (*query_hook) PARAMS ((const char *, va_list));
extern void (*warning_hook) PARAMS ((const char *, va_list));
extern void (*flush_hook) PARAMS ((GDB_FILE *stream));
extern void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b));
extern void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
extern void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt));
extern void (*target_output_hook) PARAMS ((char *));
extern void (*interactive_hook) PARAMS ((void));
extern void (*registers_changed_hook) PARAMS ((void));
extern void (*readline_begin_hook) PARAMS ((char *, ...));
extern char * (*readline_hook) PARAMS ((char *));
extern void (*readline_end_hook) PARAMS ((void));
extern void (*register_changed_hook) PARAMS ((int regno));
extern void (*memory_changed_hook) PARAMS ((CORE_ADDR addr, int len));
extern void (*context_hook) PARAMS ((int));
extern int (*target_wait_hook) PARAMS ((int pid,
					struct target_waitstatus *status));

extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c,
					  char *cmd, int from_tty));

extern NORETURN void (*error_hook) PARAMS ((void)) ATTR_NORETURN;

extern void (*error_begin_hook) PARAMS ((void));


/* Inhibit window interface if non-zero. */

extern int use_windows;

/* Symbolic definitions of filename-related things.  */
/* FIXME, this doesn't work very well if host and executable
   filesystems conventions are different.  */

#ifndef DIRNAME_SEPARATOR
#define DIRNAME_SEPARATOR ':'
#endif

#ifndef SLASH_P
#if defined(__GO32__)||defined(_WIN32)
#define SLASH_P(X) ((X)=='\\')
#else
#define SLASH_P(X) ((X)=='/')
#endif
#endif

#ifndef SLASH_CHAR
#if defined(__GO32__)||defined(_WIN32)
#define SLASH_CHAR '\\'
#else
#define SLASH_CHAR '/'
#endif
#endif

#ifndef SLASH_STRING
#if defined(__GO32__)||defined(_WIN32)
#define SLASH_STRING "\\"
#else
#define SLASH_STRING "/"
#endif
#endif

#ifndef ROOTED_P
#define ROOTED_P(X) (SLASH_P((X)[0]))
#endif

/* On some systems, PIDGET is defined to extract the inferior pid from
   an internal pid that has the thread id and pid in seperate bit
   fields.  If not defined, then just use the entire internal pid as
   the actual pid. */

#ifndef PIDGET
#define PIDGET(pid) (pid)
#endif

/* If under Cygwin, provide backwards compatibility with older
   Cygwin compilers that don't define the current cpp define. */
#ifdef __CYGWIN32__
#ifndef __CYGWIN__
#define __CYGWIN__
#endif
#endif

#endif /* #ifndef DEFS_H */
/* $Id$

Low level interface to ptrace, for the remote server for GDB.
   Copyright (C) 1995, 1996 Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 

23-jan-2000	rivers  In unsinglestep, don't remove breakpoints if we didn't
                        hit one (because of signal).
28-dec-2000	rivers	Added ability to "trace" calls to ptrace (ptracex).
			Added more debug output controlled via 'verbose'.
			Don't allow storing to any but gpr/fpr/epc registers.
 			When single stepping, if branch target == instruction after
			delay slot, then only one breakpoint.
22-march-2000	rivers	Added support to attach to a process

 */

#include "defs.h"
#include <sys/wait.h>
#include "frame.h"
#include "inferior.h"

#include <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>

/*
 * These are the various branch types
 */

#define NOBRANCH 0
#define OFFSET_16 1
#define OFFSET_24 2
#define REG_TARGET 3

extern int verbose;

struct singlestep
{
    unsigned int opcode;
    unsigned int pc;
};

struct singlestep tracebp;	/* Next instruction (or after delay slot) trace info */
struct singlestep tracebpbt;	/* Branch target trace information */

/***************Begin MY defs*********************/
int quit_flag = 0;
char registers[REGISTER_BYTES];

/* Index within `registers' of the first byte of the space for
   register N.  */


char buf2[MAX_REGISTER_RAW_SIZE];
/***************End MY defs*********************/

/*#include <sys/ptrace.h>*/

#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
#include <sys/reg.h>
#endif

extern char **environ;
extern int errno;
extern int inferior_pid;
void quit (), perror_with_name ();
int query ();
int is_branch( int );
int branch_target_address( int, int );
void single_step( void );
int unsingle_step( void );

/* Start an inferior process and returns its pid.
   ALLARGS is a vector of program-name and args.
   ENV is the environment vector to pass.  */

int
create_inferior (program, allargs)
  char *program;
  char **allargs;
{
    int pid;

    pid = fork ();
    if (pid < 0)
	perror_with_name ("fork");

    if (pid == 0)
    {
	ptracex (PTRACE_TRACEME, 0, 0, 0);

	execv (program, allargs);

	fprintf (stderr, "Cannot exec %s: %s.\n", program,
		 errno < sys_nerr ? sys_errlist[errno] : "unknown error");
	fflush (stderr);
	_exit (0177);
    }

    return pid;
}

void
attach_inferior()
{
    if( ptracex( PTRACE_ATTACH, inferior_pid, 0, 0 ) < 0 )
	perror_with_name( "ptrace" );
}

/* Kill the inferior process.  Make us have no inferior.  */

void
kill_inferior ()
{
    if (inferior_pid == 0)
	return;
    ptracex (PTRACE_KILL, inferior_pid, 0, 0);
    wait (0);
  /*************inferior_died ();****VK**************/
}

/* Return nonzero if the given thread is still alive.  */
int
mythread_alive (pid)
  int pid;
{
    return 1;
}

/* Wait for process, returns status */

unsigned char
mywait (status)
  char *status;
{
    int pid;
    int w;

    if( verbose )
	printf( "about to mywait\n" );
    
    pid = wait (&w);
    if (pid != inferior_pid)
	perror_with_name ("wait");

    if( verbose )
	printf( "wait status %08x\n", w );
    
    if (WIFEXITED (w))
    {
	fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
	*status = 'W';
	return ((unsigned char) WEXITSTATUS (w));
    }
    else if (!WIFSTOPPED (w))
    {
	fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
	*status = 'X';
	return ((unsigned char) WTERMSIG (w));
    }

    fetch_inferior_registers (0);

    *status = 'T';
    return ((unsigned char) WSTOPSIG (w));
}

/* Resume execution of the inferior process.
   If STEP is nonzero, single-step it.
   If SIGNAL is nonzero, give it that signal.  */

void
myresume (step, signal)
     int step;
     int signal;
{
    errno = 0;
    ptracex (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
    if (errno)
	perror_with_name ("ptrace");
}


#if !defined (offsetof)
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif

/* U_REGS_OFFSET is the offset of the registers within the u area.  */
#if !defined (U_REGS_OFFSET)
#define U_REGS_OFFSET \
  ptracex (PT_READ_U, inferior_pid, \
          (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
    - KERNEL_U_ADDR
#endif

CORE_ADDR
register_addr (regno, blockend)
     int regno;
     CORE_ADDR blockend;
{
    CORE_ADDR addr;

    if (regno < 0 || regno >= ARCH_NUM_REGS)
	error ("Invalid register number %d.", regno);

    if( regno < 32 ) 
	return( regno );		/* gpr's */
    else if( ( regno >= 38 ) && ( regno < 70 ) )
	return( regno - 38 + 32 ); /* fpr's */
    else if( regno == 32 )	/* sr unsupported */
	return( -1 );
    else if( regno == 33 )	/* lo */
	return( 67 );
    else if( regno == 34 )	/* hi */
	return( 68 );
    else if( regno == 35 )	/* bad */
	return( 66 );
    else if( regno == 36 )	/* cause */
	return( 65 );
    else if( regno == 37 )	/* (e)pc */
	return( 64 );
    else if( regno == 70 )	/* fsr */
	return( 69 );
    else
	return( -1 );
    
    return addr;
}

/* Fetch one register.  */

static void
fetch_register (regno)
     int regno;
{
    register unsigned int regaddr;
    register int i;

    /* Offset of registers within the u area.  */
    unsigned int offset;

    offset = 0;

    regaddr = register_addr (regno, offset);
    if( regaddr == -1 )
	return;
    
    for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
    {
	errno = 0;
	*(int *) &registers[ regno * 4 + i] = ptracex (PTRACE_PEEKUSR, inferior_pid,
						       (PTRACE_ARG3_TYPE) regaddr, 0);
	regaddr++;
	if (errno != 0)
	{
	    /* Warning, not error, in case we are attached; sometimes the
	       kernel doesn't let us at the registers.  */
	    char *err = strerror (errno);
	    char *msg = alloca (strlen (err) + 128);
	    sprintf (msg, "reading register %d: %s", regno, err);
	    error (msg);
	    goto error_exit;
	}
    }
 error_exit:;
}

/* Fetch all registers, or just one, from the child process.  */

void
fetch_inferior_registers (regno)
     int regno;
{
    if (regno == -1 || regno == 0)
	for (regno = 0; regno < NUM_REGS; regno++)
	    fetch_register (regno);
    else
	fetch_register (regno);
}

/* Store our register values back into the inferior.
   If REGNO is -1, do this for all registers.
   Otherwise, REGNO specifies which register (so we can save time).  */

void
store_inferior_registers (regno)
     int regno;
{
    register unsigned int regaddr;
    register int i;
    unsigned int offset = 0;

    if( verbose )
	printf( "store_inferior_register; %d\n", regno );
    
    if (regno >= 0)
    {
	errno = 0;

	regaddr = register_addr (regno, offset);

	if( regaddr > 64 )
	{
	    /*
	     * Only allow writing to gpr's, fpr's and pc, no other register
	     */

	    return;
	}
	
	if( regaddr == -1 )
	    return;

	for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
	{
	    errno = 0;
	    ptracex (PTRACE_POKEUSR, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
		     *(int *) &registers[REGISTER_BYTE (regno) + i]);
#if 0
	    if (errno != 0)
	    {
		/* Warning, not error, in case we are attached; sometimes the
		   kernel doesn't let us at the registers.  */
		char *err = strerror (errno);
		char *msg = alloca (strlen (err) + 128);
		sprintf (msg, "writing register %d: %s",
			 regno, err);
		error (msg);
		return;
	    }
#endif
	    regaddr++;
	}
    }
    else
	for (regno = 0; regno < NUM_REGS; regno++)
	    store_inferior_registers (regno);
}

/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
   in the NEW_SUN_PTRACE case.
   It ought to be straightforward.  But it appears that writing did
   not write the data that I specified.  I cannot understand where
   it got the data that it actually did write.  */

/* Copy LEN bytes from inferior's memory starting at MEMADDR
   to debugger memory starting at MYADDR.  */

void
read_inferior_memory (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
    register int i;
    /* Round starting address down to longword boundary.  */
    register CORE_ADDR addr = memaddr & -sizeof (int);
    /* Round ending address up; get number of longwords that makes.  */
    register int count
	= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
    /* Allocate buffer of that many longwords.  */
    register int *buffer = (int *) alloca (count * sizeof (int));

    /* Read all the longwords */
    for (i = 0; i < count; i++, addr += sizeof (int))
    {
	buffer[i] = ptracex (PTRACE_PEEKTEXT, inferior_pid, addr, 0);
    }

    /* Copy appropriate bytes out of the buffer.  */
    memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
}

/* Copy LEN bytes of data from debugger memory at MYADDR
   to inferior's memory at MEMADDR.
   On failure (cannot write the inferior)
   returns the value of errno.  */

int
write_inferior_memory (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
    register int i;
    /* Round starting address down to longword boundary.  */
    register CORE_ADDR addr = memaddr & -sizeof (int);
    /* Round ending address up; get number of longwords that makes.  */
    register int count
	= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
    /* Allocate buffer of that many longwords.  */
    register int *buffer = (int *) alloca (count * sizeof (int));
    extern int errno;

    /* Fill start and end extra bytes of buffer with existing memory data.  */

    buffer[0] = ptracex (PTRACE_PEEKTEXT, inferior_pid, addr, 0);

    if (count > 1)
    {
	buffer[count - 1]
	    = ptracex (PTRACE_PEEKTEXT, inferior_pid,
		       addr + (count - 1) * sizeof (int), 0);
    }

    /* Copy data to be written over corresponding part of buffer */

    memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);

    /* Write the entire buffer.  */

    for (i = 0; i < count; i++, addr += sizeof (int))
    {
	errno = 0;
	ptracex (PTRACE_POKETEXT, inferior_pid, addr, buffer[i]);
	if (errno)
	    return errno;
    }

    return 0;
}

void
initialize ()
{
    inferior_pid = 0;
}

int
have_inferior_p ()
{
    return inferior_pid != 0;
}

void single_step( void )

/*
 * We're being told to do a single step command ('s').  Put
 * a break instruction at the next instruction.  A special case
 * exists when the current instruction is a branch.  In this
 * special case, the break point is placed at the target of
 * the branch as well as instruction following the delay slot
 * of the branch.
 */

{
    int bkpt = 0x0005000d;	/* bpt instruction for mips */
    int branch_type;		/* Return from is_branch() */
    unsigned int pcregval;	/* current pc value */

    pcregval = *(int *)&registers[ PC_REGNUM * 4];

    tracebpbt.pc = 0;		/* By default, we set the trace bp branch target pc to 0 */

    branch_type = is_branch( pcregval );
    if( branch_type != NOBRANCH )
    {
	/*
	 * Current instruction is a branch.  Put a breakpoint
	 * after delay slot as well as target of the branch.
	 */


	pcregval += sizeof( int ) * 2;
	read_inferior_memory( pcregval, &tracebp.opcode, sizeof(int) );
	tracebp.pc = pcregval;
	write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );

	if( pcregval != branch_target_address( pcregval - sizeof( int ) * 2, branch_type ) )
	{
	    /*
	     * It's possible we're jumping to the instruction after the delay
	     * slot.  Only put one bpt in if this is the case.
	     */

	    pcregval = branch_target_address( pcregval - sizeof( int ) * 2, branch_type );
	    read_inferior_memory( pcregval, &tracebpbt.opcode, sizeof(int) );
	    tracebpbt.pc = pcregval;
	    write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );
	}
    }
    else
    {
	/*
	 * Current instruction isn't a branch.  Set the breakpoint
	 * at the next instruction.
	 */

	pcregval += sizeof( int );
	read_inferior_memory( pcregval, &tracebp.opcode, sizeof(int) );
	tracebp.pc = pcregval;
	write_inferior_memory( pcregval, (char *)&bkpt, sizeof(bkpt) );
    }
    
}

int unsingle_step( void )

/*
 * This routine is called to undo the setting of breakpoints
 * for single stepping.  It knows enough to undo both breakpoints
 * if previous instruction was a branch (for delay slot and target).
 * It also knows to adjust the pc back by a word since the pc is
 * left pointing past breakpoint instruction.
 */

{
    int *pcreg;			/* Pointer to local copy of pc register */
    int ret;
    
    ret = 1;
    if( tracebpbt.pc || tracebp.pc )
    {
#if 0
	/*
	 * Back up the pc by a word since bpt instruction
	 * leaves pc pointing past the bpt instruction.
	 */

	pcreg = (int *)&registers[ PC_REGNUM * 4];
	*pcreg -= sizeof( int );
	store_inferior_registers( PC_REGNUM );
	fetch_inferior_registers(0);
#endif
	pcreg = (int *)&registers[ PC_REGNUM * 4];
	if( ( *pcreg != tracebpbt.pc ) && ( *pcreg != tracebp.pc ) )
	{
	    /*
	     * Stopped before we should have (could have been a signal).
	     * Ignore and try again.
	     */

	    ret = 0;
	}
	else
	{
	    if( tracebpbt.pc )
		write_inferior_memory( tracebpbt.pc, &tracebpbt.opcode, sizeof(int) );
	    if( tracebp.pc )
		write_inferior_memory( tracebp.pc, &tracebp.opcode, sizeof(int) );

	    tracebp.pc = 0;
	    tracebpbt.pc = 0;
	}
    }
    else
    {
	printf( "Got to unsingle_step and tracebp and tracebpbt were null\n" );
	exit( 0 );
    }
    
    return( ret );
}

int is_branch( int adr )

/*
 * This routine is called to determine if the current instruction is a 
 * branch type instruction.  We're called when we're being told to do
 * an 's' command.  If it is a branch we need to put the 'break' instruction
 * at the target of the branch as well past the delay slot of the branch.
 */

{
    union
    {
	unsigned int opcode;
	struct 
	{
	    unsigned bits_29_31:3;
	    unsigned bits_26_28:3;
	    unsigned bits_24_25:2;
	    unsigned bits_21_23:3;
	    unsigned bits_19_20:2;
	    unsigned bits_16_18:3;
	    unsigned unused_bits:10;
	    unsigned bits_3_5:3;
	    unsigned bits_0_2:3;
	} fields;
    } code;			/* opcode and bits within for decoding. */
    int branch_type;		/* Type of branch */
    
    read_inferior_memory( adr, &code.opcode, sizeof(code.opcode) );

    branch_type = NOBRANCH;
    
    switch( code.fields.bits_29_31 )
    {
    case 0:
	switch( code.fields.bits_26_28 )
	{
	case 0:
	    /* SPECIAL */
	    switch( code.fields.bits_3_5 )
	    {
	    case 1:
		switch( code.fields.bits_0_2 )
		{
		case 0:
		case 1:
		    /* JR, JALR */
		    branch_type = REG_TARGET;
		    break;
		    
		default:
		    break;
		}
		break;
		
	    default:
		break;
	    }
	    break;
	    
	case 1:
	    /* REGIMM */
	    switch( code.fields.bits_19_20 )
	    {
	    case 0:
	    case 2:
		switch( code.fields.bits_16_18 )
		{
		case 0:
		case 1:
		case 2:
		case 3:
		    /* BLTZ, BGEZ, BLTZL, BGEZL, BLTZAL, BGEZAL, BLTZALL, BGEZALL */
		    branch_type = OFFSET_16;
		    break;
		    
		default:
		    break;
		}
		
	    default:
		break;
	    }
	    break;
	    
	case 2:
	case 3:
	    /* J, JAL */
	    branch_type = OFFSET_24;
	    break;
	    
	case 4:
	case 5:
	case 6:
	case 7:
	    /* BEQ, BNE, BLEZ, BGTZ */
	    branch_type = OFFSET_16;
	    break;
	}
	break;
	
    case 2:
	switch( code.fields.bits_26_28 )
	{
	case 0:
	case 1:
	case 2:
	case 3:
	    /* COPx */
	    if( ( code.fields.bits_24_25 == 1 ) && ( code.fields.bits_21_23 == 0 ) )
		branch_type = OFFSET_16;
	    break;
	    
	case 4:
	case 5:
	case 6:
	case 7:
	    /* BEQL, BNEL, BLEZL, BGTZL */
	    branch_type = OFFSET_16;
	    break;
	}
	break;
	
    default:
	break;
    }

    return( branch_type );
}

int branch_target_address( int adr, int branch_type )

/*
 * We're doing single step and we want to find the address of the target of
 * the branch.  The is_branch() routine has already decoded the kind of
 * branch.  This helps us out.
 */

{
    unsigned int opcode;	/* Opcode (which should be a branch */
    int offset;			/* 16 or 26 bit offset */
    int target;			/* Target of branch */
    int reg;			/* Register number of JR/JALR */
    
    read_inferior_memory( adr, &opcode, sizeof(opcode) );

    switch( branch_type )
    {
    case OFFSET_16:
	offset = ( opcode & 0xffff ) << 16;
	offset >>= 14;		/* Sign extends and shifts offset up by 2 */
	target = (int)adr + sizeof( int ) + offset;
	break;

    case OFFSET_24:
	offset = ( opcode & 0x3ffffff ) << 2;
	target = ( ( adr + sizeof( int ) ) & 0xf0000000 ) + offset;
	break;

    case REG_TARGET:
	reg = ( opcode >> 21 ) & 0x1f;
	fetch_inferior_registers( reg );
	target =  *(int *)&registers[ reg * 4];
	break;
	
    default:
	fprintf( stderr, "Unknown branch type %d\n", branch_type );
	exit( 1 );
    }

    return( target );
}

ptracex( int a, int b, int c, int d )
{
    int ret;

    if( verbose )
	printf( "(%x) %d %x %x -- ", a, b, c, d );
    ret = ptrace( a, b, c, d );
    if( verbose )
	printf( "returning %x\n", ret );
    
    return( ret );
}
/* $Id$

Main code for remote server for GDB.
   Copyright (C) 1989, 1993 Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

23-jan-2001	rivers	Don't subtract 4 from epc as linux kernel now doing
                        proper thing.
                        Stick in single step until we've actually gotten to
                        single step instruction (ignore signals coming in).
28-dec-2000	rivers	Added -v option for more verbose debug output.
    			Move 'S' handling to 's' (I really don't know what the
 			difference is but there isn't a PTRACE_SINGLESTEP
			in OS support).
22-march-2000	rivers	Added support to attach to a process

  */

#include "server.h"

int cont_thread;
int general_thread;
int thread_from_wait;
int old_thread_from_wait;
int extended_protocol;
jmp_buf toplevel;
int inferior_pid;

int verbose = 0;

static unsigned char
start_inferior (argv, statusptr)
     char *argv[];
     char *statusptr;
{
  inferior_pid = create_inferior (argv[0], argv);
  fprintf (stderr, "Process %s created; pid = %d\n", argv[0], inferior_pid);

  /* Wait till we are at 1st instruction in program, return signal number.  */
  return mywait (statusptr);
}

extern int remote_debug;

int waitcheck = 0;

int
main (argc, argv)
     int argc;
     char *argv[];
{
  char ch, status, own_buf[2000], mem_buf[2000];
  int i = 0;
  unsigned char signal;
  unsigned int len;
  CORE_ADDR mem_addr;
  int *pcreg;
  
  if (setjmp(toplevel))
    {
      fprintf(stderr, "Exiting\n");
      exit(1);
    }

  while( waitcheck )
      sleep( 1 );
  
  if (argc < 3)
    error("Usage: gdbserver [-v] -a tty prog [args ...]");

  if( ( strcmp( argv[1], "-v" ) == 0 ) )
  {
      argv++;
      argc--;
      verbose = 1;
  }

  if( ( strcmp( argv[1], "-a" ) == 0 ) && ( argc < 4 ) )
    error("Usage: gdbserver -a tty prog [args ...]");

  if( strcmp( argv[1], "-a" ) == 0 )
  {
      inferior_pid = atoi( argv[3] );

      attach_inferior( );
      
      signal = mywait( &status );

      fprintf( stderr, "Attached to process pid = %d\n", inferior_pid );
      
      argv[1] = argv[0];
      argv++;
  }
  else
  {
      /* Wait till we are at first instruction in program.  */
      signal = start_inferior (&argv[2], &status);
  }

  /* We are now stopped at the first instruction of the target process */

  while (1)
    {
	remote_open (argv[1]);
restart:
      setjmp(toplevel);

      while (getpkt (own_buf) > 0)
	{
	  unsigned char sig;

	  i = 0;
	  ch = own_buf[i++];
	  if( verbose )
	      printf( "Command '%c'\n", ch );
	  
	  switch (ch)
	    {
	    case 'd':
	      remote_debug = !remote_debug;
	      break;
	    case '!':
	      extended_protocol = 1;
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case '?':
	      prepare_resume_reply (own_buf, status, signal);
	      break;
	    case 'H':
	      switch (own_buf[1])
		{
		case 'g':
		  general_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  fetch_inferior_registers (0);
		  break;
		case 'c':
		  cont_thread = strtol (&own_buf[2], NULL, 16);
		  write_ok (own_buf);
		  break;
		default:
		  /* Silently ignore it so that gdb can extend the protocol
		     without compatibility headaches.  */
		  own_buf[0] = '\0';
		  break;
		}
	      break;
	    case 'g':
	      convert_int_to_ascii (registers, own_buf, REGISTER_BYTES);
	      break;
	    case 'G':
	      convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES);
	      store_inferior_registers (-1);
	      write_ok (own_buf);
	      break;
	    case 'm':
	      decode_m_packet (&own_buf[1], &mem_addr, &len);
	      read_inferior_memory (mem_addr, mem_buf, len);
	      convert_int_to_ascii (mem_buf, own_buf, len);
	      break;
	    case 'M':
	      decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
	      if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'C':
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      myresume (0, sig);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
#if 0
	    case 'S':
	      convert_ascii_to_int (own_buf + 1, &sig, 1);
	      myresume (1, sig);
	      signal = mywait (&status);
	      prepare_resume_reply (own_buf, status, signal);
	      break;
#endif
	    case 'c':
	      /*
	       * 'Continue' until breakpoint (or signal) occurs.
	       * Must back pc up by a word as on breakpoint the
	       * epc points past the bpt instruction.
	       */
	      myresume (0, 0);
	      signal = mywait (&status);

	      if( status == 'T' )
	      {
		fetch_inferior_registers(0);
	      }

	      prepare_resume_reply (own_buf, status, signal);
	      break;

	    case 's':
  	    case 'S':
	      /*
	       * Single step target.  Fake this by reading next word
	       * past the pc, inserting a breakpoint, continuing and
	       * then restoring that word.  Also, make sure we stay
	       * until we've hit either next instruction or branch 
	       * target (we might get fooled by signals).
	       */

	      single_step();
	      signal = 0;
	      while( 1 )
	      {
		  myresume (0, signal);
		  signal = mywait (&status);
		  if( unsingle_step() )
		      break;
	      }
	      
	      prepare_resume_reply (own_buf, status, signal);
	      break;

	    case 'k':
	      fprintf (stderr, "Killing inferior\n");
	      kill_inferior ();
	      /* When using the extended protocol, we start up a new
		 debugging session.   The traditional protocol will
	         exit instead.  */
	      if (extended_protocol)
		{
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  exit (0);
		  break;
		}
	    case 'T':
	      if (mythread_alive (strtol (&own_buf[1], NULL, 16)))
		write_ok (own_buf);
	      else
		write_enn (own_buf);
	      break;
	    case 'R':
	      /* Restarting the inferior is only supported in the
		 extended protocol.  */
	      if (extended_protocol)
		{
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  /* It is a request we don't understand.  Respond with an
		     empty packet so that gdb knows that we don't support this
		     request.  */
		  own_buf[0] = '\0';
		  break;
		}
	    default:
	      /* It is a request we don't understand.  Respond with an
		 empty packet so that gdb knows that we don't support this
		 request.  */
	      own_buf[0] = '\0';
	      break;
	    }

	  putpkt (own_buf);

	  if (status == 'W')
	    fprintf (stderr,
		     "\nChild exited with status %d\n", sig);
	  if (status == 'X')
	    fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig);
	  if (status == 'W' || status == 'X')
	    {
	      if (extended_protocol)
		{
		  fprintf (stderr, "Killing inferior\n");
		  kill_inferior ();
		  write_ok (own_buf);
		  fprintf (stderr, "GDBserver restarting\n");

		  /* Wait till we are at 1st instruction in prog.  */
		  signal = start_inferior (&argv[2], &status);
		  goto restart;
		  break;
		}
	      else
		{
		  fprintf (stderr, "GDBserver exiting\n");
		  exit (0);
		}
	    }
	}

      /* We come here when getpkt fails.

	 For the extended remote protocol we exit (and this is the only
	 way we gracefully exit!).

	 For the traditional remote protocol close the connection,
	 and re-open it at the top of the loop.  */
      if (extended_protocol)
	{
	  remote_close ();
	  exit (0);
	}
      else
	{
	  fprintf (stderr, "Remote side has terminated connection.  GDBserver will reopen the connection.\n");

	  remote_close ();
	}
    }
}
/* This is just a dummy file to symlink to when GDB is configured as a
   cross-only debugger.  */
/* Remote utility routines for the remote server for GDB.
   Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include "server.h"
#include "terminal.h"
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <fcntl.h>

int remote_debug = 0;

static int remote_desc;

/* Open a connection to a remote debugger.
   NAME is the filename used for communication.  */

void
remote_open (name)
     char *name;
{
  int save_fcntl_flags;

/*  eeprodbg( 100 );*/
  
  if (!strchr (name, ':'))
    {
      remote_desc = open (name, O_RDWR);
      if (remote_desc < 0)
	perror_with_name ("Could not open remote device");

#ifdef HAVE_TERMIOS
      {
	struct termios termios;
	tcgetattr(remote_desc, &termios);

	termios.c_iflag = 0;
	termios.c_oflag = 0;
	termios.c_lflag = 0;
	termios.c_cflag &= ~(CSIZE|PARENB);
	termios.c_cflag |= CLOCAL | CS8;
	termios.c_cc[VMIN] = 0;
	termios.c_cc[VTIME] = 0;

	tcsetattr(remote_desc, TCSANOW, &termios);
      }
#endif

#ifdef HAVE_TERMIO
      {
	struct termio termio;
	ioctl (remote_desc, TCGETA, &termio);

	termio.c_iflag = 0;
	termio.c_oflag = 0;
	termio.c_lflag = 0;
	termio.c_cflag &= ~(CSIZE|PARENB);
	termio.c_cflag |= CLOCAL | CS8;
	termio.c_cc[VMIN] = 0;
	termio.c_cc[VTIME] = 0;

	ioctl (remote_desc, TCSETA, &termio);
      }
#endif

#ifdef HAVE_SGTTY
      {
	struct sgttyb sg;

	ioctl (remote_desc, TIOCGETP, &sg);
	sg.sg_flags = RAW;
	ioctl (remote_desc, TIOCSETP, &sg);
      }
#endif


    }
  else
    {
      char *port_str;
      int port;
      struct sockaddr_in sockaddr;
      int tmp;
      struct protoent *protoent;
      int tmp_desc;

      port_str = strchr (name, ':');

      port = atoi (port_str + 1);

      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
      if (tmp_desc < 0)
	perror_with_name ("Can't open socket");

      /* Allow rapid reuse of this port. */
      tmp = 1;
      setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
		  sizeof(tmp));

      sockaddr.sin_family = PF_INET;
      sockaddr.sin_port = htons(port);
      sockaddr.sin_addr.s_addr = INADDR_ANY;

      if (bind (tmp_desc, (struct sockaddr *)&sockaddr, sizeof (sockaddr))
	  || listen (tmp_desc, 1))
	perror_with_name ("Can't bind address");

      tmp = sizeof (sockaddr);
      remote_desc = accept (tmp_desc, (struct sockaddr *)&sockaddr, &tmp);
      if (remote_desc == -1)
	perror_with_name ("Accept failed");

      protoent = getprotobyname ("tcp");
      if (!protoent)
	perror_with_name ("getprotobyname");

      /* Enable TCP keep alive process. */
      tmp = 1;
      setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));

      /* Tell TCP not to delay small packets.  This greatly speeds up
	 interactive response. */
      tmp = 1;
      setsockopt (remote_desc, protoent->p_proto, TCP_NODELAY,
		  (char *)&tmp, sizeof(tmp));

      close (tmp_desc);		/* No longer need this */

      signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply
				    exits when the remote side dies.  */
    }

#if defined(F_SETFL) && defined (FASYNC)
  save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
  fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
  disable_async_io ();
#endif /* FASYNC */
  fprintf (stderr, "Remote debugging using %s\n", name);
}

void
remote_close()
{
  close (remote_desc);
}

/* Convert hex digit A to a number.  */

static int
fromhex (a)
     int a;
{
  if (a >= '0' && a <= '9')
    return a - '0';
  else if (a >= 'a' && a <= 'f')
    return a - 'a' + 10;
  else
    error ("Reply contains invalid hex digit");
}

/* Convert number NIB to a hex digit.  */

static int
tohex (nib)
     int nib;
{
  if (nib < 10)
    return '0' + nib;
  else
    return 'a' + nib - 10;
}

/* Send a packet to the remote machine, with error checking.
   The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */

int
putpkt (buf)
     char *buf;
{
  int i;
  unsigned char csum = 0;
  char buf2[2000];
  char buf3[1];
  int cnt = strlen (buf);
  char *p;
  static int putpktcnt = 0;
  
  putpktcnt++;
  /* Copy the packet into buffer BUF2, encapsulating it
     and giving it a checksum.  */

  p = buf2;
  *p++ = '$';

  for (i = 0; i < cnt; i++)
    {
      csum += buf[i];
      *p++ = buf[i];
    }
  *p++ = '#';
  *p++ = tohex ((csum >> 4) & 0xf);
  *p++ = tohex (csum & 0xf);

  *p = '\0';

  /* Send it over and over until we get a positive ack.  */

  do
    {
      int cc;

      if (write (remote_desc, buf2, p - buf2) != p - buf2)
	{
	  perror ("putpkt(write)");
	  return -1;
	}

      if (remote_debug)
	printf ("putpkt %d (\"%s\"); [looking for ack]\n", putpktcnt, buf2);
      cc = read (remote_desc, buf3, 1);
      if (remote_debug)
	printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
      if (cc <= 0)
	{
	  if (cc == 0)
	    fprintf (stderr, "putpkt(read): Got EOF\n");
	  else
	    perror ("putpkt(read)");

	  return -1;
	}
    }
  while (buf3[0] != '+');

  return 1;			/* Success! */
}

/* Come here when we get an input interrupt from the remote side.  This
   interrupt should only be active while we are waiting for the child to do
   something.  About the only thing that should come through is a ^C, which
   will cause us to send a SIGINT to the child.  */

static void
input_interrupt()
{
  int cc;
  char c;

  cc = read (remote_desc, &c, 1);

  if (cc != 1 || c != '\003')
    {
      fprintf(stderr, "input_interrupt, cc = %d c = %d\n", cc, c);
      return;
    }

  kill (inferior_pid, SIGINT);
}

void
enable_async_io()
{
  signal (SIGIO, input_interrupt);
}

void
disable_async_io()
{
  signal (SIGIO, SIG_IGN);
}

/* Returns next char from remote GDB.  -1 if error.  */

static int
readchar ()
{
  static char buf[BUFSIZ];
  static int bufcnt = 0;
  static char *bufp;
  
  if (bufcnt-- > 0)
    return *bufp++ & 0x7f;

  bufcnt = read (remote_desc, buf, sizeof (buf));

  if (bufcnt <= 0)
    {
      if (bufcnt == 0)
	fprintf (stderr, "readchar: Got EOF\n");
      else
	perror ("readchar");

      return -1;
    }

  bufp = buf;
  bufcnt--;
  return *bufp++ & 0x7f;
}

/* Read a packet from the remote machine, with error checking,
   and store it in BUF.  Returns length of packet, or negative if error. */

int
getpkt (buf)
     char *buf;
{
  char *bp;
  unsigned char csum, c1, c2;
  int c;
  static int getpktcnt = 0;

  getpktcnt++;
  while (1)
    {
      csum = 0;

      while (1)
	{
	  c = readchar ();
	  if (c == '$')
	    break;
	  if (remote_debug)
	    printf ("[getpkt: discarding char '%c']\n", c);
	  if (c < 0)
	    return -1;
	}

      bp = buf;
      while (1)
	{
	  c = readchar ();
	  if (c < 0)
	    return -1;
	  if (c == '#')
	    break;
	  *bp++ = c;
	  csum += c;
	}
      *bp = 0;

      c1 = fromhex (readchar ());
      c2 = fromhex (readchar ());
      
      if (csum == (c1 << 4) + c2)
	break;

      fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
	       (c1 << 4) + c2, csum, buf);
      write (remote_desc, "-", 1);
    }

  if (remote_debug)
    printf ("getpkt %d (\"%s\");  [sending ack] \n", getpktcnt, buf);

  write (remote_desc, "+", 1);

  if (remote_debug)
    printf ("[sent ack]\n");
  return bp - buf;
}

void
write_ok (buf)
     char *buf;
{
  buf[0] = 'O';
  buf[1] = 'K';
  buf[2] = '\0';
}

void
write_enn (buf)
     char *buf;
{
  buf[0] = 'E';
  buf[1] = 'N';
  buf[2] = 'N';
  buf[3] = '\0';
}

void
convert_int_to_ascii (from, to, n)
     char *from, *to;
     int n;
{
  int nib;
  char ch;
  while (n--)
    {
      ch = *from++;
      nib = ((ch & 0xf0) >> 4) & 0x0f;
      *to++ = tohex (nib);
      nib = ch & 0x0f;
      *to++ = tohex (nib);
    }
  *to++ = 0;
}


void
convert_ascii_to_int (from, to, n)
     char *from, *to;
     int n;
{
  int nib1, nib2;
  while (n--)
    {
      nib1 = fromhex (*from++);
      nib2 = fromhex (*from++);
      *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
    }
}

static char *
outreg(regno, buf)
     int regno;
     char *buf;
{
  extern char registers[];
  int regsize = REGISTER_RAW_SIZE (regno);

  *buf++ = tohex (regno >> 4);
  *buf++ = tohex (regno & 0xf);
  *buf++ = ':';
  convert_int_to_ascii (&registers[REGISTER_BYTE (regno)], buf, regsize);
  buf += 2 * regsize;
  *buf++ = ';';

  return buf;
}

void
prepare_resume_reply (buf, status, signo)
     char *buf;
     char status;
     unsigned char signo;
{
  int nib;

  *buf++ = status;

  /* FIXME!  Should be converting this signal number (numbered
     according to the signal numbering of the system we are running on)
     to the signal numbers used by the gdb protocol (see enum target_signal
     in gdb/target.h).  */
  nib = ((signo & 0xf0) >> 4);
  *buf++ = tohex (nib);
  nib = signo & 0x0f;
  *buf++ = tohex (nib);

  if (status == 'T')
    {
      buf = outreg (PC_REGNUM, buf);
      buf = outreg (FP_REGNUM, buf);
      buf = outreg (SP_REGNUM, buf);
#ifdef NPC_REGNUM
      buf = outreg (NPC_REGNUM, buf);
#endif
#ifdef O7_REGNUM
      buf = outreg (O7_REGNUM, buf);
#endif

      /* If the debugger hasn't used any thread features, don't burden it with
	 threads.  If we didn't check this, GDB 4.13 and older would choke.  */
      if (cont_thread != 0)
	{
	  if (old_thread_from_wait != thread_from_wait)
	    {
	      sprintf (buf, "thread:%x;", thread_from_wait);
	      buf += strlen (buf);
	      old_thread_from_wait = thread_from_wait;
	    }
	}
    }
  /* For W and X, we're done.  */
  *buf++ = 0;
}

void
decode_m_packet (from, mem_addr_ptr, len_ptr)
     char *from;
     CORE_ADDR *mem_addr_ptr;
     unsigned int *len_ptr;
{
  int i = 0, j = 0;
  char ch;
  *mem_addr_ptr = *len_ptr = 0;

  while ((ch = from[i++]) != ',')
    {
      *mem_addr_ptr = *mem_addr_ptr << 4;
      *mem_addr_ptr |= fromhex (ch) & 0x0f;
    }

  for (j = 0; j < 4; j++)
    {
      if ((ch = from[i++]) == 0)
	break;
      *len_ptr = *len_ptr << 4;
      *len_ptr |= fromhex (ch) & 0x0f;
    }
}

void
decode_M_packet (from, mem_addr_ptr, len_ptr, to)
     char *from, *to;
     CORE_ADDR *mem_addr_ptr;
     unsigned int *len_ptr;
{
  int i = 0;
  char ch;
  *mem_addr_ptr = *len_ptr = 0;

  while ((ch = from[i++]) != ',')
    {
      *mem_addr_ptr = *mem_addr_ptr << 4;
      *mem_addr_ptr |= fromhex (ch) & 0x0f;
    }

  while ((ch = from[i++]) != ':')
    {
      *len_ptr = *len_ptr << 4;
      *len_ptr |= fromhex (ch) & 0x0f;
    }

  convert_ascii_to_int (&from[i++], to, *len_ptr);
}
/* $Id$ Common definitions for remote server for GDB.
   Copyright (C) 1993 Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include "defs.h"
#include <setjmp.h>

/* Target-specific functions */

int create_inferior PARAMS ((char *program, char **allargs));
void kill_inferior PARAMS ((void));
void attach_inferior PARAMS ((void));
void fetch_inferior_registers PARAMS ((int regno));
void store_inferior_registers PARAMS ((int regno));
int mythread_alive PARAMS ((int pid));
void myresume PARAMS ((int step, int signo));
unsigned char mywait PARAMS ((char *status));
void read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
int write_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
int create_inferior ();
void single_step( void );
int unsingle_step( void );

/* Target-specific variables */

extern char registers[];

/* Public variables in server.c */

extern int cont_thread;
extern int general_thread;
extern int thread_from_wait;
extern int old_thread_from_wait;

extern jmp_buf toplevel;
extern int inferior_pid;

/* Functions from remote-utils.c */

int putpkt PARAMS ((char *buf));
int getpkt PARAMS ((char *buf));
void remote_open PARAMS ((char *name));
void remote_close PARAMS ((void));
void write_ok PARAMS ((char *buf));
void write_enn PARAMS ((char *buf));
void enable_async_io PARAMS ((void));
void disable_async_io PARAMS ((void));
void convert_ascii_to_int PARAMS ((char *from, char *to, int n));
void convert_int_to_ascii PARAMS ((char *from, char *to, int n));
void prepare_resume_reply PARAMS ((char *buf, char status, unsigned char sig));

void decode_m_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
			     unsigned int *len_ptr));
void decode_M_packet PARAMS ((char *from, CORE_ADDR *mem_addr_ptr,
			     unsigned int *len_ptr, char *to));


/* Functions from utils.c */

/*void perror_with_name PARAMS ((char *string));*/
/* $Id$

Definitions to make GDB run on a mips box under 4.3bsd.
   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
   Free Software Foundation, Inc.
   Contributed by Per Bothner (bothner@cs.wisc.edu) at U.Wisconsin
   and by Alessandro Forin (af@cs.cmu.edu) at CMU..

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 

28-dec-2000	rivers	All registers are 4 bytes, even floating point.

 */

#ifndef TM_MIPS_H
#define TM_MIPS_H 1

#ifdef __STDC__
struct frame_info;
struct symbol;
struct type;
struct value;
#endif

#include <bfd.h>
#include "coff/sym.h"		/* Needed for PDR below.  */
#include "coff/symconst.h"

#if !defined (TARGET_BYTE_ORDER_DEFAULT)
#define TARGET_BYTE_ORDER_DEFAULT LITTLE_ENDIAN
#endif

#if !defined (GDB_TARGET_IS_MIPS64)
#define GDB_TARGET_IS_MIPS64 0
#endif

#if !defined (MIPS_EABI)
#define MIPS_EABI 0
#endif

#if !defined (TARGET_MONITOR_PROMPT)
#define TARGET_MONITOR_PROMPT "<IDT>"
#endif

/* PC should be masked to remove possible MIPS16 flag */
#if !defined (GDB_TARGET_MASK_DISAS_PC)
#define GDB_TARGET_MASK_DISAS_PC(addr) UNMAKE_MIPS16_ADDR(addr)
#endif
#if !defined (GDB_TARGET_UNMASK_DISAS_PC)
#define GDB_TARGET_UNMASK_DISAS_PC(addr) MAKE_MIPS16_ADDR(addr)
#endif

/* Floating point is IEEE compliant */
#define IEEE_FLOAT

/* The name of the usual type of MIPS processor that is in the target
   system.  */

#define DEFAULT_MIPS_TYPE "generic"

/* Remove useless bits from an instruction address.  */

#define ADDR_BITS_REMOVE(addr) mips_addr_bits_remove(addr)
CORE_ADDR mips_addr_bits_remove PARAMS ((CORE_ADDR addr));

/* Remove useless bits from the stack pointer.  */

#define TARGET_READ_SP() ADDR_BITS_REMOVE (read_register (SP_REGNUM))

/* Offset from address of function to start of its code.
   Zero on most machines.  */

#define FUNCTION_START_OFFSET 0

/* Advance PC across any function entry prologue instructions
   to reach some "real" code.  */

#define SKIP_PROLOGUE(pc)	pc = mips_skip_prologue (pc, 0)
extern CORE_ADDR mips_skip_prologue PARAMS ((CORE_ADDR addr, int lenient));

/* Return non-zero if PC points to an instruction which will cause a step
   to execute both the instruction at PC and an instruction at PC+4.  */
extern int mips_step_skips_delay PARAMS ((CORE_ADDR));
#define STEP_SKIPS_DELAY_P (1)
#define STEP_SKIPS_DELAY(pc) (mips_step_skips_delay (pc))

/* Immediately after a function call, return the saved pc.
   Can't always go through the frames for this because on some machines
   the new frame is not set up until the new function executes
   some instructions.  */

#define SAVED_PC_AFTER_CALL(frame)	read_register(RA_REGNUM)

/* Are we currently handling a signal */

extern int in_sigtramp PARAMS ((CORE_ADDR, char *));
#define IN_SIGTRAMP(pc, name)	in_sigtramp(pc, name)

/* Stack grows downward.  */

#define INNER_THAN(lhs,rhs) ((lhs) < (rhs))

#define BIG_ENDIAN 4321

/* BREAKPOINT_FROM_PC uses the program counter value to determine whether a
   16- or 32-bit breakpoint should be used.  It returns a pointer
   to a string of bytes that encode a breakpoint instruction, stores
   the length of the string to *lenptr, and adjusts the pc (if necessary) to
   point to the actual memory location where the breakpoint should be
   inserted.  */

extern breakpoint_from_pc_fn mips_breakpoint_from_pc;
#define BREAKPOINT_FROM_PC(pcptr, lenptr) mips_breakpoint_from_pc(pcptr, lenptr)

/* Amount PC must be decremented by after a breakpoint.
   This is often the number of bytes in BREAKPOINT
   but not always.  */

#define DECR_PC_AFTER_BREAK 0

/* Say how long (ordinary) registers are.  This is a piece of bogosity
   used in push_word and a few other places; REGISTER_RAW_SIZE is the
   real way to know how big a register is.  */

#define REGISTER_SIZE 4

/* The size of a register.  This is predefined in tm-mips64.h.  We
   can't use REGISTER_SIZE because that is used for various other
   things.  */

#ifndef MIPS_REGSIZE
#define MIPS_REGSIZE 4
#endif

/* The sizes of floating point registers.  */

#define MIPS_FPU_SINGLE_REGSIZE 4
#define MIPS_FPU_DOUBLE_REGSIZE 8

/* Number of machine registers */

#ifndef NUM_REGS
#define NUM_REGS 90
#endif

/* Initializer for an array of names of registers.
   There should be NUM_REGS strings in this initializer.  */

#ifndef REGISTER_NAMES
#define REGISTER_NAMES 	\
    {	"zero",	"at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3", \
	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7", \
	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7", \
	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra", \
	"sr",	"lo",	"hi",	"bad",	"cause","pc",    \
	"f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7", \
	"f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15", \
	"f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",\
	"f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",\
	"fsr",  "fir",  "fp",	"", \
	"",	"",	"",	"",	"",	"",	"",	"", \
	"",	"",	"",	"",	"",	"",	"",	"", \
    }
#endif

/* Register numbers of various important registers.
   Note that some of these values are "real" register numbers,
   and correspond to the general registers of the machine,
   and some are "phony" register numbers which are too large
   to be actual register numbers as far as the user is concerned
   but do serve to get the desired values when passed to read_register.  */

#define ZERO_REGNUM 0		/* read-only register, always 0 */
#define V0_REGNUM 2		/* Function integer return value */
#define A0_REGNUM 4		/* Loc of first arg during a subr call */
#if MIPS_EABI
#  define MIPS_LAST_ARG_REGNUM 11 /* EABI uses R4 through R11 for args */
#  define MIPS_NUM_ARG_REGS 8
#else
#  define MIPS_LAST_ARG_REGNUM 7  /* old ABI uses R4 through R7 for args */
#  define MIPS_NUM_ARG_REGS 4
#endif
#define T9_REGNUM 25		/* Contains address of callee in PIC */
#define SP_REGNUM 29		/* Contains address of top of stack */
#define RA_REGNUM 31		/* Contains return address value */
#define PS_REGNUM 32		/* Contains processor status */
#define HI_REGNUM 34            /* Multiple/divide temp */
#define LO_REGNUM 33            /* ... */
#define BADVADDR_REGNUM 35	/* bad vaddr for addressing exception */
#define CAUSE_REGNUM 36		/* describes last exception */
#define PC_REGNUM 37		/* Contains program counter */
#define FP0_REGNUM 38           /* Floating point register 0 (single float) */
#define FPA0_REGNUM (FP0_REGNUM+12) /* First float argument register */
#if MIPS_EABI			/* EABI uses F12 through F19 for args */
#  define MIPS_LAST_FP_ARG_REGNUM (FP0_REGNUM+19)
#  define MIPS_NUM_FP_ARG_REGS 8
#else				/* old ABI uses F12 through F15 for args */
#  define MIPS_LAST_FP_ARG_REGNUM (FP0_REGNUM+15)
#  define MIPS_NUM_FP_ARG_REGS 4
#endif
#define FCRCS_REGNUM 70         /* FP control/status */
#define FCRIR_REGNUM 71         /* FP implementation/revision */
#define FP_REGNUM 72		/* Pseudo register that contains true address of executing stack frame */
#define	UNUSED_REGNUM 73	/* Never used, FIXME */
#define	FIRST_EMBED_REGNUM 74	/* First CP0 register for embedded use */
#define	PRID_REGNUM 89		/* Processor ID */
#define	LAST_EMBED_REGNUM 89	/* Last one */

/* Define DO_REGISTERS_INFO() to do machine-specific formatting
   of register dumps. */

#define DO_REGISTERS_INFO(_regnum, fp) mips_do_registers_info(_regnum, fp)
extern void mips_do_registers_info PARAMS ((int, int));

/* Total amount of space needed to store our copies of the machine's
   register state, the array `registers'.  */

#define REGISTER_BYTES (NUM_REGS*MIPS_REGSIZE)

/* Index within `registers' of the first byte of the space for
   register N.  */

#define REGISTER_BYTE(N) ((N) * MIPS_REGSIZE)

/* Number of bytes of storage in the actual machine representation
   for register N. */

#define REGISTER_RAW_SIZE(N) REGISTER_VIRTUAL_SIZE(N)

/* Number of bytes of storage in the program's representation
   for register N. */

#define REGISTER_VIRTUAL_SIZE(N) (REGISTER_VIRTUAL_TYPE (N))

/* Largest value REGISTER_RAW_SIZE can have.  */

#define MAX_REGISTER_RAW_SIZE 4

/* Largest value REGISTER_VIRTUAL_SIZE can have.  */

#define MAX_REGISTER_VIRTUAL_SIZE 4

/* Return the GDB type object for the "standard" data type of data in
   register N.  */

#ifndef REGISTER_VIRTUAL_TYPE
#define REGISTER_VIRTUAL_TYPE(N) \
	(((N) >= FP0_REGNUM && (N) < FP0_REGNUM+32) ? 4 \
	 : ((N) == 32 /*SR*/) ? 4 \
	 : ((N) >= 70 && (N) <= 89) ? 4 \
	 : 4)
#endif

/* All mips targets store doubles in a register pair with the least
   significant register in the lower numbered register.
   If the target is big endian, double register values need conversion
   between memory and register formats.  */

#define REGISTER_CONVERT_TO_TYPE(n, type, buffer)			\
  do {if (TARGET_BYTE_ORDER == BIG_ENDIAN				\
	  && REGISTER_RAW_SIZE (n) == 4					\
	  && (n) >= FP0_REGNUM && (n) < FP0_REGNUM + 32			\
	  && TYPE_CODE(type) == TYPE_CODE_FLT				\
	  && TYPE_LENGTH(type) == 4) {					\
        char __temp[4];							\
	memcpy (__temp, ((char *)(buffer))+4, 4);			\
	memcpy (((char *)(buffer))+4, (buffer), 4); 			\
	memcpy (((char *)(buffer)), __temp, 4); }} while (0)

#define REGISTER_CONVERT_FROM_TYPE(n, type, buffer)			\
  do {if (TARGET_BYTE_ORDER == BIG_ENDIAN				\
	  && REGISTER_RAW_SIZE (n) == 4					\
	  && (n) >= FP0_REGNUM && (n) < FP0_REGNUM + 32			\
	  && TYPE_CODE(type) == TYPE_CODE_FLT				\
	  && TYPE_LENGTH(type) == 4) {					\
        char __temp[4];							\
	memcpy (__temp, ((char *)(buffer))+4, 4);			\
	memcpy (((char *)(buffer))+4, (buffer), 4); 			\
	memcpy (((char *)(buffer)), __temp, 4); }} while (0)

/* Store the address of the place in which to copy the structure the
   subroutine will return.  Handled by mips_push_arguments.  */

#define STORE_STRUCT_RETURN(addr, sp)	/**/

/* Extract from an array REGBUF containing the (raw) register state
   a function return value of type TYPE, and copy that, in virtual format,
   into VALBUF.  XXX floats */

#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
  mips_extract_return_value(TYPE, REGBUF, VALBUF)
extern void
mips_extract_return_value PARAMS ((struct type *, char [], char *));

/* Write into appropriate registers a function return value
   of type TYPE, given in virtual format.  */

#define STORE_RETURN_VALUE(TYPE,VALBUF) \
  mips_store_return_value(TYPE, VALBUF)
extern void mips_store_return_value PARAMS ((struct type *, char *));

/* Extract from an array REGBUF containing the (raw) register state
   the address in which a function should return its structure value,
   as a CORE_ADDR (or an expression that can be used as one).  */
/* The address is passed in a0 upon entry to the function, but when
   the function exits, the compiler has copied the value to v0.  This
   convention is specified by the System V ABI, so I think we can rely
   on it.  */

#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
  (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \
		    REGISTER_RAW_SIZE (V0_REGNUM)))

extern use_struct_convention_fn mips_use_struct_convention;
#define USE_STRUCT_CONVENTION(gcc_p, type) mips_use_struct_convention (gcc_p, type)

/* Describe the pointer in each stack frame to the previous stack frame
   (its caller).  */

/* FRAME_CHAIN takes a frame's nominal address
   and produces the frame's chain-pointer. */

#define FRAME_CHAIN(thisframe) (CORE_ADDR) mips_frame_chain (thisframe)
extern CORE_ADDR mips_frame_chain PARAMS ((struct frame_info *));

/* Define other aspects of the stack frame.  */


/* A macro that tells us whether the function invocation represented
   by FI does not have a frame on the stack associated with it.  If it
   does not, FRAMELESS is set to 1, else 0.  */
/* We handle this differently for mips, and maybe we should not */

#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS)  {(FRAMELESS) = 0;}

/* Saved Pc.  */

#define FRAME_SAVED_PC(FRAME)	(mips_frame_saved_pc(FRAME))
extern CORE_ADDR mips_frame_saved_pc PARAMS ((struct frame_info *));

#define FRAME_ARGS_ADDRESS(fi)	(fi)->frame

#define FRAME_LOCALS_ADDRESS(fi) (fi)->frame

/* Return number of args passed to a frame.
   Can return -1, meaning no way to tell.  */

#define FRAME_NUM_ARGS(num, fi)	(num = mips_frame_num_args(fi))
extern int mips_frame_num_args PARAMS ((struct frame_info *));

/* Return number of bytes at start of arglist that are not really args.  */

#define FRAME_ARGS_SKIP 0

/* Put here the code to store, into a struct frame_saved_regs,
   the addresses of the saved registers of frame described by FRAME_INFO.
   This includes special registers such as pc and fp saved in special
   ways in the stack frame.  sp is even more special:
   the address we return for it IS the sp for the next frame.  */

#define FRAME_INIT_SAVED_REGS(frame_info) \
  do { \
    if ((frame_info)->saved_regs == NULL) \
      mips_find_saved_regs (frame_info); \
    (frame_info)->saved_regs[SP_REGNUM] = (frame_info)->frame; \
  } while (0)
extern void mips_find_saved_regs PARAMS ((struct frame_info *));


/* Things needed for making the inferior call functions.  */

/* Stack must be aligned on 32-bit boundaries when synthesizing
   function calls.  We don't need STACK_ALIGN, PUSH_ARGUMENTS will
   handle it. */

#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
    sp = mips_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr))
extern CORE_ADDR
mips_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR));

/* Push an empty stack frame, to record the current PC, etc.  */

#define PUSH_DUMMY_FRAME 	mips_push_dummy_frame()
extern void mips_push_dummy_frame PARAMS ((void));

/* Discard from the stack the innermost frame, restoring all registers.  */

#define POP_FRAME		mips_pop_frame()
extern void mips_pop_frame PARAMS ((void));

#define CALL_DUMMY { 0 }

#define CALL_DUMMY_START_OFFSET (0)

#define CALL_DUMMY_BREAKPOINT_OFFSET (0)

/* On Irix, $t9 ($25) contains the address of the callee (used for PIC).
   It doesn't hurt to do this on other systems; $t9 will be ignored.  */
#define FIX_CALL_DUMMY(dummyname, start_sp, fun, nargs, args, rettype, gcc_p) \
    write_register(T9_REGNUM, fun)

#define CALL_DUMMY_LOCATION AT_ENTRY_POINT

#define CALL_DUMMY_ADDRESS() (mips_call_dummy_address ())
extern CORE_ADDR mips_call_dummy_address PARAMS ((void));

/* There's a mess in stack frame creation.  See comments in blockframe.c
   near reference to INIT_FRAME_PC_FIRST.  */

#define	INIT_FRAME_PC(fromleaf, prev) /* nada */

#define INIT_FRAME_PC_FIRST(fromleaf, prev) \
   mips_init_frame_pc_first(fromleaf, prev)
extern void mips_init_frame_pc_first PARAMS ((int, struct frame_info *));

/* Special symbol found in blocks associated with routines.  We can hang
   mips_extra_func_info_t's off of this.  */

#define MIPS_EFI_SYMBOL_NAME "__GDB_EFI_INFO__"
extern void ecoff_relocate_efi PARAMS ((struct symbol *, CORE_ADDR));

/* Specific information about a procedure.
   This overlays the MIPS's PDR records, 
   mipsread.c (ab)uses this to save memory */

typedef struct mips_extra_func_info {
	long	numargs;	/* number of args to procedure (was iopt) */
	bfd_vma high_addr;      /* upper address bound */
	long	frame_adjust;	/* offset of FP from SP (used on MIPS16) */
	PDR	pdr;		/* Procedure descriptor record */
} *mips_extra_func_info_t;

#define EXTRA_FRAME_INFO \
  mips_extra_func_info_t proc_desc; \
  int num_args;

#define INIT_EXTRA_FRAME_INFO(fromleaf, fci) init_extra_frame_info(fci)
extern void init_extra_frame_info PARAMS ((struct frame_info *));

#define	PRINT_EXTRA_FRAME_INFO(fi) \
  { \
    if (fi && fi->proc_desc && fi->proc_desc->pdr.framereg < NUM_REGS) \
      printf_filtered (" frame pointer is at %s+%d\n", \
                       REGISTER_NAME (fi->proc_desc->pdr.framereg), \
                                 fi->proc_desc->pdr.frameoffset); \
  }

/* It takes two values to specify a frame on the MIPS.

   In fact, the *PC* is the primary value that sets up a frame.  The
   PC is looked up to see what function it's in; symbol information
   from that function tells us which register is the frame pointer
   base, and what offset from there is the "virtual frame pointer".
   (This is usually an offset from SP.)  On most non-MIPS machines,
   the primary value is the SP, and the PC, if needed, disambiguates
   multiple functions with the same SP.  But on the MIPS we can't do
   that since the PC is not stored in the same part of the frame every
   time.  This does not seem to be a very clever way to set up frames,
   but there is nothing we can do about that).  */

#define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv)
extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *));

/* Convert a dbx stab register number (from `r' declaration) to a gdb REGNUM */

#define STAB_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-38)

/* Convert a ecoff register number to a gdb REGNUM */

#define ECOFF_REG_TO_REGNUM(num) ((num) < 32 ? (num) : (num)+FP0_REGNUM-32)

/* If the current gcc for for this target does not produce correct debugging
   information for float parameters, both prototyped and unprototyped, then
   define this macro.  This forces gdb to  always assume that floats are
   passed as doubles and then converted in the callee.

   For the mips chip, it appears that the debug info marks the parameters as
   floats regardless of whether the function is prototyped, but the actual
   values are passed as doubles for the non-prototyped case and floats for
   the prototyped case.  Thus we choose to make the non-prototyped case work
   for C and break the prototyped case, since the non-prototyped case is
   probably much more common.  (FIXME). */

#define COERCE_FLOAT_TO_DOUBLE (current_language -> la_language == language_c)

/* Select the default mips disassembler */

#define TM_PRINT_INSN_MACH 0


/* These are defined in mdebugread.c and are used in mips-tdep.c  */
extern CORE_ADDR sigtramp_address, sigtramp_end;
extern void fixup_sigtramp PARAMS ((void));

/* Defined in mips-tdep.c and used in remote-mips.c */
extern char *mips_read_processor_type PARAMS ((void));

/* Functions for dealing with MIPS16 call and return stubs.  */
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name)	mips_in_call_stub (pc, name)
#define IN_SOLIB_RETURN_TRAMPOLINE(pc, name)	mips_in_return_stub (pc, name)
#define SKIP_TRAMPOLINE_CODE(pc)		mips_skip_stub (pc)
#define IGNORE_HELPER_CALL(pc)			mips_ignore_helper (pc)
extern int mips_in_call_stub PARAMS ((CORE_ADDR pc,  char *name));
extern int mips_in_return_stub PARAMS ((CORE_ADDR pc,  char *name));
extern CORE_ADDR mips_skip_stub PARAMS ((CORE_ADDR pc));
extern int mips_ignore_helper PARAMS ((CORE_ADDR pc));

#ifndef TARGET_MIPS
#define TARGET_MIPS
#endif

/* Definitions and declarations used by mips-tdep.c and remote-mips.c  */
#define MIPS_INSTLEN 4		/* Length of an instruction */
#define MIPS16_INSTLEN 2	/* Length of an instruction on MIPS16*/
#define MIPS_NUMREGS 32		/* Number of integer or float registers */
typedef unsigned long t_inst;	/* Integer big enough to hold an instruction */

/* MIPS16 function addresses are odd (bit 0 is set).  Here are some
   macros to test, set, or clear bit 0 of addresses.  */
#define IS_MIPS16_ADDR(addr)	 ((addr) & 1)
#define MAKE_MIPS16_ADDR(addr)	 ((addr) | 1)
#define UNMAKE_MIPS16_ADDR(addr) ((addr) & ~1)

#endif	/* TM_MIPS_H */

/* Macros for setting and testing a bit in a minimal symbol that
   marks it as 16-bit function.  The MSB of the minimal symbol's
   "info" field is used for this purpose. This field is already
   being used to store the symbol size, so the assumption is
   that the symbol size cannot exceed 2^31.

   ELF_MAKE_MSYMBOL_SPECIAL
			tests whether an ELF symbol is "special", i.e. refers
			to a 16-bit function, and sets a "special" bit in a 
			minimal symbol to mark it as a 16-bit function
   MSYMBOL_IS_SPECIAL	tests the "special" bit in a minimal symbol
   MSYMBOL_SIZE		returns the size of the minimal symbol, i.e.
			the "info" field with the "special" bit masked out
*/

#define ELF_MAKE_MSYMBOL_SPECIAL(sym,msym) \
 { \
  if (((elf_symbol_type *)(sym))->internal_elf_sym.st_other == STO_MIPS16) { \
    MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) | 0x80000000); \
    SYMBOL_VALUE_ADDRESS (msym) |= 1; \
  } \
 }
   
#define MSYMBOL_IS_SPECIAL(msym) \
  (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
#define MSYMBOL_SIZE(msym) \
  ((long) MSYMBOL_INFO (msym) & 0x7fffffff)
/* General utility routines for the remote server for GDB.
   Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include "server.h"
#include <stdio.h>
#include <string.h>

/* Generally useful subroutines used throughout the program.  */

/* Print the system error message for errno, and also mention STRING
   as the file name for which the error was encountered.
   Then return to command level.  */

void
perror_with_name (string)
     char *string;
{
  extern int sys_nerr;
/*  extern char *sys_errlist[];*/
  extern int errno;
  char *err;
  char *combined;

  if (errno < sys_nerr)
    err = sys_errlist[errno];
  else
    err = "unknown error";

  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
  strcpy (combined, string);
  strcat (combined, ": ");
  strcat (combined, err);

  error ("%s.", combined);
}

/* Print an error message and return to command level.
   STRING is the error message, used as a fprintf string,
   and ARG is passed as an argument to it.  */

#ifdef ANSI_PROTOTYPES
NORETURN void
error (const char *string, ...)
#else
void
error (va_alist)
     va_dcl
#endif
{
  extern jmp_buf toplevel;
  va_list args;
#ifdef ANSI_PROTOTYPES
  va_start (args, string);
#else
  va_start (args);
#endif
  fflush (stdout);
#ifdef ANSI_PROTOTYPES
  vfprintf (stderr, string, args);
#else
  {
    char *string1;

    string1 = va_arg (args, char *);
    vfprintf (stderr, string1, args);
  }
#endif
  fprintf (stderr, "\n");
  longjmp(toplevel, 1);
}

/* Print an error message and exit reporting failure.
   This is for a error that we cannot continue from.
   STRING and ARG are passed to fprintf.  */

/* VARARGS */
NORETURN void
#ifdef ANSI_PROTOTYPES
fatal (char *string, ...)
#else
fatal (va_alist)
     va_dcl
#endif
{
  va_list args;
#ifdef ANSI_PROTOTYPES
  va_start (args, string);
#else
  char *string;
  va_start (args);
  string = va_arg (args, char *);
#endif
  fprintf (stderr, "gdb: ");
  vfprintf (stderr, string, args);
  fprintf (stderr, "\n");
  va_end (args);
  exit (1);
}
/* Definitions to make GDB run on a mips box under 4.3bsd.
   Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
   Contributed by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
   and by Alessandro Forin(af@cs.cmu.edu) at CMU

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#if !defined (HOST_BYTE_ORDER)
#define HOST_BYTE_ORDER LITTLE_ENDIAN
#endif

#ifdef ultrix
/* Needed for DECstation core files.  */
#include <machine/param.h>
#define KERNEL_U_ADDR UADDR

/* Native Ultrix cc has broken long long support.  */
#ifndef __GNUC__
#undef CC_HAS_LONG_LONG
#endif
#endif

#if ! defined (__STDC__) && ! defined (offsetof)
# define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif

/* Only used for core files on DECstations.
   First four registers at u.u_ar0 are saved arguments, and
   there is no r0 saved.   Float registers are saved
   in u_pcb.pcb_fpregs, not relative to u.u_ar0.  */

#define REGISTER_U_ADDR(addr, blockend, regno) 		\
	{ \
	  if (regno < FP0_REGNUM) \
	    addr = blockend + sizeof(int) * (4 + regno - 1); \
	  else \
	    addr = offsetof (struct user, u_pcb.pcb_fpregs[0]) + \
		   sizeof (int) * (regno - FP0_REGNUM); \
	}

/* Kernel is a bit tenacious about sharing text segments, disallowing bpts.  */
#define	ONE_PROCESS_WRITETEXT

/* HAVE_SGTTY also works, last we tried.

   But we have termios, at least as of Ultrix 4.2A, so use it.  */
#define HAVE_TERMIOS

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