source: SVN/rincon/u-boot/common/kgdb.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 2 years ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 14.1 KB
Line 
1/* taken from arch/ppc/kernel/ppc-stub.c */
2
3/****************************************************************************
4
5                THIS SOFTWARE IS NOT COPYRIGHTED
6
7   HP offers the following for use in the public domain.  HP makes no
8   warranty with regard to the software or its performance and the
9   user accepts the software "AS IS" with all faults.
10
11   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
12   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14
15****************************************************************************/
16
17/****************************************************************************
18 *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
19 *
20 *  Module name: remcom.c $
21 *  Revision: 1.34 $
22 *  Date: 91/03/09 12:29:49 $
23 *  Contributor:     Lake Stevens Instrument Division$
24 *
25 *  Description:     low level support for gdb debugger. $
26 *
27 *  Considerations:  only works on target hardware $
28 *
29 *  Written by:      Glenn Engel $
30 *  ModuleState:     Experimental $
31 *
32 *  NOTES:           See Below $
33 *
34 *  Modified for SPARC by Stu Grossman, Cygnus Support.
35 *
36 *  This code has been extensively tested on the Fujitsu SPARClite demo board.
37 *
38 *  To enable debugger support, two things need to happen.  One, a
39 *  call to set_debug_traps() is necessary in order to allow any breakpoints
40 *  or error conditions to be properly intercepted and reported to gdb.
41 *  Two, a breakpoint needs to be generated to begin communication.  This
42 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
43 *  simulates a breakpoint by executing a trap #1.
44 *
45 *************
46 *
47 *    The following gdb commands are supported:
48 *
49 * command          function                               Return value
50 *
51 *    g             return the value of the CPU registers  hex data or ENN
52 *    G             set the value of the CPU registers     OK or ENN
53 *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
54 *
55 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
56 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
57 *
58 *    c             Resume at current address              SNN   ( signal NN)
59 *    cAA..AA       Continue at address AA..AA             SNN
60 *
61 *    s             Step one instruction                   SNN
62 *    sAA..AA       Step one instruction from AA..AA       SNN
63 *
64 *    k             kill
65 *
66 *    ?             What was the last sigval ?             SNN   (signal NN)
67 *
68 *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
69 *                                                         baud rate
70 *
71 * All commands and responses are sent with a packet which includes a
72 * checksum.  A packet consists of
73 *
74 * $<packet info>#<checksum>.
75 *
76 * where
77 * <packet info> :: <characters representing the command or response>
78 * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
79 *
80 * When a packet is received, it is first acknowledged with either '+' or '-'.
81 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
82 *
83 * Example:
84 *
85 * Host:                  Reply:
86 * $m0,10#2a               +$00010203040506070809101112131415#42
87 *
88 ****************************************************************************/
89
90#include <common.h>
91
92#include <kgdb.h>
93#include <command.h>
94
95#if defined(CONFIG_CMD_KGDB)
96
97#undef KGDB_DEBUG
98
99/*
100 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
101 */
102#define BUFMAX 1024
103static char remcomInBuffer[BUFMAX];
104static char remcomOutBuffer[BUFMAX];
105static char remcomRegBuffer[BUFMAX];
106
107static int initialized = 0;
108static int kgdb_active = 0, first_entry = 1;
109static struct pt_regs entry_regs;
110static long error_jmp_buf[BUFMAX/2];
111static int longjmp_on_fault = 0;
112#ifdef KGDB_DEBUG
113static int kdebug = 1;
114#endif
115
116static const char hexchars[]="0123456789abcdef";
117
118/* Convert ch from a hex digit to an int */
119static int
120hex(unsigned char ch)
121{
122        if (ch >= 'a' && ch <= 'f')
123                return ch-'a'+10;
124        if (ch >= '0' && ch <= '9')
125                return ch-'0';
126        if (ch >= 'A' && ch <= 'F')
127                return ch-'A'+10;
128        return -1;
129}
130
131/* Convert the memory pointed to by mem into hex, placing result in buf.
132 * Return a pointer to the last char put in buf (null).
133 */
134static unsigned char *
135mem2hex(char *mem, char *buf, int count)
136{
137        unsigned char ch;
138
139        longjmp_on_fault = 1;
140        while (count-- > 0) {
141                ch = *mem++;
142                *buf++ = hexchars[ch >> 4];
143                *buf++ = hexchars[ch & 0xf];
144        }
145        *buf = 0;
146        longjmp_on_fault = 0;
147        return (unsigned char *)buf;
148}
149
150/* convert the hex array pointed to by buf into binary to be placed in mem
151 * return a pointer to the character AFTER the last byte fetched from buf.
152*/
153static char *
154hex2mem(char *buf, char *mem, int count)
155{
156        int i, hexValue;
157        unsigned char ch;
158        char *mem_start = mem;
159
160        longjmp_on_fault = 1;
161        for (i=0; i<count; i++) {
162                if ((hexValue = hex(*buf++)) < 0)
163                        kgdb_error(KGDBERR_NOTHEXDIG);
164                ch = hexValue << 4;
165                if ((hexValue = hex(*buf++)) < 0)
166                        kgdb_error(KGDBERR_NOTHEXDIG);
167                ch |= hexValue;
168                *mem++ = ch;
169        }
170        kgdb_flush_cache_range((void *)mem_start, (void *)(mem - 1));
171        longjmp_on_fault = 0;
172
173        return buf;
174}
175
176/*
177 * While we find nice hex chars, build an int.
178 * Return number of chars processed.
179 */
180static int
181hexToInt(char **ptr, int *intValue)
182{
183        int numChars = 0;
184        int hexValue;
185
186        *intValue = 0;
187
188        longjmp_on_fault = 1;
189        while (**ptr) {
190                hexValue = hex(**ptr);
191                if (hexValue < 0)
192                        break;
193
194                *intValue = (*intValue << 4) | hexValue;
195                numChars ++;
196
197                (*ptr)++;
198        }
199        longjmp_on_fault = 0;
200
201        return (numChars);
202}
203
204/* scan for the sequence $<data>#<checksum>     */
205static void
206getpacket(char *buffer)
207{
208        unsigned char checksum;
209        unsigned char xmitcsum;
210        int i;
211        int count;
212        unsigned char ch;
213
214        do {
215                /* wait around for the start character, ignore all other
216                 * characters */
217                while ((ch = (getDebugChar() & 0x7f)) != '$') {
218#ifdef KGDB_DEBUG
219                        if (kdebug)
220                                putc(ch);
221#endif
222                        ;
223                }
224
225                checksum = 0;
226                xmitcsum = -1;
227
228                count = 0;
229
230                /* now, read until a # or end of buffer is found */
231                while (count < BUFMAX) {
232                        ch = getDebugChar() & 0x7f;
233                        if (ch == '#')
234                                break;
235                        checksum = checksum + ch;
236                        buffer[count] = ch;
237                        count = count + 1;
238                }
239
240                if (count >= BUFMAX)
241                        continue;
242
243                buffer[count] = 0;
244
245                if (ch == '#') {
246                        xmitcsum = hex(getDebugChar() & 0x7f) << 4;
247                        xmitcsum |= hex(getDebugChar() & 0x7f);
248                        if (checksum != xmitcsum)
249                                putDebugChar('-');      /* failed checksum */
250                        else {
251                                putDebugChar('+'); /* successful transfer */
252                                /* if a sequence char is present, reply the ID */
253                                if (buffer[2] == ':') {
254                                        putDebugChar(buffer[0]);
255                                        putDebugChar(buffer[1]);
256                                        /* remove sequence chars from buffer */
257                                        count = strlen(buffer);
258                                        for (i=3; i <= count; i++)
259                                                buffer[i-3] = buffer[i];
260                                }
261                        }
262                }
263        } while (checksum != xmitcsum);
264}
265
266/* send the packet in buffer.  */
267static void
268putpacket(unsigned char *buffer)
269{
270        unsigned char checksum;
271        int count;
272        unsigned char ch, recv;
273
274        /*  $<packet info>#<checksum>. */
275        do {
276                putDebugChar('$');
277                checksum = 0;
278                count = 0;
279
280                while ((ch = buffer[count])) {
281                        putDebugChar(ch);
282                        checksum += ch;
283                        count += 1;
284                }
285
286                putDebugChar('#');
287                putDebugChar(hexchars[checksum >> 4]);
288                putDebugChar(hexchars[checksum & 0xf]);
289                recv = getDebugChar();
290        } while ((recv & 0x7f) != '+');
291}
292
293/*
294 * This function does all command processing for interfacing to gdb.
295 */
296static int
297handle_exception (struct pt_regs *regs)
298{
299        int addr;
300        int length;
301        char *ptr;
302        kgdb_data kd;
303        int i;
304
305        if (!initialized) {
306                printf("kgdb: exception before kgdb is initialized! huh?\n");
307                return (0);
308        }
309
310        /* probably should check which exception occured as well */
311        if (longjmp_on_fault) {
312                longjmp_on_fault = 0;
313                kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
314                panic("kgdb longjump failed!\n");
315        }
316
317        if (kgdb_active) {
318                printf("kgdb: unexpected exception from within kgdb\n");
319                return (0);
320        }
321        kgdb_active = 1;
322
323        kgdb_interruptible(0);
324
325        printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
326
327        if (kgdb_setjmp(error_jmp_buf) != 0)
328                panic("kgdb: error or fault in entry init!\n");
329
330        kgdb_enter(regs, &kd);
331
332        if (first_entry) {
333                /*
334                 * the first time we enter kgdb, we save the processor
335                 * state so that we can return to the monitor if the
336                 * remote end quits gdb (or at least, tells us to quit
337                 * with the 'k' packet)
338                 */
339                entry_regs = *regs;
340                first_entry = 0;
341        }
342
343        ptr = remcomOutBuffer;
344
345        *ptr++ = 'T';
346
347        *ptr++ = hexchars[kd.sigval >> 4];
348        *ptr++ = hexchars[kd.sigval & 0xf];
349
350        for (i = 0; i < kd.nregs; i++) {
351                kgdb_reg *rp = &kd.regs[i];
352
353                *ptr++ = hexchars[rp->num >> 4];
354                *ptr++ = hexchars[rp->num & 0xf];
355                *ptr++ = ':';
356                ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
357                *ptr++ = ';';
358        }
359
360        *ptr = 0;
361
362#ifdef KGDB_DEBUG
363        if (kdebug)
364                printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
365#endif
366
367        putpacket((unsigned char *)&remcomOutBuffer);
368
369        while (1) {
370                volatile int errnum;
371
372                remcomOutBuffer[0] = 0;
373
374                getpacket(remcomInBuffer);
375                ptr = &remcomInBuffer[1];
376
377#ifdef KGDB_DEBUG
378                if (kdebug)
379                        printf("kgdb:  remcomInBuffer: %s\n", remcomInBuffer);
380#endif
381
382                errnum = kgdb_setjmp(error_jmp_buf);
383
384                if (errnum == 0) switch (remcomInBuffer[0]) {
385
386                case '?':               /* report most recent signal */
387                        remcomOutBuffer[0] = 'S';
388                        remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
389                        remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
390                        remcomOutBuffer[3] = 0;
391                        break;
392
393#ifdef KGDB_DEBUG
394                case 'd':
395                        /* toggle debug flag */
396                        kdebug ^= 1;
397                        break;
398#endif
399
400                case 'g':       /* return the value of the CPU registers. */
401                        length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
402                        mem2hex(remcomRegBuffer, remcomOutBuffer, length);
403                        break;
404
405                case 'G':   /* set the value of the CPU registers */
406                        length = strlen(ptr);
407                        if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
408                        hex2mem(ptr, remcomRegBuffer, length/2);
409                        kgdb_putregs(regs, remcomRegBuffer, length/2);
410                        strcpy(remcomOutBuffer,"OK");
411                        break;
412
413                case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
414                                /* Try to read %x,%x.  */
415
416                        if (hexToInt(&ptr, &addr)
417                            && *ptr++ == ','
418                            && hexToInt(&ptr, &length)) {
419                                mem2hex((char *)addr, remcomOutBuffer, length);
420                        } else {
421                                kgdb_error(KGDBERR_BADPARAMS);
422                        }
423                        break;
424
425                case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
426                        /* Try to read '%x,%x:'.  */
427
428                        if (hexToInt(&ptr, &addr)
429                            && *ptr++ == ','
430                            && hexToInt(&ptr, &length)
431                            && *ptr++ == ':') {
432                                hex2mem(ptr, (char *)addr, length);
433                                strcpy(remcomOutBuffer, "OK");
434                        } else {
435                                kgdb_error(KGDBERR_BADPARAMS);
436                        }
437                        break;
438
439
440                case 'k':    /* kill the program, actually return to monitor */
441                        kd.extype = KGDBEXIT_KILL;
442                        *regs = entry_regs;
443                        first_entry = 1;
444                        goto doexit;
445
446                case 'C':    /* CSS  continue with signal SS */
447                        *ptr = '\0';    /* ignore the signal number for now */
448                        /* fall through */
449
450                case 'c':    /* cAA..AA  Continue; address AA..AA optional */
451                        /* try to read optional parameter, pc unchanged if no parm */
452                        kd.extype = KGDBEXIT_CONTINUE;
453
454                        if (hexToInt(&ptr, &addr)) {
455                                kd.exaddr = addr;
456                                kd.extype |= KGDBEXIT_WITHADDR;
457                        }
458
459                        goto doexit;
460
461                case 'S':    /* SSS  single step with signal SS */
462                        *ptr = '\0';    /* ignore the signal number for now */
463                        /* fall through */
464
465                case 's':
466                        kd.extype = KGDBEXIT_SINGLE;
467
468                        if (hexToInt(&ptr, &addr)) {
469                                kd.exaddr = addr;
470                                kd.extype |= KGDBEXIT_WITHADDR;
471                        }
472
473                doexit:
474/* Need to flush the instruction cache here, as we may have deposited a
475 * breakpoint, and the icache probably has no way of knowing that a data ref to
476 * some location may have changed something that is in the instruction cache.
477 */
478                        kgdb_flush_cache_all();
479                        kgdb_exit(regs, &kd);
480                        kgdb_active = 0;
481                        kgdb_interruptible(1);
482                        return (1);
483
484                case 'r':               /* Reset (if user process..exit ???)*/
485                        panic("kgdb reset.");
486                        break;
487
488                case 'P':    /* Pr=v  set reg r to value v (r and v are hex) */
489                        if (hexToInt(&ptr, &addr)
490                            && *ptr++ == '='
491                            && ((length = strlen(ptr)) & 1) == 0) {
492                                hex2mem(ptr, remcomRegBuffer, length/2);
493                                kgdb_putreg(regs, addr,
494                                        remcomRegBuffer, length/2);
495                                strcpy(remcomOutBuffer,"OK");
496                        } else {
497                                kgdb_error(KGDBERR_BADPARAMS);
498                        }
499                        break;
500                }                       /* switch */
501
502                if (errnum != 0)
503                        sprintf(remcomOutBuffer, "E%02d", errnum);
504
505#ifdef KGDB_DEBUG
506                if (kdebug)
507                        printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
508#endif
509
510                /* reply to the request */
511                putpacket((unsigned char *)&remcomOutBuffer);
512
513        } /* while(1) */
514}
515
516/*
517 * kgdb_init must be called *after* the
518 * monitor is relocated into ram
519 */
520void
521kgdb_init(void)
522{
523        kgdb_serial_init();
524        debugger_exception_handler = handle_exception;
525        initialized = 1;
526
527        putDebugStr("kgdb ready\n");
528        puts("ready\n");
529}
530
531void
532kgdb_error(int errnum)
533{
534        longjmp_on_fault = 0;
535        kgdb_longjmp(error_jmp_buf, errnum);
536        panic("kgdb_error: longjmp failed!\n");
537}
538
539/* Output string in GDB O-packet format if GDB has connected. If nothing
540   output, returns 0 (caller must then handle output). */
541int
542kgdb_output_string (const char* s, unsigned int count)
543{
544        char buffer[512];
545
546        count = (count <= (sizeof(buffer) / 2 - 2))
547                ? count : (sizeof(buffer) / 2 - 2);
548
549        buffer[0] = 'O';
550        mem2hex ((char *)s, &buffer[1], count);
551        putpacket((unsigned char *)&buffer);
552
553        return 1;
554}
555
556void
557breakpoint(void)
558{
559        if (!initialized) {
560                printf("breakpoint() called b4 kgdb init\n");
561                return;
562        }
563
564        kgdb_breakpoint(0, 0);
565}
566
567int
568do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
569{
570    printf("Entering KGDB mode via exception handler...\n\n");
571    kgdb_breakpoint(argc - 1, argv + 1);
572    printf("\nReturned from KGDB mode\n");
573    return 0;
574}
575
576U_BOOT_CMD(
577        kgdb, CFG_MAXARGS, 1,   do_kgdb,
578        "kgdb    - enter gdb remote debug mode\n",
579        "[arg0 arg1 .. argN]\n"
580        "    - executes a breakpoint so that kgdb mode is\n"
581        "      entered via the exception handler. To return\n"
582        "      to the monitor, the remote gdb debugger must\n"
583        "      execute a \"continue\" or \"quit\" command.\n"
584        "\n"
585        "      if a program is loaded by the remote gdb, any args\n"
586        "      passed to the kgdb command are given to the loaded\n"
587        "      program if it is executed (see the \"hello_world\"\n"
588        "      example program in the U-Boot examples directory)."
589);
590#else
591
592int kgdb_not_configured = 1;
593
594#endif
Note: See TracBrowser for help on using the repository browser.