xref: /openbsd/gnu/usr.bin/binutils/gdb/nlm/gdbserve.c (revision 7b36286a)
1 /* gdbserve.c -- NLM debugging stub for Novell NetWare.
2 
3    This is originally based on an m68k software stub written by Glenn
4    Engel at HP, but has changed quite a bit.  It was modified for the
5    i386 by Jim Kingdon, Cygnus Support.  It was modified to run under
6    NetWare by Ian Lance Taylor, Cygnus Support.
7 
8    This code is intended to produce an NLM (a NetWare Loadable Module)
9    to run under Novell NetWare.  To create the NLM, compile this code
10    into an object file using the NLM SDK on any i386 host, and use the
11    nlmconv program (available in the GNU binutils) to transform the
12    resulting object file into an NLM.  */
13 
14 /****************************************************************************
15 
16 		THIS SOFTWARE IS NOT COPYRIGHTED
17 
18    HP offers the following for use in the public domain.  HP makes no
19    warranty with regard to the software or it's performance and the
20    user accepts the software "AS IS" with all faults.
21 
22    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
23    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 
26 ****************************************************************************/
27 
28 /****************************************************************************
29  *
30  *    The following gdb commands are supported:
31  *
32  * command          function                               Return value
33  *
34  *    g             return the value of the CPU registers  hex data or ENN
35  *    G             set the value of the CPU registers     OK or ENN
36  *
37  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
38  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
39  *
40  *    c             Resume at current address              SNN   ( signal NN)
41  *    cAA..AA       Continue at address AA..AA             SNN
42  *
43  *    s             Step one instruction                   SNN
44  *    sAA..AA       Step one instruction from AA..AA       SNN
45  *
46  *    k             kill
47  *
48  *    ?             What was the last sigval ?             SNN   (signal NN)
49  *
50  * All commands and responses are sent with a packet which includes a
51  * checksum.  A packet consists of
52  *
53  * $<packet info>#<checksum>.
54  *
55  * where
56  * <packet info> :: <characters representing the command or response>
57  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
58  *
59  * When a packet is received, it is first acknowledged with either '+' or '-'.
60  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
61  *
62  * Example:
63  *
64  * Host:                  Reply:
65  * $m0,10#2a               +$00010203040506070809101112131415#42
66  *
67  ****************************************************************************/
68 
69 #include <stdio.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <ctype.h>
73 #include <errno.h>
74 #include <time.h>
75 
76 #ifdef __i386__
77 #include <dfs.h>
78 #include <conio.h>
79 #include <advanced.h>
80 #include <debugapi.h>
81 #include <process.h>
82 #else
83 #include <nwtypes.h>
84 #include <nwdfs.h>
85 #include <nwconio.h>
86 #include <nwadv.h>
87 #include <nwdbgapi.h>
88 #include <nwthread.h>
89 #endif
90 
91 #include <aio.h>
92 #include "cpu.h"
93 
94 
95 /****************************************************/
96 /* This information is from Novell.  It is not in any of the standard
97    NetWare header files.  */
98 
99 struct DBG_LoadDefinitionStructure
100 {
101 	void *reserved1[4];
102 	LONG reserved5;
103 	LONG LDCodeImageOffset;
104 	LONG LDCodeImageLength;
105 	LONG LDDataImageOffset;
106 	LONG LDDataImageLength;
107 	LONG LDUninitializedDataLength;
108 	LONG LDCustomDataOffset;
109 	LONG LDCustomDataSize;
110 	LONG reserved6[2];
111 	LONG (*LDInitializationProcedure)(void);
112 };
113 
114 #define LO_NORMAL		0x0000
115 #define LO_STARTUP		0x0001
116 #define LO_PROTECT		0x0002
117 #define LO_DEBUG		0x0004
118 #define LO_AUTO_LOAD  		0x0008
119 
120 /* Loader returned error codes */
121 #define LOAD_COULD_NOT_FIND_FILE		1
122 #define LOAD_ERROR_READING_FILE			2
123 #define LOAD_NOT_NLM_FILE_FORMAT		3
124 #define LOAD_WRONG_NLM_FILE_VERSION		4
125 #define LOAD_REENTRANT_INITIALIZE_FAILURE	5
126 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES	6
127 #define LOAD_ALREADY_IN_PROGRESS		7
128 #define LOAD_NOT_ENOUGH_MEMORY			8
129 #define LOAD_INITIALIZE_FAILURE			9
130 #define LOAD_INCONSISTENT_FILE_FORMAT		10
131 #define LOAD_CAN_NOT_LOAD_AT_STARTUP		11
132 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED	12
133 #define LOAD_UNRESOLVED_EXTERNAL		13
134 #define LOAD_PUBLIC_ALREADY_DEFINED		14
135 /****************************************************/
136 
137 /* The main thread ID.  */
138 static int mainthread;
139 
140 /* An error message for the main thread to print.  */
141 static char *error_message;
142 
143 /* The AIO port handle.  */
144 static int AIOhandle;
145 
146 /* BUFMAX defines the maximum number of characters in inbound/outbound
147    buffers.  At least NUMREGBYTES*2 are needed for register packets */
148 #define BUFMAX (REGISTER_BYTES * 2 + 16)
149 
150 /* remote_debug > 0 prints ill-formed commands in valid packets and
151    checksum errors. */
152 static int remote_debug = 1;
153 
154 static const char hexchars[] = "0123456789abcdef";
155 
156 unsigned char breakpoint_insn[] = BREAKPOINT;
157 
158 char *mem2hex (void *mem, char *buf, int count, int may_fault);
159 char *hex2mem (char *buf, void *mem, int count, int may_fault);
160 extern void set_step_traps (struct StackFrame *);
161 extern void clear_step_traps (struct StackFrame *);
162 
163 static int __main() {};
164 
165 /* Read a character from the serial port.  This must busy wait, but
166    that's OK because we will be the only thread running anyhow.  */
167 
168 static int
169 getDebugChar (void)
170 {
171   int err;
172   LONG got;
173   unsigned char ret;
174 
175   do
176     {
177       err = AIOReadData (AIOhandle, (char *) &ret, 1, &got);
178       if (err != 0)
179 	{
180 	  error_message = "AIOReadData failed";
181 	  ResumeThread (mainthread);
182 	  return -1;
183 	}
184     }
185   while (got == 0);
186 
187   return ret;
188 }
189 
190 /* Write a character to the serial port.  Returns 0 on failure,
191    non-zero on success.  */
192 
193 static int
194 putDebugChar (unsigned char c)
195 {
196   int err;
197   LONG put;
198 
199   put = 0;
200   while (put < 1)
201     {
202       err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
203       if (err != 0)
204 	ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
205     }
206   return 1;
207 }
208 
209 /* Turn a hex character into a number.  */
210 
211 static int
212 hex (char ch)
213 {
214   if ((ch >= 'a') && (ch <= 'f'))
215     return (ch-'a'+10);
216   if ((ch >= '0') && (ch <= '9'))
217     return (ch-'0');
218   if ((ch >= 'A') && (ch <= 'F'))
219     return (ch-'A'+10);
220   return (-1);
221 }
222 
223 /* Scan for the sequence $<data>#<checksum>.  Returns 0 on failure,
224    non-zero on success.  */
225 
226 static int
227 getpacket (char *buffer)
228 {
229   unsigned char checksum;
230   unsigned char xmitcsum;
231   int i;
232   int count;
233   int ch;
234 
235   do
236     {
237       /* wait around for the start character, ignore all other characters */
238       while ((ch = getDebugChar()) != '$')
239 	if (ch == -1)
240 	  return 0;
241       checksum = 0;
242       xmitcsum = -1;
243 
244       count = 0;
245 
246       /* now, read until a # or end of buffer is found */
247       while (count < BUFMAX)
248 	{
249 	  ch = getDebugChar();
250 	  if (ch == -1)
251 	    return 0;
252 	  if (ch == '#')
253 	    break;
254 	  checksum = checksum + ch;
255 	  buffer[count] = ch;
256 	  count = count + 1;
257 	}
258       buffer[count] = 0;
259 
260       if (ch == '#')
261 	{
262 	  ch = getDebugChar ();
263 	  if (ch == -1)
264 	    return 0;
265 	  xmitcsum = hex(ch) << 4;
266 	  ch = getDebugChar ();
267 	  if (ch == -1)
268 	    return 0;
269 	  xmitcsum += hex(ch);
270 
271 	  if (checksum != xmitcsum)
272 	    {
273 	      if (remote_debug)
274 		ConsolePrintf ("bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
275 			       checksum,xmitcsum,buffer);
276 	      /* failed checksum */
277 	      if (! putDebugChar('-'))
278 		return 0;
279 	      return 1;
280 	    }
281 	  else
282 	    {
283 	      /* successful transfer */
284 	      if (! putDebugChar('+'))
285 		return 0;
286 	      /* if a sequence char is present, reply the sequence ID */
287 	      if (buffer[2] == ':')
288 		{
289 		  if (! putDebugChar (buffer[0])
290 		      || ! putDebugChar (buffer[1]))
291 		    return 0;
292 		  /* remove sequence chars from buffer */
293 		  count = strlen(buffer);
294 		  for (i=3; i <= count; i++)
295 		    buffer[i-3] = buffer[i];
296 		}
297 	    }
298 	}
299     }
300   while (checksum != xmitcsum);
301 
302   if (remote_debug)
303     ConsolePrintf ("Received packet \"%s\"\r\n", buffer);
304 
305   return 1;
306 }
307 
308 /* Send the packet in buffer.  Returns 0 on failure, non-zero on
309    success.  */
310 
311 static int
312 putpacket (char *buffer)
313 {
314   unsigned char checksum;
315   int count;
316   int ch;
317 
318   if (remote_debug)
319     ConsolePrintf ("Sending packet \"%s\"\r\n", buffer);
320 
321   /*  $<packet info>#<checksum>. */
322   do
323     {
324       if (! putDebugChar('$'))
325 	return 0;
326       checksum = 0;
327       count = 0;
328 
329       while (ch=buffer[count])
330 	{
331 	  if (! putDebugChar(ch))
332 	    return 0;
333 	  checksum += ch;
334 	  count += 1;
335 	}
336 
337       if (! putDebugChar('#')
338 	  || ! putDebugChar(hexchars[checksum >> 4])
339 	  || ! putDebugChar(hexchars[checksum % 16]))
340 	return 0;
341 
342       ch = getDebugChar ();
343       if (ch == -1)
344 	return 0;
345     }
346   while (ch != '+');
347 
348   return 1;
349 }
350 
351 static char remcomInBuffer[BUFMAX];
352 static char remcomOutBuffer[BUFMAX];
353 static short error;
354 
355 static void
356 debug_error (char *format, char *parm)
357 {
358   if (remote_debug)
359     {
360       ConsolePrintf (format, parm);
361       ConsolePrintf ("\n");
362     }
363 }
364 
365 /* This is set if we could get a memory access fault.  */
366 static int mem_may_fault;
367 
368 /* Indicate to caller of mem2hex or hex2mem that there has been an
369    error.  */
370 volatile int mem_err = 0;
371 
372 #ifndef ALTERNATE_MEM_FUNCS
373 /* These are separate functions so that they are so short and sweet
374    that the compiler won't save any registers (if there is a fault
375    to mem_fault, they won't get restored, so there better not be any
376    saved).  */
377 
378 int
379 get_char (char *addr)
380 {
381   return *addr;
382 }
383 
384 void
385 set_char (char *addr, int val)
386 {
387   *addr = val;
388 }
389 #endif /* ALTERNATE_MEM_FUNCS */
390 
391 /* convert the memory pointed to by mem into hex, placing result in buf */
392 /* return a pointer to the last char put in buf (null) */
393 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
394    a fault; if zero treat a fault like any other fault in the stub.  */
395 
396 char *
397 mem2hex (void *mem, char *buf, int count, int may_fault)
398 {
399   int i;
400   unsigned char ch;
401   char *ptr = mem;
402 
403   mem_may_fault = may_fault;
404   for (i = 0; i < count; i++)
405     {
406       ch = get_char (ptr++);
407       if (may_fault && mem_err)
408 	return (buf);
409       *buf++ = hexchars[ch >> 4];
410       *buf++ = hexchars[ch % 16];
411     }
412   *buf = 0;
413   mem_may_fault = 0;
414   return(buf);
415 }
416 
417 /* convert the hex array pointed to by buf into binary to be placed in mem */
418 /* return a pointer to the character AFTER the last byte written */
419 
420 char *
421 hex2mem (char *buf, void *mem, int count, int may_fault)
422 {
423   int i;
424   unsigned char ch;
425   char *ptr = mem;
426 
427   mem_may_fault = may_fault;
428   for (i=0;i<count;i++)
429     {
430       ch = hex(*buf++) << 4;
431       ch = ch + hex(*buf++);
432       set_char (ptr++, ch);
433       if (may_fault && mem_err)
434 	return (ptr);
435     }
436   mem_may_fault = 0;
437   return(mem);
438 }
439 
440 /* This function takes the 386 exception vector and attempts to
441    translate this number into a unix compatible signal value.  */
442 
443 int
444 computeSignal (int exceptionVector)
445 {
446   int sigval;
447   switch (exceptionVector)
448     {
449     case 0 : sigval = 8; break; /* divide by zero */
450     case 1 : sigval = 5; break; /* debug exception */
451     case 3 : sigval = 5; break; /* breakpoint */
452     case 4 : sigval = 16; break; /* into instruction (overflow) */
453     case 5 : sigval = 16; break; /* bound instruction */
454     case 6 : sigval = 4; break; /* Invalid opcode */
455     case 7 : sigval = 8; break; /* coprocessor not available */
456     case 8 : sigval = 7; break; /* double fault */
457     case 9 : sigval = 11; break; /* coprocessor segment overrun */
458     case 10 : sigval = 11; break; /* Invalid TSS */
459     case 11 : sigval = 11; break; /* Segment not present */
460     case 12 : sigval = 11; break; /* stack exception */
461     case 13 : sigval = 11; break; /* general protection */
462     case 14 : sigval = 11; break; /* page fault */
463     case 16 : sigval = 7; break; /* coprocessor error */
464     default:
465       sigval = 7;		/* "software generated"*/
466     }
467   return (sigval);
468 }
469 
470 /**********************************************/
471 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
472 /* RETURN NUMBER OF CHARS PROCESSED           */
473 /**********************************************/
474 static int
475 hexToInt (char **ptr, int *intValue)
476 {
477   int numChars = 0;
478   int hexValue;
479 
480   *intValue = 0;
481 
482   while (**ptr)
483     {
484       hexValue = hex(**ptr);
485       if (hexValue >=0)
486 	{
487 	  *intValue = (*intValue <<4) | hexValue;
488 	  numChars ++;
489 	}
490       else
491 	break;
492 
493       (*ptr)++;
494     }
495 
496   return (numChars);
497 }
498 
499 /* This function does all command processing for interfacing to gdb.
500    It is called whenever an exception occurs in the module being
501    debugged.  */
502 
503 static LONG
504 handle_exception (struct StackFrame *frame)
505 {
506   int addr, length;
507   char *ptr;
508   static struct DBG_LoadDefinitionStructure *ldinfo = 0;
509   static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program.  */
510 
511 #if 0
512   /* According to some documentation from Novell, the bell sometimes
513      may be ringing at this point.  This can be stopped on Netware 4
514      systems by calling the undocumented StopBell() function. */
515 
516   StopBell ();
517 #endif
518 
519   if (remote_debug)
520     {
521       ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
522 		     frame->ExceptionNumber,
523 		     frame->ExceptionDescription,
524 		     frame->ExceptionPC,
525 		     GetThreadID ());
526     }
527 
528   switch (frame->ExceptionNumber)
529     {
530     case START_NLM_EVENT:
531       /* If the NLM just started, we record the module load information
532 	 and the thread ID, and set a breakpoint at the first instruction
533 	 in the program.  */
534 
535       ldinfo = ((struct DBG_LoadDefinitionStructure *)
536 		frame->ExceptionErrorCode);
537       memcpy (first_insn, ldinfo->LDInitializationProcedure,
538 	      BREAKPOINT_SIZE);
539       memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
540 	      BREAKPOINT_SIZE);
541       flush_i_cache ();
542       return RETURN_TO_PROGRAM;
543 
544     case ENTER_DEBUGGER_EVENT:
545     case KEYBOARD_BREAK_EVENT:
546       /* Pass some events on to the next debugger, in case it will handle
547 	 them.  */
548       return RETURN_TO_NEXT_DEBUGGER;
549 
550     case 3:			/* Breakpoint */
551       /* After we've reached the initial breakpoint, reset it.  */
552       if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
553 	  && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
554 		     BREAKPOINT_SIZE) == 0)
555 	{
556 	  memcpy (ldinfo->LDInitializationProcedure, first_insn,
557 		  BREAKPOINT_SIZE);
558 	  frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
559 	  flush_i_cache ();
560 	}
561       /* Normal breakpoints end up here */
562       do_status (remcomOutBuffer, frame);
563       break;
564 
565     default:
566       /* At the moment, we don't care about most of the unusual NetWare
567 	 exceptions.  */
568       if (frame->ExceptionNumber > 31)
569 	return RETURN_TO_PROGRAM;
570 
571       /* Most machine level exceptions end up here */
572       do_status (remcomOutBuffer, frame);
573       break;
574 
575     case 11:			/* Segment not present */
576     case 13:			/* General protection */
577     case 14:			/* Page fault */
578       /* If we get a GP fault, and mem_may_fault is set, and the
579 	 instruction pointer is near set_char or get_char, then we caused
580 	 the fault ourselves accessing an illegal memory location.  */
581       if (mem_may_fault
582 	  && ((frame->ExceptionPC >= (long) &set_char
583 	       && frame->ExceptionPC < (long) &set_char + 50)
584 	      || (frame->ExceptionPC >= (long) &get_char
585 		  && frame->ExceptionPC < (long) &get_char + 50)))
586 	{
587 	  mem_err = 1;
588 	  /* Point the instruction pointer at an assembly language stub
589 	     which just returns from the function.  */
590 
591 	  frame->ExceptionPC += 4; /* Skip the load or store */
592 
593 	  /* Keep going.  This will act as though it returned from
594 	     set_char or get_char.  The calling routine will check
595 	     mem_err, and do the right thing.  */
596 	  return RETURN_TO_PROGRAM;
597 	}
598       /* Random mem fault, report it */
599       do_status (remcomOutBuffer, frame);
600       break;
601 
602     case TERMINATE_NLM_EVENT:
603       /* There is no way to get the exit status.  */
604       sprintf (remcomOutBuffer, "W%02x", 0);
605       break;			/* We generate our own status */
606     }
607 
608   /* FIXME: How do we know that this exception has anything to do with
609      the program we are debugging?  We can check whether the PC is in
610      the range of the module we are debugging, but that doesn't help
611      much since an error could occur in a library routine.  */
612 
613   clear_step_traps (frame);
614 
615   if (! putpacket(remcomOutBuffer))
616     return RETURN_TO_NEXT_DEBUGGER;
617 
618   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
619     {
620       ResumeThread (mainthread);
621       return RETURN_TO_PROGRAM;
622     }
623 
624   while (1)
625     {
626       error = 0;
627       remcomOutBuffer[0] = 0;
628       if (! getpacket (remcomInBuffer))
629 	return RETURN_TO_NEXT_DEBUGGER;
630       switch (remcomInBuffer[0])
631 	{
632 	case '?':
633 	  do_status (remcomOutBuffer, frame);
634 	  break;
635 	case 'd':
636 	  remote_debug = !(remote_debug); /* toggle debug flag */
637 	  break;
638 	case 'g':
639 	  /* return the value of the CPU registers */
640 	  frame_to_registers (frame, remcomOutBuffer);
641 	  break;
642 	case 'G':
643 	  /* set the value of the CPU registers - return OK */
644 	  registers_to_frame (&remcomInBuffer[1], frame);
645 	  strcpy(remcomOutBuffer,"OK");
646 	  break;
647 
648 	case 'm':
649 	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
650 	  /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
651 	  ptr = &remcomInBuffer[1];
652 	  if (hexToInt(&ptr,&addr))
653 	    if (*(ptr++) == ',')
654 	      if (hexToInt(&ptr,&length))
655 		{
656 		  ptr = 0;
657 		  mem_err = 0;
658 		  mem2hex((char*) addr, remcomOutBuffer, length, 1);
659 		  if (mem_err)
660 		    {
661 		      strcpy (remcomOutBuffer, "E03");
662 		      debug_error ("memory fault");
663 		    }
664 		}
665 
666 	  if (ptr)
667 	    {
668 	      strcpy(remcomOutBuffer,"E01");
669 	      debug_error("malformed read memory command: %s",remcomInBuffer);
670 	    }
671 	  break;
672 
673 	case 'M':
674 	  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
675 	  /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
676 	  ptr = &remcomInBuffer[1];
677 	  if (hexToInt(&ptr,&addr))
678 	    if (*(ptr++) == ',')
679 	      if (hexToInt(&ptr,&length))
680 		if (*(ptr++) == ':')
681 		  {
682 		    mem_err = 0;
683 		    hex2mem(ptr, (char*) addr, length, 1);
684 
685 		    if (mem_err)
686 		      {
687 			strcpy (remcomOutBuffer, "E03");
688 			debug_error ("memory fault");
689 		      }
690 		    else
691 		      {
692 			strcpy(remcomOutBuffer,"OK");
693 		      }
694 
695 		    ptr = 0;
696 		  }
697 	  if (ptr)
698 	    {
699 	      strcpy(remcomOutBuffer,"E02");
700 	      debug_error("malformed write memory command: %s",remcomInBuffer);
701 	    }
702 	  break;
703 
704 	case 'c':
705 	case 's':
706 	  /* cAA..AA    Continue at address AA..AA(optional) */
707 	  /* sAA..AA   Step one instruction from AA..AA(optional) */
708 	  /* try to read optional parameter, pc unchanged if no parm */
709 	  ptr = &remcomInBuffer[1];
710 	  if (hexToInt(&ptr,&addr))
711 	    {
712 /*	      registers[PC_REGNUM].lo = addr;*/
713 	      fprintf (stderr, "Setting PC to 0x%x\n", addr);
714 	      while (1);
715 	    }
716 
717 	  if (remcomInBuffer[0] == 's')
718 	    set_step_traps (frame);
719 
720 	  flush_i_cache ();
721 	  return RETURN_TO_PROGRAM;
722 
723 	case 'k':
724 	  /* kill the program */
725 	  KillMe (ldinfo);
726 	  ResumeThread (mainthread);
727 	  return RETURN_TO_PROGRAM;
728 
729 	case 'q':		/* Query message */
730 	  if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
731 	    {
732 	      sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
733 		       ldinfo->LDCodeImageOffset,
734 		       ldinfo->LDDataImageOffset,
735 		       ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
736 	    }
737 	  else
738 	    sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
739 	  break;
740 	}
741 
742       /* reply to the request */
743       if (! putpacket(remcomOutBuffer))
744 	return RETURN_TO_NEXT_DEBUGGER;
745     }
746 }
747 
748 char *progname;
749 
750 struct bitRate {
751   BYTE bitRate;
752   const char *bitRateString;
753 };
754 
755 struct bitRate bitRateTable[] =
756 {
757   { AIO_BAUD_50    ,      "50" },
758   { AIO_BAUD_75    ,      "75" },
759   { AIO_BAUD_110   ,     "110" },
760   { AIO_BAUD_134p5 ,   "134.5" },
761   { AIO_BAUD_150   ,     "150" },
762   { AIO_BAUD_300   ,     "300" },
763   { AIO_BAUD_600   ,     "600" },
764   { AIO_BAUD_1200  ,    "1200" },
765   { AIO_BAUD_1800  ,    "1800" },
766   { AIO_BAUD_2000  ,    "2000" },
767   { AIO_BAUD_2400  ,    "2400" },
768   { AIO_BAUD_3600  ,    "3600" },
769   { AIO_BAUD_4800  ,    "4800" },
770   { AIO_BAUD_7200  ,    "7200" },
771   { AIO_BAUD_9600  ,    "9600" },
772   { AIO_BAUD_19200 ,   "19200" },
773   { AIO_BAUD_38400 ,   "38400" },
774   { AIO_BAUD_57600 ,   "57600" },
775   { AIO_BAUD_115200,  "115200" },
776   { -1, NULL }
777 };
778 
779 char dataBitsTable[] = "5678";
780 
781 char *stopBitsTable[] = { "1", "1.5", "2" };
782 
783 char parity[] = "NOEMS";
784 
785 /* Start up.  The main thread opens the named serial I/O port, loads
786    the named NLM module and then goes to sleep.  The serial I/O port
787    is named as a board number and a port number.  It would be more DOS
788    like to provide a menu of available serial ports, but I don't want
789    to have to figure out how to do that.  */
790 
791 int
792 main (int argc, char **argv)
793 {
794   int hardware, board, port;
795   BYTE bitRate;
796   BYTE dataBits;
797   BYTE stopBits;
798   BYTE parityMode;
799   LONG err;
800   struct debuggerStructure s;
801   int cmdindx;
802   char *cmdlin;
803   int i;
804 
805   /* set progname */
806   progname = "gdbserve";
807 
808   /* set default serial line */
809   hardware = -1;
810   board = 0;
811   port = 0;
812 
813   /* set default serial line characteristics */
814   bitRate  = AIO_BAUD_9600;
815   dataBits = AIO_DATA_BITS_8;
816   stopBits = AIO_STOP_BITS_1;
817   parityMode = AIO_PARITY_NONE;
818 
819   cmdindx = 0;
820   for (argc--, argv++; *argv; argc--, argv++)
821     {
822       char *bp;
823       char *ep;
824 
825       if (strnicmp(*argv, "BAUD=", 5) == 0)
826 	{
827 	  struct bitRate *brp;
828 
829 	  bp = *argv + 5;
830 	  for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++)
831 	    {
832 	      if (strcmp(brp->bitRateString, bp) == 0)
833 		{
834 		  bitRate = brp->bitRate;
835 		  break;
836 		}
837 	    }
838 
839 	  if (brp->bitRateString == NULL)
840 	    {
841 	      fprintf(stderr, "%s: %s: unknown or unsupported bit rate",
842 		      progname, bp);
843 	      exit (1);
844 	    }
845 	}
846       else if (strnicmp(*argv, "BOARD=", 6) == 0)
847         {
848 	  bp = *argv + 6;
849 	  board = strtol (bp, &ep, 0);
850 	  if (ep == bp || *ep != '\0')
851 	    {
852 	      fprintf (stderr, "%s: %s: expected integer argument\n",
853 		       progname, bp);
854 	      exit(1);
855 	    }
856 	}
857 #if 1				/* FIXME: this option has been depricated */
858       else if (strnicmp(*argv, "NODE=", 5) == 0)
859 	{
860 	  bp = *argv + 5;
861 	  board = strtol (bp, &ep, 0);
862 	  if (ep == bp || *ep != '\0')
863 	    {
864 	      fprintf (stderr, "%s: %s: expected integer argument\n",
865 		       progname, bp);
866 	      exit(1);
867 	    }
868 	}
869 #endif
870       else if (strnicmp(*argv, "PORT=", 5) == 0)
871 	{
872 	  bp = *argv + 5;
873 	  port = strtol (bp, &ep, 0);
874 	  if (ep == bp || *ep != '\0')
875 	    {
876 	      fprintf (stderr, "%s: %s: expected integer argument\n",
877 		       progname, bp);
878 	      exit(1);
879 	    }
880 	}
881       else
882 	{
883 	  break;
884 	}
885 
886       cmdindx++;
887     }
888 
889   if (argc == 0)
890     {
891       fprintf (stderr,
892 	       "Usage: load %s [options] program [arguments]\n", progname);
893       exit (1);
894     }
895 
896   err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
897   if (err != AIO_SUCCESS)
898     {
899       switch (err)
900 	{
901 	case AIO_PORT_NOT_AVAILABLE:
902 	  fprintf (stderr, "Port not available\n");
903 	  break;
904 
905 	case AIO_BOARD_NUMBER_INVALID:
906 	case AIO_PORT_NUMBER_INVALID:
907 	  fprintf (stderr, "No such port\n");
908 	  break;
909 
910 	default:
911 	  fprintf (stderr, "Could not open port: %d\n", err);
912 	  break;
913 	}
914 
915       exit (1);
916     }
917 
918   err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
919 			  AIO_HARDWARE_FLOW_CONTROL_OFF);
920 
921   if (err == AIO_QUALIFIED_SUCCESS)
922     {
923       AIOPORTCONFIG portConfig;
924 
925       fprintf (stderr, "Port configuration changed!\n");
926 
927       portConfig.returnLength = sizeof(portConfig);
928       AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
929 
930       fprintf (stderr,
931 	       "  Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
932  Flow:%s\n",
933 	       bitRateTable[portConfig.bitRate].bitRateString,
934 	       dataBitsTable[portConfig.dataBits],
935 	       stopBitsTable[portConfig.stopBits],
936 	       parity[portConfig.parityMode],
937 	       portConfig.flowCtrlMode ? "ON" : "OFF");
938     }
939   else if (err != AIO_SUCCESS)
940     {
941       fprintf (stderr, "Could not configure port: %d\n", err);
942       AIOReleasePort (AIOhandle);
943       exit (1);
944     }
945 
946   if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
947 			    (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
948       != AIO_SUCCESS)
949     {
950       LONG extStatus, chgdExtStatus;
951 
952       fprintf (stderr, "Could not set desired port controls!\n");
953       AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
954       fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
955 	       chgdExtStatus);
956     }
957 
958   /* Register ourselves as an alternate debugger.  */
959   memset (&s, 0, sizeof s);
960   s.DDSResourceTag = ((struct ResourceTagStructure *)
961 		      AllocateResourceTag (GetNLMHandle (),
962 					   (BYTE *)"gdbserver",
963 					   DebuggerSignature));
964   if (s.DDSResourceTag == 0)
965     {
966       fprintf (stderr, "AllocateResourceTag failed\n");
967       AIOReleasePort (AIOhandle);
968       exit (1);
969     }
970   s.DDSdebuggerEntry = handle_exception;
971   s.DDSFlags = TSS_FRAME_BIT;
972 
973   err = RegisterDebuggerRTag (&s, AT_FIRST);
974   if (err != 0)
975     {
976       fprintf (stderr, "RegisterDebuggerRTag failed\n");
977       AIOReleasePort (AIOhandle);
978       exit (1);
979     }
980 
981   /* Get the command line we were invoked with, and advance it past
982      our name and the board and port arguments.  */
983   cmdlin = getcmd ((char *) NULL);
984   for (i = 0; i < cmdindx; i++)
985     {
986       while (! isspace (*cmdlin))
987 	++cmdlin;
988       while (isspace (*cmdlin))
989 	++cmdlin;
990     }
991 
992   /* In case GDB is started before us, ack any packets (presumably
993      "$?#xx") sitting there.  */
994   if (! putDebugChar ('+'))
995     {
996       fprintf (stderr, "putDebugChar failed\n");
997       UnRegisterDebugger (&s);
998       AIOReleasePort (AIOhandle);
999       exit (1);
1000     }
1001 
1002   mainthread = GetThreadID ();
1003 
1004   if (remote_debug > 0)
1005     ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1006 		   cmdlin, __GetScreenID (GetCurrentScreen()));
1007 
1008   /* Start up the module to be debugged.  */
1009   err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1010 		    (BYTE *)cmdlin, LO_DEBUG);
1011   if (err != 0)
1012     {
1013       fprintf (stderr, "LoadModule failed: %d\n", err);
1014       UnRegisterDebugger (&s);
1015       AIOReleasePort (AIOhandle);
1016       exit (1);
1017     }
1018 
1019   /* Wait for the debugger to wake us up.  */
1020   if (remote_debug > 0)
1021     ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1022   SuspendThread (mainthread);
1023   if (remote_debug > 0)
1024     ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1025 
1026   /* If we are woken up, print an optional error message, deregister
1027      ourselves and exit.  */
1028   if (error_message != NULL)
1029     fprintf (stderr, "%s\n", error_message);
1030   UnRegisterDebugger (&s);
1031   AIOReleasePort (AIOhandle);
1032   exit (0);
1033 }
1034