The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kgdb_stub.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 831a07114365c62fa025a70471112b82


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.