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