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