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

4.104.114.9
Last change on this file since 39d08d55 was 39d08d55, checked in by Ralf Corsepius <ralf.corsepius@…>, on Sep 6, 2008 at 5:36:55 PM

Convert to "bool".

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