| 1 | 330 | jeremybenn | /****************************************************************************
 | 
      
         | 2 |  |  |  
 | 
      
         | 3 |  |  |                 THIS SOFTWARE IS NOT COPYRIGHTED
 | 
      
         | 4 |  |  |  
 | 
      
         | 5 |  |  |    HP offers the following for use in the public domain.  HP makes no
 | 
      
         | 6 |  |  |    warranty with regard to the software or it's performance and the
 | 
      
         | 7 |  |  |    user accepts the software "AS IS" with all faults.
 | 
      
         | 8 |  |  |  
 | 
      
         | 9 |  |  |    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
 | 
      
         | 10 |  |  |    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
      
         | 11 |  |  |    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 | 
      
         | 12 |  |  |  
 | 
      
         | 13 |  |  | ****************************************************************************/
 | 
      
         | 14 |  |  |  
 | 
      
         | 15 |  |  | /****************************************************************************
 | 
      
         | 16 |  |  |  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
 | 
      
         | 17 |  |  |  *
 | 
      
         | 18 |  |  |  *  Module name: remcom.c $
 | 
      
         | 19 |  |  |  *  Revision: 1.34 $
 | 
      
         | 20 |  |  |  *  Date: 91/03/09 12:29:49 $
 | 
      
         | 21 |  |  |  *  Contributor:     Lake Stevens Instrument Division$
 | 
      
         | 22 |  |  |  *
 | 
      
         | 23 |  |  |  *  Description:     low level support for gdb debugger. $
 | 
      
         | 24 |  |  |  *
 | 
      
         | 25 |  |  |  *  Considerations:  only works on target hardware $
 | 
      
         | 26 |  |  |  *
 | 
      
         | 27 |  |  |  *  Written by:      Glenn Engel $
 | 
      
         | 28 |  |  |  *  ModuleState:     Experimental $
 | 
      
         | 29 |  |  |  *
 | 
      
         | 30 |  |  |  *  NOTES:           See Below $
 | 
      
         | 31 |  |  |  *
 | 
      
         | 32 |  |  |  *  Modified for M32R by Michael Snyder, Cygnus Support.
 | 
      
         | 33 |  |  |  *
 | 
      
         | 34 |  |  |  *  To enable debugger support, two things need to happen.  One, a
 | 
      
         | 35 |  |  |  *  call to set_debug_traps() is necessary in order to allow any breakpoints
 | 
      
         | 36 |  |  |  *  or error conditions to be properly intercepted and reported to gdb.
 | 
      
         | 37 |  |  |  *  Two, a breakpoint needs to be generated to begin communication.  This
 | 
      
         | 38 |  |  |  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
 | 
      
         | 39 |  |  |  *  simulates a breakpoint by executing a trap #1.
 | 
      
         | 40 |  |  |  *
 | 
      
         | 41 |  |  |  *  The external function exceptionHandler() is
 | 
      
         | 42 |  |  |  *  used to attach a specific handler to a specific M32R vector number.
 | 
      
         | 43 |  |  |  *  It should use the same privilege level it runs at.  It should
 | 
      
         | 44 |  |  |  *  install it as an interrupt gate so that interrupts are masked
 | 
      
         | 45 |  |  |  *  while the handler runs.
 | 
      
         | 46 |  |  |  *
 | 
      
         | 47 |  |  |  *  Because gdb will sometimes write to the stack area to execute function
 | 
      
         | 48 |  |  |  *  calls, this program cannot rely on using the supervisor stack so it
 | 
      
         | 49 |  |  |  *  uses it's own stack area reserved in the int array remcomStack.
 | 
      
         | 50 |  |  |  *
 | 
      
         | 51 |  |  |  *************
 | 
      
         | 52 |  |  |  *
 | 
      
         | 53 |  |  |  *    The following gdb commands are supported:
 | 
      
         | 54 |  |  |  *
 | 
      
         | 55 |  |  |  * command          function                               Return value
 | 
      
         | 56 |  |  |  *
 | 
      
         | 57 |  |  |  *    g             return the value of the CPU registers  hex data or ENN
 | 
      
         | 58 |  |  |  *    G             set the value of the CPU registers     OK or ENN
 | 
      
         | 59 |  |  |  *
 | 
      
         | 60 |  |  |  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
 | 
      
         | 61 |  |  |  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
 | 
      
         | 62 |  |  |  *    XAA..AA,LLLL: Write LLLL binary bytes at address     OK or ENN
 | 
      
         | 63 |  |  |  *                  AA..AA
 | 
      
         | 64 |  |  |  *
 | 
      
         | 65 |  |  |  *    c             Resume at current address              SNN   ( signal NN)
 | 
      
         | 66 |  |  |  *    cAA..AA       Continue at address AA..AA             SNN
 | 
      
         | 67 |  |  |  *
 | 
      
         | 68 |  |  |  *    s             Step one instruction                   SNN
 | 
      
         | 69 |  |  |  *    sAA..AA       Step one instruction from AA..AA       SNN
 | 
      
         | 70 |  |  |  *
 | 
      
         | 71 |  |  |  *    k             kill
 | 
      
         | 72 |  |  |  *
 | 
      
         | 73 |  |  |  *    ?             What was the last sigval ?             SNN   (signal NN)
 | 
      
         | 74 |  |  |  *
 | 
      
         | 75 |  |  |  * All commands and responses are sent with a packet which includes a
 | 
      
         | 76 |  |  |  * checksum.  A packet consists of
 | 
      
         | 77 |  |  |  *
 | 
      
         | 78 |  |  |  * $<packet info>#<checksum>.
 | 
      
         | 79 |  |  |  *
 | 
      
         | 80 |  |  |  * where
 | 
      
         | 81 |  |  |  * <packet info> :: <characters representing the command or response>
 | 
      
         | 82 |  |  |  * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
 | 
      
         | 83 |  |  |  *
 | 
      
         | 84 |  |  |  * When a packet is received, it is first acknowledged with either '+' or '-'.
 | 
      
         | 85 |  |  |  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
 | 
      
         | 86 |  |  |  *
 | 
      
         | 87 |  |  |  * Example:
 | 
      
         | 88 |  |  |  *
 | 
      
         | 89 |  |  |  * Host:                  Reply:
 | 
      
         | 90 |  |  |  * $m0,10#2a               +$00010203040506070809101112131415#42
 | 
      
         | 91 |  |  |  *
 | 
      
         | 92 |  |  |  ****************************************************************************/
 | 
      
         | 93 |  |  |  
 | 
      
         | 94 |  |  |  
 | 
      
         | 95 |  |  | /************************************************************************
 | 
      
         | 96 |  |  |  *
 | 
      
         | 97 |  |  |  * external low-level support routines
 | 
      
         | 98 |  |  |  */
 | 
      
         | 99 |  |  | extern void putDebugChar ();    /* write a single character      */
 | 
      
         | 100 |  |  | extern int getDebugChar ();     /* read and return a single char */
 | 
      
         | 101 |  |  | extern void exceptionHandler ();        /* assign an exception handler   */
 | 
      
         | 102 |  |  |  
 | 
      
         | 103 |  |  | /*****************************************************************************
 | 
      
         | 104 |  |  |  * BUFMAX defines the maximum number of characters in inbound/outbound buffers
 | 
      
         | 105 |  |  |  * at least NUMREGBYTES*2 are needed for register packets
 | 
      
         | 106 |  |  |  */
 | 
      
         | 107 |  |  | #define BUFMAX 400
 | 
      
         | 108 |  |  |  
 | 
      
         | 109 |  |  | static char initialized;        /* boolean flag. != 0 means we've been initialized */
 | 
      
         | 110 |  |  |  
 | 
      
         | 111 |  |  | int remote_debug;
 | 
      
         | 112 |  |  | /*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
 | 
      
         | 113 |  |  |  
 | 
      
         | 114 |  |  | static const unsigned char hexchars[] = "0123456789abcdef";
 | 
      
         | 115 |  |  |  
 | 
      
         | 116 |  |  | #define NUMREGS 24
 | 
      
         | 117 |  |  |  
 | 
      
         | 118 |  |  | /* Number of bytes of registers.  */
 | 
      
         | 119 |  |  | #define NUMREGBYTES (NUMREGS * 4)
 | 
      
         | 120 |  |  | enum regnames
 | 
      
         | 121 |  |  | { R0, R1, R2, R3, R4, R5, R6, R7,
 | 
      
         | 122 |  |  |   R8, R9, R10, R11, R12, R13, R14, R15,
 | 
      
         | 123 |  |  |   PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH
 | 
      
         | 124 |  |  | };
 | 
      
         | 125 |  |  |  
 | 
      
         | 126 |  |  | enum SYS_calls
 | 
      
         | 127 |  |  | {
 | 
      
         | 128 |  |  |   SYS_null,
 | 
      
         | 129 |  |  |   SYS_exit,
 | 
      
         | 130 |  |  |   SYS_open,
 | 
      
         | 131 |  |  |   SYS_close,
 | 
      
         | 132 |  |  |   SYS_read,
 | 
      
         | 133 |  |  |   SYS_write,
 | 
      
         | 134 |  |  |   SYS_lseek,
 | 
      
         | 135 |  |  |   SYS_unlink,
 | 
      
         | 136 |  |  |   SYS_getpid,
 | 
      
         | 137 |  |  |   SYS_kill,
 | 
      
         | 138 |  |  |   SYS_fstat,
 | 
      
         | 139 |  |  |   SYS_sbrk,
 | 
      
         | 140 |  |  |   SYS_fork,
 | 
      
         | 141 |  |  |   SYS_execve,
 | 
      
         | 142 |  |  |   SYS_wait4,
 | 
      
         | 143 |  |  |   SYS_link,
 | 
      
         | 144 |  |  |   SYS_chdir,
 | 
      
         | 145 |  |  |   SYS_stat,
 | 
      
         | 146 |  |  |   SYS_utime,
 | 
      
         | 147 |  |  |   SYS_chown,
 | 
      
         | 148 |  |  |   SYS_chmod,
 | 
      
         | 149 |  |  |   SYS_time,
 | 
      
         | 150 |  |  |   SYS_pipe
 | 
      
         | 151 |  |  | };
 | 
      
         | 152 |  |  |  
 | 
      
         | 153 |  |  | static int registers[NUMREGS];
 | 
      
         | 154 |  |  |  
 | 
      
         | 155 |  |  | #define STACKSIZE 8096
 | 
      
         | 156 |  |  | static unsigned char remcomInBuffer[BUFMAX];
 | 
      
         | 157 |  |  | static unsigned char remcomOutBuffer[BUFMAX];
 | 
      
         | 158 |  |  | static int remcomStack[STACKSIZE / sizeof (int)];
 | 
      
         | 159 |  |  | static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
 | 
      
         | 160 |  |  |  
 | 
      
         | 161 |  |  | static unsigned int save_vectors[18];   /* previous exception vectors */
 | 
      
         | 162 |  |  |  
 | 
      
         | 163 |  |  | /* Indicate to caller of mem2hex or hex2mem that there has been an error. */
 | 
      
         | 164 |  |  | static volatile int mem_err = 0;
 | 
      
         | 165 |  |  |  
 | 
      
         | 166 |  |  | /* Store the vector number here (since GDB only gets the signal
 | 
      
         | 167 |  |  |    number through the usual means, and that's not very specific).  */
 | 
      
         | 168 |  |  | int gdb_m32r_vector = -1;
 | 
      
         | 169 |  |  |  
 | 
      
         | 170 |  |  | #if 0
 | 
      
         | 171 |  |  | #include "syscall.h"            /* for SYS_exit, SYS_write etc. */
 | 
      
         | 172 |  |  | #endif
 | 
      
         | 173 |  |  |  
 | 
      
         | 174 |  |  | /* Global entry points:
 | 
      
         | 175 |  |  |  */
 | 
      
         | 176 |  |  |  
 | 
      
         | 177 |  |  | extern void handle_exception (int);
 | 
      
         | 178 |  |  | extern void set_debug_traps (void);
 | 
      
         | 179 |  |  | extern void breakpoint (void);
 | 
      
         | 180 |  |  |  
 | 
      
         | 181 |  |  | /* Local functions:
 | 
      
         | 182 |  |  |  */
 | 
      
         | 183 |  |  |  
 | 
      
         | 184 |  |  | static int computeSignal (int);
 | 
      
         | 185 |  |  | static void putpacket (unsigned char *);
 | 
      
         | 186 |  |  | static unsigned char *getpacket (void);
 | 
      
         | 187 |  |  |  
 | 
      
         | 188 |  |  | static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int);
 | 
      
         | 189 |  |  | static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int);
 | 
      
         | 190 |  |  | static int hexToInt (unsigned char **, int *);
 | 
      
         | 191 |  |  | static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int);
 | 
      
         | 192 |  |  | static void stash_registers (void);
 | 
      
         | 193 |  |  | static void restore_registers (void);
 | 
      
         | 194 |  |  | static int prepare_to_step (int);
 | 
      
         | 195 |  |  | static int finish_from_step (void);
 | 
      
         | 196 |  |  | static unsigned long crc32 (unsigned char *, int, unsigned long);
 | 
      
         | 197 |  |  |  
 | 
      
         | 198 |  |  | static void gdb_error (char *, char *);
 | 
      
         | 199 |  |  | static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int);
 | 
      
         | 200 |  |  |  
 | 
      
         | 201 |  |  | static unsigned char *strcpy (unsigned char *, const unsigned char *);
 | 
      
         | 202 |  |  | static int strlen (const unsigned char *);
 | 
      
         | 203 |  |  |  
 | 
      
         | 204 |  |  | /*
 | 
      
         | 205 |  |  |  * This function does all command procesing for interfacing to gdb.
 | 
      
         | 206 |  |  |  */
 | 
      
         | 207 |  |  |  
 | 
      
         | 208 |  |  | void
 | 
      
         | 209 |  |  | handle_exception (int exceptionVector)
 | 
      
         | 210 |  |  | {
 | 
      
         | 211 |  |  |   int sigval, stepping;
 | 
      
         | 212 |  |  |   int addr, length, i;
 | 
      
         | 213 |  |  |   unsigned char *ptr;
 | 
      
         | 214 |  |  |   unsigned char buf[16];
 | 
      
         | 215 |  |  |   int binary;
 | 
      
         | 216 |  |  |  
 | 
      
         | 217 |  |  |   if (!finish_from_step ())
 | 
      
         | 218 |  |  |     return;                     /* "false step": let the target continue */
 | 
      
         | 219 |  |  |  
 | 
      
         | 220 |  |  |   gdb_m32r_vector = exceptionVector;
 | 
      
         | 221 |  |  |  
 | 
      
         | 222 |  |  |   if (remote_debug)
 | 
      
         | 223 |  |  |     {
 | 
      
         | 224 |  |  |       mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0);
 | 
      
         | 225 |  |  |       gdb_error ("Handle exception %s, ", buf);
 | 
      
         | 226 |  |  |       mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
 | 
      
         | 227 |  |  |       gdb_error ("PC == 0x%s\n", buf);
 | 
      
         | 228 |  |  |     }
 | 
      
         | 229 |  |  |  
 | 
      
         | 230 |  |  |   /* reply to host that an exception has occurred */
 | 
      
         | 231 |  |  |   sigval = computeSignal (exceptionVector);
 | 
      
         | 232 |  |  |  
 | 
      
         | 233 |  |  |   ptr = remcomOutBuffer;
 | 
      
         | 234 |  |  |  
 | 
      
         | 235 |  |  |   *ptr++ = 'T';                 /* notify gdb with signo, PC, FP and SP */
 | 
      
         | 236 |  |  |   *ptr++ = hexchars[sigval >> 4];
 | 
      
         | 237 |  |  |   *ptr++ = hexchars[sigval & 0xf];
 | 
      
         | 238 |  |  |  
 | 
      
         | 239 |  |  |   *ptr++ = hexchars[PC >> 4];
 | 
      
         | 240 |  |  |   *ptr++ = hexchars[PC & 0xf];
 | 
      
         | 241 |  |  |   *ptr++ = ':';
 | 
      
         | 242 |  |  |   ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0);   /* PC */
 | 
      
         | 243 |  |  |   *ptr++ = ';';
 | 
      
         | 244 |  |  |  
 | 
      
         | 245 |  |  |   *ptr++ = hexchars[R13 >> 4];
 | 
      
         | 246 |  |  |   *ptr++ = hexchars[R13 & 0xf];
 | 
      
         | 247 |  |  |   *ptr++ = ':';
 | 
      
         | 248 |  |  |   ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0);  /* FP */
 | 
      
         | 249 |  |  |   *ptr++ = ';';
 | 
      
         | 250 |  |  |  
 | 
      
         | 251 |  |  |   *ptr++ = hexchars[R15 >> 4];
 | 
      
         | 252 |  |  |   *ptr++ = hexchars[R15 & 0xf];
 | 
      
         | 253 |  |  |   *ptr++ = ':';
 | 
      
         | 254 |  |  |   ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0);  /* SP */
 | 
      
         | 255 |  |  |   *ptr++ = ';';
 | 
      
         | 256 |  |  |   *ptr++ = 0;
 | 
      
         | 257 |  |  |  
 | 
      
         | 258 |  |  |   if (exceptionVector == 0)      /* simulated SYS call stuff */
 | 
      
         | 259 |  |  |     {
 | 
      
         | 260 |  |  |       mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
 | 
      
         | 261 |  |  |       switch (registers[R0])
 | 
      
         | 262 |  |  |         {
 | 
      
         | 263 |  |  |         case SYS_exit:
 | 
      
         | 264 |  |  |           gdb_error ("Target program has exited at %s\n", buf);
 | 
      
         | 265 |  |  |           ptr = remcomOutBuffer;
 | 
      
         | 266 |  |  |           *ptr++ = 'W';
 | 
      
         | 267 |  |  |           sigval = registers[R1] & 0xff;
 | 
      
         | 268 |  |  |           *ptr++ = hexchars[sigval >> 4];
 | 
      
         | 269 |  |  |           *ptr++ = hexchars[sigval & 0xf];
 | 
      
         | 270 |  |  |           *ptr++ = 0;
 | 
      
         | 271 |  |  |           break;
 | 
      
         | 272 |  |  |         case SYS_open:
 | 
      
         | 273 |  |  |           gdb_error ("Target attempts SYS_open call at %s\n", buf);
 | 
      
         | 274 |  |  |           break;
 | 
      
         | 275 |  |  |         case SYS_close:
 | 
      
         | 276 |  |  |           gdb_error ("Target attempts SYS_close call at %s\n", buf);
 | 
      
         | 277 |  |  |           break;
 | 
      
         | 278 |  |  |         case SYS_read:
 | 
      
         | 279 |  |  |           gdb_error ("Target attempts SYS_read call at %s\n", buf);
 | 
      
         | 280 |  |  |           break;
 | 
      
         | 281 |  |  |         case SYS_write:
 | 
      
         | 282 |  |  |           if (registers[R1] == 1 ||     /* write to stdout  */
 | 
      
         | 283 |  |  |               registers[R1] == 2)       /* write to stderr  */
 | 
      
         | 284 |  |  |             {                   /* (we can do that) */
 | 
      
         | 285 |  |  |               registers[R0] =
 | 
      
         | 286 |  |  |                 gdb_write ((void *) registers[R2], registers[R3]);
 | 
      
         | 287 |  |  |               return;
 | 
      
         | 288 |  |  |             }
 | 
      
         | 289 |  |  |           else
 | 
      
         | 290 |  |  |             gdb_error ("Target attempts SYS_write call at %s\n", buf);
 | 
      
         | 291 |  |  |           break;
 | 
      
         | 292 |  |  |         case SYS_lseek:
 | 
      
         | 293 |  |  |           gdb_error ("Target attempts SYS_lseek call at %s\n", buf);
 | 
      
         | 294 |  |  |           break;
 | 
      
         | 295 |  |  |         case SYS_unlink:
 | 
      
         | 296 |  |  |           gdb_error ("Target attempts SYS_unlink call at %s\n", buf);
 | 
      
         | 297 |  |  |           break;
 | 
      
         | 298 |  |  |         case SYS_getpid:
 | 
      
         | 299 |  |  |           gdb_error ("Target attempts SYS_getpid call at %s\n", buf);
 | 
      
         | 300 |  |  |           break;
 | 
      
         | 301 |  |  |         case SYS_kill:
 | 
      
         | 302 |  |  |           gdb_error ("Target attempts SYS_kill call at %s\n", buf);
 | 
      
         | 303 |  |  |           break;
 | 
      
         | 304 |  |  |         case SYS_fstat:
 | 
      
         | 305 |  |  |           gdb_error ("Target attempts SYS_fstat call at %s\n", buf);
 | 
      
         | 306 |  |  |           break;
 | 
      
         | 307 |  |  |         default:
 | 
      
         | 308 |  |  |           gdb_error ("Target attempts unknown SYS call at %s\n", buf);
 | 
      
         | 309 |  |  |           break;
 | 
      
         | 310 |  |  |         }
 | 
      
         | 311 |  |  |     }
 | 
      
         | 312 |  |  |  
 | 
      
         | 313 |  |  |   putpacket (remcomOutBuffer);
 | 
      
         | 314 |  |  |  
 | 
      
         | 315 |  |  |   stepping = 0;
 | 
      
         | 316 |  |  |  
 | 
      
         | 317 |  |  |   while (1 == 1)
 | 
      
         | 318 |  |  |     {
 | 
      
         | 319 |  |  |       remcomOutBuffer[0] = 0;
 | 
      
         | 320 |  |  |       ptr = getpacket ();
 | 
      
         | 321 |  |  |       binary = 0;
 | 
      
         | 322 |  |  |       switch (*ptr++)
 | 
      
         | 323 |  |  |         {
 | 
      
         | 324 |  |  |         default:                /* Unknown code.  Return an empty reply message. */
 | 
      
         | 325 |  |  |           break;
 | 
      
         | 326 |  |  |         case 'R':
 | 
      
         | 327 |  |  |           if (hexToInt (&ptr, &addr))
 | 
      
         | 328 |  |  |             registers[PC] = addr;
 | 
      
         | 329 |  |  |           strcpy (remcomOutBuffer, "OK");
 | 
      
         | 330 |  |  |           break;
 | 
      
         | 331 |  |  |         case '!':
 | 
      
         | 332 |  |  |           strcpy (remcomOutBuffer, "OK");
 | 
      
         | 333 |  |  |           break;
 | 
      
         | 334 |  |  |         case 'X':               /* XAA..AA,LLLL:<binary data>#cs */
 | 
      
         | 335 |  |  |           binary = 1;
 | 
      
         | 336 |  |  |         case 'M':               /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
 | 
      
         | 337 |  |  |           /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
 | 
      
         | 338 |  |  |           {
 | 
      
         | 339 |  |  |             if (hexToInt (&ptr, &addr))
 | 
      
         | 340 |  |  |               if (*(ptr++) == ',')
 | 
      
         | 341 |  |  |                 if (hexToInt (&ptr, &length))
 | 
      
         | 342 |  |  |                   if (*(ptr++) == ':')
 | 
      
         | 343 |  |  |                     {
 | 
      
         | 344 |  |  |                       mem_err = 0;
 | 
      
         | 345 |  |  |                       if (binary)
 | 
      
         | 346 |  |  |                         bin2mem (ptr, (unsigned char *) addr, length, 1);
 | 
      
         | 347 |  |  |                       else
 | 
      
         | 348 |  |  |                         hex2mem (ptr, (unsigned char *) addr, length, 1);
 | 
      
         | 349 |  |  |                       if (mem_err)
 | 
      
         | 350 |  |  |                         {
 | 
      
         | 351 |  |  |                           strcpy (remcomOutBuffer, "E03");
 | 
      
         | 352 |  |  |                           gdb_error ("memory fault", "");
 | 
      
         | 353 |  |  |                         }
 | 
      
         | 354 |  |  |                       else
 | 
      
         | 355 |  |  |                         {
 | 
      
         | 356 |  |  |                           strcpy (remcomOutBuffer, "OK");
 | 
      
         | 357 |  |  |                         }
 | 
      
         | 358 |  |  |                       ptr = 0;
 | 
      
         | 359 |  |  |                     }
 | 
      
         | 360 |  |  |             if (ptr)
 | 
      
         | 361 |  |  |               {
 | 
      
         | 362 |  |  |                 strcpy (remcomOutBuffer, "E02");
 | 
      
         | 363 |  |  |               }
 | 
      
         | 364 |  |  |           }
 | 
      
         | 365 |  |  |           break;
 | 
      
         | 366 |  |  |         case 'm':               /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
 | 
      
         | 367 |  |  |           /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
 | 
      
         | 368 |  |  |           if (hexToInt (&ptr, &addr))
 | 
      
         | 369 |  |  |             if (*(ptr++) == ',')
 | 
      
         | 370 |  |  |               if (hexToInt (&ptr, &length))
 | 
      
         | 371 |  |  |                 {
 | 
      
         | 372 |  |  |                   ptr = 0;
 | 
      
         | 373 |  |  |                   mem_err = 0;
 | 
      
         | 374 |  |  |                   mem2hex ((unsigned char *) addr, remcomOutBuffer, length,
 | 
      
         | 375 |  |  |                            1);
 | 
      
         | 376 |  |  |                   if (mem_err)
 | 
      
         | 377 |  |  |                     {
 | 
      
         | 378 |  |  |                       strcpy (remcomOutBuffer, "E03");
 | 
      
         | 379 |  |  |                       gdb_error ("memory fault", "");
 | 
      
         | 380 |  |  |                     }
 | 
      
         | 381 |  |  |                 }
 | 
      
         | 382 |  |  |           if (ptr)
 | 
      
         | 383 |  |  |             {
 | 
      
         | 384 |  |  |               strcpy (remcomOutBuffer, "E01");
 | 
      
         | 385 |  |  |             }
 | 
      
         | 386 |  |  |           break;
 | 
      
         | 387 |  |  |         case '?':
 | 
      
         | 388 |  |  |           remcomOutBuffer[0] = 'S';
 | 
      
         | 389 |  |  |           remcomOutBuffer[1] = hexchars[sigval >> 4];
 | 
      
         | 390 |  |  |           remcomOutBuffer[2] = hexchars[sigval % 16];
 | 
      
         | 391 |  |  |           remcomOutBuffer[3] = 0;
 | 
      
         | 392 |  |  |           break;
 | 
      
         | 393 |  |  |         case 'd':
 | 
      
         | 394 |  |  |           remote_debug = !(remote_debug);       /* toggle debug flag */
 | 
      
         | 395 |  |  |           break;
 | 
      
         | 396 |  |  |         case 'g':               /* return the value of the CPU registers */
 | 
      
         | 397 |  |  |           mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES,
 | 
      
         | 398 |  |  |                    0);
 | 
      
         | 399 |  |  |           break;
 | 
      
         | 400 |  |  |         case 'P':               /* set the value of a single CPU register - return OK */
 | 
      
         | 401 |  |  |           {
 | 
      
         | 402 |  |  |             int regno;
 | 
      
         | 403 |  |  |  
 | 
      
         | 404 |  |  |             if (hexToInt (&ptr, ®no) && *ptr++ == '=')
 | 
      
         | 405 |  |  |               if (regno >= 0 && regno < NUMREGS)
 | 
      
         | 406 |  |  |                 {
 | 
      
         | 407 |  |  |                   int stackmode;
 | 
      
         | 408 |  |  |  
 | 
      
         | 409 |  |  |                   hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0);
 | 
      
         | 410 |  |  |                   /*
 | 
      
         | 411 |  |  |                    * Since we just changed a single CPU register, let's
 | 
      
         | 412 |  |  |                    * make sure to keep the several stack pointers consistant.
 | 
      
         | 413 |  |  |                    */
 | 
      
         | 414 |  |  |                   stackmode = registers[PSW] & 0x80;
 | 
      
         | 415 |  |  |                   if (regno == R15)     /* stack pointer changed */
 | 
      
         | 416 |  |  |                     {           /* need to change SPI or SPU */
 | 
      
         | 417 |  |  |                       if (stackmode == 0)
 | 
      
         | 418 |  |  |                         registers[SPI] = registers[R15];
 | 
      
         | 419 |  |  |                       else
 | 
      
         | 420 |  |  |                         registers[SPU] = registers[R15];
 | 
      
         | 421 |  |  |                     }
 | 
      
         | 422 |  |  |                   else if (regno == SPU)        /* "user" stack pointer changed */
 | 
      
         | 423 |  |  |                     {
 | 
      
         | 424 |  |  |                       if (stackmode != 0)        /* stack in user mode: copy SP */
 | 
      
         | 425 |  |  |                         registers[R15] = registers[SPU];
 | 
      
         | 426 |  |  |                     }
 | 
      
         | 427 |  |  |                   else if (regno == SPI)        /* "interrupt" stack pointer changed */
 | 
      
         | 428 |  |  |                     {
 | 
      
         | 429 |  |  |                       if (stackmode == 0)        /* stack in interrupt mode: copy SP */
 | 
      
         | 430 |  |  |                         registers[R15] = registers[SPI];
 | 
      
         | 431 |  |  |                     }
 | 
      
         | 432 |  |  |                   else if (regno == PSW)        /* stack mode may have changed! */
 | 
      
         | 433 |  |  |                     {           /* force SP to either SPU or SPI */
 | 
      
         | 434 |  |  |                       if (stackmode == 0)        /* stack in user mode */
 | 
      
         | 435 |  |  |                         registers[R15] = registers[SPI];
 | 
      
         | 436 |  |  |                       else      /* stack in interrupt mode */
 | 
      
         | 437 |  |  |                         registers[R15] = registers[SPU];
 | 
      
         | 438 |  |  |                     }
 | 
      
         | 439 |  |  |                   strcpy (remcomOutBuffer, "OK");
 | 
      
         | 440 |  |  |                   break;
 | 
      
         | 441 |  |  |                 }
 | 
      
         | 442 |  |  |             strcpy (remcomOutBuffer, "E01");
 | 
      
         | 443 |  |  |             break;
 | 
      
         | 444 |  |  |           }
 | 
      
         | 445 |  |  |         case 'G':               /* set the value of the CPU registers - return OK */
 | 
      
         | 446 |  |  |           hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0);
 | 
      
         | 447 |  |  |           strcpy (remcomOutBuffer, "OK");
 | 
      
         | 448 |  |  |           break;
 | 
      
         | 449 |  |  |         case 's':               /* sAA..AA      Step one instruction from AA..AA(optional) */
 | 
      
         | 450 |  |  |           stepping = 1;
 | 
      
         | 451 |  |  |         case 'c':               /* cAA..AA      Continue from address AA..AA(optional) */
 | 
      
         | 452 |  |  |           /* try to read optional parameter, pc unchanged if no parm */
 | 
      
         | 453 |  |  |           if (hexToInt (&ptr, &addr))
 | 
      
         | 454 |  |  |             registers[PC] = addr;
 | 
      
         | 455 |  |  |  
 | 
      
         | 456 |  |  |           if (stepping)         /* single-stepping */
 | 
      
         | 457 |  |  |             {
 | 
      
         | 458 |  |  |               if (!prepare_to_step (0))  /* set up for single-step */
 | 
      
         | 459 |  |  |                 {
 | 
      
         | 460 |  |  |                   /* prepare_to_step has already emulated the target insn:
 | 
      
         | 461 |  |  |                      Send SIGTRAP to gdb, don't resume the target at all.  */
 | 
      
         | 462 |  |  |                   ptr = remcomOutBuffer;
 | 
      
         | 463 |  |  |                   *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */
 | 
      
         | 464 |  |  |                   *ptr++ = '0';
 | 
      
         | 465 |  |  |                   *ptr++ = '5';
 | 
      
         | 466 |  |  |  
 | 
      
         | 467 |  |  |                   *ptr++ = hexchars[PC >> 4];   /* send PC */
 | 
      
         | 468 |  |  |                   *ptr++ = hexchars[PC & 0xf];
 | 
      
         | 469 |  |  |                   *ptr++ = ':';
 | 
      
         | 470 |  |  |                   ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0);
 | 
      
         | 471 |  |  |                   *ptr++ = ';';
 | 
      
         | 472 |  |  |  
 | 
      
         | 473 |  |  |                   *ptr++ = hexchars[R13 >> 4];  /* send FP */
 | 
      
         | 474 |  |  |                   *ptr++ = hexchars[R13 & 0xf];
 | 
      
         | 475 |  |  |                   *ptr++ = ':';
 | 
      
         | 476 |  |  |                   ptr =
 | 
      
         | 477 |  |  |                     mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0);
 | 
      
         | 478 |  |  |                   *ptr++ = ';';
 | 
      
         | 479 |  |  |  
 | 
      
         | 480 |  |  |                   *ptr++ = hexchars[R15 >> 4];  /* send SP */
 | 
      
         | 481 |  |  |                   *ptr++ = hexchars[R15 & 0xf];
 | 
      
         | 482 |  |  |                   *ptr++ = ':';
 | 
      
         | 483 |  |  |                   ptr =
 | 
      
         | 484 |  |  |                     mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0);
 | 
      
         | 485 |  |  |                   *ptr++ = ';';
 | 
      
         | 486 |  |  |                   *ptr++ = 0;
 | 
      
         | 487 |  |  |  
 | 
      
         | 488 |  |  |                   break;
 | 
      
         | 489 |  |  |                 }
 | 
      
         | 490 |  |  |             }
 | 
      
         | 491 |  |  |           else                  /* continuing, not single-stepping */
 | 
      
         | 492 |  |  |             {
 | 
      
         | 493 |  |  |               /* OK, about to do a "continue".  First check to see if the
 | 
      
         | 494 |  |  |                  target pc is on an odd boundary (second instruction in the
 | 
      
         | 495 |  |  |                  word).  If so, we must do a single-step first, because
 | 
      
         | 496 |  |  |                  ya can't jump or return back to an odd boundary!  */
 | 
      
         | 497 |  |  |               if ((registers[PC] & 2) != 0)
 | 
      
         | 498 |  |  |                 prepare_to_step (1);
 | 
      
         | 499 |  |  |             }
 | 
      
         | 500 |  |  |  
 | 
      
         | 501 |  |  |           return;
 | 
      
         | 502 |  |  |  
 | 
      
         | 503 |  |  |         case 'D':               /* Detach */
 | 
      
         | 504 |  |  | #if 0
 | 
      
         | 505 |  |  |           /* I am interpreting this to mean, release the board from control
 | 
      
         | 506 |  |  |              by the remote stub.  To do this, I am restoring the original
 | 
      
         | 507 |  |  |              (or at least previous) exception vectors.
 | 
      
         | 508 |  |  |            */
 | 
      
         | 509 |  |  |           for (i = 0; i < 18; i++)
 | 
      
         | 510 |  |  |             exceptionHandler (i, save_vectors[i]);
 | 
      
         | 511 |  |  |           putpacket ("OK");
 | 
      
         | 512 |  |  |           return;               /* continue the inferior */
 | 
      
         | 513 |  |  | #else
 | 
      
         | 514 |  |  |           strcpy (remcomOutBuffer, "OK");
 | 
      
         | 515 |  |  |           break;
 | 
      
         | 516 |  |  | #endif
 | 
      
         | 517 |  |  |         case 'q':
 | 
      
         | 518 |  |  |           if (*ptr++ == 'C' &&
 | 
      
         | 519 |  |  |               *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':')
 | 
      
         | 520 |  |  |             {
 | 
      
         | 521 |  |  |               unsigned long start, len, our_crc;
 | 
      
         | 522 |  |  |  
 | 
      
         | 523 |  |  |               if (hexToInt (&ptr, (int *) &start) &&
 | 
      
         | 524 |  |  |                   *ptr++ == ',' && hexToInt (&ptr, (int *) &len))
 | 
      
         | 525 |  |  |                 {
 | 
      
         | 526 |  |  |                   remcomOutBuffer[0] = 'C';
 | 
      
         | 527 |  |  |                   our_crc = crc32 ((unsigned char *) start, len, 0xffffffff);
 | 
      
         | 528 |  |  |                   mem2hex ((char *) &our_crc,
 | 
      
         | 529 |  |  |                            &remcomOutBuffer[1], sizeof (long), 0);
 | 
      
         | 530 |  |  |                 }               /* else do nothing */
 | 
      
         | 531 |  |  |             }                   /* else do nothing */
 | 
      
         | 532 |  |  |           break;
 | 
      
         | 533 |  |  |  
 | 
      
         | 534 |  |  |         case 'k':               /* kill the program */
 | 
      
         | 535 |  |  |           continue;
 | 
      
         | 536 |  |  |         }                       /* switch */
 | 
      
         | 537 |  |  |  
 | 
      
         | 538 |  |  |       /* reply to the request */
 | 
      
         | 539 |  |  |       putpacket (remcomOutBuffer);
 | 
      
         | 540 |  |  |     }
 | 
      
         | 541 |  |  | }
 | 
      
         | 542 |  |  |  
 | 
      
         | 543 |  |  | /* qCRC support */
 | 
      
         | 544 |  |  |  
 | 
      
         | 545 |  |  | /* Table used by the crc32 function to calcuate the checksum. */
 | 
      
         | 546 |  |  | static unsigned long crc32_table[256] = { 0, 0 };
 | 
      
         | 547 |  |  |  
 | 
      
         | 548 |  |  | static unsigned long
 | 
      
         | 549 |  |  | crc32 (unsigned char *buf, int len, unsigned long crc)
 | 
      
         | 550 |  |  | {
 | 
      
         | 551 |  |  |   if (!crc32_table[1])
 | 
      
         | 552 |  |  |     {
 | 
      
         | 553 |  |  |       /* Initialize the CRC table and the decoding table. */
 | 
      
         | 554 |  |  |       int i, j;
 | 
      
         | 555 |  |  |       unsigned long c;
 | 
      
         | 556 |  |  |  
 | 
      
         | 557 |  |  |       for (i = 0; i < 256; i++)
 | 
      
         | 558 |  |  |         {
 | 
      
         | 559 |  |  |           for (c = i << 24, j = 8; j > 0; --j)
 | 
      
         | 560 |  |  |             c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
 | 
      
         | 561 |  |  |           crc32_table[i] = c;
 | 
      
         | 562 |  |  |         }
 | 
      
         | 563 |  |  |     }
 | 
      
         | 564 |  |  |  
 | 
      
         | 565 |  |  |   while (len--)
 | 
      
         | 566 |  |  |     {
 | 
      
         | 567 |  |  |       crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
 | 
      
         | 568 |  |  |       buf++;
 | 
      
         | 569 |  |  |     }
 | 
      
         | 570 |  |  |   return crc;
 | 
      
         | 571 |  |  | }
 | 
      
         | 572 |  |  |  
 | 
      
         | 573 |  |  | static int
 | 
      
         | 574 |  |  | hex (unsigned char ch)
 | 
      
         | 575 |  |  | {
 | 
      
         | 576 |  |  |   if ((ch >= 'a') && (ch <= 'f'))
 | 
      
         | 577 |  |  |     return (ch - 'a' + 10);
 | 
      
         | 578 |  |  |   if ((ch >= '0') && (ch <= '9'))
 | 
      
         | 579 |  |  |     return (ch - '0');
 | 
      
         | 580 |  |  |   if ((ch >= 'A') && (ch <= 'F'))
 | 
      
         | 581 |  |  |     return (ch - 'A' + 10);
 | 
      
         | 582 |  |  |   return (-1);
 | 
      
         | 583 |  |  | }
 | 
      
         | 584 |  |  |  
 | 
      
         | 585 |  |  | /* scan for the sequence $<data>#<checksum>     */
 | 
      
         | 586 |  |  |  
 | 
      
         | 587 |  |  | unsigned char *
 | 
      
         | 588 |  |  | getpacket (void)
 | 
      
         | 589 |  |  | {
 | 
      
         | 590 |  |  |   unsigned char *buffer = &remcomInBuffer[0];
 | 
      
         | 591 |  |  |   unsigned char checksum;
 | 
      
         | 592 |  |  |   unsigned char xmitcsum;
 | 
      
         | 593 |  |  |   int count;
 | 
      
         | 594 |  |  |   char ch;
 | 
      
         | 595 |  |  |  
 | 
      
         | 596 |  |  |   while (1)
 | 
      
         | 597 |  |  |     {
 | 
      
         | 598 |  |  |       /* wait around for the start character, ignore all other characters */
 | 
      
         | 599 |  |  |       while ((ch = getDebugChar ()) != '$')
 | 
      
         | 600 |  |  |         ;
 | 
      
         | 601 |  |  |  
 | 
      
         | 602 |  |  |     retry:
 | 
      
         | 603 |  |  |       checksum = 0;
 | 
      
         | 604 |  |  |       xmitcsum = -1;
 | 
      
         | 605 |  |  |       count = 0;
 | 
      
         | 606 |  |  |  
 | 
      
         | 607 |  |  |       /* now, read until a # or end of buffer is found */
 | 
      
         | 608 |  |  |       while (count < BUFMAX - 1)
 | 
      
         | 609 |  |  |         {
 | 
      
         | 610 |  |  |           ch = getDebugChar ();
 | 
      
         | 611 |  |  |           if (ch == '$')
 | 
      
         | 612 |  |  |             goto retry;
 | 
      
         | 613 |  |  |           if (ch == '#')
 | 
      
         | 614 |  |  |             break;
 | 
      
         | 615 |  |  |           checksum = checksum + ch;
 | 
      
         | 616 |  |  |           buffer[count] = ch;
 | 
      
         | 617 |  |  |           count = count + 1;
 | 
      
         | 618 |  |  |         }
 | 
      
         | 619 |  |  |       buffer[count] = 0;
 | 
      
         | 620 |  |  |  
 | 
      
         | 621 |  |  |       if (ch == '#')
 | 
      
         | 622 |  |  |         {
 | 
      
         | 623 |  |  |           ch = getDebugChar ();
 | 
      
         | 624 |  |  |           xmitcsum = hex (ch) << 4;
 | 
      
         | 625 |  |  |           ch = getDebugChar ();
 | 
      
         | 626 |  |  |           xmitcsum += hex (ch);
 | 
      
         | 627 |  |  |  
 | 
      
         | 628 |  |  |           if (checksum != xmitcsum)
 | 
      
         | 629 |  |  |             {
 | 
      
         | 630 |  |  |               if (remote_debug)
 | 
      
         | 631 |  |  |                 {
 | 
      
         | 632 |  |  |                   unsigned char buf[16];
 | 
      
         | 633 |  |  |  
 | 
      
         | 634 |  |  |                   mem2hex ((unsigned char *) &checksum, buf, 4, 0);
 | 
      
         | 635 |  |  |                   gdb_error ("Bad checksum: my count = %s, ", buf);
 | 
      
         | 636 |  |  |                   mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0);
 | 
      
         | 637 |  |  |                   gdb_error ("sent count = %s\n", buf);
 | 
      
         | 638 |  |  |                   gdb_error (" -- Bad buffer: \"%s\"\n", buffer);
 | 
      
         | 639 |  |  |                 }
 | 
      
         | 640 |  |  |               putDebugChar ('-');       /* failed checksum */
 | 
      
         | 641 |  |  |             }
 | 
      
         | 642 |  |  |           else
 | 
      
         | 643 |  |  |             {
 | 
      
         | 644 |  |  |               putDebugChar ('+');       /* successful transfer */
 | 
      
         | 645 |  |  |  
 | 
      
         | 646 |  |  |               /* if a sequence char is present, reply the sequence ID */
 | 
      
         | 647 |  |  |               if (buffer[2] == ':')
 | 
      
         | 648 |  |  |                 {
 | 
      
         | 649 |  |  |                   putDebugChar (buffer[0]);
 | 
      
         | 650 |  |  |                   putDebugChar (buffer[1]);
 | 
      
         | 651 |  |  |  
 | 
      
         | 652 |  |  |                   return &buffer[3];
 | 
      
         | 653 |  |  |                 }
 | 
      
         | 654 |  |  |  
 | 
      
         | 655 |  |  |               return &buffer[0];
 | 
      
         | 656 |  |  |             }
 | 
      
         | 657 |  |  |         }
 | 
      
         | 658 |  |  |     }
 | 
      
         | 659 |  |  | }
 | 
      
         | 660 |  |  |  
 | 
      
         | 661 |  |  | /* send the packet in buffer.  */
 | 
      
         | 662 |  |  |  
 | 
      
         | 663 |  |  | static void
 | 
      
         | 664 |  |  | putpacket (unsigned char *buffer)
 | 
      
         | 665 |  |  | {
 | 
      
         | 666 |  |  |   unsigned char checksum;
 | 
      
         | 667 |  |  |   int count;
 | 
      
         | 668 |  |  |   char ch;
 | 
      
         | 669 |  |  |  
 | 
      
         | 670 |  |  |   /*  $<packet info>#<checksum>. */
 | 
      
         | 671 |  |  |   do
 | 
      
         | 672 |  |  |     {
 | 
      
         | 673 |  |  |       putDebugChar ('$');
 | 
      
         | 674 |  |  |       checksum = 0;
 | 
      
         | 675 |  |  |       count = 0;
 | 
      
         | 676 |  |  |  
 | 
      
         | 677 |  |  |       while (ch = buffer[count])
 | 
      
         | 678 |  |  |         {
 | 
      
         | 679 |  |  |           putDebugChar (ch);
 | 
      
         | 680 |  |  |           checksum += ch;
 | 
      
         | 681 |  |  |           count += 1;
 | 
      
         | 682 |  |  |         }
 | 
      
         | 683 |  |  |       putDebugChar ('#');
 | 
      
         | 684 |  |  |       putDebugChar (hexchars[checksum >> 4]);
 | 
      
         | 685 |  |  |       putDebugChar (hexchars[checksum % 16]);
 | 
      
         | 686 |  |  |     }
 | 
      
         | 687 |  |  |   while (getDebugChar () != '+');
 | 
      
         | 688 |  |  | }
 | 
      
         | 689 |  |  |  
 | 
      
         | 690 |  |  | /* Address of a routine to RTE to if we get a memory fault.  */
 | 
      
         | 691 |  |  |  
 | 
      
         | 692 |  |  | static void (*volatile mem_fault_routine) () = 0;
 | 
      
         | 693 |  |  |  
 | 
      
         | 694 |  |  | static void
 | 
      
         | 695 |  |  | set_mem_err (void)
 | 
      
         | 696 |  |  | {
 | 
      
         | 697 |  |  |   mem_err = 1;
 | 
      
         | 698 |  |  | }
 | 
      
         | 699 |  |  |  
 | 
      
         | 700 |  |  | /* Check the address for safe access ranges.  As currently defined,
 | 
      
         | 701 |  |  |    this routine will reject the "expansion bus" address range(s).
 | 
      
         | 702 |  |  |    To make those ranges useable, someone must implement code to detect
 | 
      
         | 703 |  |  |    whether there's anything connected to the expansion bus. */
 | 
      
         | 704 |  |  |  
 | 
      
         | 705 |  |  | static int
 | 
      
         | 706 |  |  | mem_safe (unsigned char *addr)
 | 
      
         | 707 |  |  | {
 | 
      
         | 708 |  |  | #define BAD_RANGE_ONE_START     ((unsigned char *) 0x600000)
 | 
      
         | 709 |  |  | #define BAD_RANGE_ONE_END       ((unsigned char *) 0xa00000)
 | 
      
         | 710 |  |  | #define BAD_RANGE_TWO_START     ((unsigned char *) 0xff680000)
 | 
      
         | 711 |  |  | #define BAD_RANGE_TWO_END       ((unsigned char *) 0xff800000)
 | 
      
         | 712 |  |  |  
 | 
      
         | 713 |  |  |   if (addr < BAD_RANGE_ONE_START)
 | 
      
         | 714 |  |  |     return 1;                   /* safe */
 | 
      
         | 715 |  |  |   if (addr < BAD_RANGE_ONE_END)
 | 
      
         | 716 |  |  |     return 0;                    /* unsafe */
 | 
      
         | 717 |  |  |   if (addr < BAD_RANGE_TWO_START)
 | 
      
         | 718 |  |  |     return 1;                   /* safe */
 | 
      
         | 719 |  |  |   if (addr < BAD_RANGE_TWO_END)
 | 
      
         | 720 |  |  |     return 0;                    /* unsafe */
 | 
      
         | 721 |  |  | }
 | 
      
         | 722 |  |  |  
 | 
      
         | 723 |  |  | /* These are separate functions so that they are so short and sweet
 | 
      
         | 724 |  |  |    that the compiler won't save any registers (if there is a fault
 | 
      
         | 725 |  |  |    to mem_fault, they won't get restored, so there better not be any
 | 
      
         | 726 |  |  |    saved).  */
 | 
      
         | 727 |  |  | static int
 | 
      
         | 728 |  |  | get_char (unsigned char *addr)
 | 
      
         | 729 |  |  | {
 | 
      
         | 730 |  |  | #if 1
 | 
      
         | 731 |  |  |   if (mem_fault_routine && !mem_safe (addr))
 | 
      
         | 732 |  |  |     {
 | 
      
         | 733 |  |  |       mem_fault_routine ();
 | 
      
         | 734 |  |  |       return 0;
 | 
      
         | 735 |  |  |     }
 | 
      
         | 736 |  |  | #endif
 | 
      
         | 737 |  |  |   return *addr;
 | 
      
         | 738 |  |  | }
 | 
      
         | 739 |  |  |  
 | 
      
         | 740 |  |  | static void
 | 
      
         | 741 |  |  | set_char (unsigned char *addr, unsigned char val)
 | 
      
         | 742 |  |  | {
 | 
      
         | 743 |  |  | #if 1
 | 
      
         | 744 |  |  |   if (mem_fault_routine && !mem_safe (addr))
 | 
      
         | 745 |  |  |     {
 | 
      
         | 746 |  |  |       mem_fault_routine ();
 | 
      
         | 747 |  |  |       return;
 | 
      
         | 748 |  |  |     }
 | 
      
         | 749 |  |  | #endif
 | 
      
         | 750 |  |  |   *addr = val;
 | 
      
         | 751 |  |  | }
 | 
      
         | 752 |  |  |  
 | 
      
         | 753 |  |  | /* Convert the memory pointed to by mem into hex, placing result in buf.
 | 
      
         | 754 |  |  |    Return a pointer to the last char put in buf (null).
 | 
      
         | 755 |  |  |    If MAY_FAULT is non-zero, then we should set mem_err in response to
 | 
      
         | 756 |  |  |    a fault; if zero treat a fault like any other fault in the stub.  */
 | 
      
         | 757 |  |  |  
 | 
      
         | 758 |  |  | static unsigned char *
 | 
      
         | 759 |  |  | mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
 | 
      
         | 760 |  |  | {
 | 
      
         | 761 |  |  |   int i;
 | 
      
         | 762 |  |  |   unsigned char ch;
 | 
      
         | 763 |  |  |  
 | 
      
         | 764 |  |  |   if (may_fault)
 | 
      
         | 765 |  |  |     mem_fault_routine = set_mem_err;
 | 
      
         | 766 |  |  |   for (i = 0; i < count; i++)
 | 
      
         | 767 |  |  |     {
 | 
      
         | 768 |  |  |       ch = get_char (mem++);
 | 
      
         | 769 |  |  |       if (may_fault && mem_err)
 | 
      
         | 770 |  |  |         return (buf);
 | 
      
         | 771 |  |  |       *buf++ = hexchars[ch >> 4];
 | 
      
         | 772 |  |  |       *buf++ = hexchars[ch % 16];
 | 
      
         | 773 |  |  |     }
 | 
      
         | 774 |  |  |   *buf = 0;
 | 
      
         | 775 |  |  |   if (may_fault)
 | 
      
         | 776 |  |  |     mem_fault_routine = 0;
 | 
      
         | 777 |  |  |   return (buf);
 | 
      
         | 778 |  |  | }
 | 
      
         | 779 |  |  |  
 | 
      
         | 780 |  |  | /* Convert the hex array pointed to by buf into binary to be placed in mem.
 | 
      
         | 781 |  |  |    Return a pointer to the character AFTER the last byte written. */
 | 
      
         | 782 |  |  |  
 | 
      
         | 783 |  |  | static unsigned char *
 | 
      
         | 784 |  |  | hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
 | 
      
         | 785 |  |  | {
 | 
      
         | 786 |  |  |   int i;
 | 
      
         | 787 |  |  |   unsigned char ch;
 | 
      
         | 788 |  |  |  
 | 
      
         | 789 |  |  |   if (may_fault)
 | 
      
         | 790 |  |  |     mem_fault_routine = set_mem_err;
 | 
      
         | 791 |  |  |   for (i = 0; i < count; i++)
 | 
      
         | 792 |  |  |     {
 | 
      
         | 793 |  |  |       ch = hex (*buf++) << 4;
 | 
      
         | 794 |  |  |       ch = ch + hex (*buf++);
 | 
      
         | 795 |  |  |       set_char (mem++, ch);
 | 
      
         | 796 |  |  |       if (may_fault && mem_err)
 | 
      
         | 797 |  |  |         return (mem);
 | 
      
         | 798 |  |  |     }
 | 
      
         | 799 |  |  |   if (may_fault)
 | 
      
         | 800 |  |  |     mem_fault_routine = 0;
 | 
      
         | 801 |  |  |   return (mem);
 | 
      
         | 802 |  |  | }
 | 
      
         | 803 |  |  |  
 | 
      
         | 804 |  |  | /* Convert the binary stream in BUF to memory.
 | 
      
         | 805 |  |  |  
 | 
      
         | 806 |  |  |    Gdb will escape $, #, and the escape char (0x7d).
 | 
      
         | 807 |  |  |    COUNT is the total number of bytes to write into
 | 
      
         | 808 |  |  |    memory. */
 | 
      
         | 809 |  |  | static unsigned char *
 | 
      
         | 810 |  |  | bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
 | 
      
         | 811 |  |  | {
 | 
      
         | 812 |  |  |   int i;
 | 
      
         | 813 |  |  |   unsigned char ch;
 | 
      
         | 814 |  |  |  
 | 
      
         | 815 |  |  |   if (may_fault)
 | 
      
         | 816 |  |  |     mem_fault_routine = set_mem_err;
 | 
      
         | 817 |  |  |   for (i = 0; i < count; i++)
 | 
      
         | 818 |  |  |     {
 | 
      
         | 819 |  |  |       /* Check for any escaped characters. Be paranoid and
 | 
      
         | 820 |  |  |          only unescape chars that should be escaped. */
 | 
      
         | 821 |  |  |       if (*buf == 0x7d)
 | 
      
         | 822 |  |  |         {
 | 
      
         | 823 |  |  |           switch (*(buf + 1))
 | 
      
         | 824 |  |  |             {
 | 
      
         | 825 |  |  |             case 0x3:           /* # */
 | 
      
         | 826 |  |  |             case 0x4:           /* $ */
 | 
      
         | 827 |  |  |             case 0x5d:          /* escape char */
 | 
      
         | 828 |  |  |               buf++;
 | 
      
         | 829 |  |  |               *buf |= 0x20;
 | 
      
         | 830 |  |  |               break;
 | 
      
         | 831 |  |  |             default:
 | 
      
         | 832 |  |  |               /* nothing */
 | 
      
         | 833 |  |  |               break;
 | 
      
         | 834 |  |  |             }
 | 
      
         | 835 |  |  |         }
 | 
      
         | 836 |  |  |  
 | 
      
         | 837 |  |  |       set_char (mem++, *buf++);
 | 
      
         | 838 |  |  |  
 | 
      
         | 839 |  |  |       if (may_fault && mem_err)
 | 
      
         | 840 |  |  |         return mem;
 | 
      
         | 841 |  |  |     }
 | 
      
         | 842 |  |  |  
 | 
      
         | 843 |  |  |   if (may_fault)
 | 
      
         | 844 |  |  |     mem_fault_routine = 0;
 | 
      
         | 845 |  |  |   return mem;
 | 
      
         | 846 |  |  | }
 | 
      
         | 847 |  |  |  
 | 
      
         | 848 |  |  | /* this function takes the m32r exception vector and attempts to
 | 
      
         | 849 |  |  |    translate this number into a unix compatible signal value */
 | 
      
         | 850 |  |  |  
 | 
      
         | 851 |  |  | static int
 | 
      
         | 852 |  |  | computeSignal (int exceptionVector)
 | 
      
         | 853 |  |  | {
 | 
      
         | 854 |  |  |   int sigval;
 | 
      
         | 855 |  |  |   switch (exceptionVector)
 | 
      
         | 856 |  |  |     {
 | 
      
         | 857 |  |  |     case 0:
 | 
      
         | 858 |  |  |       sigval = 23;
 | 
      
         | 859 |  |  |       break;                    /* I/O trap                    */
 | 
      
         | 860 |  |  |     case 1:
 | 
      
         | 861 |  |  |       sigval = 5;
 | 
      
         | 862 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 863 |  |  |     case 2:
 | 
      
         | 864 |  |  |       sigval = 5;
 | 
      
         | 865 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 866 |  |  |     case 3:
 | 
      
         | 867 |  |  |       sigval = 5;
 | 
      
         | 868 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 869 |  |  |     case 4:
 | 
      
         | 870 |  |  |       sigval = 5;
 | 
      
         | 871 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 872 |  |  |     case 5:
 | 
      
         | 873 |  |  |       sigval = 5;
 | 
      
         | 874 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 875 |  |  |     case 6:
 | 
      
         | 876 |  |  |       sigval = 5;
 | 
      
         | 877 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 878 |  |  |     case 7:
 | 
      
         | 879 |  |  |       sigval = 5;
 | 
      
         | 880 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 881 |  |  |     case 8:
 | 
      
         | 882 |  |  |       sigval = 5;
 | 
      
         | 883 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 884 |  |  |     case 9:
 | 
      
         | 885 |  |  |       sigval = 5;
 | 
      
         | 886 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 887 |  |  |     case 10:
 | 
      
         | 888 |  |  |       sigval = 5;
 | 
      
         | 889 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 890 |  |  |     case 11:
 | 
      
         | 891 |  |  |       sigval = 5;
 | 
      
         | 892 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 893 |  |  |     case 12:
 | 
      
         | 894 |  |  |       sigval = 5;
 | 
      
         | 895 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 896 |  |  |     case 13:
 | 
      
         | 897 |  |  |       sigval = 5;
 | 
      
         | 898 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 899 |  |  |     case 14:
 | 
      
         | 900 |  |  |       sigval = 5;
 | 
      
         | 901 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 902 |  |  |     case 15:
 | 
      
         | 903 |  |  |       sigval = 5;
 | 
      
         | 904 |  |  |       break;                    /* breakpoint                  */
 | 
      
         | 905 |  |  |     case 16:
 | 
      
         | 906 |  |  |       sigval = 10;
 | 
      
         | 907 |  |  |       break;                    /* BUS ERROR (alignment)       */
 | 
      
         | 908 |  |  |     case 17:
 | 
      
         | 909 |  |  |       sigval = 2;
 | 
      
         | 910 |  |  |       break;                    /* INTerrupt                   */
 | 
      
         | 911 |  |  |     default:
 | 
      
         | 912 |  |  |       sigval = 7;
 | 
      
         | 913 |  |  |       break;                    /* "software generated"        */
 | 
      
         | 914 |  |  |     }
 | 
      
         | 915 |  |  |   return (sigval);
 | 
      
         | 916 |  |  | }
 | 
      
         | 917 |  |  |  
 | 
      
         | 918 |  |  | /**********************************************/
 | 
      
         | 919 |  |  | /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
 | 
      
         | 920 |  |  | /* RETURN NUMBER OF CHARS PROCESSED           */
 | 
      
         | 921 |  |  | /**********************************************/
 | 
      
         | 922 |  |  | static int
 | 
      
         | 923 |  |  | hexToInt (unsigned char **ptr, int *intValue)
 | 
      
         | 924 |  |  | {
 | 
      
         | 925 |  |  |   int numChars = 0;
 | 
      
         | 926 |  |  |   int hexValue;
 | 
      
         | 927 |  |  |  
 | 
      
         | 928 |  |  |   *intValue = 0;
 | 
      
         | 929 |  |  |   while (**ptr)
 | 
      
         | 930 |  |  |     {
 | 
      
         | 931 |  |  |       hexValue = hex (**ptr);
 | 
      
         | 932 |  |  |       if (hexValue >= 0)
 | 
      
         | 933 |  |  |         {
 | 
      
         | 934 |  |  |           *intValue = (*intValue << 4) | hexValue;
 | 
      
         | 935 |  |  |           numChars++;
 | 
      
         | 936 |  |  |         }
 | 
      
         | 937 |  |  |       else
 | 
      
         | 938 |  |  |         break;
 | 
      
         | 939 |  |  |       (*ptr)++;
 | 
      
         | 940 |  |  |     }
 | 
      
         | 941 |  |  |   return (numChars);
 | 
      
         | 942 |  |  | }
 | 
      
         | 943 |  |  |  
 | 
      
         | 944 |  |  | /*
 | 
      
         | 945 |  |  |   Table of branch instructions:
 | 
      
         | 946 |  |  |  
 | 
      
         | 947 |  |  |   10B6          RTE     return from trap or exception
 | 
      
         | 948 |  |  |   1FCr          JMP     jump
 | 
      
         | 949 |  |  |   1ECr          JL      jump and link
 | 
      
         | 950 |  |  |   7Fxx          BRA     branch
 | 
      
         | 951 |  |  |   FFxxxxxx      BRA     branch (long)
 | 
      
         | 952 |  |  |   B09rxxxx      BNEZ    branch not-equal-zero
 | 
      
         | 953 |  |  |   Br1rxxxx      BNE     branch not-equal
 | 
      
         | 954 |  |  |   7Dxx          BNC     branch not-condition
 | 
      
         | 955 |  |  |   FDxxxxxx      BNC     branch not-condition (long)
 | 
      
         | 956 |  |  |   B0Arxxxx      BLTZ    branch less-than-zero
 | 
      
         | 957 |  |  |   B0Crxxxx      BLEZ    branch less-equal-zero
 | 
      
         | 958 |  |  |   7Exx          BL      branch and link
 | 
      
         | 959 |  |  |   FExxxxxx      BL      branch and link (long)
 | 
      
         | 960 |  |  |   B0Drxxxx      BGTZ    branch greater-than-zero
 | 
      
         | 961 |  |  |   B0Brxxxx      BGEZ    branch greater-equal-zero
 | 
      
         | 962 |  |  |   B08rxxxx      BEQZ    branch equal-zero
 | 
      
         | 963 |  |  |   Br0rxxxx      BEQ     branch equal
 | 
      
         | 964 |  |  |   7Cxx          BC      branch condition
 | 
      
         | 965 |  |  |   FCxxxxxx      BC      branch condition (long)
 | 
      
         | 966 |  |  |   */
 | 
      
         | 967 |  |  |  
 | 
      
         | 968 |  |  | static int
 | 
      
         | 969 |  |  | isShortBranch (unsigned char *instr)
 | 
      
         | 970 |  |  | {
 | 
      
         | 971 |  |  |   unsigned char instr0 = instr[0] & 0x7F;        /* mask off high bit */
 | 
      
         | 972 |  |  |  
 | 
      
         | 973 |  |  |   if (instr0 == 0x10 && instr[1] == 0xB6)       /* RTE */
 | 
      
         | 974 |  |  |     return 1;                   /* return from trap or exception */
 | 
      
         | 975 |  |  |  
 | 
      
         | 976 |  |  |   if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */
 | 
      
         | 977 |  |  |     if ((instr[1] & 0xF0) == 0xC0)
 | 
      
         | 978 |  |  |       return 2;                 /* jump thru a register */
 | 
      
         | 979 |  |  |  
 | 
      
         | 980 |  |  |   if (instr0 == 0x7C || instr0 == 0x7D ||       /* BC, BNC, BL, BRA */
 | 
      
         | 981 |  |  |       instr0 == 0x7E || instr0 == 0x7F)
 | 
      
         | 982 |  |  |     return 3;                   /* eight bit PC offset */
 | 
      
         | 983 |  |  |  
 | 
      
         | 984 |  |  |   return 0;
 | 
      
         | 985 |  |  | }
 | 
      
         | 986 |  |  |  
 | 
      
         | 987 |  |  | static int
 | 
      
         | 988 |  |  | isLongBranch (unsigned char *instr)
 | 
      
         | 989 |  |  | {
 | 
      
         | 990 |  |  |   if (instr[0] == 0xFC || instr[0] == 0xFD ||     /* BRA, BNC, BL, BC */
 | 
      
         | 991 |  |  |       instr[0] == 0xFE || instr[0] == 0xFF)       /* 24 bit relative */
 | 
      
         | 992 |  |  |     return 4;
 | 
      
         | 993 |  |  |   if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */
 | 
      
         | 994 |  |  |     {
 | 
      
         | 995 |  |  |       if ((instr[1] & 0xF0) == 0x00 ||  /* BNE, BEQ */
 | 
      
         | 996 |  |  |           (instr[1] & 0xF0) == 0x10)
 | 
      
         | 997 |  |  |         return 5;
 | 
      
         | 998 |  |  |       if (instr[0] == 0xB0)      /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */
 | 
      
         | 999 |  |  |         if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 ||
 | 
      
         | 1000 |  |  |             (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 ||
 | 
      
         | 1001 |  |  |             (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0)
 | 
      
         | 1002 |  |  |           return 6;
 | 
      
         | 1003 |  |  |     }
 | 
      
         | 1004 |  |  |   return 0;
 | 
      
         | 1005 |  |  | }
 | 
      
         | 1006 |  |  |  
 | 
      
         | 1007 |  |  | /* if address is NOT on a 4-byte boundary, or high-bit of instr is zero,
 | 
      
         | 1008 |  |  |    then it's a 2-byte instruction, else it's a 4-byte instruction.  */
 | 
      
         | 1009 |  |  |  
 | 
      
         | 1010 |  |  | #define INSTRUCTION_SIZE(addr) \
 | 
      
         | 1011 |  |  |     ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4)
 | 
      
         | 1012 |  |  |  
 | 
      
         | 1013 |  |  | static int
 | 
      
         | 1014 |  |  | isBranch (unsigned char *instr)
 | 
      
         | 1015 |  |  | {
 | 
      
         | 1016 |  |  |   if (INSTRUCTION_SIZE (instr) == 2)
 | 
      
         | 1017 |  |  |     return isShortBranch (instr);
 | 
      
         | 1018 |  |  |   else
 | 
      
         | 1019 |  |  |     return isLongBranch (instr);
 | 
      
         | 1020 |  |  | }
 | 
      
         | 1021 |  |  |  
 | 
      
         | 1022 |  |  | static int
 | 
      
         | 1023 |  |  | willBranch (unsigned char *instr, int branchCode)
 | 
      
         | 1024 |  |  | {
 | 
      
         | 1025 |  |  |   switch (branchCode)
 | 
      
         | 1026 |  |  |     {
 | 
      
         | 1027 |  |  |     case 0:
 | 
      
         | 1028 |  |  |       return 0;                  /* not a branch */
 | 
      
         | 1029 |  |  |     case 1:
 | 
      
         | 1030 |  |  |       return 1;                 /* RTE */
 | 
      
         | 1031 |  |  |     case 2:
 | 
      
         | 1032 |  |  |       return 1;                 /* JL or JMP    */
 | 
      
         | 1033 |  |  |     case 3:                     /* BC, BNC, BL, BRA (short) */
 | 
      
         | 1034 |  |  |     case 4:                     /* BC, BNC, BL, BRA (long) */
 | 
      
         | 1035 |  |  |       switch (instr[0] & 0x0F)
 | 
      
         | 1036 |  |  |         {
 | 
      
         | 1037 |  |  |         case 0xC:               /* Branch if Condition Register */
 | 
      
         | 1038 |  |  |           return (registers[CBR] != 0);
 | 
      
         | 1039 |  |  |         case 0xD:               /* Branch if NOT Condition Register */
 | 
      
         | 1040 |  |  |           return (registers[CBR] == 0);
 | 
      
         | 1041 |  |  |         case 0xE:               /* Branch and Link */
 | 
      
         | 1042 |  |  |         case 0xF:               /* Branch (unconditional) */
 | 
      
         | 1043 |  |  |           return 1;
 | 
      
         | 1044 |  |  |         default:                /* oops? */
 | 
      
         | 1045 |  |  |           return 0;
 | 
      
         | 1046 |  |  |         }
 | 
      
         | 1047 |  |  |     case 5:                     /* BNE, BEQ */
 | 
      
         | 1048 |  |  |       switch (instr[1] & 0xF0)
 | 
      
         | 1049 |  |  |         {
 | 
      
         | 1050 |  |  |         case 0x00:              /* Branch if r1 equal to r2 */
 | 
      
         | 1051 |  |  |           return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]);
 | 
      
         | 1052 |  |  |         case 0x10:              /* Branch if r1 NOT equal to r2 */
 | 
      
         | 1053 |  |  |           return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]);
 | 
      
         | 1054 |  |  |         default:                /* oops? */
 | 
      
         | 1055 |  |  |           return 0;
 | 
      
         | 1056 |  |  |         }
 | 
      
         | 1057 |  |  |     case 6:                     /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */
 | 
      
         | 1058 |  |  |       switch (instr[1] & 0xF0)
 | 
      
         | 1059 |  |  |         {
 | 
      
         | 1060 |  |  |         case 0x80:              /* Branch if reg equal to zero */
 | 
      
         | 1061 |  |  |           return (registers[instr[1] & 0x0F] == 0);
 | 
      
         | 1062 |  |  |         case 0x90:              /* Branch if reg NOT equal to zero */
 | 
      
         | 1063 |  |  |           return (registers[instr[1] & 0x0F] != 0);
 | 
      
         | 1064 |  |  |         case 0xA0:              /* Branch if reg less than zero */
 | 
      
         | 1065 |  |  |           return (registers[instr[1] & 0x0F] < 0);
 | 
      
         | 1066 |  |  |         case 0xB0:              /* Branch if reg greater or equal to zero */
 | 
      
         | 1067 |  |  |           return (registers[instr[1] & 0x0F] >= 0);
 | 
      
         | 1068 |  |  |         case 0xC0:              /* Branch if reg less than or equal to zero */
 | 
      
         | 1069 |  |  |           return (registers[instr[1] & 0x0F] <= 0);
 | 
      
         | 1070 |  |  |         case 0xD0:              /* Branch if reg greater than zero */
 | 
      
         | 1071 |  |  |           return (registers[instr[1] & 0x0F] > 0);
 | 
      
         | 1072 |  |  |         default:                /* oops? */
 | 
      
         | 1073 |  |  |           return 0;
 | 
      
         | 1074 |  |  |         }
 | 
      
         | 1075 |  |  |     default:                    /* oops? */
 | 
      
         | 1076 |  |  |       return 0;
 | 
      
         | 1077 |  |  |     }
 | 
      
         | 1078 |  |  | }
 | 
      
         | 1079 |  |  |  
 | 
      
         | 1080 |  |  | static int
 | 
      
         | 1081 |  |  | branchDestination (unsigned char *instr, int branchCode)
 | 
      
         | 1082 |  |  | {
 | 
      
         | 1083 |  |  |   switch (branchCode)
 | 
      
         | 1084 |  |  |     {
 | 
      
         | 1085 |  |  |     default:
 | 
      
         | 1086 |  |  |     case 0:                      /* not a branch */
 | 
      
         | 1087 |  |  |       return 0;
 | 
      
         | 1088 |  |  |     case 1:                     /* RTE */
 | 
      
         | 1089 |  |  |       return registers[BPC] & ~3;       /* pop BPC into PC */
 | 
      
         | 1090 |  |  |     case 2:                     /* JL or JMP */
 | 
      
         | 1091 |  |  |       return registers[instr[1] & 0x0F] & ~3;   /* jump thru a register */
 | 
      
         | 1092 |  |  |     case 3:                     /* BC, BNC, BL, BRA (short, 8-bit relative offset) */
 | 
      
         | 1093 |  |  |       return (((int) instr) & ~3) + ((char) instr[1] << 2);
 | 
      
         | 1094 |  |  |     case 4:                     /* BC, BNC, BL, BRA (long, 24-bit relative offset) */
 | 
      
         | 1095 |  |  |       return ((int) instr +
 | 
      
         | 1096 |  |  |               ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) <<
 | 
      
         | 1097 |  |  |                2));
 | 
      
         | 1098 |  |  |     case 5:                     /* BNE, BEQ (16-bit relative offset) */
 | 
      
         | 1099 |  |  |     case 6:                     /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */
 | 
      
         | 1100 |  |  |       return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2));
 | 
      
         | 1101 |  |  |     }
 | 
      
         | 1102 |  |  |  
 | 
      
         | 1103 |  |  |   /* An explanatory note: in the last three return expressions, I have
 | 
      
         | 1104 |  |  |      cast the most-significant byte of the return offset to char.
 | 
      
         | 1105 |  |  |      What this accomplishes is sign extension.  If the other
 | 
      
         | 1106 |  |  |      less-significant bytes were signed as well, they would get sign
 | 
      
         | 1107 |  |  |      extended too and, if negative, their leading bits would clobber
 | 
      
         | 1108 |  |  |      the bits of the more-significant bytes ahead of them.  There are
 | 
      
         | 1109 |  |  |      other ways I could have done this, but sign extension from
 | 
      
         | 1110 |  |  |      odd-sized integers is always a pain. */
 | 
      
         | 1111 |  |  | }
 | 
      
         | 1112 |  |  |  
 | 
      
         | 1113 |  |  | static void
 | 
      
         | 1114 |  |  | branchSideEffects (unsigned char *instr, int branchCode)
 | 
      
         | 1115 |  |  | {
 | 
      
         | 1116 |  |  |   switch (branchCode)
 | 
      
         | 1117 |  |  |     {
 | 
      
         | 1118 |  |  |     case 1:                     /* RTE */
 | 
      
         | 1119 |  |  |       return;                   /* I <THINK> this is already handled... */
 | 
      
         | 1120 |  |  |     case 2:                     /* JL (or JMP) */
 | 
      
         | 1121 |  |  |     case 3:                     /* BL (or BC, BNC, BRA) */
 | 
      
         | 1122 |  |  |     case 4:
 | 
      
         | 1123 |  |  |       if ((instr[0] & 0x0F) == 0x0E)     /* branch/jump and link */
 | 
      
         | 1124 |  |  |         registers[R14] = (registers[PC] & ~3) + 4;
 | 
      
         | 1125 |  |  |       return;
 | 
      
         | 1126 |  |  |     default:                    /* any other branch has no side effects */
 | 
      
         | 1127 |  |  |       return;
 | 
      
         | 1128 |  |  |     }
 | 
      
         | 1129 |  |  | }
 | 
      
         | 1130 |  |  |  
 | 
      
         | 1131 |  |  | static struct STEPPING_CONTEXT
 | 
      
         | 1132 |  |  | {
 | 
      
         | 1133 |  |  |   int stepping;                 /* true when we've started a single-step */
 | 
      
         | 1134 |  |  |   unsigned long target_addr;    /* the instr we're trying to execute */
 | 
      
         | 1135 |  |  |   unsigned long target_size;    /* the size of the target instr */
 | 
      
         | 1136 |  |  |   unsigned long noop_addr;      /* where we've inserted a no-op, if any */
 | 
      
         | 1137 |  |  |   unsigned long trap1_addr;     /* the trap following the target instr */
 | 
      
         | 1138 |  |  |   unsigned long trap2_addr;     /* the trap at a branch destination, if any */
 | 
      
         | 1139 |  |  |   unsigned short noop_save;     /* instruction overwritten by our no-op */
 | 
      
         | 1140 |  |  |   unsigned short trap1_save;    /* instruction overwritten by trap1 */
 | 
      
         | 1141 |  |  |   unsigned short trap2_save;    /* instruction overwritten by trap2 */
 | 
      
         | 1142 |  |  |   unsigned short continue_p;    /* true if NOT returning to gdb after step */
 | 
      
         | 1143 |  |  | } stepping;
 | 
      
         | 1144 |  |  |  
 | 
      
         | 1145 |  |  | /* Function: prepare_to_step
 | 
      
         | 1146 |  |  |    Called from handle_exception to prepare the user program to single-step.
 | 
      
         | 1147 |  |  |    Places a trap instruction after the target instruction, with special
 | 
      
         | 1148 |  |  |    extra handling for branch instructions and for instructions in the
 | 
      
         | 1149 |  |  |    second half-word of a word.
 | 
      
         | 1150 |  |  |  
 | 
      
         | 1151 |  |  |    Returns: True  if we should actually execute the instruction;
 | 
      
         | 1152 |  |  |             False if we are going to emulate executing the instruction,
 | 
      
         | 1153 |  |  |             in which case we simply report to GDB that the instruction
 | 
      
         | 1154 |  |  |             has already been executed.  */
 | 
      
         | 1155 |  |  |  
 | 
      
         | 1156 |  |  | #define TRAP1  0x10f1;          /* trap #1 instruction */
 | 
      
         | 1157 |  |  | #define NOOP   0x7000;          /* noop    instruction */
 | 
      
         | 1158 |  |  |  
 | 
      
         | 1159 |  |  | static unsigned short trap1 = TRAP1;
 | 
      
         | 1160 |  |  | static unsigned short noop = NOOP;
 | 
      
         | 1161 |  |  |  
 | 
      
         | 1162 |  |  | static int
 | 
      
         | 1163 |  |  | prepare_to_step (continue_p)
 | 
      
         | 1164 |  |  |      int continue_p;            /* if this isn't REALLY a single-step (see below) */
 | 
      
         | 1165 |  |  | {
 | 
      
         | 1166 |  |  |   unsigned long pc = registers[PC];
 | 
      
         | 1167 |  |  |   int branchCode = isBranch ((unsigned char *) pc);
 | 
      
         | 1168 |  |  |   unsigned char *p;
 | 
      
         | 1169 |  |  |  
 | 
      
         | 1170 |  |  |   /* zero out the stepping context
 | 
      
         | 1171 |  |  |      (paranoia -- it should already be zeroed) */
 | 
      
         | 1172 |  |  |   for (p = (unsigned char *) &stepping;
 | 
      
         | 1173 |  |  |        p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
 | 
      
         | 1174 |  |  |     *p = 0;
 | 
      
         | 1175 |  |  |  
 | 
      
         | 1176 |  |  |   if (branchCode != 0)           /* next instruction is a branch */
 | 
      
         | 1177 |  |  |     {
 | 
      
         | 1178 |  |  |       branchSideEffects ((unsigned char *) pc, branchCode);
 | 
      
         | 1179 |  |  |       if (willBranch ((unsigned char *) pc, branchCode))
 | 
      
         | 1180 |  |  |         registers[PC] = branchDestination ((unsigned char *) pc, branchCode);
 | 
      
         | 1181 |  |  |       else
 | 
      
         | 1182 |  |  |         registers[PC] = pc + INSTRUCTION_SIZE (pc);
 | 
      
         | 1183 |  |  |       return 0;                  /* branch "executed" -- just notify GDB */
 | 
      
         | 1184 |  |  |     }
 | 
      
         | 1185 |  |  |   else if (((int) pc & 2) != 0)  /* "second-slot" instruction */
 | 
      
         | 1186 |  |  |     {
 | 
      
         | 1187 |  |  |       /* insert no-op before pc */
 | 
      
         | 1188 |  |  |       stepping.noop_addr = pc - 2;
 | 
      
         | 1189 |  |  |       stepping.noop_save = *(unsigned short *) stepping.noop_addr;
 | 
      
         | 1190 |  |  |       *(unsigned short *) stepping.noop_addr = noop;
 | 
      
         | 1191 |  |  |       /* insert trap  after  pc */
 | 
      
         | 1192 |  |  |       stepping.trap1_addr = pc + 2;
 | 
      
         | 1193 |  |  |       stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
 | 
      
         | 1194 |  |  |       *(unsigned short *) stepping.trap1_addr = trap1;
 | 
      
         | 1195 |  |  |     }
 | 
      
         | 1196 |  |  |   else                          /* "first-slot" instruction */
 | 
      
         | 1197 |  |  |     {
 | 
      
         | 1198 |  |  |       /* insert trap  after  pc */
 | 
      
         | 1199 |  |  |       stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc);
 | 
      
         | 1200 |  |  |       stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
 | 
      
         | 1201 |  |  |       *(unsigned short *) stepping.trap1_addr = trap1;
 | 
      
         | 1202 |  |  |     }
 | 
      
         | 1203 |  |  |   /* "continue_p" means that we are actually doing a continue, and not
 | 
      
         | 1204 |  |  |      being requested to single-step by GDB.  Sometimes we have to do
 | 
      
         | 1205 |  |  |      one single-step before continuing, because the PC is on a half-word
 | 
      
         | 1206 |  |  |      boundary.  There's no way to simply resume at such an address.  */
 | 
      
         | 1207 |  |  |   stepping.continue_p = continue_p;
 | 
      
         | 1208 |  |  |   stepping.stepping = 1;        /* starting a single-step */
 | 
      
         | 1209 |  |  |   return 1;
 | 
      
         | 1210 |  |  | }
 | 
      
         | 1211 |  |  |  
 | 
      
         | 1212 |  |  | /* Function: finish_from_step
 | 
      
         | 1213 |  |  |    Called from handle_exception to finish up when the user program
 | 
      
         | 1214 |  |  |    returns from a single-step.  Replaces the instructions that had
 | 
      
         | 1215 |  |  |    been overwritten by traps or no-ops,
 | 
      
         | 1216 |  |  |  
 | 
      
         | 1217 |  |  |    Returns: True  if we should notify GDB that the target stopped.
 | 
      
         | 1218 |  |  |             False if we only single-stepped because we had to before we
 | 
      
         | 1219 |  |  |             could continue (ie. we were trying to continue at a
 | 
      
         | 1220 |  |  |             half-word boundary).  In that case don't notify GDB:
 | 
      
         | 1221 |  |  |             just "continue continuing".  */
 | 
      
         | 1222 |  |  |  
 | 
      
         | 1223 |  |  | static int
 | 
      
         | 1224 |  |  | finish_from_step (void)
 | 
      
         | 1225 |  |  | {
 | 
      
         | 1226 |  |  |   if (stepping.stepping)        /* anything to do? */
 | 
      
         | 1227 |  |  |     {
 | 
      
         | 1228 |  |  |       int continue_p = stepping.continue_p;
 | 
      
         | 1229 |  |  |       unsigned char *p;
 | 
      
         | 1230 |  |  |  
 | 
      
         | 1231 |  |  |       if (stepping.noop_addr)   /* replace instr "under" our no-op */
 | 
      
         | 1232 |  |  |         *(unsigned short *) stepping.noop_addr = stepping.noop_save;
 | 
      
         | 1233 |  |  |       if (stepping.trap1_addr)  /* replace instr "under" our trap  */
 | 
      
         | 1234 |  |  |         *(unsigned short *) stepping.trap1_addr = stepping.trap1_save;
 | 
      
         | 1235 |  |  |       if (stepping.trap2_addr)  /* ditto our other trap, if any    */
 | 
      
         | 1236 |  |  |         *(unsigned short *) stepping.trap2_addr = stepping.trap2_save;
 | 
      
         | 1237 |  |  |  
 | 
      
         | 1238 |  |  |       for (p = (unsigned char *) &stepping;     /* zero out the stepping context */
 | 
      
         | 1239 |  |  |            p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
 | 
      
         | 1240 |  |  |         *p = 0;
 | 
      
         | 1241 |  |  |  
 | 
      
         | 1242 |  |  |       return !(continue_p);
 | 
      
         | 1243 |  |  |     }
 | 
      
         | 1244 |  |  |   else                          /* we didn't single-step, therefore this must be a legitimate stop */
 | 
      
         | 1245 |  |  |     return 1;
 | 
      
         | 1246 |  |  | }
 | 
      
         | 1247 |  |  |  
 | 
      
         | 1248 |  |  | struct PSWreg
 | 
      
         | 1249 |  |  | {                               /* separate out the bit flags in the PSW register */
 | 
      
         | 1250 |  |  |   int pad1:16;
 | 
      
         | 1251 |  |  |   int bsm:1;
 | 
      
         | 1252 |  |  |   int bie:1;
 | 
      
         | 1253 |  |  |   int pad2:5;
 | 
      
         | 1254 |  |  |   int bc:1;
 | 
      
         | 1255 |  |  |   int sm:1;
 | 
      
         | 1256 |  |  |   int ie:1;
 | 
      
         | 1257 |  |  |   int pad3:5;
 | 
      
         | 1258 |  |  |   int c:1;
 | 
      
         | 1259 |  |  | } *psw;
 | 
      
         | 1260 |  |  |  
 | 
      
         | 1261 |  |  | /* Upon entry the value for LR to save has been pushed.
 | 
      
         | 1262 |  |  |    We unpush that so that the value for the stack pointer saved is correct.
 | 
      
         | 1263 |  |  |    Upon entry, all other registers are assumed to have not been modified
 | 
      
         | 1264 |  |  |    since the interrupt/trap occured.  */
 | 
      
         | 1265 |  |  |  
 | 
      
         | 1266 |  |  | asm ("\n\
 | 
      
         | 1267 |  |  | stash_registers:\n\
 | 
      
         | 1268 |  |  |         push r0\n\
 | 
      
         | 1269 |  |  |         push r1\n\
 | 
      
         | 1270 |  |  |         seth r1, #shigh(registers)\n\
 | 
      
         | 1271 |  |  |         add3 r1, r1, #low(registers)\n\
 | 
      
         | 1272 |  |  |         pop r0          ; r1\n\
 | 
      
         | 1273 |  |  |         st r0, @(4,r1)\n\
 | 
      
         | 1274 |  |  |         pop r0          ; r0\n\
 | 
      
         | 1275 |  |  |         st r0, @r1\n\
 | 
      
         | 1276 |  |  |         addi r1, #4     ; only add 4 as subsequent saves are `pre inc'\n\
 | 
      
         | 1277 |  |  |         st r2, @+r1\n\
 | 
      
         | 1278 |  |  |         st r3, @+r1\n\
 | 
      
         | 1279 |  |  |         st r4, @+r1\n\
 | 
      
         | 1280 |  |  |         st r5, @+r1\n\
 | 
      
         | 1281 |  |  |         st r6, @+r1\n\
 | 
      
         | 1282 |  |  |         st r7, @+r1\n\
 | 
      
         | 1283 |  |  |         st r8, @+r1\n\
 | 
      
         | 1284 |  |  |         st r9, @+r1\n\
 | 
      
         | 1285 |  |  |         st r10, @+r1\n\
 | 
      
         | 1286 |  |  |         st r11, @+r1\n\
 | 
      
         | 1287 |  |  |         st r12, @+r1\n\
 | 
      
         | 1288 |  |  |         st r13, @+r1    ; fp\n\
 | 
      
         | 1289 |  |  |         pop r0          ; lr (r14)\n\
 | 
      
         | 1290 |  |  |         st r0, @+r1\n\
 | 
      
         | 1291 |  |  |         st sp, @+r1     ; sp contains right value at this point\n\
 | 
      
         | 1292 |  |  |         mvfc r0, cr0\n\
 | 
      
         | 1293 |  |  |         st r0, @+r1     ; cr0 == PSW\n\
 | 
      
         | 1294 |  |  |         mvfc r0, cr1\n\
 | 
      
         | 1295 |  |  |         st r0, @+r1     ; cr1 == CBR\n\
 | 
      
         | 1296 |  |  |         mvfc r0, cr2\n\
 | 
      
         | 1297 |  |  |         st r0, @+r1     ; cr2 == SPI\n\
 | 
      
         | 1298 |  |  |         mvfc r0, cr3\n\
 | 
      
         | 1299 |  |  |         st r0, @+r1     ; cr3 == SPU\n\
 | 
      
         | 1300 |  |  |         mvfc r0, cr6\n\
 | 
      
         | 1301 |  |  |         st r0, @+r1     ; cr6 == BPC\n\
 | 
      
         | 1302 |  |  |         st r0, @+r1     ; PC  == BPC\n\
 | 
      
         | 1303 |  |  |         mvfaclo r0\n\
 | 
      
         | 1304 |  |  |         st r0, @+r1     ; ACCL\n\
 | 
      
         | 1305 |  |  |         mvfachi r0\n\
 | 
      
         | 1306 |  |  |         st r0, @+r1     ; ACCH\n\
 | 
      
         | 1307 |  |  |         jmp lr");
 | 
      
         | 1308 |  |  |  
 | 
      
         | 1309 |  |  | /* C routine to clean up what stash_registers did.
 | 
      
         | 1310 |  |  |    It is called after calling stash_registers.
 | 
      
         | 1311 |  |  |    This is separate from stash_registers as we want to do this in C
 | 
      
         | 1312 |  |  |    but doing stash_registers in C isn't straightforward.  */
 | 
      
         | 1313 |  |  |  
 | 
      
         | 1314 |  |  | static void
 | 
      
         | 1315 |  |  | cleanup_stash (void)
 | 
      
         | 1316 |  |  | {
 | 
      
         | 1317 |  |  |   psw = (struct PSWreg *) ®isters[PSW];      /* fields of PSW register */
 | 
      
         | 1318 |  |  |   psw->sm = psw->bsm;           /* fix up pre-trap values of psw fields */
 | 
      
         | 1319 |  |  |   psw->ie = psw->bie;
 | 
      
         | 1320 |  |  |   psw->c = psw->bc;
 | 
      
         | 1321 |  |  |   registers[CBR] = psw->bc;     /* fix up pre-trap "C" register */
 | 
      
         | 1322 |  |  |  
 | 
      
         | 1323 |  |  | #if 0                           /* FIXME: Was in previous version.  Necessary?
 | 
      
         | 1324 |  |  |                                    (Remember that we use the "rte" insn to return from the
 | 
      
         | 1325 |  |  |                                    trap/interrupt so the values of bsm, bie, bc are important.  */
 | 
      
         | 1326 |  |  |   psw->bsm = psw->bie = psw->bc = 0;     /* zero post-trap values */
 | 
      
         | 1327 |  |  | #endif
 | 
      
         | 1328 |  |  |  
 | 
      
         | 1329 |  |  |   /* FIXME: Copied from previous version.  This can probably be deleted
 | 
      
         | 1330 |  |  |      since methinks stash_registers has already done this.  */
 | 
      
         | 1331 |  |  |   registers[PC] = registers[BPC];       /* pre-trap PC */
 | 
      
         | 1332 |  |  |  
 | 
      
         | 1333 |  |  |   /* FIXME: Copied from previous version.  Necessary?  */
 | 
      
         | 1334 |  |  |   if (psw->sm)                  /* copy R15 into (psw->sm ? SPU : SPI) */
 | 
      
         | 1335 |  |  |     registers[SPU] = registers[R15];
 | 
      
         | 1336 |  |  |   else
 | 
      
         | 1337 |  |  |     registers[SPI] = registers[R15];
 | 
      
         | 1338 |  |  | }
 | 
      
         | 1339 |  |  |  
 | 
      
         | 1340 |  |  | asm ("\n\
 | 
      
         | 1341 |  |  | restore_and_return:\n\
 | 
      
         | 1342 |  |  |         seth r0, #shigh(registers+8)\n\
 | 
      
         | 1343 |  |  |         add3 r0, r0, #low(registers+8)\n\
 | 
      
         | 1344 |  |  |         ld r2, @r0+     ; restore r2\n\
 | 
      
         | 1345 |  |  |         ld r3, @r0+     ; restore r3\n\
 | 
      
         | 1346 |  |  |         ld r4, @r0+     ; restore r4\n\
 | 
      
         | 1347 |  |  |         ld r5, @r0+     ; restore r5\n\
 | 
      
         | 1348 |  |  |         ld r6, @r0+     ; restore r6\n\
 | 
      
         | 1349 |  |  |         ld r7, @r0+     ; restore r7\n\
 | 
      
         | 1350 |  |  |         ld r8, @r0+     ; restore r8\n\
 | 
      
         | 1351 |  |  |         ld r9, @r0+     ; restore r9\n\
 | 
      
         | 1352 |  |  |         ld r10, @r0+    ; restore r10\n\
 | 
      
         | 1353 |  |  |         ld r11, @r0+    ; restore r11\n\
 | 
      
         | 1354 |  |  |         ld r12, @r0+    ; restore r12\n\
 | 
      
         | 1355 |  |  |         ld r13, @r0+    ; restore r13\n\
 | 
      
         | 1356 |  |  |         ld r14, @r0+    ; restore r14\n\
 | 
      
         | 1357 |  |  |         ld r15, @r0+    ; restore r15\n\
 | 
      
         | 1358 |  |  |         ld r1, @r0+     ; restore cr0 == PSW\n\
 | 
      
         | 1359 |  |  |         mvtc r1, cr0\n\
 | 
      
         | 1360 |  |  |         ld r1, @r0+     ; restore cr1 == CBR (no-op, because it's read only)\n\
 | 
      
         | 1361 |  |  |         mvtc r1, cr1\n\
 | 
      
         | 1362 |  |  |         ld r1, @r0+     ; restore cr2 == SPI\n\
 | 
      
         | 1363 |  |  |         mvtc r1, cr2\n\
 | 
      
         | 1364 |  |  |         ld r1, @r0+     ; restore cr3 == SPU\n\
 | 
      
         | 1365 |  |  |         mvtc r1, cr3\n\
 | 
      
         | 1366 |  |  |         addi r0, #4     ; skip BPC\n\
 | 
      
         | 1367 |  |  |         ld r1, @r0+     ; restore cr6 (BPC) == PC\n\
 | 
      
         | 1368 |  |  |         mvtc r1, cr6\n\
 | 
      
         | 1369 |  |  |         ld r1, @r0+     ; restore ACCL\n\
 | 
      
         | 1370 |  |  |         mvtaclo r1\n\
 | 
      
         | 1371 |  |  |         ld r1, @r0+     ; restore ACCH\n\
 | 
      
         | 1372 |  |  |         mvtachi r1\n\
 | 
      
         | 1373 |  |  |         seth r0, #shigh(registers)\n\
 | 
      
         | 1374 |  |  |         add3 r0, r0, #low(registers)\n\
 | 
      
         | 1375 |  |  |         ld r1, @(4,r0)  ; restore r1\n\
 | 
      
         | 1376 |  |  |         ld r0, @r0      ; restore r0\n\
 | 
      
         | 1377 |  |  |         rte");
 | 
      
         | 1378 |  |  |  
 | 
      
         | 1379 |  |  | /* General trap handler, called after the registers have been stashed.
 | 
      
         | 1380 |  |  |    NUM is the trap/exception number.  */
 | 
      
         | 1381 |  |  |  
 | 
      
         | 1382 |  |  | static void
 | 
      
         | 1383 |  |  | process_exception (int num)
 | 
      
         | 1384 |  |  | {
 | 
      
         | 1385 |  |  |   cleanup_stash ();
 | 
      
         | 1386 |  |  |   asm volatile ("\n\
 | 
      
         | 1387 |  |  |         seth r1, #shigh(stackPtr)\n\
 | 
      
         | 1388 |  |  |         add3 r1, r1, #low(stackPtr)\n\
 | 
      
         | 1389 |  |  |         ld r15, @r1             ; setup local stack (protect user stack)\n\
 | 
      
         | 1390 |  |  |         mv r0, %0\n\
 | 
      
         | 1391 |  |  |         bl handle_exception\n\
 | 
      
         | 1392 |  |  |         bl restore_and_return"::"r" (num):"r0", "r1");
 | 
      
         | 1393 |  |  | }
 | 
      
         | 1394 |  |  |  
 | 
      
         | 1395 |  |  | void _catchException0 ();
 | 
      
         | 1396 |  |  |  
 | 
      
         | 1397 |  |  | asm ("\n\
 | 
      
         | 1398 |  |  | _catchException0:\n\
 | 
      
         | 1399 |  |  |         push lr\n\
 | 
      
         | 1400 |  |  |         bl stash_registers\n\
 | 
      
         | 1401 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1402 |  |  |         ldi r0, #0\n\
 | 
      
         | 1403 |  |  |         bl process_exception");
 | 
      
         | 1404 |  |  |  
 | 
      
         | 1405 |  |  | void _catchException1 ();
 | 
      
         | 1406 |  |  |  
 | 
      
         | 1407 |  |  | asm ("\n\
 | 
      
         | 1408 |  |  | _catchException1:\n\
 | 
      
         | 1409 |  |  |         push lr\n\
 | 
      
         | 1410 |  |  |         bl stash_registers\n\
 | 
      
         | 1411 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1412 |  |  |         bl cleanup_stash\n\
 | 
      
         | 1413 |  |  |         seth r1, #shigh(stackPtr)\n\
 | 
      
         | 1414 |  |  |         add3 r1, r1, #low(stackPtr)\n\
 | 
      
         | 1415 |  |  |         ld r15, @r1             ; setup local stack (protect user stack)\n\
 | 
      
         | 1416 |  |  |         seth r1, #shigh(registers + 21*4) ; PC\n\
 | 
      
         | 1417 |  |  |         add3 r1, r1, #low(registers + 21*4)\n\
 | 
      
         | 1418 |  |  |         ld r0, @r1\n\
 | 
      
         | 1419 |  |  |         addi r0, #-4            ; back up PC for breakpoint trap.\n\
 | 
      
         | 1420 |  |  |         st r0, @r1              ; FIXME: what about bp in right slot?\n\
 | 
      
         | 1421 |  |  |         ldi r0, #1\n\
 | 
      
         | 1422 |  |  |         bl handle_exception\n\
 | 
      
         | 1423 |  |  |         bl restore_and_return");
 | 
      
         | 1424 |  |  |  
 | 
      
         | 1425 |  |  | void _catchException2 ();
 | 
      
         | 1426 |  |  |  
 | 
      
         | 1427 |  |  | asm ("\n\
 | 
      
         | 1428 |  |  | _catchException2:\n\
 | 
      
         | 1429 |  |  |         push lr\n\
 | 
      
         | 1430 |  |  |         bl stash_registers\n\
 | 
      
         | 1431 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1432 |  |  |         ldi r0, #2\n\
 | 
      
         | 1433 |  |  |         bl process_exception");
 | 
      
         | 1434 |  |  |  
 | 
      
         | 1435 |  |  | void _catchException3 ();
 | 
      
         | 1436 |  |  |  
 | 
      
         | 1437 |  |  | asm ("\n\
 | 
      
         | 1438 |  |  | _catchException3:\n\
 | 
      
         | 1439 |  |  |         push lr\n\
 | 
      
         | 1440 |  |  |         bl stash_registers\n\
 | 
      
         | 1441 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1442 |  |  |         ldi r0, #3\n\
 | 
      
         | 1443 |  |  |         bl process_exception");
 | 
      
         | 1444 |  |  |  
 | 
      
         | 1445 |  |  | void _catchException4 ();
 | 
      
         | 1446 |  |  |  
 | 
      
         | 1447 |  |  | asm ("\n\
 | 
      
         | 1448 |  |  | _catchException4:\n\
 | 
      
         | 1449 |  |  |         push lr\n\
 | 
      
         | 1450 |  |  |         bl stash_registers\n\
 | 
      
         | 1451 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1452 |  |  |         ldi r0, #4\n\
 | 
      
         | 1453 |  |  |         bl process_exception");
 | 
      
         | 1454 |  |  |  
 | 
      
         | 1455 |  |  | void _catchException5 ();
 | 
      
         | 1456 |  |  |  
 | 
      
         | 1457 |  |  | asm ("\n\
 | 
      
         | 1458 |  |  | _catchException5:\n\
 | 
      
         | 1459 |  |  |         push lr\n\
 | 
      
         | 1460 |  |  |         bl stash_registers\n\
 | 
      
         | 1461 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1462 |  |  |         ldi r0, #5\n\
 | 
      
         | 1463 |  |  |         bl process_exception");
 | 
      
         | 1464 |  |  |  
 | 
      
         | 1465 |  |  | void _catchException6 ();
 | 
      
         | 1466 |  |  |  
 | 
      
         | 1467 |  |  | asm ("\n\
 | 
      
         | 1468 |  |  | _catchException6:\n\
 | 
      
         | 1469 |  |  |         push lr\n\
 | 
      
         | 1470 |  |  |         bl stash_registers\n\
 | 
      
         | 1471 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1472 |  |  |         ldi r0, #6\n\
 | 
      
         | 1473 |  |  |         bl process_exception");
 | 
      
         | 1474 |  |  |  
 | 
      
         | 1475 |  |  | void _catchException7 ();
 | 
      
         | 1476 |  |  |  
 | 
      
         | 1477 |  |  | asm ("\n\
 | 
      
         | 1478 |  |  | _catchException7:\n\
 | 
      
         | 1479 |  |  |         push lr\n\
 | 
      
         | 1480 |  |  |         bl stash_registers\n\
 | 
      
         | 1481 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1482 |  |  |         ldi r0, #7\n\
 | 
      
         | 1483 |  |  |         bl process_exception");
 | 
      
         | 1484 |  |  |  
 | 
      
         | 1485 |  |  | void _catchException8 ();
 | 
      
         | 1486 |  |  |  
 | 
      
         | 1487 |  |  | asm ("\n\
 | 
      
         | 1488 |  |  | _catchException8:\n\
 | 
      
         | 1489 |  |  |         push lr\n\
 | 
      
         | 1490 |  |  |         bl stash_registers\n\
 | 
      
         | 1491 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1492 |  |  |         ldi r0, #8\n\
 | 
      
         | 1493 |  |  |         bl process_exception");
 | 
      
         | 1494 |  |  |  
 | 
      
         | 1495 |  |  | void _catchException9 ();
 | 
      
         | 1496 |  |  |  
 | 
      
         | 1497 |  |  | asm ("\n\
 | 
      
         | 1498 |  |  | _catchException9:\n\
 | 
      
         | 1499 |  |  |         push lr\n\
 | 
      
         | 1500 |  |  |         bl stash_registers\n\
 | 
      
         | 1501 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1502 |  |  |         ldi r0, #9\n\
 | 
      
         | 1503 |  |  |         bl process_exception");
 | 
      
         | 1504 |  |  |  
 | 
      
         | 1505 |  |  | void _catchException10 ();
 | 
      
         | 1506 |  |  |  
 | 
      
         | 1507 |  |  | asm ("\n\
 | 
      
         | 1508 |  |  | _catchException10:\n\
 | 
      
         | 1509 |  |  |         push lr\n\
 | 
      
         | 1510 |  |  |         bl stash_registers\n\
 | 
      
         | 1511 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1512 |  |  |         ldi r0, #10\n\
 | 
      
         | 1513 |  |  |         bl process_exception");
 | 
      
         | 1514 |  |  |  
 | 
      
         | 1515 |  |  | void _catchException11 ();
 | 
      
         | 1516 |  |  |  
 | 
      
         | 1517 |  |  | asm ("\n\
 | 
      
         | 1518 |  |  | _catchException11:\n\
 | 
      
         | 1519 |  |  |         push lr\n\
 | 
      
         | 1520 |  |  |         bl stash_registers\n\
 | 
      
         | 1521 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1522 |  |  |         ldi r0, #11\n\
 | 
      
         | 1523 |  |  |         bl process_exception");
 | 
      
         | 1524 |  |  |  
 | 
      
         | 1525 |  |  | void _catchException12 ();
 | 
      
         | 1526 |  |  |  
 | 
      
         | 1527 |  |  | asm ("\n\
 | 
      
         | 1528 |  |  | _catchException12:\n\
 | 
      
         | 1529 |  |  |         push lr\n\
 | 
      
         | 1530 |  |  |         bl stash_registers\n\
 | 
      
         | 1531 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1532 |  |  |         ldi r0, #12\n\
 | 
      
         | 1533 |  |  |         bl process_exception");
 | 
      
         | 1534 |  |  |  
 | 
      
         | 1535 |  |  | void _catchException13 ();
 | 
      
         | 1536 |  |  |  
 | 
      
         | 1537 |  |  | asm ("\n\
 | 
      
         | 1538 |  |  | _catchException13:\n\
 | 
      
         | 1539 |  |  |         push lr\n\
 | 
      
         | 1540 |  |  |         bl stash_registers\n\
 | 
      
         | 1541 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1542 |  |  |         ldi r0, #13\n\
 | 
      
         | 1543 |  |  |         bl process_exception");
 | 
      
         | 1544 |  |  |  
 | 
      
         | 1545 |  |  | void _catchException14 ();
 | 
      
         | 1546 |  |  |  
 | 
      
         | 1547 |  |  | asm ("\n\
 | 
      
         | 1548 |  |  | _catchException14:\n\
 | 
      
         | 1549 |  |  |         push lr\n\
 | 
      
         | 1550 |  |  |         bl stash_registers\n\
 | 
      
         | 1551 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1552 |  |  |         ldi r0, #14\n\
 | 
      
         | 1553 |  |  |         bl process_exception");
 | 
      
         | 1554 |  |  |  
 | 
      
         | 1555 |  |  | void _catchException15 ();
 | 
      
         | 1556 |  |  |  
 | 
      
         | 1557 |  |  | asm ("\n\
 | 
      
         | 1558 |  |  | _catchException15:\n\
 | 
      
         | 1559 |  |  |         push lr\n\
 | 
      
         | 1560 |  |  |         bl stash_registers\n\
 | 
      
         | 1561 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1562 |  |  |         ldi r0, #15\n\
 | 
      
         | 1563 |  |  |         bl process_exception");
 | 
      
         | 1564 |  |  |  
 | 
      
         | 1565 |  |  | void _catchException16 ();
 | 
      
         | 1566 |  |  |  
 | 
      
         | 1567 |  |  | asm ("\n\
 | 
      
         | 1568 |  |  | _catchException16:\n\
 | 
      
         | 1569 |  |  |         push lr\n\
 | 
      
         | 1570 |  |  |         bl stash_registers\n\
 | 
      
         | 1571 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1572 |  |  |         ldi r0, #16\n\
 | 
      
         | 1573 |  |  |         bl process_exception");
 | 
      
         | 1574 |  |  |  
 | 
      
         | 1575 |  |  | void _catchException17 ();
 | 
      
         | 1576 |  |  |  
 | 
      
         | 1577 |  |  | asm ("\n\
 | 
      
         | 1578 |  |  | _catchException17:\n\
 | 
      
         | 1579 |  |  |         push lr\n\
 | 
      
         | 1580 |  |  |         bl stash_registers\n\
 | 
      
         | 1581 |  |  |         ; Note that at this point the pushed value of `lr' has been popped\n\
 | 
      
         | 1582 |  |  |         ldi r0, #17\n\
 | 
      
         | 1583 |  |  |         bl process_exception");
 | 
      
         | 1584 |  |  |  
 | 
      
         | 1585 |  |  |  
 | 
      
         | 1586 |  |  | /* this function is used to set up exception handlers for tracing and
 | 
      
         | 1587 |  |  |    breakpoints */
 | 
      
         | 1588 |  |  | void
 | 
      
         | 1589 |  |  | set_debug_traps (void)
 | 
      
         | 1590 |  |  | {
 | 
      
         | 1591 |  |  |   /*  extern void remcomHandler(); */
 | 
      
         | 1592 |  |  |   int i;
 | 
      
         | 1593 |  |  |  
 | 
      
         | 1594 |  |  |   for (i = 0; i < 18; i++)       /* keep a copy of old vectors */
 | 
      
         | 1595 |  |  |     if (save_vectors[i] == 0)    /* only copy them the first time */
 | 
      
         | 1596 |  |  |       save_vectors[i] = getExceptionHandler (i);
 | 
      
         | 1597 |  |  |  
 | 
      
         | 1598 |  |  |   stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
 | 
      
         | 1599 |  |  |  
 | 
      
         | 1600 |  |  |   exceptionHandler (0, _catchException0);
 | 
      
         | 1601 |  |  |   exceptionHandler (1, _catchException1);
 | 
      
         | 1602 |  |  |   exceptionHandler (2, _catchException2);
 | 
      
         | 1603 |  |  |   exceptionHandler (3, _catchException3);
 | 
      
         | 1604 |  |  |   exceptionHandler (4, _catchException4);
 | 
      
         | 1605 |  |  |   exceptionHandler (5, _catchException5);
 | 
      
         | 1606 |  |  |   exceptionHandler (6, _catchException6);
 | 
      
         | 1607 |  |  |   exceptionHandler (7, _catchException7);
 | 
      
         | 1608 |  |  |   exceptionHandler (8, _catchException8);
 | 
      
         | 1609 |  |  |   exceptionHandler (9, _catchException9);
 | 
      
         | 1610 |  |  |   exceptionHandler (10, _catchException10);
 | 
      
         | 1611 |  |  |   exceptionHandler (11, _catchException11);
 | 
      
         | 1612 |  |  |   exceptionHandler (12, _catchException12);
 | 
      
         | 1613 |  |  |   exceptionHandler (13, _catchException13);
 | 
      
         | 1614 |  |  |   exceptionHandler (14, _catchException14);
 | 
      
         | 1615 |  |  |   exceptionHandler (15, _catchException15);
 | 
      
         | 1616 |  |  |   exceptionHandler (16, _catchException16);
 | 
      
         | 1617 |  |  |   /*  exceptionHandler (17, _catchException17); */
 | 
      
         | 1618 |  |  |  
 | 
      
         | 1619 |  |  |   initialized = 1;
 | 
      
         | 1620 |  |  | }
 | 
      
         | 1621 |  |  |  
 | 
      
         | 1622 |  |  | /* This function will generate a breakpoint exception.  It is used at the
 | 
      
         | 1623 |  |  |    beginning of a program to sync up with a debugger and can be used
 | 
      
         | 1624 |  |  |    otherwise as a quick means to stop program execution and "break" into
 | 
      
         | 1625 |  |  |    the debugger. */
 | 
      
         | 1626 |  |  |  
 | 
      
         | 1627 |  |  | #define BREAKPOINT() asm volatile ("    trap #2");
 | 
      
         | 1628 |  |  |  
 | 
      
         | 1629 |  |  | void
 | 
      
         | 1630 |  |  | breakpoint (void)
 | 
      
         | 1631 |  |  | {
 | 
      
         | 1632 |  |  |   if (initialized)
 | 
      
         | 1633 |  |  |     BREAKPOINT ();
 | 
      
         | 1634 |  |  | }
 | 
      
         | 1635 |  |  |  
 | 
      
         | 1636 |  |  | /* STDOUT section:
 | 
      
         | 1637 |  |  |    Stuff pertaining to simulating stdout by sending chars to gdb to be echoed.
 | 
      
         | 1638 |  |  |    Functions: gdb_putchar(char ch)
 | 
      
         | 1639 |  |  |               gdb_puts(char *str)
 | 
      
         | 1640 |  |  |               gdb_write(char *str, int len)
 | 
      
         | 1641 |  |  |               gdb_error(char *format, char *parm)
 | 
      
         | 1642 |  |  |               */
 | 
      
         | 1643 |  |  |  
 | 
      
         | 1644 |  |  | /* Function: gdb_putchar(int)
 | 
      
         | 1645 |  |  |    Make gdb write a char to stdout.
 | 
      
         | 1646 |  |  |    Returns: the char */
 | 
      
         | 1647 |  |  |  
 | 
      
         | 1648 |  |  | static int
 | 
      
         | 1649 |  |  | gdb_putchar (int ch)
 | 
      
         | 1650 |  |  | {
 | 
      
         | 1651 |  |  |   char buf[4];
 | 
      
         | 1652 |  |  |  
 | 
      
         | 1653 |  |  |   buf[0] = 'O';
 | 
      
         | 1654 |  |  |   buf[1] = hexchars[ch >> 4];
 | 
      
         | 1655 |  |  |   buf[2] = hexchars[ch & 0x0F];
 | 
      
         | 1656 |  |  |   buf[3] = 0;
 | 
      
         | 1657 |  |  |   putpacket (buf);
 | 
      
         | 1658 |  |  |   return ch;
 | 
      
         | 1659 |  |  | }
 | 
      
         | 1660 |  |  |  
 | 
      
         | 1661 |  |  | /* Function: gdb_write(char *, int)
 | 
      
         | 1662 |  |  |    Make gdb write n bytes to stdout (not assumed to be null-terminated).
 | 
      
         | 1663 |  |  |    Returns: number of bytes written */
 | 
      
         | 1664 |  |  |  
 | 
      
         | 1665 |  |  | static int
 | 
      
         | 1666 |  |  | gdb_write (char *data, int len)
 | 
      
         | 1667 |  |  | {
 | 
      
         | 1668 |  |  |   char *buf, *cpy;
 | 
      
         | 1669 |  |  |   int i;
 | 
      
         | 1670 |  |  |  
 | 
      
         | 1671 |  |  |   buf = remcomOutBuffer;
 | 
      
         | 1672 |  |  |   buf[0] = 'O';
 | 
      
         | 1673 |  |  |   i = 0;
 | 
      
         | 1674 |  |  |   while (i < len)
 | 
      
         | 1675 |  |  |     {
 | 
      
         | 1676 |  |  |       for (cpy = buf + 1;
 | 
      
         | 1677 |  |  |            i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++)
 | 
      
         | 1678 |  |  |         {
 | 
      
         | 1679 |  |  |           *cpy++ = hexchars[data[i] >> 4];
 | 
      
         | 1680 |  |  |           *cpy++ = hexchars[data[i] & 0x0F];
 | 
      
         | 1681 |  |  |         }
 | 
      
         | 1682 |  |  |       *cpy = 0;
 | 
      
         | 1683 |  |  |       putpacket (buf);
 | 
      
         | 1684 |  |  |     }
 | 
      
         | 1685 |  |  |   return len;
 | 
      
         | 1686 |  |  | }
 | 
      
         | 1687 |  |  |  
 | 
      
         | 1688 |  |  | /* Function: gdb_puts(char *)
 | 
      
         | 1689 |  |  |    Make gdb write a null-terminated string to stdout.
 | 
      
         | 1690 |  |  |    Returns: the length of the string */
 | 
      
         | 1691 |  |  |  
 | 
      
         | 1692 |  |  | static int
 | 
      
         | 1693 |  |  | gdb_puts (char *str)
 | 
      
         | 1694 |  |  | {
 | 
      
         | 1695 |  |  |   return gdb_write (str, strlen (str));
 | 
      
         | 1696 |  |  | }
 | 
      
         | 1697 |  |  |  
 | 
      
         | 1698 |  |  | /* Function: gdb_error(char *, char *)
 | 
      
         | 1699 |  |  |    Send an error message to gdb's stdout.
 | 
      
         | 1700 |  |  |    First string may have 1 (one) optional "%s" in it, which
 | 
      
         | 1701 |  |  |    will cause the optional second string to be inserted.  */
 | 
      
         | 1702 |  |  |  
 | 
      
         | 1703 |  |  | static void
 | 
      
         | 1704 |  |  | gdb_error (char *format, char *parm)
 | 
      
         | 1705 |  |  | {
 | 
      
         | 1706 |  |  |   char buf[400], *cpy;
 | 
      
         | 1707 |  |  |   int len;
 | 
      
         | 1708 |  |  |  
 | 
      
         | 1709 |  |  |   if (remote_debug)
 | 
      
         | 1710 |  |  |     {
 | 
      
         | 1711 |  |  |       if (format && *format)
 | 
      
         | 1712 |  |  |         len = strlen (format);
 | 
      
         | 1713 |  |  |       else
 | 
      
         | 1714 |  |  |         return;                 /* empty input */
 | 
      
         | 1715 |  |  |  
 | 
      
         | 1716 |  |  |       if (parm && *parm)
 | 
      
         | 1717 |  |  |         len += strlen (parm);
 | 
      
         | 1718 |  |  |  
 | 
      
         | 1719 |  |  |       for (cpy = buf; *format;)
 | 
      
         | 1720 |  |  |         {
 | 
      
         | 1721 |  |  |           if (format[0] == '%' && format[1] == 's')      /* include second string */
 | 
      
         | 1722 |  |  |             {
 | 
      
         | 1723 |  |  |               format += 2;      /* advance two chars instead of just one */
 | 
      
         | 1724 |  |  |               while (parm && *parm)
 | 
      
         | 1725 |  |  |                 *cpy++ = *parm++;
 | 
      
         | 1726 |  |  |             }
 | 
      
         | 1727 |  |  |           else
 | 
      
         | 1728 |  |  |             *cpy++ = *format++;
 | 
      
         | 1729 |  |  |         }
 | 
      
         | 1730 |  |  |       *cpy = '\0';
 | 
      
         | 1731 |  |  |       gdb_puts (buf);
 | 
      
         | 1732 |  |  |     }
 | 
      
         | 1733 |  |  | }
 | 
      
         | 1734 |  |  |  
 | 
      
         | 1735 |  |  | static unsigned char *
 | 
      
         | 1736 |  |  | strcpy (unsigned char *dest, const unsigned char *src)
 | 
      
         | 1737 |  |  | {
 | 
      
         | 1738 |  |  |   unsigned char *ret = dest;
 | 
      
         | 1739 |  |  |  
 | 
      
         | 1740 |  |  |   if (dest && src)
 | 
      
         | 1741 |  |  |     {
 | 
      
         | 1742 |  |  |       while (*src)
 | 
      
         | 1743 |  |  |         *dest++ = *src++;
 | 
      
         | 1744 |  |  |       *dest = 0;
 | 
      
         | 1745 |  |  |     }
 | 
      
         | 1746 |  |  |   return ret;
 | 
      
         | 1747 |  |  | }
 | 
      
         | 1748 |  |  |  
 | 
      
         | 1749 |  |  | static int
 | 
      
         | 1750 |  |  | strlen (const unsigned char *src)
 | 
      
         | 1751 |  |  | {
 | 
      
         | 1752 |  |  |   int ret;
 | 
      
         | 1753 |  |  |  
 | 
      
         | 1754 |  |  |   for (ret = 0; *src; src++)
 | 
      
         | 1755 |  |  |     ret++;
 | 
      
         | 1756 |  |  |  
 | 
      
         | 1757 |  |  |   return ret;
 | 
      
         | 1758 |  |  | }
 | 
      
         | 1759 |  |  |  
 | 
      
         | 1760 |  |  | #if 0
 | 
      
         | 1761 |  |  | void
 | 
      
         | 1762 |  |  | exit (code)
 | 
      
         | 1763 |  |  |      int code;
 | 
      
         | 1764 |  |  | {
 | 
      
         | 1765 |  |  |   _exit (code);
 | 
      
         | 1766 |  |  | }
 | 
      
         | 1767 |  |  |  
 | 
      
         | 1768 |  |  | int
 | 
      
         | 1769 |  |  | atexit (void *p)
 | 
      
         | 1770 |  |  | {
 | 
      
         | 1771 |  |  |   return 0;
 | 
      
         | 1772 |  |  | }
 | 
      
         | 1773 |  |  |  
 | 
      
         | 1774 |  |  | void
 | 
      
         | 1775 |  |  | abort (void)
 | 
      
         | 1776 |  |  | {
 | 
      
         | 1777 |  |  |   _exit (1);
 | 
      
         | 1778 |  |  | }
 | 
      
         | 1779 |  |  | #endif
 |