xref: /openbsd-src/gnu/usr.bin/binutils/gdb/nlm/gdbserve.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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 ()
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 (c)
195      unsigned char c;
196 {
197   int err;
198   LONG put;
199 
200   put = 0;
201   while (put < 1)
202     {
203       err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
204       if (err != 0)
205 	ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
206     }
207   return 1;
208 }
209 
210 /* Turn a hex character into a number.  */
211 
212 static int
213 hex (ch)
214      char ch;
215 {
216   if ((ch >= 'a') && (ch <= 'f'))
217     return (ch-'a'+10);
218   if ((ch >= '0') && (ch <= '9'))
219     return (ch-'0');
220   if ((ch >= 'A') && (ch <= 'F'))
221     return (ch-'A'+10);
222   return (-1);
223 }
224 
225 /* Scan for the sequence $<data>#<checksum>.  Returns 0 on failure,
226    non-zero on success.  */
227 
228 static int
229 getpacket (buffer)
230      char * buffer;
231 {
232   unsigned char checksum;
233   unsigned char xmitcsum;
234   int i;
235   int count;
236   int ch;
237 
238   do
239     {
240       /* wait around for the start character, ignore all other characters */
241       while ((ch = getDebugChar()) != '$')
242 	if (ch == -1)
243 	  return 0;
244       checksum = 0;
245       xmitcsum = -1;
246 
247       count = 0;
248 
249       /* now, read until a # or end of buffer is found */
250       while (count < BUFMAX)
251 	{
252 	  ch = getDebugChar();
253 	  if (ch == -1)
254 	    return 0;
255 	  if (ch == '#')
256 	    break;
257 	  checksum = checksum + ch;
258 	  buffer[count] = ch;
259 	  count = count + 1;
260 	}
261       buffer[count] = 0;
262 
263       if (ch == '#')
264 	{
265 	  ch = getDebugChar ();
266 	  if (ch == -1)
267 	    return 0;
268 	  xmitcsum = hex(ch) << 4;
269 	  ch = getDebugChar ();
270 	  if (ch == -1)
271 	    return 0;
272 	  xmitcsum += hex(ch);
273 
274 	  if (checksum != xmitcsum)
275 	    {
276 	      if (remote_debug)
277 		ConsolePrintf ("bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
278 			       checksum,xmitcsum,buffer);
279 	      /* failed checksum */
280 	      if (! putDebugChar('-'))
281 		return 0;
282 	      return 1;
283 	    }
284 	  else
285 	    {
286 	      /* successful transfer */
287 	      if (! putDebugChar('+'))
288 		return 0;
289 	      /* if a sequence char is present, reply the sequence ID */
290 	      if (buffer[2] == ':')
291 		{
292 		  if (! putDebugChar (buffer[0])
293 		      || ! putDebugChar (buffer[1]))
294 		    return 0;
295 		  /* remove sequence chars from buffer */
296 		  count = strlen(buffer);
297 		  for (i=3; i <= count; i++)
298 		    buffer[i-3] = buffer[i];
299 		}
300 	    }
301 	}
302     }
303   while (checksum != xmitcsum);
304 
305   if (remote_debug)
306     ConsolePrintf ("Received packet \"%s\"\r\n", buffer);
307 
308   return 1;
309 }
310 
311 /* Send the packet in buffer.  Returns 0 on failure, non-zero on
312    success.  */
313 
314 static int
315 putpacket (buffer)
316      char * buffer;
317 {
318   unsigned char checksum;
319   int count;
320   int ch;
321 
322   if (remote_debug)
323     ConsolePrintf ("Sending packet \"%s\"\r\n", buffer);
324 
325   /*  $<packet info>#<checksum>. */
326   do
327     {
328       if (! putDebugChar('$'))
329 	return 0;
330       checksum = 0;
331       count = 0;
332 
333       while (ch=buffer[count])
334 	{
335 	  if (! putDebugChar(ch))
336 	    return 0;
337 	  checksum += ch;
338 	  count += 1;
339 	}
340 
341       if (! putDebugChar('#')
342 	  || ! putDebugChar(hexchars[checksum >> 4])
343 	  || ! putDebugChar(hexchars[checksum % 16]))
344 	return 0;
345 
346       ch = getDebugChar ();
347       if (ch == -1)
348 	return 0;
349     }
350   while (ch != '+');
351 
352   return 1;
353 }
354 
355 static char remcomInBuffer[BUFMAX];
356 static char remcomOutBuffer[BUFMAX];
357 static short error;
358 
359 static void
360 debug_error (format, parm)
361      char *format;
362      char *parm;
363 {
364   if (remote_debug)
365     {
366       ConsolePrintf (format, parm);
367       ConsolePrintf ("\n");
368     }
369 }
370 
371 /* This is set if we could get a memory access fault.  */
372 static int mem_may_fault;
373 
374 /* Indicate to caller of mem2hex or hex2mem that there has been an
375    error.  */
376 volatile int mem_err = 0;
377 
378 #ifndef ALTERNATE_MEM_FUNCS
379 /* These are separate functions so that they are so short and sweet
380    that the compiler won't save any registers (if there is a fault
381    to mem_fault, they won't get restored, so there better not be any
382    saved).  */
383 
384 int
385 get_char (addr)
386      char *addr;
387 {
388   return *addr;
389 }
390 
391 void
392 set_char (addr, val)
393      char *addr;
394      int val;
395 {
396   *addr = val;
397 }
398 #endif /* ALTERNATE_MEM_FUNCS */
399 
400 /* convert the memory pointed to by mem into hex, placing result in buf */
401 /* return a pointer to the last char put in buf (null) */
402 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
403    a fault; if zero treat a fault like any other fault in the stub.  */
404 
405 char *
406 mem2hex (mem, buf, count, may_fault)
407      void *mem;
408      char *buf;
409      int count;
410      int may_fault;
411 {
412   int i;
413   unsigned char ch;
414   char *ptr = mem;
415 
416   mem_may_fault = may_fault;
417   for (i = 0; i < count; i++)
418     {
419       ch = get_char (ptr++);
420       if (may_fault && mem_err)
421 	return (buf);
422       *buf++ = hexchars[ch >> 4];
423       *buf++ = hexchars[ch % 16];
424     }
425   *buf = 0;
426   mem_may_fault = 0;
427   return(buf);
428 }
429 
430 /* convert the hex array pointed to by buf into binary to be placed in mem */
431 /* return a pointer to the character AFTER the last byte written */
432 
433 char *
434 hex2mem (buf, mem, count, may_fault)
435      char *buf;
436      void *mem;
437      int count;
438      int may_fault;
439 {
440   int i;
441   unsigned char ch;
442   char *ptr = mem;
443 
444   mem_may_fault = may_fault;
445   for (i=0;i<count;i++)
446     {
447       ch = hex(*buf++) << 4;
448       ch = ch + hex(*buf++);
449       set_char (ptr++, ch);
450       if (may_fault && mem_err)
451 	return (ptr);
452     }
453   mem_may_fault = 0;
454   return(mem);
455 }
456 
457 /* This function takes the 386 exception vector and attempts to
458    translate this number into a unix compatible signal value.  */
459 
460 int
461 computeSignal (exceptionVector)
462      int exceptionVector;
463 {
464   int sigval;
465   switch (exceptionVector)
466     {
467     case 0 : sigval = 8; break; /* divide by zero */
468     case 1 : sigval = 5; break; /* debug exception */
469     case 3 : sigval = 5; break; /* breakpoint */
470     case 4 : sigval = 16; break; /* into instruction (overflow) */
471     case 5 : sigval = 16; break; /* bound instruction */
472     case 6 : sigval = 4; break; /* Invalid opcode */
473     case 7 : sigval = 8; break; /* coprocessor not available */
474     case 8 : sigval = 7; break; /* double fault */
475     case 9 : sigval = 11; break; /* coprocessor segment overrun */
476     case 10 : sigval = 11; break; /* Invalid TSS */
477     case 11 : sigval = 11; break; /* Segment not present */
478     case 12 : sigval = 11; break; /* stack exception */
479     case 13 : sigval = 11; break; /* general protection */
480     case 14 : sigval = 11; break; /* page fault */
481     case 16 : sigval = 7; break; /* coprocessor error */
482     default:
483       sigval = 7;		/* "software generated"*/
484     }
485   return (sigval);
486 }
487 
488 /**********************************************/
489 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
490 /* RETURN NUMBER OF CHARS PROCESSED           */
491 /**********************************************/
492 static int
493 hexToInt(ptr, intValue)
494      char **ptr;
495      int *intValue;
496 {
497   int numChars = 0;
498   int hexValue;
499 
500   *intValue = 0;
501 
502   while (**ptr)
503     {
504       hexValue = hex(**ptr);
505       if (hexValue >=0)
506 	{
507 	  *intValue = (*intValue <<4) | hexValue;
508 	  numChars ++;
509 	}
510       else
511 	break;
512 
513       (*ptr)++;
514     }
515 
516   return (numChars);
517 }
518 
519 /* This function does all command processing for interfacing to gdb.
520    It is called whenever an exception occurs in the module being
521    debugged.  */
522 
523 static LONG
524 handle_exception (frame)
525      struct StackFrame *frame;
526 {
527   int addr, length;
528   char *ptr;
529   static struct DBG_LoadDefinitionStructure *ldinfo = 0;
530   static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program.  */
531 
532 #if 0
533   /* According to some documentation from Novell, the bell sometimes
534      may be ringing at this point.  This can be stopped on Netware 4
535      systems by calling the undocumented StopBell() function. */
536 
537   StopBell ();
538 #endif
539 
540   if (remote_debug)
541     {
542       ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
543 		     frame->ExceptionNumber,
544 		     frame->ExceptionDescription,
545 		     frame->ExceptionPC,
546 		     GetThreadID ());
547     }
548 
549   switch (frame->ExceptionNumber)
550     {
551     case START_NLM_EVENT:
552       /* If the NLM just started, we record the module load information
553 	 and the thread ID, and set a breakpoint at the first instruction
554 	 in the program.  */
555 
556       ldinfo = ((struct DBG_LoadDefinitionStructure *)
557 		frame->ExceptionErrorCode);
558       memcpy (first_insn, ldinfo->LDInitializationProcedure,
559 	      BREAKPOINT_SIZE);
560       memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
561 	      BREAKPOINT_SIZE);
562       flush_i_cache ();
563       return RETURN_TO_PROGRAM;
564 
565     case ENTER_DEBUGGER_EVENT:
566     case KEYBOARD_BREAK_EVENT:
567       /* Pass some events on to the next debugger, in case it will handle
568 	 them.  */
569       return RETURN_TO_NEXT_DEBUGGER;
570 
571     case 3:			/* Breakpoint */
572       /* After we've reached the initial breakpoint, reset it.  */
573       if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
574 	  && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
575 		     BREAKPOINT_SIZE) == 0)
576 	{
577 	  memcpy (ldinfo->LDInitializationProcedure, first_insn,
578 		  BREAKPOINT_SIZE);
579 	  frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
580 	  flush_i_cache ();
581 	}
582       /* Normal breakpoints end up here */
583       do_status (remcomOutBuffer, frame);
584       break;
585 
586     default:
587       /* At the moment, we don't care about most of the unusual NetWare
588 	 exceptions.  */
589       if (frame->ExceptionNumber > 31)
590 	return RETURN_TO_PROGRAM;
591 
592       /* Most machine level exceptions end up here */
593       do_status (remcomOutBuffer, frame);
594       break;
595 
596     case 11:			/* Segment not present */
597     case 13:			/* General protection */
598     case 14:			/* Page fault */
599       /* If we get a GP fault, and mem_may_fault is set, and the
600 	 instruction pointer is near set_char or get_char, then we caused
601 	 the fault ourselves accessing an illegal memory location.  */
602       if (mem_may_fault
603 	  && ((frame->ExceptionPC >= (long) &set_char
604 	       && frame->ExceptionPC < (long) &set_char + 50)
605 	      || (frame->ExceptionPC >= (long) &get_char
606 		  && frame->ExceptionPC < (long) &get_char + 50)))
607 	{
608 	  mem_err = 1;
609 	  /* Point the instruction pointer at an assembly language stub
610 	     which just returns from the function.  */
611 
612 	  frame->ExceptionPC += 4; /* Skip the load or store */
613 
614 	  /* Keep going.  This will act as though it returned from
615 	     set_char or get_char.  The calling routine will check
616 	     mem_err, and do the right thing.  */
617 	  return RETURN_TO_PROGRAM;
618 	}
619       /* Random mem fault, report it */
620       do_status (remcomOutBuffer, frame);
621       break;
622 
623     case TERMINATE_NLM_EVENT:
624       /* There is no way to get the exit status.  */
625       sprintf (remcomOutBuffer, "W%02x", 0);
626       break;			/* We generate our own status */
627     }
628 
629   /* FIXME: How do we know that this exception has anything to do with
630      the program we are debugging?  We can check whether the PC is in
631      the range of the module we are debugging, but that doesn't help
632      much since an error could occur in a library routine.  */
633 
634   clear_step_traps (frame);
635 
636   if (! putpacket(remcomOutBuffer))
637     return RETURN_TO_NEXT_DEBUGGER;
638 
639   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
640     {
641       ResumeThread (mainthread);
642       return RETURN_TO_PROGRAM;
643     }
644 
645   while (1)
646     {
647       error = 0;
648       remcomOutBuffer[0] = 0;
649       if (! getpacket (remcomInBuffer))
650 	return RETURN_TO_NEXT_DEBUGGER;
651       switch (remcomInBuffer[0])
652 	{
653 	case '?':
654 	  do_status (remcomOutBuffer, frame);
655 	  break;
656 	case 'd':
657 	  remote_debug = !(remote_debug); /* toggle debug flag */
658 	  break;
659 	case 'g':
660 	  /* return the value of the CPU registers */
661 	  frame_to_registers (frame, remcomOutBuffer);
662 	  break;
663 	case 'G':
664 	  /* set the value of the CPU registers - return OK */
665 	  registers_to_frame (&remcomInBuffer[1], frame);
666 	  strcpy(remcomOutBuffer,"OK");
667 	  break;
668 
669 	case 'm':
670 	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
671 	  /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
672 	  ptr = &remcomInBuffer[1];
673 	  if (hexToInt(&ptr,&addr))
674 	    if (*(ptr++) == ',')
675 	      if (hexToInt(&ptr,&length))
676 		{
677 		  ptr = 0;
678 		  mem_err = 0;
679 		  mem2hex((char*) addr, remcomOutBuffer, length, 1);
680 		  if (mem_err)
681 		    {
682 		      strcpy (remcomOutBuffer, "E03");
683 		      debug_error ("memory fault");
684 		    }
685 		}
686 
687 	  if (ptr)
688 	    {
689 	      strcpy(remcomOutBuffer,"E01");
690 	      debug_error("malformed read memory command: %s",remcomInBuffer);
691 	    }
692 	  break;
693 
694 	case 'M':
695 	  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
696 	  /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
697 	  ptr = &remcomInBuffer[1];
698 	  if (hexToInt(&ptr,&addr))
699 	    if (*(ptr++) == ',')
700 	      if (hexToInt(&ptr,&length))
701 		if (*(ptr++) == ':')
702 		  {
703 		    mem_err = 0;
704 		    hex2mem(ptr, (char*) addr, length, 1);
705 
706 		    if (mem_err)
707 		      {
708 			strcpy (remcomOutBuffer, "E03");
709 			debug_error ("memory fault");
710 		      }
711 		    else
712 		      {
713 			strcpy(remcomOutBuffer,"OK");
714 		      }
715 
716 		    ptr = 0;
717 		  }
718 	  if (ptr)
719 	    {
720 	      strcpy(remcomOutBuffer,"E02");
721 	      debug_error("malformed write memory command: %s",remcomInBuffer);
722 	    }
723 	  break;
724 
725 	case 'c':
726 	case 's':
727 	  /* cAA..AA    Continue at address AA..AA(optional) */
728 	  /* sAA..AA   Step one instruction from AA..AA(optional) */
729 	  /* try to read optional parameter, pc unchanged if no parm */
730 	  ptr = &remcomInBuffer[1];
731 	  if (hexToInt(&ptr,&addr))
732 	    {
733 /*	      registers[PC_REGNUM].lo = addr;*/
734 	      fprintf (stderr, "Setting PC to 0x%x\n", addr);
735 	      while (1);
736 	    }
737 
738 	  if (remcomInBuffer[0] == 's')
739 	    set_step_traps (frame);
740 
741 	  flush_i_cache ();
742 	  return RETURN_TO_PROGRAM;
743 
744 	case 'k':
745 	  /* kill the program */
746 	  KillMe (ldinfo);
747 	  ResumeThread (mainthread);
748 	  return RETURN_TO_PROGRAM;
749 
750 	case 'q':		/* Query message */
751 	  if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
752 	    {
753 	      sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
754 		       ldinfo->LDCodeImageOffset,
755 		       ldinfo->LDDataImageOffset,
756 		       ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
757 	    }
758 	  else
759 	    sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
760 	  break;
761 	}
762 
763       /* reply to the request */
764       if (! putpacket(remcomOutBuffer))
765 	return RETURN_TO_NEXT_DEBUGGER;
766     }
767 }
768 
769 char *progname;
770 
771 struct bitRate {
772   BYTE bitRate;
773   const char *bitRateString;
774 };
775 
776 struct bitRate bitRateTable[] =
777 {
778   { AIO_BAUD_50    ,      "50" },
779   { AIO_BAUD_75    ,      "75" },
780   { AIO_BAUD_110   ,     "110" },
781   { AIO_BAUD_134p5 ,   "134.5" },
782   { AIO_BAUD_150   ,     "150" },
783   { AIO_BAUD_300   ,     "300" },
784   { AIO_BAUD_600   ,     "600" },
785   { AIO_BAUD_1200  ,    "1200" },
786   { AIO_BAUD_1800  ,    "1800" },
787   { AIO_BAUD_2000  ,    "2000" },
788   { AIO_BAUD_2400  ,    "2400" },
789   { AIO_BAUD_3600  ,    "3600" },
790   { AIO_BAUD_4800  ,    "4800" },
791   { AIO_BAUD_7200  ,    "7200" },
792   { AIO_BAUD_9600  ,    "9600" },
793   { AIO_BAUD_19200 ,   "19200" },
794   { AIO_BAUD_38400 ,   "38400" },
795   { AIO_BAUD_57600 ,   "57600" },
796   { AIO_BAUD_115200,  "115200" },
797   { -1, NULL }
798 };
799 
800 char dataBitsTable[] = "5678";
801 
802 char *stopBitsTable[] = { "1", "1.5", "2" };
803 
804 char parity[] = "NOEMS";
805 
806 /* Start up.  The main thread opens the named serial I/O port, loads
807    the named NLM module and then goes to sleep.  The serial I/O port
808    is named as a board number and a port number.  It would be more DOS
809    like to provide a menu of available serial ports, but I don't want
810    to have to figure out how to do that.  */
811 
812 int
813 main (argc, argv)
814      int argc;
815      char **argv;
816 {
817   int hardware, board, port;
818   BYTE bitRate;
819   BYTE dataBits;
820   BYTE stopBits;
821   BYTE parityMode;
822   LONG err;
823   struct debuggerStructure s;
824   int cmdindx;
825   char *cmdlin;
826   int i;
827 
828   /* set progname */
829   progname = "gdbserve";
830 
831   /* set default serial line */
832   hardware = -1;
833   board = 0;
834   port = 0;
835 
836   /* set default serial line characteristics */
837   bitRate  = AIO_BAUD_9600;
838   dataBits = AIO_DATA_BITS_8;
839   stopBits = AIO_STOP_BITS_1;
840   parityMode = AIO_PARITY_NONE;
841 
842   cmdindx = 0;
843   for (argc--, argv++; *argv; argc--, argv++)
844     {
845       char *bp;
846       char *ep;
847 
848       if (strnicmp(*argv, "BAUD=", 5) == 0)
849 	{
850 	  struct bitRate *brp;
851 
852 	  bp = *argv + 5;
853 	  for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++)
854 	    {
855 	      if (strcmp(brp->bitRateString, bp) == 0)
856 		{
857 		  bitRate = brp->bitRate;
858 		  break;
859 		}
860 	    }
861 
862 	  if (brp->bitRateString == NULL)
863 	    {
864 	      fprintf(stderr, "%s: %s: unknown or unsupported bit rate",
865 		      progname, bp);
866 	      exit (1);
867 	    }
868 	}
869       else if (strnicmp(*argv, "BOARD=", 6) == 0)
870         {
871 	  bp = *argv + 6;
872 	  board = strtol (bp, &ep, 0);
873 	  if (ep == bp || *ep != '\0')
874 	    {
875 	      fprintf (stderr, "%s: %s: expected integer argument\n",
876 		       progname, bp);
877 	      exit(1);
878 	    }
879 	}
880 #if 1				/* FIXME: this option has been depricated */
881       else if (strnicmp(*argv, "NODE=", 5) == 0)
882 	{
883 	  bp = *argv + 5;
884 	  board = strtol (bp, &ep, 0);
885 	  if (ep == bp || *ep != '\0')
886 	    {
887 	      fprintf (stderr, "%s: %s: expected integer argument\n",
888 		       progname, bp);
889 	      exit(1);
890 	    }
891 	}
892 #endif
893       else if (strnicmp(*argv, "PORT=", 5) == 0)
894 	{
895 	  bp = *argv + 5;
896 	  port = strtol (bp, &ep, 0);
897 	  if (ep == bp || *ep != '\0')
898 	    {
899 	      fprintf (stderr, "%s: %s: expected integer argument\n",
900 		       progname, bp);
901 	      exit(1);
902 	    }
903 	}
904       else
905 	{
906 	  break;
907 	}
908 
909       cmdindx++;
910     }
911 
912   if (argc == 0)
913     {
914       fprintf (stderr,
915 	       "Usage: load %s [options] program [arguments]\n", progname);
916       exit (1);
917     }
918 
919   err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
920   if (err != AIO_SUCCESS)
921     {
922       switch (err)
923 	{
924 	case AIO_PORT_NOT_AVAILABLE:
925 	  fprintf (stderr, "Port not available\n");
926 	  break;
927 
928 	case AIO_BOARD_NUMBER_INVALID:
929 	case AIO_PORT_NUMBER_INVALID:
930 	  fprintf (stderr, "No such port\n");
931 	  break;
932 
933 	default:
934 	  fprintf (stderr, "Could not open port: %d\n", err);
935 	  break;
936 	}
937 
938       exit (1);
939     }
940 
941   err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
942 			  AIO_HARDWARE_FLOW_CONTROL_OFF);
943 
944   if (err == AIO_QUALIFIED_SUCCESS)
945     {
946       AIOPORTCONFIG portConfig;
947 
948       fprintf (stderr, "Port configuration changed!\n");
949 
950       portConfig.returnLength = sizeof(portConfig);
951       AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
952 
953       fprintf (stderr,
954 	       "  Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
955  Flow:%s\n",
956 	       bitRateTable[portConfig.bitRate].bitRateString,
957 	       dataBitsTable[portConfig.dataBits],
958 	       stopBitsTable[portConfig.stopBits],
959 	       parity[portConfig.parityMode],
960 	       portConfig.flowCtrlMode ? "ON" : "OFF");
961     }
962   else if (err != AIO_SUCCESS)
963     {
964       fprintf (stderr, "Could not configure port: %d\n", err);
965       AIOReleasePort (AIOhandle);
966       exit (1);
967     }
968 
969   if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
970 			    (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
971       != AIO_SUCCESS)
972     {
973       LONG extStatus, chgdExtStatus;
974 
975       fprintf (stderr, "Could not set desired port controls!\n");
976       AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
977       fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
978 	       chgdExtStatus);
979     }
980 
981   /* Register ourselves as an alternate debugger.  */
982   memset (&s, 0, sizeof s);
983   s.DDSResourceTag = ((struct ResourceTagStructure *)
984 		      AllocateResourceTag (GetNLMHandle (),
985 					   (BYTE *)"gdbserver",
986 					   DebuggerSignature));
987   if (s.DDSResourceTag == 0)
988     {
989       fprintf (stderr, "AllocateResourceTag failed\n");
990       AIOReleasePort (AIOhandle);
991       exit (1);
992     }
993   s.DDSdebuggerEntry = handle_exception;
994   s.DDSFlags = TSS_FRAME_BIT;
995 
996   err = RegisterDebuggerRTag (&s, AT_FIRST);
997   if (err != 0)
998     {
999       fprintf (stderr, "RegisterDebuggerRTag failed\n");
1000       AIOReleasePort (AIOhandle);
1001       exit (1);
1002     }
1003 
1004   /* Get the command line we were invoked with, and advance it past
1005      our name and the board and port arguments.  */
1006   cmdlin = getcmd ((char *) NULL);
1007   for (i = 0; i < cmdindx; i++)
1008     {
1009       while (! isspace (*cmdlin))
1010 	++cmdlin;
1011       while (isspace (*cmdlin))
1012 	++cmdlin;
1013     }
1014 
1015   /* In case GDB is started before us, ack any packets (presumably
1016      "$?#xx") sitting there.  */
1017   if (! putDebugChar ('+'))
1018     {
1019       fprintf (stderr, "putDebugChar failed\n");
1020       UnRegisterDebugger (&s);
1021       AIOReleasePort (AIOhandle);
1022       exit (1);
1023     }
1024 
1025   mainthread = GetThreadID ();
1026 
1027   if (remote_debug > 0)
1028     ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1029 		   cmdlin, __GetScreenID (GetCurrentScreen()));
1030 
1031   /* Start up the module to be debugged.  */
1032   err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1033 		    (BYTE *)cmdlin, LO_DEBUG);
1034   if (err != 0)
1035     {
1036       fprintf (stderr, "LoadModule failed: %d\n", err);
1037       UnRegisterDebugger (&s);
1038       AIOReleasePort (AIOhandle);
1039       exit (1);
1040     }
1041 
1042   /* Wait for the debugger to wake us up.  */
1043   if (remote_debug > 0)
1044     ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1045   SuspendThread (mainthread);
1046   if (remote_debug > 0)
1047     ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1048 
1049   /* If we are woken up, print an optional error message, deregister
1050      ourselves and exit.  */
1051   if (error_message != NULL)
1052     fprintf (stderr, "%s\n", error_message);
1053   UnRegisterDebugger (&s);
1054   AIOReleasePort (AIOhandle);
1055   exit (0);
1056 }
1057