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