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

Cache object: c7c2a30c4e7ade3fb68b0685191f1b83


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