source: rtems/c/src/lib/libbsp/mips/shared/gdbstub/mips-stub.c @ 1bbe2e1

4.104.114.84.95
Last change on this file since 1bbe2e1 was 1bbe2e1, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 27, 2002 at 10:32:15 PM

2001-02-27 Joel Sherrill <joel@…>

  • Significant modifications including adding thread support, the 'X' command, and reorganizing so that target CPU independent routines could be reused.
  • gdb_if.h: Added numerous prototypes.
  • mips-stub.c: Added thread support as well as 'X' command. Also noticed that the 'P' command was from the mips protocol.
  • rtems-stub-glue.c: New file. This file contains all generic support which should be able to be reused on another target CPU.
  • Property mode set to 100644
File size: 35.5 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);
211
212extern void putDebugChar (char);
213
214
215/*
216 * BUFMAX defines the maximum number of characters in the inbound & outbound
217 * packet buffers.  At least 4+(sizeof registers)*2 bytes will be needed for
218 * register packets.  Memory dump packets can profitably use even more.
219 */
220#define BUFMAX 1500
221
222static char inBuffer[BUFMAX];
223static char outBuffer[BUFMAX];
224
225/* Structure to keep info on a z-breaks */
226#define BREAKNUM 32
227struct z0break
228{
229  /* List support */
230  struct z0break *next;
231  struct z0break *prev;
232
233  /* Location, preserved data */
234  unsigned char *address;
235  char     buf[2];
236};
237
238static struct z0break z0break_arr[BREAKNUM];
239static struct z0break *z0break_avail = NULL;
240static struct z0break *z0break_list  = NULL;
241
242
243/*
244 * Convert an int to hex.
245 */
246const char gdb_hexchars[] = "0123456789abcdef";
247
248#define highhex(x) gdb_hexchars [(x >> 4) & 0xf]
249#define lowhex(x) gdb_hexchars [x & 0xf]
250
251
252/*
253 * Convert length bytes of data starting at addr into hex, placing the
254 * result in buf.  Return a pointer to the last (null) char in buf.
255 */
256static char *
257mem2hex (void *_addr, int length, char *buf)
258{
259  unsigned int addr = (unsigned int) _addr;
260
261  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
262    {
263      long long *source = (long long *) (addr);
264      long long *limit  = (long long *) (addr + length);
265
266      while (source < limit)
267        {
268          int i;
269          long long k = *source++;
270
271          for (i = 15; i >= 0; i--)
272            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
273        }
274    }
275  else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
276    {
277      int *source = (int *) (addr);
278      int *limit  = (int *) (addr + length);
279
280      while (source < limit)
281        {
282          int i;
283          int k = *source++;
284
285          for (i = 7; i >= 0; i--)
286            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
287        }
288    }
289  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
290    {
291      short *source = (short *) (addr);
292      short *limit  = (short *) (addr + length);
293
294      while (source < limit)
295        {
296          int i;
297          short k = *source++;
298
299          for (i = 3; i >= 0; i--)
300            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
301        }
302    }
303  else                                                   /* byte aligned */
304    {
305      char *source = (char *) (addr);
306      char *limit  = (char *) (addr + length);
307
308      while (source < limit)
309        {
310          int i;
311          char k = *source++;
312
313          for (i = 1; i >= 0; i--)
314            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
315        }
316    }
317
318  *buf = '\0';
319  return (buf);
320}
321
322
323/*
324 * Convert a hex character to an int.
325 */
326static int
327hex (char ch)
328{
329  if ((ch >= 'a') && (ch <= 'f'))
330    return (ch - 'a' + 10);
331  if ((ch >= '0') && (ch <= '9'))
332    return (ch - '0');
333  if ((ch >= 'A') && (ch <= 'F'))
334    return (ch - 'A' + 10);
335  return (-1);
336}
337
338
339/*
340 * Convert a string from hex to int until a non-hex digit
341 * is found.  Return the number of characters processed.
342 */
343static int
344hexToInt (char **ptr, int *intValue)
345{
346  int numChars = 0;
347  int hexValue;
348
349  *intValue = 0;
350
351  while (**ptr)
352    {
353      hexValue = hex (**ptr);
354      if (hexValue >= 0)
355        {
356          *intValue = (*intValue << 4) | hexValue;
357          numChars++;
358        }
359      else
360        break;
361
362      (*ptr)++;
363    }
364
365  return (numChars);
366}
367
368
369/*
370 * Convert a string from hex to long long until a non-hex
371 * digit is found.  Return the number of characters processed.
372 */
373static int
374hexToLongLong (char **ptr, long long *intValue)
375{
376  int numChars = 0;
377  int hexValue;
378
379  *intValue = 0;
380
381  while (**ptr)
382    {
383      hexValue = hex (**ptr);
384      if (hexValue >= 0)
385        {
386          *intValue = (*intValue << 4) | hexValue;
387          numChars++;
388        }
389      else
390        break;
391
392      (*ptr)++;
393    }
394
395  return (numChars);
396}
397
398
399/*
400 * Convert the hex array buf into binary, placing the result at the
401 * specified address.  If the conversion fails at any point (i.e.,
402 * if fewer bytes are written than indicated by the size parameter)
403 * then return 0;  otherwise return 1.
404 */
405static int
406hex2mem (char *buf, void *_addr, int length)
407{
408  unsigned int addr = (unsigned int) _addr;
409  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
410    {
411      long long *target = (long long *) (addr);
412      long long *limit  = (long long *) (addr + length);
413
414      while (target < limit)
415        {
416          int i, j;
417          long long k = 0;
418
419          for (i = 0; i < 16; i++)
420            if ((j = hex(*buf++)) < 0)
421              return 0;
422            else
423              k = (k << 4) + j;
424          *target++ = k;
425        }
426    }
427  else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
428    {
429      int *target = (int *) (addr);
430      int *limit  = (int *) (addr + length);
431
432      while (target < limit)
433        {
434          int i, j;
435          int k = 0;
436
437          for (i = 0; i < 8; i++)
438            if ((j = hex(*buf++)) < 0)
439              return 0;
440            else
441              k = (k << 4) + j;
442          *target++ = k;
443        }
444    }
445  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
446    {
447      short *target = (short *) (addr);
448      short *limit  = (short *) (addr + length);
449
450      while (target < limit)
451        {
452          int i, j;
453          short k = 0;
454
455          for (i = 0; i < 4; i++)
456            if ((j = hex(*buf++)) < 0)
457              return 0;
458            else
459              k = (k << 4) + j;
460          *target++ = k;
461        }
462    }
463  else                                                   /* byte aligned */
464    {
465      char *target = (char *) (addr);
466      char *limit  = (char *) (addr + length);
467
468      while (target < limit)
469        {
470          int i, j;
471          char k = 0;
472
473          for (i = 0; i < 2; i++)
474            if ((j = hex(*buf++)) < 0)
475              return 0;
476            else
477              k = (k << 4) + j;
478          *target++ = k;
479        }
480    }
481
482  return 1;
483}
484
485
486/* Convert the binary stream in BUF to memory.
487
488   Gdb will escape $, #, and the escape char (0x7d).
489   COUNT is the total number of bytes to write into
490   memory. */
491static unsigned char *
492bin2mem (
493  unsigned char *buf,
494  unsigned char *mem,
495  int   count
496)
497{
498  int i;
499
500  for (i = 0; i < count; i++) {
501      /* Check for any escaped characters. Be paranoid and
502         only unescape chars that should be escaped. */
503      if (*buf == 0x7d) {
504          switch (*(buf+1)) {
505            case 0x3:  /* # */
506            case 0x4:  /* $ */
507            case 0x5d: /* escape char */
508              buf++;
509              *buf |= 0x20;
510              break;
511            default:
512              /* nothing */
513              break;
514            }
515        }
516
517      *mem++ = *buf++;
518    }
519
520  return mem;
521}
522
523
524
525/*
526 * Scan the input stream for a sequence for the form $<data>#<checksum>.
527 */
528static void
529getpacket (char *buffer)
530{
531  unsigned char checksum;
532  unsigned char xmitcsum;
533  int i;
534  int count;
535  char ch;
536  do
537    {
538      /* wait around for the start character, ignore all other characters */
539      while ((ch = getDebugChar ()) != '$');
540      checksum = 0;
541      xmitcsum = -1;
542
543      count = 0;
544
545      /* now, read until a # or end of buffer is found */
546      while ( (count < BUFMAX-1) && ((ch = getDebugChar ()) != '#') )
547          checksum += (buffer[count++] = ch);
548
549      /* make sure that the buffer is null-terminated */
550      buffer[count] = '\0';
551
552      if (ch == '#')
553        {
554          xmitcsum = hex (getDebugChar ()) << 4;
555          xmitcsum += hex (getDebugChar ());
556          if (checksum != xmitcsum)
557            putDebugChar ('-'); /* failed checksum */
558          else
559            {
560              putDebugChar ('+');       /* successful transfer */
561              /* if a sequence char is present, reply the sequence ID */
562              if (buffer[2] == ':')
563                {
564                  putDebugChar (buffer[0]);
565                  putDebugChar (buffer[1]);
566                  /* remove sequence chars from buffer */
567                  for (i = 3; i <= count; i++)
568                    buffer[i - 3] = buffer[i];
569                }
570            }
571        }
572    }
573  while (checksum != xmitcsum);
574}
575
576
577/*
578 * Send the packet in buffer and wait for a positive acknowledgement.
579 */
580static void
581putpacket (char *buffer)
582{
583  int checksum;
584
585  /* $<packet info>#<checksum> */
586  do
587    {
588      char *src = buffer;
589      putDebugChar ('$');
590      checksum = 0;
591
592      while (*src != '\0')
593        {
594          int runlen = 0;
595
596          /* Do run length encoding */
597          while ((src[runlen] == src[0]) && (runlen < 99))
598            runlen++;
599          if (runlen > 3)
600            {
601              int encode;
602              /* Got a useful amount */
603              putDebugChar (*src);
604              checksum += *src;
605              putDebugChar ('*');
606              checksum += '*';
607              checksum += (encode = (runlen - 4) + ' ');
608              putDebugChar (encode);
609              src += runlen;
610            }
611          else
612            {
613              putDebugChar (*src);
614              checksum += *src;
615              src++;
616             }
617        }
618
619      putDebugChar ('#');
620      putDebugChar (highhex (checksum));
621      putDebugChar (lowhex (checksum));
622    }
623  while  (getDebugChar () != '+');
624}
625
626
627/*
628 * Saved instruction data for single step support
629 */
630static struct
631  {
632    unsigned *targetAddr;
633    unsigned savedInstr;
634  }
635instrBuffer;
636
637
638/*
639 * If a step breakpoint was planted restore the saved instruction.
640 */
641static void
642undoSStep (void)
643{
644  if (instrBuffer.targetAddr != NULL)
645    {
646      *instrBuffer.targetAddr = instrBuffer.savedInstr;
647      instrBuffer.targetAddr = NULL;
648    }
649  instrBuffer.savedInstr = NOP_INSTR;
650}
651
652
653/*
654 * If a single step is requested put a temporary breakpoint at the instruction
655 * which logically follows the next one to be executed.  If the next instruction
656 * is a branch instruction then skip the instruction in the delay slot.  NOTE:
657 * ERET instructions are NOT handled, as it is impossible to single-step through
658 * the exit code in an exception handler.  In addition, no attempt is made to
659 * do anything about BC0T and BC0F, since a condition bit for coprocessor 0
660 * is not defined on the R4600.  Finally, BC2T and BC2F are ignored since there
661 * is no coprocessor 2 on a 4600.
662 */
663static void
664doSStep (void)
665{
666  InstFmt inst;
667
668  instrBuffer.targetAddr = (unsigned *)(registers[PC]+4);    /* set default */
669
670  inst.word = *(unsigned *)registers[PC];     /* read the next instruction  */
671
672  switch (inst.RType.op) {                    /* override default if branch */
673    case OP_SPECIAL:
674      switch (inst.RType.func) {
675        case OP_JR:
676        case OP_JALR:
677          instrBuffer.targetAddr =
678            (unsigned *)registers[inst.RType.rs];
679          break;
680      };
681      break;
682
683    case OP_REGIMM:
684      switch (inst.IType.rt) {
685        case OP_BLTZ:
686        case OP_BLTZL:
687        case OP_BLTZAL:
688        case OP_BLTZALL:
689          if (registers[inst.IType.rs] < 0 )
690            instrBuffer.targetAddr =
691              (unsigned *)(((signed short)inst.IType.imm<<2)
692                                        + (registers[PC]+4));
693          else
694            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
695          break;
696        case OP_BGEZ:
697        case OP_BGEZL:
698        case OP_BGEZAL:
699        case OP_BGEZALL:
700          if (registers[inst.IType.rs] >= 0 )
701            instrBuffer.targetAddr =
702              (unsigned *)(((signed short)inst.IType.imm<<2)
703                                        + (registers[PC]+4));
704          else
705            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
706          break;
707      };
708      break;
709
710    case OP_J:
711    case OP_JAL:
712      instrBuffer.targetAddr =
713        (unsigned *)((inst.JType.target<<2) + ((registers[PC]+4)&0xf0000000));
714      break;
715
716    case OP_BEQ:
717    case OP_BEQL:
718      if (registers[inst.IType.rs] == registers[inst.IType.rt])
719        instrBuffer.targetAddr =
720          (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
721      else
722        instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
723      break;
724    case OP_BNE:
725    case OP_BNEL:
726      if (registers[inst.IType.rs] != registers[inst.IType.rt])
727        instrBuffer.targetAddr =
728          (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
729      else
730        instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
731      break;
732    case OP_BLEZ:
733    case OP_BLEZL:
734      if (registers[inst.IType.rs] <= 0)
735        instrBuffer.targetAddr =
736          (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
737      else
738        instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
739      break;
740    case OP_BGTZ:
741    case OP_BGTZL:
742      if (registers[inst.IType.rs] > 0)
743        instrBuffer.targetAddr =
744          (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
745      else
746        instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
747      break;
748
749    case OP_COP1:
750      if (inst.RType.rs == OP_BC)
751          switch (inst.RType.rt) {
752            case COPz_BCF:
753            case COPz_BCFL:
754              if (registers[FCSR] & CSR_C)
755                instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
756              else
757                instrBuffer.targetAddr =
758                  (unsigned *)(((signed short)inst.IType.imm<<2)
759                                            + (registers[PC]+4));
760              break;
761            case COPz_BCT:
762            case COPz_BCTL:
763              if (registers[FCSR] & CSR_C)
764                instrBuffer.targetAddr =
765                  (unsigned *)(((signed short)inst.IType.imm<<2)
766                                            + (registers[PC]+4));
767              else
768                instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
769              break;
770          };
771      break;
772  }
773
774  if is_steppable (instrBuffer.targetAddr)
775    {
776      instrBuffer.savedInstr = *instrBuffer.targetAddr;
777      *instrBuffer.targetAddr = BREAK_INSTR;
778    }
779  else
780    {
781      instrBuffer.targetAddr = NULL;
782      instrBuffer.savedInstr = NOP_INSTR;
783    }
784  return;
785}
786
787
788/*
789 * Translate the R4600 exception code into a Unix-compatible signal.
790 */
791static int
792computeSignal (void)
793{
794  int exceptionCode = (registers[CAUSE] & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
795
796  switch (exceptionCode)
797    {
798    case EXC_INT:
799      /* External interrupt */
800      return SIGINT;
801
802    case EXC_RI:
803      /* Reserved instruction */
804    case EXC_CPU:
805      /* Coprocessor unusable */
806      return SIGILL;
807
808    case EXC_BP:
809      /* Break point */
810      return SIGTRAP;
811
812    case EXC_OVF:
813      /* Arithmetic overflow */
814    case EXC_TRAP:
815      /* Trap exception */
816    case EXC_FPE:
817      /* Floating Point Exception */
818      return SIGFPE;
819
820    case EXC_IBE:
821      /* Bus error (Ifetch) */
822    case EXC_DBE:
823      /* Bus error (data load or store) */
824      return SIGBUS;
825
826    case EXC_MOD:
827      /* TLB modification exception */
828    case EXC_TLBL:
829      /* TLB miss (Load or Ifetch) */
830    case EXC_TLBS:
831      /* TLB miss (Store) */
832    case EXC_ADEL:
833      /* Address error (Load or Ifetch) */
834    case EXC_ADES:
835      /* Address error (Store) */
836      return SIGSEGV;
837
838    case EXC_SYS:
839      /* System call */
840      return SIGSYS;
841
842    default:
843      return SIGTERM;
844    }
845}
846
847/*
848 *  This support function prepares and sends the message containing the
849 *  basic information about this exception.
850 */
851
852void gdb_stub_report_exception_info(
853  rtems_vector_number vector,
854  CPU_Interrupt_frame *frame,
855  int                  thread
856)
857{
858  char *optr;
859  int sigval;
860
861  optr = outBuffer;
862  *optr++ = 'T';
863  sigval = computeSignal ();
864  *optr++ = highhex (sigval);
865  *optr++ = lowhex (sigval);
866
867  *optr++ = gdb_hexchars[SP];
868  *optr++ = ':';
869  optr    = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
870  *optr++ = ';';
871 
872  *optr++ = gdb_hexchars[PC];
873  *optr++ = ':';
874  optr    = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
875  *optr++ = ';';
876
877#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
878  if (do_threads) {
879    *optr++ = 't';
880    *optr++ = 'h';
881    *optr++ = 'r';
882    *optr++ = 'e';
883    *optr++ = 'a';
884    *optr++ = 'd';
885    *optr++ = ':';
886    optr   = thread2vhstr(optr, thread);
887    *optr++ = ';';
888  }
889#endif
890  putpacket (outBuffer);
891 
892  *optr++ = '\0';
893}
894
895
896
897/*
898 * This function handles all exceptions.  It only does two things:
899 * it figures out why it was activated and tells gdb, and then it
900 * reacts to gdb's requests.
901 */
902
903CPU_Interrupt_frame current_thread_registers;
904
905void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
906{
907  int host_has_detached = 0;
908  int regno, addr, length;
909  long long regval;
910  char *ptr;
911  int  current_thread;  /* current generic thread */
912  int  thread;          /* stopped thread: context exception happened in */
913  void *regptr;
914  int  binary;
915
916  registers = (mips_register_t *)frame;
917
918  thread = 0;
919#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
920  if (do_threads) {
921    thread = rtems_gdb_stub_get_current_thread();
922  }
923#endif
924  current_thread = thread;
925
926  /* reply to host that an exception has occurred with some basic info */
927  gdb_stub_report_exception_info(vector, frame, thread);
928
929
930  /*
931   * Restore the saved instruction at
932   * the single-step target address.
933   */
934  undoSStep ();
935
936  while (!(host_has_detached)) {
937      outBuffer[0] = '\0';
938      getpacket (inBuffer);
939      binary = 0;
940
941      switch (inBuffer[0]) {
942        case '?':
943          gdb_stub_report_exception_info(vector, frame, thread);
944          break;
945
946        case 'd': /* toggle debug flag */
947          /* can print ill-formed commands in valid packets & checksum errors */
948          break;
949
950        case 'D':
951          /* remote system is detaching - return OK and exit from debugger */
952          strcpy (outBuffer, "OK");
953          host_has_detached = 1;
954          break;
955
956        case 'g':               /* return the values of the CPU registers */
957          regptr = registers;
958#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
959          if (do_threads && current_thread != thread )
960             regptr = &current_thread_registers;
961#endif
962          mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
963
964          break;
965
966        case 'G':       /* set the values of the CPU registers - return OK */
967          regptr = registers;
968#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
969          if (do_threads && current_thread != thread )
970             regptr = &current_thread_registers;
971#endif
972          if (hex2mem (&inBuffer[1], regptr, NUM_REGS * (sizeof registers)))
973              strcpy (outBuffer, "OK");
974          else
975              strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
976          break;
977
978        case 'P':
979          /* Pn...=r...  Write register n... with value r... - return OK */
980          ptr = &inBuffer[1];
981          if (hexToInt(&ptr, &regno) &&
982              *ptr++ == '=' &&
983              hexToLongLong(&ptr, &regval))
984            {
985              registers[regno] = regval;
986              strcpy (outBuffer, "OK");
987            }
988          else
989              strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
990          break;
991
992        case 'm':
993          /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
994          ptr = &inBuffer[1];
995          if (hexToInt (&ptr, &addr)
996              && *ptr++ == ','
997              && hexToInt (&ptr, &length)
998              && is_readable (addr, length)
999              && (length < (BUFMAX - 4)/2))
1000            mem2hex ((void *)addr, length, outBuffer);
1001          else
1002            strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
1003          break;
1004
1005        case 'X':  /* XAA..AA,LLLL:<binary data>#cs */
1006          binary = 1;
1007        case 'M':
1008          /* MAA..AA,LLLL:  Write LLLL bytes at address AA..AA - return OK */
1009          ptr = &inBuffer[1];
1010          if (hexToInt (&ptr, &addr)
1011              && *ptr++ == ','
1012              && hexToInt (&ptr, &length)
1013              && *ptr++ == ':'
1014              && is_writeable (addr, length) ) {
1015              if ( binary )
1016                hex2mem (ptr, (void *)addr, length);
1017              else
1018                bin2mem (ptr, (void *)addr, length);
1019              strcpy (outBuffer, "OK");
1020          }
1021          else
1022            strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
1023          break;
1024
1025        case 'c':
1026          /* cAA..AA    Continue at address AA..AA(optional) */
1027        case 's':
1028          /* sAA..AA    Step one instruction from AA..AA(optional) */
1029          {
1030            /* try to read optional parameter, pc unchanged if no parm */
1031            ptr = &inBuffer[1];
1032            if (hexToInt (&ptr, &addr))
1033              registers[PC] = addr;
1034
1035            if (inBuffer[0] == 's')
1036              doSStep ();
1037          }
1038          return;
1039
1040        case 'k':  /* remove all zbreaks if any */
1041          {
1042            int ret;
1043            struct z0break *z0, *z0last;
1044
1045            ret = 1;
1046            z0last = NULL;
1047
1048            for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1049                if (!hstr2mem(z0->address, z0->buf, 1)) {
1050                   ret = 0;
1051                }
1052
1053                z0last = z0;
1054            }
1055
1056            /* Free entries if any */
1057            if (z0last != NULL) {
1058              z0last->next  = z0break_avail;
1059              z0break_avail = z0break_list;
1060              z0break_list  = NULL;
1061            }
1062          }
1063
1064          break;
1065
1066        case 'q':   /* queries */
1067#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1068          rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
1069#endif
1070          break;
1071       
1072        case 'H':  /* set new thread */
1073#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1074          if (inBuffer[1] != 'g') {
1075            break;
1076          }
1077         
1078          if (!do_threads) {
1079            break;
1080          }
1081         
1082          {
1083            int tmp, ret;
1084           
1085            /* Set new generic thread */
1086            if (vhstr2thread(&inBuffer[2], &tmp) == NULL) {
1087              strcpy(outBuffer, "E01");
1088              break;
1089            }
1090
1091            /* 0 means `thread' */
1092            if (tmp == 0) {
1093              tmp = thread;
1094            }
1095
1096            if (tmp == current_thread) {
1097              /* No changes */
1098              strcpy(outBuffer, "OK");
1099              break;
1100            }
1101
1102            /* Save current thread registers if necessary */ 
1103            if (current_thread != thread) {
1104              ret = rtems_gdb_stub_set_thread_regs(
1105                   current_thread, (unsigned int *) &current_thread_registers);
1106              ASSERT(ret);
1107            }
1108
1109            /* Read new registers if necessary */
1110            if (tmp != thread) {
1111                ret = rtems_gdb_stub_get_thread_regs(
1112                    tmp, (unsigned int *) &current_thread_registers);
1113
1114                if (!ret) {
1115                  /* Thread does not exist */
1116                  strcpy(outBuffer, "E02");
1117                  break;
1118                }
1119            }
1120           
1121            current_thread = tmp;
1122            strcpy(outBuffer, "OK");
1123          }
1124
1125#endif
1126          break;
1127
1128        case 'Z':  /* Add breakpoint */
1129          { 
1130            int ret, type, len;
1131            unsigned char *address;
1132            struct z0break *z0;
1133
1134            ret = parse_zbreak(inBuffer, &type, &address, &len);
1135            if (!ret) {
1136              strcpy(outBuffer, "E01");
1137              break;
1138            }
1139
1140            if (type != 0) {
1141              /* We support only software break points so far */
1142              break;
1143            }
1144
1145            if (len != 1) {
1146               strcpy(outBuffer, "E02");
1147               break;
1148            }
1149
1150            /* Let us check whether this break point already set */
1151            for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1152                if (z0->address == address) {
1153                  break;
1154                }
1155            }
1156
1157            if (z0 != NULL) {
1158              /* Repeated packet */
1159              strcpy(outBuffer, "OK");
1160              break;
1161            }
1162
1163            /* Let us allocate new break point */
1164            if (z0break_avail == NULL) {
1165              strcpy(outBuffer, "E03");
1166              break;
1167            }
1168
1169            /* Get entry */
1170            z0 = z0break_avail;
1171            z0break_avail = z0break_avail->next;
1172
1173            /* Let us copy memory from address add stuff the break point in */
1174            if (mem2hstr(z0->buf, address, 1) == NULL ||
1175                !hstr2mem(address, "cc" , 1)) {
1176              /* Memory error */
1177              z0->next = z0break_avail;
1178              z0break_avail = z0;
1179              strcpy(outBuffer, "E03");
1180              break;
1181            }
1182
1183            /* Fill it */
1184            z0->address = address;
1185
1186            /* Add to the list */
1187            z0->next = z0break_list;
1188            z0->prev = NULL;
1189
1190            if (z0break_list != NULL) {
1191              z0break_list->prev = z0;
1192            }
1193
1194            z0break_list = z0;
1195
1196            strcpy(outBuffer, "OK");
1197          }
1198
1199        case 'z': /* remove breakpoint */
1200          {
1201            int ret, type, len;
1202            unsigned char  *address;
1203            struct z0break *z0, *z0last;
1204
1205            if (inBuffer[1] == 'z') {
1206                /* zz packet - remove all breaks */
1207                ret = 1;
1208                z0last = NULL;
1209                for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1210                    if(!hstr2mem(z0->address, z0->buf, 1)) {
1211                        ret = 0;
1212                      }
1213                     
1214                     z0last = z0;
1215                   }
1216
1217                /* Free entries if any */
1218                if (z0last != NULL) {
1219                    z0last->next  = z0break_avail;
1220                    z0break_avail = z0break_list;
1221                    z0break_list  = NULL;
1222                  }
1223
1224                if (ret) {
1225                  strcpy(outBuffer, "OK");
1226                } else {
1227                  strcpy(outBuffer, "E04");
1228                }
1229
1230                break;
1231              }
1232             
1233            ret = parse_zbreak(inBuffer, &type, &address, &len);
1234            if (!ret) {
1235                strcpy(outBuffer, "E01");
1236                break;
1237              }
1238           
1239            if (type != 0) {
1240              /* We support only software break points so far */
1241              break;
1242            }
1243
1244            if (len != 1) {
1245              strcpy(outBuffer, "E02");
1246              break;
1247            }
1248           
1249            /* Let us check whether this break point set */
1250            for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1251              if (z0->address == address) {
1252                break;
1253              }
1254            }
1255             
1256            if (z0 == NULL) {
1257              /* Unknown breakpoint */
1258              strcpy(outBuffer, "E03");
1259              break;
1260            }
1261           
1262            if (!hstr2mem(z0->address, z0->buf, 1)) {
1263              strcpy(outBuffer, "E04");
1264              break;
1265            }
1266   
1267            /* Unlink entry */
1268            if (z0->prev == NULL) {
1269              z0break_list = z0->next;
1270              if (z0break_list != NULL) {
1271                z0break_list->prev = NULL;
1272              }
1273            } else if (z0->next == NULL) {
1274              z0->prev->next = NULL;
1275            } else {
1276              z0->prev->next = z0->next;
1277              z0->next->prev = z0->prev;
1278           }
1279
1280           z0->next = z0break_avail;
1281           z0break_avail = z0;
1282           
1283           strcpy(outBuffer, "OK");
1284         }
1285
1286          break;
1287        default: /* do nothing */
1288          break;
1289      }
1290
1291      /* reply to the request */
1292      putpacket (outBuffer);
1293    }
1294
1295   /*
1296    *  The original code did this in the assembly wrapper.  We should consider
1297    *  doing it here before we return.
1298    *
1299    *  On exit from the exception handler invalidate each line in the I-cache
1300    *  and write back each dirty line in the D-cache.  This needs to be done
1301    *  before the target program is resumed in order to ensure that software
1302    *  breakpoints and downloaded code will actually take effect.
1303    */
1304
1305  return;
1306}
1307
1308static char initialized;   /* 0 means we are not initialized */
1309
1310void mips_gdb_stub_install(void) 
1311{
1312  rtems_isr_entry old;
1313  int i;
1314
1315  if (initialized) {
1316    ASSERT(0);
1317    return;
1318  }
1319
1320  /* z0breaks */
1321  for (i=0; i<(sizeof(z0break_arr)/sizeof(z0break_arr[0]))-1; i++) {
1322    z0break_arr[i].next = &z0break_arr[i+1];
1323  }
1324
1325  z0break_arr[i].next = NULL;
1326  z0break_avail       = &z0break_arr[0];
1327  z0break_list        = NULL;
1328
1329
1330  rtems_interrupt_catch( (rtems_isr_entry) handle_exception, MIPS_EXCEPTION_SYSCALL, &old );
1331  /* rtems_interrupt_catch( handle_exception, MIPS_EXCEPTION_BREAK, &old ); */
1332
1333  initialized = 1;
1334  /* get the attention of gdb */
1335  mips_break(1);
1336}
1337
Note: See TracBrowser for help on using the repository browser.