* nlm/gdbserve.c, nlm/ppc.c, nlm/ppc.h: Don't try to use
[external/binutils.git] / gdb / nlm / gdbserve.c
1 /* i386-nlmstub.c -- NLM debugging stub for the i386.
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 NetWare on an i386 platform.  To create the NLM,
10    compile this code into an object file using the NLM SDK on any i386
11    host, and use the nlmconv program (available in the GNU binutils)
12    to transform the 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   /* Apparently the bell can sometimes be ringing at this point, and
533      should be stopped.  */
534   StopBell ();
535
536   if (remote_debug)
537     {
538       ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
539                      frame->ExceptionNumber,
540                      frame->ExceptionDescription,
541                      frame->ExceptionPC,
542                      GetThreadID ());
543     }
544
545   switch (frame->ExceptionNumber)
546     {
547     case START_NLM_EVENT:
548       /* If the NLM just started, we record the module load information
549          and the thread ID, and set a breakpoint at the first instruction
550          in the program.  */
551
552       ldinfo = ((struct DBG_LoadDefinitionStructure *)
553                 frame->ExceptionErrorCode);
554       memcpy (first_insn, ldinfo->LDInitializationProcedure,
555               BREAKPOINT_SIZE);
556       memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
557               BREAKPOINT_SIZE);
558       flush_i_cache ();
559       return RETURN_TO_PROGRAM;
560
561     case ENTER_DEBUGGER_EVENT:
562     case KEYBOARD_BREAK_EVENT:
563       /* Pass some events on to the next debugger, in case it will handle
564          them.  */
565       return RETURN_TO_NEXT_DEBUGGER;
566
567     case 3:                     /* Breakpoint */
568       /* After we've reached the initial breakpoint, reset it.  */
569       if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
570           && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
571                      BREAKPOINT_SIZE) == 0)
572         {
573           memcpy (ldinfo->LDInitializationProcedure, first_insn,
574                   BREAKPOINT_SIZE);
575           frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
576           flush_i_cache ();
577         }
578       /* Normal breakpoints end up here */
579       do_status (remcomOutBuffer, frame);
580       break;
581
582     default:
583       /* At the moment, we don't care about most of the unusual NetWare
584          exceptions.  */
585       if (frame->ExceptionNumber > 31)
586         return RETURN_TO_PROGRAM;
587
588       /* Most machine level exceptions end up here */
589       do_status (remcomOutBuffer, frame);
590       break;
591
592     case 11:                    /* Segment not present */
593     case 13:                    /* General protection */
594     case 14:                    /* Page fault */
595       /* If we get a GP fault, and mem_may_fault is set, and the
596          instruction pointer is near set_char or get_char, then we caused
597          the fault ourselves accessing an illegal memory location.  */
598       if (mem_may_fault
599           && ((frame->ExceptionPC >= (long) &set_char
600                && frame->ExceptionPC < (long) &set_char + 50)
601               || (frame->ExceptionPC >= (long) &get_char
602                   && frame->ExceptionPC < (long) &get_char + 50)))
603         {
604           mem_err = 1;
605           /* Point the instruction pointer at an assembly language stub
606              which just returns from the function.  */
607
608           frame->ExceptionPC += 4; /* Skip the load or store */
609
610           /* Keep going.  This will act as though it returned from
611              set_char or get_char.  The calling routine will check
612              mem_err, and do the right thing.  */
613           return RETURN_TO_PROGRAM;
614         }
615       /* Random mem fault, report it */
616       do_status (remcomOutBuffer, frame);
617       break;
618
619     case TERMINATE_NLM_EVENT:
620       /* There is no way to get the exit status.  */
621       sprintf (remcomOutBuffer, "W%02x", 0);
622       break;                    /* We generate our own status */
623     }
624
625   /* FIXME: How do we know that this exception has anything to do with
626      the program we are debugging?  We can check whether the PC is in
627      the range of the module we are debugging, but that doesn't help
628      much since an error could occur in a library routine.  */
629
630   clear_step_traps (frame);
631
632   if (! putpacket(remcomOutBuffer))
633     return RETURN_TO_NEXT_DEBUGGER;
634
635   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
636     {
637       ResumeThread (mainthread);
638       return RETURN_TO_PROGRAM;
639     }
640
641   while (1)
642     {
643       error = 0;
644       remcomOutBuffer[0] = 0;
645       if (! getpacket (remcomInBuffer))
646         return RETURN_TO_NEXT_DEBUGGER;
647       switch (remcomInBuffer[0])
648         {
649         case '?':
650           do_status (remcomOutBuffer, frame);
651           break;
652         case 'd':
653           remote_debug = !(remote_debug); /* toggle debug flag */
654           break;
655         case 'g':
656           /* return the value of the CPU registers */
657           frame_to_registers (frame, remcomOutBuffer);
658           break;
659         case 'G':
660           /* set the value of the CPU registers - return OK */
661           registers_to_frame (&remcomInBuffer[1], frame);
662           strcpy(remcomOutBuffer,"OK");
663           break;
664
665         case 'm':
666           /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
667           /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
668           ptr = &remcomInBuffer[1];
669           if (hexToInt(&ptr,&addr))
670             if (*(ptr++) == ',')
671               if (hexToInt(&ptr,&length))
672                 {
673                   ptr = 0;
674                   mem_err = 0;
675                   mem2hex((char*) addr, remcomOutBuffer, length, 1);
676                   if (mem_err)
677                     {
678                       strcpy (remcomOutBuffer, "E03");
679                       debug_error ("memory fault");
680                     }
681                 }
682
683           if (ptr)
684             {
685               strcpy(remcomOutBuffer,"E01");
686               debug_error("malformed read memory command: %s",remcomInBuffer);
687             }
688           break;
689
690         case 'M':
691           /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
692           /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
693           ptr = &remcomInBuffer[1];
694           if (hexToInt(&ptr,&addr))
695             if (*(ptr++) == ',')
696               if (hexToInt(&ptr,&length))
697                 if (*(ptr++) == ':')
698                   {
699                     mem_err = 0;
700                     hex2mem(ptr, (char*) addr, length, 1);
701
702                     if (mem_err)
703                       {
704                         strcpy (remcomOutBuffer, "E03");
705                         debug_error ("memory fault");
706                       }
707                     else
708                       {
709                         strcpy(remcomOutBuffer,"OK");
710                       }
711
712                     ptr = 0;
713                   }
714           if (ptr)
715             {
716               strcpy(remcomOutBuffer,"E02");
717               debug_error("malformed write memory command: %s",remcomInBuffer);
718             }
719           break;
720
721         case 'c':
722         case 's':
723           /* cAA..AA    Continue at address AA..AA(optional) */
724           /* sAA..AA   Step one instruction from AA..AA(optional) */
725           /* try to read optional parameter, pc unchanged if no parm */
726           ptr = &remcomInBuffer[1];
727           if (hexToInt(&ptr,&addr))
728             {
729 /*            registers[PC_REGNUM].lo = addr;*/
730               fprintf (stderr, "Setting PC to 0x%x\n", addr);
731               while (1);
732             }
733
734           if (remcomInBuffer[0] == 's')
735             set_step_traps (frame);
736
737           flush_i_cache ();
738           return RETURN_TO_PROGRAM;
739
740         case 'k':
741           /* kill the program */
742           KillMe (ldinfo);
743           ResumeThread (mainthread);
744           return RETURN_TO_PROGRAM;
745
746         case 'q':               /* Query message */
747           if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
748             {
749               sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
750                        ldinfo->LDCodeImageOffset,
751                        ldinfo->LDDataImageOffset,
752                        ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
753             }
754           else
755             sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
756           break;
757         }
758
759       /* reply to the request */
760       if (! putpacket(remcomOutBuffer))
761         return RETURN_TO_NEXT_DEBUGGER;
762     }
763 }
764
765 char *progname;
766
767 struct bitRate {
768   BYTE bitRate;
769   const char *bitRateString;
770 };
771
772 struct bitRate bitRateTable[] = 
773 {
774   { AIO_BAUD_50    ,      "50" },
775   { AIO_BAUD_75    ,      "75" },
776   { AIO_BAUD_110   ,     "110" },
777   { AIO_BAUD_134p5 ,   "134.5" },
778   { AIO_BAUD_150   ,     "150" },
779   { AIO_BAUD_300   ,     "300" },
780   { AIO_BAUD_600   ,     "600" },
781   { AIO_BAUD_1200  ,    "1200" },
782   { AIO_BAUD_1800  ,    "1800" },
783   { AIO_BAUD_2000  ,    "2000" },
784   { AIO_BAUD_2400  ,    "2400" },
785   { AIO_BAUD_3600  ,    "3600" },
786   { AIO_BAUD_4800  ,    "4800" },
787   { AIO_BAUD_7200  ,    "7200" },
788   { AIO_BAUD_9600  ,    "9600" },
789   { AIO_BAUD_19200 ,   "19200" },
790   { AIO_BAUD_38400 ,   "38400" },
791   { AIO_BAUD_57600 ,   "57600" },
792   { AIO_BAUD_115200,  "115200" },
793   { -1, NULL }
794 };
795
796 char dataBitsTable[] = "5678";
797
798 char *stopBitsTable[] = { "1", "1.5", "2" };
799
800 char parity[] = "NOEMS";
801
802 /* Start up.  The main thread opens the named serial I/O port, loads
803    the named NLM module and then goes to sleep.  The serial I/O port
804    is named as a board number and a port number.  It would be more DOS
805    like to provide a menu of available serial ports, but I don't want
806    to have to figure out how to do that.  */
807
808 int
809 main (argc, argv)
810      int argc;
811      char **argv;
812 {
813   int hardware, board, port;
814   BYTE bitRate;
815   BYTE dataBits;
816   BYTE stopBits;
817   BYTE parityMode;
818   LONG err;
819   struct debuggerStructure s;
820   int cmdindx;
821   char *cmdlin;
822   int i;
823
824   /* set progname */
825   progname = "gdbserve";
826
827   /* set default serial line */
828   hardware = -1;
829   board = 0;
830   port = 0;
831
832   /* set default serial line characteristics */
833   bitRate  = AIO_BAUD_9600;
834   dataBits = AIO_DATA_BITS_8;
835   stopBits = AIO_STOP_BITS_1;
836   parityMode = AIO_PARITY_NONE;
837
838   cmdindx = 0;
839   for (argc--, argv++; *argv; argc--, argv++) 
840     {
841       char *bp;
842       char *ep;
843
844       if (strnicmp(*argv, "BAUD=", 5) == 0) 
845         {
846           struct bitRate *brp;
847
848           bp = *argv + 5;
849           for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++) 
850             {
851               if (strcmp(brp->bitRateString, bp) == 0) 
852                 {
853                   bitRate = brp->bitRate;
854                   break;
855                 }
856             }
857
858           if (brp->bitRateString == NULL) 
859             {
860               fprintf(stderr, "%s: %s: unknown or unsupported bit rate",
861                       progname, bp);
862               exit (1);
863             }
864         }
865       else if (strnicmp(*argv, "NODE=", 5) == 0)
866         {
867           bp = *argv + 5;
868           board = strtol (bp, &ep, 0);
869           if (ep == bp || *ep != '\0') 
870             {
871               fprintf (stderr, "%s: %s: expected integer argument\n", 
872                        progname, bp);
873               exit(1);
874             }
875         }
876       else if (strnicmp(*argv, "PORT=", 5) == 0)
877         {
878           bp = *argv + 5;
879           port = strtol (bp, &ep, 0);
880           if (ep == bp || *ep != '\0')
881             {
882               fprintf (stderr, "%s: %s: expected integer argument\n", 
883                        progname, bp);
884               exit(1);
885             }
886         }
887       else
888         {
889           break;
890         }
891
892       cmdindx++;
893     }
894
895   if (argc == 0)
896     {
897       fprintf (stderr,
898                "Usage: load %s [options] program [arguments]\n", progname);
899       exit (1);
900     }
901
902   err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
903   if (err != AIO_SUCCESS)
904     {
905       switch (err)
906         {
907         case AIO_PORT_NOT_AVAILABLE:
908           fprintf (stderr, "Port not available\n");
909           break;
910
911         case AIO_BOARD_NUMBER_INVALID:
912         case AIO_PORT_NUMBER_INVALID:
913           fprintf (stderr, "No such port\n");
914           break;
915
916         default:
917           fprintf (stderr, "Could not open port: %d\n", err);
918           break;
919         }
920
921       exit (1);
922     }
923
924   err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
925                           AIO_HARDWARE_FLOW_CONTROL_OFF);
926
927   if (err == AIO_QUALIFIED_SUCCESS)
928     {
929       AIOPORTCONFIG portConfig;
930
931       fprintf (stderr, "Port configuration changed!\n");
932
933       portConfig.returnLength = sizeof(portConfig);
934       AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
935
936       fprintf (stderr,
937                "  Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
938  Flow:%s\n",
939                bitRateTable[portConfig.bitRate].bitRateString,
940                dataBitsTable[portConfig.dataBits],
941                stopBitsTable[portConfig.stopBits],
942                parity[portConfig.parityMode],
943                portConfig.flowCtrlMode ? "ON" : "OFF");
944     }
945   else if (err != AIO_SUCCESS)
946     {
947       fprintf (stderr, "Could not configure port: %d\n", err);
948       AIOReleasePort (AIOhandle);
949       exit (1);
950     }
951
952   if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
953                             (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
954       != AIO_SUCCESS)
955     {
956       LONG extStatus, chgdExtStatus;
957
958       fprintf (stderr, "Could not set desired port controls!\n");
959       AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
960       fprintf (stderr, "Port controls now: %d, %d\n", extStatus, 
961                chgdExtStatus);
962     }
963
964   /* Register ourselves as an alternate debugger.  */
965   memset (&s, 0, sizeof s);
966   s.DDSResourceTag = ((struct ResourceTagStructure *)
967                       AllocateResourceTag (GetNLMHandle (),
968                                            (BYTE *)"gdbserver",
969                                            DebuggerSignature));
970   if (s.DDSResourceTag == 0)
971     {
972       fprintf (stderr, "AllocateResourceTag failed\n");
973       AIOReleasePort (AIOhandle);
974       exit (1);
975     }
976   s.DDSdebuggerEntry = handle_exception;
977   s.DDSFlags = TSS_FRAME_BIT;
978
979   err = RegisterDebuggerRTag (&s, AT_FIRST);
980   if (err != 0)
981     {
982       fprintf (stderr, "RegisterDebuggerRTag failed\n");
983       AIOReleasePort (AIOhandle);
984       exit (1);
985     }
986
987   /* Get the command line we were invoked with, and advance it past
988      our name and the board and port arguments.  */
989   cmdlin = getcmd ((char *) NULL);
990   for (i = 0; i < cmdindx; i++)
991     {
992       while (! isspace (*cmdlin))
993         ++cmdlin;
994       while (isspace (*cmdlin))
995         ++cmdlin;
996     }
997   
998   /* In case GDB is started before us, ack any packets (presumably
999      "$?#xx") sitting there.  */
1000   if (! putDebugChar ('+'))
1001     {
1002       fprintf (stderr, "putDebugChar failed\n");
1003       UnRegisterDebugger (&s);
1004       AIOReleasePort (AIOhandle);
1005       exit (1);
1006     }
1007
1008   mainthread = GetThreadID ();
1009
1010   if (remote_debug > 0)
1011     ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1012                    cmdlin, __GetScreenID (GetCurrentScreen()));
1013
1014   /* Start up the module to be debugged.  */
1015   err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1016                     (BYTE *)cmdlin, LO_DEBUG);
1017   if (err != 0)
1018     {
1019       fprintf (stderr, "LoadModule failed: %d\n", err);
1020       UnRegisterDebugger (&s);
1021       AIOReleasePort (AIOhandle);
1022       exit (1);
1023     }
1024
1025   /* Wait for the debugger to wake us up.  */
1026   if (remote_debug > 0)
1027     ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1028   SuspendThread (mainthread);
1029   if (remote_debug > 0)
1030     ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1031
1032   /* If we are woken up, print an optional error message, deregister
1033      ourselves and exit.  */
1034   if (error_message != NULL)
1035     fprintf (stderr, "%s\n", error_message);
1036   UnRegisterDebugger (&s);
1037   AIOReleasePort (AIOhandle);
1038   exit (0);
1039 }