1 /* i386-nlmstub.c -- NLM debugging stub for the i386.
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 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. */
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 ****************************************************************************/
94 /****************************************************/
95 /* This information is from Novell. It is not in any of the standard
96 NetWare header files. */
98 struct DBG_LoadDefinitionStructure
102 LONG LDCodeImageOffset
;
103 LONG LDCodeImageLength
;
104 LONG LDDataImageOffset
;
105 LONG LDDataImageLength
;
106 LONG LDUninitializedDataLength
;
107 LONG LDCustomDataOffset
;
108 LONG LDCustomDataSize
;
110 LONG (*LDInitializationProcedure
)(void);
113 #define LO_NORMAL 0x0000
114 #define LO_STARTUP 0x0001
115 #define LO_PROTECT 0x0002
116 #define LO_DEBUG 0x0004
117 #define LO_AUTO_LOAD 0x0008
119 /* Loader returned error codes */
120 #define LOAD_COULD_NOT_FIND_FILE 1
121 #define LOAD_ERROR_READING_FILE 2
122 #define LOAD_NOT_NLM_FILE_FORMAT 3
123 #define LOAD_WRONG_NLM_FILE_VERSION 4
124 #define LOAD_REENTRANT_INITIALIZE_FAILURE 5
125 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6
126 #define LOAD_ALREADY_IN_PROGRESS 7
127 #define LOAD_NOT_ENOUGH_MEMORY 8
128 #define LOAD_INITIALIZE_FAILURE 9
129 #define LOAD_INCONSISTENT_FILE_FORMAT 10
130 #define LOAD_CAN_NOT_LOAD_AT_STARTUP 11
131 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12
132 #define LOAD_UNRESOLVED_EXTERNAL 13
133 #define LOAD_PUBLIC_ALREADY_DEFINED 14
134 /****************************************************/
136 /* The main thread ID. */
137 static int mainthread
;
139 /* An error message for the main thread to print. */
140 static char *error_message
;
142 /* The AIO port handle. */
143 static int AIOhandle
;
145 /* BUFMAX defines the maximum number of characters in inbound/outbound
146 buffers. At least NUMREGBYTES*2 are needed for register packets */
147 #define BUFMAX (REGISTER_BYTES * 2 + 16)
149 /* remote_debug > 0 prints ill-formed commands in valid packets and
151 static int remote_debug
= 1;
153 static const char hexchars
[] = "0123456789abcdef";
155 unsigned char breakpoint_insn
[] = BREAKPOINT
;
157 char *mem2hex (void *mem
, char *buf
, int count
, int may_fault
);
158 char *hex2mem (char *buf
, void *mem
, int count
, int may_fault
);
159 extern void set_step_traps (struct StackFrame
*);
160 extern void clear_step_traps (struct StackFrame
*);
162 static int __main() {};
164 /* Read a character from the serial port. This must busy wait, but
165 that's OK because we will be the only thread running anyhow. */
176 err
= AIOReadData (AIOhandle
, (char *) &ret
, 1, &got
);
179 error_message
= "AIOReadData failed";
180 ResumeThread (mainthread
);
189 /* Write a character to the serial port. Returns 0 on failure,
190 non-zero on success. */
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. */
215 if ((ch
>= 'a') && (ch
<= 'f'))
217 if ((ch
>= '0') && (ch
<= '9'))
219 if ((ch
>= 'A') && (ch
<= 'F'))
224 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
225 non-zero on success. */
231 unsigned char checksum
;
232 unsigned char xmitcsum
;
239 /* wait around for the start character, ignore all other characters */
240 while ((ch
= getDebugChar()) != '$')
248 /* now, read until a # or end of buffer is found */
249 while (count
< BUFMAX
)
256 checksum
= checksum
+ ch
;
264 ch
= getDebugChar ();
267 xmitcsum
= hex(ch
) << 4;
268 ch
= getDebugChar ();
273 if (checksum
!= xmitcsum
)
276 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
277 checksum
,xmitcsum
,buffer
);
278 /* failed checksum */
279 if (! putDebugChar('-'))
285 /* successful transfer */
286 if (! putDebugChar('+'))
288 /* if a sequence char is present, reply the sequence ID */
289 if (buffer
[2] == ':')
291 if (! putDebugChar (buffer
[0])
292 || ! putDebugChar (buffer
[1]))
294 /* remove sequence chars from buffer */
295 count
= strlen(buffer
);
296 for (i
=3; i
<= count
; i
++)
297 buffer
[i
-3] = buffer
[i
];
302 while (checksum
!= xmitcsum
);
305 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
310 /* Send the packet in buffer. Returns 0 on failure, non-zero on
317 unsigned char checksum
;
322 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
324 /* $<packet info>#<checksum>. */
327 if (! putDebugChar('$'))
332 while (ch
=buffer
[count
])
334 if (! putDebugChar(ch
))
340 if (! putDebugChar('#')
341 || ! putDebugChar(hexchars
[checksum
>> 4])
342 || ! putDebugChar(hexchars
[checksum
% 16]))
345 ch
= getDebugChar ();
354 static char remcomInBuffer
[BUFMAX
];
355 static char remcomOutBuffer
[BUFMAX
];
359 debug_error (format
, parm
)
365 ConsolePrintf (format
, parm
);
366 ConsolePrintf ("\n");
370 /* This is set if we could get a memory access fault. */
371 static int mem_may_fault
;
373 /* Indicate to caller of mem2hex or hex2mem that there has been an
375 volatile int mem_err
= 0;
377 #ifndef ALTERNATE_MEM_FUNCS
378 /* These are separate functions so that they are so short and sweet
379 that the compiler won't save any registers (if there is a fault
380 to mem_fault, they won't get restored, so there better not be any
397 #endif /* ALTERNATE_MEM_FUNCS */
399 /* convert the memory pointed to by mem into hex, placing result in buf */
400 /* return a pointer to the last char put in buf (null) */
401 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
402 a fault; if zero treat a fault like any other fault in the stub. */
405 mem2hex (mem
, buf
, count
, may_fault
)
415 mem_may_fault
= may_fault
;
416 for (i
= 0; i
< count
; i
++)
418 ch
= get_char (ptr
++);
419 if (may_fault
&& mem_err
)
421 *buf
++ = hexchars
[ch
>> 4];
422 *buf
++ = hexchars
[ch
% 16];
429 /* convert the hex array pointed to by buf into binary to be placed in mem */
430 /* return a pointer to the character AFTER the last byte written */
433 hex2mem (buf
, mem
, count
, may_fault
)
443 mem_may_fault
= may_fault
;
444 for (i
=0;i
<count
;i
++)
446 ch
= hex(*buf
++) << 4;
447 ch
= ch
+ hex(*buf
++);
448 set_char (ptr
++, ch
);
449 if (may_fault
&& mem_err
)
456 /* This function takes the 386 exception vector and attempts to
457 translate this number into a unix compatible signal value. */
460 computeSignal (exceptionVector
)
464 switch (exceptionVector
)
466 case 0 : sigval
= 8; break; /* divide by zero */
467 case 1 : sigval
= 5; break; /* debug exception */
468 case 3 : sigval
= 5; break; /* breakpoint */
469 case 4 : sigval
= 16; break; /* into instruction (overflow) */
470 case 5 : sigval
= 16; break; /* bound instruction */
471 case 6 : sigval
= 4; break; /* Invalid opcode */
472 case 7 : sigval
= 8; break; /* coprocessor not available */
473 case 8 : sigval
= 7; break; /* double fault */
474 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
475 case 10 : sigval
= 11; break; /* Invalid TSS */
476 case 11 : sigval
= 11; break; /* Segment not present */
477 case 12 : sigval
= 11; break; /* stack exception */
478 case 13 : sigval
= 11; break; /* general protection */
479 case 14 : sigval
= 11; break; /* page fault */
480 case 16 : sigval
= 7; break; /* coprocessor error */
482 sigval
= 7; /* "software generated"*/
487 /**********************************************/
488 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
489 /* RETURN NUMBER OF CHARS PROCESSED */
490 /**********************************************/
492 hexToInt(ptr
, intValue
)
503 hexValue
= hex(**ptr
);
506 *intValue
= (*intValue
<<4) | hexValue
;
518 /* This function does all command processing for interfacing to gdb.
519 It is called whenever an exception occurs in the module being
523 handle_exception (frame
)
524 struct StackFrame
*frame
;
528 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
529 static unsigned char first_insn
[BREAKPOINT_SIZE
]; /* The first instruction in the program. */
531 /* Apparently the bell can sometimes be ringing at this point, and
532 should be stopped. */
537 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
538 frame
->ExceptionNumber
,
539 frame
->ExceptionDescription
,
544 switch (frame
->ExceptionNumber
)
546 case START_NLM_EVENT
:
547 /* If the NLM just started, we record the module load information
548 and the thread ID, and set a breakpoint at the first instruction
551 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
552 frame
->ExceptionErrorCode
);
553 memcpy (first_insn
, ldinfo
->LDInitializationProcedure
,
555 memcpy (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
558 return RETURN_TO_PROGRAM
;
560 case ENTER_DEBUGGER_EVENT
:
561 case KEYBOARD_BREAK_EVENT
:
562 /* Pass some events on to the next debugger, in case it will handle
564 return RETURN_TO_NEXT_DEBUGGER
;
566 case 3: /* Breakpoint */
567 /* After we've reached the initial breakpoint, reset it. */
568 if (frame
->ExceptionPC
- DECR_PC_AFTER_BREAK
== (LONG
) ldinfo
->LDInitializationProcedure
569 && memcmp (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
570 BREAKPOINT_SIZE
) == 0)
572 memcpy (ldinfo
->LDInitializationProcedure
, first_insn
,
574 frame
->ExceptionPC
-= DECR_PC_AFTER_BREAK
;
577 /* Normal breakpoints end up here */
578 do_status (remcomOutBuffer
, frame
);
582 /* At the moment, we don't care about most of the unusual NetWare
584 if (frame
->ExceptionNumber
> 31)
585 return RETURN_TO_PROGRAM
;
587 /* Most machine level exceptions end up here */
588 do_status (remcomOutBuffer
, frame
);
591 case 11: /* Segment not present */
592 case 13: /* General protection */
593 case 14: /* Page fault */
594 /* If we get a GP fault, and mem_may_fault is set, and the
595 instruction pointer is near set_char or get_char, then we caused
596 the fault ourselves accessing an illegal memory location. */
598 && ((frame
->ExceptionPC
>= (long) &set_char
599 && frame
->ExceptionPC
< (long) &set_char
+ 50)
600 || (frame
->ExceptionPC
>= (long) &get_char
601 && frame
->ExceptionPC
< (long) &get_char
+ 50)))
604 /* Point the instruction pointer at an assembly language stub
605 which just returns from the function. */
607 frame
->ExceptionPC
+= 4; /* Skip the load or store */
609 /* Keep going. This will act as though it returned from
610 set_char or get_char. The calling routine will check
611 mem_err, and do the right thing. */
612 return RETURN_TO_PROGRAM
;
614 /* Random mem fault, report it */
615 do_status (remcomOutBuffer
, frame
);
618 case TERMINATE_NLM_EVENT
:
619 /* There is no way to get the exit status. */
620 sprintf (remcomOutBuffer
, "W%02x", 0);
621 break; /* We generate our own status */
624 /* FIXME: How do we know that this exception has anything to do with
625 the program we are debugging? We can check whether the PC is in
626 the range of the module we are debugging, but that doesn't help
627 much since an error could occur in a library routine. */
629 clear_step_traps (frame
);
631 if (! putpacket(remcomOutBuffer
))
632 return RETURN_TO_NEXT_DEBUGGER
;
634 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
636 ResumeThread (mainthread
);
637 return RETURN_TO_PROGRAM
;
643 remcomOutBuffer
[0] = 0;
644 if (! getpacket (remcomInBuffer
))
645 return RETURN_TO_NEXT_DEBUGGER
;
646 switch (remcomInBuffer
[0])
649 do_status (remcomOutBuffer
, frame
);
652 remote_debug
= !(remote_debug
); /* toggle debug flag */
655 /* return the value of the CPU registers */
656 frame_to_registers (frame
, remcomOutBuffer
);
659 /* set the value of the CPU registers - return OK */
660 registers_to_frame (&remcomInBuffer
[1], frame
);
661 strcpy(remcomOutBuffer
,"OK");
665 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
666 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
667 ptr
= &remcomInBuffer
[1];
668 if (hexToInt(&ptr
,&addr
))
670 if (hexToInt(&ptr
,&length
))
674 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
677 strcpy (remcomOutBuffer
, "E03");
678 debug_error ("memory fault");
684 strcpy(remcomOutBuffer
,"E01");
685 debug_error("malformed read memory command: %s",remcomInBuffer
);
690 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
691 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
692 ptr
= &remcomInBuffer
[1];
693 if (hexToInt(&ptr
,&addr
))
695 if (hexToInt(&ptr
,&length
))
699 hex2mem(ptr
, (char*) addr
, length
, 1);
703 strcpy (remcomOutBuffer
, "E03");
704 debug_error ("memory fault");
708 strcpy(remcomOutBuffer
,"OK");
715 strcpy(remcomOutBuffer
,"E02");
716 debug_error("malformed write memory command: %s",remcomInBuffer
);
722 /* cAA..AA Continue at address AA..AA(optional) */
723 /* sAA..AA Step one instruction from AA..AA(optional) */
724 /* try to read optional parameter, pc unchanged if no parm */
725 ptr
= &remcomInBuffer
[1];
726 if (hexToInt(&ptr
,&addr
))
728 /* registers[PC_REGNUM].lo = addr;*/
729 fprintf (stderr
, "Setting PC to 0x%x\n", addr
);
733 if (remcomInBuffer
[0] == 's')
734 set_step_traps (frame
);
737 return RETURN_TO_PROGRAM
;
740 /* kill the program */
742 ResumeThread (mainthread
);
743 return RETURN_TO_PROGRAM
;
745 case 'q': /* Query message */
746 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
748 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
749 ldinfo
->LDCodeImageOffset
,
750 ldinfo
->LDDataImageOffset
,
751 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
754 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
758 /* reply to the request */
759 if (! putpacket(remcomOutBuffer
))
760 return RETURN_TO_NEXT_DEBUGGER
;
768 const char *bitRateString
;
771 struct bitRate bitRateTable
[] =
773 { AIO_BAUD_50
, "50" },
774 { AIO_BAUD_75
, "75" },
775 { AIO_BAUD_110
, "110" },
776 { AIO_BAUD_134p5
, "134.5" },
777 { AIO_BAUD_150
, "150" },
778 { AIO_BAUD_300
, "300" },
779 { AIO_BAUD_600
, "600" },
780 { AIO_BAUD_1200
, "1200" },
781 { AIO_BAUD_1800
, "1800" },
782 { AIO_BAUD_2000
, "2000" },
783 { AIO_BAUD_2400
, "2400" },
784 { AIO_BAUD_3600
, "3600" },
785 { AIO_BAUD_4800
, "4800" },
786 { AIO_BAUD_7200
, "7200" },
787 { AIO_BAUD_9600
, "9600" },
788 { AIO_BAUD_19200
, "19200" },
789 { AIO_BAUD_38400
, "38400" },
790 { AIO_BAUD_57600
, "57600" },
791 { AIO_BAUD_115200
, "115200" },
795 char dataBitsTable
[] = "5678";
797 char *stopBitsTable
[] = { "1", "1.5", "2" };
799 char parity
[] = "NOEMS";
801 /* Start up. The main thread opens the named serial I/O port, loads
802 the named NLM module and then goes to sleep. The serial I/O port
803 is named as a board number and a port number. It would be more DOS
804 like to provide a menu of available serial ports, but I don't want
805 to have to figure out how to do that. */
812 int hardware
, board
, port
;
818 struct debuggerStructure s
;
824 progname
= "gdbserve";
826 /* set default serial line */
831 /* set default serial line characteristics */
832 bitRate
= AIO_BAUD_9600
;
833 dataBits
= AIO_DATA_BITS_8
;
834 stopBits
= AIO_STOP_BITS_1
;
835 parityMode
= AIO_PARITY_NONE
;
838 for (argc
--, argv
++; *argv
; argc
--, argv
++)
843 if (strnicmp(*argv
, "BAUD=", 5) == 0)
848 for (brp
= bitRateTable
; brp
->bitRate
!= (BYTE
) -1; brp
++)
850 if (strcmp(brp
->bitRateString
, bp
) == 0)
852 bitRate
= brp
->bitRate
;
857 if (brp
->bitRateString
== NULL
)
859 fprintf(stderr
, "%s: %s: unknown or unsupported bit rate",
864 else if (strnicmp(*argv
, "NODE=", 5) == 0)
867 board
= strtol (bp
, &ep
, 0);
868 if (ep
== bp
|| *ep
!= '\0')
870 fprintf (stderr
, "%s: %s: expected integer argument\n",
875 else if (strnicmp(*argv
, "PORT=", 5) == 0)
878 port
= strtol (bp
, &ep
, 0);
879 if (ep
== bp
|| *ep
!= '\0')
881 fprintf (stderr
, "%s: %s: expected integer argument\n",
897 "Usage: load %s [options] program [arguments]\n", progname
);
901 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
902 if (err
!= AIO_SUCCESS
)
906 case AIO_PORT_NOT_AVAILABLE
:
907 fprintf (stderr
, "Port not available\n");
910 case AIO_BOARD_NUMBER_INVALID
:
911 case AIO_PORT_NUMBER_INVALID
:
912 fprintf (stderr
, "No such port\n");
916 fprintf (stderr
, "Could not open port: %d\n", err
);
923 err
= AIOConfigurePort (AIOhandle
, bitRate
, dataBits
, stopBits
, parityMode
,
924 AIO_HARDWARE_FLOW_CONTROL_OFF
);
926 if (err
== AIO_QUALIFIED_SUCCESS
)
928 AIOPORTCONFIG portConfig
;
930 fprintf (stderr
, "Port configuration changed!\n");
932 portConfig
.returnLength
= sizeof(portConfig
);
933 AIOGetPortConfiguration (AIOhandle
, &portConfig
, NULL
);
936 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
938 bitRateTable
[portConfig
.bitRate
].bitRateString
,
939 dataBitsTable
[portConfig
.dataBits
],
940 stopBitsTable
[portConfig
.stopBits
],
941 parity
[portConfig
.parityMode
],
942 portConfig
.flowCtrlMode
? "ON" : "OFF");
944 else if (err
!= AIO_SUCCESS
)
946 fprintf (stderr
, "Could not configure port: %d\n", err
);
947 AIOReleasePort (AIOhandle
);
951 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
952 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
955 LONG extStatus
, chgdExtStatus
;
957 fprintf (stderr
, "Could not set desired port controls!\n");
958 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
959 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
963 /* Register ourselves as an alternate debugger. */
964 memset (&s
, 0, sizeof s
);
965 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
966 AllocateResourceTag (GetNLMHandle (),
969 if (s
.DDSResourceTag
== 0)
971 fprintf (stderr
, "AllocateResourceTag failed\n");
972 AIOReleasePort (AIOhandle
);
975 s
.DDSdebuggerEntry
= handle_exception
;
976 s
.DDSFlags
= TSS_FRAME_BIT
;
978 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
981 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
982 AIOReleasePort (AIOhandle
);
986 /* Get the command line we were invoked with, and advance it past
987 our name and the board and port arguments. */
988 cmdlin
= getcmd ((char *) NULL
);
989 for (i
= 0; i
< cmdindx
; i
++)
991 while (! isspace (*cmdlin
))
993 while (isspace (*cmdlin
))
997 /* In case GDB is started before us, ack any packets (presumably
998 "$?#xx") sitting there. */
999 if (! putDebugChar ('+'))
1001 fprintf (stderr
, "putDebugChar failed\n");
1002 UnRegisterDebugger (&s
);
1003 AIOReleasePort (AIOhandle
);
1007 mainthread
= GetThreadID ();
1009 if (remote_debug
> 0)
1010 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1011 cmdlin
, __GetScreenID (GetCurrentScreen()));
1013 /* Start up the module to be debugged. */
1014 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1015 (BYTE
*)cmdlin
, LO_DEBUG
);
1018 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1019 UnRegisterDebugger (&s
);
1020 AIOReleasePort (AIOhandle
);
1024 /* Wait for the debugger to wake us up. */
1025 if (remote_debug
> 0)
1026 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1027 SuspendThread (mainthread
);
1028 if (remote_debug
> 0)
1029 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1031 /* If we are woken up, print an optional error message, deregister
1032 ourselves and exit. */
1033 if (error_message
!= NULL
)
1034 fprintf (stderr
, "%s\n", error_message
);
1035 UnRegisterDebugger (&s
);
1036 AIOReleasePort (AIOhandle
);