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 it's 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 386 by Jim Kingdon, Cygnus Support.
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  *
47  *	Because gdb will sometimes write to the stack area to execute function
48  *	calls, this program cannot rely on using the supervisor stack so it
49  *	uses it's own stack area reserved in the int array remcomStack.
50  *
51  *************
52  *
53  *	  The following gdb commands are supported:
54  *
55  * command			function							   Return value
56  *
57  *	  g 			return the value of the CPU registers  hex data or ENN
58  *	  G 			set the value of the CPU registers	   OK or ENN
59  *
60  *	  mAA..AA,LLLL	Read LLLL bytes at address AA..AA	   hex data or ENN
61  *	  MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
62  *
63  *	  c 			Resume at current address			   SNN	 ( signal NN)
64  *	  cAA..AA		Continue at address AA..AA			   SNN
65  *
66  *	  s 			Step one instruction				   SNN
67  *	  sAA..AA		Step one instruction from AA..AA	   SNN
68  *
69  *	  k 			kill
70  *
71  *	  ? 			What was the last sigval ?			   SNN	 (signal NN)
72  *
73  * All commands and responses are sent with a packet which includes a
74  * checksum.  A packet consists of
75  *
76  * $<packet info>#<checksum>.
77  *
78  * where
79  * <packet info> :: <characters representing the command or response>
80  * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
81  *
82  * When a packet is received, it is first acknowledged with either '+' or '-'.
83  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
84  *
85  * Example:
86  *
87  * Host:				  Reply:
88  * $m0,10#2a			   +$00010203040506070809101112131415#42
89  *
90  ****************************************************************************/
91 
92 #include <stdio.h>
93 #include <string.h>
94 
95 #include "utility/utility.h"	// for strcpy_s()
96 
97 /************************************************************************
98  *
99  * external low-level support routines
100  */
101 
102 extern void putDebugChar(); 	/* write a single character 	 */
103 extern int getDebugChar();		/* read and return a single char */
104 extern void exceptionHandler(); /* assign an exception handler	 */
105 
106 /************************************************************************/
107 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
108 /* at least NUMREGBYTES*2 are needed for register packets */
109 #define BUFMAX 400
110 
111 static char initialized;  /* boolean flag. != 0 means we've been initialized */
112 
113 int 	remote_debug;
114 /*	debug >  0 prints ill-formed commands in valid packets & checksum errors */
115 
116 static const char hexchars[]="0123456789abcdef";
117 
118 /* Number of registers.  */
119 #define NUMREGS 16
120 
121 /* Number of bytes of registers.  */
122 #define NUMREGBYTES (NUMREGS * 4)
123 
124 enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
125 			   PC /* also known as eip */,
126 			   PS /* also known as eflags */,
127 			   CS, SS, DS, ES, FS, GS};
128 
129 /*
130  * these should not be static cuz they can be used outside this module
131  */
132 int registers[NUMREGS];
133 
134 #ifndef WIN32 //MF
135 
136 #define STACKSIZE 10000
137 int remcomStack[STACKSIZE/sizeof(int)];
138 static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
139 
140 /***************************  ASSEMBLY CODE MACROS *************************/
141 /*																		   */
142 
143 extern void
144 return_to_prog ();
145 
146 /* Restore the program's registers (including the stack pointer, which
147    means we get the right stack and don't have to worry about popping our
148    return address and any stack frames and so on) and return.  */
149 asm(".text");
150 asm(".globl _return_to_prog");
151 asm("_return_to_prog:");
152 asm("        movw _registers+44, %ss");
153 asm("        movl _registers+16, %esp");
154 asm("        movl _registers+4, %ecx");
155 asm("        movl _registers+8, %edx");
156 asm("        movl _registers+12, %ebx");
157 asm("        movl _registers+20, %ebp");
158 asm("        movl _registers+24, %esi");
159 asm("        movl _registers+28, %edi");
160 asm("        movw _registers+48, %ds");
161 asm("        movw _registers+52, %es");
162 asm("        movw _registers+56, %fs");
163 asm("        movw _registers+60, %gs");
164 asm("        movl _registers+36, %eax");
165 asm("        pushl %eax");	/* saved eflags */
166 asm("        movl _registers+40, %eax");
167 asm("        pushl %eax");	/* saved cs */
168 asm("        movl _registers+32, %eax");
169 asm("        pushl %eax");	/* saved eip */
170 asm("        movl _registers, %eax");
171 
172 asm("ret"); 	//MF
173 
174 /* use iret to restore pc and flags together so
175    that trace flag works right.  */
176 asm("        iret");
177 
178 
179 #ifdef WIN32 //MF
180 asm(".data"); //MF
181 #endif
182 
183 /* Put the error code here just in case the user cares.  */
184 int gdb_i386errcode;
185 /* Likewise, the vector number here (since GDB only gets the signal
186    number through the usual means, and that's not very specific).  */
187 int gdb_i386vector = -1;
188 
189 /* GDB stores segment registers in 32-bit words (that's just the way
190    m-i386v.h is written).  So zero the appropriate areas in registers.	*/
191 #define SAVE_REGISTERS1() \
192   asm ("movl %eax, _registers");										  \
193   asm ("movl %ecx, _registers+4");											 \
194   asm ("movl %edx, _registers+8");											 \
195   asm ("movl %ebx, _registers+12"); 										 \
196   asm ("movl %ebp, _registers+20"); 										 \
197   asm ("movl %esi, _registers+24"); 										 \
198   asm ("movl %edi, _registers+28"); 										 \
199   asm ("movw $0, %ax"); 													 \
200   asm ("movw %ds, _registers+48");											 \
201   asm ("movw %ax, _registers+50");											 \
202   asm ("movw %es, _registers+52");											 \
203   asm ("movw %ax, _registers+54");											 \
204   asm ("movw %fs, _registers+56");											 \
205   asm ("movw %ax, _registers+58");											 \
206   asm ("movw %gs, _registers+60");											 \
207   asm ("movw %ax, _registers+62");
208 #define SAVE_ERRCODE() \
209   asm ("popl %ebx");								  \
210   asm ("movl %ebx, _gdb_i386errcode");
211 #define SAVE_REGISTERS2() \
212   asm ("popl %ebx"); /* old eip */											 \
213   asm ("movl %ebx, _registers+32"); 										 \
214   asm ("popl %ebx");	 /* old cs */										 \
215   asm ("movl %ebx, _registers+40"); 										 \
216   asm ("movw %ax, _registers+42");											 \
217   asm ("popl %ebx");	 /* old eflags */									 \
218   asm ("movl %ebx, _registers+36"); 										 \
219   /* Now that we've done the pops, we can save the stack pointer.");  */   \
220   asm ("movw %ss, _registers+44");											 \
221   asm ("movw %ax, _registers+46");											 \
222   asm ("movl %esp, _registers+16");
223 
224 /* See if mem_fault_routine is set, if so just IRET to that address.  */
225 #define CHECK_FAULT() \
226   asm ("cmpl $0, _mem_fault_routine");									   \
227   asm ("jne mem_fault");
228 
229 asm (".text");
230 asm ("mem_fault:");
231 /* OK to clobber temp registers; we're just going to end up in set_mem_err.  */
232 /* Pop error code from the stack and save it.  */
233 asm ("     popl %eax");
234 asm ("     movl %eax, _gdb_i386errcode");
235 
236 asm ("     popl %eax"); /* eip */
237 /* We don't want to return there, we want to return to the function
238    pointed to by mem_fault_routine instead.  */
239 asm ("     movl _mem_fault_routine, %eax");
240 asm ("     popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits).  */
241 asm ("     popl %edx"); /* eflags */
242 
243 /* Remove this stack frame; when we do the iret, we will be going to
244    the start of a function, so we want the stack to look just like it
245    would after a "call" instruction.  */
246 asm ("     leave");
247 
248 /* Push the stuff that iret wants.	*/
249 asm ("     pushl %edx"); /* eflags */
250 asm ("     pushl %ecx"); /* cs */
251 asm ("     pushl %eax"); /* eip */
252 
253 /* Zero mem_fault_routine.	*/
254 asm ("     movl $0, %eax");
255 asm ("     movl %eax, _mem_fault_routine");
256 
257 asm ("iret");
258 
259 
260 #define CALL_HOOK() asm("call _remcomHandler");
261 
262 /* This function is called when a i386 exception occurs.  It saves
263  * all the cpu regs in the _registers array, munges the stack a bit,
264  * and invokes an exception handler (remcom_handler).
265  *
266  * stack on entry:						 stack on exit:
267  *	 old eflags 						 vector number
268  *	 old cs (zero-filled to 32 bits)
269  *	 old eip
270  *
271  */
272 extern void _catchException3();
273 asm(".text");
274 asm(".globl __catchException3");
275 asm("__catchException3:");
276 SAVE_REGISTERS1();
277 SAVE_REGISTERS2();
278 asm ("pushl $3");
279 CALL_HOOK();
280 
281 /* Same thing for exception 1.	*/
282 extern void _catchException1();
283 asm(".text");
284 asm(".globl __catchException1");
285 asm("__catchException1:");
286 SAVE_REGISTERS1();
287 SAVE_REGISTERS2();
288 asm ("pushl $1");
289 CALL_HOOK();
290 
291 /* Same thing for exception 0.	*/
292 extern void _catchException0();
293 asm(".text");
294 asm(".globl __catchException0");
295 asm("__catchException0:");
296 SAVE_REGISTERS1();
297 SAVE_REGISTERS2();
298 asm ("pushl $0");
299 CALL_HOOK();
300 
301 /* Same thing for exception 4.	*/
302 extern void _catchException4();
303 asm(".text");
304 asm(".globl __catchException4");
305 asm("__catchException4:");
306 SAVE_REGISTERS1();
307 SAVE_REGISTERS2();
308 asm ("pushl $4");
309 CALL_HOOK();
310 
311 /* Same thing for exception 5.	*/
312 extern void _catchException5();
313 asm(".text");
314 asm(".globl __catchException5");
315 asm("__catchException5:");
316 SAVE_REGISTERS1();
317 SAVE_REGISTERS2();
318 asm ("pushl $5");
319 CALL_HOOK();
320 
321 /* Same thing for exception 6.	*/
322 extern void _catchException6();
323 asm(".text");
324 asm(".globl __catchException6");
325 asm("__catchException6:");
326 SAVE_REGISTERS1();
327 SAVE_REGISTERS2();
328 asm ("pushl $6");
329 CALL_HOOK();
330 
331 /* Same thing for exception 7.	*/
332 extern void _catchException7();
333 asm(".text");
334 asm(".globl __catchException7");
335 asm("__catchException7:");
336 SAVE_REGISTERS1();
337 SAVE_REGISTERS2();
338 asm ("pushl $7");
339 CALL_HOOK();
340 
341 /* Same thing for exception 8.	*/
342 extern void _catchException8();
343 asm(".text");
344 asm(".globl __catchException8");
345 asm("__catchException8:");
346 SAVE_REGISTERS1();
347 SAVE_ERRCODE();
348 SAVE_REGISTERS2();
349 asm ("pushl $8");
350 CALL_HOOK();
351 
352 /* Same thing for exception 9.	*/
353 extern void _catchException9();
354 asm(".text");
355 asm(".globl __catchException9");
356 asm("__catchException9:");
357 SAVE_REGISTERS1();
358 SAVE_REGISTERS2();
359 asm ("pushl $9");
360 CALL_HOOK();
361 
362 /* Same thing for exception 10.  */
363 extern void _catchException10();
364 asm(".text");
365 asm(".globl __catchException10");
366 asm("__catchException10:");
367 SAVE_REGISTERS1();
368 SAVE_ERRCODE();
369 SAVE_REGISTERS2();
370 asm ("pushl $10");
371 CALL_HOOK();
372 
373 /* Same thing for exception 12.  */
374 extern void _catchException12();
375 asm(".text");
376 asm(".globl __catchException12");
377 asm("__catchException12:");
378 SAVE_REGISTERS1();
379 SAVE_ERRCODE();
380 SAVE_REGISTERS2();
381 asm ("pushl $12");
382 CALL_HOOK();
383 
384 /* Same thing for exception 16.  */
385 extern void _catchException16();
386 asm(".text");
387 asm(".globl __catchException16");
388 asm("__catchException16:");
389 SAVE_REGISTERS1();
390 SAVE_REGISTERS2();
391 asm ("pushl $16");
392 CALL_HOOK();
393 
394 /* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff.  */
395 
396 /* Same thing for exception 13.  */
397 extern void _catchException13 ();
398 asm (".text");
399 asm (".globl __catchException13");
400 asm ("__catchException13:");
401 CHECK_FAULT();
402 SAVE_REGISTERS1();
403 SAVE_ERRCODE();
404 SAVE_REGISTERS2();
405 asm ("pushl $13");
406 CALL_HOOK();
407 
408 /* Same thing for exception 11.  */
409 extern void _catchException11 ();
410 asm (".text");
411 asm (".globl __catchException11");
412 asm ("__catchException11:");
413 CHECK_FAULT();
414 SAVE_REGISTERS1();
415 SAVE_ERRCODE();
416 SAVE_REGISTERS2();
417 asm ("pushl $11");
418 CALL_HOOK();
419 
420 /* Same thing for exception 14.  */
421 extern void _catchException14 ();
422 asm (".text");
423 asm (".globl __catchException14");
424 asm ("__catchException14:");
425 CHECK_FAULT();
426 SAVE_REGISTERS1();
427 SAVE_ERRCODE();
428 SAVE_REGISTERS2();
429 asm ("pushl $14");
430 CALL_HOOK();
431 
432 /*
433  * remcomHandler is a front end for handle_exception.  It moves the
434  * stack pointer into an area reserved for debugger use.
435  */
436 asm("_remcomHandler:");
437 asm("           popl %eax");		/* pop off return address	  */
438 asm("           popl %eax");	  /* get the exception number	*/
439 asm("		movl _stackPtr, %esp"); /* move to remcom stack area  */
440 asm("		pushl %eax");	 /* push exception onto stack  */
441 asm("		call  _handle_exception");	  /* this never returns */
442 
443 
444 void
_returnFromException()445 _returnFromException ()
446 {
447   return_to_prog ();
448 }
449 
450 #endif	// !WIN32
451 
452 
453 #ifdef _MSC_VER //MF
454 #define BREAKPOINT() __asm int 3;
455 #else
456 #define BREAKPOINT() asm("   int $3");
457 #endif
458 
459 
460 #ifdef WIN32 //MF
461 
462 #define WIN32_LEAN_AND_MEAN
463 //#include <windows.h>
464 
465 void handle_exception(int exceptionVector);
466 
win32_exception_handler(EXCEPTION_POINTERS * exc_info)467 void win32_exception_handler(EXCEPTION_POINTERS* exc_info)
468 {
469   PCONTEXT ctx = exc_info->ContextRecord;
470 
471   registers[EAX] = ctx->Eax;
472   registers[ECX] = ctx->Ecx;
473   registers[EDX] = ctx->Edx;
474   registers[EBX] = ctx->Ebx;
475   registers[ESP] = ctx->Esp;
476   registers[EBP] = ctx->Ebp;
477   registers[ESI] = ctx->Esi;
478   registers[EDI] = ctx->Edi;
479    registers[PC] = ctx->Eip;
480    registers[PS] = ctx->EFlags;
481   registers[CS] = ctx->SegCs;
482   registers[SS] = ctx->SegSs;
483   registers[DS] = ctx->SegDs;
484   registers[ES] = ctx->SegEs;
485   registers[FS] = ctx->SegFs;
486   registers[GS] = ctx->SegGs;
487 
488   handle_exception(exc_info->ExceptionRecord->ExceptionCode & 0xFFFF);
489 
490   ctx->Eax = registers[EAX];
491   ctx->Ecx = registers[ECX];
492   ctx->Edx = registers[EDX];
493   ctx->Ebx = registers[EBX];
494   ctx->Esp = registers[ESP];
495   ctx->Ebp = registers[EBP];
496   ctx->Esi = registers[ESI];
497   ctx->Edi = registers[EDI];
498    ctx->Eip = registers[PC];
499    ctx->EFlags = registers[PS];
500   ctx->SegCs = registers[CS];
501   ctx->SegSs = registers[SS];
502   ctx->SegDs = registers[DS];
503   ctx->SegEs = registers[ES];
504   ctx->SegFs = registers[FS];
505   ctx->SegGs = registers[GS];
506 }
507 
508 #endif // WIN32
509 
510 
511 int
hex(ch)512 hex (ch)
513 	 char ch;
514 {
515   if ((ch >= 'a') && (ch <= 'f'))
516 	return (ch - 'a' + 10);
517   if ((ch >= '0') && (ch <= '9'))
518 	return (ch - '0');
519   if ((ch >= 'A') && (ch <= 'F'))
520 	return (ch - 'A' + 10);
521   return (-1);
522 }
523 
524 static char remcomInBuffer[BUFMAX];
525 static char remcomOutBuffer[BUFMAX];
526 
527 /* scan for the sequence $<data>#<checksum> 	*/
528 
529 char *
getpacket(void)530 getpacket (void)
531 {
532   char *buffer = &remcomInBuffer[0];
533   unsigned char checksum;
534   unsigned char xmitcsum;
535   int count;
536   char ch;
537 
538   while (1)
539 	{
540 	  /* wait around for the start character, ignore all other characters */
541 	  while ((ch = getDebugChar ()) != '$')
542 		;
543 
544 	retry:
545 	  checksum = 0;
546 	  xmitcsum = -1;
547 	  count = 0;
548 
549 	  /* now, read until a # or end of buffer is found */
550 	  while (count < BUFMAX - 1)
551 		{
552 		  ch = getDebugChar ();
553 		  if (ch == '$')
554 			goto retry;
555 		  if (ch == '#')
556 			break;
557 		  checksum = checksum + ch;
558 		  buffer[count] = ch;
559 		  count = count + 1;
560 		}
561 	  buffer[count] = 0;
562 
563 	  if (ch == '#')
564 		{
565 		  ch = getDebugChar ();
566 		  xmitcsum = hex (ch) << 4;
567 		  ch = getDebugChar ();
568 		  xmitcsum += hex (ch);
569 
570 		  if (checksum != xmitcsum)
571 			{
572 			  if (remote_debug)
573 				{
574 				  fprintf (stderr,
575 						   "bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
576 						   checksum, xmitcsum, buffer);
577 				}
578 			  putDebugChar ('-');		/* failed checksum */
579 			}
580 		  else
581 			{
582 			  putDebugChar ('+');		/* successful transfer */
583 
584 			  /* if a sequence char is present, reply the sequence ID */
585 			  if (buffer[2] == ':')
586 				{
587 				  putDebugChar (buffer[0]);
588 				  putDebugChar (buffer[1]);
589 
590 				  return &buffer[3];
591 				}
592 
593 			  return &buffer[0];
594 			}
595 		}
596 	}
597 }
598 
599 /* send the packet in buffer.  */
600 
601 void
putpacket(char * buffer)602 putpacket (char *buffer)
603 {
604   unsigned char checksum;
605   int count;
606   char ch;
607 
608   /*  $<packet info>#<checksum>. */
609   do
610 	{
611 	  putDebugChar ('$');
612 	  checksum = 0;
613 	  count = 0;
614 
615 	  while ((ch = buffer[count]) != 0)
616 		{
617 		  putDebugChar (ch);
618 		  checksum += ch;
619 		  count += 1;
620 		}
621 
622 	  putDebugChar ('#');
623 	  putDebugChar (hexchars[checksum >> 4]);
624 	  putDebugChar (hexchars[checksum % 16]);
625 
626 	}
627   while (getDebugChar () != '+');
628 }
629 
debug_error(char * format)630 void debug_error (char* format/*, char* parm*/)
631 {
632   if (remote_debug)
633     fprintf (stderr, format/*, parm*/);
634 }
635 
636 /* Address of a routine to RTE to if we get a memory fault.  */
637 static void (*volatile mem_fault_routine) () = NULL;
638 
639 /* Indicate to caller of mem2hex or hex2mem that there has been an
640    error.  */
641 static volatile int mem_err = 0;
642 
643 void
set_mem_err(void)644 set_mem_err (void)
645 {
646   mem_err = 1;
647 }
648 
649 /* These are separate functions so that they are so short and sweet
650    that the compiler won't save any registers (if there is a fault
651    to mem_fault, they won't get restored, so there better not be any
652    saved).	*/
653 int
get_char(char * addr)654 get_char (char *addr)
655 {
656   return *addr;
657 }
658 
659 void
set_char(char * addr,int val)660 set_char (char *addr, int val)
661 {
662   *addr = val;
663 }
664 
665 /* convert the memory pointed to by mem into hex, placing result in buf */
666 /* return a pointer to the last char put in buf (null) */
667 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
668    a fault; if zero treat a fault like any other fault in the stub.  */
669 char *
mem2hex(mem,buf,count,may_fault)670 mem2hex (mem, buf, count, may_fault)
671 	 char *mem;
672 	 char *buf;
673 	 int count;
674 	 int may_fault;
675 {
676   int i;
677   unsigned char ch;
678 
679 #ifdef WIN32 //MF
680   if (IsBadReadPtr(mem, count))
681 	return mem;
682 #else
683   if (may_fault)
684 	mem_fault_routine = set_mem_err;
685 #endif
686   for (i = 0; i < count; i++)
687 	{
688 	  ch = get_char (mem++);
689 	  if (may_fault && mem_err)
690 		return (buf);
691 	  *buf++ = hexchars[ch >> 4];
692 	  *buf++ = hexchars[ch % 16];
693 	}
694   *buf = 0;
695 #ifndef WIN32 //MF
696   if (may_fault)
697 	mem_fault_routine = NULL;
698 #endif
699   return (buf);
700 }
701 
702 /* convert the hex array pointed to by buf into binary to be placed in mem */
703 /* return a pointer to the character AFTER the last byte written */
704 char *
hex2mem(buf,mem,count,may_fault)705 hex2mem (buf, mem, count, may_fault)
706 	 char *buf;
707 	 char *mem;
708 	 int count;
709 	 int may_fault;
710 {
711   int i;
712   unsigned char ch;
713 
714 #ifdef WIN32 //MF
715    // MinGW does not support structured exception handling, so let's
716    // go safe and make memory writable by default
717   DWORD old_protect;
718 
719   VirtualProtect(mem, count, PAGE_EXECUTE_READWRITE, &old_protect);
720 #else
721   if (may_fault)
722 	mem_fault_routine = set_mem_err;
723 #endif
724 
725   for (i = 0; i < count; i++)
726 	{
727 	  ch = hex (*buf++) << 4;
728 	  ch = ch + hex (*buf++);
729 	  set_char (mem++, ch);
730 	  if (may_fault && mem_err)
731 		return (mem);
732 	}
733 
734 #ifndef WIN32 //MF
735   if (may_fault)
736 	mem_fault_routine = NULL;
737 #endif
738 
739   return (mem);
740 }
741 
742 /* this function takes the 386 exception vector and attempts to
743    translate this number into a unix compatible signal value */
744 int
computeSignal(int exceptionVector)745 computeSignal (int exceptionVector)
746 {
747   int sigval;
748   switch (exceptionVector)
749 	{
750 	case 0:
751 	  sigval = 8;
752 	  break;					/* divide by zero */
753 	case 1:
754 	  sigval = 5;
755 	  break;					/* debug exception */
756 	case 3:
757 	  sigval = 5;
758 	  break;					/* breakpoint */
759 	case 4:
760 	  sigval = 16;
761 	  break;					/* into instruction (overflow) */
762 	case 5:
763 	  sigval = 16;
764 	  break;					/* bound instruction */
765 	case 6:
766 	  sigval = 4;
767 	  break;					/* Invalid opcode */
768 	case 7:
769 	  sigval = 8;
770 	  break;					/* coprocessor not available */
771 	case 8:
772 	  sigval = 7;
773 	  break;					/* double fault */
774 	case 9:
775 	  sigval = 11;
776 	  break;					/* coprocessor segment overrun */
777 	case 10:
778 	  sigval = 11;
779 	  break;					/* Invalid TSS */
780 	case 11:
781 	  sigval = 11;
782 	  break;					/* Segment not present */
783 	case 12:
784 	  sigval = 11;
785 	  break;					/* stack exception */
786 	case 13:
787 	  sigval = 11;
788 	  break;					/* general protection */
789 	case 14:
790 	  sigval = 11;
791 	  break;					/* page fault */
792 	case 16:
793 	  sigval = 7;
794 	  break;					/* coprocessor error */
795 	default:
796 	  sigval = 7;				/* "software generated" */
797 	}
798   return (sigval);
799 }
800 
801 /**********************************************/
802 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
803 /* RETURN NUMBER OF CHARS PROCESSED 		  */
804 /**********************************************/
805 int
hexToInt(char ** ptr,int * intValue)806 hexToInt (char **ptr, int *intValue)
807 {
808   int numChars = 0;
809   int hexValue;
810 
811   *intValue = 0;
812 
813   while (**ptr)
814 	{
815 	  hexValue = hex (**ptr);
816 	  if (hexValue >= 0)
817 		{
818 		  *intValue = (*intValue << 4) | hexValue;
819 		  numChars++;
820 		}
821 	  else
822 		break;
823 
824 	  (*ptr)++;
825 	}
826 
827   return (numChars);
828 }
829 
830 /*
831  * This function does all command procesing for interfacing to gdb.
832  */
833 void
handle_exception(int exceptionVector)834 handle_exception (int exceptionVector)
835 {
836   int sigval, stepping;
837   int addr, length;
838   char *ptr;
839 
840 #ifndef WIN32 //MF
841   gdb_i386vector = exceptionVector;
842 #endif
843 
844   if (remote_debug)
845 	{
846 	  printf ("vector=%d, sr=0x%x, pc=0x%x\n",
847 			  exceptionVector, registers[PS], registers[PC]);
848 	}
849 
850   /* reply to host that an exception has occurred */
851   sigval = computeSignal (exceptionVector);
852 
853   ptr = remcomOutBuffer;
854 
855   *ptr++ = 'T'; 				/* notify gdb with signo, PC, FP and SP */
856   *ptr++ = hexchars[sigval >> 4];
857   *ptr++ = hexchars[sigval & 0xf];
858 
859   *ptr++ = hexchars[ESP];
860   *ptr++ = ':';
861   ptr = mem2hex((char *)&registers[ESP], ptr, 4, 0);	/* SP */
862   *ptr++ = ';';
863 
864   *ptr++ = hexchars[EBP];
865   *ptr++ = ':';
866   ptr = mem2hex((char *)&registers[EBP], ptr, 4, 0);	/* FP */
867   *ptr++ = ';';
868 
869   *ptr++ = hexchars[PC];
870   *ptr++ = ':';
871   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0); 	/* PC */
872   *ptr++ = ';';
873 
874   *ptr = '\0';
875 
876   putpacket (remcomOutBuffer);
877 
878   stepping = 0;
879 
880   while (1 == 1)
881 	{
882 	  remcomOutBuffer[0] = 0;
883 	  ptr = getpacket ();
884 
885 	  switch (*ptr++)
886 		{
887 		case '?':
888 		  remcomOutBuffer[0] = 'S';
889 		  remcomOutBuffer[1] = hexchars[sigval >> 4];
890 		  remcomOutBuffer[2] = hexchars[sigval % 16];
891 		  remcomOutBuffer[3] = 0;
892 		  break;
893 		case 'd':
894 		  remote_debug = !(remote_debug);		/* toggle debug flag */
895 		  break;
896 		case 'g':				/* return the value of the CPU registers */
897 		  mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0);
898 		  break;
899 		case 'G':				/* set the value of the CPU registers - return OK */
900 		  hex2mem (ptr, (char *) registers, NUMREGBYTES, 0);
901 		  strcpy_s(remcomOutBuffer, BUFMAX, "OK");
902 		  break;
903 		case 'P':				/* set the value of a single CPU register - return OK */
904 		  {
905 			int regno;
906 
907 			if (hexToInt (&ptr, &regno) && *ptr++ == '=')
908 			  if (regno >= 0 && regno < NUMREGS)
909 				{
910 				  hex2mem (ptr, (char *) &registers[regno], 4, 0);
911 				  strcpy_s(remcomOutBuffer, BUFMAX, "OK");
912 				  break;
913 				}
914 
915 			strcpy_s(remcomOutBuffer, BUFMAX, "E01");
916 			break;
917 		  }
918 
919 		  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
920 		case 'm':
921 		  /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
922 		  if (hexToInt (&ptr, &addr))
923 			if (*(ptr++) == ',')
924 			  if (hexToInt (&ptr, &length))
925 				{
926 				  ptr = 0;
927 				  mem_err = 0;
928 				  mem2hex ((char *) addr, remcomOutBuffer, length, 1);
929 				  if (mem_err)
930 					{
931 					  strcpy_s(remcomOutBuffer, BUFMAX, "E03");
932 					  debug_error ("memory fault");
933 					}
934 				}
935 
936 		  if (ptr)
937 			{
938 			  strcpy_s(remcomOutBuffer, BUFMAX, "E01");
939 			}
940 		  break;
941 
942 		  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
943 		case 'M':
944 		  /* TRY TO READ '%x,%x:'.	IF SUCCEED, SET PTR = 0 */
945 		  if (hexToInt (&ptr, &addr))
946 			if (*(ptr++) == ',')
947 			  if (hexToInt (&ptr, &length))
948 				if (*(ptr++) == ':')
949 				  {
950 					mem_err = 0;
951 					hex2mem (ptr, (char *) addr, length, 1);
952 
953 					if (mem_err)
954 					  {
955 						strcpy_s(remcomOutBuffer, BUFMAX, "E03");
956 						debug_error ("memory fault");
957 					  }
958 					else
959 					  {
960 						strcpy_s(remcomOutBuffer, BUFMAX, "OK");
961 					  }
962 
963 					ptr = 0;
964 				  }
965 		  if (ptr)
966 			{
967 			  strcpy_s(remcomOutBuffer, BUFMAX, "E02");
968 			}
969 		  break;
970 
971 		  /* cAA..AA	Continue at address AA..AA(optional) */
972 		  /* sAA..AA   Step one instruction from AA..AA(optional) */
973 		case 's':
974 		  stepping = 1;
975 		case 'c':
976 		  /* try to read optional parameter, pc unchanged if no parm */
977 		  if (hexToInt (&ptr, &addr))
978 			registers[PC] = addr;
979 
980 		  /* clear the trace bit */
981 		  registers[PS] &= 0xfffffeff;
982 
983 		  /* set the trace bit if we're stepping */
984 		  if (stepping)
985 			registers[PS] |= 0x100;
986 
987 #ifdef WIN32 //MF
988 		  return;
989 #else
990 		  _returnFromException ();		/* this is a jump */
991 #endif
992 		  break;
993 
994 		  /* kill the program */
995 		case 'k':				/* do nothing */
996 #if 0
997 		  /* Huh? This doesn't look like "nothing".
998 			 m68k-stub.c and sparc-stub.c don't have it.  */
999 		  BREAKPOINT ();
1000 #endif
1001 		  break;
1002 		}						/* switch */
1003 
1004 	  /* reply to the request */
1005 	  putpacket (remcomOutBuffer);
1006 	}
1007 }
1008 
1009 /* this function is used to set up exception handlers for tracing and
1010    breakpoints */
1011 void
set_debug_traps(void)1012 set_debug_traps (void)
1013 {
1014 #ifndef WIN32 //MF
1015   stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
1016 
1017   exceptionHandler (0, _catchException0);
1018   exceptionHandler (1, _catchException1);
1019   exceptionHandler (3, _catchException3);
1020   exceptionHandler (4, _catchException4);
1021   exceptionHandler (5, _catchException5);
1022   exceptionHandler (6, _catchException6);
1023   exceptionHandler (7, _catchException7);
1024   exceptionHandler (8, _catchException8);
1025   exceptionHandler (9, _catchException9);
1026   exceptionHandler (10, _catchException10);
1027   exceptionHandler (11, _catchException11);
1028   exceptionHandler (12, _catchException12);
1029   exceptionHandler (13, _catchException13);
1030   exceptionHandler (14, _catchException14);
1031   exceptionHandler (16, _catchException16);
1032 #endif // WIN32
1033 
1034   initialized = 1;
1035 }
1036 
1037 /* This function will generate a breakpoint exception.	It is used at the
1038    beginning of a program to sync up with a debugger and can be used
1039    otherwise as a quick means to stop program execution and "break" into
1040    the debugger. */
1041 
1042 void
breakpoint(void)1043 breakpoint (void)
1044 {
1045   if (initialized)
1046 	BREAKPOINT ();
1047 }
1048 
1049 
1050 
1051  //
1052  // debugger stub implementation for WIN32 applications
1053  // M. Fuchs, 29.11.2003
1054  //
1055 
1056 #ifdef WIN32
1057 
1058 #include <stdlib.h>
1059 #include <errno.h>
1060 
1061 #include "utility/utility.h"
1062 
1063 
1064 int s_initial_breakpoint = 0;
1065 
1066 
1067 #ifdef DEBUG_SERIAL
1068 
1069 FILE* ser_port = NULL;
1070 
init_gdb_connect()1071 int init_gdb_connect()
1072 {
1073 		 //TODO: set up connection using serial communication port
1074 
1075 		ser_port = fopen("COM1:", "rwb");
1076 
1077 		return 1;
1078 }
1079 
getDebugChar()1080 int getDebugChar()
1081 {
1082 		return fgetc(ser_port);
1083 }
1084 
putDebugChar(int c)1085 void putDebugChar(int c)
1086 {
1087 		fputc(c, ser_port);
1088 }
1089 
1090 
1091 #else // DEBUG_SERIAL
1092 
1093 
1094 static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler = 0;
1095 
1096 
1097 #define I386_EXCEPTION_CNT		17
1098 
exc_protection_handler(EXCEPTION_POINTERS * exc_info)1099 LONG WINAPI exc_protection_handler(EXCEPTION_POINTERS* exc_info)
1100 {
1101 		int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF;
1102 
1103 		if (exc_nr < I386_EXCEPTION_CNT) {
1104 				//LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr));
1105 
1106 				if (exc_nr==11 || exc_nr==13 || exc_nr==14) {
1107 						if (mem_fault_routine)
1108 								mem_fault_routine();
1109 				}
1110 
1111 				++exc_info->ContextRecord->Eip;
1112 		}
1113 
1114 		return EXCEPTION_CONTINUE_EXECUTION;
1115 }
1116 
exc_handler(EXCEPTION_POINTERS * exc_info)1117 LONG WINAPI exc_handler(EXCEPTION_POINTERS* exc_info)
1118 {
1119 		int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF;
1120 
1121 		if (exc_nr < I386_EXCEPTION_CNT) {
1122 				//LOG(FmtString("Exception %x", exc_nr));
1123 				//LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1124 
1125 				 // step over initial breakpoint
1126 				if (s_initial_breakpoint) {
1127 						s_initial_breakpoint = 0;
1128 						++exc_info->ContextRecord->Eip;
1129 				}
1130 
1131 				SetUnhandledExceptionFilter(exc_protection_handler);
1132 
1133 				win32_exception_handler(exc_info);
1134 				//LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags));
1135 
1136 				SetUnhandledExceptionFilter(exc_handler);
1137 
1138 				return EXCEPTION_CONTINUE_EXECUTION;
1139 		}
1140 
1141 		return EXCEPTION_CONTINUE_SEARCH;
1142 }
1143 
1144 /* not needed because we use win32_exception_handler() instead of catchExceptionX()
1145 void exceptionHandler(int exc_nr, void* exc_addr)
1146 {
1147 		if (exc_nr>=0 && exc_nr<I386_EXCEPTION_CNT)
1148 				exc_handlers[exc_nr] = exc_addr;
1149 }
1150 */
1151 
disable_debugging()1152 void disable_debugging()
1153 {
1154 		if (s_prev_exc_handler) {
1155 				SetUnhandledExceptionFilter(s_prev_exc_handler);
1156 				s_prev_exc_handler = 0;
1157 		}
1158 }
1159 
1160 #define _INC_WINDOWS
1161 #include <winsock.h>
1162 #ifdef _MSC_VER
1163 #pragma comment(lib, "wsock32")
1164 #endif
1165 
1166 static int s_rem_fd = -1;
1167 
init_gdb_connect()1168 int init_gdb_connect()
1169 {
1170 		SOCKADDR_IN srv_addr = {0};
1171 		SOCKADDR_IN rem_addr;
1172 		WSADATA wsa_data;
1173 		int srv_socket, rem_len;
1174 
1175 		s_prev_exc_handler = SetUnhandledExceptionFilter(exc_handler);
1176 
1177 		if (WSAStartup(MAKEWORD(2,2), &wsa_data)) {
1178 				fprintf(stderr, "WSAStartup() failed");
1179 				return 0;
1180 		}
1181 
1182 		srv_addr.sin_family = AF_INET;
1183 		srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1184 		srv_addr.sin_port = htons(9999);
1185 
1186 		srv_socket = socket(PF_INET, SOCK_STREAM, 0);
1187 		if (srv_socket == -1) {
1188 				perror("socket()");
1189 				return 0;
1190 		}
1191 
1192 		if (bind(srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) {
1193 				perror("bind()");
1194 				return 0;
1195 		}
1196 
1197 		if (listen(srv_socket, 4) == -1) {
1198 				perror("listen()");
1199 				return 0;
1200 		}
1201 
1202 		rem_len = sizeof(rem_addr);
1203 
1204 		for(;;) {
1205 				s_rem_fd = accept(srv_socket, (struct sockaddr*)&rem_addr, &rem_len);
1206 
1207 				if (s_rem_fd < 0) {
1208 						if (errno == EINTR)
1209 								continue;
1210 
1211 						perror("accept()");
1212 						return 0;
1213 				}
1214 
1215 				break;
1216 		}
1217 
1218 		return 1;
1219 }
1220 
1221 #endif // DEBUG_SERIAL
1222 
1223 
getDebugChar()1224 int getDebugChar()
1225 {
1226 		char buffer[1024];
1227 		int r;
1228 
1229 		if (s_rem_fd == -1)
1230 				return EOF;
1231 
1232 		r = recv(s_rem_fd, buffer, 1, 0);
1233 		if (r == -1) {
1234 				perror("recv()");
1235 				LOG(TEXT("debugger connection broken"));
1236 				s_rem_fd = -1;
1237 				return EOF;
1238 		}
1239 
1240 		if (!r)
1241 				return EOF;
1242 
1243 		return buffer[0];
1244 }
1245 
putDebugChar(int c)1246 void putDebugChar(int c)
1247 {
1248 		if (s_rem_fd != -1) {
1249 				const char buffer[] = {c};
1250 
1251 				if (!send(s_rem_fd, buffer, 1, 0)) {
1252 						perror("send()");
1253 						LOG(TEXT("debugger connection broken"));
1254 						exit(-1);
1255 				}
1256 		}
1257 }
1258 
1259 
1260  // start up GDB stub interface
1261 
initialize_gdb_stub()1262 int initialize_gdb_stub()
1263 {
1264 		if (!init_gdb_connect())
1265 				return 0;
1266 
1267 		set_debug_traps();
1268 
1269 		s_initial_breakpoint = 1;
1270 		breakpoint();
1271 
1272 		return 1;
1273 }
1274 
1275 #endif // WIN32
1276