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

Cache object: 4ede41a7c3dee5a50fd498b910144b6c


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