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