* i386-nlmstub.c: More changes to be compatible with remote.c.
[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 127/* The LoadDefinitionStructure of the NLM being debugged. */
ef0faeb6 128static struct DBG_LoadDefinitionStructure *handle;
72dd16ea
ILT
129
130/* Whether we have connected to gdb. */
131static int talking;
132
133/* The actual first instruction in the program. */
134static unsigned char first_insn;
135
136/* An error message for the main thread to print. */
137static char *error_message;
138
139/* The AIO port handle. */
140static int AIOhandle;
141
72dd16ea
ILT
142/* BUFMAX defines the maximum number of characters in inbound/outbound
143 buffers. At least NUMREGBYTES*2 are needed for register packets */
144#define BUFMAX 400
145
146/* remote_debug > 0 prints ill-formed commands in valid packets and
147 checksum errors. */
148static int remote_debug = 1;
149
150static const char hexchars[] = "0123456789abcdef";
151
152/* Number of bytes of registers. */
153#define NUMREGBYTES 64
154enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
155 PC /* also known as eip */,
156 PS /* also known as eflags */,
157 CS, SS, DS, ES, FS, GS};
158
159/* Register values. */
160static int registers[NUMREGBYTES/4];
161
d0e2b767
SG
162__main() {};
163
72dd16ea
ILT
164/* Read a character from the serial port. This must busy wait, but
165 that's OK because we will be the only thread running anyhow. */
166
167static int
168getDebugChar ()
169{
170 int err;
171 LONG got;
172 unsigned char ret;
173
174 do
175 {
176 err = AIOReadData (AIOhandle, (char *) &ret, 1, &got);
177 if (err != 0)
178 {
179 error_message = "AIOReadData failed";
180 ResumeThread (mainthread);
181 return -1;
182 }
183 }
184 while (got == 0);
185
186 return ret;
187}
188
189/* Write a character to the serial port. Returns 0 on failure,
190 non-zero on success. */
191
192static int
193putDebugChar (c)
194 unsigned char c;
195{
196 int err;
197 LONG put;
198
d0e2b767
SG
199 put = 0;
200 while (put < 1)
72dd16ea 201 {
d0e2b767
SG
202 err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
203 if (err != 0)
204 ConsolePrintf ("AIOWriteData: err = %d, put = %d\r\n", err, put);
72dd16ea
ILT
205 }
206 return 1;
207}
208
209/* Get the registers out of the frame information. */
210
211static void
212frame_to_registers (frame, regs)
213 T_TSS_StackFrame *frame;
214 int *regs;
215{
216 regs[EAX] = frame->ExceptionEAX;
217 regs[ECX] = frame->ExceptionECX;
218 regs[EDX] = frame->ExceptionEDX;
219 regs[EBX] = frame->ExceptionEBX;
220 regs[ESP] = frame->ExceptionESP;
221 regs[EBP] = frame->ExceptionEBP;
222 regs[ESI] = frame->ExceptionESI;
223 regs[EDI] = frame->ExceptionEDI;
224 regs[PC] = frame->ExceptionEIP;
225 regs[PS] = frame->ExceptionSystemFlags;
226 regs[CS] = frame->ExceptionCS[0];
227 regs[SS] = frame->ExceptionSS[0];
228 regs[DS] = frame->ExceptionDS[0];
229 regs[ES] = frame->ExceptionES[0];
230 regs[FS] = frame->ExceptionFS[0];
231 regs[GS] = frame->ExceptionGS[0];
232}
233
234/* Put the registers back into the frame information. */
235
236static void
237registers_to_frame (regs, frame)
238 int *regs;
239 T_TSS_StackFrame *frame;
240{
241 frame->ExceptionEAX = regs[EAX];
242 frame->ExceptionECX = regs[ECX];
243 frame->ExceptionEDX = regs[EDX];
244 frame->ExceptionEBX = regs[EBX];
245 frame->ExceptionESP = regs[ESP];
246 frame->ExceptionEBP = regs[EBP];
247 frame->ExceptionESI = regs[ESI];
248 frame->ExceptionEDI = regs[EDI];
249 frame->ExceptionEIP = regs[PC];
250 frame->ExceptionSystemFlags = regs[PS];
251 frame->ExceptionCS[0] = regs[CS];
252 frame->ExceptionSS[0] = regs[SS];
253 frame->ExceptionDS[0] = regs[DS];
254 frame->ExceptionES[0] = regs[ES];
255 frame->ExceptionFS[0] = regs[FS];
256 frame->ExceptionGS[0] = regs[GS];
257}
258
259/* Turn a hex character into a number. */
260
261static int
262hex (ch)
263 char ch;
264{
265 if ((ch >= 'a') && (ch <= 'f'))
266 return (ch-'a'+10);
267 if ((ch >= '0') && (ch <= '9'))
268 return (ch-'0');
269 if ((ch >= 'A') && (ch <= 'F'))
270 return (ch-'A'+10);
271 return (-1);
272}
273
274/* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
275 non-zero on success. */
276
277static int
278getpacket (buffer)
279 char * buffer;
280{
281 unsigned char checksum;
282 unsigned char xmitcsum;
283 int i;
284 int count;
285 int ch;
286
287 do
288 {
289 /* wait around for the start character, ignore all other characters */
290 while ((ch = getDebugChar()) != '$')
291 if (ch == -1)
292 return 0;
293 checksum = 0;
294 xmitcsum = -1;
295
296 count = 0;
297
298 /* now, read until a # or end of buffer is found */
299 while (count < BUFMAX)
300 {
301 ch = getDebugChar();
302 if (ch == -1)
303 return 0;
304 if (ch == '#')
305 break;
306 checksum = checksum + ch;
307 buffer[count] = ch;
308 count = count + 1;
309 }
310 buffer[count] = 0;
311
312 if (ch == '#')
313 {
314 ch = getDebugChar ();
315 if (ch == -1)
316 return 0;
317 xmitcsum = hex(ch) << 4;
318 ch = getDebugChar ();
319 if (ch == -1)
320 return 0;
321 xmitcsum += hex(ch);
322 if ((remote_debug ) && (checksum != xmitcsum))
323 {
0bbe764a 324 fprintf(stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
72dd16ea
ILT
325 checksum,xmitcsum,buffer);
326 }
327
328 if (checksum != xmitcsum)
329 {
330 /* failed checksum */
331 if (! putDebugChar('-'))
332 return 0;
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 {
0bbe764a
SG
416 fprintf (stderr, format, parm);
417 fprintf (stderr, "\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)
467 char *mem;
468 char *buf;
469 int count;
470 int may_fault;
471{
472 int i;
473 unsigned char ch;
474
89709d42 475 mem_may_fault = may_fault;
72dd16ea
ILT
476 for (i = 0; i < count; i++)
477 {
478 ch = get_char (mem++);
479 if (may_fault && mem_err)
480 return (buf);
481 *buf++ = hexchars[ch >> 4];
482 *buf++ = hexchars[ch % 16];
483 }
484 *buf = 0;
89709d42 485 mem_may_fault = 0;
72dd16ea
ILT
486 return(buf);
487}
488
489/* convert the hex array pointed to by buf into binary to be placed in mem */
490/* return a pointer to the character AFTER the last byte written */
491
492static char *
493hex2mem (buf, mem, count, may_fault)
494 char *buf;
495 char *mem;
496 int count;
497 int may_fault;
498{
499 int i;
500 unsigned char ch;
501
89709d42 502 mem_may_fault = may_fault;
72dd16ea
ILT
503 for (i=0;i<count;i++)
504 {
505 ch = hex(*buf++) << 4;
506 ch = ch + hex(*buf++);
507 set_char (mem++, ch);
508 if (may_fault && mem_err)
509 return (mem);
510 }
89709d42 511 mem_may_fault = 0;
72dd16ea
ILT
512 return(mem);
513}
514
515/* This function takes the 386 exception vector and attempts to
516 translate this number into a unix compatible signal value. */
517
518static int
519computeSignal (exceptionVector)
520 int exceptionVector;
521{
522 int sigval;
523 switch (exceptionVector)
524 {
525 case 0 : sigval = 8; break; /* divide by zero */
526 case 1 : sigval = 5; break; /* debug exception */
527 case 3 : sigval = 5; break; /* breakpoint */
528 case 4 : sigval = 16; break; /* into instruction (overflow) */
529 case 5 : sigval = 16; break; /* bound instruction */
530 case 6 : sigval = 4; break; /* Invalid opcode */
531 case 7 : sigval = 8; break; /* coprocessor not available */
532 case 8 : sigval = 7; break; /* double fault */
533 case 9 : sigval = 11; break; /* coprocessor segment overrun */
534 case 10 : sigval = 11; break; /* Invalid TSS */
535 case 11 : sigval = 11; break; /* Segment not present */
536 case 12 : sigval = 11; break; /* stack exception */
537 case 13 : sigval = 11; break; /* general protection */
538 case 14 : sigval = 11; break; /* page fault */
539 case 16 : sigval = 7; break; /* coprocessor error */
540 default:
541 sigval = 7; /* "software generated"*/
542 }
543 return (sigval);
544}
545
546/**********************************************/
547/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
548/* RETURN NUMBER OF CHARS PROCESSED */
549/**********************************************/
550static int
551hexToInt(ptr, intValue)
552 char **ptr;
553 int *intValue;
554{
555 int numChars = 0;
556 int hexValue;
557
558 *intValue = 0;
559
560 while (**ptr)
561 {
562 hexValue = hex(**ptr);
563 if (hexValue >=0)
564 {
565 *intValue = (*intValue <<4) | hexValue;
566 numChars ++;
567 }
568 else
569 break;
570
571 (*ptr)++;
572 }
573
574 return (numChars);
575}
576
577/* This function does all command processing for interfacing to gdb.
578 It is called whenever an exception occurs in the module being
579 debugged. */
580
581static LONG
582handle_exception (T_StackFrame *old_frame)
583{
584 T_TSS_StackFrame *frame = (T_TSS_StackFrame *) old_frame;
72dd16ea
ILT
585 int sigval;
586 int addr, length;
587 char * ptr;
588 int newPC;
589
590 /* Apparently the bell can sometimes be ringing at this point, and
591 should be stopped. */
592 StopBell ();
593
594 if (remote_debug)
595 {
d0e2b767 596 ConsolePrintf ("vector=%d: %s, sr=%08x, pc=%08x, thread=%08x\r\n",
72dd16ea
ILT
597 frame->ExceptionNumber,
598 frame->ExceptionDescription,
599 frame->ExceptionSystemFlags,
600 frame->ExceptionEIP,
601 GetThreadID ());
602 }
603
604 /* If the NLM just started, we record the module load information
605 and the thread ID, and set a breakpoint at the first instruction
606 in the program. */
607 if (frame->ExceptionNumber == START_NLM_EVENT
608 && handle == NULL)
609 {
ef0faeb6
ILT
610 handle = ((struct DBG_LoadDefinitionStructure *)
611 frame->ExceptionErrorCode);
72dd16ea
ILT
612 first_insn = *(char *) handle->LDInitializationProcedure;
613 *(unsigned char *) handle->LDInitializationProcedure = 0xcc;
d0e2b767
SG
614 ConsolePrintf ("NLM offsets/lengths: Code: 0x%x/0x%x, Data: 0x%x/0x%x, BSS: /0x%x\r\n",
615 handle->LDCodeImageOffset, handle->LDCodeImageLength,
616 handle->LDDataImageOffset, handle->LDDataImageLength,
617 handle->LDUninitializedDataLength);
618
72dd16ea
ILT
619 return RETURN_TO_PROGRAM;
620 }
621
89709d42
ILT
622 /* After we've reached the initial breakpoint, reset it. */
623 if (frame->ExceptionEIP == (LONG) handle->LDInitializationProcedure + 1
624 && *(unsigned char *) handle->LDInitializationProcedure == 0xcc)
625 {
626 *(char *) handle->LDInitializationProcedure = first_insn;
627 frame->ExceptionEIP = (LONG) handle->LDInitializationProcedure;
628 }
629
d6a99838
ILT
630 /* Pass some events on to the next debugger, in case it will handle
631 them. */
632 if (frame->ExceptionNumber == ENTER_DEBUGGER_EVENT
633 || frame->ExceptionNumber == KEYBOARD_BREAK_EVENT)
634 return RETURN_TO_NEXT_DEBUGGER;
635
72dd16ea
ILT
636 /* At the moment, we don't care about most of the unusual NetWare
637 exceptions. */
638 if (frame->ExceptionNumber != TERMINATE_NLM_EVENT
639 && frame->ExceptionNumber > 31)
640 return RETURN_TO_PROGRAM;
641
89709d42
ILT
642 /* If we get a GP fault, and mem_may_fault is set, and the
643 instruction pointer is near set_char or get_char, then we caused
644 the fault ourselves accessing an illegal memory location. */
645 if (mem_may_fault
646 && (frame->ExceptionNumber == 11
647 || frame->ExceptionNumber == 13
648 || frame->ExceptionNumber == 14)
649 && ((frame->ExceptionEIP >= (long) &set_char
650 && frame->ExceptionEIP < (long) &set_char + 50)
651 || (frame->ExceptionEIP >= (long) &get_char
652 && frame->ExceptionEIP < (long) &get_char + 50)))
72dd16ea 653 {
89709d42
ILT
654 mem_err = 1;
655 /* Point the instruction pointer at an assembly language stub
656 which just returns from the function. */
657 frame->ExceptionEIP = (long) &just_return;
658 /* Keep going. This will act as though it returned from
659 set_char or get_char. The calling routine will check
660 mem_err, and do the right thing. */
661 return RETURN_TO_PROGRAM;
72dd16ea
ILT
662 }
663
664 /* FIXME: How do we know that this exception has anything to do with
665 the program we are debugging? We can check whether the PC is in
666 the range of the module we are debugging, but that doesn't help
667 much since an error could occur in a library routine. */
668
669 frame_to_registers (frame, registers);
670
671 /* reply to host that an exception has occurred */
672 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
673 {
674 /* There is no way to get the exit status. */
675 remcomOutBuffer[0] = 'W';
676 remcomOutBuffer[1] = hexchars[0];
677 remcomOutBuffer[2] = hexchars[0];
678 remcomOutBuffer[3] = 0;
679 }
680 else
681 {
682 sigval = computeSignal (frame->ExceptionNumber);
68ba2fa5 683 remcomOutBuffer[0] = 'S';
72dd16ea
ILT
684 remcomOutBuffer[1] = hexchars[sigval >> 4];
685 remcomOutBuffer[2] = hexchars[sigval % 16];
68ba2fa5 686 remcomOutBuffer[3] = 0;
72dd16ea
ILT
687 }
688
689 if (! putpacket(remcomOutBuffer))
690 return RETURN_TO_NEXT_DEBUGGER;
691
692 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
693 {
694 ResumeThread (mainthread);
695 return RETURN_TO_PROGRAM;
696 }
697
698 while (1)
699 {
700 error = 0;
701 remcomOutBuffer[0] = 0;
702 if (! getpacket (remcomInBuffer))
703 return RETURN_TO_NEXT_DEBUGGER;
704 talking = 1;
705 switch (remcomInBuffer[0])
706 {
707 case '?':
708 sigval = computeSignal (frame->ExceptionNumber);
68ba2fa5 709 remcomOutBuffer[0] = 'S';
72dd16ea
ILT
710 remcomOutBuffer[1] = hexchars[sigval >> 4];
711 remcomOutBuffer[2] = hexchars[sigval % 16];
68ba2fa5 712 remcomOutBuffer[3] = 0;
72dd16ea
ILT
713 break;
714 case 'd':
715 remote_debug = !(remote_debug); /* toggle debug flag */
716 break;
717 case 'g':
718 /* return the value of the CPU registers */
719 mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES, 0);
720 break;
721 case 'G':
722 /* set the value of the CPU registers - return OK */
723 hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0);
724 strcpy(remcomOutBuffer,"OK");
725 break;
726
727 case 'm':
728 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
729 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
730 ptr = &remcomInBuffer[1];
731 if (hexToInt(&ptr,&addr))
732 if (*(ptr++) == ',')
733 if (hexToInt(&ptr,&length))
734 {
735 ptr = 0;
736 mem_err = 0;
737 mem2hex((char*) addr, remcomOutBuffer, length, 1);
738 if (mem_err)
739 {
740 strcpy (remcomOutBuffer, "E03");
741 debug_error ("memory fault");
742 }
743 }
744
745 if (ptr)
746 {
747 strcpy(remcomOutBuffer,"E01");
748 debug_error("malformed read memory command: %s",remcomInBuffer);
749 }
750 break;
751
752 case 'M':
753 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
754 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
755 ptr = &remcomInBuffer[1];
756 if (hexToInt(&ptr,&addr))
757 if (*(ptr++) == ',')
758 if (hexToInt(&ptr,&length))
759 if (*(ptr++) == ':')
760 {
761 mem_err = 0;
762 hex2mem(ptr, (char*) addr, length, 1);
763
764 if (mem_err)
765 {
766 strcpy (remcomOutBuffer, "E03");
767 debug_error ("memory fault");
768 }
769 else
770 {
771 strcpy(remcomOutBuffer,"OK");
772 }
773
774 ptr = 0;
775 }
776 if (ptr)
777 {
778 strcpy(remcomOutBuffer,"E02");
779 debug_error("malformed write memory command: %s",remcomInBuffer);
780 }
781 break;
782
783 case 'c':
784 case 's':
785 /* cAA..AA Continue at address AA..AA(optional) */
786 /* sAA..AA Step one instruction from AA..AA(optional) */
787 /* try to read optional parameter, pc unchanged if no parm */
788 ptr = &remcomInBuffer[1];
789 if (hexToInt(&ptr,&addr))
790 registers[ PC ] = addr;
791
792 newPC = registers[ PC];
793
794 /* clear the trace bit */
795 registers[ PS ] &= 0xfffffeff;
796
797 /* set the trace bit if we're stepping */
798 if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100;
799
800 registers_to_frame (registers, frame);
801 return RETURN_TO_PROGRAM;
802
803 case 'k':
804 /* kill the program */
805 KillMe (handle);
806 ResumeThread (mainthread);
807 return RETURN_TO_PROGRAM;
68ba2fa5
SG
808
809 case 'q': /* Query message */
810 if (strcmp (&remcomInBuffer[1], "Offsets") == 0)
811 {
812 sprintf (remcomOutBuffer, "Text=%x;Data=%x;Bss=%x",
813 handle->LDCodeImageOffset,
814 handle->LDDataImageOffset,
815 handle->LDDataImageOffset + handle->LDDataImageLength);
816 }
817 else
818 sprintf (remcomOutBuffer, "E04, Unknown query %s", &remcomInBuffer[1]);
819 break;
72dd16ea
ILT
820 }
821
822 /* reply to the request */
823 if (! putpacket(remcomOutBuffer))
824 return RETURN_TO_NEXT_DEBUGGER;
825 }
826}
827
d0e2b767
SG
828char *baudRates[] = { "50", "75", "110", "134.5", "150", "300", "600", "1200",
829 "1800", "2000", "2400", "3600", "4800", "7200", "9600",
830 "19200", "38400", "57600", "115200" };
831
832char dataBits[] = "5678";
833
834char *stopBits[] = { "1", "1.5", "2" };
835
836char parity[] = "NOEMS";
837
72dd16ea
ILT
838/* Start up. The main thread opens the named serial I/O port, loads
839 the named NLM module and then goes to sleep. The serial I/O port
840 is named as a board number and a port number. It would be more DOS
841 like to provide a menu of available serial ports, but I don't want
842 to have to figure out how to do that. */
843
844int
845main (argc, argv)
846 int argc;
847 char **argv;
848{
849 int hardware, board, port;
850 LONG err;
851 struct debuggerStructure s;
852 char *cmdlin;
853 int i;
854
d0e2b767
SG
855/* Use the -B option to invoke the NID if you want to debug the stub. */
856
857 if (argc > 1 && strcmp(argv[1], "-B") == 0)
858 {
859 Breakpoint(argc);
860 ++argv, --argc;
861 }
72dd16ea
ILT
862
863 if (argc < 4)
864 {
0bbe764a 865 fprintf (stderr,
d0e2b767 866 "Usage: load gdbserve board port program [arguments]\n");
72dd16ea
ILT
867 exit (1);
868 }
869
870 hardware = -1;
871 board = strtol (argv[1], (char **) NULL, 0);
872 port = strtol (argv[2], (char **) NULL, 0);
873
874 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
875 if (err != AIO_SUCCESS)
876 {
877 switch (err)
878 {
879 case AIO_PORT_NOT_AVAILABLE:
0bbe764a 880 fprintf (stderr, "Port not available\n");
72dd16ea
ILT
881 break;
882
883 case AIO_BOARD_NUMBER_INVALID:
884 case AIO_PORT_NUMBER_INVALID:
0bbe764a 885 fprintf (stderr, "No such port\n");
72dd16ea
ILT
886 break;
887
888 default:
0bbe764a 889 fprintf (stderr, "Could not open port: %d\n", err);
72dd16ea
ILT
890 break;
891 }
892
893 exit (1);
894 }
895
896 err = AIOConfigurePort (AIOhandle, AIO_BAUD_9600, AIO_DATA_BITS_8,
897 AIO_STOP_BITS_1, AIO_PARITY_NONE,
898 AIO_HARDWARE_FLOW_CONTROL_OFF);
d0e2b767
SG
899
900 if (err == AIO_QUALIFIED_SUCCESS)
901 {
902 AIOPORTCONFIG portConfig;
903 AIODVRCONFIG dvrConfig;
904
905 fprintf (stderr, "Port configuration changed!\n");
906 AIOGetPortConfiguration (AIOhandle, &portConfig, &dvrConfig);
907 fprintf (stderr,
908 " Bit Rate: %s, Data Bits: %c, Stop Bits: %s, Parity: %c,\
909 Flow:%s\n",
910 baudRates[portConfig.bitRate],
911 dataBits[portConfig.dataBits],
912 stopBits[portConfig.stopBits],
913 parity[portConfig.parityMode],
914 portConfig.flowCtrlMode ? "ON" : "OFF");
915 }
916 else if (err != AIO_SUCCESS)
72dd16ea 917 {
0bbe764a 918 fprintf (stderr, "Could not configure port: %d\n", err);
72dd16ea
ILT
919 AIOReleasePort (AIOhandle);
920 exit (1);
921 }
922
d0e2b767
SG
923 if (AIOSetExternalControl(AIOhandle, AIO_EXTERNAL_CONTROL,
924 (AIO_EXTCTRL_DTR | AIO_EXTCTRL_RTS))
925 != AIO_SUCCESS)
926 {
927 LONG extStatus, chgdExtStatus;
928
929 fprintf (stderr, "Could not set desired port controls!\n");
930 AIOGetExternalStatus (AIOhandle, &extStatus, &chgdExtStatus);
931 fprintf (stderr, "Port controls now: %d, %d\n", extStatus,
932 chgdExtStatus);
933 }
934
72dd16ea
ILT
935 /* Register ourselves as an alternate debugger. */
936 memset (&s, 0, sizeof s);
937 s.DDSResourceTag = ((struct ResourceTagStructure *)
938 AllocateResourceTag (GetNLMHandle (),
939 "gdbserver",
940 DebuggerSignature));
941 if (s.DDSResourceTag == 0)
942 {
0bbe764a 943 fprintf (stderr, "AllocateResourceTag failed\n");
72dd16ea
ILT
944 AIOReleasePort (AIOhandle);
945 exit (1);
946 }
947 s.DDSdebuggerEntry = handle_exception;
948 s.DDSFlags = TSS_FRAME_BIT;
949
950 err = RegisterDebuggerRTag (&s, AT_FIRST);
951 if (err != 0)
952 {
0bbe764a 953 fprintf (stderr, "RegisterDebuggerRTag failed\n");
72dd16ea
ILT
954 AIOReleasePort (AIOhandle);
955 exit (1);
956 }
957
958 /* Get the command line we were invoked with, and advance it past
959 our name and the board and port arguments. */
960 cmdlin = getcmd ((char *) NULL);
961 for (i = 0; i < 2; i++)
962 {
963 while (! isspace (*cmdlin))
964 ++cmdlin;
965 while (isspace (*cmdlin))
966 ++cmdlin;
967 }
968
969 /* In case GDB is started before us, ack any packets (presumably
970 "$?#xx") sitting there. */
971 if (! putDebugChar ('+'))
972 {
0bbe764a 973 fprintf (stderr, "putDebugChar failed\n");
72dd16ea
ILT
974 UnRegisterDebugger (&s);
975 AIOReleasePort (AIOhandle);
976 exit (1);
977 }
978
979 mainthread = GetThreadID ();
980 handle = NULL;
981 talking = 0;
982
983 if (remote_debug > 0)
d0e2b767
SG
984 ConsolePrintf ("About to call LoadModule with \"%s\" %08x\r\n",
985 cmdlin, __GetScreenID (GetCurrentScreen()));
72dd16ea
ILT
986
987 /* Start up the module to be debugged. */
d0e2b767 988 err = LoadModule ((struct ScreenStruct *) __GetScreenID (GetCurrentScreen()),
72dd16ea
ILT
989 cmdlin, LO_DEBUG);
990 if (err != 0)
991 {
0bbe764a 992 fprintf (stderr, "LoadModule failed: %d\n", err);
72dd16ea
ILT
993 UnRegisterDebugger (&s);
994 AIOReleasePort (AIOhandle);
995 exit (1);
996 }
997
d6a99838 998 /* Wait for the debugger to wake us up. */
72dd16ea 999 if (remote_debug > 0)
d0e2b767 1000 ConsolePrintf ("Suspending main thread (%08x)\r\n", mainthread);
72dd16ea 1001 SuspendThread (mainthread);
d6a99838 1002 if (remote_debug > 0)
d0e2b767 1003 ConsolePrintf ("Resuming main thread (%08x)\r\n", mainthread);
72dd16ea
ILT
1004
1005 /* If we are woken up, print an optional error message, deregister
1006 ourselves and exit. */
1007 if (error_message != NULL)
0bbe764a 1008 fprintf (stderr, "%s\n", error_message);
72dd16ea
ILT
1009 UnRegisterDebugger (&s);
1010 AIOReleasePort (AIOhandle);
1011 exit (0);
1012}
This page took 0.096629 seconds and 4 git commands to generate.