* dbxread.c: Don't include libbfd.h.
[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
2e6784a8
SG
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
155unsigned char breakpoint_insn[] = BREAKPOINT;
156#define BREAKPOINT_SIZE (sizeof breakpoint_insn)
157
a49666fe 158static void flush_i_cache() {}
72dd16ea 159
a49666fe
SG
160static char *mem2hex (void *mem, char *buf, int count, int may_fault);
161static char *hex2mem (char *buf, void *mem, int count, int may_fault);
2e6784a8
SG
162static void set_step_traps (struct StackFrame *);
163static void clear_step_traps (struct StackFrame *);
72dd16ea 164
a49666fe 165#if 0
d0e2b767 166__main() {};
a49666fe 167#endif
d0e2b767 168
72dd16ea
ILT
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
172static int
173getDebugChar ()
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
197static int
198putDebugChar (c)
199 unsigned char c;
200{
201 int err;
202 LONG put;
203
d0e2b767
SG
204 put = 0;
205 while (put < 1)
72dd16ea 206 {
d0e2b767
SG
207 err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
208 if (err != 0)
209 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
72dd16ea
ILT
210 }
211 return 1;
212}
213
214/* Get the registers out of the frame information. */
215
216static void
217frame_to_registers (frame, regs)
2e6784a8 218 struct StackFrame *frame;
a49666fe 219 char *regs;
72dd16ea 220{
a49666fe
SG
221 /* Copy EAX -> EDI */
222 mem2hex (&frame->ExceptionEAX, &regs[0 * 4 * 2], 4 * 8, 0);
223
224 /* Copy EIP & PS */
2e6784a8 225 mem2hex (&frame->ExceptionPC, &regs[8 * 4 * 2], 4 * 2, 0);
a49666fe
SG
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);
72dd16ea
ILT
235}
236
237/* Put the registers back into the frame information. */
238
239static void
240registers_to_frame (regs, frame)
a49666fe 241 char *regs;
2e6784a8 242 struct StackFrame *frame;
72dd16ea 243{
a49666fe
SG
244 /* Copy EAX -> EDI */
245 hex2mem (&regs[0 * 4 * 2], &frame->ExceptionEAX, 4 * 8, 0);
246
247 /* Copy EIP & PS */
2e6784a8 248 hex2mem (&regs[8 * 4 * 2], &frame->ExceptionPC, 4 * 2, 0);
a49666fe
SG
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);
72dd16ea
ILT
258}
259
260/* Turn a hex character into a number. */
261
262static int
263hex (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
278static int
279getpacket (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);
72dd16ea
ILT
323
324 if (checksum != xmitcsum)
325 {
a49666fe
SG
326 if (remote_debug)
327 ConsolePrintf ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
328 checksum,xmitcsum,buffer);
72dd16ea
ILT
329 /* failed checksum */
330 if (! putDebugChar('-'))
331 return 0;
a49666fe 332 return 1;
72dd16ea
ILT
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
89709d42
ILT
355 if (remote_debug)
356 ConsolePrintf ("Received packet \"%s\"\r\n", buffer);
357
72dd16ea
ILT
358 return 1;
359}
360
361/* Send the packet in buffer. Returns 0 on failure, non-zero on
362 success. */
363
364static int
365putpacket (buffer)
366 char * buffer;
367{
368 unsigned char checksum;
369 int count;
370 int ch;
371
89709d42
ILT
372 if (remote_debug)
373 ConsolePrintf ("Sending packet \"%s\"\r\n", buffer);
374
72dd16ea
ILT
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
405static char remcomInBuffer[BUFMAX];
406static char remcomOutBuffer[BUFMAX];
407static short error;
408
409static void
410debug_error (format, parm)
411 char *format;
412 char *parm;
413{
414 if (remote_debug)
89709d42 415 {
a49666fe
SG
416 ConsolePrintf (format, parm);
417 ConsolePrintf ("\n");
89709d42 418 }
72dd16ea
ILT
419}
420
89709d42
ILT
421/* This is set if we could get a memory access fault. */
422static int mem_may_fault;
72dd16ea
ILT
423
424/* Indicate to caller of mem2hex or hex2mem that there has been an
425 error. */
426static volatile int mem_err = 0;
427
72dd16ea
ILT
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
433static int
434get_char (addr)
435 char *addr;
436{
437 return *addr;
438}
439
440static void
441set_char (addr, val)
442 char *addr;
443 int val;
444{
445 *addr = val;
446}
447
89709d42
ILT
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
452extern void just_return ();
453asm (".globl just_return");
454asm (".globl _just_return");
455asm ("just_return:");
456asm ("_just_return:");
457asm ("leave");
458asm ("ret");
459
72dd16ea
ILT
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
465static char *
466mem2hex (mem, buf, count, may_fault)
a49666fe 467 void *mem;
72dd16ea
ILT
468 char *buf;
469 int count;
470 int may_fault;
471{
472 int i;
473 unsigned char ch;
a49666fe 474 char *ptr = mem;
72dd16ea 475
89709d42 476 mem_may_fault = may_fault;
72dd16ea
ILT
477 for (i = 0; i < count; i++)
478 {
a49666fe 479 ch = get_char (ptr++);
72dd16ea
ILT
480 if (may_fault && mem_err)
481 return (buf);
482 *buf++ = hexchars[ch >> 4];
483 *buf++ = hexchars[ch % 16];
484 }
485 *buf = 0;
89709d42 486 mem_may_fault = 0;
72dd16ea
ILT
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
493static char *
494hex2mem (buf, mem, count, may_fault)
495 char *buf;
a49666fe 496 void *mem;
72dd16ea
ILT
497 int count;
498 int may_fault;
499{
500 int i;
501 unsigned char ch;
a49666fe 502 char *ptr = mem;
72dd16ea 503
89709d42 504 mem_may_fault = may_fault;
72dd16ea
ILT
505 for (i=0;i<count;i++)
506 {
507 ch = hex(*buf++) << 4;
508 ch = ch + hex(*buf++);
a49666fe 509 set_char (ptr++, ch);
72dd16ea 510 if (may_fault && mem_err)
a49666fe 511 return (ptr);
72dd16ea 512 }
89709d42 513 mem_may_fault = 0;
72dd16ea
ILT
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
520static int
521computeSignal (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/**********************************************/
552static int
553hexToInt(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
2e6784a8
SG
579static void
580set_step_traps (frame)
581 struct StackFrame *frame;
582{
583 frame->ExceptionSystemFlags |= 0x100;
584}
585
586static void
587clear_step_traps (frame)
588 struct StackFrame *frame;
589{
590 frame->ExceptionSystemFlags &= ~0x100;
591}
592
a49666fe
SG
593static void
594do_status (ptr, frame)
595 char *ptr;
2e6784a8 596 struct StackFrame *frame;
a49666fe
SG
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);
2e6784a8 606 ptr = mem2hex (&frame->ExceptionPC, ptr + 3, 4, 0);
a49666fe
SG
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
72dd16ea
ILT
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
624static LONG
a49666fe 625handle_exception (frame)
2e6784a8 626 struct StackFrame *frame;
72dd16ea 627{
72dd16ea 628 int addr, length;
a49666fe
SG
629 char *ptr;
630 static struct DBG_LoadDefinitionStructure *ldinfo = 0;
2e6784a8 631 static unsigned char first_insn[BREAKPOINT_SIZE]; /* The first instruction in the program. */
72dd16ea
ILT
632
633 /* Apparently the bell can sometimes be ringing at this point, and
634 should be stopped. */
635 StopBell ();
636
637 if (remote_debug)
638 {
d0e2b767 639 ConsolePrintf ("vector=%d: %s, sr=%08x, pc=%08x, thread=%08x\r\n",
72dd16ea
ILT
640 frame->ExceptionNumber,
641 frame->ExceptionDescription,
642 frame->ExceptionSystemFlags,
2e6784a8 643 frame->ExceptionPC,
72dd16ea
ILT
644 GetThreadID ());
645 }
646
a49666fe 647 switch (frame->ExceptionNumber)
72dd16ea 648 {
a49666fe
SG
649 case START_NLM_EVENT:
650 /* If the NLM just started, we record the module load information
651 and the thread ID, and set a breakpoint at the first instruction
652 in the program. */
d0e2b767 653
a49666fe
SG
654 ldinfo = ((struct DBG_LoadDefinitionStructure *)
655 frame->ExceptionErrorCode);
2e6784a8
SG
656 memcpy (first_insn, ldinfo->LDInitializationProcedure,
657 BREAKPOINT_SIZE);
658 memcpy (ldinfo->LDInitializationProcedure, breakpoint_insn,
659 BREAKPOINT_SIZE);
a49666fe 660 flush_i_cache ();
72dd16ea 661 return RETURN_TO_PROGRAM;
72dd16ea 662
a49666fe
SG
663 case ENTER_DEBUGGER_EVENT:
664 case KEYBOARD_BREAK_EVENT:
665 /* Pass some events on to the next debugger, in case it will handle
666 them. */
667 return RETURN_TO_NEXT_DEBUGGER;
89709d42 668
a49666fe
SG
669 case 3: /* Breakpoint */
670 /* After we've reached the initial breakpoint, reset it. */
2e6784a8
SG
671 if (frame->ExceptionPC - DECR_PC_AFTER_BREAK == (LONG) ldinfo->LDInitializationProcedure
672 && memcmp (ldinfo->LDInitializationProcedure, breakpoint_insn,
673 BREAKPOINT_SIZE) == 0)
a49666fe 674 {
2e6784a8
SG
675 memcpy (ldinfo->LDInitializationProcedure, first_insn,
676 BREAKPOINT_SIZE);
677 frame->ExceptionPC -= DECR_PC_AFTER_BREAK;
a49666fe
SG
678 flush_i_cache ();
679 }
680 /* Normal breakpoints end up here */
681 do_status (remcomOutBuffer, frame);
682 break;
d6a99838 683
a49666fe
SG
684 default:
685 /* At the moment, we don't care about most of the unusual NetWare
686 exceptions. */
687 if (frame->ExceptionNumber > 31)
688 return RETURN_TO_PROGRAM;
689
690 /* Most machine level exceptions end up here */
691 do_status (remcomOutBuffer, frame);
692 break;
693
694 case 11: /* Segment not present */
695 case 13: /* General protection */
696 case 14: /* Page fault */
697 /* If we get a GP fault, and mem_may_fault is set, and the
698 instruction pointer is near set_char or get_char, then we caused
699 the fault ourselves accessing an illegal memory location. */
700 if (mem_may_fault
2e6784a8
SG
701 && ((frame->ExceptionPC >= (long) &set_char
702 && frame->ExceptionPC < (long) &set_char + 50)
703 || (frame->ExceptionPC >= (long) &get_char
704 && frame->ExceptionPC < (long) &get_char + 50)))
a49666fe
SG
705 {
706 mem_err = 1;
707 /* Point the instruction pointer at an assembly language stub
708 which just returns from the function. */
709
2e6784a8 710 frame->ExceptionPC = (long) &just_return;
a49666fe
SG
711
712 /* Keep going. This will act as though it returned from
713 set_char or get_char. The calling routine will check
714 mem_err, and do the right thing. */
715 return RETURN_TO_PROGRAM;
716 }
717 /* Random mem fault, report it */
718 do_status (remcomOutBuffer, frame);
719 break;
720
721 case TERMINATE_NLM_EVENT:
722 /* There is no way to get the exit status. */
723 sprintf (remcomOutBuffer, "W%02x", 0);
724 break; /* We generate our own status */
72dd16ea
ILT
725 }
726
727 /* FIXME: How do we know that this exception has anything to do with
728 the program we are debugging? We can check whether the PC is in
729 the range of the module we are debugging, but that doesn't help
730 much since an error could occur in a library routine. */
731
2e6784a8
SG
732 clear_step_traps (frame);
733
72dd16ea
ILT
734 if (! putpacket(remcomOutBuffer))
735 return RETURN_TO_NEXT_DEBUGGER;
736
737 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
738 {
739 ResumeThread (mainthread);
740 return RETURN_TO_PROGRAM;
741 }
742
743 while (1)
744 {
745 error = 0;
746 remcomOutBuffer[0] = 0;
747 if (! getpacket (remcomInBuffer))
748 return RETURN_TO_NEXT_DEBUGGER;
72dd16ea
ILT
749 switch (remcomInBuffer[0])
750 {
751 case '?':
a49666fe 752 do_status (remcomOutBuffer, frame);
72dd16ea
ILT
753 break;
754 case 'd':
755 remote_debug = !(remote_debug); /* toggle debug flag */
756 break;
757 case 'g':
758 /* return the value of the CPU registers */
a49666fe 759 frame_to_registers (frame, remcomOutBuffer);
72dd16ea
ILT
760 break;
761 case 'G':
762 /* set the value of the CPU registers - return OK */
a49666fe 763 registers_to_frame (&remcomInBuffer[1], frame);
72dd16ea
ILT
764 strcpy(remcomOutBuffer,"OK");
765 break;
766
767 case 'm':
768 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
769 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
770 ptr = &remcomInBuffer[1];
771 if (hexToInt(&ptr,&addr))
772 if (*(ptr++) == ',')
773 if (hexToInt(&ptr,&length))
774 {
775 ptr = 0;
776 mem_err = 0;
777 mem2hex((char*) addr, remcomOutBuffer, length, 1);
778 if (mem_err)
779 {
780 strcpy (remcomOutBuffer, "E03");
781 debug_error ("memory fault");
782 }
783 }
784
785 if (ptr)
786 {
787 strcpy(remcomOutBuffer,"E01");
788 debug_error("malformed read memory command: %s",remcomInBuffer);
789 }
790 break;
791
792 case 'M':
793 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
794 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
795 ptr = &remcomInBuffer[1];
796 if (hexToInt(&ptr,&addr))
797 if (*(ptr++) == ',')
798 if (hexToInt(&ptr,&length))
799 if (*(ptr++) == ':')
800 {
801 mem_err = 0;
802 hex2mem(ptr, (char*) addr, length, 1);
803
804 if (mem_err)
805 {
806 strcpy (remcomOutBuffer, "E03");
807 debug_error ("memory fault");
808 }
809 else
810 {
811 strcpy(remcomOutBuffer,"OK");
812 }
813
814 ptr = 0;
815 }
816 if (ptr)
817 {
818 strcpy(remcomOutBuffer,"E02");
819 debug_error("malformed write memory command: %s",remcomInBuffer);
820 }
821 break;
822
823 case 'c':
824 case 's':
825 /* cAA..AA Continue at address AA..AA(optional) */
826 /* sAA..AA Step one instruction from AA..AA(optional) */
827 /* try to read optional parameter, pc unchanged if no parm */
828 ptr = &remcomInBuffer[1];
829 if (hexToInt(&ptr,&addr))
a49666fe
SG
830 {
831/* registers[PC_REGNUM].lo = addr;*/
832 fprintf (stderr, "Setting PC to 0x%x\n", addr);
833 while (1);
834 }
72dd16ea 835
a49666fe 836 if (remcomInBuffer[0] == 's')
2e6784a8 837 set_step_traps (frame);
72dd16ea 838
a49666fe 839 flush_i_cache ();
72dd16ea
ILT
840 return RETURN_TO_PROGRAM;
841
842 case 'k':
843 /* kill the program */
a49666fe 844 KillMe (ldinfo);
72dd16ea
ILT
845 ResumeThread (mainthread);
846 return RETURN_TO_PROGRAM;
68ba2fa5
SG
847
848 case 'q': /* Query message */
849 if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
850 {
851 sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
a49666fe
SG
852 ldinfo->LDCodeImageOffset,
853 ldinfo->LDDataImageOffset,
854 ldinfo->LDDataImageOffset + ldinfo->LDDataImageLength);
68ba2fa5
SG
855 }
856 else
857 sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
858 break;
72dd16ea
ILT
859 }
860
861 /* reply to the request */
862 if (! putpacket(remcomOutBuffer))
863 return RETURN_TO_NEXT_DEBUGGER;
864 }
865}
866
d0e2b767
SG
867char *baudRates[] = { "50", "75", "110", "134.5", "150", "300", "600", "1200",
868 "1800", "2000", "2400", "3600", "4800", "7200", "9600",
869 "19200", "38400", "57600", "115200" };
870
871char dataBits[] = "5678";
872
873char *stopBits[] = { "1", "1.5", "2" };
874
875char parity[] = "NOEMS";
876
72dd16ea
ILT
877/* Start up. The main thread opens the named serial I/O port, loads
878 the named NLM module and then goes to sleep. The serial I/O port
879 is named as a board number and a port number. It would be more DOS
880 like to provide a menu of available serial ports, but I don't want
881 to have to figure out how to do that. */
882
883int
884main (argc, argv)
885 int argc;
886 char **argv;
887{
888 int hardware, board, port;
889 LONG err;
890 struct debuggerStructure s;
891 char *cmdlin;
892 int i;
893
d0e2b767
SG
894/* Use the -B option to invoke the NID if you want to debug the stub. */
895
896 if (argc > 1 && strcmp(argv[1], "-B") == 0)
897 {
898 Breakpoint(argc);
899 ++argv, --argc;
900 }
72dd16ea
ILT
901
902 if (argc < 4)
903 {
0bbe764a 904 fprintf (stderr,
d0e2b767 905 "Usage: load gdbserve board port program [arguments]\n");
72dd16ea
ILT
906 exit (1);
907 }
908
909 hardware = -1;
910 board = strtol (argv[1], (char **) NULL, 0);
911 port = strtol (argv[2], (char **) NULL, 0);
912
913 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
914 if (err != AIO_SUCCESS)
915 {
916 switch (err)
917 {
918 case AIO_PORT_NOT_AVAILABLE:
0bbe764a 919 fprintf (stderr, "Port not available\n");
72dd16ea
ILT
920 break;
921
922 case AIO_BOARD_NUMBER_INVALID:
923 case AIO_PORT_NUMBER_INVALID:
0bbe764a 924 fprintf (stderr, "No such port\n");
72dd16ea
ILT
925 break;
926
927 default:
0bbe764a 928 fprintf (stderr, "Could not open port: %d\n", err);
72dd16ea
ILT
929 break;
930 }
931
932 exit (1);
933 }
934
935 err = AIOConfigurePort (AIOhandle, AIO_BAUD_9600, AIO_DATA_BITS_8,
936 AIO_STOP_BITS_1, AIO_PARITY_NONE,
937 AIO_HARDWARE_FLOW_CONTROL_OFF);
d0e2b767
SG
938
939 if (err == AIO_QUALIFIED_SUCCESS)
940 {
941 AIOPORTCONFIG portConfig;
942 AIODVRCONFIG dvrConfig;
943
944 fprintf (stderr, "Port configuration changed!\n");
945 AIOGetPortConfiguration (AIOhandle, &portConfig, &dvrConfig);
946 fprintf (stderr,
947 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
948 Flow:%s\n",
949 baudRates[portConfig.bitRate],
950 dataBits[portConfig.dataBits],
951 stopBits[portConfig.stopBits],
952 parity[portConfig.parityMode],
953 portConfig.flowCtrlMode ? "ON" : "OFF");
954 }
955 else if (err != AIO_SUCCESS)
72dd16ea 956 {
0bbe764a 957 fprintf (stderr, "Could not configure port: %d\n", err);
72dd16ea
ILT
958 AIOReleasePort (AIOhandle);
959 exit (1);
960 }
961
d0e2b767
SG
962 if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
963 (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
964 != AIO_SUCCESS)
965 {
966 LONG extStatus, chgdExtStatus;
967
968 fprintf (stderr, "Could not set desired port controls!\n");
969 AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
970 fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
971 chgdExtStatus);
972 }
973
72dd16ea
ILT
974 /* Register ourselves as an alternate debugger. */
975 memset (&s, 0, sizeof s);
976 s.DDSResourceTag = ((struct ResourceTagStructure *)
977 AllocateResourceTag (GetNLMHandle (),
a49666fe 978 (BYTE *)"gdbserver",
72dd16ea
ILT
979 DebuggerSignature));
980 if (s.DDSResourceTag == 0)
981 {
0bbe764a 982 fprintf (stderr, "AllocateResourceTag failed\n");
72dd16ea
ILT
983 AIOReleasePort (AIOhandle);
984 exit (1);
985 }
986 s.DDSdebuggerEntry = handle_exception;
987 s.DDSFlags = TSS_FRAME_BIT;
988
989 err = RegisterDebuggerRTag (&s, AT_FIRST);
990 if (err != 0)
991 {
0bbe764a 992 fprintf (stderr, "RegisterDebuggerRTag failed\n");
72dd16ea
ILT
993 AIOReleasePort (AIOhandle);
994 exit (1);
995 }
996
997 /* Get the command line we were invoked with, and advance it past
998 our name and the board and port arguments. */
999 cmdlin = getcmd ((char *) NULL);
1000 for (i = 0; i < 2; i++)
1001 {
1002 while (! isspace (*cmdlin))
1003 ++cmdlin;
1004 while (isspace (*cmdlin))
1005 ++cmdlin;
1006 }
1007
1008 /* In case GDB is started before us, ack any packets (presumably
1009 "$?#xx") sitting there. */
1010 if (! putDebugChar ('+'))
1011 {
0bbe764a 1012 fprintf (stderr, "putDebugChar failed\n");
72dd16ea
ILT
1013 UnRegisterDebugger (&s);
1014 AIOReleasePort (AIOhandle);
1015 exit (1);
1016 }
1017
1018 mainthread = GetThreadID ();
72dd16ea
ILT
1019
1020 if (remote_debug > 0)
d0e2b767
SG
1021 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
1022 cmdlin, __GetScreenID (GetCurrentScreen()));
72dd16ea
ILT
1023
1024 /* Start up the module to be debugged. */
d0e2b767 1025 err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
a49666fe 1026 (BYTE *)cmdlin, LO_DEBUG);
72dd16ea
ILT
1027 if (err != 0)
1028 {
0bbe764a 1029 fprintf (stderr, "LoadModule failed: %d\n", err);
72dd16ea
ILT
1030 UnRegisterDebugger (&s);
1031 AIOReleasePort (AIOhandle);
1032 exit (1);
1033 }
1034
d6a99838 1035 /* Wait for the debugger to wake us up. */
72dd16ea 1036 if (remote_debug > 0)
d0e2b767 1037 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
72dd16ea 1038 SuspendThread (mainthread);
d6a99838 1039 if (remote_debug > 0)
d0e2b767 1040 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
72dd16ea
ILT
1041
1042 /* If we are woken up, print an optional error message, deregister
1043 ourselves and exit. */
1044 if (error_message != NULL)
0bbe764a 1045 fprintf (stderr, "%s\n", error_message);
72dd16ea
ILT
1046 UnRegisterDebugger (&s);
1047 AIOReleasePort (AIOhandle);
1048 exit (0);
1049}
This page took 0.117999 seconds and 4 git commands to generate.