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