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
strlen(const char * s)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 *
strcpy(char * dst,const char * src)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
putDebugChar(int c)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
getDebugChar(void)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
hex(char ch)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
getpacket(char * buffer)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
putpacket(char * buffer)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
get_char(vm_offset_t addr)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
set_char(vm_offset_t addr,int val)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 *
mem2hex(vm_offset_t mem,char * buf,int count)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 *
hex2mem(char * buf,vm_offset_t mem,int count)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
computeSignal(int exceptionVector)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
hexToInt(char ** ptr,int * intValue)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
hexToLong(char ** ptr,long * longValue)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
gdb_handle_exception(db_regs_t * raw_regs,int type,int code)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)®isters.rip, ptr, 8);
515 *ptr++ = ';';
516
517 *ptr++ = hexchars[FP >> 4];
518 *ptr++ = hexchars[FP & 0xf];
519 *ptr++ = ':';
520 ptr = mem2hex ((vm_offset_t)®isters.rbp, ptr, 8);
521 *ptr++ = ';';
522
523 *ptr++ = hexchars[SP >> 4];
524 *ptr++ = hexchars[SP & 0xf];
525 *ptr++ = ':';
526 ptr = mem2hex ((vm_offset_t)®isters.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)®isters, remcomOutBuffer, NUMREGBYTES);
554 break;
555
556 case 'G': /* set the value of the CPU registers - return OK */
557 hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, 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, ®no)
568 && *ptr++ == '='
569 && regno < NUM_REGS)
570 {
571 /* JG */
572 hex2mem (ptr, (vm_offset_t)®isters + 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