]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/nlm/gdbserve.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / 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 }