xref: /dragonfly/sys/cpu/x86_64/misc/x86_64-gdbstub.c (revision e98bdfd3)
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 <machine/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 >= '0') && (ch <= '9')) return (ch-'0');
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 
666