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