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