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

4.104.114.84.95
Last change on this file since f14b925 was f14b925, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 1, 2002 at 10:21:52 PM

2002-07-01 Joel Sherrill <joel@…>

  • m68k-stub.c: Eliminated multi-line asm statements for gcc 3.x.
  • Property mode set to 100644
File size: 42.0 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("
353        lea     registers,%a5   /* get address of registers     */
354        move.(%sp),%d1        /* get status register          */
355        move.w   %d1,66(%a5)      /* save sr                    */     
356        move.l   2(%sp),%a4      /* save pc in a4 for later use  */
357        move.w   6(%sp),%d0     /* get '020 exception format    */
358        move.w   %d0,%d2        /* make a copy of format word   */
359#
360# compute exception number
361        and.l    #0xfff,%d2     /* mask off vector offset       */
362        lsr.w    #2,%d2         /* divide by 4 to get vect num  */
363#if 1
364        cmp.l    #33,%d2
365        bne      nopc_adjust
366        subq.l   #2,%a4
367nopc_adjust:
368#endif
369        move.l   %a4,68(%a5)     /* save pc in _regisers[]              */
370
371#
372# figure out how many bytes in the stack frame
373        andi.w   #0xf000,%d0    /* mask off format type         */
374        rol.w    #5,%d0         /* rotate into the low byte *2  */
375        lea     exceptionSize,%a1   
376        add.w    %d0,%a1        /* index into the table         */
377        move.w   (%a1),%d0      /* get number of words in frame */
378        move.w   %d0,%d3        /* save it                      */
379        sub.w    %d0,%a0        /* adjust save pointer          */
380        sub.w    %d0,%a0        /* adjust save pointer(bytes)   */
381        move.l   %a0,%a1        /* copy save pointer            */
382        subq.l   #1,%d0         /* predecrement loop counter    */
383#
384# copy the frame
385saveFrameLoop:
386        move.(%sp)+,(%a1)+
387        dbf     %d0,saveFrameLoop
388#
389# now that the stack has been clenaed,
390# save the a7 in use at time of exception
391        move.l   %sp,superStack  /* save supervisor sp           */
392        andi.w   #0x2000,%d1      /* were we in supervisor mode ? */
393        beq      userMode       
394        move.l   %a7,60(%a5)      /* save a7                  */
395        bra      a7saveDone
396userMode: 
397        move.l   %usp,%a1       
398        move.l   %a1,60(%a5)      /* save user stack pointer    */
399a7saveDone:
400
401#
402# save size of frame
403        move.w   %d3,-(%a0)
404
405        move.l   %d2,-(%a0)     /* save vector number           */
406#
407# save pc causing exception
408        move.l   %a4,-(%a0)
409#
410# save old frame link and set the new value
411        move.l  lastFrame,%a1   /* last frame pointer */
412        move.l   %a1,-(%a0)             /* save pointer to prev frame   */
413        move.l   %a0,lastFrame
414
415        move.l   %d2,-(%sp)         /* push exception num           */
416        move.l   exceptionHook,%a0  /* get address of handler */
417        jbsr    (%a0)             /* and call it */
418        clr.l   (%sp)            /* replace exception num parm with frame ptr */
419        jbsr     _returnFromException   /* jbsr, but never returns */
420");
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("
435.text
436.globl _catchException
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(format, parm)
669char * format;
670char * parm;
671{
672  if (remote_debug) fprintf (stderr,format,parm);
673}
674
675/* convert the memory pointed to by mem into hex, placing result in buf */
676/* return a pointer to the last char put in buf (null) */
677char* mem2hex(mem, buf, count)
678char* mem;
679char* buf;
680int   count;
681{
682      int i;
683      unsigned char ch;
684      for (i=0;i<count;i++) {
685          ch = *mem++;
686          *buf++ = gdb_hexchars[ch >> 4];
687          *buf++ = gdb_hexchars[ch % 16];
688      }
689      *buf = 0; 
690      return(buf);
691}
692
693/* convert the hex array pointed to by buf into binary to be placed in mem */
694/* return a pointer to the character AFTER the last byte written */
695char* hex2mem(buf, mem, count)
696char* buf;
697char* mem;
698int   count;
699{
700      int i;
701      unsigned char ch;
702      for (i=0;i<count;i++) {
703          ch = hex(*buf++) << 4;
704          ch = ch + hex(*buf++);
705          *mem++ = ch;
706      }
707      return(mem);
708}
709
710/* Convert the binary stream in BUF to memory.
711
712   Gdb will escape $, #, and the escape char (0x7d).
713   COUNT is the total number of bytes to write into
714   memory. */
715static unsigned char *
716bin2mem (
717  unsigned char *buf,
718  unsigned char *mem,
719  int   count
720)
721{
722  int i;
723
724  for (i = 0; i < count; i++) {
725      /* Check for any escaped characters. Be paranoid and
726         only unescape chars that should be escaped. */
727      if (*buf == 0x7d) {
728          switch (*(buf+1)) {
729            case 0x3:  /* # */
730            case 0x4:  /* $ */
731            case 0x5d: /* escape char */
732              buf++;
733              *buf |= 0x20;
734              break;
735            default:
736              /* nothing */
737              break;
738            }
739        }
740
741      *mem++ = *buf++;
742    }
743
744  return mem;
745}
746
747/* a bus error has occurred, perform a longjmp
748   to return execution and allow handling of the error */
749
750void handle_buserror()
751{
752  longjmp(remcomEnv,1);
753}
754
755/* this function takes the 68000 exception number and attempts to
756   translate this number into a unix compatible signal value */
757int computeSignal( exceptionVector )
758int exceptionVector;
759{
760  int sigval;
761  switch (exceptionVector) {
762    case 2 : sigval = 10; break; /* bus error           */
763    case 3 : sigval = 10; break; /* address error       */
764    case 4 : sigval = 4;  break; /* illegal instruction */
765    case 5 : sigval = 8;  break; /* zero divide         */
766    case 6 : sigval = 8; break; /* chk instruction     */
767    case 7 : sigval = 8; break; /* trapv instruction   */
768    case 8 : sigval = 11; break; /* privilege violation */
769    case 9 : sigval = 5;  break; /* trace trap          */
770    case 10: sigval = 4;  break; /* line 1010 emulator  */
771    case 11: sigval = 4;  break; /* line 1111 emulator  */
772
773      /* Coprocessor protocol violation.  Using a standard MMU or FPU
774         this cannot be triggered by software.  Call it a SIGBUS.  */
775    case 13: sigval = 10;  break;
776
777    case 31: sigval = 2;  break; /* interrupt           */
778    case 33: sigval = 5;  break; /* GDB breakpoint      */
779    case 34: sigval = 5;  break; /* coded breakpoint    */
780
781      /* This is a trap #8 instruction.  Apparently it is someone's software
782         convention for some sort of SIGFPE condition.  Whose?  How many
783         people are being screwed by having this code the way it is?
784         Is there a clean solution?  */
785    case 40: sigval = 8;  break; /* floating point err  */
786
787    case 48: sigval = 8;  break; /* floating point err  */
788    case 49: sigval = 8;  break; /* floating point err  */
789    case 50: sigval = 8;  break; /* zero divide         */
790    case 51: sigval = 8;  break; /* underflow           */
791    case 52: sigval = 8;  break; /* operand error       */
792    case 53: sigval = 8;  break; /* overflow            */
793    case 54: sigval = 8;  break; /* NAN                 */
794    default: 
795      sigval = 7;         /* "software generated"*/
796  }
797  return (sigval);
798}
799
800/**********************************************/
801/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
802/* RETURN NUMBER OF CHARS PROCESSED           */
803/**********************************************/
804int hexToInt(char **ptr, int *intValue)
805{
806    int numChars = 0;
807    int hexValue;
808   
809    *intValue = 0;
810
811    while (**ptr)
812    {
813        hexValue = hex(**ptr);
814        if (hexValue >=0)
815        {
816            *intValue = (*intValue <<4) | hexValue;
817            numChars ++;
818        }
819        else
820            break;
821       
822        (*ptr)++;
823    }
824
825    return (numChars);
826}
827
828/*
829 *  This support function prepares and sends the message containing the
830 *  basic information about this exception.
831 */
832
833void gdb_stub_report_exception_info(
834  int vector,
835  int *regs,
836  int thread
837)
838{
839   char *optr;
840   int sigval;
841
842   optr = remcomOutBuffer;
843   *optr++ = 'T';
844   sigval = computeSignal (vector);
845   *optr++ = highhex (sigval);
846   *optr++ = lowhex (sigval);
847
848   *optr++ = highhex(A7);
849   *optr++ = lowhex(A7);
850   *optr++ = ':';
851   optr    = mem2hstr(optr, 
852                      (unsigned char *)&(regs[A7]), 
853                      sizeof(regs[A7]));
854   *optr++ = ';';
855 
856   *optr++ = highhex(PC);
857   *optr++ = lowhex(PC);
858   *optr++ = ':';
859   optr    = mem2hstr(optr, 
860                      (unsigned char *)&(regs[PC]), 
861                      sizeof(regs[PC]) );
862   *optr++ = ';';
863
864#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
865   if (do_threads) 
866   {
867      *optr++ = 't';
868      *optr++ = 'h';
869      *optr++ = 'r';
870      *optr++ = 'e';
871      *optr++ = 'a';
872      *optr++ = 'd';
873      *optr++ = ':';
874      optr   = thread2vhstr(optr, thread);
875      *optr++ = ';';
876   }
877#endif
878   *optr++ = '\0';
879}
880
881/*
882 * This function does all command procesing for interfacing to gdb.
883 */
884void handle_exception(int exceptionVector)
885{
886  int    host_has_detached = 0;
887  int    addr, length;
888  char * ptr;
889  int    newPC;
890  Frame  *frame;
891  int          current_thread;  /* current generic thread */
892  int          thread;          /* stopped thread: context exception happened in */
893   void         *regptr;
894   int binary;
895
896  if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n", 
897                            exceptionVector,
898                            registers[ PS ], 
899                            registers[ PC ]);
900
901   thread = 0;
902#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
903   if (do_threads) {
904      thread = rtems_gdb_stub_get_current_thread();
905   }
906#endif
907   current_thread = thread;
908 
909#if 0
910  /* reply to host that an exception has occurred */
911  sigval = computeSignal( exceptionVector );
912  remcomOutBuffer[0] = 'S';
913  remcomOutBuffer[1] =  gdb_hexchars[sigval >> 4];
914  remcomOutBuffer[2] =  gdb_hexchars[sigval % 16];
915  remcomOutBuffer[3] = 0;
916#else
917   /* reply to host that an exception has occurred with some basic info */
918   gdb_stub_report_exception_info(exceptionVector, registers, thread);
919#endif
920
921  putpacket(remcomOutBuffer); 
922
923  while (!(host_has_detached)) { 
924    binary = 0;
925    error = 0;
926    remcomOutBuffer[0] = 0;
927    getpacket(remcomInBuffer);
928    switch (remcomInBuffer[0]) {
929#if 0
930      case '?' :   remcomOutBuffer[0] = 'S';
931                   remcomOutBuffer[1] =  gdb_hexchars[sigval >> 4];
932                   remcomOutBuffer[2] =  gdb_hexchars[sigval % 16];
933                   remcomOutBuffer[3] = 0;
934                 break;
935#else
936      case '?' : gdb_stub_report_exception_info(exceptionVector,
937                                                registers,
938                                                thread);
939                 break;
940#endif
941      case 'd' : remote_debug = !(remote_debug);  /* toggle debug flag */
942                 break; 
943      case 'D' : /* host has detached */
944                 strcpy(remcomOutBuffer,"OK");
945                 host_has_detached = 1;
946                 break; 
947         case 'g':               /* return the values of the CPU registers */
948            regptr = registers;
949#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
950            if (do_threads && current_thread != thread )
951               regptr = &current_thread_registers;
952#endif
953            mem2hex (regptr, remcomOutBuffer, sizeof registers);
954            break;
955
956
957         case 'G':       /* set the values of the CPU registers - return OK */
958           regptr = registers;
959#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
960           if (do_threads && current_thread != thread )
961             regptr = &current_thread_registers;
962#endif
963           if (hex2mem (&remcomInBuffer[1], 
964                        regptr, 
965                        sizeof registers)) {
966             strcpy (remcomOutBuffer, "OK");
967           }
968           else {
969             strcpy (remcomOutBuffer, "E00"); /* E00 = bad "set register" command */
970           }
971           break;
972     
973      /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
974      case 'm' : 
975                if (setjmp(remcomEnv) == 0)
976                {
977                    m68k_exceptionHandler(2,handle_buserror); 
978
979                    /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
980                    ptr = &remcomInBuffer[1];
981                    if (hexToInt(&ptr,&addr))
982                        if (*(ptr++) == ',')
983                            if (hexToInt(&ptr,&length)) 
984                            {
985                                ptr = 0;
986                                mem2hex((char*) addr, remcomOutBuffer, length);
987                            }
988
989                    if (ptr)
990                    {
991                      strcpy(remcomOutBuffer,"E01");
992                      debug_error("malformed read memory command: %s",remcomInBuffer);
993                  }     
994                } 
995                else {
996                  m68k_exceptionHandler(2,_catchException);   
997                  strcpy(remcomOutBuffer,"E03");
998                  debug_error("bus error");
999                  }     
1000               
1001                /* restore handler for bus error */
1002                m68k_exceptionHandler(2,_catchException);   
1003                break;
1004     
1005      /* XAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1006      /* Transfer is in binary, '$', '#' and 0x7d is escaped with 0x7d */
1007      case 'X' : 
1008                binary = 1;
1009      /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1010      case 'M' : 
1011                if (setjmp(remcomEnv) == 0) {
1012                    m68k_exceptionHandler(2,handle_buserror); 
1013                   
1014                    /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
1015                    ptr = &remcomInBuffer[1];
1016                    if (hexToInt(&ptr,&addr))
1017                        if (*(ptr++) == ',')
1018                            if (hexToInt(&ptr,&length))
1019                                if (*(ptr++) == ':')
1020                                {
1021                                  if (binary) {
1022                                    bin2mem(ptr,(char *)addr,length);
1023                                  }
1024                                  else {
1025                                    hex2mem(ptr, (char*) addr, length);
1026                                  }
1027                                  ptr = 0;
1028                                  strcpy(remcomOutBuffer,"OK");
1029                                }
1030                    if (ptr)
1031                    {
1032                      strcpy(remcomOutBuffer,"E02");
1033                      debug_error("malformed write memory command: %s",remcomInBuffer);
1034                      }     
1035                } 
1036                else {
1037                  m68k_exceptionHandler(2,_catchException);   
1038                  strcpy(remcomOutBuffer,"E03");
1039                  debug_error("bus error");
1040                  }     
1041
1042                /* restore handler for bus error */
1043                m68k_exceptionHandler(2,_catchException);   
1044                break;
1045
1046     /* cAA..AA    Continue at address AA..AA(optional) */
1047     /* sAA..AA   Step one instruction from AA..AA(optional) */
1048     case 'c' : 
1049     case 's' : 
1050          /* try to read optional parameter, pc unchanged if no parm */
1051         ptr = &remcomInBuffer[1];
1052         if (hexToInt(&ptr,&addr))
1053             registers[ PC ] = addr;
1054             
1055          newPC = registers[ PC];
1056         
1057          /* clear the trace bit */
1058          registers[ PS ] &= 0x7fff;
1059         
1060          /* set the trace bit if we're stepping */
1061          if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000;
1062         
1063          /*
1064           * look for newPC in the linked list of exception frames.
1065           * if it is found, use the old frame it.  otherwise,
1066           * fake up a dummy frame in returnFromException().
1067           */
1068          if (remote_debug) printf("new pc = 0x%x\n",newPC);
1069          frame = lastFrame;
1070          while (frame)
1071          {
1072              if (remote_debug)
1073                  printf("frame at 0x%x has pc=0x%x, except#=%d\n",
1074                         (unsigned32) frame,
1075                         (unsigned32) frame->exceptionPC,
1076                         (unsigned32) frame->exceptionVector);
1077              if (frame->exceptionPC == newPC) break;  /* bingo! a match */
1078              /*
1079               * for a breakpoint instruction, the saved pc may
1080               * be off by two due to re-executing the instruction
1081               * replaced by the trap instruction.  Check for this.
1082               */
1083              if ((frame->exceptionVector == 33) &&
1084                  (frame->exceptionPC == (newPC+2))) break;
1085              if (frame == frame->previous)
1086              {
1087                  frame = 0; /* no match found */ 
1088                  break; 
1089              }
1090              frame = frame->previous;
1091          }
1092         
1093          /*
1094           * If we found a match for the PC AND we are not returning
1095           * as a result of a breakpoint (33),
1096           * trace exception (9), nmi (31), jmp to
1097           * the old exception handler as if this code never ran.
1098           */
1099          if (frame) 
1100          {
1101              if ((frame->exceptionVector != 9)  && 
1102                  (frame->exceptionVector != 31) && 
1103                  (frame->exceptionVector != 33))
1104              { 
1105                  /*
1106                   * invoke the previous handler.
1107                   */
1108                  if (oldExceptionHook)
1109                      (*oldExceptionHook) (frame->exceptionVector);
1110                  newPC = registers[ PC ];    /* pc may have changed  */
1111                  if (newPC != frame->exceptionPC)
1112                  {
1113                      if (remote_debug)
1114                          printf("frame at 0x%x has pc=0x%x, except#=%d\n",
1115                                 (unsigned32) frame,
1116                                 frame->exceptionPC,
1117                                 frame->exceptionVector);
1118                      /* re-use the last frame, we're skipping it (longjump?)*/
1119                      frame = (Frame *) 0;
1120                      _returnFromException( frame );  /* this is a jump */
1121                  }
1122              }
1123          }         
1124
1125          /* if we couldn't find a frame, create one */
1126          if (frame == 0)
1127          {
1128              frame = lastFrame -1 ;
1129             
1130              /* by using a bunch of print commands with breakpoints,
1131                 it's possible for the frame stack to creep down.  If it creeps
1132                 too far, give up and reset it to the top.  Normal use should
1133                 not see this happen.
1134              */
1135              if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack)
1136              {
1137                 initializeRemcomErrorFrame();
1138                 frame = lastFrame; 
1139              }
1140              frame->previous = lastFrame;
1141              lastFrame = frame;
1142              frame = 0;  /* null so _return... will properly initialize it */ 
1143          }   
1144         
1145          _returnFromException( frame ); /* this is a jump */
1146
1147          break;
1148         
1149         case 'q':   /* queries */
1150#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1151            rtems_gdb_process_query( remcomInBuffer, 
1152                                     remcomOutBuffer, 
1153                                     do_threads, 
1154                                     thread );
1155#endif
1156            break;
1157
1158#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1159         case 'T':
1160         {
1161            int testThread;
1162
1163            if( vhstr2thread(&remcomInBuffer[1], &testThread) == NULL ) 
1164            {
1165               strcpy(remcomOutBuffer, "E01");
1166               break;
1167            }
1168
1169            if( rtems_gdb_index_to_stub_id(testThread) == NULL )
1170            {
1171               strcpy(remcomOutBuffer, "E02");
1172            }
1173            else
1174            {
1175               strcpy(remcomOutBuffer, "OK");
1176            }
1177         }
1178         break;
1179#endif
1180       
1181         case 'H':  /* set new thread */
1182#if defined(GDB_STUB_ENABLE_THREAD_SUPPORT)
1183            if (remcomInBuffer[1] != 'g') {
1184               break;
1185            }
1186         
1187            if (!do_threads) {
1188               break;
1189            }
1190         
1191            {
1192               int tmp, ret;
1193           
1194               /* Set new generic thread */
1195               if (vhstr2thread(&remcomInBuffer[2], &tmp) == NULL) {
1196                  strcpy(remcomOutBuffer, "E01");
1197                  break;
1198               }
1199
1200               /* 0 means `thread' */
1201               if (tmp == 0) {
1202                  tmp = thread;
1203               }
1204
1205               if (tmp == current_thread) {
1206                  /* No changes */
1207                  strcpy(remcomOutBuffer, "OK");
1208                  break;
1209               }
1210
1211               /* Save current thread registers if necessary */ 
1212               if (current_thread != thread) {
1213                  ret = rtems_gdb_stub_set_thread_regs(
1214                     current_thread, (unsigned int *) &current_thread_registers);
1215               }
1216
1217               /* Read new registers if necessary */
1218               if (tmp != thread) {
1219                  ret = rtems_gdb_stub_get_thread_regs(
1220                     tmp, (unsigned int *) &current_thread_registers);
1221
1222                  if (!ret) {
1223                     /* Thread does not exist */
1224                     strcpy(remcomOutBuffer, "E02");
1225                     break;
1226                  }
1227               }
1228           
1229               current_thread = tmp;
1230               strcpy(remcomOutBuffer, "OK");
1231            }
1232#endif
1233            break;
1234
1235      /* kill the program */
1236      case 'k' :  /* do nothing */
1237                break;
1238      } /* switch */ 
1239   
1240    /* reply to the request */
1241    putpacket(remcomOutBuffer); 
1242    }
1243}
1244
1245
1246void
1247initializeRemcomErrorFrame()
1248{
1249    lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
1250    lastFrame->previous = lastFrame;
1251}
1252
1253/* this function is used to set up exception handlers for tracing and
1254   breakpoints */
1255void set_debug_traps()
1256{
1257  extern void _debug_level7();
1258  extern void remcomHandler();
1259  int exception;
1260
1261  initializeRemcomErrorFrame();
1262  stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
1263
1264  for (exception = 2; exception <= 23; exception++)
1265      m68k_exceptionHandler(exception,_catchException);   
1266
1267  /* level 7 interrupt              */
1268  m68k_exceptionHandler(31,_debug_level7);   
1269 
1270  /* GDB breakpoint exception (trap #1) */
1271  m68k_exceptionHandler(33,_catchException);
1272
1273  /* coded breakpoint exception (trap #2) */
1274  m68k_exceptionHandler(34,_catchException);
1275 
1276  /* This is a trap #8 instruction.  Apparently it is someone's software
1277     convention for some sort of SIGFPE condition.  Whose?  How many
1278     people are being screwed by having this code the way it is?
1279     Is there a clean solution?  */
1280  m68k_exceptionHandler(40,_catchException);
1281 
1282  /* 48 to 54 are floating point coprocessor errors */
1283  for (exception = 48; exception <= 54; exception++)
1284      m68k_exceptionHandler(exception,_catchException);   
1285
1286  if (oldExceptionHook != remcomHandler)
1287  {
1288      oldExceptionHook = exceptionHook;
1289      exceptionHook    = remcomHandler;
1290  }
1291 
1292  initialized = 1;
1293
1294}
1295
1296/* This function will generate a breakpoint exception.  It is used at the
1297   beginning of a program to sync up with a debugger and can be used
1298   otherwise as a quick means to stop program execution and "break" into
1299   the debugger. */
1300   
1301void breakpoint()
1302{
1303  if (initialized) BREAKPOINT();
1304}
1305
Note: See TracBrowser for help on using the repository browser.