* xcoffread.c (read_xcoff_symtab): When creating a dummy parameter
[deliverable/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 /* 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, "BOARD=", 6) == 0)
866 {
867 bp = *argv + 6;
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 #if 1 /* FIXME: this option has been depricated */
877 else if (strnicmp(*argv, "NODE=", 5) == 0)
878 {
879 bp = *argv + 5;
880 board = strtol (bp, &ep, 0);
881 if (ep == bp || *ep != '\0')
882 {
883 fprintf (stderr, "%s: %s: expected integer argument\n",
884 progname, bp);
885 exit(1);
886 }
887 }
888 #endif
889 else if (strnicmp(*argv, "PORT=", 5) == 0)
890 {
891 bp = *argv + 5;
892 port = strtol (bp, &ep, 0);
893 if (ep == bp || *ep != '\0')
894 {
895 fprintf (stderr, "%s: %s: expected integer argument\n",
896 progname, bp);
897 exit(1);
898 }
899 }
900 else
901 {
902 break;
903 }
904
905 cmdindx++;
906 }
907
908 if (argc == 0)
909 {
910 fprintf (stderr,
911 "Usage: load %s [options] program [arguments]\n", progname);
912 exit (1);
913 }
914
915 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
916 if (err != AIO_SUCCESS)
917 {
918 switch (err)
919 {
920 case AIO_PORT_NOT_AVAILABLE:
921 fprintf (stderr, "Port not available\n");
922 break;
923
924 case AIO_BOARD_NUMBER_INVALID:
925 case AIO_PORT_NUMBER_INVALID:
926 fprintf (stderr, "No such port\n");
927 break;
928
929 default:
930 fprintf (stderr, "Could not open port: %d\n", err);
931 break;
932 }
933
934 exit (1);
935 }
936
937 err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
938 AIO_HARDWARE_FLOW_CONTROL_OFF);
939
940 if (err == AIO_QUALIFIED_SUCCESS)
941 {
942 AIOPORTCONFIG portConfig;
943
944 fprintf (stderr, "Port configuration changed!\n");
945
946 portConfig.returnLength = sizeof(portConfig);
947 AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
948
949 fprintf (stderr,
950 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
951 Flow:%s\n",
952 bitRateTable[portConfig.bitRate].bitRateString,
953 dataBitsTable[portConfig.dataBits],
954 stopBitsTable[portConfig.stopBits],
955 parity[portConfig.parityMode],
956 portConfig.flowCtrlMode ? "ON" : "OFF");
957 }
958 else if (err != AIO_SUCCESS)
959 {
960 fprintf (stderr, "Could not configure port: %d\n", err);
961 AIOReleasePort (AIOhandle);
962 exit (1);
963 }
964
965 if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
966 (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
967 != AIO_SUCCESS)
968 {
969 LONG extStatus, chgdExtStatus;
970
971 fprintf (stderr, "Could not set desired port controls!\n");
972 AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
973 fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
974 chgdExtStatus);
975 }
976
977 /* Register ourselves as an alternate debugger. */
978 memset (&s, 0, sizeof s);
979 s.DDSResourceTag = ((struct ResourceTagStructure *)
980 AllocateResourceTag (GetNLMHandle (),
981 (BYTE *)"gdbserver",
982 DebuggerSignature));
983 if (s.DDSResourceTag == 0)
984 {
985 fprintf (stderr, "AllocateResourceTag failed\n");
986 AIOReleasePort (AIOhandle);
987 exit (1);
988 }
989 s.DDSdebuggerEntry = handle_exception;
990 s.DDSFlags = TSS_FRAME_BIT;
991
992 err = RegisterDebuggerRTag (&s, AT_FIRST);
993 if (err != 0)
994 {
995 fprintf (stderr, "RegisterDebuggerRTag failed\n");
996 AIOReleasePort (AIOhandle);
997 exit (1);
998 }
999
1000 /* Get the command line we were invoked with, and advance it past
1001 our name and the board and port arguments. */
1002 cmdlin = getcmd ((char *) NULL);
1003 for (i = 0; i < cmdindx; i++)
1004 {
1005 while (! isspace (*cmdlin))
1006 ++cmdlin;
1007 while (isspace (*cmdlin))
1008 ++cmdlin;
1009 }
1010
1011 /* In case GDB is started before us, ack any packets (presumably
1012 "$?#xx") sitting there. */
1013 if (! putDebugChar ('+'))
1014 {
1015 fprintf (stderr, "putDebugChar failed\n");
1016 UnRegisterDebugger (&s);
1017 AIOReleasePort (AIOhandle);
1018 exit (1);
1019 }
1020
1021 mainthread = GetThreadID ();
1022
1023 if (remote_debug > 0)
1024 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1025 cmdlin, __GetScreenID (GetCurrentScreen()));
1026
1027 /* Start up the module to be debugged. */
1028 err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1029 (BYTE *)cmdlin, LO_DEBUG);
1030 if (err != 0)
1031 {
1032 fprintf (stderr, "LoadModule failed: %d\n", err);
1033 UnRegisterDebugger (&s);
1034 AIOReleasePort (AIOhandle);
1035 exit (1);
1036 }
1037
1038 /* Wait for the debugger to wake us up. */
1039 if (remote_debug > 0)
1040 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1041 SuspendThread (mainthread);
1042 if (remote_debug > 0)
1043 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1044
1045 /* If we are woken up, print an optional error message, deregister
1046 ourselves and exit. */
1047 if (error_message != NULL)
1048 fprintf (stderr, "%s\n", error_message);
1049 UnRegisterDebugger (&s);
1050 AIOReleasePort (AIOhandle);
1051 exit (0);
1052 }
This page took 0.065364 seconds and 4 git commands to generate.