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 ****************************************************************************/
73 /*#include <ctype.h>*/
79 /*#include <process.h>*/
82 #include "alpha-patch.h"
84 /****************************************************/
85 /* This information is from Novell. It is not in any of the standard
86 NetWare header files. */
88 struct DBG_LoadDefinitionStructure
92 LONG LDCodeImageOffset;
93 LONG LDCodeImageLength;
94 LONG LDDataImageOffset;
95 LONG LDDataImageLength;
96 LONG LDUninitializedDataLength;
97 LONG LDCustomDataOffset;
98 LONG LDCustomDataSize;
100 LONG (*LDInitializationProcedure)(void);
103 #define LO_NORMAL 0x0000
104 #define LO_STARTUP 0x0001
105 #define LO_PROTECT 0x0002
106 #define LO_DEBUG 0x0004
107 #define LO_AUTO_LOAD 0x0008
109 /* Loader returned error codes */
110 #define LOAD_COULD_NOT_FIND_FILE 1
111 #define LOAD_ERROR_READING_FILE 2
112 #define LOAD_NOT_NLM_FILE_FORMAT 3
113 #define LOAD_WRONG_NLM_FILE_VERSION 4
114 #define LOAD_REENTRANT_INITIALIZE_FAILURE 5
115 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6
116 #define LOAD_ALREADY_IN_PROGRESS 7
117 #define LOAD_NOT_ENOUGH_MEMORY 8
118 #define LOAD_INITIALIZE_FAILURE 9
119 #define LOAD_INCONSISTENT_FILE_FORMAT 10
120 #define LOAD_CAN_NOT_LOAD_AT_STARTUP 11
121 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12
122 #define LOAD_UNRESOLVED_EXTERNAL 13
123 #define LOAD_PUBLIC_ALREADY_DEFINED 14
124 /****************************************************/
126 /* The main thread ID. */
127 static int mainthread;
129 /* An error message for the main thread to print. */
130 static char *error_message;
132 /* The AIO port handle. */
133 static int AIOhandle;
135 /* BUFMAX defines the maximum number of characters in inbound/outbound
136 buffers. At least NUMREGBYTES*2 are needed for register packets */
137 #define BUFMAX (REGISTER_BYTES * 2 + 16)
139 /* remote_debug > 0 prints ill-formed commands in valid packets and
141 static int remote_debug = 1;
143 static const char hexchars[] = "0123456789abcdef";
145 /* Register values. All of these values *MUST* agree with tm.h */
146 #define RA_REGNUM 26 /* Contains return address value */
147 #define SP_REGNUM 30 /* Contains address of top of stack */
148 #define PC_REGNUM 64 /* Contains program counter */
149 #define FP_REGNUM 65 /* Virtual frame pointer */
150 #define V0_REGNUM 0 /* Function integer return value */
151 #define NUM_REGS 66 /* Number of machine registers */
152 #define REGISTER_BYTES (NUM_REGS * 8) /* Total size of registers array */
154 #define ExceptionPC ExceptionRegs[SF_REG_PC].lo
155 #define DECR_PC_AFTER_BREAK 0 /* NT's Palcode gets this right! */
156 #define BREAKPOINT {0x80, 0, 0, 0} /* call_pal bpt */
158 unsigned char breakpoint_insn[] = BREAKPOINT;
159 #define BREAKPOINT_SIZE (sizeof breakpoint_insn)
161 /*#define flush_i_cache() asm("call_pal 0x86")*/
163 static char *mem2hex (void *mem, char *buf, int count, int may_fault);
164 static char *hex2mem (char *buf, void *mem, int count, int may_fault);
165 static void set_step_traps (struct StackFrame *);
166 static void clear_step_traps (struct StackFrame *);
172 /* Read a character from the serial port. This must busy wait, but
173 that's OK because we will be the only thread running anyhow. */
184 err = AIOReadData (AIOhandle, (char *) &ret, 1, &got);
187 error_message = "AIOReadData failed";
188 ResumeThread (mainthread);
197 /* Write a character to the serial port. Returns 0 on failure,
198 non-zero on success. */
210 err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
212 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
217 /* Get the registers out of the frame information. */
220 frame_to_registers (frame, regs)
221 struct StackFrame *frame;
224 mem2hex (&frame->ExceptionPC, ®s[PC_REGNUM * 8 * 2], 8 * 1, 0);
226 mem2hex (&frame->ExceptionRegs[SF_IREG_OFFSET], ®s[V0_REGNUM * 8 * 2], 8 * 64, 0);
229 /* Put the registers back into the frame information. */
232 registers_to_frame (regs, frame)
234 struct StackFrame *frame;
236 hex2mem (®s[PC_REGNUM * 8 * 2], &frame->ExceptionPC, 8 * 1, 0);
238 hex2mem (®s[V0_REGNUM * 8 * 2], &frame->ExceptionRegs[SF_IREG_OFFSET], 8 * 64, 0);
241 /* Turn a hex character into a number. */
247 if ((ch >= 'a') && (ch <= 'f'))
249 if ((ch >= '0') && (ch <= '9'))
251 if ((ch >= 'A') && (ch <= 'F'))
256 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
257 non-zero on success. */
263 unsigned char checksum;
264 unsigned char xmitcsum;
271 /* wait around for the start character, ignore all other characters */
272 while ((ch = getDebugChar()) != '$')
280 /* now, read until a # or end of buffer is found */
281 while (count < BUFMAX)
288 checksum = checksum + ch;
296 ch = getDebugChar ();
299 xmitcsum = hex(ch) << 4;
300 ch = getDebugChar ();
305 if (checksum != xmitcsum)
308 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
309 checksum,xmitcsum,buffer);
310 /* failed checksum */
311 if (! putDebugChar('-'))
317 /* successful transfer */
318 if (! putDebugChar('+'))
320 /* if a sequence char is present, reply the sequence ID */
321 if (buffer[2] == ':')
323 if (! putDebugChar (buffer[0])
324 || ! putDebugChar (buffer[1]))
326 /* remove sequence chars from buffer */
327 count = strlen(buffer);
328 for (i=3; i <= count; i++)
329 buffer[i-3] = buffer[i];
334 while (checksum != xmitcsum);
337 ConsolePrintf ("Received packet \"%s\"\r\n", buffer);
342 /* Send the packet in buffer. Returns 0 on failure, non-zero on
349 unsigned char checksum;
354 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer);
356 /* $<packet info>#<checksum>. */
359 if (! putDebugChar('$'))
364 while (ch=buffer[count])
366 if (! putDebugChar(ch))
372 if (! putDebugChar('#')
373 || ! putDebugChar(hexchars[checksum >> 4])
374 || ! putDebugChar(hexchars[checksum % 16]))
377 ch = getDebugChar ();
386 static char remcomInBuffer[BUFMAX];
387 static char remcomOutBuffer[BUFMAX];
391 debug_error (format, parm)
397 ConsolePrintf (format, parm);
398 ConsolePrintf ("\n");
402 /* This is set if we could get a memory access fault. */
403 static int mem_may_fault;
405 /* Indicate to caller of mem2hex or hex2mem that there has been an
407 static volatile int mem_err = 0;
409 /* These are separate functions so that they are so short and sweet
410 that the compiler won't save any registers (if there is a fault
411 to mem_fault, they won't get restored, so there better not be any
429 /* This bit of assembly language just returns from a function. If a
430 memory error occurs within get_char or set_char, the debugger
431 handler points EIP at these instructions to get out. */
433 extern void just_return ();
435 asm (".globl just_return");
436 asm (".globl _just_return");
437 asm ("just_return:");
438 asm ("_just_return:");
443 /* convert the memory pointed to by mem into hex, placing result in buf */
444 /* return a pointer to the last char put in buf (null) */
445 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
446 a fault; if zero treat a fault like any other fault in the stub. */
449 mem2hex (mem, buf, count, may_fault)
459 mem_may_fault = may_fault;
460 for (i = 0; i < count; i++)
462 ch = get_char (ptr++);
463 if (may_fault && mem_err)
465 *buf++ = hexchars[ch >> 4];
466 *buf++ = hexchars[ch % 16];
473 /* convert the hex array pointed to by buf into binary to be placed in mem */
474 /* return a pointer to the character AFTER the last byte written */
477 hex2mem (buf, mem, count, may_fault)
487 mem_may_fault = may_fault;
488 for (i=0;i<count;i++)
490 ch = hex(*buf++) << 4;
491 ch = ch + hex(*buf++);
492 set_char (ptr++, ch);
493 if (may_fault && mem_err)
500 /* This function takes the 386 exception vector and attempts to
501 translate this number into a unix compatible signal value. */
504 computeSignal (exceptionVector)
508 switch (exceptionVector)
510 case 0 : sigval = 8; break; /* divide by zero */
511 case 1 : sigval = 5; break; /* debug exception */
512 case 3 : sigval = 5; break; /* breakpoint */
513 case 4 : sigval = 16; break; /* into instruction (overflow) */
514 case 5 : sigval = 16; break; /* bound instruction */
515 case 6 : sigval = 4; break; /* Invalid opcode */
516 case 7 : sigval = 8; break; /* coprocessor not available */
517 case 8 : sigval = 7; break; /* double fault */
518 case 9 : sigval = 11; break; /* coprocessor segment overrun */
519 case 10 : sigval = 11; break; /* Invalid TSS */
520 case 11 : sigval = 11; break; /* Segment not present */
521 case 12 : sigval = 11; break; /* stack exception */
522 case 13 : sigval = 11; break; /* general protection */
523 case 14 : sigval = 11; break; /* page fault */
524 case 16 : sigval = 7; break; /* coprocessor error */
526 sigval = 7; /* "software generated"*/
531 /**********************************************/
532 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
533 /* RETURN NUMBER OF CHARS PROCESSED */
534 /**********************************************/
536 hexToInt(ptr, intValue)
547 hexValue = hex(**ptr);
550 *intValue = (*intValue <<4) | hexValue;
587 static LONG saved_inst;
588 static LONG *saved_inst_pc = 0;
589 static LONG saved_target_inst;
590 static LONG *saved_target_inst_pc = 0;
593 set_step_traps (frame)
594 struct StackFrame *frame;
600 LONG *pc = (LONG *)frame->ExceptionPC;
604 opcode = inst.inst.variant.branch.opcode;
606 if ((opcode & 0x30) == 0x30) /* A branch of some sort */
607 target = inst.inst.variant.branch.disp + pc;
608 else if (opcode == 0x1a) /* jmp, ret, etc... */
609 target = (LONG *)(frame->ExceptionRegs[SF_IREG_OFFSET
610 + inst.inst.variant.jump.rb].lo
616 *pc = 0x80; /* call_pal bpt */
621 saved_target_inst = *target;
622 *target = 0x80; /* call_pal bpt */
623 saved_target_inst_pc = target;
627 /* Remove step breakpoints. Returns non-zero if pc was at a step breakpoint,
628 zero otherwise. This routine works even if there were no step breakpoints
632 clear_step_traps (frame)
633 struct StackFrame *frame;
636 LONG *pc = (LONG *)frame->ExceptionPC;
638 if (saved_inst_pc == pc || saved_target_inst_pc == pc)
645 *saved_inst_pc = saved_inst;
649 if (saved_target_inst_pc)
651 *saved_target_inst_pc = saved_target_inst;
652 saved_target_inst_pc = 0;
659 do_status (ptr, frame)
661 struct StackFrame *frame;
665 sigval = computeSignal (frame->ExceptionNumber);
667 sprintf (ptr, "T%02x", sigval);
670 sprintf (ptr, "%02x:", PC_REGNUM);
671 ptr = mem2hex (&frame->ExceptionPC, ptr + 3, 8, 0);
674 sprintf (ptr, "%02x:", SP_REGNUM);
675 ptr = mem2hex (&frame->ExceptionRegs[SF_IREG_OFFSET + SP_REGNUM], ptr + 3, 8, 0);
678 sprintf (ptr, "%02x:", RA_REGNUM);
679 ptr = mem2hex (&frame->ExceptionRegs[SF_IREG_OFFSET + RA_REGNUM], ptr + 3, 8, 0);
682 sprintf (ptr, "%02x:", FP_REGNUM);
683 ptr = mem2hex (&frame->ExceptionRegs[SF_IREG_OFFSET + FP_REGNUM], ptr + 3, 8, 0);
689 /* This function does all command processing for interfacing to gdb.
690 It is called whenever an exception occurs in the module being
694 handle_exception (frame)
695 struct StackFrame *frame;
699 static struct DBG_LoadDefinitionStructure *ldinfo = 0;
700 static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program. */
702 /* Apparently the bell can sometimes be ringing at this point, and
703 should be stopped. */
708 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
709 frame->ExceptionNumber,
710 frame->ExceptionDescription,
715 switch (frame->ExceptionNumber)
717 case START_NLM_EVENT:
718 /* If the NLM just started, we record the module load information
719 and the thread ID, and set a breakpoint at the first instruction
722 ldinfo = ((struct DBG_LoadDefinitionStructure *)
723 frame->ExceptionErrorCode);
724 memcpy (first_insn, ldinfo->LDInitializationProcedure,
726 memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
729 return RETURN_TO_PROGRAM;
731 case ENTER_DEBUGGER_EVENT:
732 case KEYBOARD_BREAK_EVENT:
733 /* Pass some events on to the next debugger, in case it will handle
735 return RETURN_TO_NEXT_DEBUGGER;
737 case 3: /* Breakpoint */
738 /* After we've reached the initial breakpoint, reset it. */
739 if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
740 && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
741 BREAKPOINT_SIZE) == 0)
743 memcpy (ldinfo->LDInitializationProcedure, first_insn,
745 frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
748 /* Normal breakpoints end up here */
749 do_status (remcomOutBuffer, frame);
753 /* At the moment, we don't care about most of the unusual NetWare
755 if (frame->ExceptionNumber > 31)
756 return RETURN_TO_PROGRAM;
758 /* Most machine level exceptions end up here */
759 do_status (remcomOutBuffer, frame);
762 case 11: /* Segment not present */
763 case 13: /* General protection */
764 case 14: /* Page fault */
765 /* If we get a GP fault, and mem_may_fault is set, and the
766 instruction pointer is near set_char or get_char, then we caused
767 the fault ourselves accessing an illegal memory location. */
769 && ((frame->ExceptionPC >= (long) &set_char
770 && frame->ExceptionPC < (long) &set_char + 50)
771 || (frame->ExceptionPC >= (long) &get_char
772 && frame->ExceptionPC < (long) &get_char + 50)))
775 /* Point the instruction pointer at an assembly language stub
776 which just returns from the function. */
778 frame->ExceptionPC += 4; /* Skip the load or store */
780 /* Keep going. This will act as though it returned from
781 set_char or get_char. The calling routine will check
782 mem_err, and do the right thing. */
783 return RETURN_TO_PROGRAM;
785 /* Random mem fault, report it */
786 do_status (remcomOutBuffer, frame);
789 case TERMINATE_NLM_EVENT:
790 /* There is no way to get the exit status. */
791 sprintf (remcomOutBuffer, "W%02x", 0);
792 break; /* We generate our own status */
795 /* FIXME: How do we know that this exception has anything to do with
796 the program we are debugging? We can check whether the PC is in
797 the range of the module we are debugging, but that doesn't help
798 much since an error could occur in a library routine. */
800 clear_step_traps (frame);
802 if (! putpacket(remcomOutBuffer))
803 return RETURN_TO_NEXT_DEBUGGER;
805 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
807 ResumeThread (mainthread);
808 return RETURN_TO_PROGRAM;
814 remcomOutBuffer[0] = 0;
815 if (! getpacket (remcomInBuffer))
816 return RETURN_TO_NEXT_DEBUGGER;
817 switch (remcomInBuffer[0])
820 do_status (remcomOutBuffer, frame);
823 remote_debug = !(remote_debug); /* toggle debug flag */
826 /* return the value of the CPU registers */
827 frame_to_registers (frame, remcomOutBuffer);
830 /* set the value of the CPU registers - return OK */
831 registers_to_frame (&remcomInBuffer[1], frame);
832 strcpy(remcomOutBuffer,"OK");
836 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
837 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
838 ptr = &remcomInBuffer[1];
839 if (hexToInt(&ptr,&addr))
841 if (hexToInt(&ptr,&length))
845 mem2hex((char*) addr, remcomOutBuffer, length, 1);
848 strcpy (remcomOutBuffer, "E03");
849 debug_error ("memory fault");
855 strcpy(remcomOutBuffer,"E01");
856 debug_error("malformed read memory command: %s",remcomInBuffer);
861 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
862 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
863 ptr = &remcomInBuffer[1];
864 if (hexToInt(&ptr,&addr))
866 if (hexToInt(&ptr,&length))
870 hex2mem(ptr, (char*) addr, length, 1);
874 strcpy (remcomOutBuffer, "E03");
875 debug_error ("memory fault");
879 strcpy(remcomOutBuffer,"OK");
886 strcpy(remcomOutBuffer,"E02");
887 debug_error("malformed write memory command: %s",remcomInBuffer);
893 /* cAA..AA Continue at address AA..AA(optional) */
894 /* sAA..AA Step one instruction from AA..AA(optional) */
895 /* try to read optional parameter, pc unchanged if no parm */
896 ptr = &remcomInBuffer[1];
897 if (hexToInt(&ptr,&addr))
899 /* registers[PC_REGNUM].lo = addr;*/
900 fprintf (stderr, "Setting PC to 0x%x\n", addr);
904 if (remcomInBuffer[0] == 's')
905 set_step_traps (frame);
908 return RETURN_TO_PROGRAM;
911 /* kill the program */
913 ResumeThread (mainthread);
914 return RETURN_TO_PROGRAM;
916 case 'q': /* Query message */
917 if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
919 sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
920 ldinfo->LDCodeImageOffset,
921 ldinfo->LDDataImageOffset,
922 ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
925 sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
929 /* reply to the request */
930 if (! putpacket(remcomOutBuffer))
931 return RETURN_TO_NEXT_DEBUGGER;
935 char *baudRates[] = { "50", "75", "110", "134.5", "150", "300", "600", "1200",
936 "1800", "2000", "2400", "3600", "4800", "7200", "9600",
937 "19200", "38400", "57600", "115200" };
939 char dataBits[] = "5678";
941 char *stopBits[] = { "1", "1.5", "2" };
943 char parity[] = "NOEMS";
945 /* Start up. The main thread opens the named serial I/O port, loads
946 the named NLM module and then goes to sleep. The serial I/O port
947 is named as a board number and a port number. It would be more DOS
948 like to provide a menu of available serial ports, but I don't want
949 to have to figure out how to do that. */
956 int hardware, board, port;
958 struct debuggerStructure s;
962 /* Use the -B option to invoke the NID if you want to debug the stub. */
964 if (argc > 1 && strcmp(argv[1], "-B") == 0)
973 "Usage: load gdbserve board port program [arguments]\n");
978 board = strtol (argv[1], (char **) NULL, 0);
979 port = strtol (argv[2], (char **) NULL, 0);
981 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
982 if (err != AIO_SUCCESS)
986 case AIO_PORT_NOT_AVAILABLE:
987 fprintf (stderr, "Port not available\n");
990 case AIO_BOARD_NUMBER_INVALID:
991 case AIO_PORT_NUMBER_INVALID:
992 fprintf (stderr, "No such port\n");
996 fprintf (stderr, "Could not open port: %d\n", err);
1003 err = AIOConfigurePort (AIOhandle, AIO_BAUD_9600, AIO_DATA_BITS_8,
1004 AIO_STOP_BITS_1, AIO_PARITY_NONE,
1005 AIO_HARDWARE_FLOW_CONTROL_OFF);
1007 if (err == AIO_QUALIFIED_SUCCESS)
1009 AIOPORTCONFIG portConfig;
1010 AIODVRCONFIG dvrConfig;
1012 fprintf (stderr, "Port configuration changed!\n");
1013 AIOGetPortConfiguration (AIOhandle, &portConfig, &dvrConfig);
1015 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
1017 baudRates[portConfig.bitRate],
1018 dataBits[portConfig.dataBits],
1019 stopBits[portConfig.stopBits],
1020 parity[portConfig.parityMode],
1021 portConfig.flowCtrlMode ? "ON" : "OFF");
1023 else if (err != AIO_SUCCESS)
1025 fprintf (stderr, "Could not configure port: %d\n", err);
1026 AIOReleasePort (AIOhandle);
1030 if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
1031 (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
1034 LONG extStatus, chgdExtStatus;
1036 fprintf (stderr, "Could not set desired port controls!\n");
1037 AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
1038 fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
1042 /* Register ourselves as an alternate debugger. */
1043 memset (&s, 0, sizeof s);
1044 s.DDSResourceTag = ((struct ResourceTagStructure *)
1045 AllocateResourceTag (GetNLMHandle (),
1046 (BYTE *)"gdbserver",
1047 DebuggerSignature));
1048 if (s.DDSResourceTag == 0)
1050 fprintf (stderr, "AllocateResourceTag failed\n");
1051 AIOReleasePort (AIOhandle);
1054 s.DDSdebuggerEntry = handle_exception;
1055 s.DDSFlags = TSS_FRAME_BIT;
1057 err = RegisterDebuggerRTag (&s, AT_FIRST);
1060 fprintf (stderr, "RegisterDebuggerRTag failed\n");
1061 AIOReleasePort (AIOhandle);
1065 /* Get the command line we were invoked with, and advance it past
1066 our name and the board and port arguments. */
1067 cmdlin = getcmd ((char *) NULL);
1068 for (i = 0; i < 2; i++)
1070 while (! isspace (*cmdlin))
1072 while (isspace (*cmdlin))
1076 /* In case GDB is started before us, ack any packets (presumably
1077 "$?#xx") sitting there. */
1078 if (! putDebugChar ('+'))
1080 fprintf (stderr, "putDebugChar failed\n");
1081 UnRegisterDebugger (&s);
1082 AIOReleasePort (AIOhandle);
1086 mainthread = GetThreadID ();
1088 if (remote_debug > 0)
1089 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1090 cmdlin, __GetScreenID (GetCurrentScreen()));
1092 /* Start up the module to be debugged. */
1093 err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1094 (BYTE *)cmdlin, LO_DEBUG);
1097 fprintf (stderr, "LoadModule failed: %d\n", err);
1098 UnRegisterDebugger (&s);
1099 AIOReleasePort (AIOhandle);
1103 /* Wait for the debugger to wake us up. */
1104 if (remote_debug > 0)
1105 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1106 SuspendThread (mainthread);
1107 if (remote_debug > 0)
1108 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1110 /* If we are woken up, print an optional error message, deregister
1111 ourselves and exit. */
1112 if (error_message != NULL)
1113 fprintf (stderr, "%s\n", error_message);
1114 UnRegisterDebugger (&s);
1115 AIOReleasePort (AIOhandle);