source: rtems/c/src/lib/libbsp/mips/shared/gdbstub/mips-stub.c @ 45477a3

4.104.114.84.95
Last change on this file since 45477a3 was 45477a3, checked in by Joel Sherrill <joel.sherrill@…>, on 07/17/03 at 21:59:42

2003-07-17 Joel Sherrill <joel@…>

PR 433/tools

  • mips-stub.c: Patch from C. M. Heard <heard@…> described as:

The purpose of the patch is to make the stub ignore all
characters except '+' (ack) or '-' (nak) when it has transmitted a
packet and expects an acknowledgment. Without the patch,
putpacket() will retransmit each time it receives anything other
than '+' when expecting an ack, and that, bitter experience has
found, frequently results in the stub failing to sync up when
initially attaching to gdb.

I think that rtems users will notice significant improvement in
the of the mips stub if this patch is incorporated in the
distribution; certainly I did in my stand-aline environment. I
should hasten to add that it is only an improvement and not a 100%
cure for synchronization problems because '+' characters can (and
do) during as message data, and it's still possible for these to
be mistaken as acks. I have no idea how to fix that short of
redesigning the gdb-remote protocol.

  • Property mode set to 100644
File size: 43.9 KB
Line 
1#define  GDB_STUB_ENABLE_THREAD_SUPPORT 1
2/*******************************************************************************
3
4                     THIS SOFTWARE IS NOT COPYRIGHTED
5
6    The following software is offered for use in the public domain.
7    There is no warranty with regard to this software or its performance
8    and the user must accept the software "AS IS" with all faults.
9
10    THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
11    REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
12    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13
14    $Id$
15
16********************************************************************************
17*
18*   r46kstub.c -- target debugging stub for the IDT R4600 Orion processor
19*
20*   This module is based on the stub for the Hitachi SH processor written by
21*   Ben Lee and Steve Chamberlain and supplied with gdb 4.16.  The latter
22*   in turn "is originally based on an m68k software stub written by Glenn
23*   Engel at HP, but has changed quite a bit."  The changes for the R4600
24*   were written by C. M. Heard at VVNET.  They were based in part on the
25*   Algorithmics R4000 version of Phil Bunce's PMON program.
26*
27*  Remote communication protocol:
28*
29*  A debug packet whose contents are <data>
30*  is encapsulated for transmission in the form:
31*
32*       $ <data> # CSUM1 CSUM2
33*
34*       <data> must be ASCII alphanumeric and cannot include characters
35*       '$' or '#'.  If <data> starts with two characters followed by
36*       ':', then the existing stubs interpret this as a sequence number.
37*
38*       CSUM1 and CSUM2 are ascii hex representation of an 8-bit
39*       checksum of <data>, the most significant nibble is sent first.
40*       the hex digits 0-9,a-f are used.
41*
42*  Receiver responds with:
43*
44*       +    if CSUM is correct
45*       -    if CSUM is incorrect
46*
47*  <data> is as follows.  All values are encoded in ascii hex digits.
48*
49*       Request         Packet
50*
51*       read registers  g
52*       reply           XX....X         Each byte of register data
53*                                       is described by two hex digits.
54*                                       Registers are in the internal order
55*                                       for GDB, and the bytes in a register
56*                                       are in the same order the machine uses.
57*                       or ENN          for an error.
58*
59*       write regs      GXX..XX         Each byte of register data
60*                                       is described by two hex digits.
61*       reply           OK              for success
62*                       ENN             for an error
63*
64*       write reg       Pn...=r...      Write register n... with value r....
65*       reply           OK              for success
66*                       ENN             for an error
67*
68*       read mem        mAA..AA,LLLL    AA..AA is address, LLLL is length.
69*       reply           XX..XX          XX..XX is mem contents
70*                                       Can be fewer bytes than requested
71*                                       if able to read only part of the data.
72*                       or ENN          NN is errno
73*
74*       write mem       MAA..AA,LLLL:XX..XX
75*                                       AA..AA is address,
76*                                       LLLL is number of bytes,
77*                                       XX..XX is data
78*       reply           OK              for success
79*                       ENN             for an error (this includes the case
80*                                       where only part of the data was
81*                                       written).
82*
83*       cont            cAA..AA         AA..AA is address to resume
84*                                       If AA..AA is omitted,
85*                                       resume at same address.
86*
87*       step            sAA..AA         AA..AA is address to resume
88*                                       If AA..AA is omitted,
89*                                       resume at same address.
90*
91*       There is no immediate reply to step or cont.
92*       The reply comes when the machine stops.
93*       It is           SAA             AA is the "signal number"
94*
95*       last signal     ?               Reply with the reason for stopping.
96*                                       This is the same reply as is generated
97*                                       for step or cont: SAA where AA is the
98*                                       signal number.
99*
100*       detach          D               Host is detaching.  Reply OK and
101*                                       end remote debugging session.
102*
103*       reserved        <other>         On other requests, the stub should
104*                                       ignore the request and send an empty
105*                                       response ($#<checksum>).  This way
106*                                       we can extend the protocol and GDB
107*                                       can tell whether the stub it is
108*                                       talking to uses the old or the new.
109*
110*       Responses can be run-length encoded to save space.  A '*' means that
111*       the next character is an ASCII encoding giving a repeat count which
112*       stands for that many repetitions of the character preceding the '*'.
113*       The encoding is n+29, yielding a printable character when n >=3
114*       (which is where rle starts to win).  Don't use n > 99 since gdb
115*       masks each character is receives with 0x7f in order to strip off
116*       the parity bit.
117*
118*       As an example, "0* " means the same thing as "0000".
119*
120*******************************************************************************/
121
122
123#include <string.h>
124#include <signal.h>
125#include "mips_opcode.h"
126/* #include "memlimits.h" */
127#include <rtems.h>
128#include "gdb_if.h"
129
130extern int printk(const char *fmt, ...);
131
132/* Change it to something meaningful when debugging */
133#undef ASSERT
134#define ASSERT(x) if(!(x)) printk("ASSERT: stub: %d\n", __LINE__)
135
136/***************/
137/* Exception Codes */
138#define EXC_INT         0               /* External interrupt */
139#define EXC_MOD         1               /* TLB modification exception */
140#define EXC_TLBL        2               /* TLB miss (Load or Ifetch) */
141#define EXC_TLBS        3               /* TLB miss (Store) */
142#define EXC_ADEL        4               /* Address error (Load or Ifetch) */
143#define EXC_ADES        5               /* Address error (Store) */
144#define EXC_IBE         6               /* Bus error (Ifetch) */
145#define EXC_DBE         7               /* Bus error (data load or store) */
146#define EXC_SYS         8               /* System call */
147#define EXC_BP          9               /* Break point */
148#define EXC_RI          10              /* Reserved instruction */
149#define EXC_CPU         11              /* Coprocessor unusable */
150#define EXC_OVF         12              /* Arithmetic overflow */
151#define EXC_TRAP        13              /* Trap exception */
152#define EXC_FPE         15              /* Floating Point Exception */
153
154/* FPU Control/Status register fields */
155#define CSR_FS          0x01000000      /* Set to flush denormals to zero */
156#define CSR_C           0x00800000      /* Condition bit (set by FP compare) */
157
158#define CSR_CMASK       (0x3f<<12)
159#define CSR_CE          0x00020000
160#define CSR_CV          0x00010000
161#define CSR_CZ          0x00008000
162#define CSR_CO          0x00004000
163#define CSR_CU          0x00002000
164#define CSR_CI          0x00001000
165
166#define CSR_EMASK       (0x1f<<7)
167#define CSR_EV          0x00000800
168#define CSR_EZ          0x00000400
169#define CSR_EO          0x00000200
170#define CSR_EU          0x00000100
171#define CSR_EI          0x00000080
172
173#define CSR_FMASK       (0x1f<<2)
174#define CSR_FV          0x00000040
175#define CSR_FZ          0x00000020
176#define CSR_FO          0x00000010
177#define CSR_FU          0x00000008
178#define CSR_FI          0x00000004
179
180#define CSR_RMODE_MASK  (0x3<<0)
181#define CSR_RM          0x00000003
182#define CSR_RP          0x00000002
183#define CSR_RZ          0x00000001
184#define CSR_RN          0x00000000
185
186/***************/
187
188/*
189 * Saved register information.  Must be prepared by the exception
190 * preprocessor before handle_exception is invoked.
191 */
192#if (__mips == 3)
193typedef long long mips_register_t;
194#define R_SZ 8
195#elif (__mips == 1)
196typedef unsigned int mips_register_t;
197#define R_SZ 4
198#else
199#error "unknown MIPS ISA"
200#endif
201static mips_register_t *registers;
202
203#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
204static char do_threads;      /* != 0 means we are supporting threads */
205#endif
206
207/*
208 * The following external functions provide character input and output.
209 */
210extern char getDebugChar (void);
211extern void putDebugChar (char);
212
213
214
215/*
216 * The following definitions are used for the gdb stub memory map
217 */
218struct memseg
219{
220      unsigned begin, end, opts;
221};
222
223static int is_readable(unsigned,unsigned);
224static int is_writeable(unsigned,unsigned);
225static int is_steppable(unsigned);
226
227
228
229
230
231
232/*
233 * BUFMAX defines the maximum number of characters in the inbound & outbound
234 * packet buffers.  At least 4+(sizeof registers)*2 bytes will be needed for
235 * register packets.  Memory dump packets can profitably use even more.
236 */
237#define BUFMAX 1500
238
239static char inBuffer[BUFMAX];
240static char outBuffer[BUFMAX];
241
242/* Structure to keep info on a z-breaks */
243#define BREAKNUM 32
244
245struct z0break
246{
247  /* List support */
248  struct z0break *next;
249  struct z0break *prev;
250
251  /* Location, preserved data */
252
253  /* the address pointer, really, really must be a pointer to
254  ** a 32 bit quantity (likely 64 on the R4k), so the full instruction is read &
255  ** written.  Making it a char * as on the i386 will cause
256  ** the zbreaks to mess up the breakpoint instructions
257  */
258  unsigned *address;
259  unsigned instr;
260};
261
262static struct z0break z0break_arr[BREAKNUM];
263static struct z0break *z0break_avail = NULL;
264static struct z0break *z0break_list  = NULL;
265
266
267/*
268 * Convert an int to hex.
269 */
270const char gdb_hexchars[] = "0123456789abcdef";
271
272#define highhex(x) gdb_hexchars [(x >> 4) & 0xf]
273#define lowhex(x) gdb_hexchars [x & 0xf]
274
275
276/*
277 * Convert length bytes of data starting at addr into hex, placing the
278 * result in buf.  Return a pointer to the last (null) char in buf.
279 */
280static char *
281mem2hex (void *_addr, int length, char *buf)
282{
283  unsigned int addr = (unsigned int) _addr;
284
285  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
286    {
287      long long *source = (long long *) (addr);
288      long long *limit  = (long long *) (addr + length);
289
290      while (source < limit)
291        {
292          int i;
293          long long k = *source++;
294
295          for (i = 15; i >= 0; i--)
296            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
297        }
298    }
299  else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
300    {
301      int *source = (int *) (addr);
302      int *limit  = (int *) (addr + length);
303
304      while (source < limit)
305        {
306          int i;
307          int k = *source++;
308
309          for (i = 7; i >= 0; i--)
310            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
311        }
312    }
313  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
314    {
315      short *source = (short *) (addr);
316      short *limit  = (short *) (addr + length);
317
318      while (source < limit)
319        {
320          int i;
321          short k = *source++;
322
323          for (i = 3; i >= 0; i--)
324            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
325        }
326    }
327  else                                                   /* byte aligned */
328    {
329      char *source = (char *) (addr);
330      char *limit  = (char *) (addr + length);
331
332      while (source < limit)
333        {
334          int i;
335          char k = *source++;
336
337          for (i = 1; i >= 0; i--)
338            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
339        }
340    }
341
342  *buf = '\0';
343  return (buf);
344}
345
346
347/*
348 * Convert a hex character to an int.
349 */
350static int
351hex (char ch)
352{
353  if ((ch >= 'a') && (ch <= 'f'))
354    return (ch - 'a' + 10);
355  if ((ch >= '0') && (ch <= '9'))
356    return (ch - '0');
357  if ((ch >= 'A') && (ch <= 'F'))
358    return (ch - 'A' + 10);
359  return (-1);
360}
361
362
363/*
364 * Convert a string from hex to int until a non-hex digit
365 * is found.  Return the number of characters processed.
366 */
367static int
368hexToInt (char **ptr, int *intValue)
369{
370  int numChars = 0;
371  int hexValue;
372
373  *intValue = 0;
374
375  while (**ptr)
376    {
377      hexValue = hex (**ptr);
378      if (hexValue >= 0)
379        {
380          *intValue = (*intValue << 4) | hexValue;
381          numChars++;
382        }
383      else
384        break;
385
386      (*ptr)++;
387    }
388
389  return (numChars);
390}
391
392
393/*
394 * Convert a string from hex to long long until a non-hex
395 * digit is found.  Return the number of characters processed.
396 */
397static int
398hexToLongLong (char **ptr, long long *intValue)
399{
400  int numChars = 0;
401  int hexValue;
402
403  *intValue = 0;
404
405  while (**ptr)
406    {
407      hexValue = hex (**ptr);
408      if (hexValue >= 0)
409        {
410          *intValue = (*intValue << 4) | hexValue;
411          numChars++;
412        }
413      else
414        break;
415
416      (*ptr)++;
417    }
418
419  return (numChars);
420}
421
422
423/*
424 * Convert the hex array buf into binary, placing the result at the
425 * specified address.  If the conversion fails at any point (i.e.,
426 * if fewer bytes are written than indicated by the size parameter)
427 * then return 0;  otherwise return 1.
428 */
429static int
430hex2mem (char *buf, void *_addr, int length)
431{
432  unsigned int addr = (unsigned int) _addr;
433  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
434    {
435      long long *target = (long long *) (addr);
436      long long *limit  = (long long *) (addr + length);
437
438      while (target < limit)
439        {
440          int i, j;
441          long long k = 0;
442
443          for (i = 0; i < 16; i++)
444            if ((j = hex(*buf++)) < 0)
445              return 0;
446            else
447              k = (k << 4) + j;
448          *target++ = k;
449        }
450    }
451  else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
452    {
453      int *target = (int *) (addr);
454      int *limit  = (int *) (addr + length);
455
456      while (target < limit)
457        {
458          int i, j;
459          int k = 0;
460
461          for (i = 0; i < 8; i++)
462            if ((j = hex(*buf++)) < 0)
463              return 0;
464            else
465              k = (k << 4) + j;
466          *target++ = k;
467        }
468    }
469  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
470    {
471      short *target = (short *) (addr);
472      short *limit  = (short *) (addr + length);
473
474      while (target < limit)
475        {
476          int i, j;
477          short k = 0;
478
479          for (i = 0; i < 4; i++)
480            if ((j = hex(*buf++)) < 0)
481              return 0;
482            else
483              k = (k << 4) + j;
484          *target++ = k;
485        }
486    }
487  else                                                   /* byte aligned */
488    {
489      char *target = (char *) (addr);
490      char *limit  = (char *) (addr + length);
491
492      while (target < limit)
493        {
494          int i, j;
495          char k = 0;
496
497          for (i = 0; i < 2; i++)
498            if ((j = hex(*buf++)) < 0)
499              return 0;
500            else
501              k = (k << 4) + j;
502          *target++ = k;
503        }
504    }
505
506  return 1;
507}
508
509
510/* Convert the binary stream in BUF to memory.
511
512   Gdb will escape $, #, and the escape char (0x7d).
513   COUNT is the total number of bytes to write into
514   memory. */
515static unsigned char *
516bin2mem (
517  unsigned char *buf,
518  unsigned char *mem,
519  int   count
520)
521{
522  int i;
523
524  for (i = 0; i < count; i++) {
525      /* Check for any escaped characters. Be paranoid and
526         only unescape chars that should be escaped. */
527      if (*buf == 0x7d) {
528          switch (*(buf+1)) {
529            case 0x3:  /* # */
530            case 0x4:  /* $ */
531            case 0x5d: /* escape char */
532              buf++;
533              *buf |= 0x20;
534              break;
535            default:
536              /* nothing */
537              break;
538            }
539        }
540
541      *mem++ = *buf++;
542    }
543
544  return mem;
545}
546
547
548
549/*
550 * Scan the input stream for a sequence for the form $<data>#<checksum>.
551 */
552static void
553getpacket (char *buffer)
554{
555  unsigned char checksum;
556  unsigned char xmitcsum;
557  int i;
558  int count;
559  char ch;
560  do
561    {
562      /* wait around for the start character, ignore all other characters */
563      while ((ch = getDebugChar ()) != '$');
564      checksum = 0;
565      xmitcsum = -1;
566
567      count = 0;
568
569      /* now, read until a # or end of buffer is found */
570      while ( (count < BUFMAX-1) && ((ch = getDebugChar ()) != '#') )
571          checksum += (buffer[count++] = ch);
572
573      /* make sure that the buffer is null-terminated */
574      buffer[count] = '\0';
575
576      if (ch == '#')
577        {
578          xmitcsum = hex (getDebugChar ()) << 4;
579          xmitcsum += hex (getDebugChar ());
580          if (checksum != xmitcsum)
581            putDebugChar ('-'); /* failed checksum */
582          else
583            {
584              putDebugChar ('+');       /* successful transfer */
585              /* if a sequence char is present, reply the sequence ID */
586              if (buffer[2] == ':')
587                {
588                  putDebugChar (buffer[0]);
589                  putDebugChar (buffer[1]);
590                  /* remove sequence chars from buffer */
591                  for (i = 3; i <= count; i++)
592                    buffer[i - 3] = buffer[i];
593                }
594            }
595        }
596    }
597  while (checksum != xmitcsum);
598}
599
600
601/*
602 * Get a positive/negative acknowledgment for a transmitted packet.
603 */
604static char
605getAck (void)
606{
607  char c;
608
609  do
610    {
611      c = getDebugChar ();
612    }
613  while ((c != '+') && (c != '-'));
614
615  return c;
616}
617
618
619/*
620 * Send the packet in buffer and wait for a positive acknowledgement.
621 */
622static void
623putpacket (char *buffer)
624{
625  int checksum;
626
627  /* $<packet info>#<checksum> */
628  do
629    {
630      char *src = buffer;
631      putDebugChar ('$');
632      checksum = 0;
633
634      while (*src != '\0')
635        {
636          int runlen = 0;
637
638          /* Do run length encoding */
639          while ((src[runlen] == src[0]) && (runlen < 99))
640            runlen++;
641          if (runlen > 3)
642            {
643              int encode;
644              /* Got a useful amount */
645              putDebugChar (*src);
646              checksum += *src;
647              putDebugChar ('*');
648              checksum += '*';
649              checksum += (encode = (runlen - 4) + ' ');
650              putDebugChar (encode);
651              src += runlen;
652            }
653          else
654            {
655              putDebugChar (*src);
656              checksum += *src;
657              src++;
658             }
659        }
660
661      putDebugChar ('#');
662      putDebugChar (highhex (checksum));
663      putDebugChar (lowhex (checksum));
664    }
665  while  (getAck () != '+');
666}
667
668
669
670
671
672
673
674/*
675 * Saved instruction data for single step support
676 */
677static struct
678  {
679    unsigned *targetAddr;
680    unsigned savedInstr;
681  }
682instrBuffer;
683
684
685/*
686 * If a step breakpoint was planted restore the saved instruction.
687 */
688static void
689undoSStep (void)
690{
691  if (instrBuffer.targetAddr != NULL)
692    {
693      *instrBuffer.targetAddr = instrBuffer.savedInstr;
694      instrBuffer.targetAddr = NULL;
695    }
696  instrBuffer.savedInstr = NOP_INSTR;
697}
698
699
700/*
701 * If a single step is requested put a temporary breakpoint at the instruction
702 * which logically follows the next one to be executed.  If the next instruction
703 * is a branch instruction then skip the instruction in the delay slot.  NOTE:
704 * ERET instructions are NOT handled, as it is impossible to single-step through
705 * the exit code in an exception handler.  In addition, no attempt is made to
706 * do anything about BC0T and BC0F, since a condition bit for coprocessor 0
707 * is not defined on the R4600.  Finally, BC2T and BC2F are ignored since there
708 * is no coprocessor 2 on a 4600.
709 */
710static void
711doSStep (void)
712{
713   InstFmt inst;
714
715   instrBuffer.targetAddr = (unsigned *)(registers[PC]+4);    /* set default */
716
717   inst.word = *(unsigned *)registers[PC];     /* read the next instruction  */
718
719   switch (inst.RType.op) {                    /* override default if branch */
720      case OP_SPECIAL:
721         switch (inst.RType.func) {
722            case OP_JR:
723            case OP_JALR:
724               instrBuffer.targetAddr =
725                  (unsigned *)registers[inst.RType.rs];
726               break;
727         };
728         break;
729
730      case OP_REGIMM:
731         switch (inst.IType.rt) {
732            case OP_BLTZ:
733            case OP_BLTZL:
734            case OP_BLTZAL:
735            case OP_BLTZALL:
736               if (registers[inst.IType.rs] < 0 )
737                  instrBuffer.targetAddr =
738                     (unsigned *)(((signed short)inst.IType.imm<<2)
739                                  + (registers[PC]+4));
740               else
741                  instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
742               break;
743            case OP_BGEZ:
744            case OP_BGEZL:
745            case OP_BGEZAL:
746            case OP_BGEZALL:
747               if (registers[inst.IType.rs] >= 0 )
748                  instrBuffer.targetAddr =
749                     (unsigned *)(((signed short)inst.IType.imm<<2)
750                                  + (registers[PC]+4));
751               else
752                  instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
753               break;
754         };
755         break;
756
757      case OP_J:
758      case OP_JAL:
759         instrBuffer.targetAddr =
760            (unsigned *)((inst.JType.target<<2) + ((registers[PC]+4)&0xf0000000));
761         break;
762
763      case OP_BEQ:
764      case OP_BEQL:
765         if (registers[inst.IType.rs] == registers[inst.IType.rt])
766            instrBuffer.targetAddr =
767               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
768         else
769            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
770         break;
771      case OP_BNE:
772      case OP_BNEL:
773         if (registers[inst.IType.rs] != registers[inst.IType.rt])
774            instrBuffer.targetAddr =
775               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
776         else
777            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
778         break;
779      case OP_BLEZ:
780      case OP_BLEZL:
781         if (registers[inst.IType.rs] <= 0)
782            instrBuffer.targetAddr =
783               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
784         else
785            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
786         break;
787      case OP_BGTZ:
788      case OP_BGTZL:
789         if (registers[inst.IType.rs] > 0)
790            instrBuffer.targetAddr =
791               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
792         else
793            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
794         break;
795
796      case OP_COP1:
797         if (inst.RType.rs == OP_BC)
798            switch (inst.RType.rt) {
799               case COPz_BCF:
800               case COPz_BCFL:
801                  if (registers[FCSR] & CSR_C)
802                     instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
803                  else
804                     instrBuffer.targetAddr =
805                        (unsigned *)(((signed short)inst.IType.imm<<2)
806                                     + (registers[PC]+4));
807                  break;
808               case COPz_BCT:
809               case COPz_BCTL:
810                  if (registers[FCSR] & CSR_C)
811                     instrBuffer.targetAddr =
812                        (unsigned *)(((signed short)inst.IType.imm<<2)
813                                     + (registers[PC]+4));
814                  else
815                     instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
816                  break;
817            };
818         break;
819   }
820
821
822   if( is_steppable((unsigned)instrBuffer.targetAddr) && *(instrBuffer.targetAddr) != BREAK_INSTR )
823   {
824      instrBuffer.savedInstr = *instrBuffer.targetAddr;
825      *instrBuffer.targetAddr = BREAK_INSTR;
826   }
827   else
828   {
829      instrBuffer.targetAddr = NULL;
830      instrBuffer.savedInstr = NOP_INSTR;
831   }
832   return;
833}
834
835
836
837
838
839
840/*
841 * Translate the R4600 exception code into a Unix-compatible signal.
842 */
843static int
844computeSignal (void)
845{
846  int exceptionCode = (registers[CAUSE] & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
847
848  switch (exceptionCode)
849    {
850    case EXC_INT:
851      /* External interrupt */
852      return SIGINT;
853
854    case EXC_RI:
855      /* Reserved instruction */
856    case EXC_CPU:
857      /* Coprocessor unusable */
858      return SIGILL;
859
860    case EXC_BP:
861      /* Break point */
862      return SIGTRAP;
863
864    case EXC_OVF:
865      /* Arithmetic overflow */
866    case EXC_TRAP:
867      /* Trap exception */
868    case EXC_FPE:
869      /* Floating Point Exception */
870      return SIGFPE;
871
872    case EXC_IBE:
873      /* Bus error (Ifetch) */
874    case EXC_DBE:
875      /* Bus error (data load or store) */
876      return SIGBUS;
877
878    case EXC_MOD:
879      /* TLB modification exception */
880    case EXC_TLBL:
881      /* TLB miss (Load or Ifetch) */
882    case EXC_TLBS:
883      /* TLB miss (Store) */
884    case EXC_ADEL:
885      /* Address error (Load or Ifetch) */
886    case EXC_ADES:
887      /* Address error (Store) */
888      return SIGSEGV;
889
890    case EXC_SYS:
891      /* System call */
892      return SIGSYS;
893
894    default:
895      return SIGTERM;
896    }
897}
898
899/*
900 *  This support function prepares and sends the message containing the
901 *  basic information about this exception.
902 */
903
904void gdb_stub_report_exception_info(
905  rtems_vector_number vector,
906  CPU_Interrupt_frame *frame,
907  int                  thread
908)
909{
910   char *optr;
911   int sigval;
912
913   optr = outBuffer;
914   *optr++ = 'T';
915   sigval = computeSignal ();
916   *optr++ = highhex (sigval);
917   *optr++ = lowhex (sigval);
918
919   *optr++ = highhex(SP); /*gdb_hexchars[SP]; */
920   *optr++ = lowhex(SP);
921   *optr++ = ':';
922   optr    = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
923   *optr++ = ';';
924 
925   *optr++ = highhex(PC); /*gdb_hexchars[PC]; */
926   *optr++ = lowhex(PC);
927   *optr++ = ':';
928   optr    = mem2hstr(optr, (unsigned char *)&frame->epc, R_SZ );
929   *optr++ = ';';
930
931#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
932   if (do_threads)
933   {
934      *optr++ = 't';
935      *optr++ = 'h';
936      *optr++ = 'r';
937      *optr++ = 'e';
938      *optr++ = 'a';
939      *optr++ = 'd';
940      *optr++ = ':';
941      optr   = thread2vhstr(optr, thread);
942      *optr++ = ';';
943   }
944#endif
945   *optr++ = '\0';
946}
947
948
949
950
951/*
952 * Scratch frame used to retrieve contexts for different threads, so as
953 * not to disrupt our current context on the stack
954 */
955CPU_Interrupt_frame current_thread_registers;
956
957
958
959/*
960 * This function handles all exceptions.  It only does two things:
961 * it figures out why it was activated and tells gdb, and then it
962 * reacts to gdb's requests.
963 */
964
965
966void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
967{
968   int          host_has_detached = 0;
969   int          regno, addr, length;
970   char         *ptr;
971   int          current_thread;  /* current generic thread */
972   int          thread;          /* stopped thread: context exception happened in */
973
974   long long    regval;
975   void         *regptr;
976   int          binary;
977   
978
979   registers = (mips_register_t *)frame;
980
981   thread = 0;
982#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
983   if (do_threads) {
984      thread = rtems_gdb_stub_get_current_thread();
985   }
986#endif
987   current_thread = thread;
988
989
990   {
991      /* reapply all breakpoints regardless of how we came in */
992      struct z0break *z0, *zother;
993
994      for (zother=z0break_list; zother!=NULL; zother=zother->next)
995      {
996         if( zother->instr == 0xffffffff )
997         {
998            /* grab the instruction */
999            zother->instr = *(zother->address);
1000            /* and insert the breakpoint */
1001            *(zother->address) = BREAK_INSTR;
1002         }
1003      }
1004
1005
1006
1007      /* see if we're coming from a breakpoint */
1008      if( *((unsigned *)frame->epc) == BREAK_INSTR )
1009      {
1010         /* see if its one of our zbreaks */
1011         for (z0=z0break_list; z0!=NULL; z0=z0->next)
1012         {
1013            if( (unsigned)z0->address == frame->epc)
1014               break;
1015         }
1016         if( z0 )
1017         {
1018            /* restore the original instruction */
1019            *(z0->address) = z0->instr;
1020            /* flag the breakpoint */
1021            z0->instr = 0xffffffff;
1022
1023            /*
1024               now when we return, we'll execute the original code in
1025               the original state.  This leaves our breakpoint inactive
1026               since the break instruction isn't there, but we'll reapply
1027               it the next time we come in via step or breakpoint
1028            */
1029         }
1030         else
1031         {
1032            /* not a zbreak, see if its our trusty stepping code */
1033
1034            /*
1035             * Restore the saved instruction at
1036             * the single-step target address.
1037             */
1038            undoSStep();
1039         }
1040      }
1041   }
1042
1043
1044
1045
1046
1047   /* reply to host that an exception has occurred with some basic info */
1048   gdb_stub_report_exception_info(vector, frame, thread);
1049   putpacket (outBuffer);
1050
1051
1052
1053   while (!(host_has_detached)) {
1054      outBuffer[0] = '\0';
1055      getpacket (inBuffer);
1056      binary = 0;
1057
1058      switch (inBuffer[0]) {
1059         case '?':
1060            gdb_stub_report_exception_info(vector, frame, thread);
1061            break;
1062
1063         case 'd': /* toggle debug flag */
1064            /* can print ill-formed commands in valid packets & checksum errors */
1065            break;
1066
1067         case 'D':
1068            /* remote system is detaching - return OK and exit from debugger */
1069            strcpy (outBuffer, "OK");
1070            host_has_detached = 1;
1071            break;
1072
1073         case 'g':               /* return the values of the CPU registers */
1074            regptr = registers;
1075#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1076            if (do_threads && current_thread != thread )
1077               regptr = &current_thread_registers;
1078#endif
1079            mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
1080            break;
1081
1082
1083         case 'G':       /* set the values of the CPU registers - return OK */
1084            regptr = registers;
1085#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1086            if (do_threads && current_thread != thread )
1087               regptr = &current_thread_registers;
1088#endif
1089            if (hex2mem (&inBuffer[1], regptr, NUM_REGS * (sizeof registers)))
1090               strcpy (outBuffer, "OK");
1091            else
1092               strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
1093            break;
1094
1095
1096         case 'P':
1097            /* Pn...=r...  Write register n... with value r... - return OK */
1098            ptr = &inBuffer[1];
1099            if (hexToInt(&ptr, &regno) &&
1100                *ptr++ == '=' &&
1101                hexToLongLong(&ptr, &regval))
1102            {
1103               registers[regno] = regval;
1104               strcpy (outBuffer, "OK");
1105            }
1106            else
1107               strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
1108            break;
1109
1110
1111         case 'm':
1112            /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
1113            ptr = &inBuffer[1];
1114            if (hexToInt (&ptr, &addr)
1115                && *ptr++ == ','
1116                && hexToInt (&ptr, &length)
1117                && is_readable (addr, length)
1118                && (length < (BUFMAX - 4)/2))
1119               mem2hex ((void *)addr, length, outBuffer);
1120            else
1121               strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
1122            break;
1123
1124
1125         case 'X':  /* XAA..AA,LLLL:<binary data>#cs */
1126            binary = 1;
1127         case 'M':
1128            /* MAA..AA,LLLL:  Write LLLL bytes at address AA..AA - return OK */
1129            ptr = &inBuffer[1];
1130            if (hexToInt (&ptr, &addr)
1131                && *ptr++ == ','
1132                && hexToInt (&ptr, &length)
1133                && *ptr++ == ':'
1134                && is_writeable (addr, length) ) {
1135               if ( binary )
1136                  hex2mem (ptr, (void *)addr, length);
1137               else
1138                  bin2mem (ptr, (void *)addr, length);
1139               strcpy (outBuffer, "OK");
1140            }
1141            else
1142               strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
1143            break;
1144
1145
1146
1147         case 'c':
1148            /* cAA..AA    Continue at address AA..AA(optional) */
1149         case 's':
1150            /* sAA..AA    Step one instruction from AA..AA(optional) */
1151         {
1152            /* try to read optional parameter, pc unchanged if no parm */
1153            ptr = &inBuffer[1];
1154            if (hexToInt (&ptr, &addr))
1155               registers[PC] = addr;
1156
1157            if (inBuffer[0] == 's')
1158               doSStep ();
1159         }
1160         goto stubexit;
1161
1162
1163
1164
1165
1166         case 'k':  /* remove all zbreaks if any */
1167        dumpzbreaks:
1168         {
1169            {
1170               /* Unlink the entire list */
1171               struct z0break *z0, *znxt;
1172
1173               while( (z0= z0break_list) )
1174               {
1175
1176                  /* put back the instruction */
1177                  if( z0->instr != 0xffffffff )
1178                     *(z0->address) = z0->instr;
1179
1180                  /* pop off the top entry */
1181                  znxt = z0->next;
1182                  if( znxt ) znxt->prev = NULL;
1183                  z0break_list = znxt;
1184
1185                  /* and put it on the free list */
1186                  z0->prev = NULL;
1187                  z0->next = z0break_avail;
1188                  z0break_avail = z0;
1189               }
1190            }
1191
1192            strcpy(outBuffer, "OK");
1193         }
1194         break;
1195
1196
1197
1198
1199
1200         case 'q':   /* queries */
1201#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1202            rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
1203#endif
1204            break;
1205
1206#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1207         case 'T':
1208         {
1209            int testThread;
1210
1211            if( vhstr2thread(&inBuffer[1], &testThread) == NULL )
1212            {
1213               strcpy(outBuffer, "E01");
1214               break;
1215            }
1216
1217            if( rtems_gdb_index_to_stub_id(testThread) == NULL )
1218            {
1219               strcpy(outBuffer, "E02");
1220            }
1221            else
1222            {
1223               strcpy(outBuffer, "OK");
1224            }
1225         }
1226         break;
1227#endif
1228       
1229         case 'H':  /* set new thread */
1230#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1231            if (inBuffer[1] != 'g') {
1232               break;
1233            }
1234         
1235            if (!do_threads) {
1236               break;
1237            }
1238         
1239            {
1240               int tmp, ret;
1241           
1242               /* Set new generic thread */
1243               if (vhstr2thread(&inBuffer[2], &tmp) == NULL) {
1244                  strcpy(outBuffer, "E01");
1245                  break;
1246               }
1247
1248               /* 0 means `thread' */
1249               if (tmp == 0) {
1250                  tmp = thread;
1251               }
1252
1253               if (tmp == current_thread) {
1254                  /* No changes */
1255                  strcpy(outBuffer, "OK");
1256                  break;
1257               }
1258
1259               /* Save current thread registers if necessary */
1260               if (current_thread != thread) {
1261                  ret = rtems_gdb_stub_set_thread_regs(
1262                     current_thread, (unsigned int *) &current_thread_registers);
1263                  ASSERT(ret);
1264               }
1265
1266               /* Read new registers if necessary */
1267               if (tmp != thread) {
1268                  ret = rtems_gdb_stub_get_thread_regs(
1269                     tmp, (unsigned int *) &current_thread_registers);
1270
1271                  if (!ret) {
1272                     /* Thread does not exist */
1273                     strcpy(outBuffer, "E02");
1274                     break;
1275                  }
1276               }
1277           
1278               current_thread = tmp;
1279               strcpy(outBuffer, "OK");
1280            }
1281#endif
1282            break;
1283
1284
1285
1286
1287         case 'Z':  /* Add breakpoint */
1288         {
1289            int ret, type, len;
1290            unsigned *address;
1291            struct z0break *z0;
1292
1293            ret = parse_zbreak(inBuffer, &type, (unsigned char **)&address, &len);
1294            if (!ret) {
1295               strcpy(outBuffer, "E01");
1296               break;
1297            }
1298
1299            if (type != 0) {
1300               /* We support only software break points so far */
1301               strcpy(outBuffer, "E02");
1302               break;
1303            }
1304
1305            if (len != R_SZ) {     /* was 1 */
1306               strcpy(outBuffer, "E03");
1307               break;
1308            }
1309
1310            /* Let us check whether this break point already set */
1311            for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1312               if (z0->address == address) {
1313                  break;
1314               }
1315            }
1316
1317            if (z0 != NULL) {
1318               /* we already have a breakpoint for this address */
1319               strcpy(outBuffer, "E04");
1320               break;
1321            }
1322
1323            /* Let us allocate new break point */
1324            if (z0break_avail == NULL) {
1325               strcpy(outBuffer, "E05");
1326               break;
1327            }
1328
1329
1330            /* Get entry */
1331            z0 = z0break_avail;
1332            z0break_avail = z0break_avail->next;
1333
1334            /* Let us copy memory from address add stuff the break point in */
1335            /*
1336            *if (mem2hstr(z0->buf, address, 1) == NULL ||
1337              !hstr2mem(address, "cc" , 1)) {
1338
1339               * Memory error *
1340               z0->next = z0break_avail;
1341               z0break_avail = z0;
1342               strcpy(outBuffer, "E05");
1343               break;
1344            }*/
1345
1346            /* Fill it */
1347            z0->address = address;
1348
1349            if( z0->address == (unsigned *) frame->epc )
1350            {
1351               /* re-asserting the breakpoint that put us in here, so
1352               we'll add the breakpoint but leave the code in place
1353               since we'll be returning to it when the user continues */
1354               z0->instr = 0xffffffff;
1355            }
1356            else
1357            {
1358               /* grab the instruction */
1359               z0->instr = *(z0->address);
1360               /* and insert the break */
1361               *(z0->address) = BREAK_INSTR;
1362            }
1363
1364            /* Add to the list */
1365            {
1366               struct z0break *znxt = z0break_list;
1367
1368               z0->prev = NULL;
1369               z0->next = znxt;
1370               
1371               if( znxt ) znxt->prev = z0;
1372               z0break_list = z0;
1373            }
1374
1375            strcpy(outBuffer, "OK");
1376         }
1377         break;
1378
1379
1380         case 'z': /* remove breakpoint */
1381            if (inBuffer[1] == 'z')
1382            {
1383               goto dumpzbreaks;
1384               
1385
1386               /*
1387                * zz packet - remove all breaks *
1388                z0last = NULL;
1389
1390                for (z0=z0break_list; z0!=NULL; z0=z0->next)
1391                {
1392                if(!hstr2mem(z0->address, z0->buf, R_SZ))
1393                {
1394                ret = 0;
1395                }
1396                z0last = z0;
1397                }
1398
1399                * Free entries if any *
1400                if (z0last != NULL) {
1401                z0last->next  = z0break_avail;
1402                z0break_avail = z0break_list;
1403                z0break_list  = NULL;
1404                }
1405
1406                if (ret) {
1407                strcpy(outBuffer, "OK");
1408                } else {
1409                strcpy(outBuffer, "E04");
1410                }
1411                break;
1412               */
1413            }
1414            else
1415            {
1416               int ret, type, len;
1417               unsigned *address;
1418               struct z0break *z0;
1419             
1420
1421               ret = parse_zbreak(inBuffer, &type, (unsigned char **)&address, &len);
1422               if (!ret) {
1423                  strcpy(outBuffer, "E01");
1424                  break;
1425               }
1426
1427               if (type != 0) {
1428                  /* We support only software break points so far */
1429                  break;
1430               }
1431
1432               if (len != R_SZ) {
1433                  strcpy(outBuffer, "E02");
1434                  break;
1435               }
1436           
1437               /* Let us check whether this break point set */
1438               for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1439                  if (z0->address == address) {
1440                     break;
1441                  }
1442               }
1443             
1444               if (z0 == NULL) {
1445                  /* Unknown breakpoint */
1446                  strcpy(outBuffer, "E03");
1447                  break;
1448               }
1449           
1450               /*
1451               if (!hstr2mem(z0->address, z0->buf, R_SZ)) {
1452                  strcpy(outBuffer, "E04");
1453                  break;
1454                  }*/
1455
1456               if( z0->instr != 0xffffffff )
1457               {
1458                  /* put the old instruction back  */
1459                  *(z0->address) = z0->instr;
1460               }
1461   
1462               /* Unlink entry */
1463               {
1464                  struct z0break *zprv = z0->prev, *znxt = z0->next;
1465
1466                  if( zprv ) zprv->next = znxt;
1467                  if( znxt ) znxt->prev = zprv;
1468
1469                  if( !zprv ) z0break_list = znxt;
1470
1471                  znxt = z0break_avail;
1472
1473                  z0break_avail = z0;
1474                  z0->prev = NULL;
1475                  z0->next = znxt;
1476               }
1477   
1478               strcpy(outBuffer, "OK");
1479            }
1480            break;
1481
1482
1483         default: /* do nothing */
1484            break;
1485      }
1486
1487      /* reply to the request */
1488      putpacket (outBuffer);
1489   }
1490
1491  stubexit:
1492
1493   /*
1494    *  The original code did this in the assembly wrapper.  We should consider
1495    *  doing it here before we return.
1496    *
1497    *  On exit from the exception handler invalidate each line in the I-cache
1498    *  and write back each dirty line in the D-cache.  This needs to be done
1499    *  before the target program is resumed in order to ensure that software
1500    *  breakpoints and downloaded code will actually take effect.  This
1501    *  is because modifications to code in ram will affect the D-cache,
1502    *  but not necessarily the I-cache.
1503    */
1504
1505   {
1506      extern void clear_cache();
1507      clear_cache();
1508   }
1509
1510   return;
1511}
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522static int numsegs;
1523static struct memseg   memsegments[NUM_MEMSEGS];
1524
1525int gdbstub_add_memsegment( unsigned base, unsigned end, int opts )
1526{
1527   if( numsegs == NUM_MEMSEGS ) return -1;
1528
1529   memsegments[numsegs].begin = base;
1530   memsegments[numsegs].end   = end;
1531   memsegments[numsegs].opts   = opts;
1532
1533   ++numsegs;
1534   return RTEMS_SUCCESSFUL;
1535}
1536
1537
1538
1539
1540static int is_readable(unsigned ptr, unsigned len)
1541{
1542   struct memseg *ms;
1543   int i;
1544
1545   if( (ptr & 0x3) ) return -1;
1546
1547   for(i=0; i<numsegs; i++)
1548   {
1549      ms= &memsegments[i];
1550
1551      if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_READABLE) )
1552         return -1;
1553   }
1554   return 0;
1555}
1556
1557
1558static int is_writeable(unsigned ptr, unsigned len)
1559{
1560   struct memseg *ms;
1561   int i;
1562
1563   if( (ptr & 0x3) ) return -1;
1564
1565   for(i=0; i<numsegs; i++)
1566   {
1567      ms= &memsegments[i];
1568
1569      if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
1570         return -1;
1571   }
1572   return 0;
1573}
1574
1575
1576static int is_steppable(unsigned ptr)
1577{
1578   struct memseg *ms;
1579   int i;
1580
1581   if( (ptr & 0x3) ) return -1;
1582
1583   for(i=0; i<numsegs; i++)
1584   {
1585      ms= &memsegments[i];
1586
1587      if( ms->begin <= ptr && ptr <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
1588         return -1;
1589   }
1590   return 0;
1591}
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606static char initialized = 0;   /* 0 means we are not initialized */
1607
1608void mips_gdb_stub_install(int enableThreads)
1609{
1610   /*
1611     These are the RTEMS-defined vectors for all the MIPS exceptions
1612   */
1613   int exceptionVector[]= { MIPS_EXCEPTION_MOD, \
1614                            MIPS_EXCEPTION_TLBL, \
1615                            MIPS_EXCEPTION_TLBS, \
1616                            MIPS_EXCEPTION_ADEL, \
1617                            MIPS_EXCEPTION_ADES, \
1618                            MIPS_EXCEPTION_IBE, \
1619                            MIPS_EXCEPTION_DBE, \
1620                            MIPS_EXCEPTION_SYSCALL, \
1621                            MIPS_EXCEPTION_BREAK, \
1622                            MIPS_EXCEPTION_RI, \
1623                            MIPS_EXCEPTION_CPU, \
1624                            MIPS_EXCEPTION_OVERFLOW, \
1625                            MIPS_EXCEPTION_TRAP, \
1626                            MIPS_EXCEPTION_VCEI, \
1627                            MIPS_EXCEPTION_FPE, \
1628                            MIPS_EXCEPTION_C2E, \
1629                            MIPS_EXCEPTION_WATCH, \
1630                            MIPS_EXCEPTION_VCED, \
1631                            -1 };
1632   int  i;
1633   rtems_isr_entry old;
1634
1635   if (initialized)
1636   {
1637      ASSERT(0);
1638      return;
1639   }
1640
1641   memset( memsegments,0,sizeof(struct memseg)*NUM_MEMSEGS );
1642   numsegs = 0;
1643
1644#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1645   if( enableThreads )
1646      do_threads = 1;
1647   else
1648      do_threads = 0;
1649#endif
1650
1651   {
1652      struct z0break *z0;
1653
1654      z0break_avail = NULL;
1655      z0break_list  = NULL;
1656   
1657      /* z0breaks list init, now we'll do it so it makes sense... */
1658      for (i=0; i<BREAKNUM; i++)
1659      {
1660         memset( (z0= &z0break_arr[i]), 0, sizeof(struct z0break));
1661
1662         z0->next = z0break_avail;
1663         z0break_avail = z0;
1664      }
1665   }     
1666
1667   for(i=0; exceptionVector[i] > -1; i++)
1668   {
1669      rtems_interrupt_catch( (rtems_isr_entry) handle_exception, exceptionVector[i], &old );
1670   }
1671
1672   initialized = 1;
1673
1674   /* get the attention of gdb */
1675   /* mips_break(1);  disabled so user code can choose to invoke it or not */
1676}
1677
1678
1679
Note: See TracBrowser for help on using the repository browser.