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/amd64/amd64/amd64-gdbstub.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /****************************************************************************
    2 
    3                 THIS SOFTWARE IS NOT COPYRIGHTED
    4 
    5    HP offers the following for use in the public domain.  HP makes no
    6    warranty with regard to the software or its performance and the
    7    user accepts the software "AS IS" with all faults.
    8 
    9    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
   10    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   11    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   12 
   13 ****************************************************************************/
   14 
   15 /****************************************************************************
   16  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
   17  *
   18  *  Module name: remcom.c $
   19  *  Revision: 1.34 $
   20  *  Date: 91/03/09 12:29:49 $
   21  *  Contributor:     Lake Stevens Instrument Division$
   22  *
   23  *  Description:     low level support for gdb debugger. $
   24  *
   25  *  Considerations:  only works on target hardware $
   26  *
   27  *  Written by:      Glenn Engel $
   28  *  ModuleState:     Experimental $
   29  *
   30  *  NOTES:           See Below $
   31  *
   32  *  Modified for FreeBSD by Stu Grossman.
   33  *
   34  *  To enable debugger support, two things need to happen.  One, a
   35  *  call to set_debug_traps() is necessary in order to allow any breakpoints
   36  *  or error conditions to be properly intercepted and reported to gdb.
   37  *  Two, a breakpoint needs to be generated to begin communication.  This
   38  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
   39  *  simulates a breakpoint by executing a trap #1.
   40  *
   41  *  The external function exceptionHandler() is
   42  *  used to attach a specific handler to a specific 386 vector number.
   43  *  It should use the same privilege level it runs at.  It should
   44  *  install it as an interrupt gate so that interrupts are masked
   45  *  while the handler runs.
   46  *  Also, need to assign exceptionHook and oldExceptionHook.
   47  *
   48  *  Because gdb will sometimes write to the stack area to execute function
   49  *  calls, this program cannot rely on using the supervisor stack so it
   50  *  uses its own stack area reserved in the int array remcomStack.
   51  *
   52  *************
   53  *
   54  *    The following gdb commands are supported:
   55  *
   56  * command          function                               Return value
   57  *
   58  *    g             return the value of the CPU registers  hex data or ENN
   59  *    G             set the value of the CPU registers     OK or ENN
   60  *
   61  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
   62  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
   63  *
   64  *    c             Resume at current address              SNN   ( signal NN)
   65  *    cAA..AA       Continue at address AA..AA             SNN
   66  *
   67  *    s             Step one instruction                   SNN
   68  *    sAA..AA       Step one instruction from AA..AA       SNN
   69  *
   70  *    k             kill
   71  *
   72  *    ?             What was the last sigval ?             SNN   (signal NN)
   73  *
   74  *    D             detach                                 OK
   75  *
   76  * All commands and responses are sent with a packet which includes a
   77  * checksum.  A packet consists of
   78  *
   79  * $<packet info>#<checksum>.
   80  *
   81  * where
   82  * <packet info> :: <characters representing the command or response>
   83  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
   84  *
   85  * When a packet is received, it is first acknowledged with either '+' or '-'.
   86  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
   87  *
   88  * Example:
   89  *
   90  * Host:                  Reply:
   91  * $m0,10#2a               +$00010203040506070809101112131415#42
   92  *
   93  ****************************************************************************/
   94 
   95 /* $FreeBSD: releng/5.1/sys/amd64/amd64/amd64-gdbstub.c 115404 2003-05-30 01:02:52Z peter $ */
   96 
   97 #include <sys/param.h>
   98 #include <sys/reboot.h>
   99 #include <sys/systm.h>
  100 #include <sys/cons.h>
  101 
  102 #include <ddb/ddb.h>
  103 
  104 #include <machine/setjmp.h>
  105 
  106 #include "opt_ddb.h"
  107 
  108 int             gdb_handle_exception (db_regs_t *, int, int);
  109 
  110 /************************************************************************/
  111 
  112 extern jmp_buf  db_jmpbuf;
  113 
  114 /************************************************************************/
  115 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
  116 /* at least NUMREGBYTES*2 are needed for register packets */
  117 #define BUFMAX 400
  118 
  119 /* Create private copies of common functions used by the stub.  This prevents
  120    nasty interactions between app code and the stub (for instance if user steps
  121    into strlen, etc..) */
  122 
  123 #define strlen  gdb_strlen
  124 #define strcpy  gdb_strcpy
  125 
  126 static int
  127 strlen (const char *s)
  128 {
  129   const char *s1 = s;
  130 
  131   while (*s1++ != '\000');
  132 
  133   return s1 - s;
  134 }
  135 
  136 static char *
  137 strcpy (char *dst, const char *src)
  138 {
  139   char *retval = dst;
  140 
  141   while ((*dst++ = *src++) != '\000');
  142 
  143   return retval;
  144 }
  145 
  146 static int
  147 putDebugChar (int c)            /* write a single character      */
  148 {
  149   if (gdb_arg == NULL)
  150         return 0;
  151   (*gdb_putc)(gdb_arg, c);
  152   return 1;
  153 }
  154 
  155 static int
  156 getDebugChar (void)             /* read and return a single char */
  157 {
  158   if (gdb_arg == NULL)
  159         return -1;
  160   return (*gdb_getc)(gdb_arg);
  161 }
  162 
  163 static const char hexchars[]="0123456789abcdef";
  164 
  165 static int
  166 hex(char ch)
  167 {
  168   if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
  169   if ((ch >= '') && (ch <= '9')) return (ch-'');
  170   if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
  171   return (-1);
  172 }
  173 
  174 /* scan for the sequence $<data>#<checksum>     */
  175 static void
  176 getpacket (char *buffer)
  177 {
  178   unsigned char checksum;
  179   unsigned char xmitcsum;
  180   int i;
  181   int count;
  182   unsigned char ch;
  183 
  184   do
  185     {
  186       /* wait around for the start character, ignore all other characters */
  187 
  188       while ((ch = (getDebugChar () & 0x7f)) != '$');
  189 
  190       checksum = 0;
  191       xmitcsum = -1;
  192 
  193       count = 0;
  194 
  195       /* now, read until a # or end of buffer is found */
  196 
  197       while (count < BUFMAX)
  198         {
  199           ch = getDebugChar () & 0x7f;
  200           if (ch == '#')
  201             break;
  202           checksum = checksum + ch;
  203           buffer[count] = ch;
  204           count = count + 1;
  205         }
  206       buffer[count] = 0;
  207 
  208       if (ch == '#')
  209         {
  210           xmitcsum = hex (getDebugChar () & 0x7f) << 4;
  211           xmitcsum += hex (getDebugChar () & 0x7f);
  212 
  213           if (checksum != xmitcsum)
  214             putDebugChar ('-');  /* failed checksum */
  215           else
  216             {
  217               putDebugChar ('+'); /* successful transfer */
  218               /* if a sequence char is present, reply the sequence ID */
  219               if (buffer[2] == ':')
  220                 {
  221                   putDebugChar (buffer[0]);
  222                   putDebugChar (buffer[1]);
  223 
  224                   /* remove sequence chars from buffer */
  225 
  226                   count = strlen (buffer);
  227                   for (i=3; i <= count; i++)
  228                     buffer[i-3] = buffer[i];
  229                 }
  230             }
  231         }
  232     }
  233   while (checksum != xmitcsum);
  234 }
  235 
  236 /* send the packet in buffer.  */
  237 
  238 static void
  239 putpacket (char *buffer)
  240 {
  241   unsigned char checksum;
  242   int count;
  243   unsigned char ch;
  244 
  245   /*  $<packet info>#<checksum>. */
  246   do
  247     {
  248 /*
  249  * This is a non-standard hack to allow use of the serial console for
  250  * operation as well as debugging.  Simply turn on 'remotechat' in gdb.
  251  *
  252  * This extension is not part of the Cygnus protocol, is kinda gross,
  253  * but gets the job done.
  254  */
  255 #ifdef GDB_REMOTE_CHAT
  256       putDebugChar ('|');
  257       putDebugChar ('|');
  258       putDebugChar ('|');
  259       putDebugChar ('|');
  260 #endif
  261       putDebugChar ('$');
  262       checksum = 0;
  263       count = 0;
  264 
  265       while ((ch=buffer[count]) != 0)
  266         {
  267           putDebugChar (ch);
  268           checksum += ch;
  269           count += 1;
  270         }
  271 
  272       putDebugChar ('#');
  273       putDebugChar (hexchars[checksum >> 4]);
  274       putDebugChar (hexchars[checksum & 0xf]);
  275     }
  276   while ((getDebugChar () & 0x7f) != '+');
  277 }
  278 
  279 static char  remcomInBuffer[BUFMAX];
  280 static char  remcomOutBuffer[BUFMAX];
  281 
  282 static int
  283 get_char (vm_offset_t addr)
  284 {
  285   char data;
  286 
  287   if (setjmp (db_jmpbuf))
  288     return -1;
  289 
  290   db_read_bytes (addr, 1, &data);
  291 
  292   return data & 0xff;
  293 }
  294 
  295 static int
  296 set_char (vm_offset_t addr, int val)
  297 {
  298   char data;
  299 
  300   if (setjmp (db_jmpbuf))
  301     return -1;
  302 
  303   data = val;
  304 
  305   db_write_bytes (addr, 1, &data);
  306   return 0;
  307 }
  308 
  309 /* convert the memory pointed to by mem into hex, placing result in buf */
  310 /* return a pointer to the last char put in buf (null) */
  311 
  312 static char *
  313 mem2hex (vm_offset_t mem, char *buf, int count)
  314 {
  315       int i;
  316       int ch;
  317 
  318       for (i=0;i<count;i++) {
  319           ch = get_char (mem++);
  320           if (ch == -1)
  321             return NULL;
  322           *buf++ = hexchars[ch >> 4];
  323           *buf++ = hexchars[ch % 16];
  324       }
  325       *buf = 0;
  326       return(buf);
  327 }
  328 
  329 /* convert the hex array pointed to by buf into binary to be placed in mem */
  330 /* return a pointer to the character AFTER the last byte written */
  331 static char *
  332 hex2mem (char *buf, vm_offset_t mem, int count)
  333 {
  334       int i;
  335       int ch;
  336       int rv;
  337 
  338       for (i=0;i<count;i++) {
  339           ch = hex(*buf++) << 4;
  340           ch = ch + hex(*buf++);
  341           rv = set_char (mem++, ch);
  342           if (rv == -1)
  343             return NULL;
  344       }
  345       return(buf);
  346 }
  347 
  348 /* this function takes the 386 exception vector and attempts to
  349    translate this number into a unix compatible signal value */
  350 static int
  351 computeSignal (int exceptionVector)
  352 {
  353   int sigval;
  354   switch (exceptionVector & ~T_USER)
  355     {
  356     case 0: sigval = 8; break; /* divide by zero */
  357     case 1: sigval = 5; break; /* debug exception */
  358     case 3: sigval = 5; break; /* breakpoint */
  359     case 4: sigval = 16; break; /* into instruction (overflow) */
  360     case 5: sigval = 16; break; /* bound instruction */
  361     case 6: sigval = 4; break; /* Invalid opcode */
  362     case 7: sigval = 8; break; /* coprocessor not available */
  363     case 8: sigval = 7; break; /* double fault */
  364     case 9: sigval = 11; break; /* coprocessor segment overrun */
  365     case 10: sigval = 5; break; /* Invalid TSS (also single-step) */
  366     case 11: sigval = 11; break; /* Segment not present */
  367     case 12: sigval = 11; break; /* stack exception */
  368     case 13: sigval = 11; break; /* general protection */
  369     case 14: sigval = 11; break; /* page fault */
  370     case 16: sigval = 7; break; /* coprocessor error */
  371     default:
  372       sigval = 7;         /* "software generated"*/
  373     }
  374   return (sigval);
  375 }
  376 
  377 /*
  378  * While we find nice hex chars, build an int.
  379  * Return number of chars processed.
  380  */
  381 
  382 static int
  383 hexToInt(char **ptr, int *intValue)
  384 {
  385     int numChars = 0;
  386     int hexValue;
  387 
  388     *intValue = 0;
  389 
  390     while (**ptr)
  391     {
  392         hexValue = hex(**ptr);
  393         if (hexValue >=0)
  394         {
  395             *intValue = (*intValue <<4) | hexValue;
  396             numChars ++;
  397         }
  398         else
  399             break;
  400 
  401         (*ptr)++;
  402     }
  403 
  404     return (numChars);
  405 }
  406 
  407 #define NUMREGBYTES (sizeof registers)
  408 #define PC 8
  409 #define SP 4
  410 #define FP 5
  411 #define NUM_REGS 14
  412 
  413 /*
  414  * This function does all command procesing for interfacing to gdb.
  415  */
  416 int
  417 gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
  418 {
  419   int    sigval;
  420   int    addr, length;
  421   char * ptr;
  422   struct i386regs {
  423     unsigned int rax;
  424     unsigned int rcx;
  425     unsigned int rdx;
  426     unsigned int rbx;
  427     unsigned int rsp;
  428     unsigned int rbp;
  429     unsigned int rsi;
  430     unsigned int rdi;
  431     unsigned int rip;
  432     unsigned int rflags;
  433     unsigned int cs;
  434     unsigned int ss;
  435     unsigned int ds;
  436     unsigned int es;
  437   };
  438   struct i386regs registers;
  439 
  440   registers.rax = raw_regs->tf_rax;
  441   registers.rbx = raw_regs->tf_rbx;
  442   registers.rcx = raw_regs->tf_rcx;
  443   registers.rdx = raw_regs->tf_rdx;
  444 
  445   registers.rsp = raw_regs->tf_rsp;
  446   registers.rbp = raw_regs->tf_rbp;
  447   registers.rsi = raw_regs->tf_rsi;
  448   registers.rdi = raw_regs->tf_rdi;
  449 
  450   registers.rip = raw_regs->tf_rip;
  451   registers.rflags = raw_regs->tf_rflags;
  452 
  453   registers.cs = raw_regs->tf_cs;
  454   registers.ss = raw_regs->tf_ss;
  455   registers.ds = 0;     /* XXX rds() */
  456   registers.es = 0;     /* XXX res() */
  457 
  458   /* reply to host that an exception has occurred */
  459   sigval = computeSignal (type);
  460   ptr = remcomOutBuffer;
  461 
  462   *ptr++ = 'T';
  463   *ptr++ = hexchars[sigval >> 4];
  464   *ptr++ = hexchars[sigval & 0xf];
  465 
  466   *ptr++ = hexchars[PC >> 4];
  467   *ptr++ = hexchars[PC & 0xf];
  468   *ptr++ = ':';
  469   ptr = mem2hex ((vm_offset_t)&registers.rip, ptr, 4);
  470   *ptr++ = ';';
  471 
  472   *ptr++ = hexchars[FP >> 4];
  473   *ptr++ = hexchars[FP & 0xf];
  474   *ptr++ = ':';
  475   ptr = mem2hex ((vm_offset_t)&registers.rbp, ptr, 4);
  476   *ptr++ = ';';
  477 
  478   *ptr++ = hexchars[SP >> 4];
  479   *ptr++ = hexchars[SP & 0xf];
  480   *ptr++ = ':';
  481   ptr = mem2hex ((vm_offset_t)&registers.rsp, ptr, 4);
  482   *ptr++ = ';';
  483 
  484   *ptr++ = 0;
  485 
  486   putpacket (remcomOutBuffer);
  487 
  488   while (1)
  489     {
  490       if (gdb_arg == NULL)
  491         return 1;               /* somebody has removed the gdb device */
  492       remcomOutBuffer[0] = 0;
  493 
  494       getpacket (remcomInBuffer);
  495       switch (remcomInBuffer[0]) 
  496         {
  497         case '?':
  498           remcomOutBuffer[0] = 'S';
  499           remcomOutBuffer[1] = hexchars[sigval >> 4];
  500           remcomOutBuffer[2] = hexchars[sigval % 16];
  501           remcomOutBuffer[3] = 0;
  502           break;
  503 
  504         case 'D':               /* detach; say OK and turn off gdb */
  505           putpacket(remcomOutBuffer);
  506           boothowto &= ~RB_GDB;
  507           return 0;
  508 
  509         case 'g':               /* return the value of the CPU registers */
  510           mem2hex ((vm_offset_t)&registers, remcomOutBuffer, NUMREGBYTES);
  511           break;
  512 
  513         case 'G':               /* set the value of the CPU registers - return OK */
  514           hex2mem (&remcomInBuffer[1], (vm_offset_t)&registers, NUMREGBYTES);
  515           strcpy (remcomOutBuffer, "OK");
  516           break;
  517 
  518         case 'P':               /* Set the value of one register */
  519           {
  520             int regno;
  521 
  522             ptr = &remcomInBuffer[1];
  523 
  524             if (hexToInt (&ptr, &regno)
  525                 && *ptr++ == '='
  526                 && regno < NUM_REGS)
  527               {
  528                 hex2mem (ptr, (vm_offset_t)&registers + regno * 4, 4);
  529                 strcpy(remcomOutBuffer,"OK");
  530               }
  531             else
  532               strcpy (remcomOutBuffer, "P01");
  533             break;
  534           }
  535         case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
  536           /* Try to read %x,%x.  */
  537 
  538           ptr = &remcomInBuffer[1];
  539 
  540           if (hexToInt (&ptr, &addr)
  541               && *(ptr++) == ','
  542               && hexToInt (&ptr, &length))
  543             {
  544               if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL)
  545                 strcpy (remcomOutBuffer, "E03");
  546               break;
  547             }
  548           else
  549             strcpy (remcomOutBuffer, "E01");
  550           break;
  551 
  552         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
  553 
  554           /* Try to read '%x,%x:'.  */
  555 
  556           ptr = &remcomInBuffer[1];
  557 
  558           if (hexToInt(&ptr,&addr)
  559               && *(ptr++) == ','
  560               && hexToInt(&ptr, &length)
  561               && *(ptr++) == ':')
  562             {
  563               if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL)
  564                 strcpy (remcomOutBuffer, "E03");
  565               else
  566                 strcpy (remcomOutBuffer, "OK");
  567             }
  568           else
  569             strcpy (remcomOutBuffer, "E02");
  570           break;
  571 
  572           /* cAA..AA    Continue at address AA..AA(optional) */
  573           /* sAA..AA   Step one instruction from AA..AA(optional) */
  574         case 'c' :
  575         case 's' :
  576           /* try to read optional parameter, pc unchanged if no parm */
  577 
  578           ptr = &remcomInBuffer[1];
  579           if (hexToInt(&ptr,&addr))
  580             registers.rip = addr;
  581 
  582 
  583           /* set the trace bit if we're stepping */
  584           if (remcomInBuffer[0] == 's')
  585             registers.rflags |= PSL_T;
  586           else
  587             registers.rflags &= ~PSL_T;
  588 
  589           raw_regs->tf_rax = registers.rax;
  590           raw_regs->tf_rbx = registers.rbx;
  591           raw_regs->tf_rcx = registers.rcx;
  592           raw_regs->tf_rdx = registers.rdx;
  593 
  594           raw_regs->tf_rsp = registers.rsp;
  595           raw_regs->tf_rbp = registers.rbp;
  596           raw_regs->tf_rsi = registers.rsi;
  597           raw_regs->tf_rdi = registers.rdi;
  598 
  599           raw_regs->tf_rip = registers.rip;
  600           raw_regs->tf_rflags = registers.rflags;
  601 
  602           raw_regs->tf_cs = registers.cs;
  603           raw_regs->tf_ss = registers.ss;
  604 #if 0
  605           raw_regs->tf_ds = registers.ds;
  606           raw_regs->tf_es = registers.es;
  607 #endif
  608           return 0;
  609 
  610         } /* switch */
  611 
  612       /* reply to the request */
  613       putpacket (remcomOutBuffer);
  614     }
  615   return 0;
  616 }

Cache object: 39867afa2c4e0812816083c2c37d87c3


[ 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.