source: rtems/c/src/lib/libbsp/mips/shared/gdbstub/mips-stub.c @ 2f89140

4.104.114.84.95
Last change on this file since 2f89140 was 2f89140, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/02 at 16:32:07

2001-03-05 Greg Menke <gregory.menke@…>

  • mips-stub.c: Debugged & tweaked the gdb command processing, zbreak stuff, breakpoint and step code. Implemented 'T' command support and debugged remote gdb support w/ the Mongoose bsp. Added the memory segment support.
  • memlimits.h: Disabled all contents in favor of memory sement support. This file could probably go away.
  • rtems-stub-glue.c (rtems_gdb_index_to_stub_id()): New routine. rtems_gdb_stub_get_register_from_context(): Implemented MIPS version. rtems_gdb_stub_get_offsets(): Implemented MIPS version.
  • README: Updated.
  • Property mode set to 100644
File size: 43.4 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  unsigned *address;
253  unsigned instr;
254};
255
256static struct z0break z0break_arr[BREAKNUM];
257static struct z0break *z0break_avail = NULL;
258static struct z0break *z0break_list  = NULL;
259
260
261/*
262 * Convert an int to hex.
263 */
264const char gdb_hexchars[] = "0123456789abcdef";
265
266#define highhex(x) gdb_hexchars [(x >> 4) & 0xf]
267#define lowhex(x) gdb_hexchars [x & 0xf]
268
269
270/*
271 * Convert length bytes of data starting at addr into hex, placing the
272 * result in buf.  Return a pointer to the last (null) char in buf.
273 */
274static char *
275mem2hex (void *_addr, int length, char *buf)
276{
277  unsigned int addr = (unsigned int) _addr;
278
279  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
280    {
281      long long *source = (long long *) (addr);
282      long long *limit  = (long long *) (addr + length);
283
284      while (source < limit)
285        {
286          int i;
287          long long k = *source++;
288
289          for (i = 15; i >= 0; i--)
290            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
291        }
292    }
293  else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
294    {
295      int *source = (int *) (addr);
296      int *limit  = (int *) (addr + length);
297
298      while (source < limit)
299        {
300          int i;
301          int k = *source++;
302
303          for (i = 7; i >= 0; i--)
304            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
305        }
306    }
307  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
308    {
309      short *source = (short *) (addr);
310      short *limit  = (short *) (addr + length);
311
312      while (source < limit)
313        {
314          int i;
315          short k = *source++;
316
317          for (i = 3; i >= 0; i--)
318            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
319        }
320    }
321  else                                                   /* byte aligned */
322    {
323      char *source = (char *) (addr);
324      char *limit  = (char *) (addr + length);
325
326      while (source < limit)
327        {
328          int i;
329          char k = *source++;
330
331          for (i = 1; i >= 0; i--)
332            *buf++ = gdb_hexchars [(k >> (i*4)) & 0xf];
333        }
334    }
335
336  *buf = '\0';
337  return (buf);
338}
339
340
341/*
342 * Convert a hex character to an int.
343 */
344static int
345hex (char ch)
346{
347  if ((ch >= 'a') && (ch <= 'f'))
348    return (ch - 'a' + 10);
349  if ((ch >= '0') && (ch <= '9'))
350    return (ch - '0');
351  if ((ch >= 'A') && (ch <= 'F'))
352    return (ch - 'A' + 10);
353  return (-1);
354}
355
356
357/*
358 * Convert a string from hex to int until a non-hex digit
359 * is found.  Return the number of characters processed.
360 */
361static int
362hexToInt (char **ptr, int *intValue)
363{
364  int numChars = 0;
365  int hexValue;
366
367  *intValue = 0;
368
369  while (**ptr)
370    {
371      hexValue = hex (**ptr);
372      if (hexValue >= 0)
373        {
374          *intValue = (*intValue << 4) | hexValue;
375          numChars++;
376        }
377      else
378        break;
379
380      (*ptr)++;
381    }
382
383  return (numChars);
384}
385
386
387/*
388 * Convert a string from hex to long long until a non-hex
389 * digit is found.  Return the number of characters processed.
390 */
391static int
392hexToLongLong (char **ptr, long long *intValue)
393{
394  int numChars = 0;
395  int hexValue;
396
397  *intValue = 0;
398
399  while (**ptr)
400    {
401      hexValue = hex (**ptr);
402      if (hexValue >= 0)
403        {
404          *intValue = (*intValue << 4) | hexValue;
405          numChars++;
406        }
407      else
408        break;
409
410      (*ptr)++;
411    }
412
413  return (numChars);
414}
415
416
417/*
418 * Convert the hex array buf into binary, placing the result at the
419 * specified address.  If the conversion fails at any point (i.e.,
420 * if fewer bytes are written than indicated by the size parameter)
421 * then return 0;  otherwise return 1.
422 */
423static int
424hex2mem (char *buf, void *_addr, int length)
425{
426  unsigned int addr = (unsigned int) _addr;
427  if (((addr & 0x7) == 0) && ((length & 0x7) == 0))      /* dword aligned */
428    {
429      long long *target = (long long *) (addr);
430      long long *limit  = (long long *) (addr + length);
431
432      while (target < limit)
433        {
434          int i, j;
435          long long k = 0;
436
437          for (i = 0; i < 16; 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 & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
446    {
447      int *target = (int *) (addr);
448      int *limit  = (int *) (addr + length);
449
450      while (target < limit)
451        {
452          int i, j;
453          int k = 0;
454
455          for (i = 0; i < 8; i++)
456            if ((j = hex(*buf++)) < 0)
457              return 0;
458            else
459              k = (k << 4) + j;
460          *target++ = k;
461        }
462    }
463  else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
464    {
465      short *target = (short *) (addr);
466      short *limit  = (short *) (addr + length);
467
468      while (target < limit)
469        {
470          int i, j;
471          short k = 0;
472
473          for (i = 0; i < 4; i++)
474            if ((j = hex(*buf++)) < 0)
475              return 0;
476            else
477              k = (k << 4) + j;
478          *target++ = k;
479        }
480    }
481  else                                                   /* byte aligned */
482    {
483      char *target = (char *) (addr);
484      char *limit  = (char *) (addr + length);
485
486      while (target < limit)
487        {
488          int i, j;
489          char k = 0;
490
491          for (i = 0; i < 2; i++)
492            if ((j = hex(*buf++)) < 0)
493              return 0;
494            else
495              k = (k << 4) + j;
496          *target++ = k;
497        }
498    }
499
500  return 1;
501}
502
503
504/* Convert the binary stream in BUF to memory.
505
506   Gdb will escape $, #, and the escape char (0x7d).
507   COUNT is the total number of bytes to write into
508   memory. */
509static unsigned char *
510bin2mem (
511  unsigned char *buf,
512  unsigned char *mem,
513  int   count
514)
515{
516  int i;
517
518  for (i = 0; i < count; i++) {
519      /* Check for any escaped characters. Be paranoid and
520         only unescape chars that should be escaped. */
521      if (*buf == 0x7d) {
522          switch (*(buf+1)) {
523            case 0x3:  /* # */
524            case 0x4:  /* $ */
525            case 0x5d: /* escape char */
526              buf++;
527              *buf |= 0x20;
528              break;
529            default:
530              /* nothing */
531              break;
532            }
533        }
534
535      *mem++ = *buf++;
536    }
537
538  return mem;
539}
540
541
542
543/*
544 * Scan the input stream for a sequence for the form $<data>#<checksum>.
545 */
546static void
547getpacket (char *buffer)
548{
549  unsigned char checksum;
550  unsigned char xmitcsum;
551  int i;
552  int count;
553  char ch;
554  do
555    {
556      /* wait around for the start character, ignore all other characters */
557      while ((ch = getDebugChar ()) != '$');
558      checksum = 0;
559      xmitcsum = -1;
560
561      count = 0;
562
563      /* now, read until a # or end of buffer is found */
564      while ( (count < BUFMAX-1) && ((ch = getDebugChar ()) != '#') )
565          checksum += (buffer[count++] = ch);
566
567      /* make sure that the buffer is null-terminated */
568      buffer[count] = '\0';
569
570      if (ch == '#')
571        {
572          xmitcsum = hex (getDebugChar ()) << 4;
573          xmitcsum += hex (getDebugChar ());
574          if (checksum != xmitcsum)
575            putDebugChar ('-'); /* failed checksum */
576          else
577            {
578              putDebugChar ('+');       /* successful transfer */
579              /* if a sequence char is present, reply the sequence ID */
580              if (buffer[2] == ':')
581                {
582                  putDebugChar (buffer[0]);
583                  putDebugChar (buffer[1]);
584                  /* remove sequence chars from buffer */
585                  for (i = 3; i <= count; i++)
586                    buffer[i - 3] = buffer[i];
587                }
588            }
589        }
590    }
591  while (checksum != xmitcsum);
592}
593
594
595/*
596 * Send the packet in buffer and wait for a positive acknowledgement.
597 */
598static void
599putpacket (char *buffer)
600{
601  int checksum;
602
603  /* $<packet info>#<checksum> */
604  do
605    {
606      char *src = buffer;
607      putDebugChar ('$');
608      checksum = 0;
609
610      while (*src != '\0')
611        {
612          int runlen = 0;
613
614          /* Do run length encoding */
615          while ((src[runlen] == src[0]) && (runlen < 99))
616            runlen++;
617          if (runlen > 3)
618            {
619              int encode;
620              /* Got a useful amount */
621              putDebugChar (*src);
622              checksum += *src;
623              putDebugChar ('*');
624              checksum += '*';
625              checksum += (encode = (runlen - 4) + ' ');
626              putDebugChar (encode);
627              src += runlen;
628            }
629          else
630            {
631              putDebugChar (*src);
632              checksum += *src;
633              src++;
634             }
635        }
636
637      putDebugChar ('#');
638      putDebugChar (highhex (checksum));
639      putDebugChar (lowhex (checksum));
640    }
641  while  (getDebugChar () != '+');
642}
643
644
645
646
647
648
649
650/*
651 * Saved instruction data for single step support
652 */
653static struct
654  {
655    unsigned *targetAddr;
656    unsigned savedInstr;
657  }
658instrBuffer;
659
660
661/*
662 * If a step breakpoint was planted restore the saved instruction.
663 */
664static void
665undoSStep (void)
666{
667  if (instrBuffer.targetAddr != NULL)
668    {
669      *instrBuffer.targetAddr = instrBuffer.savedInstr;
670      instrBuffer.targetAddr = NULL;
671    }
672  instrBuffer.savedInstr = NOP_INSTR;
673}
674
675
676/*
677 * If a single step is requested put a temporary breakpoint at the instruction
678 * which logically follows the next one to be executed.  If the next instruction
679 * is a branch instruction then skip the instruction in the delay slot.  NOTE:
680 * ERET instructions are NOT handled, as it is impossible to single-step through
681 * the exit code in an exception handler.  In addition, no attempt is made to
682 * do anything about BC0T and BC0F, since a condition bit for coprocessor 0
683 * is not defined on the R4600.  Finally, BC2T and BC2F are ignored since there
684 * is no coprocessor 2 on a 4600.
685 */
686static void
687doSStep (void)
688{
689   struct z0break *z0;
690   InstFmt inst;
691
692   instrBuffer.targetAddr = (unsigned *)(registers[PC]+4);    /* set default */
693
694   inst.word = *(unsigned *)registers[PC];     /* read the next instruction  */
695
696   switch (inst.RType.op) {                    /* override default if branch */
697      case OP_SPECIAL:
698         switch (inst.RType.func) {
699            case OP_JR:
700            case OP_JALR:
701               instrBuffer.targetAddr =
702                  (unsigned *)registers[inst.RType.rs];
703               break;
704         };
705         break;
706
707      case OP_REGIMM:
708         switch (inst.IType.rt) {
709            case OP_BLTZ:
710            case OP_BLTZL:
711            case OP_BLTZAL:
712            case OP_BLTZALL:
713               if (registers[inst.IType.rs] < 0 )
714                  instrBuffer.targetAddr =
715                     (unsigned *)(((signed short)inst.IType.imm<<2)
716                                  + (registers[PC]+4));
717               else
718                  instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
719               break;
720            case OP_BGEZ:
721            case OP_BGEZL:
722            case OP_BGEZAL:
723            case OP_BGEZALL:
724               if (registers[inst.IType.rs] >= 0 )
725                  instrBuffer.targetAddr =
726                     (unsigned *)(((signed short)inst.IType.imm<<2)
727                                  + (registers[PC]+4));
728               else
729                  instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
730               break;
731         };
732         break;
733
734      case OP_J:
735      case OP_JAL:
736         instrBuffer.targetAddr =
737            (unsigned *)((inst.JType.target<<2) + ((registers[PC]+4)&0xf0000000));
738         break;
739
740      case OP_BEQ:
741      case OP_BEQL:
742         if (registers[inst.IType.rs] == registers[inst.IType.rt])
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      case OP_BNE:
749      case OP_BNEL:
750         if (registers[inst.IType.rs] != registers[inst.IType.rt])
751            instrBuffer.targetAddr =
752               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
753         else
754            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
755         break;
756      case OP_BLEZ:
757      case OP_BLEZL:
758         if (registers[inst.IType.rs] <= 0)
759            instrBuffer.targetAddr =
760               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
761         else
762            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
763         break;
764      case OP_BGTZ:
765      case OP_BGTZL:
766         if (registers[inst.IType.rs] > 0)
767            instrBuffer.targetAddr =
768               (unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
769         else
770            instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
771         break;
772
773      case OP_COP1:
774         if (inst.RType.rs == OP_BC)
775            switch (inst.RType.rt) {
776               case COPz_BCF:
777               case COPz_BCFL:
778                  if (registers[FCSR] & CSR_C)
779                     instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
780                  else
781                     instrBuffer.targetAddr =
782                        (unsigned *)(((signed short)inst.IType.imm<<2)
783                                     + (registers[PC]+4));
784                  break;
785               case COPz_BCT:
786               case COPz_BCTL:
787                  if (registers[FCSR] & CSR_C)
788                     instrBuffer.targetAddr =
789                        (unsigned *)(((signed short)inst.IType.imm<<2)
790                                     + (registers[PC]+4));
791                  else
792                     instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
793                  break;
794            };
795         break;
796   }
797
798
799   if( is_steppable((unsigned)instrBuffer.targetAddr) && *(instrBuffer.targetAddr) != BREAK_INSTR )
800   {
801      instrBuffer.savedInstr = *instrBuffer.targetAddr;
802      *instrBuffer.targetAddr = BREAK_INSTR;
803   }
804   else
805   {
806      instrBuffer.targetAddr = NULL;
807      instrBuffer.savedInstr = NOP_INSTR;
808   }
809   return;
810}
811
812
813
814
815
816
817/*
818 * Translate the R4600 exception code into a Unix-compatible signal.
819 */
820static int
821computeSignal (void)
822{
823  int exceptionCode = (registers[CAUSE] & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
824
825  switch (exceptionCode)
826    {
827    case EXC_INT:
828      /* External interrupt */
829      return SIGINT;
830
831    case EXC_RI:
832      /* Reserved instruction */
833    case EXC_CPU:
834      /* Coprocessor unusable */
835      return SIGILL;
836
837    case EXC_BP:
838      /* Break point */
839      return SIGTRAP;
840
841    case EXC_OVF:
842      /* Arithmetic overflow */
843    case EXC_TRAP:
844      /* Trap exception */
845    case EXC_FPE:
846      /* Floating Point Exception */
847      return SIGFPE;
848
849    case EXC_IBE:
850      /* Bus error (Ifetch) */
851    case EXC_DBE:
852      /* Bus error (data load or store) */
853      return SIGBUS;
854
855    case EXC_MOD:
856      /* TLB modification exception */
857    case EXC_TLBL:
858      /* TLB miss (Load or Ifetch) */
859    case EXC_TLBS:
860      /* TLB miss (Store) */
861    case EXC_ADEL:
862      /* Address error (Load or Ifetch) */
863    case EXC_ADES:
864      /* Address error (Store) */
865      return SIGSEGV;
866
867    case EXC_SYS:
868      /* System call */
869      return SIGSYS;
870
871    default:
872      return SIGTERM;
873    }
874}
875
876/*
877 *  This support function prepares and sends the message containing the
878 *  basic information about this exception.
879 */
880
881void gdb_stub_report_exception_info(
882  rtems_vector_number vector,
883  CPU_Interrupt_frame *frame,
884  int                  thread
885)
886{
887   char *optr;
888   int sigval;
889
890   optr = outBuffer;
891   *optr++ = 'T';
892   sigval = computeSignal ();
893   *optr++ = highhex (sigval);
894   *optr++ = lowhex (sigval);
895
896   *optr++ = highhex(SP); /*gdb_hexchars[SP]; */
897   *optr++ = lowhex(SP);
898   *optr++ = ':';
899   optr    = mem2hstr(optr, (unsigned char *)&frame->sp, R_SZ );
900   *optr++ = ';';
901 
902   *optr++ = highhex(PC); /*gdb_hexchars[PC]; */
903   *optr++ = lowhex(PC);
904   *optr++ = ':';
905   optr    = mem2hstr(optr, (unsigned char *)&frame->epc, R_SZ );
906   *optr++ = ';';
907
908#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
909   if (do_threads)
910   {
911      *optr++ = 't';
912      *optr++ = 'h';
913      *optr++ = 'r';
914      *optr++ = 'e';
915      *optr++ = 'a';
916      *optr++ = 'd';
917      *optr++ = ':';
918      optr   = thread2vhstr(optr, thread);
919      *optr++ = ';';
920   }
921#endif
922   *optr++ = '\0';
923}
924
925
926
927
928/*
929 * Scratch frame used to retrieve contexts for different threads, so as
930 * not to disrupt our current context on the stack
931 */
932CPU_Interrupt_frame current_thread_registers;
933
934
935
936/*
937 * This function handles all exceptions.  It only does two things:
938 * it figures out why it was activated and tells gdb, and then it
939 * reacts to gdb's requests.
940 */
941
942
943void handle_exception (rtems_vector_number vector, CPU_Interrupt_frame *frame)
944{
945   int          host_has_detached = 0;
946   int          regno, addr, length;
947   char         *ptr;
948   int          current_thread;  /* current generic thread */
949   int          thread;          /* stopped thread: context exception happened in */
950
951   long long    regval;
952   void         *regptr;
953   int          binary;
954   
955
956   registers = (mips_register_t *)frame;
957
958   thread = 0;
959#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
960   if (do_threads) {
961      thread = rtems_gdb_stub_get_current_thread();
962   }
963#endif
964   current_thread = thread;
965
966
967   {
968      /* reapply all breakpoints regardless of how we came in */
969      struct z0break *z0, *zother;
970
971      for (zother=z0break_list; zother!=NULL; zother=zother->next)
972      {
973         if( zother->instr == 0xffffffff )
974         {
975            /* grab the instruction */
976            zother->instr = *(zother->address);
977            /* and insert the breakpoint */
978            *(zother->address) = BREAK_INSTR;
979         }
980      }
981
982
983
984      /* see if we're coming from a breakpoint */
985      if( *((unsigned *)frame->epc) == BREAK_INSTR )
986      {
987         /* see if its one of our zbreaks */
988         for (z0=z0break_list; z0!=NULL; z0=z0->next)
989         {
990            if( (unsigned)z0->address == frame->epc)
991               break;
992         }
993         if( z0 )
994         {
995            /* restore the original instruction */
996            *(z0->address) = z0->instr;
997            /* flag the breakpoint */
998            z0->instr = 0xffffffff;
999
1000            /*
1001               now when we return, we'll execute the original code in
1002               the original state.  This leaves our breakpoint inactive
1003               since the break instruction isn't there, but we'll reapply
1004               it the next time we come in via step or breakpoint
1005            */
1006         }
1007         else
1008         {
1009            /* not a zbreak, see if its our trusty stepping code */
1010
1011            /*
1012             * Restore the saved instruction at
1013             * the single-step target address.
1014             */
1015            undoSStep();
1016         }
1017      }
1018   }
1019
1020
1021
1022
1023
1024   /* reply to host that an exception has occurred with some basic info */
1025   gdb_stub_report_exception_info(vector, frame, thread);
1026   putpacket (outBuffer);
1027
1028
1029
1030   while (!(host_has_detached)) {
1031      outBuffer[0] = '\0';
1032      getpacket (inBuffer);
1033      binary = 0;
1034
1035      switch (inBuffer[0]) {
1036         case '?':
1037            gdb_stub_report_exception_info(vector, frame, thread);
1038            break;
1039
1040         case 'd': /* toggle debug flag */
1041            /* can print ill-formed commands in valid packets & checksum errors */
1042            break;
1043
1044         case 'D':
1045            /* remote system is detaching - return OK and exit from debugger */
1046            strcpy (outBuffer, "OK");
1047            host_has_detached = 1;
1048            break;
1049
1050         case 'g':               /* return the values of the CPU registers */
1051            regptr = registers;
1052#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1053            if (do_threads && current_thread != thread )
1054               regptr = &current_thread_registers;
1055#endif
1056            mem2hex (regptr, NUM_REGS * (sizeof registers), outBuffer);
1057            break;
1058
1059
1060         case 'G':       /* set the values of the CPU registers - return OK */
1061            regptr = registers;
1062#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1063            if (do_threads && current_thread != thread )
1064               regptr = &current_thread_registers;
1065#endif
1066            if (hex2mem (&inBuffer[1], regptr, NUM_REGS * (sizeof registers)))
1067               strcpy (outBuffer, "OK");
1068            else
1069               strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
1070            break;
1071
1072
1073         case 'P':
1074            /* Pn...=r...  Write register n... with value r... - return OK */
1075            ptr = &inBuffer[1];
1076            if (hexToInt(&ptr, &regno) &&
1077                *ptr++ == '=' &&
1078                hexToLongLong(&ptr, &regval))
1079            {
1080               registers[regno] = regval;
1081               strcpy (outBuffer, "OK");
1082            }
1083            else
1084               strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
1085            break;
1086
1087
1088         case 'm':
1089            /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
1090            ptr = &inBuffer[1];
1091            if (hexToInt (&ptr, &addr)
1092                && *ptr++ == ','
1093                && hexToInt (&ptr, &length)
1094                && is_readable (addr, length)
1095                && (length < (BUFMAX - 4)/2))
1096               mem2hex ((void *)addr, length, outBuffer);
1097            else
1098               strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
1099            break;
1100
1101
1102         case 'X':  /* XAA..AA,LLLL:<binary data>#cs */
1103            binary = 1;
1104         case 'M':
1105            /* MAA..AA,LLLL:  Write LLLL bytes at address AA..AA - return OK */
1106            ptr = &inBuffer[1];
1107            if (hexToInt (&ptr, &addr)
1108                && *ptr++ == ','
1109                && hexToInt (&ptr, &length)
1110                && *ptr++ == ':'
1111                && is_writeable (addr, length) ) {
1112               if ( binary )
1113                  hex2mem (ptr, (void *)addr, length);
1114               else
1115                  bin2mem (ptr, (void *)addr, length);
1116               strcpy (outBuffer, "OK");
1117            }
1118            else
1119               strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
1120            break;
1121
1122
1123
1124         case 'c':
1125            /* cAA..AA    Continue at address AA..AA(optional) */
1126         case 's':
1127            /* sAA..AA    Step one instruction from AA..AA(optional) */
1128         {
1129            /* try to read optional parameter, pc unchanged if no parm */
1130            ptr = &inBuffer[1];
1131            if (hexToInt (&ptr, &addr))
1132               registers[PC] = addr;
1133
1134            if (inBuffer[0] == 's')
1135               doSStep ();
1136         }
1137         goto stubexit;
1138
1139
1140
1141
1142
1143         case 'k':  /* remove all zbreaks if any */
1144        dumpzbreaks:
1145         {
1146            {
1147               /* Unlink the entire list */
1148               struct z0break *z0, *znxt;
1149
1150               while( (z0= z0break_list) )
1151               {
1152
1153                  /* put back the instruction */
1154                  if( z0->instr != 0xffffffff )
1155                     *(z0->address) = z0->instr;
1156
1157                  /* pop off the top entry */
1158                  znxt = z0->next;
1159                  if( znxt ) znxt->prev = NULL;
1160                  z0break_list = znxt;
1161
1162                  /* and put it on the free list */
1163                  z0->prev = NULL;
1164                  z0->next = z0break_avail;
1165                  z0break_avail = z0;
1166               }
1167            }
1168
1169            strcpy(outBuffer, "OK");
1170         }
1171         break;
1172
1173
1174
1175
1176
1177         case 'q':   /* queries */
1178#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1179            rtems_gdb_process_query( inBuffer, outBuffer, do_threads, thread );
1180#endif
1181            break;
1182
1183#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1184         case 'T':
1185         {
1186            int testThread;
1187
1188            if( vhstr2thread(&inBuffer[1], &testThread) == NULL )
1189            {
1190               strcpy(outBuffer, "E01");
1191               break;
1192            }
1193
1194            if( rtems_gdb_index_to_stub_id(testThread) == NULL )
1195            {
1196               strcpy(outBuffer, "E02");
1197            }
1198            else
1199            {
1200               strcpy(outBuffer, "OK");
1201            }
1202         }
1203         break;
1204#endif
1205       
1206         case 'H':  /* set new thread */
1207#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1208            if (inBuffer[1] != 'g') {
1209               break;
1210            }
1211         
1212            if (!do_threads) {
1213               break;
1214            }
1215         
1216            {
1217               int tmp, ret;
1218           
1219               /* Set new generic thread */
1220               if (vhstr2thread(&inBuffer[2], &tmp) == NULL) {
1221                  strcpy(outBuffer, "E01");
1222                  break;
1223               }
1224
1225               /* 0 means `thread' */
1226               if (tmp == 0) {
1227                  tmp = thread;
1228               }
1229
1230               if (tmp == current_thread) {
1231                  /* No changes */
1232                  strcpy(outBuffer, "OK");
1233                  break;
1234               }
1235
1236               /* Save current thread registers if necessary */
1237               if (current_thread != thread) {
1238                  ret = rtems_gdb_stub_set_thread_regs(
1239                     current_thread, (unsigned int *) &current_thread_registers);
1240                  ASSERT(ret);
1241               }
1242
1243               /* Read new registers if necessary */
1244               if (tmp != thread) {
1245                  ret = rtems_gdb_stub_get_thread_regs(
1246                     tmp, (unsigned int *) &current_thread_registers);
1247
1248                  if (!ret) {
1249                     /* Thread does not exist */
1250                     strcpy(outBuffer, "E02");
1251                     break;
1252                  }
1253               }
1254           
1255               current_thread = tmp;
1256               strcpy(outBuffer, "OK");
1257            }
1258#endif
1259            break;
1260
1261
1262
1263
1264         case 'Z':  /* Add breakpoint */
1265         {
1266            int ret, type, len;
1267            unsigned *address;
1268            struct z0break *z0;
1269
1270            ret = parse_zbreak(inBuffer, &type, &address, &len);
1271            if (!ret) {
1272               strcpy(outBuffer, "E01");
1273               break;
1274            }
1275
1276            if (type != 0) {
1277               /* We support only software break points so far */
1278               strcpy(outBuffer, "E02");
1279               break;
1280            }
1281
1282            if (len != R_SZ) {     /* was 1 */
1283               strcpy(outBuffer, "E03");
1284               break;
1285            }
1286
1287            /* Let us check whether this break point already set */
1288            for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1289               if (z0->address == address) {
1290                  break;
1291               }
1292            }
1293
1294            if (z0 != NULL) {
1295               /* we already have a breakpoint for this address */
1296               strcpy(outBuffer, "E04");
1297               break;
1298            }
1299
1300            /* Let us allocate new break point */
1301            if (z0break_avail == NULL) {
1302               strcpy(outBuffer, "E05");
1303               break;
1304            }
1305
1306
1307            /* Get entry */
1308            z0 = z0break_avail;
1309            z0break_avail = z0break_avail->next;
1310
1311            /* Let us copy memory from address add stuff the break point in */
1312            /*
1313            *if (mem2hstr(z0->buf, address, 1) == NULL ||
1314              !hstr2mem(address, "cc" , 1)) {
1315
1316               * Memory error *
1317               z0->next = z0break_avail;
1318               z0break_avail = z0;
1319               strcpy(outBuffer, "E05");
1320               break;
1321            }*/
1322
1323            /* Fill it */
1324            z0->address = address;
1325
1326            if( z0->address == frame->epc )
1327            {
1328               /* re-asserting the breakpoint that put us in here, so
1329               we'll add the breakpoint but leave the code in place
1330               since we'll be returning to it when the user continues */
1331               z0->instr = 0xffffffff;
1332            }
1333            else
1334            {
1335               /* grab the instruction */
1336               z0->instr = *(z0->address);
1337               /* and insert the break */
1338               *(z0->address) = BREAK_INSTR;
1339            }
1340
1341            /* Add to the list */
1342            {
1343               struct z0break *znxt = z0break_list;
1344
1345               z0->prev = NULL;
1346               z0->next = znxt;
1347               
1348               if( znxt ) znxt->prev = z0;
1349               z0break_list = z0;
1350            }
1351
1352            strcpy(outBuffer, "OK");
1353         }
1354         break;
1355
1356
1357         case 'z': /* remove breakpoint */
1358            if (inBuffer[1] == 'z')
1359            {
1360               goto dumpzbreaks;
1361               
1362
1363               /*
1364                * zz packet - remove all breaks *
1365                z0last = NULL;
1366
1367                for (z0=z0break_list; z0!=NULL; z0=z0->next)
1368                {
1369                if(!hstr2mem(z0->address, z0->buf, R_SZ))
1370                {
1371                ret = 0;
1372                }
1373                z0last = z0;
1374                }
1375
1376                * Free entries if any *
1377                if (z0last != NULL) {
1378                z0last->next  = z0break_avail;
1379                z0break_avail = z0break_list;
1380                z0break_list  = NULL;
1381                }
1382
1383                if (ret) {
1384                strcpy(outBuffer, "OK");
1385                } else {
1386                strcpy(outBuffer, "E04");
1387                }
1388                break;
1389               */
1390            }
1391            else
1392            {
1393               int ret, type, len;
1394               unsigned   *address;
1395               struct z0break *z0;
1396             
1397               ret = parse_zbreak(inBuffer, &type, &address, &len);
1398               if (!ret) {
1399                  strcpy(outBuffer, "E01");
1400                  break;
1401               }
1402
1403               if (type != 0) {
1404                  /* We support only software break points so far */
1405                  break;
1406               }
1407
1408               if (len != R_SZ) {
1409                  strcpy(outBuffer, "E02");
1410                  break;
1411               }
1412           
1413               /* Let us check whether this break point set */
1414               for (z0=z0break_list; z0!=NULL; z0=z0->next) {
1415                  if (z0->address == address) {
1416                     break;
1417                  }
1418               }
1419             
1420               if (z0 == NULL) {
1421                  /* Unknown breakpoint */
1422                  strcpy(outBuffer, "E03");
1423                  break;
1424               }
1425           
1426               /*
1427               if (!hstr2mem(z0->address, z0->buf, R_SZ)) {
1428                  strcpy(outBuffer, "E04");
1429                  break;
1430                  }*/
1431
1432               if( z0->instr != 0xffffffff )
1433               {
1434                  /* put the old instruction back  */
1435                  *(z0->address) = z0->instr;
1436               }
1437   
1438               /* Unlink entry */
1439               {
1440                  struct z0break *zprv = z0->prev, *znxt = z0->next;
1441
1442                  if( zprv ) zprv->next = znxt;
1443                  if( znxt ) znxt->prev = zprv;
1444
1445                  if( !zprv ) z0break_list = znxt;
1446
1447                  znxt = z0break_avail;
1448
1449                  z0break_avail = z0;
1450                  z0->prev = NULL;
1451                  z0->next = znxt;
1452               }
1453   
1454               strcpy(outBuffer, "OK");
1455            }
1456            break;
1457
1458
1459         default: /* do nothing */
1460            break;
1461      }
1462
1463      /* reply to the request */
1464      putpacket (outBuffer);
1465   }
1466
1467  stubexit:
1468
1469   /*
1470    *  The original code did this in the assembly wrapper.  We should consider
1471    *  doing it here before we return.
1472    *
1473    *  On exit from the exception handler invalidate each line in the I-cache
1474    *  and write back each dirty line in the D-cache.  This needs to be done
1475    *  before the target program is resumed in order to ensure that software
1476    *  breakpoints and downloaded code will actually take effect.  This
1477    *  is because modifications to code in ram will affect the D-cache,
1478    *  but not necessarily the I-cache.
1479    */
1480
1481   {
1482      extern void clear_cache();
1483      clear_cache();
1484   }
1485
1486   return;
1487}
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498static int numsegs;
1499static struct memseg   memsegments[NUM_MEMSEGS];
1500
1501int gdbstub_add_memsegment( unsigned base, unsigned end, int opts )
1502{
1503   if( numsegs == NUM_MEMSEGS ) return -1;
1504
1505   memsegments[numsegs].begin = base;
1506   memsegments[numsegs].end   = end;
1507   memsegments[numsegs].opts   = opts;
1508
1509   ++numsegs;
1510   return RTEMS_SUCCESSFUL;
1511}
1512
1513
1514
1515
1516static int is_readable(unsigned ptr, unsigned len)
1517{
1518   struct memseg *ms;
1519   int i;
1520
1521   if( (ptr & 0x3) ) return -1;
1522
1523   for(i=0; i<numsegs; i++)
1524   {
1525      ms= &memsegments[i];
1526
1527      if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_READABLE) )
1528         return -1;
1529   }
1530   return 0;
1531}
1532
1533
1534static int is_writeable(unsigned ptr, unsigned len)
1535{
1536   struct memseg *ms;
1537   int i;
1538
1539   if( (ptr & 0x3) ) return -1;
1540
1541   for(i=0; i<numsegs; i++)
1542   {
1543      ms= &memsegments[i];
1544
1545      if( ms->begin <= ptr && ptr+len <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
1546         return -1;
1547   }
1548   return 0;
1549}
1550
1551
1552static int is_steppable(unsigned ptr)
1553{
1554   struct memseg *ms;
1555   int i;
1556
1557   if( (ptr & 0x3) ) return -1;
1558
1559   for(i=0; i<numsegs; i++)
1560   {
1561      ms= &memsegments[i];
1562
1563      if( ms->begin <= ptr && ptr <= ms->end && (ms->opts & MEMOPT_WRITEABLE) )
1564         return -1;
1565   }
1566   return 0;
1567}
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582static char initialized = 0;   /* 0 means we are not initialized */
1583
1584void mips_gdb_stub_install(int enableThreads)
1585{
1586   /*
1587     These are the RTEMS-defined vectors for all the MIPS exceptions
1588   */
1589   int exceptionVector[]= { MIPS_EXCEPTION_MOD, \
1590                            MIPS_EXCEPTION_TLBL, \
1591                            MIPS_EXCEPTION_TLBS, \
1592                            MIPS_EXCEPTION_ADEL, \
1593                            MIPS_EXCEPTION_ADES, \
1594                            MIPS_EXCEPTION_IBE, \
1595                            MIPS_EXCEPTION_DBE, \
1596                            MIPS_EXCEPTION_SYSCALL, \
1597                            MIPS_EXCEPTION_BREAK, \
1598                            MIPS_EXCEPTION_RI, \
1599                            MIPS_EXCEPTION_CPU, \
1600                            MIPS_EXCEPTION_OVERFLOW, \
1601                            MIPS_EXCEPTION_TRAP, \
1602                            MIPS_EXCEPTION_VCEI, \
1603                            MIPS_EXCEPTION_FPE, \
1604                            MIPS_EXCEPTION_C2E, \
1605                            MIPS_EXCEPTION_WATCH, \
1606                            MIPS_EXCEPTION_VCED, \
1607                            -1 };
1608   int  i;
1609   rtems_isr_entry old;
1610
1611   if (initialized)
1612   {
1613      ASSERT(0);
1614      return;
1615   }
1616
1617   memset( memsegments,0,sizeof(struct memseg)*NUM_MEMSEGS );
1618   numsegs = 0;
1619
1620#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1621   if( enableThreads )
1622      do_threads = 1;
1623   else
1624      do_threads = 0;
1625#endif
1626
1627   {
1628      struct z0break *z0;
1629
1630      z0break_avail = NULL;
1631      z0break_list  = NULL;
1632   
1633      /* z0breaks list init, now we'll do it so it makes sense... */
1634      for (i=0; i<BREAKNUM; i++)
1635      {
1636         memset( (z0= &z0break_arr[i]), 0, sizeof(struct z0break));
1637
1638         z0->next = z0break_avail;
1639         z0break_avail = z0;
1640      }
1641   }     
1642
1643   for(i=0; exceptionVector[i] > -1; i++)
1644   {
1645      rtems_interrupt_catch( (rtems_isr_entry) handle_exception, exceptionVector[i], &old );
1646   }
1647
1648   initialized = 1;
1649
1650   /* get the attention of gdb */
1651   /* mips_break(1);  disabled so user code can choose to invoke it or not */
1652}
1653
1654
1655
Note: See TracBrowser for help on using the repository browser.