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/i386/i386/i386-gdbstub.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 /****************************************************************************
    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 it's 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 it's 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 #include <sys/param.h>
   96 #include <sys/reboot.h>
   97 #include <sys/systm.h>
   98 
   99 #include <machine/cons.h>
  100 
  101 #include <ddb/ddb.h>
  102 
  103 #include <setjmp.h>
  104 
  105 #include "sio.h"
  106 
  107 #if NSIO == 0
  108 void
  109 gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
  110 {
  111 }
  112 #else
  113 /************************************************************************/
  114 
  115 void            gdb_handle_exception (db_regs_t *, int, int);
  116 
  117 extern jmp_buf  db_jmpbuf;
  118 
  119 /************************************************************************/
  120 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
  121 /* at least NUMREGBYTES*2 are needed for register packets */
  122 #define BUFMAX 400
  123 
  124 /* Create private copies of common functions used by the stub.  This prevents
  125    nasty interactions between app code and the stub (for instance if user steps
  126    into strlen, etc..) */
  127 /* XXX this is fairly bogus.  strlen() and strcpy() should be reentrant,
  128    and are reentrant under FreeBSD.  In any case, our versions should not
  129    be named the same as the standard versions, so that the address `strlen'
  130    is unambiguous...  */
  131 
  132 static int
  133 strlen (const char *s)
  134 {
  135   const char *s1 = s;
  136 
  137   while (*s1++ != '\000');
  138 
  139   return s1 - s;
  140 }
  141 
  142 static char *
  143 strcpy (char *dst, const char *src)
  144 {
  145   char *retval = dst;
  146 
  147   while ((*dst++ = *src++) != '\000');
  148 
  149   return retval;
  150 }
  151 
  152 /* XXX sio always uses its major with minor 0 no matter what we specify.  */
  153 #define REMOTE_DEV      0
  154 
  155 static int
  156 putDebugChar (int c)            /* write a single character      */
  157 {
  158   siocnputc (REMOTE_DEV, c);
  159   return 1;
  160 }
  161 
  162 static int
  163 getDebugChar (void)             /* read and return a single char */
  164 {
  165   return siocngetc (REMOTE_DEV);
  166 }
  167 
  168 static const char hexchars[]="0123456789abcdef";
  169 
  170 static int
  171 hex(char ch)
  172 {
  173   if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
  174   if ((ch >= '') && (ch <= '9')) return (ch-'');
  175   if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
  176   return (-1);
  177 }
  178 
  179 /* scan for the sequence $<data>#<checksum>     */
  180 static void
  181 getpacket (char *buffer)
  182 {
  183   unsigned char checksum;
  184   unsigned char xmitcsum;
  185   int i;
  186   int count;
  187   unsigned char ch;
  188 
  189   do
  190     {
  191       /* wait around for the start character, ignore all other characters */
  192 
  193       while ((ch = (getDebugChar () & 0x7f)) != '$');
  194 
  195       checksum = 0;
  196       xmitcsum = -1;
  197 
  198       count = 0;
  199 
  200       /* now, read until a # or end of buffer is found */
  201 
  202       while (count < BUFMAX)
  203         {
  204           ch = getDebugChar () & 0x7f;
  205           if (ch == '#')
  206             break;
  207           checksum = checksum + ch;
  208           buffer[count] = ch;
  209           count = count + 1;
  210         }
  211       buffer[count] = 0;
  212 
  213       if (ch == '#')
  214         {
  215           xmitcsum = hex (getDebugChar () & 0x7f) << 4;
  216           xmitcsum += hex (getDebugChar () & 0x7f);
  217 
  218           if (checksum != xmitcsum)
  219             putDebugChar ('-');  /* failed checksum */
  220           else
  221             {
  222               putDebugChar ('+'); /* successful transfer */
  223               /* if a sequence char is present, reply the sequence ID */
  224               if (buffer[2] == ':')
  225                 {
  226                   putDebugChar (buffer[0]);
  227                   putDebugChar (buffer[1]);
  228 
  229                   /* remove sequence chars from buffer */
  230 
  231                   count = strlen (buffer);
  232                   for (i=3; i <= count; i++)
  233                     buffer[i-3] = buffer[i];
  234                 }
  235             }
  236         }
  237     }
  238   while (checksum != xmitcsum);
  239 }
  240 
  241 /* send the packet in buffer.  */
  242 
  243 static void
  244 putpacket (char *buffer)
  245 {
  246   unsigned char checksum;
  247   int count;
  248   unsigned char ch;
  249 
  250   /*  $<packet info>#<checksum>. */
  251   do
  252     {
  253       putDebugChar ('$');
  254       checksum = 0;
  255       count = 0;
  256 
  257       while (ch=buffer[count])
  258         {
  259           putDebugChar (ch);
  260           checksum += ch;
  261           count += 1;
  262         }
  263 
  264       putDebugChar ('#');
  265       putDebugChar (hexchars[checksum >> 4]);
  266       putDebugChar (hexchars[checksum & 0xf]);
  267     }
  268   while ((getDebugChar () & 0x7f) != '+');
  269 }
  270 
  271 static char  remcomInBuffer[BUFMAX];
  272 static char  remcomOutBuffer[BUFMAX];
  273 
  274 static int
  275 get_char (vm_offset_t addr)
  276 {
  277   char data;
  278 
  279   if (setjmp (db_jmpbuf))
  280     return -1;
  281 
  282   db_read_bytes (addr, 1, &data);
  283 
  284   return data & 0xff;
  285 }
  286 
  287 static int
  288 set_char (vm_offset_t addr, int val)
  289 {
  290   char data;
  291 
  292   if (setjmp (db_jmpbuf))
  293     return -1;
  294 
  295   data = val;
  296 
  297   db_write_bytes (addr, 1, &data);
  298   return 0;
  299 }
  300 
  301 /* convert the memory pointed to by mem into hex, placing result in buf */
  302 /* return a pointer to the last char put in buf (null) */
  303 
  304 static char *
  305 mem2hex (vm_offset_t mem, char *buf, int count)
  306 {
  307       int i;
  308       int ch;
  309 
  310       for (i=0;i<count;i++) {
  311           ch = get_char (mem++);
  312           if (ch == -1)
  313             return NULL;
  314           *buf++ = hexchars[ch >> 4];
  315           *buf++ = hexchars[ch % 16];
  316       }
  317       *buf = 0;
  318       return(buf);
  319 }
  320 
  321 /* convert the hex array pointed to by buf into binary to be placed in mem */
  322 /* return a pointer to the character AFTER the last byte written */
  323 static char *
  324 hex2mem (char *buf, vm_offset_t mem, int count)
  325 {
  326       int i;
  327       int ch;
  328       int rv;
  329 
  330       for (i=0;i<count;i++) {
  331           ch = hex(*buf++) << 4;
  332           ch = ch + hex(*buf++);
  333           rv = set_char (mem++, ch);
  334           if (rv == -1)
  335             return NULL;
  336       }
  337       return(buf);
  338 }
  339 
  340 /* this function takes the 386 exception vector and attempts to
  341    translate this number into a unix compatible signal value */
  342 static int
  343 computeSignal (int exceptionVector)
  344 {
  345   int sigval;
  346   switch (exceptionVector & ~T_USER)
  347     {
  348     case 0: sigval = 8; break; /* divide by zero */
  349     case 1: sigval = 5; break; /* debug exception */
  350     case 3: sigval = 5; break; /* breakpoint */
  351     case 4: sigval = 16; break; /* into instruction (overflow) */
  352     case 5: sigval = 16; break; /* bound instruction */
  353     case 6: sigval = 4; break; /* Invalid opcode */
  354     case 7: sigval = 8; break; /* coprocessor not available */
  355     case 8: sigval = 7; break; /* double fault */
  356     case 9: sigval = 11; break; /* coprocessor segment overrun */
  357     case 10: sigval = 5; break; /* Invalid TSS (also single-step) */
  358     case 11: sigval = 11; break; /* Segment not present */
  359     case 12: sigval = 11; break; /* stack exception */
  360     case 13: sigval = 11; break; /* general protection */
  361     case 14: sigval = 11; break; /* page fault */
  362     case 16: sigval = 7; break; /* coprocessor error */
  363     default:
  364       sigval = 7;         /* "software generated"*/
  365     }
  366   return (sigval);
  367 }
  368 
  369 /*
  370  * While we find nice hex chars, build an int.
  371  * Return number of chars processed.
  372  */
  373 
  374 static int
  375 hexToInt(char **ptr, int *intValue)
  376 {
  377     int numChars = 0;
  378     int hexValue;
  379 
  380     *intValue = 0;
  381 
  382     while (**ptr)
  383     {
  384         hexValue = hex(**ptr);
  385         if (hexValue >=0)
  386         {
  387             *intValue = (*intValue <<4) | hexValue;
  388             numChars ++;
  389         }
  390         else
  391             break;
  392 
  393         (*ptr)++;
  394     }
  395 
  396     return (numChars);
  397 }
  398 
  399 #define NUMREGBYTES (sizeof registers)
  400 #define PC 8
  401 #define SP 4
  402 #define FP 5
  403 #define NUM_REGS 14
  404 
  405 /*
  406  * This function does all command procesing for interfacing to gdb.
  407  */
  408 void
  409 gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
  410 {
  411   int    sigval;
  412   int    addr, length;
  413   char * ptr;
  414   struct i386regs {
  415     unsigned int eax;
  416     unsigned int ecx;
  417     unsigned int edx;
  418     unsigned int ebx;
  419     unsigned int esp;
  420     unsigned int ebp;
  421     unsigned int esi;
  422     unsigned int edi;
  423     unsigned int eip;
  424     unsigned int eflags;
  425     unsigned int cs;
  426     unsigned int ss;
  427     unsigned int ds;
  428     unsigned int es;
  429   };
  430   struct i386regs registers;
  431 
  432   registers.eax = raw_regs->tf_eax;
  433   registers.ebx = raw_regs->tf_ebx;
  434   registers.ecx = raw_regs->tf_ecx;
  435   registers.edx = raw_regs->tf_edx;
  436 
  437   registers.esp = raw_regs->tf_esp;
  438   registers.ebp = raw_regs->tf_ebp;
  439   registers.esi = raw_regs->tf_esi;
  440   registers.edi = raw_regs->tf_edi;
  441 
  442   registers.eip = raw_regs->tf_eip;
  443   registers.eflags = raw_regs->tf_eflags;
  444 
  445   registers.cs = raw_regs->tf_cs;
  446   registers.ss = raw_regs->tf_ss;
  447   registers.ds = raw_regs->tf_ds;
  448   registers.es = raw_regs->tf_es;
  449 
  450   /* reply to host that an exception has occurred */
  451   sigval = computeSignal (type);
  452   ptr = remcomOutBuffer;
  453 
  454   *ptr++ = 'T';
  455   *ptr++ = hexchars[sigval >> 4];
  456   *ptr++ = hexchars[sigval & 0xf];
  457 
  458   *ptr++ = hexchars[PC >> 4];
  459   *ptr++ = hexchars[PC & 0xf];
  460   *ptr++ = ':';
  461   ptr = mem2hex ((vm_offset_t)&registers.eip, ptr, 4);
  462   *ptr++ = ';';
  463 
  464   *ptr++ = hexchars[FP >> 4];
  465   *ptr++ = hexchars[FP & 0xf];
  466   *ptr++ = ':';
  467   ptr = mem2hex ((vm_offset_t)&registers.ebp, ptr, 4);
  468   *ptr++ = ';';
  469 
  470   *ptr++ = hexchars[SP >> 4];
  471   *ptr++ = hexchars[SP & 0xf];
  472   *ptr++ = ':';
  473   ptr = mem2hex ((vm_offset_t)&registers.esp, ptr, 4);
  474   *ptr++ = ';';
  475 
  476   *ptr++ = 0;
  477 
  478   putpacket (remcomOutBuffer);
  479 
  480   while (1)
  481     {
  482       remcomOutBuffer[0] = 0;
  483 
  484       getpacket (remcomInBuffer);
  485       switch (remcomInBuffer[0]) 
  486         {
  487         case '?':
  488           remcomOutBuffer[0] = 'S';
  489           remcomOutBuffer[1] = hexchars[sigval >> 4];
  490           remcomOutBuffer[2] = hexchars[sigval % 16];
  491           remcomOutBuffer[3] = 0;
  492           break;
  493 
  494         case 'D':               /* detach; say OK and turn off gdb */
  495           putpacket(remcomOutBuffer);
  496           boothowto &= ~RB_GDB;
  497           return;
  498 
  499         case 'g':               /* return the value of the CPU registers */
  500           mem2hex ((vm_offset_t)&registers, remcomOutBuffer, NUMREGBYTES);
  501           break;
  502 
  503         case 'G':               /* set the value of the CPU registers - return OK */
  504           hex2mem (&remcomInBuffer[1], (vm_offset_t)&registers, NUMREGBYTES);
  505           strcpy (remcomOutBuffer, "OK");
  506           break;
  507 
  508         case 'P':               /* Set the value of one register */
  509           {
  510             int regno;
  511 
  512             ptr = &remcomInBuffer[1];
  513 
  514             if (hexToInt (&ptr, &regno)
  515                 && *ptr++ == '='
  516                 && regno < NUM_REGS)
  517               {
  518                 hex2mem (ptr, (vm_offset_t)&registers + regno * 4, 4);
  519                 strcpy(remcomOutBuffer,"OK");
  520               }
  521             else
  522               strcpy (remcomOutBuffer, "P01");
  523             break;
  524           }
  525         case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
  526           /* Try to read %x,%x.  */
  527 
  528           ptr = &remcomInBuffer[1];
  529 
  530           if (hexToInt (&ptr, &addr)
  531               && *(ptr++) == ','
  532               && hexToInt (&ptr, &length))
  533             {
  534               if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL)
  535                 strcpy (remcomOutBuffer, "E03");
  536               break;
  537             }
  538           else
  539             strcpy (remcomOutBuffer, "E01");
  540           break;
  541 
  542         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
  543 
  544           /* Try to read '%x,%x:'.  */
  545 
  546           ptr = &remcomInBuffer[1];
  547 
  548           if (hexToInt(&ptr,&addr)
  549               && *(ptr++) == ','
  550               && hexToInt(&ptr, &length)
  551               && *(ptr++) == ':')
  552             {
  553               if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL)
  554                 strcpy (remcomOutBuffer, "E03");
  555               else
  556                 strcpy (remcomOutBuffer, "OK");
  557             }
  558           else
  559             strcpy (remcomOutBuffer, "E02");
  560           break;
  561 
  562           /* cAA..AA    Continue at address AA..AA(optional) */
  563           /* sAA..AA   Step one instruction from AA..AA(optional) */
  564         case 'c' :
  565         case 's' :
  566           /* try to read optional parameter, pc unchanged if no parm */
  567 
  568           ptr = &remcomInBuffer[1];
  569           if (hexToInt(&ptr,&addr))
  570             registers.eip = addr;
  571 
  572 
  573           /* set the trace bit if we're stepping */
  574           if (remcomInBuffer[0] == 's')
  575             registers.eflags |= PSL_T;
  576           else
  577             registers.eflags &= ~PSL_T;
  578 
  579           raw_regs->tf_eax = registers.eax;
  580           raw_regs->tf_ebx = registers.ebx;
  581           raw_regs->tf_ecx = registers.ecx;
  582           raw_regs->tf_edx = registers.edx;
  583 
  584           raw_regs->tf_esp = registers.esp;
  585           raw_regs->tf_ebp = registers.ebp;
  586           raw_regs->tf_esi = registers.esi;
  587           raw_regs->tf_edi = registers.edi;
  588 
  589           raw_regs->tf_eip = registers.eip;
  590           raw_regs->tf_eflags = registers.eflags;
  591 
  592           raw_regs->tf_cs = registers.cs;
  593           raw_regs->tf_ss = registers.ss;
  594           raw_regs->tf_ds = registers.ds;
  595           raw_regs->tf_es = registers.es;
  596           return;
  597 
  598         } /* switch */
  599 
  600       /* reply to the request */
  601       putpacket (remcomOutBuffer);
  602     }
  603 }
  604 #endif /* NSIO > 0 */

Cache object: 358a90552636c8a1c485f52ed0344603


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