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

Cache object: 1ab7d27b442617bca1e945b1087e25a6


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