xref: /openbsd-src/gnu/usr.bin/binutils/gdb/nlm/gdbserve.c (revision b725ae7711052a2233e31a66fefb8a752c388d7a)
1e93f7393Sniklas /* gdbserve.c -- NLM debugging stub for Novell NetWare.
2e93f7393Sniklas 
3e93f7393Sniklas    This is originally based on an m68k software stub written by Glenn
4e93f7393Sniklas    Engel at HP, but has changed quite a bit.  It was modified for the
5e93f7393Sniklas    i386 by Jim Kingdon, Cygnus Support.  It was modified to run under
6e93f7393Sniklas    NetWare by Ian Lance Taylor, Cygnus Support.
7e93f7393Sniklas 
8e93f7393Sniklas    This code is intended to produce an NLM (a NetWare Loadable Module)
9e93f7393Sniklas    to run under Novell NetWare.  To create the NLM, compile this code
10e93f7393Sniklas    into an object file using the NLM SDK on any i386 host, and use the
11e93f7393Sniklas    nlmconv program (available in the GNU binutils) to transform the
12e93f7393Sniklas    resulting object file into an NLM.  */
13e93f7393Sniklas 
14e93f7393Sniklas /****************************************************************************
15e93f7393Sniklas 
16e93f7393Sniklas 		THIS SOFTWARE IS NOT COPYRIGHTED
17e93f7393Sniklas 
18e93f7393Sniklas    HP offers the following for use in the public domain.  HP makes no
19e93f7393Sniklas    warranty with regard to the software or it's performance and the
20e93f7393Sniklas    user accepts the software "AS IS" with all faults.
21e93f7393Sniklas 
22e93f7393Sniklas    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
23e93f7393Sniklas    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24e93f7393Sniklas    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25e93f7393Sniklas 
26e93f7393Sniklas ****************************************************************************/
27e93f7393Sniklas 
28e93f7393Sniklas /****************************************************************************
29e93f7393Sniklas  *
30e93f7393Sniklas  *    The following gdb commands are supported:
31e93f7393Sniklas  *
32e93f7393Sniklas  * command          function                               Return value
33e93f7393Sniklas  *
34e93f7393Sniklas  *    g             return the value of the CPU registers  hex data or ENN
35e93f7393Sniklas  *    G             set the value of the CPU registers     OK or ENN
36e93f7393Sniklas  *
37e93f7393Sniklas  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
38e93f7393Sniklas  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
39e93f7393Sniklas  *
40e93f7393Sniklas  *    c             Resume at current address              SNN   ( signal NN)
41e93f7393Sniklas  *    cAA..AA       Continue at address AA..AA             SNN
42e93f7393Sniklas  *
43e93f7393Sniklas  *    s             Step one instruction                   SNN
44e93f7393Sniklas  *    sAA..AA       Step one instruction from AA..AA       SNN
45e93f7393Sniklas  *
46e93f7393Sniklas  *    k             kill
47e93f7393Sniklas  *
48e93f7393Sniklas  *    ?             What was the last sigval ?             SNN   (signal NN)
49e93f7393Sniklas  *
50e93f7393Sniklas  * All commands and responses are sent with a packet which includes a
51e93f7393Sniklas  * checksum.  A packet consists of
52e93f7393Sniklas  *
53e93f7393Sniklas  * $<packet info>#<checksum>.
54e93f7393Sniklas  *
55e93f7393Sniklas  * where
56e93f7393Sniklas  * <packet info> :: <characters representing the command or response>
57e93f7393Sniklas  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
58e93f7393Sniklas  *
59e93f7393Sniklas  * When a packet is received, it is first acknowledged with either '+' or '-'.
60e93f7393Sniklas  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
61e93f7393Sniklas  *
62e93f7393Sniklas  * Example:
63e93f7393Sniklas  *
64e93f7393Sniklas  * Host:                  Reply:
65e93f7393Sniklas  * $m0,10#2a               +$00010203040506070809101112131415#42
66e93f7393Sniklas  *
67e93f7393Sniklas  ****************************************************************************/
68e93f7393Sniklas 
69e93f7393Sniklas #include <stdio.h>
70e93f7393Sniklas #include <string.h>
71e93f7393Sniklas #include <stdlib.h>
72e93f7393Sniklas #include <ctype.h>
73e93f7393Sniklas #include <errno.h>
74e93f7393Sniklas #include <time.h>
75e93f7393Sniklas 
76e93f7393Sniklas #ifdef __i386__
77e93f7393Sniklas #include <dfs.h>
78e93f7393Sniklas #include <conio.h>
79e93f7393Sniklas #include <advanced.h>
80e93f7393Sniklas #include <debugapi.h>
81e93f7393Sniklas #include <process.h>
82e93f7393Sniklas #else
83e93f7393Sniklas #include <nwtypes.h>
84e93f7393Sniklas #include <nwdfs.h>
85e93f7393Sniklas #include <nwconio.h>
86e93f7393Sniklas #include <nwadv.h>
87e93f7393Sniklas #include <nwdbgapi.h>
88e93f7393Sniklas #include <nwthread.h>
89e93f7393Sniklas #endif
90e93f7393Sniklas 
91e93f7393Sniklas #include <aio.h>
92e93f7393Sniklas #include "cpu.h"
93e93f7393Sniklas 
94e93f7393Sniklas 
95e93f7393Sniklas /****************************************************/
96e93f7393Sniklas /* This information is from Novell.  It is not in any of the standard
97e93f7393Sniklas    NetWare header files.  */
98e93f7393Sniklas 
99e93f7393Sniklas struct DBG_LoadDefinitionStructure
100e93f7393Sniklas {
101e93f7393Sniklas 	void *reserved1[4];
102e93f7393Sniklas 	LONG reserved5;
103e93f7393Sniklas 	LONG LDCodeImageOffset;
104e93f7393Sniklas 	LONG LDCodeImageLength;
105e93f7393Sniklas 	LONG LDDataImageOffset;
106e93f7393Sniklas 	LONG LDDataImageLength;
107e93f7393Sniklas 	LONG LDUninitializedDataLength;
108e93f7393Sniklas 	LONG LDCustomDataOffset;
109e93f7393Sniklas 	LONG LDCustomDataSize;
110e93f7393Sniklas 	LONG reserved6[2];
111e93f7393Sniklas 	LONG (*LDInitializationProcedure)(void);
112e93f7393Sniklas };
113e93f7393Sniklas 
114e93f7393Sniklas #define LO_NORMAL		0x0000
115e93f7393Sniklas #define LO_STARTUP		0x0001
116e93f7393Sniklas #define LO_PROTECT		0x0002
117e93f7393Sniklas #define LO_DEBUG		0x0004
118e93f7393Sniklas #define LO_AUTO_LOAD  		0x0008
119e93f7393Sniklas 
120e93f7393Sniklas /* Loader returned error codes */
121e93f7393Sniklas #define LOAD_COULD_NOT_FIND_FILE		1
122e93f7393Sniklas #define LOAD_ERROR_READING_FILE			2
123e93f7393Sniklas #define LOAD_NOT_NLM_FILE_FORMAT		3
124e93f7393Sniklas #define LOAD_WRONG_NLM_FILE_VERSION		4
125e93f7393Sniklas #define LOAD_REENTRANT_INITIALIZE_FAILURE	5
126e93f7393Sniklas #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES	6
127e93f7393Sniklas #define LOAD_ALREADY_IN_PROGRESS		7
128e93f7393Sniklas #define LOAD_NOT_ENOUGH_MEMORY			8
129e93f7393Sniklas #define LOAD_INITIALIZE_FAILURE			9
130e93f7393Sniklas #define LOAD_INCONSISTENT_FILE_FORMAT		10
131e93f7393Sniklas #define LOAD_CAN_NOT_LOAD_AT_STARTUP		11
132e93f7393Sniklas #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED	12
133e93f7393Sniklas #define LOAD_UNRESOLVED_EXTERNAL		13
134e93f7393Sniklas #define LOAD_PUBLIC_ALREADY_DEFINED		14
135e93f7393Sniklas /****************************************************/
136e93f7393Sniklas 
137e93f7393Sniklas /* The main thread ID.  */
138e93f7393Sniklas static int mainthread;
139e93f7393Sniklas 
140e93f7393Sniklas /* An error message for the main thread to print.  */
141e93f7393Sniklas static char *error_message;
142e93f7393Sniklas 
143e93f7393Sniklas /* The AIO port handle.  */
144e93f7393Sniklas static int AIOhandle;
145e93f7393Sniklas 
146e93f7393Sniklas /* BUFMAX defines the maximum number of characters in inbound/outbound
147e93f7393Sniklas    buffers.  At least NUMREGBYTES*2 are needed for register packets */
148e93f7393Sniklas #define BUFMAX (REGISTER_BYTES * 2 + 16)
149e93f7393Sniklas 
150e93f7393Sniklas /* remote_debug > 0 prints ill-formed commands in valid packets and
151e93f7393Sniklas    checksum errors. */
152e93f7393Sniklas static int remote_debug = 1;
153e93f7393Sniklas 
154e93f7393Sniklas static const char hexchars[] = "0123456789abcdef";
155e93f7393Sniklas 
156e93f7393Sniklas unsigned char breakpoint_insn[] = BREAKPOINT;
157e93f7393Sniklas 
158e93f7393Sniklas char *mem2hex (void *mem, char *buf, int count, int may_fault);
159e93f7393Sniklas char *hex2mem (char *buf, void *mem, int count, int may_fault);
160e93f7393Sniklas extern void set_step_traps (struct StackFrame *);
161e93f7393Sniklas extern void clear_step_traps (struct StackFrame *);
162e93f7393Sniklas 
__main()163e93f7393Sniklas static int __main() {};
164e93f7393Sniklas 
165e93f7393Sniklas /* Read a character from the serial port.  This must busy wait, but
166e93f7393Sniklas    that's OK because we will be the only thread running anyhow.  */
167e93f7393Sniklas 
168e93f7393Sniklas static int
getDebugChar(void)169*b725ae77Skettenis getDebugChar (void)
170e93f7393Sniklas {
171e93f7393Sniklas   int err;
172e93f7393Sniklas   LONG got;
173e93f7393Sniklas   unsigned char ret;
174e93f7393Sniklas 
175e93f7393Sniklas   do
176e93f7393Sniklas     {
177e93f7393Sniklas       err = AIOReadData (AIOhandle, (char *) &ret, 1, &got);
178e93f7393Sniklas       if (err != 0)
179e93f7393Sniklas 	{
180e93f7393Sniklas 	  error_message = "AIOReadData failed";
181e93f7393Sniklas 	  ResumeThread (mainthread);
182e93f7393Sniklas 	  return -1;
183e93f7393Sniklas 	}
184e93f7393Sniklas     }
185e93f7393Sniklas   while (got == 0);
186e93f7393Sniklas 
187e93f7393Sniklas   return ret;
188e93f7393Sniklas }
189e93f7393Sniklas 
190e93f7393Sniklas /* Write a character to the serial port.  Returns 0 on failure,
191e93f7393Sniklas    non-zero on success.  */
192e93f7393Sniklas 
193e93f7393Sniklas static int
putDebugChar(unsigned char c)194*b725ae77Skettenis putDebugChar (unsigned char c)
195e93f7393Sniklas {
196e93f7393Sniklas   int err;
197e93f7393Sniklas   LONG put;
198e93f7393Sniklas 
199e93f7393Sniklas   put = 0;
200e93f7393Sniklas   while (put < 1)
201e93f7393Sniklas     {
202e93f7393Sniklas       err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
203e93f7393Sniklas       if (err != 0)
204e93f7393Sniklas 	ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
205e93f7393Sniklas     }
206e93f7393Sniklas   return 1;
207e93f7393Sniklas }
208e93f7393Sniklas 
209e93f7393Sniklas /* Turn a hex character into a number.  */
210e93f7393Sniklas 
211e93f7393Sniklas static int
hex(char ch)212*b725ae77Skettenis hex (char ch)
213e93f7393Sniklas {
214e93f7393Sniklas   if ((ch >= 'a') && (ch <= 'f'))
215e93f7393Sniklas     return (ch-'a'+10);
216e93f7393Sniklas   if ((ch >= '0') && (ch <= '9'))
217e93f7393Sniklas     return (ch-'0');
218e93f7393Sniklas   if ((ch >= 'A') && (ch <= 'F'))
219e93f7393Sniklas     return (ch-'A'+10);
220e93f7393Sniklas   return (-1);
221e93f7393Sniklas }
222e93f7393Sniklas 
223e93f7393Sniklas /* Scan for the sequence $<data>#<checksum>.  Returns 0 on failure,
224e93f7393Sniklas    non-zero on success.  */
225e93f7393Sniklas 
226e93f7393Sniklas static int
getpacket(char * buffer)227*b725ae77Skettenis getpacket (char *buffer)
228e93f7393Sniklas {
229e93f7393Sniklas   unsigned char checksum;
230e93f7393Sniklas   unsigned char xmitcsum;
231e93f7393Sniklas   int i;
232e93f7393Sniklas   int count;
233e93f7393Sniklas   int ch;
234e93f7393Sniklas 
235e93f7393Sniklas   do
236e93f7393Sniklas     {
237e93f7393Sniklas       /* wait around for the start character, ignore all other characters */
238e93f7393Sniklas       while ((ch = getDebugChar()) != '$')
239e93f7393Sniklas 	if (ch == -1)
240e93f7393Sniklas 	  return 0;
241e93f7393Sniklas       checksum = 0;
242e93f7393Sniklas       xmitcsum = -1;
243e93f7393Sniklas 
244e93f7393Sniklas       count = 0;
245e93f7393Sniklas 
246e93f7393Sniklas       /* now, read until a # or end of buffer is found */
247e93f7393Sniklas       while (count < BUFMAX)
248e93f7393Sniklas 	{
249e93f7393Sniklas 	  ch = getDebugChar();
250e93f7393Sniklas 	  if (ch == -1)
251e93f7393Sniklas 	    return 0;
252e93f7393Sniklas 	  if (ch == '#')
253e93f7393Sniklas 	    break;
254e93f7393Sniklas 	  checksum = checksum + ch;
255e93f7393Sniklas 	  buffer[count] = ch;
256e93f7393Sniklas 	  count = count + 1;
257e93f7393Sniklas 	}
258e93f7393Sniklas       buffer[count] = 0;
259e93f7393Sniklas 
260e93f7393Sniklas       if (ch == '#')
261e93f7393Sniklas 	{
262e93f7393Sniklas 	  ch = getDebugChar ();
263e93f7393Sniklas 	  if (ch == -1)
264e93f7393Sniklas 	    return 0;
265e93f7393Sniklas 	  xmitcsum = hex(ch) << 4;
266e93f7393Sniklas 	  ch = getDebugChar ();
267e93f7393Sniklas 	  if (ch == -1)
268e93f7393Sniklas 	    return 0;
269e93f7393Sniklas 	  xmitcsum += hex(ch);
270e93f7393Sniklas 
271e93f7393Sniklas 	  if (checksum != xmitcsum)
272e93f7393Sniklas 	    {
273e93f7393Sniklas 	      if (remote_debug)
274e93f7393Sniklas 		ConsolePrintf ("bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
275e93f7393Sniklas 			       checksum,xmitcsum,buffer);
276e93f7393Sniklas 	      /* failed checksum */
277e93f7393Sniklas 	      if (! putDebugChar('-'))
278e93f7393Sniklas 		return 0;
279e93f7393Sniklas 	      return 1;
280e93f7393Sniklas 	    }
281e93f7393Sniklas 	  else
282e93f7393Sniklas 	    {
283e93f7393Sniklas 	      /* successful transfer */
284e93f7393Sniklas 	      if (! putDebugChar('+'))
285e93f7393Sniklas 		return 0;
286e93f7393Sniklas 	      /* if a sequence char is present, reply the sequence ID */
287e93f7393Sniklas 	      if (buffer[2] == ':')
288e93f7393Sniklas 		{
289e93f7393Sniklas 		  if (! putDebugChar (buffer[0])
290e93f7393Sniklas 		      || ! putDebugChar (buffer[1]))
291e93f7393Sniklas 		    return 0;
292e93f7393Sniklas 		  /* remove sequence chars from buffer */
293e93f7393Sniklas 		  count = strlen(buffer);
294e93f7393Sniklas 		  for (i=3; i <= count; i++)
295e93f7393Sniklas 		    buffer[i-3] = buffer[i];
296e93f7393Sniklas 		}
297e93f7393Sniklas 	    }
298e93f7393Sniklas 	}
299e93f7393Sniklas     }
300e93f7393Sniklas   while (checksum != xmitcsum);
301e93f7393Sniklas 
302e93f7393Sniklas   if (remote_debug)
303e93f7393Sniklas     ConsolePrintf ("Received packet \"%s\"\r\n", buffer);
304e93f7393Sniklas 
305e93f7393Sniklas   return 1;
306e93f7393Sniklas }
307e93f7393Sniklas 
308e93f7393Sniklas /* Send the packet in buffer.  Returns 0 on failure, non-zero on
309e93f7393Sniklas    success.  */
310e93f7393Sniklas 
311e93f7393Sniklas static int
putpacket(char * buffer)312*b725ae77Skettenis putpacket (char *buffer)
313e93f7393Sniklas {
314e93f7393Sniklas   unsigned char checksum;
315e93f7393Sniklas   int count;
316e93f7393Sniklas   int ch;
317e93f7393Sniklas 
318e93f7393Sniklas   if (remote_debug)
319e93f7393Sniklas     ConsolePrintf ("Sending packet \"%s\"\r\n", buffer);
320e93f7393Sniklas 
321e93f7393Sniklas   /*  $<packet info>#<checksum>. */
322e93f7393Sniklas   do
323e93f7393Sniklas     {
324e93f7393Sniklas       if (! putDebugChar('$'))
325e93f7393Sniklas 	return 0;
326e93f7393Sniklas       checksum = 0;
327e93f7393Sniklas       count = 0;
328e93f7393Sniklas 
329e93f7393Sniklas       while (ch=buffer[count])
330e93f7393Sniklas 	{
331e93f7393Sniklas 	  if (! putDebugChar(ch))
332e93f7393Sniklas 	    return 0;
333e93f7393Sniklas 	  checksum += ch;
334e93f7393Sniklas 	  count += 1;
335e93f7393Sniklas 	}
336e93f7393Sniklas 
337e93f7393Sniklas       if (! putDebugChar('#')
338e93f7393Sniklas 	  || ! putDebugChar(hexchars[checksum >> 4])
339e93f7393Sniklas 	  || ! putDebugChar(hexchars[checksum % 16]))
340e93f7393Sniklas 	return 0;
341e93f7393Sniklas 
342e93f7393Sniklas       ch = getDebugChar ();
343e93f7393Sniklas       if (ch == -1)
344e93f7393Sniklas 	return 0;
345e93f7393Sniklas     }
346e93f7393Sniklas   while (ch != '+');
347e93f7393Sniklas 
348e93f7393Sniklas   return 1;
349e93f7393Sniklas }
350e93f7393Sniklas 
351e93f7393Sniklas static char remcomInBuffer[BUFMAX];
352e93f7393Sniklas static char remcomOutBuffer[BUFMAX];
353e93f7393Sniklas static short error;
354e93f7393Sniklas 
355e93f7393Sniklas static void
debug_error(char * format,char * parm)356*b725ae77Skettenis debug_error (char *format, char *parm)
357e93f7393Sniklas {
358e93f7393Sniklas   if (remote_debug)
359e93f7393Sniklas     {
360e93f7393Sniklas       ConsolePrintf (format, parm);
361e93f7393Sniklas       ConsolePrintf ("\n");
362e93f7393Sniklas     }
363e93f7393Sniklas }
364e93f7393Sniklas 
365e93f7393Sniklas /* This is set if we could get a memory access fault.  */
366e93f7393Sniklas static int mem_may_fault;
367e93f7393Sniklas 
368e93f7393Sniklas /* Indicate to caller of mem2hex or hex2mem that there has been an
369e93f7393Sniklas    error.  */
370e93f7393Sniklas volatile int mem_err = 0;
371e93f7393Sniklas 
372e93f7393Sniklas #ifndef ALTERNATE_MEM_FUNCS
373e93f7393Sniklas /* These are separate functions so that they are so short and sweet
374e93f7393Sniklas    that the compiler won't save any registers (if there is a fault
375e93f7393Sniklas    to mem_fault, they won't get restored, so there better not be any
376e93f7393Sniklas    saved).  */
377e93f7393Sniklas 
378e93f7393Sniklas int
get_char(char * addr)379*b725ae77Skettenis get_char (char *addr)
380e93f7393Sniklas {
381e93f7393Sniklas   return *addr;
382e93f7393Sniklas }
383e93f7393Sniklas 
384e93f7393Sniklas void
set_char(char * addr,int val)385*b725ae77Skettenis set_char (char *addr, int val)
386e93f7393Sniklas {
387e93f7393Sniklas   *addr = val;
388e93f7393Sniklas }
389e93f7393Sniklas #endif /* ALTERNATE_MEM_FUNCS */
390e93f7393Sniklas 
391e93f7393Sniklas /* convert the memory pointed to by mem into hex, placing result in buf */
392e93f7393Sniklas /* return a pointer to the last char put in buf (null) */
393e93f7393Sniklas /* If MAY_FAULT is non-zero, then we should set mem_err in response to
394e93f7393Sniklas    a fault; if zero treat a fault like any other fault in the stub.  */
395e93f7393Sniklas 
396e93f7393Sniklas char *
mem2hex(void * mem,char * buf,int count,int may_fault)397*b725ae77Skettenis mem2hex (void *mem, char *buf, int count, int may_fault)
398e93f7393Sniklas {
399e93f7393Sniklas   int i;
400e93f7393Sniklas   unsigned char ch;
401e93f7393Sniklas   char *ptr = mem;
402e93f7393Sniklas 
403e93f7393Sniklas   mem_may_fault = may_fault;
404e93f7393Sniklas   for (i = 0; i < count; i++)
405e93f7393Sniklas     {
406e93f7393Sniklas       ch = get_char (ptr++);
407e93f7393Sniklas       if (may_fault && mem_err)
408e93f7393Sniklas 	return (buf);
409e93f7393Sniklas       *buf++ = hexchars[ch >> 4];
410e93f7393Sniklas       *buf++ = hexchars[ch % 16];
411e93f7393Sniklas     }
412e93f7393Sniklas   *buf = 0;
413e93f7393Sniklas   mem_may_fault = 0;
414e93f7393Sniklas   return(buf);
415e93f7393Sniklas }
416e93f7393Sniklas 
417e93f7393Sniklas /* convert the hex array pointed to by buf into binary to be placed in mem */
418e93f7393Sniklas /* return a pointer to the character AFTER the last byte written */
419e93f7393Sniklas 
420e93f7393Sniklas char *
hex2mem(char * buf,void * mem,int count,int may_fault)421*b725ae77Skettenis hex2mem (char *buf, void *mem, int count, int may_fault)
422e93f7393Sniklas {
423e93f7393Sniklas   int i;
424e93f7393Sniklas   unsigned char ch;
425e93f7393Sniklas   char *ptr = mem;
426e93f7393Sniklas 
427e93f7393Sniklas   mem_may_fault = may_fault;
428e93f7393Sniklas   for (i=0;i<count;i++)
429e93f7393Sniklas     {
430e93f7393Sniklas       ch = hex(*buf++) << 4;
431e93f7393Sniklas       ch = ch + hex(*buf++);
432e93f7393Sniklas       set_char (ptr++, ch);
433e93f7393Sniklas       if (may_fault && mem_err)
434e93f7393Sniklas 	return (ptr);
435e93f7393Sniklas     }
436e93f7393Sniklas   mem_may_fault = 0;
437e93f7393Sniklas   return(mem);
438e93f7393Sniklas }
439e93f7393Sniklas 
440e93f7393Sniklas /* This function takes the 386 exception vector and attempts to
441e93f7393Sniklas    translate this number into a unix compatible signal value.  */
442e93f7393Sniklas 
443e93f7393Sniklas int
computeSignal(int exceptionVector)444*b725ae77Skettenis computeSignal (int exceptionVector)
445e93f7393Sniklas {
446e93f7393Sniklas   int sigval;
447e93f7393Sniklas   switch (exceptionVector)
448e93f7393Sniklas     {
449e93f7393Sniklas     case 0 : sigval = 8; break; /* divide by zero */
450e93f7393Sniklas     case 1 : sigval = 5; break; /* debug exception */
451e93f7393Sniklas     case 3 : sigval = 5; break; /* breakpoint */
452e93f7393Sniklas     case 4 : sigval = 16; break; /* into instruction (overflow) */
453e93f7393Sniklas     case 5 : sigval = 16; break; /* bound instruction */
454e93f7393Sniklas     case 6 : sigval = 4; break; /* Invalid opcode */
455e93f7393Sniklas     case 7 : sigval = 8; break; /* coprocessor not available */
456e93f7393Sniklas     case 8 : sigval = 7; break; /* double fault */
457e93f7393Sniklas     case 9 : sigval = 11; break; /* coprocessor segment overrun */
458e93f7393Sniklas     case 10 : sigval = 11; break; /* Invalid TSS */
459e93f7393Sniklas     case 11 : sigval = 11; break; /* Segment not present */
460e93f7393Sniklas     case 12 : sigval = 11; break; /* stack exception */
461e93f7393Sniklas     case 13 : sigval = 11; break; /* general protection */
462e93f7393Sniklas     case 14 : sigval = 11; break; /* page fault */
463e93f7393Sniklas     case 16 : sigval = 7; break; /* coprocessor error */
464e93f7393Sniklas     default:
465e93f7393Sniklas       sigval = 7;		/* "software generated"*/
466e93f7393Sniklas     }
467e93f7393Sniklas   return (sigval);
468e93f7393Sniklas }
469e93f7393Sniklas 
470e93f7393Sniklas /**********************************************/
471e93f7393Sniklas /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
472e93f7393Sniklas /* RETURN NUMBER OF CHARS PROCESSED           */
473e93f7393Sniklas /**********************************************/
474e93f7393Sniklas static int
hexToInt(char ** ptr,int * intValue)475*b725ae77Skettenis hexToInt (char **ptr, int *intValue)
476e93f7393Sniklas {
477e93f7393Sniklas   int numChars = 0;
478e93f7393Sniklas   int hexValue;
479e93f7393Sniklas 
480e93f7393Sniklas   *intValue = 0;
481e93f7393Sniklas 
482e93f7393Sniklas   while (**ptr)
483e93f7393Sniklas     {
484e93f7393Sniklas       hexValue = hex(**ptr);
485e93f7393Sniklas       if (hexValue >=0)
486e93f7393Sniklas 	{
487e93f7393Sniklas 	  *intValue = (*intValue <<4) | hexValue;
488e93f7393Sniklas 	  numChars ++;
489e93f7393Sniklas 	}
490e93f7393Sniklas       else
491e93f7393Sniklas 	break;
492e93f7393Sniklas 
493e93f7393Sniklas       (*ptr)++;
494e93f7393Sniklas     }
495e93f7393Sniklas 
496e93f7393Sniklas   return (numChars);
497e93f7393Sniklas }
498e93f7393Sniklas 
499e93f7393Sniklas /* This function does all command processing for interfacing to gdb.
500e93f7393Sniklas    It is called whenever an exception occurs in the module being
501e93f7393Sniklas    debugged.  */
502e93f7393Sniklas 
503e93f7393Sniklas static LONG
handle_exception(struct StackFrame * frame)504*b725ae77Skettenis handle_exception (struct StackFrame *frame)
505e93f7393Sniklas {
506e93f7393Sniklas   int addr, length;
507e93f7393Sniklas   char *ptr;
508e93f7393Sniklas   static struct DBG_LoadDefinitionStructure *ldinfo = 0;
509e93f7393Sniklas   static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program.  */
510e93f7393Sniklas 
511e93f7393Sniklas #if 0
512e93f7393Sniklas   /* According to some documentation from Novell, the bell sometimes
513e93f7393Sniklas      may be ringing at this point.  This can be stopped on Netware 4
514e93f7393Sniklas      systems by calling the undocumented StopBell() function. */
515e93f7393Sniklas 
516e93f7393Sniklas   StopBell ();
517e93f7393Sniklas #endif
518e93f7393Sniklas 
519e93f7393Sniklas   if (remote_debug)
520e93f7393Sniklas     {
521e93f7393Sniklas       ConsolePrintf ("vector=%d: %s, pc=%08x, thread=%08x\r\n",
522e93f7393Sniklas 		     frame->ExceptionNumber,
523e93f7393Sniklas 		     frame->ExceptionDescription,
524e93f7393Sniklas 		     frame->ExceptionPC,
525e93f7393Sniklas 		     GetThreadID ());
526e93f7393Sniklas     }
527e93f7393Sniklas 
528e93f7393Sniklas   switch (frame->ExceptionNumber)
529e93f7393Sniklas     {
530e93f7393Sniklas     case START_NLM_EVENT:
531e93f7393Sniklas       /* If the NLM just started, we record the module load information
532e93f7393Sniklas 	 and the thread ID, and set a breakpoint at the first instruction
533e93f7393Sniklas 	 in the program.  */
534e93f7393Sniklas 
535e93f7393Sniklas       ldinfo = ((struct DBG_LoadDefinitionStructure *)
536e93f7393Sniklas 		frame->ExceptionErrorCode);
537e93f7393Sniklas       memcpy (first_insn, ldinfo->LDInitializationProcedure,
538e93f7393Sniklas 	      BREAKPOINT_SIZE);
539e93f7393Sniklas       memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
540e93f7393Sniklas 	      BREAKPOINT_SIZE);
541e93f7393Sniklas       flush_i_cache ();
542e93f7393Sniklas       return RETURN_TO_PROGRAM;
543e93f7393Sniklas 
544e93f7393Sniklas     case ENTER_DEBUGGER_EVENT:
545e93f7393Sniklas     case KEYBOARD_BREAK_EVENT:
546e93f7393Sniklas       /* Pass some events on to the next debugger, in case it will handle
547e93f7393Sniklas 	 them.  */
548e93f7393Sniklas       return RETURN_TO_NEXT_DEBUGGER;
549e93f7393Sniklas 
550e93f7393Sniklas     case 3:			/* Breakpoint */
551e93f7393Sniklas       /* After we've reached the initial breakpoint, reset it.  */
552e93f7393Sniklas       if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
553e93f7393Sniklas 	  && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
554e93f7393Sniklas 		     BREAKPOINT_SIZE) == 0)
555e93f7393Sniklas 	{
556e93f7393Sniklas 	  memcpy (ldinfo->LDInitializationProcedure, first_insn,
557e93f7393Sniklas 		  BREAKPOINT_SIZE);
558e93f7393Sniklas 	  frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
559e93f7393Sniklas 	  flush_i_cache ();
560e93f7393Sniklas 	}
561e93f7393Sniklas       /* Normal breakpoints end up here */
562e93f7393Sniklas       do_status (remcomOutBuffer, frame);
563e93f7393Sniklas       break;
564e93f7393Sniklas 
565e93f7393Sniklas     default:
566e93f7393Sniklas       /* At the moment, we don't care about most of the unusual NetWare
567e93f7393Sniklas 	 exceptions.  */
568e93f7393Sniklas       if (frame->ExceptionNumber > 31)
569e93f7393Sniklas 	return RETURN_TO_PROGRAM;
570e93f7393Sniklas 
571e93f7393Sniklas       /* Most machine level exceptions end up here */
572e93f7393Sniklas       do_status (remcomOutBuffer, frame);
573e93f7393Sniklas       break;
574e93f7393Sniklas 
575e93f7393Sniklas     case 11:			/* Segment not present */
576e93f7393Sniklas     case 13:			/* General protection */
577e93f7393Sniklas     case 14:			/* Page fault */
578e93f7393Sniklas       /* If we get a GP fault, and mem_may_fault is set, and the
579e93f7393Sniklas 	 instruction pointer is near set_char or get_char, then we caused
580e93f7393Sniklas 	 the fault ourselves accessing an illegal memory location.  */
581e93f7393Sniklas       if (mem_may_fault
582e93f7393Sniklas 	  && ((frame->ExceptionPC >= (long) &set_char
583e93f7393Sniklas 	       && frame->ExceptionPC < (long) &set_char + 50)
584e93f7393Sniklas 	      || (frame->ExceptionPC >= (long) &get_char
585e93f7393Sniklas 		  && frame->ExceptionPC < (long) &get_char + 50)))
586e93f7393Sniklas 	{
587e93f7393Sniklas 	  mem_err = 1;
588e93f7393Sniklas 	  /* Point the instruction pointer at an assembly language stub
589e93f7393Sniklas 	     which just returns from the function.  */
590e93f7393Sniklas 
591e93f7393Sniklas 	  frame->ExceptionPC += 4; /* Skip the load or store */
592e93f7393Sniklas 
593e93f7393Sniklas 	  /* Keep going.  This will act as though it returned from
594e93f7393Sniklas 	     set_char or get_char.  The calling routine will check
595e93f7393Sniklas 	     mem_err, and do the right thing.  */
596e93f7393Sniklas 	  return RETURN_TO_PROGRAM;
597e93f7393Sniklas 	}
598e93f7393Sniklas       /* Random mem fault, report it */
599e93f7393Sniklas       do_status (remcomOutBuffer, frame);
600e93f7393Sniklas       break;
601e93f7393Sniklas 
602e93f7393Sniklas     case TERMINATE_NLM_EVENT:
603e93f7393Sniklas       /* There is no way to get the exit status.  */
604e93f7393Sniklas       sprintf (remcomOutBuffer, "W%02x", 0);
605e93f7393Sniklas       break;			/* We generate our own status */
606e93f7393Sniklas     }
607e93f7393Sniklas 
608e93f7393Sniklas   /* FIXME: How do we know that this exception has anything to do with
609e93f7393Sniklas      the program we are debugging?  We can check whether the PC is in
610e93f7393Sniklas      the range of the module we are debugging, but that doesn't help
611e93f7393Sniklas      much since an error could occur in a library routine.  */
612e93f7393Sniklas 
613e93f7393Sniklas   clear_step_traps (frame);
614e93f7393Sniklas 
615e93f7393Sniklas   if (! putpacket(remcomOutBuffer))
616e93f7393Sniklas     return RETURN_TO_NEXT_DEBUGGER;
617e93f7393Sniklas 
618e93f7393Sniklas   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
619e93f7393Sniklas     {
620e93f7393Sniklas       ResumeThread (mainthread);
621e93f7393Sniklas       return RETURN_TO_PROGRAM;
622e93f7393Sniklas     }
623e93f7393Sniklas 
624e93f7393Sniklas   while (1)
625e93f7393Sniklas     {
626e93f7393Sniklas       error = 0;
627e93f7393Sniklas       remcomOutBuffer[0] = 0;
628e93f7393Sniklas       if (! getpacket (remcomInBuffer))
629e93f7393Sniklas 	return RETURN_TO_NEXT_DEBUGGER;
630e93f7393Sniklas       switch (remcomInBuffer[0])
631e93f7393Sniklas 	{
632e93f7393Sniklas 	case '?':
633e93f7393Sniklas 	  do_status (remcomOutBuffer, frame);
634e93f7393Sniklas 	  break;
635e93f7393Sniklas 	case 'd':
636e93f7393Sniklas 	  remote_debug = !(remote_debug); /* toggle debug flag */
637e93f7393Sniklas 	  break;
638e93f7393Sniklas 	case 'g':
639e93f7393Sniklas 	  /* return the value of the CPU registers */
640e93f7393Sniklas 	  frame_to_registers (frame, remcomOutBuffer);
641e93f7393Sniklas 	  break;
642e93f7393Sniklas 	case 'G':
643e93f7393Sniklas 	  /* set the value of the CPU registers - return OK */
644e93f7393Sniklas 	  registers_to_frame (&remcomInBuffer[1], frame);
645e93f7393Sniklas 	  strcpy(remcomOutBuffer,"OK");
646e93f7393Sniklas 	  break;
647e93f7393Sniklas 
648e93f7393Sniklas 	case 'm':
649e93f7393Sniklas 	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
650e93f7393Sniklas 	  /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
651e93f7393Sniklas 	  ptr = &remcomInBuffer[1];
652e93f7393Sniklas 	  if (hexToInt(&ptr,&addr))
653e93f7393Sniklas 	    if (*(ptr++) == ',')
654e93f7393Sniklas 	      if (hexToInt(&ptr,&length))
655e93f7393Sniklas 		{
656e93f7393Sniklas 		  ptr = 0;
657e93f7393Sniklas 		  mem_err = 0;
658e93f7393Sniklas 		  mem2hex((char*) addr, remcomOutBuffer, length, 1);
659e93f7393Sniklas 		  if (mem_err)
660e93f7393Sniklas 		    {
661e93f7393Sniklas 		      strcpy (remcomOutBuffer, "E03");
662e93f7393Sniklas 		      debug_error ("memory fault");
663e93f7393Sniklas 		    }
664e93f7393Sniklas 		}
665e93f7393Sniklas 
666e93f7393Sniklas 	  if (ptr)
667e93f7393Sniklas 	    {
668e93f7393Sniklas 	      strcpy(remcomOutBuffer,"E01");
669e93f7393Sniklas 	      debug_error("malformed read memory command: %s",remcomInBuffer);
670e93f7393Sniklas 	    }
671e93f7393Sniklas 	  break;
672e93f7393Sniklas 
673e93f7393Sniklas 	case 'M':
674e93f7393Sniklas 	  /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
675e93f7393Sniklas 	  /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
676e93f7393Sniklas 	  ptr = &remcomInBuffer[1];
677e93f7393Sniklas 	  if (hexToInt(&ptr,&addr))
678e93f7393Sniklas 	    if (*(ptr++) == ',')
679e93f7393Sniklas 	      if (hexToInt(&ptr,&length))
680e93f7393Sniklas 		if (*(ptr++) == ':')
681e93f7393Sniklas 		  {
682e93f7393Sniklas 		    mem_err = 0;
683e93f7393Sniklas 		    hex2mem(ptr, (char*) addr, length, 1);
684e93f7393Sniklas 
685e93f7393Sniklas 		    if (mem_err)
686e93f7393Sniklas 		      {
687e93f7393Sniklas 			strcpy (remcomOutBuffer, "E03");
688e93f7393Sniklas 			debug_error ("memory fault");
689e93f7393Sniklas 		      }
690e93f7393Sniklas 		    else
691e93f7393Sniklas 		      {
692e93f7393Sniklas 			strcpy(remcomOutBuffer,"OK");
693e93f7393Sniklas 		      }
694e93f7393Sniklas 
695e93f7393Sniklas 		    ptr = 0;
696e93f7393Sniklas 		  }
697e93f7393Sniklas 	  if (ptr)
698e93f7393Sniklas 	    {
699e93f7393Sniklas 	      strcpy(remcomOutBuffer,"E02");
700e93f7393Sniklas 	      debug_error("malformed write memory command: %s",remcomInBuffer);
701e93f7393Sniklas 	    }
702e93f7393Sniklas 	  break;
703e93f7393Sniklas 
704e93f7393Sniklas 	case 'c':
705e93f7393Sniklas 	case 's':
706e93f7393Sniklas 	  /* cAA..AA    Continue at address AA..AA(optional) */
707e93f7393Sniklas 	  /* sAA..AA   Step one instruction from AA..AA(optional) */
708e93f7393Sniklas 	  /* try to read optional parameter, pc unchanged if no parm */
709e93f7393Sniklas 	  ptr = &remcomInBuffer[1];
710e93f7393Sniklas 	  if (hexToInt(&ptr,&addr))
711e93f7393Sniklas 	    {
712e93f7393Sniklas /*	      registers[PC_REGNUM].lo = addr;*/
713e93f7393Sniklas 	      fprintf (stderr, "Setting PC to 0x%x\n", addr);
714e93f7393Sniklas 	      while (1);
715e93f7393Sniklas 	    }
716e93f7393Sniklas 
717e93f7393Sniklas 	  if (remcomInBuffer[0] == 's')
718e93f7393Sniklas 	    set_step_traps (frame);
719e93f7393Sniklas 
720e93f7393Sniklas 	  flush_i_cache ();
721e93f7393Sniklas 	  return RETURN_TO_PROGRAM;
722e93f7393Sniklas 
723e93f7393Sniklas 	case 'k':
724e93f7393Sniklas 	  /* kill the program */
725e93f7393Sniklas 	  KillMe (ldinfo);
726e93f7393Sniklas 	  ResumeThread (mainthread);
727e93f7393Sniklas 	  return RETURN_TO_PROGRAM;
728e93f7393Sniklas 
729e93f7393Sniklas 	case 'q':		/* Query message */
730e93f7393Sniklas 	  if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
731e93f7393Sniklas 	    {
732e93f7393Sniklas 	      sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
733e93f7393Sniklas 		       ldinfo->LDCodeImageOffset,
734e93f7393Sniklas 		       ldinfo->LDDataImageOffset,
735e93f7393Sniklas 		       ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
736e93f7393Sniklas 	    }
737e93f7393Sniklas 	  else
738e93f7393Sniklas 	    sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
739e93f7393Sniklas 	  break;
740e93f7393Sniklas 	}
741e93f7393Sniklas 
742e93f7393Sniklas       /* reply to the request */
743e93f7393Sniklas       if (! putpacket(remcomOutBuffer))
744e93f7393Sniklas 	return RETURN_TO_NEXT_DEBUGGER;
745e93f7393Sniklas     }
746e93f7393Sniklas }
747e93f7393Sniklas 
748e93f7393Sniklas char *progname;
749e93f7393Sniklas 
750e93f7393Sniklas struct bitRate {
751e93f7393Sniklas   BYTE bitRate;
752e93f7393Sniklas   const char *bitRateString;
753e93f7393Sniklas };
754e93f7393Sniklas 
755e93f7393Sniklas struct bitRate bitRateTable[] =
756e93f7393Sniklas {
757e93f7393Sniklas   { AIO_BAUD_50    ,      "50" },
758e93f7393Sniklas   { AIO_BAUD_75    ,      "75" },
759e93f7393Sniklas   { AIO_BAUD_110   ,     "110" },
760e93f7393Sniklas   { AIO_BAUD_134p5 ,   "134.5" },
761e93f7393Sniklas   { AIO_BAUD_150   ,     "150" },
762e93f7393Sniklas   { AIO_BAUD_300   ,     "300" },
763e93f7393Sniklas   { AIO_BAUD_600   ,     "600" },
764e93f7393Sniklas   { AIO_BAUD_1200  ,    "1200" },
765e93f7393Sniklas   { AIO_BAUD_1800  ,    "1800" },
766e93f7393Sniklas   { AIO_BAUD_2000  ,    "2000" },
767e93f7393Sniklas   { AIO_BAUD_2400  ,    "2400" },
768e93f7393Sniklas   { AIO_BAUD_3600  ,    "3600" },
769e93f7393Sniklas   { AIO_BAUD_4800  ,    "4800" },
770e93f7393Sniklas   { AIO_BAUD_7200  ,    "7200" },
771e93f7393Sniklas   { AIO_BAUD_9600  ,    "9600" },
772e93f7393Sniklas   { AIO_BAUD_19200 ,   "19200" },
773e93f7393Sniklas   { AIO_BAUD_38400 ,   "38400" },
774e93f7393Sniklas   { AIO_BAUD_57600 ,   "57600" },
775e93f7393Sniklas   { AIO_BAUD_115200,  "115200" },
776e93f7393Sniklas   { -1, NULL }
777e93f7393Sniklas };
778e93f7393Sniklas 
779e93f7393Sniklas char dataBitsTable[] = "5678";
780e93f7393Sniklas 
781e93f7393Sniklas char *stopBitsTable[] = { "1", "1.5", "2" };
782e93f7393Sniklas 
783e93f7393Sniklas char parity[] = "NOEMS";
784e93f7393Sniklas 
785e93f7393Sniklas /* Start up.  The main thread opens the named serial I/O port, loads
786e93f7393Sniklas    the named NLM module and then goes to sleep.  The serial I/O port
787e93f7393Sniklas    is named as a board number and a port number.  It would be more DOS
788e93f7393Sniklas    like to provide a menu of available serial ports, but I don't want
789e93f7393Sniklas    to have to figure out how to do that.  */
790e93f7393Sniklas 
791e93f7393Sniklas int
main(int argc,char ** argv)792*b725ae77Skettenis main (int argc, char **argv)
793e93f7393Sniklas {
794e93f7393Sniklas   int hardware, board, port;
795e93f7393Sniklas   BYTE bitRate;
796e93f7393Sniklas   BYTE dataBits;
797e93f7393Sniklas   BYTE stopBits;
798e93f7393Sniklas   BYTE parityMode;
799e93f7393Sniklas   LONG err;
800e93f7393Sniklas   struct debuggerStructure s;
801e93f7393Sniklas   int cmdindx;
802e93f7393Sniklas   char *cmdlin;
803e93f7393Sniklas   int i;
804e93f7393Sniklas 
805e93f7393Sniklas   /* set progname */
806e93f7393Sniklas   progname = "gdbserve";
807e93f7393Sniklas 
808e93f7393Sniklas   /* set default serial line */
809e93f7393Sniklas   hardware = -1;
810e93f7393Sniklas   board = 0;
811e93f7393Sniklas   port = 0;
812e93f7393Sniklas 
813e93f7393Sniklas   /* set default serial line characteristics */
814e93f7393Sniklas   bitRate  = AIO_BAUD_9600;
815e93f7393Sniklas   dataBits = AIO_DATA_BITS_8;
816e93f7393Sniklas   stopBits = AIO_STOP_BITS_1;
817e93f7393Sniklas   parityMode = AIO_PARITY_NONE;
818e93f7393Sniklas 
819e93f7393Sniklas   cmdindx = 0;
820e93f7393Sniklas   for (argc--, argv++; *argv; argc--, argv++)
821e93f7393Sniklas     {
822e93f7393Sniklas       char *bp;
823e93f7393Sniklas       char *ep;
824e93f7393Sniklas 
825e93f7393Sniklas       if (strnicmp(*argv, "BAUD=", 5) == 0)
826e93f7393Sniklas 	{
827e93f7393Sniklas 	  struct bitRate *brp;
828e93f7393Sniklas 
829e93f7393Sniklas 	  bp = *argv + 5;
830e93f7393Sniklas 	  for (brp = bitRateTable; brp->bitRate != (BYTE) -1; brp++)
831e93f7393Sniklas 	    {
832e93f7393Sniklas 	      if (strcmp(brp->bitRateString, bp) == 0)
833e93f7393Sniklas 		{
834e93f7393Sniklas 		  bitRate = brp->bitRate;
835e93f7393Sniklas 		  break;
836e93f7393Sniklas 		}
837e93f7393Sniklas 	    }
838e93f7393Sniklas 
839e93f7393Sniklas 	  if (brp->bitRateString == NULL)
840e93f7393Sniklas 	    {
841e93f7393Sniklas 	      fprintf(stderr, "%s: %s: unknown or unsupported bit rate",
842e93f7393Sniklas 		      progname, bp);
843e93f7393Sniklas 	      exit (1);
844e93f7393Sniklas 	    }
845e93f7393Sniklas 	}
846e93f7393Sniklas       else if (strnicmp(*argv, "BOARD=", 6) == 0)
847e93f7393Sniklas         {
848e93f7393Sniklas 	  bp = *argv + 6;
849e93f7393Sniklas 	  board = strtol (bp, &ep, 0);
850e93f7393Sniklas 	  if (ep == bp || *ep != '\0')
851e93f7393Sniklas 	    {
852e93f7393Sniklas 	      fprintf (stderr, "%s: %s: expected integer argument\n",
853e93f7393Sniklas 		       progname, bp);
854e93f7393Sniklas 	      exit(1);
855e93f7393Sniklas 	    }
856e93f7393Sniklas 	}
857e93f7393Sniklas #if 1				/* FIXME: this option has been depricated */
858e93f7393Sniklas       else if (strnicmp(*argv, "NODE=", 5) == 0)
859e93f7393Sniklas 	{
860e93f7393Sniklas 	  bp = *argv + 5;
861e93f7393Sniklas 	  board = strtol (bp, &ep, 0);
862e93f7393Sniklas 	  if (ep == bp || *ep != '\0')
863e93f7393Sniklas 	    {
864e93f7393Sniklas 	      fprintf (stderr, "%s: %s: expected integer argument\n",
865e93f7393Sniklas 		       progname, bp);
866e93f7393Sniklas 	      exit(1);
867e93f7393Sniklas 	    }
868e93f7393Sniklas 	}
869e93f7393Sniklas #endif
870e93f7393Sniklas       else if (strnicmp(*argv, "PORT=", 5) == 0)
871e93f7393Sniklas 	{
872e93f7393Sniklas 	  bp = *argv + 5;
873e93f7393Sniklas 	  port = strtol (bp, &ep, 0);
874e93f7393Sniklas 	  if (ep == bp || *ep != '\0')
875e93f7393Sniklas 	    {
876e93f7393Sniklas 	      fprintf (stderr, "%s: %s: expected integer argument\n",
877e93f7393Sniklas 		       progname, bp);
878e93f7393Sniklas 	      exit(1);
879e93f7393Sniklas 	    }
880e93f7393Sniklas 	}
881e93f7393Sniklas       else
882e93f7393Sniklas 	{
883e93f7393Sniklas 	  break;
884e93f7393Sniklas 	}
885e93f7393Sniklas 
886e93f7393Sniklas       cmdindx++;
887e93f7393Sniklas     }
888e93f7393Sniklas 
889e93f7393Sniklas   if (argc == 0)
890e93f7393Sniklas     {
891e93f7393Sniklas       fprintf (stderr,
892e93f7393Sniklas 	       "Usage: load %s [options] program [arguments]\n", progname);
893e93f7393Sniklas       exit (1);
894e93f7393Sniklas     }
895e93f7393Sniklas 
896e93f7393Sniklas   err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
897e93f7393Sniklas   if (err != AIO_SUCCESS)
898e93f7393Sniklas     {
899e93f7393Sniklas       switch (err)
900e93f7393Sniklas 	{
901e93f7393Sniklas 	case AIO_PORT_NOT_AVAILABLE:
902e93f7393Sniklas 	  fprintf (stderr, "Port not available\n");
903e93f7393Sniklas 	  break;
904e93f7393Sniklas 
905e93f7393Sniklas 	case AIO_BOARD_NUMBER_INVALID:
906e93f7393Sniklas 	case AIO_PORT_NUMBER_INVALID:
907e93f7393Sniklas 	  fprintf (stderr, "No such port\n");
908e93f7393Sniklas 	  break;
909e93f7393Sniklas 
910e93f7393Sniklas 	default:
911e93f7393Sniklas 	  fprintf (stderr, "Could not open port: %d\n", err);
912e93f7393Sniklas 	  break;
913e93f7393Sniklas 	}
914e93f7393Sniklas 
915e93f7393Sniklas       exit (1);
916e93f7393Sniklas     }
917e93f7393Sniklas 
918e93f7393Sniklas   err = AIOConfigurePort (AIOhandle, bitRate, dataBits, stopBits, parityMode,
919e93f7393Sniklas 			  AIO_HARDWARE_FLOW_CONTROL_OFF);
920e93f7393Sniklas 
921e93f7393Sniklas   if (err == AIO_QUALIFIED_SUCCESS)
922e93f7393Sniklas     {
923e93f7393Sniklas       AIOPORTCONFIG portConfig;
924e93f7393Sniklas 
925e93f7393Sniklas       fprintf (stderr, "Port configuration changed!\n");
926e93f7393Sniklas 
927e93f7393Sniklas       portConfig.returnLength = sizeof(portConfig);
928e93f7393Sniklas       AIOGetPortConfiguration (AIOhandle, &portConfig, NULL);
929e93f7393Sniklas 
930e93f7393Sniklas       fprintf (stderr,
931e93f7393Sniklas 	       "  Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
932e93f7393Sniklas  Flow:%s\n",
933e93f7393Sniklas 	       bitRateTable[portConfig.bitRate].bitRateString,
934e93f7393Sniklas 	       dataBitsTable[portConfig.dataBits],
935e93f7393Sniklas 	       stopBitsTable[portConfig.stopBits],
936e93f7393Sniklas 	       parity[portConfig.parityMode],
937e93f7393Sniklas 	       portConfig.flowCtrlMode ? "ON" : "OFF");
938e93f7393Sniklas     }
939e93f7393Sniklas   else if (err != AIO_SUCCESS)
940e93f7393Sniklas     {
941e93f7393Sniklas       fprintf (stderr, "Could not configure port: %d\n", err);
942e93f7393Sniklas       AIOReleasePort (AIOhandle);
943e93f7393Sniklas       exit (1);
944e93f7393Sniklas     }
945e93f7393Sniklas 
946e93f7393Sniklas   if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
947e93f7393Sniklas 			    (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
948e93f7393Sniklas       != AIO_SUCCESS)
949e93f7393Sniklas     {
950e93f7393Sniklas       LONG extStatus, chgdExtStatus;
951e93f7393Sniklas 
952e93f7393Sniklas       fprintf (stderr, "Could not set desired port controls!\n");
953e93f7393Sniklas       AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
954e93f7393Sniklas       fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
955e93f7393Sniklas 	       chgdExtStatus);
956e93f7393Sniklas     }
957e93f7393Sniklas 
958e93f7393Sniklas   /* Register ourselves as an alternate debugger.  */
959e93f7393Sniklas   memset (&s, 0, sizeof s);
960e93f7393Sniklas   s.DDSResourceTag = ((struct ResourceTagStructure *)
961e93f7393Sniklas 		      AllocateResourceTag (GetNLMHandle (),
962e93f7393Sniklas 					   (BYTE *)"gdbserver",
963e93f7393Sniklas 					   DebuggerSignature));
964e93f7393Sniklas   if (s.DDSResourceTag == 0)
965e93f7393Sniklas     {
966e93f7393Sniklas       fprintf (stderr, "AllocateResourceTag failed\n");
967e93f7393Sniklas       AIOReleasePort (AIOhandle);
968e93f7393Sniklas       exit (1);
969e93f7393Sniklas     }
970e93f7393Sniklas   s.DDSdebuggerEntry = handle_exception;
971e93f7393Sniklas   s.DDSFlags = TSS_FRAME_BIT;
972e93f7393Sniklas 
973e93f7393Sniklas   err = RegisterDebuggerRTag (&s, AT_FIRST);
974e93f7393Sniklas   if (err != 0)
975e93f7393Sniklas     {
976e93f7393Sniklas       fprintf (stderr, "RegisterDebuggerRTag failed\n");
977e93f7393Sniklas       AIOReleasePort (AIOhandle);
978e93f7393Sniklas       exit (1);
979e93f7393Sniklas     }
980e93f7393Sniklas 
981e93f7393Sniklas   /* Get the command line we were invoked with, and advance it past
982e93f7393Sniklas      our name and the board and port arguments.  */
983e93f7393Sniklas   cmdlin = getcmd ((char *) NULL);
984e93f7393Sniklas   for (i = 0; i < cmdindx; i++)
985e93f7393Sniklas     {
986e93f7393Sniklas       while (! isspace (*cmdlin))
987e93f7393Sniklas 	++cmdlin;
988e93f7393Sniklas       while (isspace (*cmdlin))
989e93f7393Sniklas 	++cmdlin;
990e93f7393Sniklas     }
991e93f7393Sniklas 
992e93f7393Sniklas   /* In case GDB is started before us, ack any packets (presumably
993e93f7393Sniklas      "$?#xx") sitting there.  */
994e93f7393Sniklas   if (! putDebugChar ('+'))
995e93f7393Sniklas     {
996e93f7393Sniklas       fprintf (stderr, "putDebugChar failed\n");
997e93f7393Sniklas       UnRegisterDebugger (&s);
998e93f7393Sniklas       AIOReleasePort (AIOhandle);
999e93f7393Sniklas       exit (1);
1000e93f7393Sniklas     }
1001e93f7393Sniklas 
1002e93f7393Sniklas   mainthread = GetThreadID ();
1003e93f7393Sniklas 
1004e93f7393Sniklas   if (remote_debug > 0)
1005e93f7393Sniklas     ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1006e93f7393Sniklas 		   cmdlin, __GetScreenID (GetCurrentScreen()));
1007e93f7393Sniklas 
1008e93f7393Sniklas   /* Start up the module to be debugged.  */
1009e93f7393Sniklas   err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
1010e93f7393Sniklas 		    (BYTE *)cmdlin, LO_DEBUG);
1011e93f7393Sniklas   if (err != 0)
1012e93f7393Sniklas     {
1013e93f7393Sniklas       fprintf (stderr, "LoadModule failed: %d\n", err);
1014e93f7393Sniklas       UnRegisterDebugger (&s);
1015e93f7393Sniklas       AIOReleasePort (AIOhandle);
1016e93f7393Sniklas       exit (1);
1017e93f7393Sniklas     }
1018e93f7393Sniklas 
1019e93f7393Sniklas   /* Wait for the debugger to wake us up.  */
1020e93f7393Sniklas   if (remote_debug > 0)
1021e93f7393Sniklas     ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
1022e93f7393Sniklas   SuspendThread (mainthread);
1023e93f7393Sniklas   if (remote_debug > 0)
1024e93f7393Sniklas     ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
1025e93f7393Sniklas 
1026e93f7393Sniklas   /* If we are woken up, print an optional error message, deregister
1027e93f7393Sniklas      ourselves and exit.  */
1028e93f7393Sniklas   if (error_message != NULL)
1029e93f7393Sniklas     fprintf (stderr, "%s\n", error_message);
1030e93f7393Sniklas   UnRegisterDebugger (&s);
1031e93f7393Sniklas   AIOReleasePort (AIOhandle);
1032e93f7393Sniklas   exit (0);
1033e93f7393Sniklas }
1034