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 ****************************************************************************/
82 /****************************************************/
83 /* This information is from Novell. It is not in any of the standard
84 NetWare header files. */
86 struct DBG_LoadDefinitionStructure
90 LONG LDCodeImageOffset
;
91 LONG LDCodeImageLength
;
92 LONG LDDataImageOffset
;
93 LONG LDDataImageLength
;
94 LONG LDUninitializedDataLength
;
95 LONG LDCustomDataOffset
;
96 LONG LDCustomDataSize
;
98 LONG (*LDInitializationProcedure
)(void);
101 #define LO_NORMAL 0x0000
102 #define LO_STARTUP 0x0001
103 #define LO_PROTECT 0x0002
104 #define LO_DEBUG 0x0004
105 #define LO_AUTO_LOAD 0x0008
107 /* Loader returned error codes */
108 #define LOAD_COULD_NOT_FIND_FILE 1
109 #define LOAD_ERROR_READING_FILE 2
110 #define LOAD_NOT_NLM_FILE_FORMAT 3
111 #define LOAD_WRONG_NLM_FILE_VERSION 4
112 #define LOAD_REENTRANT_INITIALIZE_FAILURE 5
113 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6
114 #define LOAD_ALREADY_IN_PROGRESS 7
115 #define LOAD_NOT_ENOUGH_MEMORY 8
116 #define LOAD_INITIALIZE_FAILURE 9
117 #define LOAD_INCONSISTENT_FILE_FORMAT 10
118 #define LOAD_CAN_NOT_LOAD_AT_STARTUP 11
119 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12
120 #define LOAD_UNRESOLVED_EXTERNAL 13
121 #define LOAD_PUBLIC_ALREADY_DEFINED 14
122 /****************************************************/
124 /* The main thread ID. */
125 static int mainthread
;
127 /* The LoadDefinitionStructure of the NLM being debugged. */
128 static struct DBG_LoadDefinitionStructure
*handle
;
130 /* Whether we have connected to gdb. */
133 /* The actual first instruction in the program. */
134 static unsigned char first_insn
;
136 /* An error message for the main thread to print. */
137 static char *error_message
;
139 /* The AIO port handle. */
140 static int AIOhandle
;
142 /* BUFMAX defines the maximum number of characters in inbound/outbound
143 buffers. At least NUMREGBYTES*2 are needed for register packets */
146 /* remote_debug > 0 prints ill-formed commands in valid packets and
148 static int remote_debug
= 1;
150 static const char hexchars
[] = "0123456789abcdef";
152 /* Number of bytes of registers. */
153 #define NUMREGBYTES 64
154 enum regnames
{EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
,
155 PC
/* also known as eip */,
156 PS
/* also known as eflags */,
157 CS
, SS
, DS
, ES
, FS
, GS
};
159 /* Register values. */
160 static int registers
[NUMREGBYTES
/4];
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 /* Get the registers out of the frame information. */
212 frame_to_registers (frame
, regs
)
213 T_TSS_StackFrame
*frame
;
216 regs
[EAX
] = frame
->ExceptionEAX
;
217 regs
[ECX
] = frame
->ExceptionECX
;
218 regs
[EDX
] = frame
->ExceptionEDX
;
219 regs
[EBX
] = frame
->ExceptionEBX
;
220 regs
[ESP
] = frame
->ExceptionESP
;
221 regs
[EBP
] = frame
->ExceptionEBP
;
222 regs
[ESI
] = frame
->ExceptionESI
;
223 regs
[EDI
] = frame
->ExceptionEDI
;
224 regs
[PC
] = frame
->ExceptionEIP
;
225 regs
[PS
] = frame
->ExceptionSystemFlags
;
226 regs
[CS
] = frame
->ExceptionCS
[0];
227 regs
[SS
] = frame
->ExceptionSS
[0];
228 regs
[DS
] = frame
->ExceptionDS
[0];
229 regs
[ES
] = frame
->ExceptionES
[0];
230 regs
[FS
] = frame
->ExceptionFS
[0];
231 regs
[GS
] = frame
->ExceptionGS
[0];
234 /* Put the registers back into the frame information. */
237 registers_to_frame (regs
, frame
)
239 T_TSS_StackFrame
*frame
;
241 frame
->ExceptionEAX
= regs
[EAX
];
242 frame
->ExceptionECX
= regs
[ECX
];
243 frame
->ExceptionEDX
= regs
[EDX
];
244 frame
->ExceptionEBX
= regs
[EBX
];
245 frame
->ExceptionESP
= regs
[ESP
];
246 frame
->ExceptionEBP
= regs
[EBP
];
247 frame
->ExceptionESI
= regs
[ESI
];
248 frame
->ExceptionEDI
= regs
[EDI
];
249 frame
->ExceptionEIP
= regs
[PC
];
250 frame
->ExceptionSystemFlags
= regs
[PS
];
251 frame
->ExceptionCS
[0] = regs
[CS
];
252 frame
->ExceptionSS
[0] = regs
[SS
];
253 frame
->ExceptionDS
[0] = regs
[DS
];
254 frame
->ExceptionES
[0] = regs
[ES
];
255 frame
->ExceptionFS
[0] = regs
[FS
];
256 frame
->ExceptionGS
[0] = regs
[GS
];
259 /* Turn a hex character into a number. */
265 if ((ch
>= 'a') && (ch
<= 'f'))
267 if ((ch
>= '0') && (ch
<= '9'))
269 if ((ch
>= 'A') && (ch
<= 'F'))
274 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
275 non-zero on success. */
281 unsigned char checksum
;
282 unsigned char xmitcsum
;
289 /* wait around for the start character, ignore all other characters */
290 while ((ch
= getDebugChar()) != '$')
298 /* now, read until a # or end of buffer is found */
299 while (count
< BUFMAX
)
306 checksum
= checksum
+ ch
;
314 ch
= getDebugChar ();
317 xmitcsum
= hex(ch
) << 4;
318 ch
= getDebugChar ();
322 if ((remote_debug
) && (checksum
!= xmitcsum
))
324 fprintf(stderr
,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
325 checksum
,xmitcsum
,buffer
);
328 if (checksum
!= xmitcsum
)
330 /* failed checksum */
331 if (! putDebugChar('-'))
336 /* successful transfer */
337 if (! putDebugChar('+'))
339 /* if a sequence char is present, reply the sequence ID */
340 if (buffer
[2] == ':')
342 if (! putDebugChar (buffer
[0])
343 || ! putDebugChar (buffer
[1]))
345 /* remove sequence chars from buffer */
346 count
= strlen(buffer
);
347 for (i
=3; i
<= count
; i
++)
348 buffer
[i
-3] = buffer
[i
];
353 while (checksum
!= xmitcsum
);
356 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
361 /* Send the packet in buffer. Returns 0 on failure, non-zero on
368 unsigned char checksum
;
373 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
375 /* $<packet info>#<checksum>. */
378 if (! putDebugChar('$'))
383 while (ch
=buffer
[count
])
385 if (! putDebugChar(ch
))
391 if (! putDebugChar('#')
392 || ! putDebugChar(hexchars
[checksum
>> 4])
393 || ! putDebugChar(hexchars
[checksum
% 16]))
396 ch
= getDebugChar ();
405 static char remcomInBuffer
[BUFMAX
];
406 static char remcomOutBuffer
[BUFMAX
];
410 debug_error (format
, parm
)
416 fprintf (stderr
, format
, parm
);
417 fprintf (stderr
, "\n");
421 /* This is set if we could get a memory access fault. */
422 static int mem_may_fault
;
424 /* Indicate to caller of mem2hex or hex2mem that there has been an
426 static volatile int mem_err
= 0;
428 /* These are separate functions so that they are so short and sweet
429 that the compiler won't save any registers (if there is a fault
430 to mem_fault, they won't get restored, so there better not be any
448 /* This bit of assembly language just returns from a function. If a
449 memory error occurs within get_char or set_char, the debugger
450 handler points EIP at these instructions to get out. */
452 extern void just_return ();
453 asm (".globl just_return");
454 asm (".globl _just_return");
455 asm ("just_return:");
456 asm ("_just_return:");
460 /* convert the memory pointed to by mem into hex, placing result in buf */
461 /* return a pointer to the last char put in buf (null) */
462 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
463 a fault; if zero treat a fault like any other fault in the stub. */
466 mem2hex (mem
, buf
, count
, may_fault
)
475 mem_may_fault
= may_fault
;
476 for (i
= 0; i
< count
; i
++)
478 ch
= get_char (mem
++);
479 if (may_fault
&& mem_err
)
481 *buf
++ = hexchars
[ch
>> 4];
482 *buf
++ = hexchars
[ch
% 16];
489 /* convert the hex array pointed to by buf into binary to be placed in mem */
490 /* return a pointer to the character AFTER the last byte written */
493 hex2mem (buf
, mem
, count
, may_fault
)
502 mem_may_fault
= may_fault
;
503 for (i
=0;i
<count
;i
++)
505 ch
= hex(*buf
++) << 4;
506 ch
= ch
+ hex(*buf
++);
507 set_char (mem
++, ch
);
508 if (may_fault
&& mem_err
)
515 /* This function takes the 386 exception vector and attempts to
516 translate this number into a unix compatible signal value. */
519 computeSignal (exceptionVector
)
523 switch (exceptionVector
)
525 case 0 : sigval
= 8; break; /* divide by zero */
526 case 1 : sigval
= 5; break; /* debug exception */
527 case 3 : sigval
= 5; break; /* breakpoint */
528 case 4 : sigval
= 16; break; /* into instruction (overflow) */
529 case 5 : sigval
= 16; break; /* bound instruction */
530 case 6 : sigval
= 4; break; /* Invalid opcode */
531 case 7 : sigval
= 8; break; /* coprocessor not available */
532 case 8 : sigval
= 7; break; /* double fault */
533 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
534 case 10 : sigval
= 11; break; /* Invalid TSS */
535 case 11 : sigval
= 11; break; /* Segment not present */
536 case 12 : sigval
= 11; break; /* stack exception */
537 case 13 : sigval
= 11; break; /* general protection */
538 case 14 : sigval
= 11; break; /* page fault */
539 case 16 : sigval
= 7; break; /* coprocessor error */
541 sigval
= 7; /* "software generated"*/
546 /**********************************************/
547 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
548 /* RETURN NUMBER OF CHARS PROCESSED */
549 /**********************************************/
551 hexToInt(ptr
, intValue
)
562 hexValue
= hex(**ptr
);
565 *intValue
= (*intValue
<<4) | hexValue
;
577 /* This function does all command processing for interfacing to gdb.
578 It is called whenever an exception occurs in the module being
582 handle_exception (T_StackFrame
*old_frame
)
584 T_TSS_StackFrame
*frame
= (T_TSS_StackFrame
*) old_frame
;
590 /* Apparently the bell can sometimes be ringing at this point, and
591 should be stopped. */
596 ConsolePrintf ("vector=%d: %s, sr=%08x, pc=%08x, thread=%08x\r\n",
597 frame
->ExceptionNumber
,
598 frame
->ExceptionDescription
,
599 frame
->ExceptionSystemFlags
,
604 /* If the NLM just started, we record the module load information
605 and the thread ID, and set a breakpoint at the first instruction
607 if (frame
->ExceptionNumber
== START_NLM_EVENT
610 handle
= ((struct DBG_LoadDefinitionStructure
*)
611 frame
->ExceptionErrorCode
);
612 first_insn
= *(char *) handle
->LDInitializationProcedure
;
613 *(unsigned char *) handle
->LDInitializationProcedure
= 0xcc;
614 ConsolePrintf ("NLM offsets/lengths: Code: 0x%x/0x%x, Data: 0x%x/0x%x, BSS: /0x%x\r\n",
615 handle
->LDCodeImageOffset
, handle
->LDCodeImageLength
,
616 handle
->LDDataImageOffset
, handle
->LDDataImageLength
,
617 handle
->LDUninitializedDataLength
);
619 return RETURN_TO_PROGRAM
;
622 /* After we've reached the initial breakpoint, reset it. */
623 if (frame
->ExceptionEIP
== (LONG
) handle
->LDInitializationProcedure
+ 1
624 && *(unsigned char *) handle
->LDInitializationProcedure
== 0xcc)
626 *(char *) handle
->LDInitializationProcedure
= first_insn
;
627 frame
->ExceptionEIP
= (LONG
) handle
->LDInitializationProcedure
;
630 /* Pass some events on to the next debugger, in case it will handle
632 if (frame
->ExceptionNumber
== ENTER_DEBUGGER_EVENT
633 || frame
->ExceptionNumber
== KEYBOARD_BREAK_EVENT
)
634 return RETURN_TO_NEXT_DEBUGGER
;
636 /* At the moment, we don't care about most of the unusual NetWare
638 if (frame
->ExceptionNumber
!= TERMINATE_NLM_EVENT
639 && frame
->ExceptionNumber
> 31)
640 return RETURN_TO_PROGRAM
;
642 /* If we get a GP fault, and mem_may_fault is set, and the
643 instruction pointer is near set_char or get_char, then we caused
644 the fault ourselves accessing an illegal memory location. */
646 && (frame
->ExceptionNumber
== 11
647 || frame
->ExceptionNumber
== 13
648 || frame
->ExceptionNumber
== 14)
649 && ((frame
->ExceptionEIP
>= (long) &set_char
650 && frame
->ExceptionEIP
< (long) &set_char
+ 50)
651 || (frame
->ExceptionEIP
>= (long) &get_char
652 && frame
->ExceptionEIP
< (long) &get_char
+ 50)))
655 /* Point the instruction pointer at an assembly language stub
656 which just returns from the function. */
657 frame
->ExceptionEIP
= (long) &just_return
;
658 /* Keep going. This will act as though it returned from
659 set_char or get_char. The calling routine will check
660 mem_err, and do the right thing. */
661 return RETURN_TO_PROGRAM
;
664 /* FIXME: How do we know that this exception has anything to do with
665 the program we are debugging? We can check whether the PC is in
666 the range of the module we are debugging, but that doesn't help
667 much since an error could occur in a library routine. */
669 frame_to_registers (frame
, registers
);
671 /* reply to host that an exception has occurred */
672 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
674 /* There is no way to get the exit status. */
675 remcomOutBuffer
[0] = 'W';
676 remcomOutBuffer
[1] = hexchars
[0];
677 remcomOutBuffer
[2] = hexchars
[0];
678 remcomOutBuffer
[3] = 0;
682 sigval
= computeSignal (frame
->ExceptionNumber
);
683 remcomOutBuffer
[0] = 'S';
684 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
685 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
686 remcomOutBuffer
[3] = 0;
689 if (! putpacket(remcomOutBuffer
))
690 return RETURN_TO_NEXT_DEBUGGER
;
692 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
694 ResumeThread (mainthread
);
695 return RETURN_TO_PROGRAM
;
701 remcomOutBuffer
[0] = 0;
702 if (! getpacket (remcomInBuffer
))
703 return RETURN_TO_NEXT_DEBUGGER
;
705 switch (remcomInBuffer
[0])
708 sigval
= computeSignal (frame
->ExceptionNumber
);
709 remcomOutBuffer
[0] = 'S';
710 remcomOutBuffer
[1] = hexchars
[sigval
>> 4];
711 remcomOutBuffer
[2] = hexchars
[sigval
% 16];
712 remcomOutBuffer
[3] = 0;
715 remote_debug
= !(remote_debug
); /* toggle debug flag */
718 /* return the value of the CPU registers */
719 mem2hex((char*) registers
, remcomOutBuffer
, NUMREGBYTES
, 0);
722 /* set the value of the CPU registers - return OK */
723 hex2mem(&remcomInBuffer
[1], (char*) registers
, NUMREGBYTES
, 0);
724 strcpy(remcomOutBuffer
,"OK");
728 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
729 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
730 ptr
= &remcomInBuffer
[1];
731 if (hexToInt(&ptr
,&addr
))
733 if (hexToInt(&ptr
,&length
))
737 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
740 strcpy (remcomOutBuffer
, "E03");
741 debug_error ("memory fault");
747 strcpy(remcomOutBuffer
,"E01");
748 debug_error("malformed read memory command: %s",remcomInBuffer
);
753 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
754 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
755 ptr
= &remcomInBuffer
[1];
756 if (hexToInt(&ptr
,&addr
))
758 if (hexToInt(&ptr
,&length
))
762 hex2mem(ptr
, (char*) addr
, length
, 1);
766 strcpy (remcomOutBuffer
, "E03");
767 debug_error ("memory fault");
771 strcpy(remcomOutBuffer
,"OK");
778 strcpy(remcomOutBuffer
,"E02");
779 debug_error("malformed write memory command: %s",remcomInBuffer
);
785 /* cAA..AA Continue at address AA..AA(optional) */
786 /* sAA..AA Step one instruction from AA..AA(optional) */
787 /* try to read optional parameter, pc unchanged if no parm */
788 ptr
= &remcomInBuffer
[1];
789 if (hexToInt(&ptr
,&addr
))
790 registers
[ PC
] = addr
;
792 newPC
= registers
[ PC
];
794 /* clear the trace bit */
795 registers
[ PS
] &= 0xfffffeff;
797 /* set the trace bit if we're stepping */
798 if (remcomInBuffer
[0] == 's') registers
[ PS
] |= 0x100;
800 registers_to_frame (registers
, frame
);
801 return RETURN_TO_PROGRAM
;
804 /* kill the program */
806 ResumeThread (mainthread
);
807 return RETURN_TO_PROGRAM
;
809 case 'q': /* Query message */
810 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
812 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
813 handle
->LDCodeImageOffset
,
814 handle
->LDDataImageOffset
,
815 handle
->LDDataImageOffset
+ handle
->LDDataImageLength
);
818 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
822 /* reply to the request */
823 if (! putpacket(remcomOutBuffer
))
824 return RETURN_TO_NEXT_DEBUGGER
;
828 char *baudRates
[] = { "50", "75", "110", "134.5", "150", "300", "600", "1200",
829 "1800", "2000", "2400", "3600", "4800", "7200", "9600",
830 "19200", "38400", "57600", "115200" };
832 char dataBits
[] = "5678";
834 char *stopBits
[] = { "1", "1.5", "2" };
836 char parity
[] = "NOEMS";
838 /* Start up. The main thread opens the named serial I/O port, loads
839 the named NLM module and then goes to sleep. The serial I/O port
840 is named as a board number and a port number. It would be more DOS
841 like to provide a menu of available serial ports, but I don't want
842 to have to figure out how to do that. */
849 int hardware
, board
, port
;
851 struct debuggerStructure s
;
855 /* Use the -B option to invoke the NID if you want to debug the stub. */
857 if (argc
> 1 && strcmp(argv
[1], "-B") == 0)
866 "Usage: load gdbserve board port program [arguments]\n");
871 board
= strtol (argv
[1], (char **) NULL
, 0);
872 port
= strtol (argv
[2], (char **) NULL
, 0);
874 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
875 if (err
!= AIO_SUCCESS
)
879 case AIO_PORT_NOT_AVAILABLE
:
880 fprintf (stderr
, "Port not available\n");
883 case AIO_BOARD_NUMBER_INVALID
:
884 case AIO_PORT_NUMBER_INVALID
:
885 fprintf (stderr
, "No such port\n");
889 fprintf (stderr
, "Could not open port: %d\n", err
);
896 err
= AIOConfigurePort (AIOhandle
, AIO_BAUD_9600
, AIO_DATA_BITS_8
,
897 AIO_STOP_BITS_1
, AIO_PARITY_NONE
,
898 AIO_HARDWARE_FLOW_CONTROL_OFF
);
900 if (err
== AIO_QUALIFIED_SUCCESS
)
902 AIOPORTCONFIG portConfig
;
903 AIODVRCONFIG dvrConfig
;
905 fprintf (stderr
, "Port configuration changed!\n");
906 AIOGetPortConfiguration (AIOhandle
, &portConfig
, &dvrConfig
);
908 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
910 baudRates
[portConfig
.bitRate
],
911 dataBits
[portConfig
.dataBits
],
912 stopBits
[portConfig
.stopBits
],
913 parity
[portConfig
.parityMode
],
914 portConfig
.flowCtrlMode
? "ON" : "OFF");
916 else if (err
!= AIO_SUCCESS
)
918 fprintf (stderr
, "Could not configure port: %d\n", err
);
919 AIOReleasePort (AIOhandle
);
923 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
924 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
927 LONG extStatus
, chgdExtStatus
;
929 fprintf (stderr
, "Could not set desired port controls!\n");
930 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
931 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
935 /* Register ourselves as an alternate debugger. */
936 memset (&s
, 0, sizeof s
);
937 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
938 AllocateResourceTag (GetNLMHandle (),
941 if (s
.DDSResourceTag
== 0)
943 fprintf (stderr
, "AllocateResourceTag failed\n");
944 AIOReleasePort (AIOhandle
);
947 s
.DDSdebuggerEntry
= handle_exception
;
948 s
.DDSFlags
= TSS_FRAME_BIT
;
950 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
953 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
954 AIOReleasePort (AIOhandle
);
958 /* Get the command line we were invoked with, and advance it past
959 our name and the board and port arguments. */
960 cmdlin
= getcmd ((char *) NULL
);
961 for (i
= 0; i
< 2; i
++)
963 while (! isspace (*cmdlin
))
965 while (isspace (*cmdlin
))
969 /* In case GDB is started before us, ack any packets (presumably
970 "$?#xx") sitting there. */
971 if (! putDebugChar ('+'))
973 fprintf (stderr
, "putDebugChar failed\n");
974 UnRegisterDebugger (&s
);
975 AIOReleasePort (AIOhandle
);
979 mainthread
= GetThreadID ();
983 if (remote_debug
> 0)
984 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
985 cmdlin
, __GetScreenID (GetCurrentScreen()));
987 /* Start up the module to be debugged. */
988 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
992 fprintf (stderr
, "LoadModule failed: %d\n", err
);
993 UnRegisterDebugger (&s
);
994 AIOReleasePort (AIOhandle
);
998 /* Wait for the debugger to wake us up. */
999 if (remote_debug
> 0)
1000 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1001 SuspendThread (mainthread
);
1002 if (remote_debug
> 0)
1003 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1005 /* If we are woken up, print an optional error message, deregister
1006 ourselves and exit. */
1007 if (error_message
!= NULL
)
1008 fprintf (stderr
, "%s\n", error_message
);
1009 UnRegisterDebugger (&s
);
1010 AIOReleasePort (AIOhandle
);