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