1 /* gdbserve.c -- NLM debugging stub for Novell NetWare.
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.
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. */
14 /****************************************************************************
16 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
26 ****************************************************************************/
28 /****************************************************************************
30 * The following gdb commands are supported:
32 * command function Return value
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
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
40 * c Resume at current address SNN ( signal NN)
41 * cAA..AA Continue at address AA..AA SNN
43 * s Step one instruction SNN
44 * sAA..AA Step one instruction from AA..AA SNN
48 * ? What was the last sigval ? SNN (signal NN)
50 * All commands and responses are sent with a packet which includes a
51 * checksum. A packet consists of
53 * $<packet info>#<checksum>.
56 * <packet info> :: <characters representing the command or response>
57 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
59 * When a packet is received, it is first acknowledged with either '+' or '-'.
60 * '+' indicates a successful transfer. '-' indicates a failed transfer.
65 * $m0,10#2a +$00010203040506070809101112131415#42
67 ****************************************************************************/
95 /****************************************************/
96 /* This information is from Novell. It is not in any of the standard
97 NetWare header files. */
99 struct DBG_LoadDefinitionStructure
103 LONG LDCodeImageOffset
;
104 LONG LDCodeImageLength
;
105 LONG LDDataImageOffset
;
106 LONG LDDataImageLength
;
107 LONG LDUninitializedDataLength
;
108 LONG LDCustomDataOffset
;
109 LONG LDCustomDataSize
;
111 LONG (*LDInitializationProcedure
)(void);
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
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 /****************************************************/
137 /* The main thread ID. */
138 static int mainthread
;
140 /* An error message for the main thread to print. */
141 static char *error_message
;
143 /* The AIO port handle. */
144 static int AIOhandle
;
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)
150 /* remote_debug > 0 prints ill-formed commands in valid packets and
152 static int remote_debug
= 1;
154 static const char hexchars
[] = "0123456789abcdef";
156 unsigned char breakpoint_insn
[] = BREAKPOINT
;
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
*);
163 static int __main() {};
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. */
177 err
= AIOReadData (AIOhandle
, (char *) &ret
, 1, &got
);
180 error_message
= "AIOReadData failed";
181 ResumeThread (mainthread
);
190 /* Write a character to the serial port. Returns 0 on failure,
191 non-zero on success. */
194 putDebugChar (unsigned char c
)
202 err
= AIOWriteData (AIOhandle
, (char *) &c
, 1, &put
);
204 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err
, put
);
209 /* Turn a hex character into a number. */
214 if ((ch
>= 'a') && (ch
<= 'f'))
216 if ((ch
>= '0') && (ch
<= '9'))
218 if ((ch
>= 'A') && (ch
<= 'F'))
223 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
224 non-zero on success. */
227 getpacket (char *buffer
)
229 unsigned char checksum
;
230 unsigned char xmitcsum
;
237 /* wait around for the start character, ignore all other characters */
238 while ((ch
= getDebugChar()) != '$')
246 /* now, read until a # or end of buffer is found */
247 while (count
< BUFMAX
)
254 checksum
= checksum
+ ch
;
262 ch
= getDebugChar ();
265 xmitcsum
= hex(ch
) << 4;
266 ch
= getDebugChar ();
271 if (checksum
!= xmitcsum
)
274 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
275 checksum
,xmitcsum
,buffer
);
276 /* failed checksum */
277 if (! putDebugChar('-'))
283 /* successful transfer */
284 if (! putDebugChar('+'))
286 /* if a sequence char is present, reply the sequence ID */
287 if (buffer
[2] == ':')
289 if (! putDebugChar (buffer
[0])
290 || ! putDebugChar (buffer
[1]))
292 /* remove sequence chars from buffer */
293 count
= strlen(buffer
);
294 for (i
=3; i
<= count
; i
++)
295 buffer
[i
-3] = buffer
[i
];
300 while (checksum
!= xmitcsum
);
303 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
308 /* Send the packet in buffer. Returns 0 on failure, non-zero on
312 putpacket (char *buffer
)
314 unsigned char checksum
;
319 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
321 /* $<packet info>#<checksum>. */
324 if (! putDebugChar('$'))
329 while (ch
=buffer
[count
])
331 if (! putDebugChar(ch
))
337 if (! putDebugChar('#')
338 || ! putDebugChar(hexchars
[checksum
>> 4])
339 || ! putDebugChar(hexchars
[checksum
% 16]))
342 ch
= getDebugChar ();
351 static char remcomInBuffer
[BUFMAX
];
352 static char remcomOutBuffer
[BUFMAX
];
356 debug_error (char *format
, char *parm
)
360 ConsolePrintf (format
, parm
);
361 ConsolePrintf ("\n");
365 /* This is set if we could get a memory access fault. */
366 static int mem_may_fault
;
368 /* Indicate to caller of mem2hex or hex2mem that there has been an
370 volatile int mem_err
= 0;
372 #ifndef ALTERNATE_MEM_FUNCS
373 /* These are separate functions so that they are so short and sweet
374 that the compiler won't save any registers (if there is a fault
375 to mem_fault, they won't get restored, so there better not be any
379 get_char (char *addr
)
385 set_char (char *addr
, int val
)
389 #endif /* ALTERNATE_MEM_FUNCS */
391 /* convert the memory pointed to by mem into hex, placing result in buf */
392 /* return a pointer to the last char put in buf (null) */
393 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
394 a fault; if zero treat a fault like any other fault in the stub. */
397 mem2hex (void *mem
, char *buf
, int count
, int may_fault
)
403 mem_may_fault
= may_fault
;
404 for (i
= 0; i
< count
; i
++)
406 ch
= get_char (ptr
++);
407 if (may_fault
&& mem_err
)
409 *buf
++ = hexchars
[ch
>> 4];
410 *buf
++ = hexchars
[ch
% 16];
417 /* convert the hex array pointed to by buf into binary to be placed in mem */
418 /* return a pointer to the character AFTER the last byte written */
421 hex2mem (char *buf
, void *mem
, int count
, int may_fault
)
427 mem_may_fault
= may_fault
;
428 for (i
=0;i
<count
;i
++)
430 ch
= hex(*buf
++) << 4;
431 ch
= ch
+ hex(*buf
++);
432 set_char (ptr
++, ch
);
433 if (may_fault
&& mem_err
)
440 /* This function takes the 386 exception vector and attempts to
441 translate this number into a unix compatible signal value. */
444 computeSignal (int exceptionVector
)
447 switch (exceptionVector
)
449 case 0 : sigval
= 8; break; /* divide by zero */
450 case 1 : sigval
= 5; break; /* debug exception */
451 case 3 : sigval
= 5; break; /* breakpoint */
452 case 4 : sigval
= 16; break; /* into instruction (overflow) */
453 case 5 : sigval
= 16; break; /* bound instruction */
454 case 6 : sigval
= 4; break; /* Invalid opcode */
455 case 7 : sigval
= 8; break; /* coprocessor not available */
456 case 8 : sigval
= 7; break; /* double fault */
457 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
458 case 10 : sigval
= 11; break; /* Invalid TSS */
459 case 11 : sigval
= 11; break; /* Segment not present */
460 case 12 : sigval
= 11; break; /* stack exception */
461 case 13 : sigval
= 11; break; /* general protection */
462 case 14 : sigval
= 11; break; /* page fault */
463 case 16 : sigval
= 7; break; /* coprocessor error */
465 sigval
= 7; /* "software generated"*/
470 /**********************************************/
471 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
472 /* RETURN NUMBER OF CHARS PROCESSED */
473 /**********************************************/
475 hexToInt (char **ptr
, int *intValue
)
484 hexValue
= hex(**ptr
);
487 *intValue
= (*intValue
<<4) | hexValue
;
499 /* This function does all command processing for interfacing to gdb.
500 It is called whenever an exception occurs in the module being
504 handle_exception (struct StackFrame
*frame
)
508 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
509 static unsigned char first_insn
[BREAKPOINT_SIZE
]; /* The first instruction in the program. */
512 /* According to some documentation from Novell, the bell sometimes
513 may be ringing at this point. This can be stopped on Netware 4
514 systems by calling the undocumented StopBell() function. */
521 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
522 frame
->ExceptionNumber
,
523 frame
->ExceptionDescription
,
528 switch (frame
->ExceptionNumber
)
530 case START_NLM_EVENT
:
531 /* If the NLM just started, we record the module load information
532 and the thread ID, and set a breakpoint at the first instruction
535 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
536 frame
->ExceptionErrorCode
);
537 memcpy (first_insn
, ldinfo
->LDInitializationProcedure
,
539 memcpy (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
542 return RETURN_TO_PROGRAM
;
544 case ENTER_DEBUGGER_EVENT
:
545 case KEYBOARD_BREAK_EVENT
:
546 /* Pass some events on to the next debugger, in case it will handle
548 return RETURN_TO_NEXT_DEBUGGER
;
550 case 3: /* Breakpoint */
551 /* After we've reached the initial breakpoint, reset it. */
552 if (frame
->ExceptionPC
- DECR_PC_AFTER_BREAK
== (LONG
) ldinfo
->LDInitializationProcedure
553 && memcmp (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
554 BREAKPOINT_SIZE
) == 0)
556 memcpy (ldinfo
->LDInitializationProcedure
, first_insn
,
558 frame
->ExceptionPC
-= DECR_PC_AFTER_BREAK
;
561 /* Normal breakpoints end up here */
562 do_status (remcomOutBuffer
, frame
);
566 /* At the moment, we don't care about most of the unusual NetWare
568 if (frame
->ExceptionNumber
> 31)
569 return RETURN_TO_PROGRAM
;
571 /* Most machine level exceptions end up here */
572 do_status (remcomOutBuffer
, frame
);
575 case 11: /* Segment not present */
576 case 13: /* General protection */
577 case 14: /* Page fault */
578 /* If we get a GP fault, and mem_may_fault is set, and the
579 instruction pointer is near set_char or get_char, then we caused
580 the fault ourselves accessing an illegal memory location. */
582 && ((frame
->ExceptionPC
>= (long) &set_char
583 && frame
->ExceptionPC
< (long) &set_char
+ 50)
584 || (frame
->ExceptionPC
>= (long) &get_char
585 && frame
->ExceptionPC
< (long) &get_char
+ 50)))
588 /* Point the instruction pointer at an assembly language stub
589 which just returns from the function. */
591 frame
->ExceptionPC
+= 4; /* Skip the load or store */
593 /* Keep going. This will act as though it returned from
594 set_char or get_char. The calling routine will check
595 mem_err, and do the right thing. */
596 return RETURN_TO_PROGRAM
;
598 /* Random mem fault, report it */
599 do_status (remcomOutBuffer
, frame
);
602 case TERMINATE_NLM_EVENT
:
603 /* There is no way to get the exit status. */
604 sprintf (remcomOutBuffer
, "W%02x", 0);
605 break; /* We generate our own status */
608 /* FIXME: How do we know that this exception has anything to do with
609 the program we are debugging? We can check whether the PC is in
610 the range of the module we are debugging, but that doesn't help
611 much since an error could occur in a library routine. */
613 clear_step_traps (frame
);
615 if (! putpacket(remcomOutBuffer
))
616 return RETURN_TO_NEXT_DEBUGGER
;
618 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
620 ResumeThread (mainthread
);
621 return RETURN_TO_PROGRAM
;
627 remcomOutBuffer
[0] = 0;
628 if (! getpacket (remcomInBuffer
))
629 return RETURN_TO_NEXT_DEBUGGER
;
630 switch (remcomInBuffer
[0])
633 do_status (remcomOutBuffer
, frame
);
636 remote_debug
= !(remote_debug
); /* toggle debug flag */
639 /* return the value of the CPU registers */
640 frame_to_registers (frame
, remcomOutBuffer
);
643 /* set the value of the CPU registers - return OK */
644 registers_to_frame (&remcomInBuffer
[1], frame
);
645 strcpy(remcomOutBuffer
,"OK");
649 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
650 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
651 ptr
= &remcomInBuffer
[1];
652 if (hexToInt(&ptr
,&addr
))
654 if (hexToInt(&ptr
,&length
))
658 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
661 strcpy (remcomOutBuffer
, "E03");
662 debug_error ("memory fault");
668 strcpy(remcomOutBuffer
,"E01");
669 debug_error("malformed read memory command: %s",remcomInBuffer
);
674 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
675 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
676 ptr
= &remcomInBuffer
[1];
677 if (hexToInt(&ptr
,&addr
))
679 if (hexToInt(&ptr
,&length
))
683 hex2mem(ptr
, (char*) addr
, length
, 1);
687 strcpy (remcomOutBuffer
, "E03");
688 debug_error ("memory fault");
692 strcpy(remcomOutBuffer
,"OK");
699 strcpy(remcomOutBuffer
,"E02");
700 debug_error("malformed write memory command: %s",remcomInBuffer
);
706 /* cAA..AA Continue at address AA..AA(optional) */
707 /* sAA..AA Step one instruction from AA..AA(optional) */
708 /* try to read optional parameter, pc unchanged if no parm */
709 ptr
= &remcomInBuffer
[1];
710 if (hexToInt(&ptr
,&addr
))
712 /* registers[PC_REGNUM].lo = addr;*/
713 fprintf (stderr
, "Setting PC to 0x%x\n", addr
);
717 if (remcomInBuffer
[0] == 's')
718 set_step_traps (frame
);
721 return RETURN_TO_PROGRAM
;
724 /* kill the program */
726 ResumeThread (mainthread
);
727 return RETURN_TO_PROGRAM
;
729 case 'q': /* Query message */
730 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
732 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
733 ldinfo
->LDCodeImageOffset
,
734 ldinfo
->LDDataImageOffset
,
735 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
738 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
742 /* reply to the request */
743 if (! putpacket(remcomOutBuffer
))
744 return RETURN_TO_NEXT_DEBUGGER
;
752 const char *bitRateString
;
755 struct bitRate bitRateTable
[] =
757 { AIO_BAUD_50
, "50" },
758 { AIO_BAUD_75
, "75" },
759 { AIO_BAUD_110
, "110" },
760 { AIO_BAUD_134p5
, "134.5" },
761 { AIO_BAUD_150
, "150" },
762 { AIO_BAUD_300
, "300" },
763 { AIO_BAUD_600
, "600" },
764 { AIO_BAUD_1200
, "1200" },
765 { AIO_BAUD_1800
, "1800" },
766 { AIO_BAUD_2000
, "2000" },
767 { AIO_BAUD_2400
, "2400" },
768 { AIO_BAUD_3600
, "3600" },
769 { AIO_BAUD_4800
, "4800" },
770 { AIO_BAUD_7200
, "7200" },
771 { AIO_BAUD_9600
, "9600" },
772 { AIO_BAUD_19200
, "19200" },
773 { AIO_BAUD_38400
, "38400" },
774 { AIO_BAUD_57600
, "57600" },
775 { AIO_BAUD_115200
, "115200" },
779 char dataBitsTable
[] = "5678";
781 char *stopBitsTable
[] = { "1", "1.5", "2" };
783 char parity
[] = "NOEMS";
785 /* Start up. The main thread opens the named serial I/O port, loads
786 the named NLM module and then goes to sleep. The serial I/O port
787 is named as a board number and a port number. It would be more DOS
788 like to provide a menu of available serial ports, but I don't want
789 to have to figure out how to do that. */
792 main (int argc
, char **argv
)
794 int hardware
, board
, port
;
800 struct debuggerStructure s
;
806 progname
= "gdbserve";
808 /* set default serial line */
813 /* set default serial line characteristics */
814 bitRate
= AIO_BAUD_9600
;
815 dataBits
= AIO_DATA_BITS_8
;
816 stopBits
= AIO_STOP_BITS_1
;
817 parityMode
= AIO_PARITY_NONE
;
820 for (argc
--, argv
++; *argv
; argc
--, argv
++)
825 if (strnicmp(*argv
, "BAUD=", 5) == 0)
830 for (brp
= bitRateTable
; brp
->bitRate
!= (BYTE
) -1; brp
++)
832 if (strcmp(brp
->bitRateString
, bp
) == 0)
834 bitRate
= brp
->bitRate
;
839 if (brp
->bitRateString
== NULL
)
841 fprintf(stderr
, "%s: %s: unknown or unsupported bit rate",
846 else if (strnicmp(*argv
, "BOARD=", 6) == 0)
849 board
= strtol (bp
, &ep
, 0);
850 if (ep
== bp
|| *ep
!= '\0')
852 fprintf (stderr
, "%s: %s: expected integer argument\n",
857 #if 1 /* FIXME: this option has been depricated */
858 else if (strnicmp(*argv
, "NODE=", 5) == 0)
861 board
= strtol (bp
, &ep
, 0);
862 if (ep
== bp
|| *ep
!= '\0')
864 fprintf (stderr
, "%s: %s: expected integer argument\n",
870 else if (strnicmp(*argv
, "PORT=", 5) == 0)
873 port
= strtol (bp
, &ep
, 0);
874 if (ep
== bp
|| *ep
!= '\0')
876 fprintf (stderr
, "%s: %s: expected integer argument\n",
892 "Usage: load %s [options] program [arguments]\n", progname
);
896 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
897 if (err
!= AIO_SUCCESS
)
901 case AIO_PORT_NOT_AVAILABLE
:
902 fprintf (stderr
, "Port not available\n");
905 case AIO_BOARD_NUMBER_INVALID
:
906 case AIO_PORT_NUMBER_INVALID
:
907 fprintf (stderr
, "No such port\n");
911 fprintf (stderr
, "Could not open port: %d\n", err
);
918 err
= AIOConfigurePort (AIOhandle
, bitRate
, dataBits
, stopBits
, parityMode
,
919 AIO_HARDWARE_FLOW_CONTROL_OFF
);
921 if (err
== AIO_QUALIFIED_SUCCESS
)
923 AIOPORTCONFIG portConfig
;
925 fprintf (stderr
, "Port configuration changed!\n");
927 portConfig
.returnLength
= sizeof(portConfig
);
928 AIOGetPortConfiguration (AIOhandle
, &portConfig
, NULL
);
931 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
933 bitRateTable
[portConfig
.bitRate
].bitRateString
,
934 dataBitsTable
[portConfig
.dataBits
],
935 stopBitsTable
[portConfig
.stopBits
],
936 parity
[portConfig
.parityMode
],
937 portConfig
.flowCtrlMode
? "ON" : "OFF");
939 else if (err
!= AIO_SUCCESS
)
941 fprintf (stderr
, "Could not configure port: %d\n", err
);
942 AIOReleasePort (AIOhandle
);
946 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
947 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
950 LONG extStatus
, chgdExtStatus
;
952 fprintf (stderr
, "Could not set desired port controls!\n");
953 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
954 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
958 /* Register ourselves as an alternate debugger. */
959 memset (&s
, 0, sizeof s
);
960 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
961 AllocateResourceTag (GetNLMHandle (),
964 if (s
.DDSResourceTag
== 0)
966 fprintf (stderr
, "AllocateResourceTag failed\n");
967 AIOReleasePort (AIOhandle
);
970 s
.DDSdebuggerEntry
= handle_exception
;
971 s
.DDSFlags
= TSS_FRAME_BIT
;
973 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
976 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
977 AIOReleasePort (AIOhandle
);
981 /* Get the command line we were invoked with, and advance it past
982 our name and the board and port arguments. */
983 cmdlin
= getcmd ((char *) NULL
);
984 for (i
= 0; i
< cmdindx
; i
++)
986 while (! isspace (*cmdlin
))
988 while (isspace (*cmdlin
))
992 /* In case GDB is started before us, ack any packets (presumably
993 "$?#xx") sitting there. */
994 if (! putDebugChar ('+'))
996 fprintf (stderr
, "putDebugChar failed\n");
997 UnRegisterDebugger (&s
);
998 AIOReleasePort (AIOhandle
);
1002 mainthread
= GetThreadID ();
1004 if (remote_debug
> 0)
1005 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1006 cmdlin
, __GetScreenID (GetCurrentScreen()));
1008 /* Start up the module to be debugged. */
1009 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1010 (BYTE
*)cmdlin
, LO_DEBUG
);
1013 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1014 UnRegisterDebugger (&s
);
1015 AIOReleasePort (AIOhandle
);
1019 /* Wait for the debugger to wake us up. */
1020 if (remote_debug
> 0)
1021 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1022 SuspendThread (mainthread
);
1023 if (remote_debug
> 0)
1024 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1026 /* If we are woken up, print an optional error message, deregister
1027 ourselves and exit. */
1028 if (error_message
!= NULL
)
1029 fprintf (stderr
, "%s\n", error_message
);
1030 UnRegisterDebugger (&s
);
1031 AIOReleasePort (AIOhandle
);