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