root/kern/kgdb_stub.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kgdb_copy
  2. kgdb_zero
  3. digit2i
  4. i2digit
  5. mem2hex
  6. hex2mem
  7. hex2i
  8. kgdb_send
  9. kgdb_recv
  10. kgdb_attach
  11. kgdb_trap
  12. kgdb_connect
  13. kgdb_panic

    1 /*      $OpenBSD: kgdb_stub.c,v 1.8 2005/11/17 19:23:01 fgsch Exp $     */
    2 /*      $NetBSD: kgdb_stub.c,v 1.6 1998/08/30 20:30:57 scottr Exp $     */
    3 
    4 /*
    5  * Copyright (c) 1990, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This software was developed by the Computer Systems Engineering group
    9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   10  * contributed to Berkeley.
   11  *
   12  * All advertising materials mentioning features or use of this software
   13  * must display the following acknowledgement:
   14  *      This product includes software developed by the University of
   15  *      California, Lawrence Berkeley Laboratories.
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  * 3. Neither the name of the University nor the names of its contributors
   26  *    may be used to endorse or promote products derived from this software
   27  *    without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   39  * SUCH DAMAGE.
   40  *
   41  *      @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
   42  */
   43 
   44 /*
   45  * "Stub" to allow remote cpu to debug over a serial line using gdb.
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/kgdb.h>
   51 
   52 /* #define      DEBUG_KGDB XXX */
   53 
   54 /* XXX: Maybe these should be in the MD files? */
   55 #ifndef KGDBDEV
   56 #define KGDBDEV -1
   57 #endif
   58 #ifndef KGDBRATE
   59 #define KGDBRATE 19200
   60 #endif
   61 
   62 int kgdb_dev = KGDBDEV;         /* remote debugging device (-1 if none) */
   63 int kgdb_rate = KGDBRATE;       /* remote debugging baud rate */
   64 int kgdb_active = 0;            /* remote debugging active if != 0 */
   65 int kgdb_debug_init = 0;        /* != 0 waits for remote at system init */
   66 int kgdb_debug_panic = 0;       /* != 0 waits for remote on panic */
   67 label_t *kgdb_recover = 0;
   68 
   69 static void kgdb_copy(void *, void *, int);
   70 /* static void kgdb_zero(void *, int); */
   71 static void kgdb_send(u_char *);
   72 static int kgdb_recv(u_char *, int);
   73 static int digit2i(u_char);
   74 static u_char i2digit(int);
   75 static void mem2hex(void *, void *, int);
   76 static u_char *hex2mem(void *, u_char *, int);
   77 static vaddr_t hex2i(u_char **);
   78 
   79 static int (*kgdb_getc)(void *);
   80 static void (*kgdb_putc)(void *, int);
   81 static void *kgdb_ioarg;
   82 
   83 static u_char buffer[KGDB_BUFLEN];
   84 static kgdb_reg_t gdb_regs[KGDB_NUMREGS];
   85 
   86 #define GETC()  ((*kgdb_getc)(kgdb_ioarg))
   87 #define PUTC(c) ((*kgdb_putc)(kgdb_ioarg, c))
   88 
   89 /*
   90  * This little routine exists simply so that bcopy() can be debugged.
   91  */
   92 static void
   93 kgdb_copy(void *vsrc, void *vdst, int len)
   94 {
   95         char *src = vsrc;
   96         char *dst = vdst;
   97 
   98         while (--len >= 0)
   99                 *dst++ = *src++;
  100 }
  101 
  102 #if 0
  103 /* ditto for bzero */
  104 static void
  105 kgdb_zero(void *vptr, int len)
  106 {
  107         char *ptr = vptr;
  108 
  109         while (--len >= 0)
  110                 *ptr++ = (char) 0;
  111 }
  112 #endif
  113 
  114 /*
  115  * Convert a hex digit into an integer.
  116  * This returns -1 if the argument passed is no
  117  * valid hex digit.
  118  */
  119 static int
  120 digit2i(u_char c)
  121 {
  122         if (c >= '0' && c <= '9')
  123                 return (c - '0');
  124         else if (c >= 'a' && c <= 'f')
  125                 return (c - 'a' + 10);
  126         else if (c >= 'A' && c <= 'F')
  127 
  128                 return (c - 'A' + 10);
  129         else
  130                 return (-1);
  131 }
  132 
  133 /*
  134  * Convert the low 4 bits of an integer into
  135  * an hex digit.
  136  */
  137 static u_char
  138 i2digit(int n)
  139 {
  140         return ("0123456789abcdef"[n & 0x0f]);
  141 }
  142 
  143 /*
  144  * Convert a byte array into an hex string.
  145  */
  146 static void
  147 mem2hex(void *vdst, void *vsrc, int len)
  148 {
  149         u_char *dst = vdst;
  150         u_char *src = vsrc;
  151 
  152         while (len--) {
  153                 *dst++ = i2digit(*src >> 4);
  154                 *dst++ = i2digit(*src++);
  155         }
  156         *dst = '\0';
  157 }
  158 
  159 /*
  160  * Convert an hex string into a byte array.
  161  * This returns a pointer to the character following
  162  * the last valid hex digit. If the string ends in
  163  * the middle of a byte, NULL is returned.
  164  */
  165 static u_char *
  166 hex2mem(void *vdst, u_char *src, int maxlen)
  167 {
  168         u_char *dst = vdst;
  169         int msb, lsb;
  170 
  171         while (*src && maxlen--) {
  172                 msb = digit2i(*src++);
  173                 if (msb < 0)
  174                         return (src - 1);
  175                 lsb = digit2i(*src++);
  176                 if (lsb < 0)
  177                         return (NULL);
  178                 *dst++ = (msb << 4) | lsb;
  179         }
  180         return (src);
  181 }
  182 
  183 /*
  184  * Convert an hex string into an integer.
  185  * This returns a pointer to the character following
  186  * the last valid hex digit.
  187  */
  188 static vaddr_t
  189 hex2i(u_char **srcp)
  190 {
  191         char *src = *srcp;
  192         vaddr_t r = 0;
  193         int nibble;
  194 
  195         while ((nibble = digit2i(*src)) >= 0) {
  196                 r *= 16;
  197                 r += nibble;
  198                 src++;
  199         }
  200         *srcp = src;
  201         return (r);
  202 }
  203 
  204 /*
  205  * Send a packet.
  206  */
  207 static void
  208 kgdb_send(u_char *bp)
  209 {
  210         u_char *p;
  211         u_char csum, c;
  212 
  213 #ifdef  DEBUG_KGDB
  214         printf("kgdb_send: %s\n", bp);
  215 #endif
  216         do {
  217                 p = bp;
  218                 PUTC(KGDB_START);
  219                 for (csum = 0; (c = *p); p++) {
  220                         PUTC(c);
  221                         csum += c;
  222                 }
  223                 PUTC(KGDB_END);
  224                 PUTC(i2digit(csum >> 4));
  225                 PUTC(i2digit(csum));
  226         } while ((c = GETC() & 0x7f) == KGDB_BADP);
  227 }
  228 
  229 /*
  230  * Receive a packet.
  231  */
  232 static int
  233 kgdb_recv(u_char *bp, int maxlen)
  234 {
  235         u_char *p;
  236         int c, csum;
  237         int len;
  238 
  239         do {
  240                 p = bp;
  241                 csum = len = 0;
  242                 while ((c = GETC()) != KGDB_START)
  243                         ;
  244 
  245                 while ((c = GETC()) != KGDB_END && len < maxlen) {
  246                         c &= 0x7f;
  247                         csum += c;
  248                         *p++ = c;
  249                         len++;
  250                 }
  251                 csum &= 0xff;
  252                 *p = '\0';
  253 
  254                 if (len >= maxlen) {
  255                         PUTC(KGDB_BADP);
  256                         continue;
  257                 }
  258 
  259                 csum -= digit2i(GETC()) * 16;
  260                 csum -= digit2i(GETC());
  261 
  262                 if (csum == 0) {
  263                         PUTC(KGDB_GOODP);
  264                         /* Sequence present? */
  265                         if (bp[2] == ':') {
  266                                 PUTC(bp[0]);
  267                                 PUTC(bp[1]);
  268                                 len -= 3;
  269                                 kgdb_copy(bp + 3, bp, len);
  270                         }
  271                         break;
  272                 }
  273                 PUTC(KGDB_BADP);
  274         } while (1);
  275 #ifdef  DEBUG_KGDB
  276         printf("kgdb_recv: %s\n", bp);
  277 #endif
  278         return (len);
  279 }
  280 
  281 /*
  282  * This is called by the appropriate tty driver.
  283  */
  284 void
  285 kgdb_attach(int (*getfn)(void *), void (*putfn)(void *, int), void *ioarg)
  286 {
  287         kgdb_getc = getfn;
  288         kgdb_putc = putfn;
  289         kgdb_ioarg = ioarg;
  290 }
  291 
  292 /*
  293  * This function does all command processing for interfacing to
  294  * a remote gdb.  Note that the error codes are ignored by gdb
  295  * at present, but might eventually become meaningful. (XXX)
  296  * It might makes sense to use POSIX errno values, because
  297  * that is what the gdb/remote.c functions want to return.
  298  */
  299 int
  300 kgdb_trap(int type, db_regs_t *regs)
  301 {
  302         label_t jmpbuf;
  303         vaddr_t addr;
  304         size_t len;
  305         u_char *p;
  306 
  307         if (kgdb_dev < 0 || kgdb_getc == NULL) {
  308                 /* not debugging */
  309                 return (0);
  310         }
  311 
  312         /* Detect and recover from unexpected traps. */
  313         if (kgdb_recover != 0) {
  314                 printf("kgdb: caught trap 0x%x at %p\n",
  315                            type, (void *)PC_REGS(regs));
  316                 kgdb_send("E0E"); /* 14==EFAULT */
  317                 longjmp(kgdb_recover);
  318         }
  319 
  320         /*
  321          * The first entry to this function is normally through
  322          * a breakpoint trap in kgdb_connect(), in which case we
  323          * must advance past the breakpoint because gdb will not.
  324          *
  325          * Machines vary as to where they leave the PC after a
  326          * breakpoint trap.  Those that leave the PC set to the
  327          * address of the trap instruction (i.e. pc532) will not
  328          * define FIXUP_PC_AFTER_BREAK(), and therefore will just
  329          * advance the PC.  On machines that leave the PC set to
  330          * the instruction after the trap, FIXUP_PC_AFTER_BREAK
  331          * will be defined to back-up the PC, so that after the
  332          * "first-time" part of the if statement below has run,
  333          * the PC will be the same as it was on entry.
  334          *
  335          * On the first entry here, we expect that gdb is not yet
  336          * listening to us, so just enter the interaction loop.
  337          * After the debugger is "active" (connected) it will be
  338          * waiting for a "signaled" message from us.
  339          */
  340         if (kgdb_active == 0) {
  341                 if (!IS_BREAKPOINT_TRAP(type, 0)) {
  342                         /* No debugger active -- let trap handle this. */
  343                         return (0);
  344                 }
  345                 /* Make the PC point at the breakpoint... */
  346 #ifdef  FIXUP_PC_AFTER_BREAK
  347                 FIXUP_PC_AFTER_BREAK(regs);
  348 #endif
  349                 /* ... and then advance past it. */
  350 #ifdef  PC_ADVANCE
  351                 PC_ADVANCE(regs);
  352 #else
  353                 PC_REGS(regs) += BKPT_SIZE;
  354 #endif
  355                 kgdb_active = 1;
  356         } else {
  357                 /* Tell remote host that an exception has occurred. */
  358                 snprintf(buffer, sizeof buffer, "S%02x", kgdb_signal(type));
  359                 kgdb_send(buffer);
  360         }
  361 
  362         /* Stick frame regs into our reg cache. */
  363         kgdb_getregs(regs, gdb_regs);
  364 
  365         /*
  366          * Interact with gdb until it lets us go.
  367          * If we cause a trap, resume here.
  368          */
  369         (void)setjmp((kgdb_recover = &jmpbuf));
  370         for (;;) {
  371                 kgdb_recv(buffer, sizeof(buffer));
  372                 switch (buffer[0]) {
  373 
  374                 default:
  375                         /* Unknown command. */
  376                         kgdb_send("");
  377                         continue;
  378 
  379                 case KGDB_SIGNAL:
  380                         /*
  381                          * if this command came from a running gdb,
  382                          * answer it -- the other guy has no way of
  383                          * knowing if we're in or out of this loop
  384                          * when he issues a "remote-signal".
  385                          */
  386                         snprintf(buffer, sizeof buffer, "S%02x",
  387                             kgdb_signal(type));
  388                         kgdb_send(buffer);
  389                         continue;
  390 
  391                 case KGDB_REG_R:
  392                         mem2hex(buffer, gdb_regs, sizeof(gdb_regs));
  393                         kgdb_send(buffer);
  394                         continue;
  395 
  396                 case KGDB_REG_W:
  397                         p = hex2mem(gdb_regs, buffer + 1, sizeof(gdb_regs));
  398                         if (p == NULL || *p != '\0')
  399                                 kgdb_send("E01");
  400                         else {
  401                                 kgdb_setregs(regs, gdb_regs);
  402                                 kgdb_send("OK");
  403                         }
  404                         continue;
  405 
  406                 case KGDB_MEM_R:
  407                         p = buffer + 1;
  408                         addr = hex2i(&p);
  409                         if (*p++ != ',') {
  410                                 kgdb_send("E02");
  411                                 continue;
  412                         }
  413                         len = hex2i(&p);
  414                         if (*p != '\0') {
  415                                 kgdb_send("E03");
  416                                 continue;
  417                         }
  418                         if (len > sizeof(buffer) / 2) {
  419                                 kgdb_send("E04");
  420                                 continue;
  421                         }
  422                         if (kgdb_acc(addr, len) == 0) {
  423                                 kgdb_send("E05");
  424                                 continue;
  425                         }
  426                         db_read_bytes(addr, (size_t)len,
  427                                         (char *)buffer + sizeof(buffer) / 2);
  428                         mem2hex(buffer, buffer + sizeof(buffer) / 2, len);
  429                         kgdb_send(buffer);
  430                         continue;
  431 
  432                 case KGDB_MEM_W:
  433                         p = buffer + 1;
  434                         addr = hex2i(&p);
  435                         if (*p++ != ',') {
  436                                 kgdb_send("E06");
  437                                 continue;
  438                         }
  439                         len = hex2i(&p);
  440                         if (*p++ != ':') {
  441                                 kgdb_send("E07");
  442                                 continue;
  443                         }
  444                         if (len > (sizeof(buffer) - (p - buffer))) {
  445                                 kgdb_send("E08");
  446                                 continue;
  447                         }
  448                         p = hex2mem(buffer, p, sizeof(buffer));
  449                         if (p == NULL) {
  450                                 kgdb_send("E09");
  451                                 continue;
  452                         }
  453                         if (kgdb_acc(addr, len) == 0) {
  454                                 kgdb_send("E0A");
  455                                 continue;
  456                         }
  457                         db_write_bytes(addr, (size_t)len, (char *)buffer);
  458                         kgdb_send("OK");
  459                         continue;
  460 
  461                 case KGDB_DETACH:
  462                         kgdb_active = 0;
  463                         printf("kgdb detached\n");
  464                         db_clear_single_step(regs);
  465                         kgdb_send("OK");
  466                         goto out;
  467 
  468                 case KGDB_KILL:
  469                         kgdb_active = 0;
  470                         printf("kgdb detached\n");
  471                         db_clear_single_step(regs);
  472                         goto out;
  473 
  474                 case KGDB_CONT:
  475                         if (buffer[1]) {
  476                                 p = buffer + 1;
  477                                 addr = hex2i(&p);
  478                                 if (*p) {
  479                                         kgdb_send("E0B");
  480                                         continue;
  481                                 }
  482                                 PC_REGS(regs) = addr;
  483                         }
  484                         db_clear_single_step(regs);
  485                         goto out;
  486 
  487                 case KGDB_STEP:
  488                         if (buffer[1]) {
  489                                 p = buffer + 1;
  490                                 addr = hex2i(&p);
  491                                 if (*p) {
  492                                         kgdb_send("E0B");
  493                                         continue;
  494                                 }
  495                                 PC_REGS(regs) = addr;
  496                         }
  497                         db_set_single_step(regs);
  498                         goto out;
  499                 }
  500         }
  501  out:
  502         kgdb_recover = 0;
  503         return (1);
  504 }
  505 
  506 /*
  507  * Trap into kgdb to wait for debugger to connect,
  508  * noting on the console why nothing else is going on.
  509  */
  510 void
  511 kgdb_connect(int verbose)
  512 {
  513         if (kgdb_dev < 0)
  514                 return;
  515 
  516         KGDB_PREPARE;
  517 
  518         if (verbose)
  519                 printf("kgdb waiting...");
  520 
  521         KGDB_ENTER;
  522 
  523         if (verbose)
  524                 printf("connected.\n");
  525 
  526         kgdb_debug_panic = 1;
  527 }
  528 
  529 /*
  530  * Decide what to do on panic.
  531  * (This is called by panic, like Debugger())
  532  */
  533 void
  534 kgdb_panic()
  535 {
  536         if (kgdb_dev >= 0 && kgdb_debug_panic) {
  537                 printf("entering kgdb\n");
  538                 kgdb_connect(kgdb_active == 0);
  539         }
  540 }

/* [<][>][^][v][top][bottom][index][help] */