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 /* An error message for the main thread to print. */
128 static char *error_message
;
130 /* The AIO port handle. */
131 static int AIOhandle
;
133 /* BUFMAX defines the maximum number of characters in inbound/outbound
134 buffers. At least NUMREGBYTES*2 are needed for register packets */
135 #define BUFMAX (REGISTER_BYTES * 2 + 16)
137 /* remote_debug > 0 prints ill-formed commands in valid packets and
139 static int remote_debug
= 1;
141 static const char hexchars
[] = "0123456789abcdef";
143 /* Register values. All of these values *MUST* agree with tm.h */
144 #define SP_REGNUM 4 /* Contains address of top of stack */
145 #define PC_REGNUM 8 /* Contains program counter */
146 #define FP_REGNUM 5 /* Virtual frame pointer */
147 #define NUM_REGS 16 /* Number of machine registers */
148 #define REGISTER_BYTES (NUM_REGS * 4) /* Total size of registers array */
150 #define ExceptionPC ExceptionEIP
151 #define DECR_PC_AFTER_BREAK 1 /* int 3 leaves PC pointing after insn */
152 #define BREAKPOINT {0xcc}
153 #define StackFrame T_TSS_StackFrame
155 unsigned char breakpoint_insn
[] = BREAKPOINT
;
156 #define BREAKPOINT_SIZE (sizeof breakpoint_insn)
158 static void flush_i_cache() {}
160 static char *mem2hex (void *mem
, char *buf
, int count
, int may_fault
);
161 static char *hex2mem (char *buf
, void *mem
, int count
, int may_fault
);
162 static void set_step_traps (struct StackFrame
*);
163 static void clear_step_traps (struct StackFrame
*);
169 /* Read a character from the serial port. This must busy wait, but
170 that's OK because we will be the only thread running anyhow. */
181 err
= AIOReadData (AIOhandle
, (char *) &ret
, 1, &got
);
184 error_message
= "AIOReadData failed";
185 ResumeThread (mainthread
);
194 /* Write a character to the serial port. Returns 0 on failure,
195 non-zero on success. */
207 err
= AIOWriteData (AIOhandle
, (char *) &c
, 1, &put
);
209 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err
, put
);
214 /* Get the registers out of the frame information. */
217 frame_to_registers (frame
, regs
)
218 struct StackFrame
*frame
;
221 /* Copy EAX -> EDI */
222 mem2hex (&frame
->ExceptionEAX
, ®s
[0 * 4 * 2], 4 * 8, 0);
225 mem2hex (&frame
->ExceptionPC
, ®s
[8 * 4 * 2], 4 * 2, 0);
227 /* Copy CS, SS, DS */
228 mem2hex (&frame
->ExceptionCS
, ®s
[10 * 4 * 2], 4 * 3, 0);
231 mem2hex (&frame
->ExceptionES
, ®s
[13 * 4 * 2], 4 * 1, 0);
234 mem2hex (&frame
->ExceptionFS
, ®s
[14 * 4 * 2], 4 * 2, 0);
237 /* Put the registers back into the frame information. */
240 registers_to_frame (regs
, frame
)
242 struct StackFrame
*frame
;
244 /* Copy EAX -> EDI */
245 hex2mem (®s
[0 * 4 * 2], &frame
->ExceptionEAX
, 4 * 8, 0);
248 hex2mem (®s
[8 * 4 * 2], &frame
->ExceptionPC
, 4 * 2, 0);
250 /* Copy CS, SS, DS */
251 hex2mem (®s
[10 * 4 * 2], &frame
->ExceptionCS
, 4 * 3, 0);
254 hex2mem (®s
[13 * 4 * 2], &frame
->ExceptionES
, 4 * 1, 0);
257 hex2mem (®s
[14 * 4 * 2], &frame
->ExceptionFS
, 4 * 2, 0);
260 /* Turn a hex character into a number. */
266 if ((ch
>= 'a') && (ch
<= 'f'))
268 if ((ch
>= '0') && (ch
<= '9'))
270 if ((ch
>= 'A') && (ch
<= 'F'))
275 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
276 non-zero on success. */
282 unsigned char checksum
;
283 unsigned char xmitcsum
;
290 /* wait around for the start character, ignore all other characters */
291 while ((ch
= getDebugChar()) != '$')
299 /* now, read until a # or end of buffer is found */
300 while (count
< BUFMAX
)
307 checksum
= checksum
+ ch
;
315 ch
= getDebugChar ();
318 xmitcsum
= hex(ch
) << 4;
319 ch
= getDebugChar ();
324 if (checksum
!= xmitcsum
)
327 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
328 checksum
,xmitcsum
,buffer
);
329 /* failed checksum */
330 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 ConsolePrintf (format
, parm
);
417 ConsolePrintf ("\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
)
476 mem_may_fault
= may_fault
;
477 for (i
= 0; i
< count
; i
++)
479 ch
= get_char (ptr
++);
480 if (may_fault
&& mem_err
)
482 *buf
++ = hexchars
[ch
>> 4];
483 *buf
++ = hexchars
[ch
% 16];
490 /* convert the hex array pointed to by buf into binary to be placed in mem */
491 /* return a pointer to the character AFTER the last byte written */
494 hex2mem (buf
, mem
, count
, may_fault
)
504 mem_may_fault
= may_fault
;
505 for (i
=0;i
<count
;i
++)
507 ch
= hex(*buf
++) << 4;
508 ch
= ch
+ hex(*buf
++);
509 set_char (ptr
++, ch
);
510 if (may_fault
&& mem_err
)
517 /* This function takes the 386 exception vector and attempts to
518 translate this number into a unix compatible signal value. */
521 computeSignal (exceptionVector
)
525 switch (exceptionVector
)
527 case 0 : sigval
= 8; break; /* divide by zero */
528 case 1 : sigval
= 5; break; /* debug exception */
529 case 3 : sigval
= 5; break; /* breakpoint */
530 case 4 : sigval
= 16; break; /* into instruction (overflow) */
531 case 5 : sigval
= 16; break; /* bound instruction */
532 case 6 : sigval
= 4; break; /* Invalid opcode */
533 case 7 : sigval
= 8; break; /* coprocessor not available */
534 case 8 : sigval
= 7; break; /* double fault */
535 case 9 : sigval
= 11; break; /* coprocessor segment overrun */
536 case 10 : sigval
= 11; break; /* Invalid TSS */
537 case 11 : sigval
= 11; break; /* Segment not present */
538 case 12 : sigval
= 11; break; /* stack exception */
539 case 13 : sigval
= 11; break; /* general protection */
540 case 14 : sigval
= 11; break; /* page fault */
541 case 16 : sigval
= 7; break; /* coprocessor error */
543 sigval
= 7; /* "software generated"*/
548 /**********************************************/
549 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
550 /* RETURN NUMBER OF CHARS PROCESSED */
551 /**********************************************/
553 hexToInt(ptr
, intValue
)
564 hexValue
= hex(**ptr
);
567 *intValue
= (*intValue
<<4) | hexValue
;
580 set_step_traps (frame
)
581 struct StackFrame
*frame
;
583 frame
->ExceptionSystemFlags
|= 0x100;
587 clear_step_traps (frame
)
588 struct StackFrame
*frame
;
590 frame
->ExceptionSystemFlags
&= ~0x100;
594 do_status (ptr
, frame
)
596 struct StackFrame
*frame
;
600 sigval
= computeSignal (frame
->ExceptionNumber
);
602 sprintf (ptr
, "T%02x", sigval
);
605 sprintf (ptr
, "%02x:", PC_REGNUM
);
606 ptr
= mem2hex (&frame
->ExceptionPC
, ptr
+ 3, 4, 0);
609 sprintf (ptr
, "%02x:", SP_REGNUM
);
610 ptr
= mem2hex (&frame
->ExceptionESP
, ptr
+ 3, 4, 0);
613 sprintf (ptr
, "%02x:", FP_REGNUM
);
614 ptr
= mem2hex (&frame
->ExceptionEBP
, ptr
+ 3, 4, 0);
620 /* This function does all command processing for interfacing to gdb.
621 It is called whenever an exception occurs in the module being
625 handle_exception (frame
)
626 struct StackFrame
*frame
;
630 static int killed
= 0;
631 static struct DBG_LoadDefinitionStructure
*ldinfo
= 0;
632 static unsigned char first_insn
[BREAKPOINT_SIZE
]; /* The first instruction in the program. */
634 /* Apparently the bell can sometimes be ringing at this point, and
635 should be stopped. */
640 ConsolePrintf ("vector=%d: %s, sr=%08x, pc=%08x, thread=%08x\r\n",
641 frame
->ExceptionNumber
,
642 frame
->ExceptionDescription
,
643 frame
->ExceptionSystemFlags
,
648 switch (frame
->ExceptionNumber
)
650 case START_NLM_EVENT
:
651 /* If the NLM just started, we record the module load information
652 and the thread ID, and set a breakpoint at the first instruction
655 ldinfo
= ((struct DBG_LoadDefinitionStructure
*)
656 frame
->ExceptionErrorCode
);
657 memcpy (first_insn
, ldinfo
->LDInitializationProcedure
,
659 memcpy (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
662 return RETURN_TO_PROGRAM
;
664 case TERMINATE_NLM_EVENT
:
667 /* NetWare processes don't have an exit status so we
669 sprintf (remcomOutBuffer
, "W%02x", 0);
670 putpacket(remcomOutBuffer
);
672 ResumeThread (mainthread
);
673 return RETURN_TO_PROGRAM
;
675 case ENTER_DEBUGGER_EVENT
:
676 case KEYBOARD_BREAK_EVENT
:
677 /* Pass some events on to the next debugger, in case it will handle
679 return RETURN_TO_NEXT_DEBUGGER
;
681 case 3: /* Breakpoint */
682 /* After we've reached the initial breakpoint, reset it. */
683 if (frame
->ExceptionPC
- DECR_PC_AFTER_BREAK
== (LONG
) ldinfo
->LDInitializationProcedure
684 && memcmp (ldinfo
->LDInitializationProcedure
, breakpoint_insn
,
685 BREAKPOINT_SIZE
) == 0)
687 memcpy (ldinfo
->LDInitializationProcedure
, first_insn
,
689 frame
->ExceptionPC
-= DECR_PC_AFTER_BREAK
;
692 /* Normal breakpoints end up here */
693 do_status (remcomOutBuffer
, frame
);
697 /* At the moment, we don't care about most of the unusual NetWare
699 if (frame
->ExceptionNumber
> 31)
700 return RETURN_TO_PROGRAM
;
702 /* Most machine level exceptions end up here */
703 do_status (remcomOutBuffer
, frame
);
706 case 11: /* Segment not present */
707 case 13: /* General protection */
708 case 14: /* Page fault */
709 /* If we get a GP fault, and mem_may_fault is set, and the
710 instruction pointer is near set_char or get_char, then we caused
711 the fault ourselves accessing an illegal memory location. */
713 && ((frame
->ExceptionPC
>= (long) &set_char
714 && frame
->ExceptionPC
< (long) &set_char
+ 50)
715 || (frame
->ExceptionPC
>= (long) &get_char
716 && frame
->ExceptionPC
< (long) &get_char
+ 50)))
719 /* Point the instruction pointer at an assembly language stub
720 which just returns from the function. */
722 frame
->ExceptionPC
= (long) &just_return
;
724 /* Keep going. This will act as though it returned from
725 set_char or get_char. The calling routine will check
726 mem_err, and do the right thing. */
727 return RETURN_TO_PROGRAM
;
729 /* Random mem fault, report it */
730 do_status (remcomOutBuffer
, frame
);
734 /* FIXME: How do we know that this exception has anything to do with
735 the program we are debugging? We can check whether the PC is in
736 the range of the module we are debugging, but that doesn't help
737 much since an error could occur in a library routine. */
739 clear_step_traps (frame
);
741 if (! putpacket(remcomOutBuffer
))
742 return RETURN_TO_NEXT_DEBUGGER
;
747 remcomOutBuffer
[0] = 0;
748 if (! getpacket (remcomInBuffer
))
749 return RETURN_TO_NEXT_DEBUGGER
;
750 switch (remcomInBuffer
[0])
753 do_status (remcomOutBuffer
, frame
);
756 remote_debug
= !(remote_debug
); /* toggle debug flag */
759 /* return the value of the CPU registers */
760 frame_to_registers (frame
, remcomOutBuffer
);
763 /* set the value of the CPU registers - return OK */
764 registers_to_frame (&remcomInBuffer
[1], frame
);
765 strcpy(remcomOutBuffer
,"OK");
769 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
770 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
771 ptr
= &remcomInBuffer
[1];
772 if (hexToInt(&ptr
,&addr
))
774 if (hexToInt(&ptr
,&length
))
778 mem2hex((char*) addr
, remcomOutBuffer
, length
, 1);
781 strcpy (remcomOutBuffer
, "E03");
782 debug_error ("memory fault");
788 strcpy(remcomOutBuffer
,"E01");
789 debug_error("malformed read memory command: %s",remcomInBuffer
);
794 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
795 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
796 ptr
= &remcomInBuffer
[1];
797 if (hexToInt(&ptr
,&addr
))
799 if (hexToInt(&ptr
,&length
))
803 hex2mem(ptr
, (char*) addr
, length
, 1);
807 strcpy (remcomOutBuffer
, "E03");
808 debug_error ("memory fault");
812 strcpy(remcomOutBuffer
,"OK");
819 strcpy(remcomOutBuffer
,"E02");
820 debug_error("malformed write memory command: %s",remcomInBuffer
);
826 /* cAA..AA Continue at address AA..AA(optional) */
827 /* sAA..AA Step one instruction from AA..AA(optional) */
828 /* try to read optional parameter, pc unchanged if no parm */
829 ptr
= &remcomInBuffer
[1];
830 if (hexToInt(&ptr
,&addr
))
832 /* registers[PC_REGNUM].lo = addr;*/
833 ConsolePrintf("Setting PC to 0x%x\n", addr
);
837 if (remcomInBuffer
[0] == 's')
838 set_step_traps (frame
);
841 return RETURN_TO_PROGRAM
;
844 /* The undocumented netware call KillMe() is supposed to
845 schedule the NLM to be killed when it next blocks. What
846 really happens is that the server hangs as it tries to
849 So, since netware won't cooperate, we just point the PC
850 at the start of _exit() and continue, while noting that
851 we've killed the process. */
854 frame
->ExceptionPC
= &_exit
;
855 return RETURN_TO_PROGRAM
;
857 case 'q': /* Query message */
858 if (strcmp (&remcomInBuffer
[1], "Offsets") == 0)
860 sprintf (remcomOutBuffer
, "Text=%x;Data=%x;Bss=%x",
861 ldinfo
->LDCodeImageOffset
,
862 ldinfo
->LDDataImageOffset
,
863 ldinfo
->LDDataImageOffset
+ ldinfo
->LDDataImageLength
);
866 sprintf (remcomOutBuffer
, "E04, Unknown query %s", &remcomInBuffer
[1]);
870 /* reply to the request */
871 if (! putpacket(remcomOutBuffer
))
872 return RETURN_TO_NEXT_DEBUGGER
;
881 const char *bitRateString
;
884 struct bitRate bitRateTable
[] =
886 { AIO_BAUD_50
, "50" },
887 { AIO_BAUD_75
, "75" },
888 { AIO_BAUD_110
, "110" },
889 { AIO_BAUD_134p5
, "134.5" },
890 { AIO_BAUD_150
, "150" },
891 { AIO_BAUD_300
, "300" },
892 { AIO_BAUD_600
, "600" },
893 { AIO_BAUD_1200
, "1200" },
894 { AIO_BAUD_1800
, "1800" },
895 { AIO_BAUD_2000
, "2000" },
896 { AIO_BAUD_2400
, "2400" },
897 { AIO_BAUD_3600
, "3600" },
898 { AIO_BAUD_4800
, "4800" },
899 { AIO_BAUD_7200
, "7200" },
900 { AIO_BAUD_9600
, "9600" },
901 { AIO_BAUD_19200
, "19200" },
902 { AIO_BAUD_38400
, "38400" },
903 { AIO_BAUD_57600
, "57600" },
904 { AIO_BAUD_115200
, "115200" },
908 char dataBitsTable
[] = "5678";
910 char *stopBitsTable
[] = { "1", "1.5", "2" };
912 char parity
[] = "NOEMS";
914 /* Start up. The main thread opens the named serial I/O port, loads
915 the named NLM module and then goes to sleep. The serial I/O port
916 is named as a board number and a port number. It would be more DOS
917 like to provide a menu of available serial ports, but I don't want
918 to have to figure out how to do that. */
925 int hardware
, board
, port
;
931 struct debuggerStructure s
;
937 progname
= "nlmstub";
943 /* set default serial line characteristics */
944 bitRate
= AIO_BAUD_9600
;
945 dataBits
= AIO_DATA_BITS_8
;
946 stopBits
= AIO_STOP_BITS_1
;
947 parityMode
= AIO_PARITY_NONE
;
950 for (argc
--, argv
++; *argv
; argc
--, argv
++)
955 if (strnicmp(*argv
, "BAUD=", 5) == 0)
960 for (brp
= bitRateTable
; brp
->bitRate
!= (BYTE
) -1; brp
++)
962 if (strcmp(brp
->bitRateString
, bp
) == 0)
964 bitRate
= brp
->bitRate
;
969 if (brp
->bitRateString
== NULL
)
971 fprintf(stderr
, "%s: %s: unknown or unsupported bit rate",
976 else if (strnicmp(*argv
, "NODE=", 5) == 0)
979 board
= strtol (bp
, &ep
, 0);
980 if (ep
== bp
|| *ep
!= '\0')
982 fprintf (stderr
, "%s: %s: expected integer argument\n",
987 else if (strnicmp(*argv
, "PORT=", 5) == 0)
990 port
= strtol (bp
, &ep
, 0);
991 if (ep
== bp
|| *ep
!= '\0')
993 fprintf (stderr
, "%s: %s: expected integer argument\n",
1009 "Usage: load %s [options] program [arguments]\n", progname
);
1013 err
= AIOAcquirePort (&hardware
, &board
, &port
, &AIOhandle
);
1014 if (err
!= AIO_SUCCESS
)
1018 case AIO_PORT_NOT_AVAILABLE
:
1019 fprintf (stderr
, "Port not available\n");
1022 case AIO_BOARD_NUMBER_INVALID
:
1023 case AIO_PORT_NUMBER_INVALID
:
1024 fprintf (stderr
, "No such port\n");
1028 fprintf (stderr
, "Could not open port: %d\n", err
);
1035 err
= AIOConfigurePort (AIOhandle
, bitRate
, dataBits
, stopBits
, parityMode
,
1036 AIO_HARDWARE_FLOW_CONTROL_OFF
);
1038 if (err
== AIO_QUALIFIED_SUCCESS
)
1040 AIOPORTCONFIG portConfig
;
1042 fprintf (stderr
, "Port configuration changed!\n");
1044 portConfig
.returnLength
= sizeof(portConfig
);
1045 AIOGetPortConfiguration (AIOhandle
, &portConfig
, NULL
);
1048 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
1050 bitRateTable
[portConfig
.bitRate
].bitRateString
,
1051 dataBitsTable
[portConfig
.dataBits
],
1052 stopBitsTable
[portConfig
.stopBits
],
1053 parity
[portConfig
.parityMode
],
1054 portConfig
.flowCtrlMode
? "ON" : "OFF");
1056 else if (err
!= AIO_SUCCESS
)
1058 fprintf (stderr
, "Could not configure port: %d\n", err
);
1059 AIOReleasePort (AIOhandle
);
1063 if (AIOSetExternalControl(AIOhandle
, AIO_EXTERNAL_CONTROL
,
1064 (AIO_EXTCTRL_DTR
| AIO_EXTCTRL_RTS
))
1067 LONG extStatus
, chgdExtStatus
;
1069 fprintf (stderr
, "Could not set desired port controls!\n");
1070 AIOGetExternalStatus (AIOhandle
, &extStatus
, &chgdExtStatus
);
1071 fprintf (stderr
, "Port controls now: %d, %d\n", extStatus
,
1075 /* Register ourselves as an alternate debugger. */
1076 memset (&s
, 0, sizeof s
);
1077 s
.DDSResourceTag
= ((struct ResourceTagStructure
*)
1078 AllocateResourceTag (GetNLMHandle (),
1079 (BYTE
*)"gdbserver",
1080 DebuggerSignature
));
1081 if (s
.DDSResourceTag
== 0)
1083 fprintf (stderr
, "AllocateResourceTag failed\n");
1084 AIOReleasePort (AIOhandle
);
1087 s
.DDSdebuggerEntry
= handle_exception
;
1088 s
.DDSFlags
= TSS_FRAME_BIT
;
1090 err
= RegisterDebuggerRTag (&s
, AT_FIRST
);
1093 fprintf (stderr
, "RegisterDebuggerRTag failed\n");
1094 AIOReleasePort (AIOhandle
);
1098 /* Get the command line we were invoked with, and advance it past
1099 our name and command line arguments. */
1100 cmdlin
= getcmd ((char *) NULL
);
1101 for (i
= 0; i
< cmdindx
; i
++)
1103 while (! isspace (*cmdlin
))
1105 while (isspace (*cmdlin
))
1109 /* In case GDB is started before us, ack any packets (presumably
1110 "$?#xx") sitting there. */
1111 if (! putDebugChar ('+'))
1113 fprintf (stderr
, "putDebugChar failed\n");
1114 UnRegisterDebugger (&s
);
1115 AIOReleasePort (AIOhandle
);
1119 mainthread
= GetThreadID ();
1121 if (remote_debug
> 0)
1122 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1123 cmdlin
, __GetScreenID (GetCurrentScreen()));
1125 /* Start up the module to be debugged. */
1126 err
= LoadModule ((struct ScreenStruct
*) __GetScreenID (GetCurrentScreen()),
1127 (BYTE
*)cmdlin
, LO_DEBUG
);
1130 fprintf (stderr
, "LoadModule failed: %d\n", err
);
1131 UnRegisterDebugger (&s
);
1132 AIOReleasePort (AIOhandle
);
1136 /* Wait for the debugger to wake us up. */
1137 if (remote_debug
> 0)
1138 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread
);
1139 SuspendThread (mainthread
);
1140 if (remote_debug
> 0)
1141 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread
);
1143 /* If we are woken up, print an optional error message, deregister
1144 ourselves and exit. */
1145 if (error_message
!= NULL
)
1146 fprintf (stderr
, "%s\n", error_message
);
1147 UnRegisterDebugger (&s
);
1148 AIOReleasePort (AIOhandle
);