dma: add DragonFly compat files
[dragonfly.git] / sys / cpu / amd64 / misc / amd64-gdbstub.c
blobb4beae852e295a3fe5ee746e77e81cd97145e891
1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
30 * NOTES: See Below $
32 * Modified for FreeBSD by Stu Grossman.
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.
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.
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.
52 *************
54 * The following gdb commands are supported:
56 * command function Return value
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
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
64 * c Resume at current address SNN ( signal NN)
65 * cAA..AA Continue at address AA..AA SNN
67 * s Step one instruction SNN
68 * sAA..AA Step one instruction from AA..AA SNN
70 * k kill
72 * ? What was the last sigval ? SNN (signal NN)
74 * D detach OK
76 * All commands and responses are sent with a packet which includes a
77 * checksum. A packet consists of
79 * $<packet info>#<checksum>.
81 * where
82 * <packet info> :: <characters representing the command or response>
83 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
85 * When a packet is received, it is first acknowledged with either '+' or '-'.
86 * '+' indicates a successful transfer. '-' indicates a failed transfer.
88 * Example:
90 * Host: Reply:
91 * $m0,10#2a +$00010203040506070809101112131415#42
93 ****************************************************************************/
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 $
99 #include "opt_ddb.h"
101 #include <sys/param.h>
102 #include <sys/reboot.h>
103 #include <sys/systm.h>
104 #include <sys/cons.h>
106 #include <ddb/ddb.h>
108 #include <setjmp.h>
110 void gdb_handle_exception (db_regs_t *, int, int);
112 /************************************************************************/
114 extern jmp_buf db_jmpbuf;
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
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..) */
125 #define strlen gdb_strlen
126 #define strcpy gdb_strcpy
128 static int
129 strlen (const char *s)
131 const char *s1 = s;
133 while (*s1++ != '\000');
135 return s1 - s;
138 static char *
139 strcpy (char *dst, const char *src)
141 char *retval = dst;
143 while ((*dst++ = *src++) != '\000');
145 return retval;
148 static int
149 putDebugChar (int c) /* write a single character */
151 if (gdb_tab == NULL)
152 return 0;
153 gdb_tab->cn_putc(gdb_tab->cn_gdbprivate, c);
154 return 1;
157 static int
158 getDebugChar (void) /* read and return a single char */
160 if (gdb_tab == NULL)
161 return -1;
162 return gdb_tab->cn_getc(gdb_tab->cn_gdbprivate);
165 static const char hexchars[]="0123456789abcdef";
167 static int
168 hex(char ch)
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);
176 /* scan for the sequence $<data>#<checksum> */
177 static void
178 getpacket (char *buffer)
180 unsigned char checksum;
181 unsigned char xmitcsum;
182 int i;
183 int count;
184 unsigned char ch;
188 /* wait around for the start character, ignore all other characters */
190 while ((ch = (getDebugChar () & 0x7f)) != '$');
192 checksum = 0;
193 xmitcsum = -1;
195 count = 0;
197 /* now, read until a # or end of buffer is found */
199 while (count < BUFMAX)
201 ch = getDebugChar () & 0x7f;
202 if (ch == '#')
203 break;
204 checksum = checksum + ch;
205 buffer[count] = ch;
206 count = count + 1;
208 buffer[count] = 0;
210 if (ch == '#')
212 xmitcsum = hex (getDebugChar () & 0x7f) << 4;
213 xmitcsum += hex (getDebugChar () & 0x7f);
215 if (checksum != xmitcsum)
216 putDebugChar ('-'); /* failed checksum */
217 else
219 putDebugChar ('+'); /* successful transfer */
220 /* if a sequence char is present, reply the sequence ID */
221 if (buffer[2] == ':')
223 putDebugChar (buffer[0]);
224 putDebugChar (buffer[1]);
226 /* remove sequence chars from buffer */
228 count = strlen (buffer);
229 for (i=3; i <= count; i++)
230 buffer[i-3] = buffer[i];
235 while (checksum != xmitcsum);
238 /* send the packet in buffer. */
240 static void
241 putpacket (char *buffer)
243 unsigned char checksum;
244 int count;
245 unsigned char ch;
247 /* $<packet info>#<checksum>. */
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.
254 * This extension is not part of the Cygnus protocol, is kinda gross,
255 * but gets the job done.
257 #ifdef GDB_REMOTE_CHAT
258 putDebugChar ('|');
259 putDebugChar ('|');
260 putDebugChar ('|');
261 putDebugChar ('|');
262 #endif
263 putDebugChar ('$');
264 checksum = 0;
265 count = 0;
267 while ((ch=buffer[count]) != 0)
269 putDebugChar (ch);
270 checksum += ch;
271 count += 1;
274 putDebugChar ('#');
275 putDebugChar (hexchars[checksum >> 4]);
276 putDebugChar (hexchars[checksum & 0xf]);
278 while ((getDebugChar () & 0x7f) != '+');
281 static char remcomInBuffer[BUFMAX];
282 static char remcomOutBuffer[BUFMAX];
284 static int
285 get_char (vm_offset_t addr)
287 char data;
289 if (setjmp (db_jmpbuf))
290 return -1;
292 db_read_bytes (addr, 1, &data);
294 return data & 0xff;
297 static int
298 set_char (vm_offset_t addr, int val)
300 char data;
302 if (setjmp (db_jmpbuf))
303 return -1;
305 data = val;
307 db_write_bytes (addr, 1, &data);
308 return 0;
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) */
314 static char *
315 mem2hex (vm_offset_t mem, char *buf, int count)
317 int i;
318 int ch;
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];
327 *buf = 0;
328 return(buf);
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)
336 int i;
337 int ch;
338 int rv;
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;
347 return(buf);
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)
355 int sigval;
356 switch (exceptionVector & ~T_USER)
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"*/
376 return (sigval);
380 * While we find nice hex chars, build an int.
381 * Return number of chars processed.
384 static int
385 hexToInt(char **ptr, int *intValue)
387 int numChars = 0;
388 int hexValue;
390 *intValue = 0;
392 while (**ptr)
394 hexValue = hex(**ptr);
395 if (hexValue >=0)
397 *intValue = (*intValue <<4) | hexValue;
398 numChars ++;
400 else
401 break;
403 (*ptr)++;
406 return (numChars);
410 * While we find nice hex chars, build a long.
411 * Return number of chars processed.
414 static long
415 hexToLong(char **ptr, long *longValue)
417 int numChars = 0;
418 int hexValue;
420 *longValue = 0;
422 while (**ptr)
424 hexValue = hex(**ptr);
425 if (hexValue >=0)
427 *longValue = (*longValue <<4) | hexValue;
428 numChars ++;
430 else
431 break;
433 (*ptr)++;
436 return (numChars);
439 #define NUMREGBYTES (sizeof registers)
440 #define PC 16
441 #define SP 7
442 #define FP 6
443 #define NUM_REGS 22
446 * This function does all command procesing for interfacing to gdb.
448 void
449 gdb_handle_exception (db_regs_t *raw_regs, int type, int code)
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;
477 struct amd64regs registers;
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;
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;
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;
498 registers.rip = raw_regs->tf_rip;
499 registers.rflags = raw_regs->tf_rflags;
501 registers.cs = raw_regs->tf_cs;
502 registers.ss = raw_regs->tf_ss;
504 /* reply to host that an exception has occurred */
505 sigval = computeSignal (type);
506 ptr = remcomOutBuffer;
508 *ptr++ = 'T';
509 *ptr++ = hexchars[sigval >> 4];
510 *ptr++ = hexchars[sigval & 0xf];
512 *ptr++ = hexchars[PC >> 4];
513 *ptr++ = hexchars[PC & 0xf];
514 *ptr++ = ':';
515 ptr = mem2hex ((vm_offset_t)&registers.rip, ptr, 8);
516 *ptr++ = ';';
518 *ptr++ = hexchars[FP >> 4];
519 *ptr++ = hexchars[FP & 0xf];
520 *ptr++ = ':';
521 ptr = mem2hex ((vm_offset_t)&registers.rbp, ptr, 8);
522 *ptr++ = ';';
524 *ptr++ = hexchars[SP >> 4];
525 *ptr++ = hexchars[SP & 0xf];
526 *ptr++ = ':';
527 ptr = mem2hex ((vm_offset_t)&registers.rsp, ptr, 8);
528 *ptr++ = ';';
530 *ptr++ = 0;
532 putpacket (remcomOutBuffer);
534 while (1)
536 remcomOutBuffer[0] = 0;
538 getpacket (remcomInBuffer);
539 switch (remcomInBuffer[0])
541 case '?':
542 remcomOutBuffer[0] = 'S';
543 remcomOutBuffer[1] = hexchars[sigval >> 4];
544 remcomOutBuffer[2] = hexchars[sigval % 16];
545 remcomOutBuffer[3] = 0;
546 break;
548 case 'D': /* detach; say OK and turn off gdb */
549 putpacket(remcomOutBuffer);
550 boothowto &= ~RB_GDB;
551 return;
553 case 'g': /* return the value of the CPU registers */
554 mem2hex ((vm_offset_t)&registers, remcomOutBuffer, NUMREGBYTES);
555 break;
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;
562 case 'P': /* Set the value of one register */
564 int regno;
566 ptr = &remcomInBuffer[1];
568 if (hexToInt (&ptr, &regno)
569 && *ptr++ == '='
570 && regno < NUM_REGS)
572 /* JG */
573 hex2mem (ptr, (vm_offset_t)&registers + regno * 8, 8);
574 strcpy(remcomOutBuffer,"OK");
576 else
577 strcpy (remcomOutBuffer, "P01");
578 break;
580 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
581 /* Try to read %x,%x. */
583 ptr = &remcomInBuffer[1];
585 if (hexToLong (&ptr, &addr)
586 && *(ptr++) == ','
587 && hexToInt (&ptr, &length))
589 if (mem2hex((vm_offset_t) addr, remcomOutBuffer, length) == NULL)
590 strcpy (remcomOutBuffer, "E03");
591 break;
593 else
594 strcpy (remcomOutBuffer, "E01");
595 break;
597 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
599 /* Try to read '%x,%x:'. */
601 ptr = &remcomInBuffer[1];
603 if (hexToLong(&ptr,&addr)
604 && *(ptr++) == ','
605 && hexToInt(&ptr, &length)
606 && *(ptr++) == ':')
608 if (hex2mem(ptr, (vm_offset_t) addr, length) == NULL)
609 strcpy (remcomOutBuffer, "E03");
610 else
611 strcpy (remcomOutBuffer, "OK");
613 else
614 strcpy (remcomOutBuffer, "E02");
615 break;
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 */
623 ptr = &remcomInBuffer[1];
624 if (hexToLong(&ptr,&addr))
625 registers.rip = addr;
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;
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;
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;
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;
653 raw_regs->tf_rip = registers.rip;
654 raw_regs->tf_rflags = registers.rflags;
656 raw_regs->tf_cs = registers.cs;
657 raw_regs->tf_ss = registers.ss;
658 return;
660 } /* switch */
662 /* reply to the request */
663 putpacket (remcomOutBuffer);