source: rtems/c/src/lib/libbsp/m68k/shared/gdbstub/m68k-stub.c @ 1c3ea41

4.104.114.84.95
Last change on this file since 1c3ea41 was ee55cdb, checked in by Joel Sherrill <joel.sherrill@…>, on 10/31/02 at 20:07:42

2002-10-31 Joel Sherrill <joel@…>

  • m68k-stub.c: Fixed warnings about multi-line strings in asm.
  • Property mode set to 100644
File size: 42.2 KB
Line 
1#define  GDB_STUB_ENABLE_THREAD_SUPPORT 1
2/****************************************************************************
3
4                THIS SOFTWARE IS NOT COPYRIGHTED 
5   
6   HP offers the following for use in the public domain.  HP makes no
7   warranty with regard to the software or it's performance and the
8   user accepts the software "AS IS" with all faults.
9
10   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
11   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
12   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13
14****************************************************************************/
15
16/****************************************************************************
17 *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $                   
18 *
19 *  Module name: remcom.c $ 
20 *  Revision: 1.34 $
21 *  Date: 91/03/09 12:29:49 $
22 *  Contributor:     Lake Stevens Instrument Division$
23 * 
24 *  Description:     low level support for gdb debugger. $
25 *
26 *  Considerations:  only works on target hardware $
27 *
28 *  Written by:      Glenn Engel $
29 *  ModuleState:     Experimental $
30 *
31 *  NOTES:           See Below $
32 *
33 *  To enable debugger support, two things need to happen.  One, a
34 *  call to set_debug_traps() is necessary in order to allow any breakpoints
35 *  or error conditions to be properly intercepted and reported to gdb.
36 *  Two, a breakpoint needs to be generated to begin communication.  This
37 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
38 *  simulates a breakpoint by executing a trap #1.  The breakpoint instruction
39 *  is hardwired to trap #1 because not to do so is a compatibility problem--
40 *  there either should be a standard breakpoint instruction, or the protocol
41 *  should be extended to provide some means to communicate which breakpoint
42 *  instruction is in use (or have the stub insert the breakpoint).
43 * 
44 *  Some explanation is probably necessary to explain how exceptions are
45 *  handled.  When an exception is encountered the 68000 pushes the current
46 *  program counter and status register onto the supervisor stack and then
47 *  transfers execution to a location specified in it's vector table.
48 *  The handlers for the exception vectors are hardwired to jmp to an address
49 *  given by the relation:  (exception - 256) * 6.  These are decending
50 *  addresses starting from -6, -12, -18, ...  By allowing 6 bytes for
51 *  each entry, a jsr, jmp, bsr, ... can be used to enter the exception
52 *  handler.  Using a jsr to handle an exception has an added benefit of
53 *  allowing a single handler to service several exceptions and use the
54 *  return address as the key differentiation.  The vector number can be
55 *  computed from the return address by [ exception = (addr + 1530) / 6 ].
56 *  The sole purpose of the routine _catchException is to compute the
57 *  exception number and push it on the stack in place of the return address.
58 *  The external function exceptionHandler() is
59 *  used to attach a specific handler to a specific m68k exception.
60 *  For 68020 machines, the ability to have a return address around just
61 *  so the vector can be determined is not necessary because the '020 pushes an
62 *  extra word onto the stack containing the vector offset
63 *
64 *  Because gdb will sometimes write to the stack area to execute function
65 *  calls, this program cannot rely on using the supervisor stack so it
66 *  uses it's own stack area reserved in the int array remcomStack. 
67 *
68 *************
69 *
70 *    The following gdb commands are supported:
71 *
72 * command          function                               Return value
73 *
74 *    g             return the value of the CPU registers  hex data or ENN
75 *    G             set the value of the CPU registers     OK or ENN
76 *
77 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
78 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
79 *
80 *    c             Resume at current address              SNN   ( signal NN)
81 *    cAA..AA       Continue at address AA..AA             SNN
82 *
83 *    s             Step one instruction                   SNN
84 *    sAA..AA       Step one instruction from AA..AA       SNN
85 *
86 *    k             kill
87 *
88 *    ?             What was the last sigval ?             SNN   (signal NN)
89 *
90 * All commands and responses are sent with a packet which includes a
91 * checksum.  A packet consists of
92 *
93 * $<packet info>#<checksum>.
94 *
95 * where
96 * <packet info> :: <characters representing the command or response>
97 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
98 *
99 * When a packet is received, it is first acknowledged with either '+' or '-'.
100 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
101 *
102 * Example:
103 *
104 * Host:                  Reply:
105 * $m0,10#2a               +$00010203040506070809101112131415#42
106 *
107 ***************************************************************************
108 *    added 05/27/02 by IMD, Thomas Doerfler:
109 *    XAA..AA,LLLL: Write LLLL binary bytes at address AA.AA      OK or ENN
110 ****************************************************************************/
111
112#include <stdio.h>
113#include <string.h>
114#include <setjmp.h>
115/* #include <asm.h>*/
116#include <rtems.h>
117#include <rtems/score/cpu.h>
118#include "gdb_if.h"
119
120#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
121static char do_threads = 1;      /* != 0 means we are supporting threads */
122int current_thread_registers[NUMREGBYTES/4];
123#endif
124
125/************************************************************************
126 *
127 * external low-level support routines
128 */
129typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
130typedef void (*Function)();           /* pointer to a function */
131
132
133extern void putDebugChar();     /* write a single character      */
134extern int getDebugChar();      /* read and return a single char */
135
136
137/************************/
138/* FORWARD DECLARATIONS */
139/************************/
140static void
141initializeRemcomErrorFrame ();
142
143/************************************************************************/
144/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
145/* at least NUMREGBYTES*2 are needed for register packets */
146#define BUFMAX 400
147
148static char initialized;  /* boolean flag. != 0 means we've been initialized */
149
150int     remote_debug;
151/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
152
153const char gdb_hexchars[]="0123456789abcdef";
154#define highhex(x) gdb_hexchars [(x >> 4) & 0xf]
155#define lowhex(x) gdb_hexchars [x & 0xf]
156
157
158
159/* We keep a whole frame cache here.  "Why?", I hear you cry, "doesn't
160   GDB handle that sort of thing?"  Well, yes, I believe the only
161   reason for this cache is to save and restore floating point state
162   (fsave/frestore).  A cleaner way to do this would be to make the
163 fsave data part of the registers which GDB deals with like any
164   other registers.  This should not be a performance problem if the
165   ability to read individual registers is added to the protocol.  */
166
167typedef struct FrameStruct
168{
169    struct FrameStruct  *previous;
170    int       exceptionPC;      /* pc value when this frame created */
171    int       exceptionVector;  /* cpu vector causing exception     */
172    short     frameSize;        /* size of cpu frame in words       */
173    short     sr;               /* for 68000, this not always sr    */
174    int       pc;
175    short     format;
176    int       fsaveHeader;
177    int       morejunk[0];        /* exception frame, fp save... */
178} Frame;
179
180#define FRAMESIZE 500
181int   gdbFrameStack[FRAMESIZE];
182static Frame *lastFrame;
183
184/*
185 * these should not be static cuz they can be used outside this module
186 */
187int registers[NUMREGBYTES/4];
188int superStack;
189
190#define STACKSIZE 10000
191int remcomStack[STACKSIZE/sizeof(int)];
192static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
193
194/*
195 * In many cases, the system will want to continue exception processing
196 * when a continue command is given. 
197 * oldExceptionHook is a function to invoke in this case.
198 */
199
200static ExceptionHook oldExceptionHook;
201/* the size of the exception stack on the 68020/30/40/CPU32 varies with
202 * the type of exception.  The following table is the number of WORDS used
203 * for each exception format.
204 * This table should be common for all 68k with VBR
205 * although each member only implements some of the formats
206 */
207const short exceptionSize[] = { 4,4,6,6,4,4,4,30,29,10,16,46,12,4,4,4 };
208
209
210/************* jump buffer used for setjmp/longjmp **************************/
211jmp_buf remcomEnv;
212
213/***************************  ASSEMBLY CODE MACROS *************************/
214/*                                                                         */
215
216#ifdef __HAVE_68881__
217/* do an fsave, then remember the address to begin a restore from */
218#define SAVE_FP_REGS()    asm(" fsave   -(%a0)");               \
219                          asm(" fmovem.x %fp0-%fp7,registers+72");        \
220                          asm(" fmovem.l %fpcr/%fpsr/%fpi,registers+168");
221#define RESTORE_FP_REGS()                              \
222asm("                                                \n\
223    fmovem.l  registers+168,%fpcr/%fpsr/%fpi            \n\
224    fmovem.x  registers+72,%fp0-%fp7                   \n\
225    cmp.l     #-1,(%a0)     |  skip frestore flag set ? \n\
226    beq      skip_frestore                           \n\
227    frestore (%a0)+                                    \n\
228skip_frestore:                                       \n\
229");
230
231#else
232#define SAVE_FP_REGS()
233#define RESTORE_FP_REGS()
234#endif /* __HAVE_68881__ */
235
236void return_to_super();
237void return_to_user();
238extern void _catchException ();
239
240void m68k_exceptionHandler
241(
242 int vecnum,                            /* vector index to hook at         */
243 void *vector                           /* address of handler function     */
244)
245{
246  void **vec_base = NULL;
247#if M68K_HAS_VBR
248  /*
249   * get vector base register
250   */
251  asm(" movec.l %%vbr,%0":"=a" (vec_base));
252#endif
253  vec_base[vecnum] = vector;
254}
255
256ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
257
258void m68k_stub_dummy_asm_wrapper()
259     /*
260      * this dummy wrapper function ensures,
261      * that the C compiler manages sections properly
262      */
263{
264asm("\n\
265.globl return_to_super                                                  \n\
266return_to_super:                                                        \n\
267        move.l   registers+60,%sp /* get new stack pointer */           \n\
268        move.l   lastFrame,%a0   /* get last frame info  */             \n\
269        bra     return_to_any                                           \n\
270                                                                        \n\
271.globl _return_to_user                                                  \n\
272return_to_user:                                                         \n\
273        move.l   registers+60,%a0 /* get usp */                         \n\
274        move.l   %a0,%usp           /* set usp */                       \n\
275        move.l   superStack,%sp  /* get original stack pointer */       \n\
276                                                                        \n\
277return_to_any:                                                          \n\
278        move.l   lastFrame,%a0   /* get last frame info  */             \n\
279        move.l   (%a0)+,lastFrame /* link in previous frame     */      \n\
280        addq.l   #8,%a0           /* skip over pc, vector#*/            \n\
281        move.w   (%a0)+,%d0         /* get # of words in cpu frame */   \n\
282        add.w    %d0,%a0           /* point to end of data        */    \n\
283        add.w    %d0,%a0           /* point to end of data        */    \n\
284        move.l   %a0,%a1                                                \n\
285#                                                                       \n\
286# copy the stack frame                                                  \n\
287        subq.l   #1,%d0                                                 \n\
288copyUserLoop:                                                           \n\
289        move.w   -(%a1),-(%sp)                                          \n\
290        dbf     %d0,copyUserLoop                                        \n\
291");
292        RESTORE_FP_REGS()
293   asm("   movem.l  registers,%d0-%d7/%a0-%a6");                               
294   asm("   rte");  /* pop and go! */                                   
295
296#define DISABLE_INTERRUPTS()   asm("         oriw   #0x0700,%sr");
297#define BREAKPOINT() asm("   trap #2");
298
299/* this function is called immediately when a level 7 interrupt occurs */
300/* if the previous interrupt level was 7 then we're already servicing  */
301/* this interrupt and an rte is in order to return to the debugger.    */
302/* For the 68000, the offset for sr is 6 due to the jsr return address */
303asm("                                           \n\
304.text                                           \n\
305.globl _debug_level7                            \n\
306_debug_level7:                                  \n\
307        move.w   %d0,-(%sp)");
308#if M68K_HAS_VBR
309asm("   move.w   2(%sp),%d0");
310#else
311asm("   move.w   6(%sp),%d0");
312#endif
313asm("   andi.w   #0x700,%d0                     \n\
314        cmpi.w   #0x700,%d0                     \n\
315        beq     already7                        \n\
316        move.w   (%sp)+,%d0                     \n\
317        bra     _catchException                 \n\
318already7:                                       \n\
319        move.w   (%sp)+,%d0");
320#if !M68K_HAS_VBR
321asm("   lea     4(%sp),%sp");     /* pull off 68000 return address */
322#endif
323asm("   rte");
324
325
326#if M68K_HAS_VBR
327/* This function is called when a 68020 exception occurs.  It saves
328 * all the cpu and fpcp regs in the _registers array, creates a frame on a
329 * linked list of frames which has the cpu and fpcp stack frames needed
330 * to properly restore the context of these processors, and invokes
331 * an exception handler (remcom_handler).
332 *
333 * stack on entry:                       stack on exit:
334 *   N bytes of junk                     exception # MSWord
335 *   Exception Format Word               exception # MSWord
336 *   Program counter LSWord             
337 *   Program counter MSWord             
338 *   Status Register                   
339 *                                       
340 *                                       
341 */
342asm("                                           \n\
343.text                                           \n\
344.globl _catchException                          \n\
345_catchException:");
346DISABLE_INTERRUPTS();
347asm("                                                                   \n\
348        movem.l  %d0-%d7/%a0-%a6,registers /* save registers        */  \n\
349        move.l  lastFrame,%a0   /* last frame pointer */                \n\
350");
351SAVE_FP_REGS();       
352asm("\n\
353        lea     registers,%a5   /* get address of registers     */\n\
354        move.w  (%sp),%d1        /* get status register          */\n\
355        move.w   %d1,66(%a5)      /* save sr                    */      \n\
356        move.l   2(%sp),%a4      /* save pc in a4 for later use  */\n\
357        move.w   6(%sp),%d0     /* get '020 exception format    */\n\
358        move.w   %d0,%d2        /* make a copy of format word   */\n\
359#\n\
360# compute exception number\n\
361        and.l    #0xfff,%d2     /* mask off vector offset       */\n\
362        lsr.w    #2,%d2         /* divide by 4 to get vect num  */\n\
363/* #if 1 */\n\
364        cmp.l    #33,%d2\n\
365        bne      nopc_adjust\n\
366        subq.l   #2,%a4\n\
367nopc_adjust:\n\
368/* #endif */\n\
369        move.l   %a4,68(%a5)     /* save pc in _regisers[]              */\n\
370\n\
371#\n\
372# figure out how many bytes in the stack frame\n\
373        andi.w   #0xf000,%d0    /* mask off format type         */\n\
374        rol.w    #5,%d0         /* rotate into the low byte *2  */\n\
375        lea     exceptionSize,%a1   \n\
376        add.w    %d0,%a1        /* index into the table         */\n\
377        move.w   (%a1),%d0      /* get number of words in frame */\n\
378        move.w   %d0,%d3        /* save it                      */\n\
379        sub.w    %d0,%a0        /* adjust save pointer          */\n\
380        sub.w    %d0,%a0        /* adjust save pointer(bytes)   */\n\
381        move.l   %a0,%a1        /* copy save pointer            */\n\
382        subq.l   #1,%d0         /* predecrement loop counter    */\n\
383#\n\
384# copy the frame\n\
385saveFrameLoop:\n\
386        move.w  (%sp)+,(%a1)+\n\
387        dbf     %d0,saveFrameLoop\n\
388#\n\
389# now that the stack has been clenaed,\n\
390# save the a7 in use at time of exception\n\
391        move.l   %sp,superStack  /* save supervisor sp           */\n\
392        andi.w   #0x2000,%d1      /* were we in supervisor mode ? */\n\
393        beq      userMode       \n\
394        move.l   %a7,60(%a5)      /* save a7                  */\n\
395        bra      a7saveDone\n\
396userMode:  \n\
397        move.l   %usp,%a1       \n\
398        move.l   %a1,60(%a5)      /* save user stack pointer    */\n\
399a7saveDone:\n\
400\n\
401#\n\
402# save size of frame\n\
403        move.w   %d3,-(%a0)\n\
404\n\
405        move.l   %d2,-(%a0)     /* save vector number           */\n\
406#\n\
407# save pc causing exception\n\
408        move.l   %a4,-(%a0)\n\
409#\n\
410# save old frame link and set the new value\n\
411        move.l  lastFrame,%a1   /* last frame pointer */\n\
412        move.l   %a1,-(%a0)             /* save pointer to prev frame   */\n\
413        move.l   %a0,lastFrame\n\
414\n\
415        move.l   %d2,-(%sp)         /* push exception num           */\n\
416        move.l   exceptionHook,%a0  /* get address of handler */\n\
417        jbsr    (%a0)             /* and call it */\n\
418        clr.l   (%sp)            /* replace exception num parm with frame ptr */\n\
419        jbsr     _returnFromException   /* jbsr, but never returns */\n\
420");\n\
421#else /* mc68000 */
422/* This function is called when an exception occurs.  It translates the
423 * return address found on the stack into an exception vector # which
424 * is then handled by either handle_exception or a system handler.
425 * _catchException provides a front end for both. 
426 *
427 * stack on entry:                       stack on exit:
428 *   Program counter MSWord              exception # MSWord
429 *   Program counter LSWord              exception # MSWord
430 *   Status Register                     
431 *   Return Address  MSWord             
432 *   Return Address  LSWord             
433 */
434asm("\n\
435.text\n\
436.globl _catchException\n\
437_catchException:");
438DISABLE_INTERRUPTS();
439asm("\
440        moveml %d0-%d7/%a0-%a6,registers  /* save registers               */ \n\
441        movel   lastFrame,%a0   /* last frame pointer */ \n\
442");
443SAVE_FP_REGS();       
444asm(" \n\
445        lea     registers,%a5   /* get address of registers     */ \n\
446        movel   (%sp)+,%d2         /* pop return address           */ \n\
447        addl    #1530,%d2        /* convert return addr to      */ \n\
448        divs    #6,%d2          /*  exception number            */ \n\
449        extl    %d2    \n\
450 \n\
451        moveql  #3,%d3           /* assume a three word frame     */ \n\
452 \n\
453        cmpiw   #3,%d2           /* bus error or address error ? */ \n\
454        bgt     normal          /* if >3 then normal error      */ \n\
455        movel   (%sp)+,-(%a0)       /* copy error info to frame buff*/ \n\
456        movel   (%sp)+,-(%a0)       /* these are never used         */ \n\
457        moveql  #7,%d3           /* this is a 7 word frame       */ \n\
458      \n\
459normal:    \n\
460        movew   (%sp)+,%d1         /* pop status register          */ \n\
461        movel   (%sp)+,%a4         /* pop program counter          */ \n\
462        movew   %d1,66(%a5)      /* save sr                     */       \n\
463        movel   %a4,68(%a5)      /* save pc in _regisers[]              */ \n\
464        movel   %a4,-(%a0)         /* copy pc to frame buffer      */ \n\
465        movew   %d1,-(%a0)         /* copy sr to frame buffer      */ \n\
466 \n\
467        movel   %sp,superStack  /* save supervisor sp          */ \n\
468 \n\
469        andiw   #0x2000,%d1      /* were we in supervisor mode ? */ \n\
470        beq     userMode        \n\
471        movel   %a7,60(%a5)      /* save a7                  */ \n\
472        bra     saveDone              \n\
473userMode: \n\
474        movel   %usp,%a1        /* save user stack pointer      */ \n\
475        movel   %a1,60(%a5)      /* save user stack pointer     */ \n\
476saveDone: \n\
477 \n\
478        movew   %d3,-(%a0)         /* push frame size in words     */ \n\
479        movel   %d2,-(%a0)         /* push vector number           */ \n\
480        movel   %a4,-(%a0)         /* push exception pc            */ \n\
481 \n\
482# \n\
483# save old frame link and set the new value \n\
484        movel   _lastFrame,%a1  /* last frame pointer */ \n\
485        movel   %a1,-(%a0)              /* save pointer to prev frame   */ \n\
486        movel   %a0,lastFrame \n\
487 \n\
488        movel   %d2,-(%sp)              /* push exception num           */ \n\
489        movel   exceptionHook,%a0  /* get address of handler */ \n\
490        jbsr    (%a0)             /* and call it */ \n\
491        clrl    (%sp)             /* replace exception num parm with frame ptr */ \n\
492        jbsr     _returnFromException   /* jbsr, but never returns */ \n\
493");
494#endif
495
496
497/*
498 * remcomHandler is a front end for handle_exception.  It moves the
499 * stack pointer into an area reserved for debugger use in case the
500 * breakpoint happened in supervisor mode.
501 */
502asm("remcomHandler:");
503asm("           add.l    #4,%sp");        /* pop off return address     */
504asm("           move.l   (%sp)+,%d0");      /* get the exception number   */
505asm("           move.l   stackPtr,%sp"); /* move to remcom stack area  */
506asm("           move.l   %d0,-(%sp)");  /* push exception onto stack  */
507asm("           jbsr    handle_exception");    /* this never returns */
508asm("           rts");                  /* return */
509} /* end of stub_dummy_asm_wrapper function */
510
511void _returnFromException( Frame *frame )
512{
513    /* if no passed in frame, use the last one */
514    if (! frame)
515    {
516        frame = lastFrame;
517        frame->frameSize = 4;
518        frame->format = 0;
519        frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/
520    }
521
522#if !M68K_HAS_VBR
523    /* a 68000 cannot use the internal info pushed onto a bus error
524     * or address error frame when doing an RTE so don't put this info
525     * onto the stack or the stack will creep every time this happens.
526     */
527    frame->frameSize=3;
528#endif
529
530    /* throw away any frames in the list after this frame */
531    lastFrame = frame;
532
533    frame->sr = registers[(int) PS];
534    frame->pc = registers[(int) PC];
535
536    if (registers[(int) PS] & 0x2000)
537    {
538        /* return to supervisor mode... */
539        return_to_super();
540    }
541    else
542    { /* return to user mode */
543        return_to_user();
544    }
545}
546
547int hex(ch)
548char ch;
549{
550  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
551  if ((ch >= '0') && (ch <= '9')) return (ch-'0');
552  if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
553  return (-1);
554}
555
556
557/* scan for the sequence $<data>#<checksum>     */
558void getpacket(buffer)
559char * buffer;
560{
561  unsigned char checksum;
562  unsigned char xmitcsum;
563  int  i;
564  int  count;
565  char ch;
566 
567  do {
568    /* wait around for the start character, ignore all other characters */
569    while ((ch = getDebugChar()) != '$');
570    checksum = 0;
571    xmitcsum = -1;
572   
573    count = 0;
574   
575    /* now, read until a # or end of buffer is found */
576    while (count < BUFMAX) {
577      ch = getDebugChar();
578      if (ch == '#') break;
579      checksum = checksum + ch;
580      buffer[count] = ch;
581      count = count + 1;
582      }
583    buffer[count] = 0;
584
585    if (ch == '#') {
586      xmitcsum = hex(getDebugChar()) << 4;
587      xmitcsum += hex(getDebugChar());
588      if ((remote_debug ) && (checksum != xmitcsum)) {
589        fprintf (stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
590                                                     checksum,xmitcsum,buffer);
591      }
592     
593      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
594      else {
595         putDebugChar('+');  /* successful transfer */
596         /* if a sequence char is present, reply the sequence ID */
597         if (buffer[2] == ':') {
598            putDebugChar( buffer[0] );
599            putDebugChar( buffer[1] );
600            /* remove sequence chars from buffer */
601            count = strlen(buffer);
602            for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
603         }
604      }
605    }
606  } while (checksum != xmitcsum);
607 
608}
609
610/* send the packet in buffer.  The host get's one chance to read it. 
611   This routine does not wait for a positive acknowledge.  */
612
613
614/*
615 * Send the packet in buffer and wait for a positive acknowledgement.
616 */
617static void
618putpacket (char *buffer)
619{
620  int checksum;
621
622  /* $<packet info>#<checksum> */
623  do
624    {
625      char *src = buffer;
626      putDebugChar ('$');
627      checksum = 0;
628
629      while (*src != '\0')
630        {
631          int runlen = 0;
632
633          /* Do run length encoding */
634          while ((src[runlen] == src[0]) && (runlen < 99))
635            runlen++;
636          if (runlen > 3)
637            {
638              int encode;
639              /* Got a useful amount */
640              putDebugChar (*src);
641              checksum += *src;
642              putDebugChar ('*');
643              checksum += '*';
644              checksum += (encode = (runlen - 4) + ' ');
645              putDebugChar (encode);
646              src += runlen;
647            }
648          else
649            {
650              putDebugChar (*src);
651              checksum += *src;
652              src++;
653             }
654        }
655
656      putDebugChar ('#');
657      putDebugChar (highhex (checksum));
658      putDebugChar (lowhex (checksum));
659    }
660  while  (getDebugChar () != '+');
661}
662
663char  remcomInBuffer[BUFMAX];
664char  remcomOutBuffer[BUFMAX];
665static short error;
666
667
668void debug_error(
669char * format,
670char * parm
671)
672{
673  if (remote_debug) fprintf (stderr,format,parm);
674}
675
676/* convert the memory pointed to by mem into hex, placing result in buf */
677/* return a pointer to the last char put in buf (null) */
678char* mem2hex(mem, buf, count)
679char* mem;
680char* buf;
681int   count;
682{
683      int i;
684      unsigned char ch;
685      for (i=0;i<count;i++) {
686          ch = *mem++;
687          *buf++ = gdb_hexchars[ch >> 4];
688          *buf++ = gdb_hexchars[ch % 16];
689      }
690      *buf = 0;
691      return(buf);
692}
693
694/* convert the hex array pointed to by buf into binary to be placed in mem */
695/* return a pointer to the character AFTER the last byte written */
696char* hex2mem(buf, mem, count)
697char* buf;
698char* mem;
699int   count;
700{
701      int i;
702      unsigned char ch;
703      for (i=0;i<count;i++) {
704          ch = hex(*buf++) << 4;
705          ch = ch + hex(*buf++);
706          *mem++ = ch;
707      }
708      return(mem);
709}
710
711/* Convert the binary stream in BUF to memory.
712
713   Gdb will escape $, #, and the escape char (0x7d).
714   COUNT is the total number of bytes to write into
715   memory. */
716static unsigned char *
717bin2mem (
718  unsigned char *buf,
719  unsigned char *mem,
720  int   count
721)
722{
723  int i;
724
725  for (i = 0; i < count; i++) {
726      /* Check for any escaped characters. Be paranoid and
727         only unescape chars that should be escaped. */
728      if (*buf == 0x7d) {
729          switch (*(buf+1)) {
730            case 0x3:  /* # */
731            case 0x4:  /* $ */
732            case 0x5d: /* escape char */
733              buf++;
734              *buf |= 0x20;
735              break;
736            default:
737              /* nothing */
738              break;
739            }
740        }
741
742      *mem++ = *buf++;
743    }
744
745  return mem;
746}
747
748/* a bus error has occurred, perform a longjmp
749   to return execution and allow handling of the error */
750
751void handle_buserror()
752{
753  longjmp(remcomEnv,1);
754}
755
756/* this function takes the 68000 exception number and attempts to
757   translate this number into a unix compatible signal value */
758int computeSignal( exceptionVector )
759int exceptionVector;
760{
761  int sigval;
762  switch (exceptionVector) {
763    case 2 : sigval = 10; break; /* bus error           */
764    case 3 : sigval = 10; break; /* address error       */
765    case 4 : sigval = 4;  break; /* illegal instruction */
766    case 5 : sigval = 8;  break; /* zero divide         */
767    case 6 : sigval = 8; break; /* chk instruction     */
768    case 7 : sigval = 8; break; /* trapv instruction   */
769    case 8 : sigval = 11; break; /* privilege violation */
770    case 9 : sigval = 5;  break; /* trace trap          */
771    case 10: sigval = 4;  break; /* line 1010 emulator  */
772    case 11: sigval = 4;  break; /* line 1111 emulator  */
773
774      /* Coprocessor protocol violation.  Using a standard MMU or FPU
775         this cannot be triggered by software.  Call it a SIGBUS.  */
776    case 13: sigval = 10;  break;
777
778    case 31: sigval = 2;  break; /* interrupt           */
779    case 33: sigval = 5;  break; /* GDB breakpoint      */
780    case 34: sigval = 5;  break; /* coded breakpoint    */
781
782      /* This is a trap #8 instruction.  Apparently it is someone's software
783         convention for some sort of SIGFPE condition.  Whose?  How many
784         people are being screwed by having this code the way it is?
785         Is there a clean solution?  */
786    case 40: sigval = 8;  break; /* floating point err  */
787
788    case 48: sigval = 8;  break; /* floating point err  */
789    case 49: sigval = 8;  break; /* floating point err  */
790    case 50: sigval = 8;  break; /* zero divide         */
791    case 51: sigval = 8;  break; /* underflow           */
792    case 52: sigval = 8;  break; /* operand error       */
793    case 53: sigval = 8;  break; /* overflow            */
794    case 54: sigval = 8;  break; /* NAN                 */
795    default:
796      sigval = 7;         /* "software generated"*/
797  }
798  return (sigval);
799}
800
801/**********************************************/
802/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
803/* RETURN NUMBER OF CHARS PROCESSED           */
804/**********************************************/
805int hexToInt(char **ptr, int *intValue)
806{
807    int numChars = 0;
808    int hexValue;
809   
810    *intValue = 0;
811
812    while (**ptr)
813    {
814        hexValue = hex(**ptr);
815        if (hexValue >=0)
816        {
817            *intValue = (*intValue <<4) | hexValue;
818            numChars ++;
819        }
820        else
821            break;
822       
823        (*ptr)++;
824    }
825
826    return (numChars);
827}
828
829/*
830 *  This support function prepares and sends the message containing the
831 *  basic information about this exception.
832 */
833
834void gdb_stub_report_exception_info(
835  int vector,
836  int *regs,
837  int thread
838)
839{
840   char *optr;
841   int sigval;
842
843   optr = remcomOutBuffer;
844   *optr++ = 'T';
845   sigval = computeSignal (vector);
846   *optr++ = highhex (sigval);
847   *optr++ = lowhex (sigval);
848
849   *optr++ = highhex(A7);
850   *optr++ = lowhex(A7);
851   *optr++ = ':';
852   optr    = mem2hstr(optr,
853                      (unsigned char *)&(regs[A7]),
854                      sizeof(regs[A7]));
855   *optr++ = ';';
856 
857   *optr++ = highhex(PC);
858   *optr++ = lowhex(PC);
859   *optr++ = ':';
860   optr    = mem2hstr(optr,
861                      (unsigned char *)&(regs[PC]),
862                      sizeof(regs[PC]) );
863   *optr++ = ';';
864
865#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
866   if (do_threads)
867   {
868      *optr++ = 't';
869      *optr++ = 'h';
870      *optr++ = 'r';
871      *optr++ = 'e';
872      *optr++ = 'a';
873      *optr++ = 'd';
874      *optr++ = ':';
875      optr   = thread2vhstr(optr, thread);
876      *optr++ = ';';
877   }
878#endif
879   *optr++ = '\0';
880}
881
882/*
883 * This function does all command procesing for interfacing to gdb.
884 */
885void handle_exception(int exceptionVector)
886{
887  int    host_has_detached = 0;
888  int    addr, length;
889  char * ptr;
890  int    newPC;
891  Frame  *frame;
892  int          current_thread;  /* current generic thread */
893  int          thread;          /* stopped thread: context exception happened in */
894   void         *regptr;
895   int binary;
896
897  if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n",
898                            exceptionVector,
899                            registers[ PS ],
900                            registers[ PC ]);
901
902   thread = 0;
903#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
904   if (do_threads) {
905      thread = rtems_gdb_stub_get_current_thread();
906   }
907#endif
908   current_thread = thread;
909 
910#if 0
911  /* reply to host that an exception has occurred */
912  sigval = computeSignal( exceptionVector );
913  remcomOutBuffer[0] = 'S';
914  remcomOutBuffer[1] =  gdb_hexchars[sigval >> 4];
915  remcomOutBuffer[2] =  gdb_hexchars[sigval % 16];
916  remcomOutBuffer[3] = 0;
917#else
918   /* reply to host that an exception has occurred with some basic info */
919   gdb_stub_report_exception_info(exceptionVector, registers, thread);
920#endif
921
922  putpacket(remcomOutBuffer);
923
924  while (!(host_has_detached)) {
925    binary = 0;
926    error = 0;
927    remcomOutBuffer[0] = 0;
928    getpacket(remcomInBuffer);
929    switch (remcomInBuffer[0]) {
930#if 0
931      case '?' :   remcomOutBuffer[0] = 'S';
932                   remcomOutBuffer[1] =  gdb_hexchars[sigval >> 4];
933                   remcomOutBuffer[2] =  gdb_hexchars[sigval % 16];
934                   remcomOutBuffer[3] = 0;
935                 break;
936#else
937      case '?' : gdb_stub_report_exception_info(exceptionVector,
938                                                registers,
939                                                thread);
940                 break;
941#endif
942      case 'd' : remote_debug = !(remote_debug);  /* toggle debug flag */
943                 break;
944      case 'D' : /* host has detached */
945                 strcpy(remcomOutBuffer,"OK");
946                 host_has_detached = 1;
947                 break;
948         case 'g':               /* return the values of the CPU registers */
949            regptr = registers;
950#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
951            if (do_threads && current_thread != thread )
952               regptr = &current_thread_registers;
953#endif
954            mem2hex (regptr, remcomOutBuffer, sizeof registers);
955            break;
956
957
958         case 'G':       /* set the values of the CPU registers - return OK */
959           regptr = registers;
960#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
961           if (do_threads && current_thread != thread )
962             regptr = &current_thread_registers;
963#endif
964           if (hex2mem (&remcomInBuffer[1],
965                        regptr,
966                        sizeof registers)) {
967             strcpy (remcomOutBuffer, "OK");
968           }
969           else {
970             strcpy (remcomOutBuffer, "E00"); /* E00 = bad "set register" command */
971           }
972           break;
973     
974      /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
975      case 'm' :
976                if (setjmp(remcomEnv) == 0)
977                {
978                    m68k_exceptionHandler(2,handle_buserror);
979
980                    /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
981                    ptr = &remcomInBuffer[1];
982                    if (hexToInt(&ptr,&addr))
983                        if (*(ptr++) == ',')
984                            if (hexToInt(&ptr,&length))
985                            {
986                                ptr = 0;
987                                mem2hex((char*) addr, remcomOutBuffer, length);
988                            }
989
990                    if (ptr)
991                    {
992                      strcpy(remcomOutBuffer,"E01");
993                      debug_error("malformed read memory command: %s",remcomInBuffer);
994                  }     
995                }
996                else {
997                  m68k_exceptionHandler(2,_catchException);   
998                  strcpy(remcomOutBuffer,"E03");
999                  debug_error("bus error");
1000                  }     
1001               
1002                /* restore handler for bus error */
1003                m68k_exceptionHandler(2,_catchException);   
1004                break;
1005     
1006      /* XAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1007      /* Transfer is in binary, '$', '#' and 0x7d is escaped with 0x7d */
1008      case 'X' :
1009                binary = 1;
1010      /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1011      case 'M' :
1012                if (setjmp(remcomEnv) == 0) {
1013                    m68k_exceptionHandler(2,handle_buserror);
1014                   
1015                    /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
1016                    ptr = &remcomInBuffer[1];
1017                    if (hexToInt(&ptr,&addr))
1018                        if (*(ptr++) == ',')
1019                            if (hexToInt(&ptr,&length))
1020                                if (*(ptr++) == ':')
1021                                {
1022                                  if (binary) {
1023                                    bin2mem(ptr,(char *)addr,length);
1024                                  }
1025                                  else {
1026                                    hex2mem(ptr, (char*) addr, length);
1027                                  }
1028                                  ptr = 0;
1029                                  strcpy(remcomOutBuffer,"OK");
1030                                }
1031                    if (ptr)
1032                    {
1033                      strcpy(remcomOutBuffer,"E02");
1034                      debug_error("malformed write memory command: %s",remcomInBuffer);
1035                      }     
1036                }
1037                else {
1038                  m68k_exceptionHandler(2,_catchException);   
1039                  strcpy(remcomOutBuffer,"E03");
1040                  debug_error("bus error");
1041                  }     
1042
1043                /* restore handler for bus error */
1044                m68k_exceptionHandler(2,_catchException);   
1045                break;
1046
1047     /* cAA..AA    Continue at address AA..AA(optional) */
1048     /* sAA..AA   Step one instruction from AA..AA(optional) */
1049     case 'c' :
1050     case 's' :
1051          /* try to read optional parameter, pc unchanged if no parm */
1052         ptr = &remcomInBuffer[1];
1053         if (hexToInt(&ptr,&addr))
1054             registers[ PC ] = addr;
1055             
1056          newPC = registers[ PC];
1057         
1058          /* clear the trace bit */
1059          registers[ PS ] &= 0x7fff;
1060         
1061          /* set the trace bit if we're stepping */
1062          if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000;
1063         
1064          /*
1065           * look for newPC in the linked list of exception frames.
1066           * if it is found, use the old frame it.  otherwise,
1067           * fake up a dummy frame in returnFromException().
1068           */
1069          if (remote_debug) printf("new pc = 0x%x\n",newPC);
1070          frame = lastFrame;
1071          while (frame)
1072          {
1073              if (remote_debug)
1074                  printf("frame at 0x%x has pc=0x%x, except#=%d\n",
1075                         (unsigned32) frame,
1076                         (unsigned32) frame->exceptionPC,
1077                         (unsigned32) frame->exceptionVector);
1078              if (frame->exceptionPC == newPC) break;  /* bingo! a match */
1079              /*
1080               * for a breakpoint instruction, the saved pc may
1081               * be off by two due to re-executing the instruction
1082               * replaced by the trap instruction.  Check for this.
1083               */
1084              if ((frame->exceptionVector == 33) &&
1085                  (frame->exceptionPC == (newPC+2))) break;
1086              if (frame == frame->previous)
1087              {
1088                  frame = 0; /* no match found */
1089                  break;
1090              }
1091              frame = frame->previous;
1092          }
1093         
1094          /*
1095           * If we found a match for the PC AND we are not returning
1096           * as a result of a breakpoint (33),
1097           * trace exception (9), nmi (31), jmp to
1098           * the old exception handler as if this code never ran.
1099           */
1100          if (frame)
1101          {
1102              if ((frame->exceptionVector != 9)  &&
1103                  (frame->exceptionVector != 31) &&
1104                  (frame->exceptionVector != 33))
1105              {
1106                  /*
1107                   * invoke the previous handler.
1108                   */
1109                  if (oldExceptionHook)
1110                      (*oldExceptionHook) (frame->exceptionVector);
1111                  newPC = registers[ PC ];    /* pc may have changed  */
1112                  if (newPC != frame->exceptionPC)
1113                  {
1114                      if (remote_debug)
1115                          printf("frame at 0x%x has pc=0x%x, except#=%d\n",
1116                                 (unsigned32) frame,
1117                                 frame->exceptionPC,
1118                                 frame->exceptionVector);
1119                      /* re-use the last frame, we're skipping it (longjump?)*/
1120                      frame = (Frame *) 0;
1121                      _returnFromException( frame );  /* this is a jump */
1122                  }
1123              }
1124          }         
1125
1126          /* if we couldn't find a frame, create one */
1127          if (frame == 0)
1128          {
1129              frame = lastFrame -1 ;
1130             
1131              /* by using a bunch of print commands with breakpoints,
1132                 it's possible for the frame stack to creep down.  If it creeps
1133                 too far, give up and reset it to the top.  Normal use should
1134                 not see this happen.
1135              */
1136              if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack)
1137              {
1138                 initializeRemcomErrorFrame();
1139                 frame = lastFrame;
1140              }
1141              frame->previous = lastFrame;
1142              lastFrame = frame;
1143              frame = 0;  /* null so _return... will properly initialize it */
1144          }   
1145         
1146          _returnFromException( frame ); /* this is a jump */
1147
1148          break;
1149         
1150         case 'q':   /* queries */
1151#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1152            rtems_gdb_process_query( remcomInBuffer,
1153                                     remcomOutBuffer,
1154                                     do_threads,
1155                                     thread );
1156#endif
1157            break;
1158
1159#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1160         case 'T':
1161         {
1162            int testThread;
1163
1164            if( vhstr2thread(&remcomInBuffer[1], &testThread) == NULL )
1165            {
1166               strcpy(remcomOutBuffer, "E01");
1167               break;
1168            }
1169
1170            if( rtems_gdb_index_to_stub_id(testThread) == NULL )
1171            {
1172               strcpy(remcomOutBuffer, "E02");
1173            }
1174            else
1175            {
1176               strcpy(remcomOutBuffer, "OK");
1177            }
1178         }
1179         break;
1180#endif
1181       
1182         case 'H':  /* set new thread */
1183#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1184            if (remcomInBuffer[1] != 'g') {
1185               break;
1186            }
1187         
1188            if (!do_threads) {
1189               break;
1190            }
1191         
1192            {
1193               int tmp, ret;
1194           
1195               /* Set new generic thread */
1196               if (vhstr2thread(&remcomInBuffer[2], &tmp) == NULL) {
1197                  strcpy(remcomOutBuffer, "E01");
1198                  break;
1199               }
1200
1201               /* 0 means `thread' */
1202               if (tmp == 0) {
1203                  tmp = thread;
1204               }
1205
1206               if (tmp == current_thread) {
1207                  /* No changes */
1208                  strcpy(remcomOutBuffer, "OK");
1209                  break;
1210               }
1211
1212               /* Save current thread registers if necessary */
1213               if (current_thread != thread) {
1214                  ret = rtems_gdb_stub_set_thread_regs(
1215                     current_thread, (unsigned int *) &current_thread_registers);
1216               }
1217
1218               /* Read new registers if necessary */
1219               if (tmp != thread) {
1220                  ret = rtems_gdb_stub_get_thread_regs(
1221                     tmp, (unsigned int *) &current_thread_registers);
1222
1223                  if (!ret) {
1224                     /* Thread does not exist */
1225                     strcpy(remcomOutBuffer, "E02");
1226                     break;
1227                  }
1228               }
1229           
1230               current_thread = tmp;
1231               strcpy(remcomOutBuffer, "OK");
1232            }
1233#endif
1234            break;
1235
1236      /* kill the program */
1237      case 'k' :  /* do nothing */
1238                break;
1239      } /* switch */
1240   
1241    /* reply to the request */
1242    putpacket(remcomOutBuffer);
1243    }
1244}
1245
1246
1247void
1248initializeRemcomErrorFrame()
1249{
1250    lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
1251    lastFrame->previous = lastFrame;
1252}
1253
1254/* this function is used to set up exception handlers for tracing and
1255   breakpoints */
1256void set_debug_traps()
1257{
1258  extern void _debug_level7();
1259  extern void remcomHandler();
1260  int exception;
1261
1262  initializeRemcomErrorFrame();
1263  stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
1264
1265  for (exception = 2; exception <= 23; exception++)
1266      m68k_exceptionHandler(exception,_catchException);   
1267
1268  /* level 7 interrupt              */
1269  m68k_exceptionHandler(31,_debug_level7);   
1270 
1271  /* GDB breakpoint exception (trap #1) */
1272  m68k_exceptionHandler(33,_catchException);
1273
1274  /* coded breakpoint exception (trap #2) */
1275  m68k_exceptionHandler(34,_catchException);
1276 
1277  /* This is a trap #8 instruction.  Apparently it is someone's software
1278     convention for some sort of SIGFPE condition.  Whose?  How many
1279     people are being screwed by having this code the way it is?
1280     Is there a clean solution?  */
1281  m68k_exceptionHandler(40,_catchException);
1282 
1283  /* 48 to 54 are floating point coprocessor errors */
1284  for (exception = 48; exception <= 54; exception++)
1285      m68k_exceptionHandler(exception,_catchException);   
1286
1287  if (oldExceptionHook != remcomHandler)
1288  {
1289      oldExceptionHook = exceptionHook;
1290      exceptionHook    = remcomHandler;
1291  }
1292 
1293  initialized = 1;
1294
1295}
1296
1297/* This function will generate a breakpoint exception.  It is used at the
1298   beginning of a program to sync up with a debugger and can be used
1299   otherwise as a quick means to stop program execution and "break" into
1300   the debugger. */
1301   
1302void breakpoint()
1303{
1304  if (initialized) BREAKPOINT();
1305}
1306
Note: See TracBrowser for help on using the repository browser.