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. */
203 err
= AIOWriteData (AIOhandle
, (char *) &c
, 1, &put
);
205 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err
, put
);
210 /* Turn a hex character into a number. */
216 if ((ch
>= 'a') && (ch
<= 'f'))
218 if ((ch
>= '0') && (ch
<= '9'))
220 if ((ch
>= 'A') && (ch
<= 'F'))
225 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
226 non-zero on success. */
232 unsigned char checksum
;
233 unsigned char xmitcsum
;
240 /* wait around for the start character, ignore all other characters */
241 while ((ch
= getDebugChar()) != '$')
249 /* now, read until a # or end of buffer is found */
250 while (count
< BUFMAX
)
257 checksum
= checksum
+ ch
;
265 ch
= getDebugChar ();
268 xmitcsum
= hex(ch
) << 4;
269 ch
= getDebugChar ();
274 if (checksum
!= xmitcsum
)
277 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
278 checksum
,xmitcsum
,buffer
);
279 /* failed checksum */
280 if (! putDebugChar('-'))
286 /* successful transfer */
287 if (! putDebugChar('+'))
289 /* if a sequence char is present, reply the sequence ID */
290 if (buffer
[2] == ':')
292 if (! putDebugChar (buffer
[0])
293 || ! putDebugChar (buffer
[1]))
295 /* remove sequence chars from buffer */
296 count
= strlen(buffer
);
297 for (i
=3; i
<= count
; i
++)
298 buffer
[i
-3] = buffer
[i
];
303 while (checksum
!= xmitcsum
);
306 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
311 /* Send the packet in buffer. Returns 0 on failure, non-zero on
318 unsigned char checksum
;
323 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
325 /* $<packet info>#<checksum>. */
328 if (! putDebugChar('$'))
333 while (ch
=buffer
[count
])
335 if (! putDebugChar(ch
))
341 if (! putDebugChar('#')
342 || ! putDebugChar(hexchars
[checksum
>> 4])
343 || ! putDebugChar(hexchars
[checksum
% 16]))
346 ch
= getDebugChar ();
355 static char remcomInBuffer
[BUFMAX
];
356 static char remcomOutBuffer
[BUFMAX
];
360 debug_error (format
, parm
)
366 ConsolePrintf (format
, parm
);
367 ConsolePrintf ("\n");
371 /* This is set if we could get a memory access fault. */
372 static int mem_may_fault
;
374 /* Indicate to caller of mem2hex or hex2mem that there has been an
376 volatile int mem_err
= 0;
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
398 #endif /* ALTERNATE_MEM_FUNCS */
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. */
406 mem2hex (mem
, buf
, count
, may_fault
)
416 mem_may_fault
= may_fault
;
417 for (i
= 0; i
< count
; i
++)
419 ch
= get_char (ptr
++);
420 if (may_fault
&& mem_err
)
422 *buf
++ = hexchars
[ch
>> 4];
423 *buf
++ = hexchars
[ch
% 16];
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 */
434 hex2mem (buf
, mem
, count
, may_fault
)
444 mem_may_fault
= may_fault
;
445 for (i
=0;i
<count
;i
++)
447 ch
= hex(*buf
++) << 4;
448 ch
= ch
+ hex(*buf
++);
449 set_char (ptr
++, ch
);
450 if (may_fault
&& mem_err
)
457 /* This function takes the 386 exception vector and attempts to
458 translate this number into a unix compatible signal value. */
461 computeSignal (exceptionVector
)
465 switch (exceptionVector
)
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 */
483 sigval
= 7; /* "software generated"*/
488 /**********************************************/
489 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
490 /* RETURN NUMBER OF CHARS PROCESSED */
491 /**********************************************/
493 hexToInt(ptr
, intValue
)
504 hexValue
= hex(**ptr
);
507 *intValue
= (*intValue
<<4) | hexValue
;
519 /* This function does all command processing for interfacing to gdb.
520 It is called whenever an exception occurs in the module being
524 handle_exception (frame
)
525 struct StackFrame
*frame
;
529 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
530 static unsigned char first_insn
[BREAKPOINT_SIZE
]; /* The first instruction in the program. */
533 /* According to some documentation from Novell, the bell sometimes
534 may be ringing at this point. This can be stopped on Netware 4
535 systems by calling the undocumented StopBell() function. */
542 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
543 frame
->ExceptionNumber
,
544 frame
->ExceptionDescription
,
549 switch (frame
->ExceptionNumber
)
551 case START_NLM_EVENT
:
552 /* If the NLM just started, we record the module load information
553 and the thread ID, and set a breakpoint at the first instruction
556 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
557 frame
->ExceptionErrorCode
);
558 memcpy (first_insn
, ldinfo
->LDInitializationProcedure
,
560 memcpy (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
563 return RETURN_TO_PROGRAM
;
565 case ENTER_DEBUGGER_EVENT
:
566 case KEYBOARD_BREAK_EVENT
:
567 /* Pass some events on to the next debugger, in case it will handle
569 return RETURN_TO_NEXT_DEBUGGER
;
571 case 3: /* Breakpoint */
572 /* After we've reached the initial breakpoint, reset it. */
573 if (frame
->ExceptionPC
- DECR_PC_AFTER_BREAK
== (LONG
) ldinfo
->LDInitializationProcedure
574 && memcmp (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
575 BREAKPOINT_SIZE
) == 0)
577 memcpy (ldinfo
->LDInitializationProcedure
, first_insn
,
579 frame
->ExceptionPC
-= DECR_PC_AFTER_BREAK
;
582 /* Normal breakpoints end up here */
583 do_status (remcomOutBuffer
, frame
);
587 /* At the moment, we don't care about most of the unusual NetWare
589 if (frame
->ExceptionNumber
> 31)
590 return RETURN_TO_PROGRAM
;
592 /* Most machine level exceptions end up here */
593 do_status (remcomOutBuffer
, frame
);
596 case 11: /* Segment not present */
597 case 13: /* General protection */
598 case 14: /* Page fault */
599 /* If we get a GP fault, and mem_may_fault is set, and the
600 instruction pointer is near set_char or get_char, then we caused
601 the fault ourselves accessing an illegal memory location. */
603 && ((frame
->ExceptionPC
>= (long) &set_char
604 && frame
->ExceptionPC
< (long) &set_char
+ 50)
605 || (frame
->ExceptionPC
>= (long) &get_char
606 && frame
->ExceptionPC
< (long) &get_char
+ 50)))
609 /* Point the instruction pointer at an assembly language stub
610 which just returns from the function. */
612 frame
->ExceptionPC
+= 4; /* Skip the load or store */
614 /* Keep going. This will act as though it returned from
615 set_char or get_char. The calling routine will check
616 mem_err, and do the right thing. */
617 return RETURN_TO_PROGRAM
;
619 /* Random mem fault, report it */
620 do_status (remcomOutBuffer
, frame
);
623 case TERMINATE_NLM_EVENT
:
624 /* There is no way to get the exit status. */
625 sprintf (remcomOutBuffer
, "W%02x", 0);
626 break; /* We generate our own status */
629 /* FIXME: How do we know that this exception has anything to do with
630 the program we are debugging? We can check whether the PC is in
631 the range of the module we are debugging, but that doesn't help
632 much since an error could occur in a library routine. */
634 clear_step_traps (frame
);
636 if (! putpacket(remcomOutBuffer
))
637 return RETURN_TO_NEXT_DEBUGGER
;
639 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
641 ResumeThread (mainthread
);
642 return RETURN_TO_PROGRAM
;
648 remcomOutBuffer
[0] = 0;
649 if (! getpacket (remcomInBuffer
))
650 return RETURN_TO_NEXT_DEBUGGER
;
651 switch (remcomInBuffer
[0])
654 do_status (remcomOutBuffer
, frame
);
657 remote_debug
= !(remote_debug
); /* toggle debug flag */
660 /* return the value of the CPU registers */
661 frame_to_registers (frame
, remcomOutBuffer
);
664 /* set the value of the CPU registers - return OK */
665 registers_to_frame (&remcomInBuffer
[1], frame
);
666 strcpy(remcomOutBuffer
,"OK");
670 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
671 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
672 ptr
= &remcomInBuffer
[1];
673 if (hexToInt(&ptr
,&addr
))
675 if (hexToInt(&ptr
,&length
))
679 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
682 strcpy (remcomOutBuffer
, "E03");
683 debug_error ("memory fault");
689 strcpy(remcomOutBuffer
,"E01");
690 debug_error("malformed read memory command: %s",remcomInBuffer
);
695 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
696 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
697 ptr
= &remcomInBuffer
[1];
698 if (hexToInt(&ptr
,&addr
))
700 if (hexToInt(&ptr
,&length
))
704 hex2mem(ptr
, (char*) addr
, length
, 1);
708 strcpy (remcomOutBuffer
, "E03");
709 debug_error ("memory fault");
713 strcpy(remcomOutBuffer
,"OK");
720 strcpy(remcomOutBuffer
,"E02");
721 debug_error("malformed write memory command: %s",remcomInBuffer
);
727 /* cAA..AA Continue at address AA..AA(optional) */
728 /* sAA..AA Step one instruction from AA..AA(optional) */
729 /* try to read optional parameter, pc unchanged if no parm */
730 ptr
= &remcomInBuffer
[1];
731 if (hexToInt(&ptr
,&addr
))
733 /* registers[PC_REGNUM].lo = addr;*/
734 fprintf (stderr
, "Setting PC to 0x%x\n", addr
);
738 if (remcomInBuffer
[0] == 's')
739 set_step_traps (frame
);
742 return RETURN_TO_PROGRAM
;
745 /* kill the program */
747 ResumeThread (mainthread
);
748 return RETURN_TO_PROGRAM
;
750 case 'q': /* Query message */
751 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
753 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
754 ldinfo
->LDCodeImageOffset
,
755 ldinfo
->LDDataImageOffset
,
756 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
759 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
763 /* reply to the request */
764 if (! putpacket(remcomOutBuffer
))
765 return RETURN_TO_NEXT_DEBUGGER
;
773 const char *bitRateString
;
776 struct bitRate bitRateTable
[] =
778 { AIO_BAUD_50
, "50" },
779 { AIO_BAUD_75
, "75" },
780 { AIO_BAUD_110
, "110" },
781 { AIO_BAUD_134p5
, "134.5" },
782 { AIO_BAUD_150
, "150" },
783 { AIO_BAUD_300
, "300" },
784 { AIO_BAUD_600
, "600" },
785 { AIO_BAUD_1200
, "1200" },
786 { AIO_BAUD_1800
, "1800" },
787 { AIO_BAUD_2000
, "2000" },
788 { AIO_BAUD_2400
, "2400" },
789 { AIO_BAUD_3600
, "3600" },
790 { AIO_BAUD_4800
, "4800" },
791 { AIO_BAUD_7200
, "7200" },
792 { AIO_BAUD_9600
, "9600" },
793 { AIO_BAUD_19200
, "19200" },
794 { AIO_BAUD_38400
, "38400" },
795 { AIO_BAUD_57600
, "57600" },
796 { AIO_BAUD_115200
, "115200" },
800 char dataBitsTable
[] = "5678";
802 char *stopBitsTable
[] = { "1", "1.5", "2" };
804 char parity
[] = "NOEMS";
806 /* Start up. The main thread opens the named serial I/O port, loads
807 the named NLM module and then goes to sleep. The serial I/O port
808 is named as a board number and a port number. It would be more DOS
809 like to provide a menu of available serial ports, but I don't want
810 to have to figure out how to do that. */
817 int hardware
, board
, port
;
823 struct debuggerStructure s
;
829 progname
= "gdbserve";
831 /* set default serial line */
836 /* set default serial line characteristics */
837 bitRate
= AIO_BAUD_9600
;
838 dataBits
= AIO_DATA_BITS_8
;
839 stopBits
= AIO_STOP_BITS_1
;
840 parityMode
= AIO_PARITY_NONE
;
843 for (argc
--, argv
++; *argv
; argc
--, argv
++)
848 if (strnicmp(*argv
, "BAUD=", 5) == 0)
853 for (brp
= bitRateTable
; brp
->bitRate
!= (BYTE
) -1; brp
++)
855 if (strcmp(brp
->bitRateString
, bp
) == 0)
857 bitRate
= brp
->bitRate
;
862 if (brp
->bitRateString
== NULL
)
864 fprintf(stderr
, "%s: %s: unknown or unsupported bit rate",
869 else if (strnicmp(*argv
, "BOARD=", 6) == 0)
872 board
= strtol (bp
, &ep
, 0);
873 if (ep
== bp
|| *ep
!= '\0')
875 fprintf (stderr
, "%s: %s: expected integer argument\n",
880 #if 1 /* FIXME: this option has been depricated */
881 else if (strnicmp(*argv
, "NODE=", 5) == 0)
884 board
= strtol (bp
, &ep
, 0);
885 if (ep
== bp
|| *ep
!= '\0')
887 fprintf (stderr
, "%s: %s: expected integer argument\n",
893 else if (strnicmp(*argv
, "PORT=", 5) == 0)
896 port
= strtol (bp
, &ep
, 0);
897 if (ep
== bp
|| *ep
!= '\0')
899 fprintf (stderr
, "%s: %s: expected integer argument\n",
915 "Usage: load %s [options] program [arguments]\n", progname
);
919 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
920 if (err
!= AIO_SUCCESS
)
924 case AIO_PORT_NOT_AVAILABLE
:
925 fprintf (stderr
, "Port not available\n");
928 case AIO_BOARD_NUMBER_INVALID
:
929 case AIO_PORT_NUMBER_INVALID
:
930 fprintf (stderr
, "No such port\n");
934 fprintf (stderr
, "Could not open port: %d\n", err
);
941 err
= AIOConfigurePort (AIOhandle
, bitRate
, dataBits
, stopBits
, parityMode
,
942 AIO_HARDWARE_FLOW_CONTROL_OFF
);
944 if (err
== AIO_QUALIFIED_SUCCESS
)
946 AIOPORTCONFIG portConfig
;
948 fprintf (stderr
, "Port configuration changed!\n");
950 portConfig
.returnLength
= sizeof(portConfig
);
951 AIOGetPortConfiguration (AIOhandle
, &portConfig
, NULL
);
954 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
956 bitRateTable
[portConfig
.bitRate
].bitRateString
,
957 dataBitsTable
[portConfig
.dataBits
],
958 stopBitsTable
[portConfig
.stopBits
],
959 parity
[portConfig
.parityMode
],
960 portConfig
.flowCtrlMode
? "ON" : "OFF");
962 else if (err
!= AIO_SUCCESS
)
964 fprintf (stderr
, "Could not configure port: %d\n", err
);
965 AIOReleasePort (AIOhandle
);
969 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
970 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
973 LONG extStatus
, chgdExtStatus
;
975 fprintf (stderr
, "Could not set desired port controls!\n");
976 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
977 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
981 /* Register ourselves as an alternate debugger. */
982 memset (&s
, 0, sizeof s
);
983 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
984 AllocateResourceTag (GetNLMHandle (),
987 if (s
.DDSResourceTag
== 0)
989 fprintf (stderr
, "AllocateResourceTag failed\n");
990 AIOReleasePort (AIOhandle
);
993 s
.DDSdebuggerEntry
= handle_exception
;
994 s
.DDSFlags
= TSS_FRAME_BIT
;
996 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
999 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
1000 AIOReleasePort (AIOhandle
);
1004 /* Get the command line we were invoked with, and advance it past
1005 our name and the board and port arguments. */
1006 cmdlin
= getcmd ((char *) NULL
);
1007 for (i
= 0; i
< cmdindx
; i
++)
1009 while (! isspace (*cmdlin
))
1011 while (isspace (*cmdlin
))
1015 /* In case GDB is started before us, ack any packets (presumably
1016 "$?#xx") sitting there. */
1017 if (! putDebugChar ('+'))
1019 fprintf (stderr
, "putDebugChar failed\n");
1020 UnRegisterDebugger (&s
);
1021 AIOReleasePort (AIOhandle
);
1025 mainthread
= GetThreadID ();
1027 if (remote_debug
> 0)
1028 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1029 cmdlin
, __GetScreenID (GetCurrentScreen()));
1031 /* Start up the module to be debugged. */
1032 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1033 (BYTE
*)cmdlin
, LO_DEBUG
);
1036 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1037 UnRegisterDebugger (&s
);
1038 AIOReleasePort (AIOhandle
);
1042 /* Wait for the debugger to wake us up. */
1043 if (remote_debug
> 0)
1044 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1045 SuspendThread (mainthread
);
1046 if (remote_debug
> 0)
1047 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1049 /* If we are woken up, print an optional error message, deregister
1050 ourselves and exit. */
1051 if (error_message
!= NULL
)
1052 fprintf (stderr
, "%s\n", error_message
);
1053 UnRegisterDebugger (&s
);
1054 AIOReleasePort (AIOhandle
);