Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / gdb / gdb / nlm / gdbserve.c
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 }