* nlm/gdbserve.c: conditionalize header file inclusion for either
[deliverable/binutils-gdb.git] / gdb / nlm / gdbserve.c
CommitLineData
27847c6f
SG
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
27847c6f
SG
69#include <stdio.h>
70#include <string.h>
71#include <stdlib.h>
27847c6f 72#include <time.h>
86165efc
C
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>
27847c6f
SG
83#include <nwconio.h>
84#include <nwadv.h>
85#include <nwdbgapi.h>
27847c6f 86#include <nwthread.h>
86165efc 87#endif
b7da2494 88#include <aio.h>
86165efc 89
b7da2494 90#include "cpu.h"
27847c6f 91
86165efc 92
27847c6f
SG
93/****************************************************/
94/* This information is from Novell. It is not in any of the standard
95 NetWare header files. */
96
97struct 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. */
136static int mainthread;
137
138/* An error message for the main thread to print. */
139static char *error_message;
140
141/* The AIO port handle. */
142static 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. */
150static int remote_debug = 1;
151
152static const char hexchars[] = "0123456789abcdef";
153
2e6784a8 154unsigned char breakpoint_insn[] = BREAKPOINT;
27847c6f 155
b7da2494
SG
156char *mem2hex (void *mem, char *buf, int count, int may_fault);
157char *hex2mem (char *buf, void *mem, int count, int may_fault);
158extern void set_step_traps (struct StackFrame *);
159extern void clear_step_traps (struct StackFrame *);
27847c6f
SG
160
161#if 0
162__main() {};
163#endif
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
168static int
169getDebugChar ()
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
193static int
194putDebugChar (c)
195 unsigned char c;
196{
197 int err;
198 LONG put;
199
5a3a28f2
SG
200 put = 0;
201 while (put < 1)
27847c6f 202 {
5a3a28f2
SG
203 err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
204 if (err != 0)
205 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
27847c6f
SG
206 }
207 return 1;
208}
209
27847c6f
SG
210/* Turn a hex character into a number. */
211
212static int
213hex (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
228static int
229getpacket (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
314static int
315putpacket (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
355static char remcomInBuffer[BUFMAX];
356static char remcomOutBuffer[BUFMAX];
357static short error;
358
359static void
360debug_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. */
372static int mem_may_fault;
373
374/* Indicate to caller of mem2hex or hex2mem that there has been an
375 error. */
b7da2494 376volatile int mem_err = 0;
27847c6f 377
b7da2494 378#ifndef ALTERNATE_MEM_FUNCS
27847c6f
SG
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
384static int
385get_char (addr)
386 char *addr;
387{
388 return *addr;
389}
390
391static void
392set_char (addr, val)
393 char *addr;
394 int val;
395{
396 *addr = val;
397}
b7da2494 398#endif /* ALTERNATE_MEM_FUNCS */
27847c6f
SG
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
b7da2494 405char *
27847c6f
SG
406mem2hex (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
b7da2494 433char *
27847c6f
SG
434hex2mem (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;
5a3a28f2 442 char *ptr = mem;
27847c6f
SG
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)
5a3a28f2 451 return (ptr);
27847c6f
SG
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
b7da2494 460int
27847c6f
SG
461computeSignal (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/**********************************************/
492static int
493hexToInt(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
27847c6f
SG
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
523static LONG
5a3a28f2
SG
524handle_exception (frame)
525 struct StackFrame *frame;
27847c6f
SG
526{
527 int addr, length;
528 char *ptr;
529 static struct DBG_LoadDefinitionStructure *ldinfo = 0;
2e6784a8 530 static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program. */
27847c6f
SG
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,
2e6784a8 541 frame->ExceptionPC,
27847c6f
SG
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);
2e6784a8
SG
554 memcpy (first_insn, ldinfo->LDInitializationProcedure,
555 BREAKPOINT_SIZE);
556 memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
557 BREAKPOINT_SIZE);
27847c6f
SG
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. */
2e6784a8
SG
569 if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
570 && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
571 BREAKPOINT_SIZE) == 0)
27847c6f 572 {
2e6784a8
SG
573 memcpy (ldinfo->LDInitializationProcedure, first_insn,
574 BREAKPOINT_SIZE);
575 frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
27847c6f
SG
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
2e6784a8
SG
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)))
27847c6f
SG
603 {
604 mem_err = 1;
605 /* Point the instruction pointer at an assembly language stub
606 which just returns from the function. */
607
2e6784a8 608 frame->ExceptionPC += 4; /* Skip the load or store */
27847c6f
SG
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
2e6784a8 630 clear_step_traps (frame);
27847c6f
SG
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')
2e6784a8 735 set_step_traps (frame);
27847c6f
SG
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
1e47d512 765char *progname;
27847c6f 766
1e47d512
C
767struct bitRate {
768 BYTE bitRate;
769 const char *bitRateString;
770};
771
772struct 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
796char dataBitsTable[] = "5678";
27847c6f 797
1e47d512 798char *stopBitsTable[] = { "1", "1.5", "2" };
27847c6f
SG
799
800char 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
808int
809main (argc, argv)
810 int argc;
811 char **argv;
812{
813 int hardware, board, port;
1e47d512
C
814 BYTE bitRate;
815 BYTE dataBits;
816 BYTE stopBits;
817 BYTE parityMode;
27847c6f
SG
818 LONG err;
819 struct debuggerStructure s;
1e47d512 820 int cmdindx;
27847c6f
SG
821 char *cmdlin;
822 int i;
823
1e47d512
C
824 /* set progname */
825 progname = "gdbserve";
27847c6f 826
1e47d512
C
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++)
27847c6f 840 {
1e47d512
C
841 char *bp;
842 char *ep;
843
844 if (strnicmp(*argv, "BAUD=", 5) == 0)
845 {
846 struct bitRate *brp;
847
848 bp = *argv + 5;
849 for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++)
850 {
851 if (strcmp(brp->bitRateString, bp) == 0)
852 {
853 bitRate = brp->bitRate;
854 break;
855 }
856 }
857
858 if (brp->bitRateString == NULL)
859 {
860 fprintf(stderr, "%s: %s: unknown or unsupported bit rate",
861 progname, bp);
862 exit (1);
863 }
864 }
865 else if (strnicmp(*argv, "NODE=", 5) == 0)
866 {
867 bp = *argv + 5;
868 board = strtol (bp, &ep, 0);
869 if (ep == bp || *ep != '\0')
870 {
871 fprintf (stderr, "%s: %s: expected integer argument\n",
872 progname, bp);
873 exit(1);
874 }
875 }
876 else if (strnicmp(*argv, "PORT=", 5) == 0)
877 {
878 bp = *argv + 5;
879 port = strtol (bp, &ep, 0);
880 if (ep == bp || *ep != '\0')
881 {
882 fprintf (stderr, "%s: %s: expected integer argument\n",
883 progname, bp);
884 exit(1);
885 }
886 }
887 else
888 {
889 break;
890 }
891
892 cmdindx++;
27847c6f
SG
893 }
894
1e47d512 895 if (argc == 0)
27847c6f
SG
896 {
897 fprintf (stderr,
1e47d512 898 "Usage: load %s [options] program [arguments]\n", progname);
27847c6f
SG
899 exit (1);
900 }
901
27847c6f
SG
902 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
903 if (err != AIO_SUCCESS)
904 {
905 switch (err)
906 {
907 case AIO_PORT_NOT_AVAILABLE:
908 fprintf (stderr, "Port not available\n");
909 break;
910
911 case AIO_BOARD_NUMBER_INVALID:
912 case AIO_PORT_NUMBER_INVALID:
913 fprintf (stderr, "No such port\n");
914 break;
915
916 default:
917 fprintf (stderr, "Could not open port: %d\n", err);
918 break;
919 }
920
921 exit (1);
922 }
923
1e47d512 924 err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
27847c6f
SG
925 AIO_HARDWARE_FLOW_CONTROL_OFF);
926
927 if (err == AIO_QUALIFIED_SUCCESS)
928 {
929 AIOPORTCONFIG portConfig;
27847c6f
SG
930
931 fprintf (stderr, "Port configuration changed!\n");
1e47d512
C
932
933 portConfig.returnLength = sizeof(portConfig);
934 AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
935
27847c6f
SG
936 fprintf (stderr,
937 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
938 Flow:%s\n",
1e47d512
C
939 bitRateTable[portConfig.bitRate].bitRateString,
940 dataBitsTable[portConfig.dataBits],
941 stopBitsTable[portConfig.stopBits],
27847c6f
SG
942 parity[portConfig.parityMode],
943 portConfig.flowCtrlMode ? "ON" : "OFF");
944 }
945 else if (err != AIO_SUCCESS)
946 {
947 fprintf (stderr, "Could not configure port: %d\n", err);
948 AIOReleasePort (AIOhandle);
949 exit (1);
950 }
951
952 if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
953 (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
954 != AIO_SUCCESS)
955 {
956 LONG extStatus, chgdExtStatus;
957
958 fprintf (stderr, "Could not set desired port controls!\n");
959 AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
960 fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
961 chgdExtStatus);
962 }
963
964 /* Register ourselves as an alternate debugger. */
965 memset (&s, 0, sizeof s);
966 s.DDSResourceTag = ((struct ResourceTagStructure *)
967 AllocateResourceTag (GetNLMHandle (),
968 (BYTE *)"gdbserver",
969 DebuggerSignature));
970 if (s.DDSResourceTag == 0)
971 {
972 fprintf (stderr, "AllocateResourceTag failed\n");
973 AIOReleasePort (AIOhandle);
974 exit (1);
975 }
976 s.DDSdebuggerEntry = handle_exception;
977 s.DDSFlags = TSS_FRAME_BIT;
978
979 err = RegisterDebuggerRTag (&s, AT_FIRST);
980 if (err != 0)
981 {
982 fprintf (stderr, "RegisterDebuggerRTag failed\n");
983 AIOReleasePort (AIOhandle);
984 exit (1);
985 }
986
987 /* Get the command line we were invoked with, and advance it past
988 our name and the board and port arguments. */
989 cmdlin = getcmd ((char *) NULL);
1e47d512 990 for (i = 0; i < cmdindx; i++)
27847c6f
SG
991 {
992 while (! isspace (*cmdlin))
993 ++cmdlin;
994 while (isspace (*cmdlin))
995 ++cmdlin;
996 }
997
998 /* In case GDB is started before us, ack any packets (presumably
999 "$?#xx") sitting there. */
1000 if (! putDebugChar ('+'))
1001 {
1002 fprintf (stderr, "putDebugChar failed\n");
1003 UnRegisterDebugger (&s);
1004 AIOReleasePort (AIOhandle);
1005 exit (1);
1006 }
1007
1008 mainthread = GetThreadID ();
1009
1010 if (remote_debug > 0)
5a3a28f2
SG
1011 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1012 cmdlin, __GetScreenID (GetCurrentScreen()));
27847c6f
SG
1013
1014 /* Start up the module to be debugged. */
1015 err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1016 (BYTE *)cmdlin, LO_DEBUG);
1017 if (err != 0)
1018 {
1019 fprintf (stderr, "LoadModule failed: %d\n", err);
1020 UnRegisterDebugger (&s);
1021 AIOReleasePort (AIOhandle);
1022 exit (1);
1023 }
1024
1025 /* Wait for the debugger to wake us up. */
1026 if (remote_debug > 0)
5a3a28f2 1027 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
27847c6f
SG
1028 SuspendThread (mainthread);
1029 if (remote_debug > 0)
5a3a28f2 1030 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
27847c6f
SG
1031
1032 /* If we are woken up, print an optional error message, deregister
1033 ourselves and exit. */
1034 if (error_message != NULL)
1035 fprintf (stderr, "%s\n", error_message);
1036 UnRegisterDebugger (&s);
1037 AIOReleasePort (AIOhandle);
1038 exit (0);
1039}
This page took 0.079238 seconds and 4 git commands to generate.