uboot/common/kgdb.c
<<
>>
Prefs
   1/* taken from arch/powerpc/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#include <asm/ptrace.h>
  92
  93#include <kgdb.h>
  94#include <command.h>
  95
  96#undef KGDB_DEBUG
  97
  98/*
  99 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
 100 */
 101#define BUFMAX 1024
 102static char remcomInBuffer[BUFMAX];
 103static char remcomOutBuffer[BUFMAX];
 104static char remcomRegBuffer[BUFMAX];
 105
 106static int initialized = 0;
 107static int kgdb_active;
 108static struct pt_regs entry_regs;
 109static long error_jmp_buf[BUFMAX/2];
 110static int longjmp_on_fault = 0;
 111#ifdef KGDB_DEBUG
 112static int kdebug = 1;
 113#endif
 114
 115static const char hexchars[]="0123456789abcdef";
 116
 117/* Convert ch from a hex digit to an int */
 118static int
 119hex(unsigned char ch)
 120{
 121        if (ch >= 'a' && ch <= 'f')
 122                return ch-'a'+10;
 123        if (ch >= '0' && ch <= '9')
 124                return ch-'0';
 125        if (ch >= 'A' && ch <= 'F')
 126                return ch-'A'+10;
 127        return -1;
 128}
 129
 130/* Convert the memory pointed to by mem into hex, placing result in buf.
 131 * Return a pointer to the last char put in buf (null).
 132 */
 133static unsigned char *
 134mem2hex(char *mem, char *buf, int count)
 135{
 136        char *tmp;
 137        unsigned char ch;
 138
 139        /*
 140         * We use the upper half of buf as an intermediate buffer for the
 141         * raw memory copy.  Hex conversion will work against this one.
 142         */
 143        tmp = buf + count;
 144        longjmp_on_fault = 1;
 145
 146        memcpy(tmp, mem, count);
 147
 148        while (count-- > 0) {
 149                ch = *tmp++;
 150                *buf++ = hexchars[ch >> 4];
 151                *buf++ = hexchars[ch & 0xf];
 152        }
 153        *buf = 0;
 154        longjmp_on_fault = 0;
 155        return (unsigned char *)buf;
 156}
 157
 158/* convert the hex array pointed to by buf into binary to be placed in mem
 159 * return a pointer to the character AFTER the last byte fetched from buf.
 160*/
 161static char *
 162hex2mem(char *buf, char *mem, int count)
 163{
 164        int hexValue;
 165        char *tmp_raw, *tmp_hex;
 166
 167        /*
 168         * We use the upper half of buf as an intermediate buffer for the
 169         * raw memory that is converted from hex.
 170         */
 171        tmp_raw = buf + count * 2;
 172        tmp_hex = tmp_raw - 1;
 173
 174        longjmp_on_fault = 1;
 175        while (tmp_hex >= buf) {
 176                tmp_raw--;
 177                hexValue = hex(*tmp_hex--);
 178                if (hexValue < 0)
 179                        kgdb_error(KGDBERR_NOTHEXDIG);
 180                *tmp_raw = hexValue;
 181                hexValue = hex(*tmp_hex--);
 182                if (hexValue < 0)
 183                        kgdb_error(KGDBERR_NOTHEXDIG);
 184                *tmp_raw |= hexValue << 4;
 185
 186        }
 187
 188        memcpy(mem, tmp_raw, count);
 189
 190        kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
 191        longjmp_on_fault = 0;
 192
 193        return buf;
 194}
 195
 196/*
 197 * While we find nice hex chars, build an int.
 198 * Return number of chars processed.
 199 */
 200static int
 201hexToInt(char **ptr, int *intValue)
 202{
 203        int numChars = 0;
 204        int hexValue;
 205
 206        *intValue = 0;
 207
 208        longjmp_on_fault = 1;
 209        while (**ptr) {
 210                hexValue = hex(**ptr);
 211                if (hexValue < 0)
 212                        break;
 213
 214                *intValue = (*intValue << 4) | hexValue;
 215                numChars ++;
 216
 217                (*ptr)++;
 218        }
 219        longjmp_on_fault = 0;
 220
 221        return (numChars);
 222}
 223
 224/* scan for the sequence $<data>#<checksum>     */
 225static void
 226getpacket(char *buffer)
 227{
 228        unsigned char checksum;
 229        unsigned char xmitcsum;
 230        int i;
 231        int count;
 232        unsigned char ch;
 233
 234        do {
 235                /* wait around for the start character, ignore all other
 236                 * characters */
 237                while ((ch = (getDebugChar() & 0x7f)) != '$') {
 238#ifdef KGDB_DEBUG
 239                        if (kdebug)
 240                                putc(ch);
 241#endif
 242                        ;
 243                }
 244
 245                checksum = 0;
 246                xmitcsum = -1;
 247
 248                count = 0;
 249
 250                /* now, read until a # or end of buffer is found */
 251                while (count < BUFMAX) {
 252                        ch = getDebugChar() & 0x7f;
 253                        if (ch == '#')
 254                                break;
 255                        checksum = checksum + ch;
 256                        buffer[count] = ch;
 257                        count = count + 1;
 258                }
 259
 260                if (count >= BUFMAX)
 261                        continue;
 262
 263                buffer[count] = 0;
 264
 265                if (ch == '#') {
 266                        xmitcsum = hex(getDebugChar() & 0x7f) << 4;
 267                        xmitcsum |= hex(getDebugChar() & 0x7f);
 268                        if (checksum != xmitcsum)
 269                                putDebugChar('-');      /* failed checksum */
 270                        else {
 271                                putDebugChar('+'); /* successful transfer */
 272                                /* if a sequence char is present, reply the ID */
 273                                if (buffer[2] == ':') {
 274                                        putDebugChar(buffer[0]);
 275                                        putDebugChar(buffer[1]);
 276                                        /* remove sequence chars from buffer */
 277                                        count = strlen(buffer);
 278                                        for (i=3; i <= count; i++)
 279                                                buffer[i-3] = buffer[i];
 280                                }
 281                        }
 282                }
 283        } while (checksum != xmitcsum);
 284}
 285
 286/* send the packet in buffer.  */
 287static void
 288putpacket(unsigned char *buffer)
 289{
 290        unsigned char checksum;
 291        int count;
 292        unsigned char ch, recv;
 293
 294        /*  $<packet info>#<checksum>. */
 295        do {
 296                putDebugChar('$');
 297                checksum = 0;
 298                count = 0;
 299
 300                while ((ch = buffer[count])) {
 301                        putDebugChar(ch);
 302                        checksum += ch;
 303                        count += 1;
 304                }
 305
 306                putDebugChar('#');
 307                putDebugChar(hexchars[checksum >> 4]);
 308                putDebugChar(hexchars[checksum & 0xf]);
 309                recv = getDebugChar();
 310        } while ((recv & 0x7f) != '+');
 311}
 312
 313/*
 314 * This function does all command processing for interfacing to gdb.
 315 */
 316static int
 317handle_exception (struct pt_regs *regs)
 318{
 319        int addr;
 320        int length;
 321        char *ptr;
 322        kgdb_data kd;
 323        int i;
 324
 325        if (!initialized) {
 326                printf("kgdb: exception before kgdb is initialized! huh?\n");
 327                return (0);
 328        }
 329
 330        /* probably should check which exception occurred as well */
 331        if (longjmp_on_fault) {
 332                longjmp_on_fault = 0;
 333                kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
 334                panic("kgdb longjump failed!\n");
 335        }
 336
 337        if (kgdb_active) {
 338                printf("kgdb: unexpected exception from within kgdb\n");
 339                return (0);
 340        }
 341        kgdb_active = 1;
 342
 343        kgdb_interruptible(0);
 344
 345        printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
 346
 347        if (kgdb_setjmp(error_jmp_buf) != 0)
 348                panic("kgdb: error or fault in entry init!\n");
 349
 350        kgdb_enter(regs, &kd);
 351
 352        entry_regs = *regs;
 353
 354        ptr = remcomOutBuffer;
 355
 356        *ptr++ = 'T';
 357
 358        *ptr++ = hexchars[kd.sigval >> 4];
 359        *ptr++ = hexchars[kd.sigval & 0xf];
 360
 361        for (i = 0; i < kd.nregs; i++) {
 362                kgdb_reg *rp = &kd.regs[i];
 363
 364                *ptr++ = hexchars[rp->num >> 4];
 365                *ptr++ = hexchars[rp->num & 0xf];
 366                *ptr++ = ':';
 367                ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
 368                *ptr++ = ';';
 369        }
 370
 371        *ptr = 0;
 372
 373#ifdef KGDB_DEBUG
 374        if (kdebug)
 375                printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
 376#endif
 377
 378        putpacket((unsigned char *)&remcomOutBuffer);
 379
 380        while (1) {
 381                volatile int errnum;
 382
 383                remcomOutBuffer[0] = 0;
 384
 385                getpacket(remcomInBuffer);
 386                ptr = &remcomInBuffer[1];
 387
 388#ifdef KGDB_DEBUG
 389                if (kdebug)
 390                        printf("kgdb:  remcomInBuffer: %s\n", remcomInBuffer);
 391#endif
 392
 393                errnum = kgdb_setjmp(error_jmp_buf);
 394
 395                if (errnum == 0) switch (remcomInBuffer[0]) {
 396
 397                case '?':               /* report most recent signal */
 398                        remcomOutBuffer[0] = 'S';
 399                        remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
 400                        remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
 401                        remcomOutBuffer[3] = 0;
 402                        break;
 403
 404#ifdef KGDB_DEBUG
 405                case 'd':
 406                        /* toggle debug flag */
 407                        kdebug ^= 1;
 408                        break;
 409#endif
 410
 411                case 'g':       /* return the value of the CPU registers. */
 412                        length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
 413                        mem2hex(remcomRegBuffer, remcomOutBuffer, length);
 414                        break;
 415
 416                case 'G':   /* set the value of the CPU registers */
 417                        length = strlen(ptr);
 418                        if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
 419                        hex2mem(ptr, remcomRegBuffer, length/2);
 420                        kgdb_putregs(regs, remcomRegBuffer, length/2);
 421                        strcpy(remcomOutBuffer,"OK");
 422                        break;
 423
 424                case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
 425                                /* Try to read %x,%x.  */
 426
 427                        if (hexToInt(&ptr, &addr)
 428                            && *ptr++ == ','
 429                            && hexToInt(&ptr, &length)) {
 430                                mem2hex((char *)addr, remcomOutBuffer, length);
 431                        } else {
 432                                kgdb_error(KGDBERR_BADPARAMS);
 433                        }
 434                        break;
 435
 436                case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
 437                        /* Try to read '%x,%x:'.  */
 438
 439                        if (hexToInt(&ptr, &addr)
 440                            && *ptr++ == ','
 441                            && hexToInt(&ptr, &length)
 442                            && *ptr++ == ':') {
 443                                hex2mem(ptr, (char *)addr, length);
 444                                strcpy(remcomOutBuffer, "OK");
 445                        } else {
 446                                kgdb_error(KGDBERR_BADPARAMS);
 447                        }
 448                        break;
 449
 450
 451                case 'k':    /* kill the program, actually return to monitor */
 452                        kd.extype = KGDBEXIT_KILL;
 453                        *regs = entry_regs;
 454                        goto doexit;
 455
 456                case 'C':    /* CSS  continue with signal SS */
 457                        *ptr = '\0';    /* ignore the signal number for now */
 458                        /* fall through */
 459
 460                case 'c':    /* cAA..AA  Continue; address AA..AA optional */
 461                        /* try to read optional parameter, pc unchanged if no parm */
 462                        kd.extype = KGDBEXIT_CONTINUE;
 463
 464                        if (hexToInt(&ptr, &addr)) {
 465                                kd.exaddr = addr;
 466                                kd.extype |= KGDBEXIT_WITHADDR;
 467                        }
 468
 469                        goto doexit;
 470
 471                case 'S':    /* SSS  single step with signal SS */
 472                        *ptr = '\0';    /* ignore the signal number for now */
 473                        /* fall through */
 474
 475                case 's':
 476                        kd.extype = KGDBEXIT_SINGLE;
 477
 478                        if (hexToInt(&ptr, &addr)) {
 479                                kd.exaddr = addr;
 480                                kd.extype |= KGDBEXIT_WITHADDR;
 481                        }
 482
 483                doexit:
 484/* Need to flush the instruction cache here, as we may have deposited a
 485 * breakpoint, and the icache probably has no way of knowing that a data ref to
 486 * some location may have changed something that is in the instruction cache.
 487 */
 488                        kgdb_flush_cache_all();
 489                        kgdb_exit(regs, &kd);
 490                        kgdb_active = 0;
 491                        kgdb_interruptible(1);
 492                        return (1);
 493
 494                case 'r':               /* Reset (if user process..exit ???)*/
 495                        panic("kgdb reset.");
 496                        break;
 497
 498                case 'P':    /* Pr=v  set reg r to value v (r and v are hex) */
 499                        if (hexToInt(&ptr, &addr)
 500                            && *ptr++ == '='
 501                            && ((length = strlen(ptr)) & 1) == 0) {
 502                                hex2mem(ptr, remcomRegBuffer, length/2);
 503                                kgdb_putreg(regs, addr,
 504                                        remcomRegBuffer, length/2);
 505                                strcpy(remcomOutBuffer,"OK");
 506                        } else {
 507                                kgdb_error(KGDBERR_BADPARAMS);
 508                        }
 509                        break;
 510                }                       /* switch */
 511
 512                if (errnum != 0)
 513                        sprintf(remcomOutBuffer, "E%02d", errnum);
 514
 515#ifdef KGDB_DEBUG
 516                if (kdebug)
 517                        printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
 518#endif
 519
 520                /* reply to the request */
 521                putpacket((unsigned char *)&remcomOutBuffer);
 522
 523        } /* while(1) */
 524}
 525
 526/*
 527 * kgdb_init must be called *after* the
 528 * monitor is relocated into ram
 529 */
 530void
 531kgdb_init(void)
 532{
 533        kgdb_serial_init();
 534        debugger_exception_handler = handle_exception;
 535        initialized = 1;
 536
 537        putDebugStr("kgdb ready\n");
 538        puts("ready\n");
 539}
 540
 541void
 542kgdb_error(int errnum)
 543{
 544        longjmp_on_fault = 0;
 545        kgdb_longjmp(error_jmp_buf, errnum);
 546        panic("kgdb_error: longjmp failed!\n");
 547}
 548
 549/* Output string in GDB O-packet format if GDB has connected. If nothing
 550   output, returns 0 (caller must then handle output). */
 551int
 552kgdb_output_string (const char* s, unsigned int count)
 553{
 554        char buffer[512];
 555
 556        count = (count <= (sizeof(buffer) / 2 - 2))
 557                ? count : (sizeof(buffer) / 2 - 2);
 558
 559        buffer[0] = 'O';
 560        mem2hex ((char *)s, &buffer[1], count);
 561        putpacket((unsigned char *)&buffer);
 562
 563        return 1;
 564}
 565
 566void
 567breakpoint(void)
 568{
 569        if (!initialized) {
 570                printf("breakpoint() called b4 kgdb init\n");
 571                return;
 572        }
 573
 574        kgdb_breakpoint(0, 0);
 575}
 576
 577int
 578do_kgdb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 579{
 580    printf("Entering KGDB mode via exception handler...\n\n");
 581    kgdb_breakpoint(argc - 1, argv + 1);
 582    printf("\nReturned from KGDB mode\n");
 583    return 0;
 584}
 585
 586U_BOOT_CMD(
 587        kgdb, CONFIG_SYS_MAXARGS, 1,    do_kgdb,
 588        "enter gdb remote debug mode",
 589        "[arg0 arg1 .. argN]\n"
 590        "    - executes a breakpoint so that kgdb mode is\n"
 591        "      entered via the exception handler. To return\n"
 592        "      to the monitor, the remote gdb debugger must\n"
 593        "      execute a \"continue\" or \"quit\" command.\n"
 594        "\n"
 595        "      if a program is loaded by the remote gdb, any args\n"
 596        "      passed to the kgdb command are given to the loaded\n"
 597        "      program if it is executed (see the \"hello_world\"\n"
 598        "      example program in the U-Boot examples directory)."
 599);
 600