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 ****************************************************************************/
75 #if defined(__netware__) && defined(__i386__)
93 /****************************************************/
94 /* This information is from Novell. It is not in any of the standard
95 NetWare header files. */
97 struct DBG_LoadDefinitionStructure
101 LONG LDCodeImageOffset
;
102 LONG LDCodeImageLength
;
103 LONG LDDataImageOffset
;
104 LONG LDDataImageLength
;
105 LONG LDUninitializedDataLength
;
106 LONG LDCustomDataOffset
;
107 LONG LDCustomDataSize
;
109 LONG (*LDInitializationProcedure
)(void);
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
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 /****************************************************/
135 /* The main thread ID. */
136 static int mainthread
;
138 /* An error message for the main thread to print. */
139 static char *error_message
;
141 /* The AIO port handle. */
142 static int AIOhandle
;
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)
148 /* remote_debug > 0 prints ill-formed commands in valid packets and
150 static int remote_debug
= 1;
152 static const char hexchars
[] = "0123456789abcdef";
154 unsigned char breakpoint_insn
[] = BREAKPOINT
;
156 char *mem2hex (void *mem
, char *buf
, int count
, int may_fault
);
157 char *hex2mem (char *buf
, void *mem
, int count
, int may_fault
);
158 extern void set_step_traps (struct StackFrame
*);
159 extern void clear_step_traps (struct StackFrame
*);
161 static int __main() {};
163 /* Read a character from the serial port. This must busy wait, but
164 that's OK because we will be the only thread running anyhow. */
175 err
= AIOReadData (AIOhandle
, (char *) &ret
, 1, &got
);
178 error_message
= "AIOReadData failed";
179 ResumeThread (mainthread
);
188 /* Write a character to the serial port. Returns 0 on failure,
189 non-zero on success. */
201 err
= AIOWriteData (AIOhandle
, (char *) &c
, 1, &put
);
203 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err
, put
);
208 /* 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. */
230 unsigned char checksum
;
231 unsigned char xmitcsum
;
238 /* wait around for the start character, ignore all other characters */
239 while ((ch
= getDebugChar()) != '$')
247 /* now, read until a # or end of buffer is found */
248 while (count
< BUFMAX
)
255 checksum
= checksum
+ ch
;
263 ch
= getDebugChar ();
266 xmitcsum
= hex(ch
) << 4;
267 ch
= getDebugChar ();
272 if (checksum
!= xmitcsum
)
275 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
276 checksum
,xmitcsum
,buffer
);
277 /* failed checksum */
278 if (! putDebugChar('-'))
284 /* successful transfer */
285 if (! putDebugChar('+'))
287 /* if a sequence char is present, reply the sequence ID */
288 if (buffer
[2] == ':')
290 if (! putDebugChar (buffer
[0])
291 || ! putDebugChar (buffer
[1]))
293 /* remove sequence chars from buffer */
294 count
= strlen(buffer
);
295 for (i
=3; i
<= count
; i
++)
296 buffer
[i
-3] = buffer
[i
];
301 while (checksum
!= xmitcsum
);
304 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
309 /* Send the packet in buffer. Returns 0 on failure, non-zero on
316 unsigned char checksum
;
321 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
323 /* $<packet info>#<checksum>. */
326 if (! putDebugChar('$'))
331 while (ch
=buffer
[count
])
333 if (! putDebugChar(ch
))
339 if (! putDebugChar('#')
340 || ! putDebugChar(hexchars
[checksum
>> 4])
341 || ! putDebugChar(hexchars
[checksum
% 16]))
344 ch
= getDebugChar ();
353 static char remcomInBuffer
[BUFMAX
];
354 static char remcomOutBuffer
[BUFMAX
];
358 debug_error (format
, parm
)
364 ConsolePrintf (format
, parm
);
365 ConsolePrintf ("\n");
369 /* This is set if we could get a memory access fault. */
370 static int mem_may_fault
;
372 /* Indicate to caller of mem2hex or hex2mem that there has been an
374 volatile int mem_err
= 0;
376 #ifndef ALTERNATE_MEM_FUNCS
377 /* These are separate functions so that they are so short and sweet
378 that the compiler won't save any registers (if there is a fault
379 to mem_fault, they won't get restored, so there better not be any
396 #endif /* ALTERNATE_MEM_FUNCS */
398 /* convert the memory pointed to by mem into hex, placing result in buf */
399 /* return a pointer to the last char put in buf (null) */
400 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
401 a fault; if zero treat a fault like any other fault in the stub. */
404 mem2hex (mem
, buf
, count
, may_fault
)
414 mem_may_fault
= may_fault
;
415 for (i
= 0; i
< count
; i
++)
417 ch
= get_char (ptr
++);
418 if (may_fault
&& mem_err
)
420 *buf
++ = hexchars
[ch
>> 4];
421 *buf
++ = hexchars
[ch
% 16];
428 /* convert the hex array pointed to by buf into binary to be placed in mem */
429 /* return a pointer to the character AFTER the last byte written */
432 hex2mem (buf
, mem
, count
, may_fault
)
442 mem_may_fault
= may_fault
;
443 for (i
=0;i
<count
;i
++)
445 ch
= hex(*buf
++) << 4;
446 ch
= ch
+ hex(*buf
++);
447 set_char (ptr
++, ch
);
448 if (may_fault
&& mem_err
)
455 /* This function takes the 386 exception vector and attempts to
456 translate this number into a unix compatible signal value. */
459 computeSignal (exceptionVector
)
463 switch (exceptionVector
)
465 case 0 : sigval
= 8; break; /* divide by zero */
466 case 1 : sigval
= 5; break; /* debug exception */
467 case 3 : sigval
= 5; break; /* breakpoint */
468 case 4 : sigval
= 16; break; /* into instruction (overflow) */
469 case 5 : sigval
= 16; break; /* bound instruction */
470 case 6 : sigval
= 4; break; /* Invalid opcode */
471 case 7 : sigval
= 8; break; /* coprocessor not available */
472 case 8 : sigval
= 7; break; /* double fault */
473 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
474 case 10 : sigval
= 11; break; /* Invalid TSS */
475 case 11 : sigval
= 11; break; /* Segment not present */
476 case 12 : sigval
= 11; break; /* stack exception */
477 case 13 : sigval
= 11; break; /* general protection */
478 case 14 : sigval
= 11; break; /* page fault */
479 case 16 : sigval
= 7; break; /* coprocessor error */
481 sigval
= 7; /* "software generated"*/
486 /**********************************************/
487 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
488 /* RETURN NUMBER OF CHARS PROCESSED */
489 /**********************************************/
491 hexToInt(ptr
, intValue
)
502 hexValue
= hex(**ptr
);
505 *intValue
= (*intValue
<<4) | hexValue
;
517 /* This function does all command processing for interfacing to gdb.
518 It is called whenever an exception occurs in the module being
522 handle_exception (frame
)
523 struct StackFrame
*frame
;
527 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
528 static unsigned char first_insn
[BREAKPOINT_SIZE
]; /* The first instruction in the program. */
530 /* Apparently the bell can sometimes be ringing at this point, and
531 should be stopped. */
536 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
537 frame
->ExceptionNumber
,
538 frame
->ExceptionDescription
,
543 switch (frame
->ExceptionNumber
)
545 case START_NLM_EVENT
:
546 /* If the NLM just started, we record the module load information
547 and the thread ID, and set a breakpoint at the first instruction
550 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
551 frame
->ExceptionErrorCode
);
552 memcpy (first_insn
, ldinfo
->LDInitializationProcedure
,
554 memcpy (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
557 return RETURN_TO_PROGRAM
;
559 case ENTER_DEBUGGER_EVENT
:
560 case KEYBOARD_BREAK_EVENT
:
561 /* Pass some events on to the next debugger, in case it will handle
563 return RETURN_TO_NEXT_DEBUGGER
;
565 case 3: /* Breakpoint */
566 /* After we've reached the initial breakpoint, reset it. */
567 if (frame
->ExceptionPC
- DECR_PC_AFTER_BREAK
== (LONG
) ldinfo
->LDInitializationProcedure
568 && memcmp (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
569 BREAKPOINT_SIZE
) == 0)
571 memcpy (ldinfo
->LDInitializationProcedure
, first_insn
,
573 frame
->ExceptionPC
-= DECR_PC_AFTER_BREAK
;
576 /* Normal breakpoints end up here */
577 do_status (remcomOutBuffer
, frame
);
581 /* At the moment, we don't care about most of the unusual NetWare
583 if (frame
->ExceptionNumber
> 31)
584 return RETURN_TO_PROGRAM
;
586 /* Most machine level exceptions end up here */
587 do_status (remcomOutBuffer
, frame
);
590 case 11: /* Segment not present */
591 case 13: /* General protection */
592 case 14: /* Page fault */
593 /* If we get a GP fault, and mem_may_fault is set, and the
594 instruction pointer is near set_char or get_char, then we caused
595 the fault ourselves accessing an illegal memory location. */
597 && ((frame
->ExceptionPC
>= (long) &set_char
598 && frame
->ExceptionPC
< (long) &set_char
+ 50)
599 || (frame
->ExceptionPC
>= (long) &get_char
600 && frame
->ExceptionPC
< (long) &get_char
+ 50)))
603 /* Point the instruction pointer at an assembly language stub
604 which just returns from the function. */
606 frame
->ExceptionPC
+= 4; /* Skip the load or store */
608 /* Keep going. This will act as though it returned from
609 set_char or get_char. The calling routine will check
610 mem_err, and do the right thing. */
611 return RETURN_TO_PROGRAM
;
613 /* Random mem fault, report it */
614 do_status (remcomOutBuffer
, frame
);
617 case TERMINATE_NLM_EVENT
:
618 /* There is no way to get the exit status. */
619 sprintf (remcomOutBuffer
, "W%02x", 0);
620 break; /* We generate our own status */
623 /* FIXME: How do we know that this exception has anything to do with
624 the program we are debugging? We can check whether the PC is in
625 the range of the module we are debugging, but that doesn't help
626 much since an error could occur in a library routine. */
628 clear_step_traps (frame
);
630 if (! putpacket(remcomOutBuffer
))
631 return RETURN_TO_NEXT_DEBUGGER
;
633 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
635 ResumeThread (mainthread
);
636 return RETURN_TO_PROGRAM
;
642 remcomOutBuffer
[0] = 0;
643 if (! getpacket (remcomInBuffer
))
644 return RETURN_TO_NEXT_DEBUGGER
;
645 switch (remcomInBuffer
[0])
648 do_status (remcomOutBuffer
, frame
);
651 remote_debug
= !(remote_debug
); /* toggle debug flag */
654 /* return the value of the CPU registers */
655 frame_to_registers (frame
, remcomOutBuffer
);
658 /* set the value of the CPU registers - return OK */
659 registers_to_frame (&remcomInBuffer
[1], frame
);
660 strcpy(remcomOutBuffer
,"OK");
664 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
665 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
666 ptr
= &remcomInBuffer
[1];
667 if (hexToInt(&ptr
,&addr
))
669 if (hexToInt(&ptr
,&length
))
673 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
676 strcpy (remcomOutBuffer
, "E03");
677 debug_error ("memory fault");
683 strcpy(remcomOutBuffer
,"E01");
684 debug_error("malformed read memory command: %s",remcomInBuffer
);
689 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
690 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
691 ptr
= &remcomInBuffer
[1];
692 if (hexToInt(&ptr
,&addr
))
694 if (hexToInt(&ptr
,&length
))
698 hex2mem(ptr
, (char*) addr
, length
, 1);
702 strcpy (remcomOutBuffer
, "E03");
703 debug_error ("memory fault");
707 strcpy(remcomOutBuffer
,"OK");
714 strcpy(remcomOutBuffer
,"E02");
715 debug_error("malformed write memory command: %s",remcomInBuffer
);
721 /* cAA..AA Continue at address AA..AA(optional) */
722 /* sAA..AA Step one instruction from AA..AA(optional) */
723 /* try to read optional parameter, pc unchanged if no parm */
724 ptr
= &remcomInBuffer
[1];
725 if (hexToInt(&ptr
,&addr
))
727 /* registers[PC_REGNUM].lo = addr;*/
728 fprintf (stderr
, "Setting PC to 0x%x\n", addr
);
732 if (remcomInBuffer
[0] == 's')
733 set_step_traps (frame
);
736 return RETURN_TO_PROGRAM
;
739 /* kill the program */
741 ResumeThread (mainthread
);
742 return RETURN_TO_PROGRAM
;
744 case 'q': /* Query message */
745 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
747 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
748 ldinfo
->LDCodeImageOffset
,
749 ldinfo
->LDDataImageOffset
,
750 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
753 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
757 /* reply to the request */
758 if (! putpacket(remcomOutBuffer
))
759 return RETURN_TO_NEXT_DEBUGGER
;
767 const char *bitRateString
;
770 struct bitRate bitRateTable
[] =
772 { AIO_BAUD_50
, "50" },
773 { AIO_BAUD_75
, "75" },
774 { AIO_BAUD_110
, "110" },
775 { AIO_BAUD_134p5
, "134.5" },
776 { AIO_BAUD_150
, "150" },
777 { AIO_BAUD_300
, "300" },
778 { AIO_BAUD_600
, "600" },
779 { AIO_BAUD_1200
, "1200" },
780 { AIO_BAUD_1800
, "1800" },
781 { AIO_BAUD_2000
, "2000" },
782 { AIO_BAUD_2400
, "2400" },
783 { AIO_BAUD_3600
, "3600" },
784 { AIO_BAUD_4800
, "4800" },
785 { AIO_BAUD_7200
, "7200" },
786 { AIO_BAUD_9600
, "9600" },
787 { AIO_BAUD_19200
, "19200" },
788 { AIO_BAUD_38400
, "38400" },
789 { AIO_BAUD_57600
, "57600" },
790 { AIO_BAUD_115200
, "115200" },
794 char dataBitsTable
[] = "5678";
796 char *stopBitsTable
[] = { "1", "1.5", "2" };
798 char parity
[] = "NOEMS";
800 /* Start up. The main thread opens the named serial I/O port, loads
801 the named NLM module and then goes to sleep. The serial I/O port
802 is named as a board number and a port number. It would be more DOS
803 like to provide a menu of available serial ports, but I don't want
804 to have to figure out how to do that. */
811 int hardware
, board
, port
;
817 struct debuggerStructure s
;
823 progname
= "gdbserve";
825 /* set default serial line */
830 /* set default serial line characteristics */
831 bitRate
= AIO_BAUD_9600
;
832 dataBits
= AIO_DATA_BITS_8
;
833 stopBits
= AIO_STOP_BITS_1
;
834 parityMode
= AIO_PARITY_NONE
;
837 for (argc
--, argv
++; *argv
; argc
--, argv
++)
842 if (strnicmp(*argv
, "BAUD=", 5) == 0)
847 for (brp
= bitRateTable
; brp
->bitRate
!= (BYTE
) -1; brp
++)
849 if (strcmp(brp
->bitRateString
, bp
) == 0)
851 bitRate
= brp
->bitRate
;
856 if (brp
->bitRateString
== NULL
)
858 fprintf(stderr
, "%s: %s: unknown or unsupported bit rate",
863 else if (strnicmp(*argv
, "NODE=", 5) == 0)
866 board
= strtol (bp
, &ep
, 0);
867 if (ep
== bp
|| *ep
!= '\0')
869 fprintf (stderr
, "%s: %s: expected integer argument\n",
874 else if (strnicmp(*argv
, "PORT=", 5) == 0)
877 port
= strtol (bp
, &ep
, 0);
878 if (ep
== bp
|| *ep
!= '\0')
880 fprintf (stderr
, "%s: %s: expected integer argument\n",
896 "Usage: load %s [options] program [arguments]\n", progname
);
900 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
901 if (err
!= AIO_SUCCESS
)
905 case AIO_PORT_NOT_AVAILABLE
:
906 fprintf (stderr
, "Port not available\n");
909 case AIO_BOARD_NUMBER_INVALID
:
910 case AIO_PORT_NUMBER_INVALID
:
911 fprintf (stderr
, "No such port\n");
915 fprintf (stderr
, "Could not open port: %d\n", err
);
922 err
= AIOConfigurePort (AIOhandle
, bitRate
, dataBits
, stopBits
, parityMode
,
923 AIO_HARDWARE_FLOW_CONTROL_OFF
);
925 if (err
== AIO_QUALIFIED_SUCCESS
)
927 AIOPORTCONFIG portConfig
;
929 fprintf (stderr
, "Port configuration changed!\n");
931 portConfig
.returnLength
= sizeof(portConfig
);
932 AIOGetPortConfiguration (AIOhandle
, &portConfig
, NULL
);
935 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
937 bitRateTable
[portConfig
.bitRate
].bitRateString
,
938 dataBitsTable
[portConfig
.dataBits
],
939 stopBitsTable
[portConfig
.stopBits
],
940 parity
[portConfig
.parityMode
],
941 portConfig
.flowCtrlMode
? "ON" : "OFF");
943 else if (err
!= AIO_SUCCESS
)
945 fprintf (stderr
, "Could not configure port: %d\n", err
);
946 AIOReleasePort (AIOhandle
);
950 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
951 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
954 LONG extStatus
, chgdExtStatus
;
956 fprintf (stderr
, "Could not set desired port controls!\n");
957 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
958 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
962 /* Register ourselves as an alternate debugger. */
963 memset (&s
, 0, sizeof s
);
964 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
965 AllocateResourceTag (GetNLMHandle (),
968 if (s
.DDSResourceTag
== 0)
970 fprintf (stderr
, "AllocateResourceTag failed\n");
971 AIOReleasePort (AIOhandle
);
974 s
.DDSdebuggerEntry
= handle_exception
;
975 s
.DDSFlags
= TSS_FRAME_BIT
;
977 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
980 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
981 AIOReleasePort (AIOhandle
);
985 /* Get the command line we were invoked with, and advance it past
986 our name and the board and port arguments. */
987 cmdlin
= getcmd ((char *) NULL
);
988 for (i
= 0; i
< cmdindx
; i
++)
990 while (! isspace (*cmdlin
))
992 while (isspace (*cmdlin
))
996 /* In case GDB is started before us, ack any packets (presumably
997 "$?#xx") sitting there. */
998 if (! putDebugChar ('+'))
1000 fprintf (stderr
, "putDebugChar failed\n");
1001 UnRegisterDebugger (&s
);
1002 AIOReleasePort (AIOhandle
);
1006 mainthread
= GetThreadID ();
1008 if (remote_debug
> 0)
1009 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1010 cmdlin
, __GetScreenID (GetCurrentScreen()));
1012 /* Start up the module to be debugged. */
1013 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1014 (BYTE
*)cmdlin
, LO_DEBUG
);
1017 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1018 UnRegisterDebugger (&s
);
1019 AIOReleasePort (AIOhandle
);
1023 /* Wait for the debugger to wake us up. */
1024 if (remote_debug
> 0)
1025 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1026 SuspendThread (mainthread
);
1027 if (remote_debug
> 0)
1028 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1030 /* If we are woken up, print an optional error message, deregister
1031 ourselves and exit. */
1032 if (error_message
!= NULL
)
1033 fprintf (stderr
, "%s\n", error_message
);
1034 UnRegisterDebugger (&s
);
1035 AIOReleasePort (AIOhandle
);