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 flush_i_cache() asm("call_pal 0x86")*/
156 static char *mem2hex (void *mem
, char *buf
, int count
, int may_fault
);
157 static char *hex2mem (char *buf
, void *mem
, int count
, int may_fault
);
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. */
198 err
= AIOWriteData (AIOhandle
, (char *) &c
, 1, &put
);
199 if (err
!= 0 || put
!= 1)
201 error_message
= "AIOWriteData failed";
202 ResumeThread (mainthread
);
208 /* Get the registers out of the frame information. */
211 frame_to_registers (frame
, regs
)
212 struct StackFrame
*frame
;
215 mem2hex (&frame
->ExceptionRegs
[SF_REG_PC
], ®s
[PC_REGNUM
* 8 * 2], 8, 0);
217 mem2hex (&frame
->ExceptionRegs
[SF_IREG_OFFSET
], ®s
[V0_REGNUM
* 8 * 2], 8 * 64, 0);
220 /* Put the registers back into the frame information. */
223 registers_to_frame (regs
, frame
)
225 struct StackFrame
*frame
;
227 hex2mem (®s
[PC_REGNUM
* 8 * 2], &frame
->ExceptionRegs
[SF_REG_PC
], 8, 0);
229 hex2mem (®s
[V0_REGNUM
* 8 * 2], &frame
->ExceptionRegs
[SF_IREG_OFFSET
], 8 * 64, 0);
232 /* Turn a hex character into a number. */
238 if ((ch
>= 'a') && (ch
<= 'f'))
240 if ((ch
>= '0') && (ch
<= '9'))
242 if ((ch
>= 'A') && (ch
<= 'F'))
247 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
248 non-zero on success. */
254 unsigned char checksum
;
255 unsigned char xmitcsum
;
262 /* wait around for the start character, ignore all other characters */
263 while ((ch
= getDebugChar()) != '$')
271 /* now, read until a # or end of buffer is found */
272 while (count
< BUFMAX
)
279 checksum
= checksum
+ ch
;
287 ch
= getDebugChar ();
290 xmitcsum
= hex(ch
) << 4;
291 ch
= getDebugChar ();
296 if (checksum
!= xmitcsum
)
299 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
300 checksum
,xmitcsum
,buffer
);
301 /* failed checksum */
302 if (! putDebugChar('-'))
308 /* successful transfer */
309 if (! putDebugChar('+'))
311 /* if a sequence char is present, reply the sequence ID */
312 if (buffer
[2] == ':')
314 if (! putDebugChar (buffer
[0])
315 || ! putDebugChar (buffer
[1]))
317 /* remove sequence chars from buffer */
318 count
= strlen(buffer
);
319 for (i
=3; i
<= count
; i
++)
320 buffer
[i
-3] = buffer
[i
];
325 while (checksum
!= xmitcsum
);
328 ConsolePrintf ("Received packet \"%s\"\r\n", buffer
);
333 /* Send the packet in buffer. Returns 0 on failure, non-zero on
340 unsigned char checksum
;
345 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer
);
347 /* $<packet info>#<checksum>. */
350 if (! putDebugChar('$'))
355 while (ch
=buffer
[count
])
357 if (! putDebugChar(ch
))
363 if (! putDebugChar('#')
364 || ! putDebugChar(hexchars
[checksum
>> 4])
365 || ! putDebugChar(hexchars
[checksum
% 16]))
368 ch
= getDebugChar ();
377 static char remcomInBuffer
[BUFMAX
];
378 static char remcomOutBuffer
[BUFMAX
];
382 debug_error (format
, parm
)
388 ConsolePrintf (format
, parm
);
389 ConsolePrintf ("\n");
393 /* This is set if we could get a memory access fault. */
394 static int mem_may_fault
;
396 /* Indicate to caller of mem2hex or hex2mem that there has been an
398 static volatile int mem_err
= 0;
400 /* These are separate functions so that they are so short and sweet
401 that the compiler won't save any registers (if there is a fault
402 to mem_fault, they won't get restored, so there better not be any
420 /* This bit of assembly language just returns from a function. If a
421 memory error occurs within get_char or set_char, the debugger
422 handler points EIP at these instructions to get out. */
424 extern void just_return ();
426 asm (".globl just_return");
427 asm (".globl _just_return");
428 asm ("just_return:");
429 asm ("_just_return:");
434 /* convert the memory pointed to by mem into hex, placing result in buf */
435 /* return a pointer to the last char put in buf (null) */
436 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
437 a fault; if zero treat a fault like any other fault in the stub. */
440 mem2hex (mem
, buf
, count
, may_fault
)
450 mem_may_fault
= may_fault
;
451 for (i
= 0; i
< count
; i
++)
453 ch
= get_char (ptr
++);
454 if (may_fault
&& mem_err
)
456 *buf
++ = hexchars
[ch
>> 4];
457 *buf
++ = hexchars
[ch
% 16];
464 /* convert the hex array pointed to by buf into binary to be placed in mem */
465 /* return a pointer to the character AFTER the last byte written */
468 hex2mem (buf
, mem
, count
, may_fault
)
478 mem_may_fault
= may_fault
;
479 for (i
=0;i
<count
;i
++)
481 ch
= hex(*buf
++) << 4;
482 ch
= ch
+ hex(*buf
++);
483 set_char (ptr
++, ch
);
484 if (may_fault
&& mem_err
)
491 /* This function takes the 386 exception vector and attempts to
492 translate this number into a unix compatible signal value. */
495 computeSignal (exceptionVector
)
499 switch (exceptionVector
)
501 case 0 : sigval
= 8; break; /* divide by zero */
502 case 1 : sigval
= 5; break; /* debug exception */
503 case 3 : sigval
= 5; break; /* breakpoint */
504 case 4 : sigval
= 16; break; /* into instruction (overflow) */
505 case 5 : sigval
= 16; break; /* bound instruction */
506 case 6 : sigval
= 4; break; /* Invalid opcode */
507 case 7 : sigval
= 8; break; /* coprocessor not available */
508 case 8 : sigval
= 7; break; /* double fault */
509 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
510 case 10 : sigval
= 11; break; /* Invalid TSS */
511 case 11 : sigval
= 11; break; /* Segment not present */
512 case 12 : sigval
= 11; break; /* stack exception */
513 case 13 : sigval
= 11; break; /* general protection */
514 case 14 : sigval
= 11; break; /* page fault */
515 case 16 : sigval
= 7; break; /* coprocessor error */
517 sigval
= 7; /* "software generated"*/
522 /**********************************************/
523 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
524 /* RETURN NUMBER OF CHARS PROCESSED */
525 /**********************************************/
527 hexToInt(ptr
, intValue
)
538 hexValue
= hex(**ptr
);
541 *intValue
= (*intValue
<<4) | hexValue
;
578 static LONG saved_inst
;
579 static LONG
*saved_inst_pc
= 0;
580 static LONG saved_target_inst
;
581 static LONG
*saved_target_inst_pc
= 0;
584 set_step_breakpoint (pc
, frame
)
586 struct StackFrame
*frame
;
595 opcode
= inst
.inst
.variant
.branch
.opcode
;
597 if ((opcode
& 0x30) == 0x30) /* A branch of some sort */
598 target
= inst
.inst
.variant
.branch
.disp
+ pc
;
599 else if (opcode
== 0x1a) /* jmp, ret, etc... */
600 target
= (LONG
*)(frame
->ExceptionRegs
[SF_IREG_OFFSET
601 + inst
.inst
.variant
.jump
.rb
].lo
607 *pc
= 0x80; /* call_pal bpt */
612 saved_target_inst
= *target
;
613 *target
= 0x80; /* call_pal bpt */
614 saved_target_inst_pc
= target
;
618 /* Remove step breakpoints. Returns non-zero if pc was at a step breakpoint,
619 zero otherwise. This routine works even if there were no step breakpoints
623 clear_step_breakpoint (pc
)
628 if (saved_inst_pc
== pc
|| saved_target_inst_pc
== pc
)
635 *saved_inst_pc
= saved_inst
;
639 if (saved_target_inst_pc
)
641 *saved_target_inst_pc
= saved_target_inst
;
642 saved_target_inst_pc
= 0;
649 do_status (ptr
, frame
)
651 struct StackFrame
*frame
;
655 sigval
= computeSignal (frame
->ExceptionNumber
);
657 sprintf (ptr
, "T%02x", sigval
);
660 sprintf (ptr
, "%02x:", PC_REGNUM
);
661 ptr
= mem2hex (&frame
->ExceptionRegs
[SF_REG_PC
], ptr
+ 3, 8, 0);
664 sprintf (ptr
, "%02x:", SP_REGNUM
);
665 ptr
= mem2hex (&frame
->ExceptionRegs
[SF_IREG_OFFSET
+ SP_REGNUM
], ptr
+ 3, 8, 0);
668 sprintf (ptr
, "%02x:", RA_REGNUM
);
669 ptr
= mem2hex (&frame
->ExceptionRegs
[SF_IREG_OFFSET
+ RA_REGNUM
], ptr
+ 3, 8, 0);
672 sprintf (ptr
, "%02x:", FP_REGNUM
);
673 ptr
= mem2hex (&frame
->ExceptionRegs
[SF_IREG_OFFSET
+ FP_REGNUM
], ptr
+ 3, 8, 0);
679 /* This function does all command processing for interfacing to gdb.
680 It is called whenever an exception occurs in the module being
684 handle_exception (struct StackFrame
*frame
)
688 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
689 static LONG first_insn
; /* The first instruction in the program. */
691 /* Apparently the bell can sometimes be ringing at this point, and
692 should be stopped. */
697 ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
698 frame
->ExceptionNumber
,
699 frame
->ExceptionDescription
,
700 frame
->ExceptionRegs
[SF_REG_PC
].lo
,
704 switch (frame
->ExceptionNumber
)
706 case START_NLM_EVENT
:
707 /* If the NLM just started, we record the module load information
708 and the thread ID, and set a breakpoint at the first instruction
711 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
712 frame
->ExceptionErrorCode
);
713 first_insn
= *(LONG
*)ldinfo
->LDInitializationProcedure
;
714 *(LONG
*)ldinfo
->LDInitializationProcedure
= 0x80; /* call_pal bpt */
716 return RETURN_TO_PROGRAM
;
718 case ENTER_DEBUGGER_EVENT
:
719 case KEYBOARD_BREAK_EVENT
:
720 /* Pass some events on to the next debugger, in case it will handle
722 return RETURN_TO_NEXT_DEBUGGER
;
724 case 3: /* Breakpoint */
725 /* After we've reached the initial breakpoint, reset it. */
726 if (frame
->ExceptionRegs
[SF_REG_PC
].lo
== (LONG
) ldinfo
->LDInitializationProcedure
727 && *(LONG
*) ldinfo
->LDInitializationProcedure
== 0x80)
729 *(LONG
*) ldinfo
->LDInitializationProcedure
= first_insn
;
732 /* Normal breakpoints end up here */
733 do_status (remcomOutBuffer
, frame
);
737 /* At the moment, we don't care about most of the unusual NetWare
739 if (frame
->ExceptionNumber
> 31)
740 return RETURN_TO_PROGRAM
;
742 /* Most machine level exceptions end up here */
743 do_status (remcomOutBuffer
, frame
);
746 case 11: /* Segment not present */
747 case 13: /* General protection */
748 case 14: /* Page fault */
749 /* If we get a GP fault, and mem_may_fault is set, and the
750 instruction pointer is near set_char or get_char, then we caused
751 the fault ourselves accessing an illegal memory location. */
753 && ((frame
->ExceptionRegs
[SF_REG_PC
].lo
>= (long) &set_char
754 && frame
->ExceptionRegs
[SF_REG_PC
].lo
< (long) &set_char
+ 50)
755 || (frame
->ExceptionRegs
[SF_REG_PC
].lo
>= (long) &get_char
756 && frame
->ExceptionRegs
[SF_REG_PC
].lo
< (long) &get_char
+ 50)))
759 /* Point the instruction pointer at an assembly language stub
760 which just returns from the function. */
762 frame
->ExceptionRegs
[SF_REG_PC
].lo
+= 4; /* Skip the load or store */
764 /* Keep going. This will act as though it returned from
765 set_char or get_char. The calling routine will check
766 mem_err, and do the right thing. */
767 return RETURN_TO_PROGRAM
;
769 /* Random mem fault, report it */
770 do_status (remcomOutBuffer
, frame
);
773 case TERMINATE_NLM_EVENT
:
774 /* There is no way to get the exit status. */
775 sprintf (remcomOutBuffer
, "W%02x", 0);
776 break; /* We generate our own status */
779 /* FIXME: How do we know that this exception has anything to do with
780 the program we are debugging? We can check whether the PC is in
781 the range of the module we are debugging, but that doesn't help
782 much since an error could occur in a library routine. */
784 clear_step_breakpoint (frame
->ExceptionRegs
[SF_REG_PC
]);
786 if (! putpacket(remcomOutBuffer
))
787 return RETURN_TO_NEXT_DEBUGGER
;
789 if (frame
->ExceptionNumber
== TERMINATE_NLM_EVENT
)
791 ResumeThread (mainthread
);
792 return RETURN_TO_PROGRAM
;
798 remcomOutBuffer
[0] = 0;
799 if (! getpacket (remcomInBuffer
))
800 return RETURN_TO_NEXT_DEBUGGER
;
801 switch (remcomInBuffer
[0])
804 do_status (remcomOutBuffer
, frame
);
807 remote_debug
= !(remote_debug
); /* toggle debug flag */
810 /* return the value of the CPU registers */
811 frame_to_registers (frame
, remcomOutBuffer
);
814 /* set the value of the CPU registers - return OK */
815 registers_to_frame (&remcomInBuffer
[1], frame
);
816 strcpy(remcomOutBuffer
,"OK");
820 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
821 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
822 ptr
= &remcomInBuffer
[1];
823 if (hexToInt(&ptr
,&addr
))
825 if (hexToInt(&ptr
,&length
))
829 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
832 strcpy (remcomOutBuffer
, "E03");
833 debug_error ("memory fault");
839 strcpy(remcomOutBuffer
,"E01");
840 debug_error("malformed read memory command: %s",remcomInBuffer
);
845 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
846 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
847 ptr
= &remcomInBuffer
[1];
848 if (hexToInt(&ptr
,&addr
))
850 if (hexToInt(&ptr
,&length
))
854 hex2mem(ptr
, (char*) addr
, length
, 1);
858 strcpy (remcomOutBuffer
, "E03");
859 debug_error ("memory fault");
863 strcpy(remcomOutBuffer
,"OK");
870 strcpy(remcomOutBuffer
,"E02");
871 debug_error("malformed write memory command: %s",remcomInBuffer
);
877 /* cAA..AA Continue at address AA..AA(optional) */
878 /* sAA..AA Step one instruction from AA..AA(optional) */
879 /* try to read optional parameter, pc unchanged if no parm */
880 ptr
= &remcomInBuffer
[1];
881 if (hexToInt(&ptr
,&addr
))
883 /* registers[PC_REGNUM].lo = addr;*/
884 fprintf (stderr
, "Setting PC to 0x%x\n", addr
);
888 if (remcomInBuffer
[0] == 's')
889 set_step_breakpoint (frame
->ExceptionRegs
[SF_REG_PC
].lo
);
892 return RETURN_TO_PROGRAM
;
895 /* kill the program */
897 ResumeThread (mainthread
);
898 return RETURN_TO_PROGRAM
;
900 case 'q': /* Query message */
901 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
903 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
904 ldinfo
->LDCodeImageOffset
,
905 ldinfo
->LDDataImageOffset
,
906 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
909 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
913 /* reply to the request */
914 if (! putpacket(remcomOutBuffer
))
915 return RETURN_TO_NEXT_DEBUGGER
;
919 char *baudRates
[] = { "50", "75", "110", "134.5", "150", "300", "600", "1200",
920 "1800", "2000", "2400", "3600", "4800", "7200", "9600",
921 "19200", "38400", "57600", "115200" };
923 char dataBits
[] = "5678";
925 char *stopBits
[] = { "1", "1.5", "2" };
927 char parity
[] = "NOEMS";
929 /* Start up. The main thread opens the named serial I/O port, loads
930 the named NLM module and then goes to sleep. The serial I/O port
931 is named as a board number and a port number. It would be more DOS
932 like to provide a menu of available serial ports, but I don't want
933 to have to figure out how to do that. */
940 int hardware
, board
, port
;
942 struct debuggerStructure s
;
946 /* Use the -B option to invoke the NID if you want to debug the stub. */
948 if (argc
> 1 && strcmp(argv
[1], "-B") == 0)
957 "Usage: load gdbserve board port program [arguments]\n");
962 board
= strtol (argv
[1], (char **) NULL
, 0);
963 port
= strtol (argv
[2], (char **) NULL
, 0);
965 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
966 if (err
!= AIO_SUCCESS
)
970 case AIO_PORT_NOT_AVAILABLE
:
971 fprintf (stderr
, "Port not available\n");
974 case AIO_BOARD_NUMBER_INVALID
:
975 case AIO_PORT_NUMBER_INVALID
:
976 fprintf (stderr
, "No such port\n");
980 fprintf (stderr
, "Could not open port: %d\n", err
);
987 err
= AIOConfigurePort (AIOhandle
, AIO_BAUD_9600
, AIO_DATA_BITS_8
,
988 AIO_STOP_BITS_1
, AIO_PARITY_NONE
,
989 AIO_HARDWARE_FLOW_CONTROL_OFF
);
991 if (err
== AIO_QUALIFIED_SUCCESS
)
993 AIOPORTCONFIG portConfig
;
994 AIODVRCONFIG dvrConfig
;
996 fprintf (stderr
, "Port configuration changed!\n");
997 AIOGetPortConfiguration (AIOhandle
, &portConfig
, &dvrConfig
);
999 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
1001 baudRates
[portConfig
.bitRate
],
1002 dataBits
[portConfig
.dataBits
],
1003 stopBits
[portConfig
.stopBits
],
1004 parity
[portConfig
.parityMode
],
1005 portConfig
.flowCtrlMode
? "ON" : "OFF");
1007 else if (err
!= AIO_SUCCESS
)
1009 fprintf (stderr
, "Could not configure port: %d\n", err
);
1010 AIOReleasePort (AIOhandle
);
1014 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
1015 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
1018 LONG extStatus
, chgdExtStatus
;
1020 fprintf (stderr
, "Could not set desired port controls!\n");
1021 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
1022 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
1026 /* Register ourselves as an alternate debugger. */
1027 memset (&s
, 0, sizeof s
);
1028 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
1029 AllocateResourceTag (GetNLMHandle (),
1030 (BYTE
*)"gdbserver",
1031 DebuggerSignature
));
1032 if (s
.DDSResourceTag
== 0)
1034 fprintf (stderr
, "AllocateResourceTag failed\n");
1035 AIOReleasePort (AIOhandle
);
1038 s
.DDSdebuggerEntry
= handle_exception
;
1039 s
.DDSFlags
= TSS_FRAME_BIT
;
1041 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
1044 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
1045 AIOReleasePort (AIOhandle
);
1049 /* Get the command line we were invoked with, and advance it past
1050 our name and the board and port arguments. */
1051 cmdlin
= getcmd ((char *) NULL
);
1052 for (i
= 0; i
< 2; i
++)
1054 while (! isspace (*cmdlin
))
1056 while (isspace (*cmdlin
))
1060 /* In case GDB is started before us, ack any packets (presumably
1061 "$?#xx") sitting there. */
1062 if (! putDebugChar ('+'))
1064 fprintf (stderr
, "putDebugChar failed\n");
1065 UnRegisterDebugger (&s
);
1066 AIOReleasePort (AIOhandle
);
1070 mainthread
= GetThreadID ();
1072 if (remote_debug
> 0)
1073 fprintf (stderr
, "About to call LoadModule with \"%s\" %08x\r\n",
1074 cmdlin
, __GetScreenID (GetCurrentScreen()));
1076 /* Start up the module to be debugged. */
1077 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1078 (BYTE
*)cmdlin
, LO_DEBUG
);
1081 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1082 UnRegisterDebugger (&s
);
1083 AIOReleasePort (AIOhandle
);
1087 /* Wait for the debugger to wake us up. */
1088 if (remote_debug
> 0)
1089 fprintf (stderr
, "Suspending main thread (%08x)\r\n", mainthread
);
1090 SuspendThread (mainthread
);
1091 if (remote_debug
> 0)
1092 fprintf (stderr
, "Resuming main thread (%08x)\r\n", mainthread
);
1094 /* If we are woken up, print an optional error message, deregister
1095 ourselves and exit. */
1096 if (error_message
!= NULL
)
1097 fprintf (stderr
, "%s\n", error_message
);
1098 UnRegisterDebugger (&s
);
1099 AIOReleasePort (AIOhandle
);