Snapshot of stand alone i386 NLM debugging stub. Currently sanitized
[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
81 /************************************************************************/
82 /*****************************************************************************
83 *
84 * (C) Copyright 1988-1993 Novell, Inc.
85 * All Rights Reserved.
86 *
87 * This program is an unpublished copyrighted work which is proprietary
88 * to Novell, Inc. and contains confidential information that is not
89 * to be reproduced or disclosed to any other person or entity without
90 * prior written consent from Novell, Inc. in each and every instance.
91 *
92 * WARNING: Unauthorized reproduction of this program as well as
93 * unauthorized preparation of derivative works based upon the
94 * program or distribution of copies by sale, rental, lease or
95 * lending are violations of federal copyright laws and state trade
96 * secret laws, punishable by civil and criminal penalties.
97 *
98 * $release$
99 * $modname: loadstuff.h$
100 * $version: 1.37$
101 * $date: Fri, Jan 15, 1993$
102 *
103 ****************************************************************************/
104
105
106 /* WARNING: THIS IS NOT A COMPLETE OS HEADER FILE - DON'T GET CONFUSED
107 ***********************************************************************
108 * The information is this file is a subset of the OS LOADER.H.
109 * This file was created to reveal the LoadDefinitionStrucutre and some
110 * associated information to Cygnus Support to assist them in their
111 * efforts to develop GNU netware utilities. Don't confuse this file
112 * with LOADER.H or any other actually supported NetWare header.
113
114 ************************************************************************/
115
116 struct LoadDefinitionStructure
117 {
118 struct LoadDefinitionStructure *LDLink;
119 struct LoadDefinitionStructure *LDKillLink;
120 struct LoadDefinitionStructure *LDScanLink;
121 struct ResourceTagStructure *LDResourceList;
122 LONG LDIdentificationNumber;
123 LONG LDCodeImageOffset;
124 LONG LDCodeImageLength;
125 LONG LDDataImageOffset;
126 LONG LDDataImageLength;
127 LONG LDUninitializedDataLength;
128 LONG LDCustomDataOffset;
129 LONG LDCustomDataSize;
130 LONG LDFlags;
131 LONG LDType;
132 LONG (*LDInitializationProcedure)(
133 struct LoadDefinitionStructure *LoadRecord,
134 struct ScreenStruct *screenID,
135 BYTE *CommandLine,
136 BYTE *loadDirectoryPath,
137 LONG uninitializedDataLength,
138 LONG fileHandle,
139 LONG (*ReadRoutine)(
140 LONG fileHandle,
141 LONG offset,
142 void *buffer,
143 LONG numberOfBytes),
144 LONG customDataOffset,
145 LONG customDataSize);
146 void (*LDExitProcedure)(void);
147 LONG (*LDCheckUnloadProcedure)(
148 struct ScreenStruct *screenID);
149 struct ExternalPublicDefinitionStructure *LDPublics;
150 BYTE LDFileName[36];
151 BYTE LDName[128];
152 LONG *LDCLIBLoadStructure;
153 LONG *LDNLMDebugger;
154 LONG LDParentID;
155 LONG LDReservedForCLIB;
156 LONG Reserved0;
157 LONG Reserved1;
158 void *LDModuleObjectHandle; /* If Instrumented BEW 10/16/90 */
159 LONG LDMajorVersion;
160 LONG LDMinorVersion;
161 LONG LDRevision;
162 LONG LDYear;
163 LONG LDMonth;
164 LONG LDDay;
165 BYTE *LDCopyright;
166 LONG LDAllocAvailBytes;
167 LONG LDAllocFreeCount;
168 LONG LDLastGarbCollect;
169 LONG LDAlloc16Lists[64];
170 LONG LDAlloc256Lists[12];
171 LONG LDAlloc4kList;
172 struct DomainStructure *LDDomainID; /* This must be non-zero for the Alloc Hunt code to work right. */
173 /* It also points to the domain structure. */
174 struct LoadDefinitionStructure *LDEnvLink;
175 void *LDAllocPagesListHead;
176 struct ExternalPublicDefinitionStructure *LDTempPublicList;
177 LONG LDMessageLanguage; /* for enabling */
178 BYTE **LDMessages; /* for enabling */
179 LONG LDMessageCount; /* for enabling */
180 BYTE *LDHelpFile; /* for enabling */
181 LONG LDMessageBufferSize; /* for enabling */
182 LONG LDHelpBufferSize; /* for enabling */
183 LONG LDSharedCodeOffset; /* for protection */
184 LONG LDSharedCodeLength; /* for protection */
185 LONG LDSharedDataOffset; /* for protection */
186 LONG LDSharedDataLength; /* for protection */
187 LONG (*LDSharedInitProcedure)(
188 struct LoadDefinitionStructure *LoadRecord,
189 struct ScreenStruct *screenID,
190 BYTE *CommandLine);
191 void (*LDSharedExitProcedure)(void);
192 LONG LDRPCDataTable;
193 LONG LDRealRPCDataTable;
194 LONG LDRPCDataTableSize;
195 LONG LDNumberOfReferencedPublics;
196 struct ExternalPublicDefinitionStructure **LDReferencedPublics;
197 LONG LDNumberOfReferencedExports;
198 };
199
200
201 /* define the LDFlags. */
202
203 #define LDModuleIsReEntrantBit 0x00000001
204 #define LDModuleCanBeMultiplyLoadedBit 0x00000002
205 #define LDSynchronizeStart 0x00000004
206 #define LDPseudoPreemptionBit 0x00000008
207 #define LDLoadInOSDomain 0x00000010
208 #define LDDontUnloadBit 0x20000000
209 #define LDModuleIsBeingDebugged 0x40000000
210 #define LDMemoryOn4KBoundriesBit 0x80000000
211
212 /* LoadModule load options */
213 #define LO_NORMAL 0x0000
214 #define LO_STARTUP 0x0001
215 #define LO_PROTECT 0x0002
216 #define LO_DEBUG 0x0004
217 #define LO_AUTO_LOAD 0x0008
218 #define LO_DONT_PROMPT 0x0010
219 #define LO_LOAD_LOW 0x0020
220 #define LO_RETURN_HANDLE 0x0040
221 #define LO_LOAD_SILENT 0x0080
222
223 /* Loader returned error codes */
224 #define LOAD_COULD_NOT_FIND_FILE 1
225 #define LOAD_ERROR_READING_FILE 2
226 #define LOAD_NOT_NLM_FILE_FORMAT 3
227 #define LOAD_WRONG_NLM_FILE_VERSION 4
228 #define LOAD_REENTRANT_INITIALIZE_FAILURE 5
229 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES 6
230 #define LOAD_ALREADY_IN_PROGRESS 7
231 #define LOAD_NOT_ENOUGH_MEMORY 8
232 #define LOAD_INITIALIZE_FAILURE 9
233 #define LOAD_INCONSISTENT_FILE_FORMAT 10
234 #define LOAD_CAN_NOT_LOAD_AT_STARTUP 11
235 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED 12
236 #define LOAD_UNRESOLVED_EXTERNAL 13
237 #define LOAD_PUBLIC_ALREADY_DEFINED 14
238 #define LOAD_XDC_DATA_ERROR 15
239 #define LOAD_NOT_OS_DOMAIN 16
240
241 /****************************************************************************/
242
243 /* The main thread ID. */
244 static int mainthread;
245
246 /* The debug server thread ID. */
247 static int debugthread;
248
249 /* The LoadDefinitionStructure of the NLM being debugged. */
250 static struct LoadDefinitionStructure *handle;
251
252 /* Whether we have connected to gdb. */
253 static int talking;
254
255 /* The actual first instruction in the program. */
256 static unsigned char first_insn;
257
258 /* An error message for the main thread to print. */
259 static char *error_message;
260
261 /* The AIO port handle. */
262 static int AIOhandle;
263
264 /* The console screen. */
265 static int console_screen;
266
267 /* BUFMAX defines the maximum number of characters in inbound/outbound
268 buffers. At least NUMREGBYTES*2 are needed for register packets */
269 #define BUFMAX 400
270
271 /* remote_debug > 0 prints ill-formed commands in valid packets and
272 checksum errors. */
273 static int remote_debug = 1;
274
275 static const char hexchars[] = "0123456789abcdef";
276
277 /* Number of bytes of registers. */
278 #define NUMREGBYTES 64
279 enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
280 PC /* also known as eip */,
281 PS /* also known as eflags */,
282 CS, SS, DS, ES, FS, GS};
283
284 /* Register values. */
285 static int registers[NUMREGBYTES/4];
286
287 /* Read a character from the serial port. This must busy wait, but
288 that's OK because we will be the only thread running anyhow. */
289
290 static int
291 getDebugChar ()
292 {
293 int err;
294 LONG got;
295 unsigned char ret;
296
297 do
298 {
299 err = AIOReadData (AIOhandle, (char *) &ret, 1, &got);
300 if (err != 0)
301 {
302 error_message = "AIOReadData failed";
303 ResumeThread (mainthread);
304 return -1;
305 }
306 }
307 while (got == 0);
308
309 return ret;
310 }
311
312 /* Write a character to the serial port. Returns 0 on failure,
313 non-zero on success. */
314
315 static int
316 putDebugChar (c)
317 unsigned char c;
318 {
319 int err;
320 LONG put;
321
322 err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
323 if (err != 0 || put != 1)
324 {
325 error_message = "AIOWriteData failed";
326 ResumeThread (mainthread);
327 return 0;
328 }
329 return 1;
330 }
331
332 /* Get the registers out of the frame information. */
333
334 static void
335 frame_to_registers (frame, regs)
336 T_TSS_StackFrame *frame;
337 int *regs;
338 {
339 regs[EAX] = frame->ExceptionEAX;
340 regs[ECX] = frame->ExceptionECX;
341 regs[EDX] = frame->ExceptionEDX;
342 regs[EBX] = frame->ExceptionEBX;
343 regs[ESP] = frame->ExceptionESP;
344 regs[EBP] = frame->ExceptionEBP;
345 regs[ESI] = frame->ExceptionESI;
346 regs[EDI] = frame->ExceptionEDI;
347 regs[PC] = frame->ExceptionEIP;
348 regs[PS] = frame->ExceptionSystemFlags;
349 regs[CS] = frame->ExceptionCS[0];
350 regs[SS] = frame->ExceptionSS[0];
351 regs[DS] = frame->ExceptionDS[0];
352 regs[ES] = frame->ExceptionES[0];
353 regs[FS] = frame->ExceptionFS[0];
354 regs[GS] = frame->ExceptionGS[0];
355 }
356
357 /* Put the registers back into the frame information. */
358
359 static void
360 registers_to_frame (regs, frame)
361 int *regs;
362 T_TSS_StackFrame *frame;
363 {
364 frame->ExceptionEAX = regs[EAX];
365 frame->ExceptionECX = regs[ECX];
366 frame->ExceptionEDX = regs[EDX];
367 frame->ExceptionEBX = regs[EBX];
368 frame->ExceptionESP = regs[ESP];
369 frame->ExceptionEBP = regs[EBP];
370 frame->ExceptionESI = regs[ESI];
371 frame->ExceptionEDI = regs[EDI];
372 frame->ExceptionEIP = regs[PC];
373 frame->ExceptionSystemFlags = regs[PS];
374 frame->ExceptionCS[0] = regs[CS];
375 frame->ExceptionSS[0] = regs[SS];
376 frame->ExceptionDS[0] = regs[DS];
377 frame->ExceptionES[0] = regs[ES];
378 frame->ExceptionFS[0] = regs[FS];
379 frame->ExceptionGS[0] = regs[GS];
380 }
381
382 /* Turn a hex character into a number. */
383
384 static int
385 hex (ch)
386 char ch;
387 {
388 if ((ch >= 'a') && (ch <= 'f'))
389 return (ch-'a'+10);
390 if ((ch >= '0') && (ch <= '9'))
391 return (ch-'0');
392 if ((ch >= 'A') && (ch <= 'F'))
393 return (ch-'A'+10);
394 return (-1);
395 }
396
397 /* Scan for the sequence $<data>#<checksum>. Returns 0 on failure,
398 non-zero on success. */
399
400 static int
401 getpacket (buffer)
402 char * buffer;
403 {
404 unsigned char checksum;
405 unsigned char xmitcsum;
406 int i;
407 int count;
408 int ch;
409
410 do
411 {
412 /* wait around for the start character, ignore all other characters */
413 while ((ch = getDebugChar()) != '$')
414 if (ch == -1)
415 return 0;
416 checksum = 0;
417 xmitcsum = -1;
418
419 count = 0;
420
421 /* now, read until a # or end of buffer is found */
422 while (count < BUFMAX)
423 {
424 ch = getDebugChar();
425 if (ch == -1)
426 return 0;
427 if (ch == '#')
428 break;
429 checksum = checksum + ch;
430 buffer[count] = ch;
431 count = count + 1;
432 }
433 buffer[count] = 0;
434
435 if (ch == '#')
436 {
437 ch = getDebugChar ();
438 if (ch == -1)
439 return 0;
440 xmitcsum = hex(ch) << 4;
441 ch = getDebugChar ();
442 if (ch == -1)
443 return 0;
444 xmitcsum += hex(ch);
445 if ((remote_debug ) && (checksum != xmitcsum))
446 {
447 fprintf(stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
448 checksum,xmitcsum,buffer);
449 }
450
451 if (checksum != xmitcsum)
452 {
453 /* failed checksum */
454 if (! putDebugChar('-'))
455 return 0;
456 }
457 else
458 {
459 /* successful transfer */
460 if (! putDebugChar('+'))
461 return 0;
462 /* if a sequence char is present, reply the sequence ID */
463 if (buffer[2] == ':')
464 {
465 if (! putDebugChar (buffer[0])
466 || ! putDebugChar (buffer[1]))
467 return 0;
468 /* remove sequence chars from buffer */
469 count = strlen(buffer);
470 for (i=3; i <= count; i++)
471 buffer[i-3] = buffer[i];
472 }
473 }
474 }
475 }
476 while (checksum != xmitcsum);
477
478 return 1;
479 }
480
481 /* Send the packet in buffer. Returns 0 on failure, non-zero on
482 success. */
483
484 static int
485 putpacket (buffer)
486 char * buffer;
487 {
488 unsigned char checksum;
489 int count;
490 int ch;
491
492 /* $<packet info>#<checksum>. */
493 do
494 {
495 if (! putDebugChar('$'))
496 return 0;
497 checksum = 0;
498 count = 0;
499
500 while (ch=buffer[count])
501 {
502 if (! putDebugChar(ch))
503 return 0;
504 checksum += ch;
505 count += 1;
506 }
507
508 if (! putDebugChar('#')
509 || ! putDebugChar(hexchars[checksum >> 4])
510 || ! putDebugChar(hexchars[checksum % 16]))
511 return 0;
512
513 ch = getDebugChar ();
514 if (ch == -1)
515 return 0;
516 }
517 while (ch != '+');
518
519 return 1;
520 }
521
522 static char remcomInBuffer[BUFMAX];
523 static char remcomOutBuffer[BUFMAX];
524 static short error;
525
526 static void
527 debug_error (format, parm)
528 char *format;
529 char *parm;
530 {
531 if (remote_debug)
532 fprintf (stderr, format, parm);
533 }
534
535 /* Address of a routine to RTE to if we get a memory fault. */
536 static volatile void (*mem_fault_routine)() = NULL;
537
538 /* Indicate to caller of mem2hex or hex2mem that there has been an
539 error. */
540 static volatile int mem_err = 0;
541
542 static void
543 set_mem_err ()
544 {
545 mem_err = 1;
546 }
547
548 /* These are separate functions so that they are so short and sweet
549 that the compiler won't save any registers (if there is a fault
550 to mem_fault, they won't get restored, so there better not be any
551 saved). */
552
553 static int
554 get_char (addr)
555 char *addr;
556 {
557 return *addr;
558 }
559
560 static void
561 set_char (addr, val)
562 char *addr;
563 int val;
564 {
565 *addr = val;
566 }
567
568 /* convert the memory pointed to by mem into hex, placing result in buf */
569 /* return a pointer to the last char put in buf (null) */
570 /* If MAY_FAULT is non-zero, then we should set mem_err in response to
571 a fault; if zero treat a fault like any other fault in the stub. */
572
573 static char *
574 mem2hex (mem, buf, count, may_fault)
575 char *mem;
576 char *buf;
577 int count;
578 int may_fault;
579 {
580 int i;
581 unsigned char ch;
582
583 if (may_fault)
584 mem_fault_routine = set_mem_err;
585 for (i = 0; i < count; i++)
586 {
587 ch = get_char (mem++);
588 if (may_fault && mem_err)
589 return (buf);
590 *buf++ = hexchars[ch >> 4];
591 *buf++ = hexchars[ch % 16];
592 }
593 *buf = 0;
594 if (may_fault)
595 mem_fault_routine = NULL;
596 return(buf);
597 }
598
599 /* convert the hex array pointed to by buf into binary to be placed in mem */
600 /* return a pointer to the character AFTER the last byte written */
601
602 static char *
603 hex2mem (buf, mem, count, may_fault)
604 char *buf;
605 char *mem;
606 int count;
607 int may_fault;
608 {
609 int i;
610 unsigned char ch;
611
612 if (may_fault)
613 mem_fault_routine = set_mem_err;
614 for (i=0;i<count;i++)
615 {
616 ch = hex(*buf++) << 4;
617 ch = ch + hex(*buf++);
618 set_char (mem++, ch);
619 if (may_fault && mem_err)
620 return (mem);
621 }
622 if (may_fault)
623 mem_fault_routine = NULL;
624 return(mem);
625 }
626
627 /* This function takes the 386 exception vector and attempts to
628 translate this number into a unix compatible signal value. */
629
630 static int
631 computeSignal (exceptionVector)
632 int exceptionVector;
633 {
634 int sigval;
635 switch (exceptionVector)
636 {
637 case 0 : sigval = 8; break; /* divide by zero */
638 case 1 : sigval = 5; break; /* debug exception */
639 case 3 : sigval = 5; break; /* breakpoint */
640 case 4 : sigval = 16; break; /* into instruction (overflow) */
641 case 5 : sigval = 16; break; /* bound instruction */
642 case 6 : sigval = 4; break; /* Invalid opcode */
643 case 7 : sigval = 8; break; /* coprocessor not available */
644 case 8 : sigval = 7; break; /* double fault */
645 case 9 : sigval = 11; break; /* coprocessor segment overrun */
646 case 10 : sigval = 11; break; /* Invalid TSS */
647 case 11 : sigval = 11; break; /* Segment not present */
648 case 12 : sigval = 11; break; /* stack exception */
649 case 13 : sigval = 11; break; /* general protection */
650 case 14 : sigval = 11; break; /* page fault */
651 case 16 : sigval = 7; break; /* coprocessor error */
652 default:
653 sigval = 7; /* "software generated"*/
654 }
655 return (sigval);
656 }
657
658 /**********************************************/
659 /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
660 /* RETURN NUMBER OF CHARS PROCESSED */
661 /**********************************************/
662 static int
663 hexToInt(ptr, intValue)
664 char **ptr;
665 int *intValue;
666 {
667 int numChars = 0;
668 int hexValue;
669
670 *intValue = 0;
671
672 while (**ptr)
673 {
674 hexValue = hex(**ptr);
675 if (hexValue >=0)
676 {
677 *intValue = (*intValue <<4) | hexValue;
678 numChars ++;
679 }
680 else
681 break;
682
683 (*ptr)++;
684 }
685
686 return (numChars);
687 }
688
689 /* This function does all command processing for interfacing to gdb.
690 It is called whenever an exception occurs in the module being
691 debugged. */
692
693 static LONG
694 handle_exception (T_StackFrame *old_frame)
695 {
696 T_TSS_StackFrame *frame = (T_TSS_StackFrame *) old_frame;
697 int first = 0;
698 int sigval;
699 int addr, length;
700 char * ptr;
701 int newPC;
702
703 /* Apparently the bell can sometimes be ringing at this point, and
704 should be stopped. */
705 StopBell ();
706
707 if (remote_debug)
708 {
709 ConsolePrintf ("vector=%d: %s, sr=0x%x, pc=0x%x, thread=%d\r\n",
710 frame->ExceptionNumber,
711 frame->ExceptionDescription,
712 frame->ExceptionSystemFlags,
713 frame->ExceptionEIP,
714 GetThreadID ());
715 }
716
717 /* If the NLM just started, we record the module load information
718 and the thread ID, and set a breakpoint at the first instruction
719 in the program. */
720 if (frame->ExceptionNumber == START_NLM_EVENT
721 && handle == NULL)
722 {
723 debugthread = GetThreadID ();
724 handle = (struct LoadDefinitionStructure *) frame->ExceptionErrorCode;
725 first_insn = *(char *) handle->LDInitializationProcedure;
726 *(unsigned char *) handle->LDInitializationProcedure = 0xcc;
727 return RETURN_TO_PROGRAM;
728 }
729
730 /* At the moment, we don't care about most of the unusual NetWare
731 exceptions. */
732 if (frame->ExceptionNumber != TERMINATE_NLM_EVENT
733 && frame->ExceptionNumber > 31)
734 return RETURN_TO_PROGRAM;
735
736 /* Reset the initial breakpoint if necessary. */
737 if (frame->ExceptionNumber == 3
738 && frame->ExceptionEIP == (LONG) handle->LDInitializationProcedure + 1
739 && *(unsigned char *) handle->LDInitializationProcedure == 0xcc)
740 {
741 *(char *) handle->LDInitializationProcedure = first_insn;
742 frame->ExceptionEIP = (LONG) handle->LDInitializationProcedure;
743 first = 1;
744 }
745
746 /* FIXME: How do we know that this exception has anything to do with
747 the program we are debugging? We can check whether the PC is in
748 the range of the module we are debugging, but that doesn't help
749 much since an error could occur in a library routine. */
750
751 frame_to_registers (frame, registers);
752
753 /* reply to host that an exception has occurred */
754 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
755 {
756 /* There is no way to get the exit status. */
757 remcomOutBuffer[0] = 'W';
758 remcomOutBuffer[1] = hexchars[0];
759 remcomOutBuffer[2] = hexchars[0];
760 remcomOutBuffer[3] = 0;
761 }
762 else
763 {
764 sigval = computeSignal (frame->ExceptionNumber);
765 remcomOutBuffer[0] = 'S';
766 remcomOutBuffer[1] = hexchars[sigval >> 4];
767 remcomOutBuffer[2] = hexchars[sigval % 16];
768 remcomOutBuffer[3] = 0;
769 if (first)
770 {
771 remcomOutBuffer[0] = 'N';
772 sprintf (remcomOutBuffer + 3, "0x%x;0x%x;0x%x",
773 handle->LDCodeImageOffset,
774 handle->LDDataImageOffset,
775 handle->LDDataImageOffset + handle->LDDataImageLength);
776 }
777 }
778
779 if (! putpacket(remcomOutBuffer))
780 return RETURN_TO_NEXT_DEBUGGER;
781
782 if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
783 {
784 ResumeThread (mainthread);
785 return RETURN_TO_PROGRAM;
786 }
787
788 while (1)
789 {
790 error = 0;
791 remcomOutBuffer[0] = 0;
792 if (! getpacket (remcomInBuffer))
793 return RETURN_TO_NEXT_DEBUGGER;
794 talking = 1;
795 switch (remcomInBuffer[0])
796 {
797 case '?':
798 sigval = computeSignal (frame->ExceptionNumber);
799 remcomOutBuffer[0] = 'S';
800 remcomOutBuffer[1] = hexchars[sigval >> 4];
801 remcomOutBuffer[2] = hexchars[sigval % 16];
802 remcomOutBuffer[3] = 0;
803 if (first)
804 {
805 remcomOutBuffer[0] = 'N';
806 sprintf (remcomOutBuffer + 3, "0x%x;0x%x;0x%x",
807 handle->LDCodeImageOffset,
808 handle->LDDataImageOffset,
809 (handle->LDDataImageOffset
810 + handle->LDDataImageLength));
811 }
812 break;
813 case 'd':
814 remote_debug = !(remote_debug); /* toggle debug flag */
815 break;
816 case 'g':
817 /* return the value of the CPU registers */
818 mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES, 0);
819 break;
820 case 'G':
821 /* set the value of the CPU registers - return OK */
822 hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0);
823 strcpy(remcomOutBuffer,"OK");
824 break;
825
826 case 'm':
827 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
828 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
829 ptr = &remcomInBuffer[1];
830 if (hexToInt(&ptr,&addr))
831 if (*(ptr++) == ',')
832 if (hexToInt(&ptr,&length))
833 {
834 ptr = 0;
835 mem_err = 0;
836 mem2hex((char*) addr, remcomOutBuffer, length, 1);
837 if (mem_err)
838 {
839 strcpy (remcomOutBuffer, "E03");
840 debug_error ("memory fault");
841 }
842 }
843
844 if (ptr)
845 {
846 strcpy(remcomOutBuffer,"E01");
847 debug_error("malformed read memory command: %s",remcomInBuffer);
848 }
849 break;
850
851 case 'M':
852 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
853 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
854 ptr = &remcomInBuffer[1];
855 if (hexToInt(&ptr,&addr))
856 if (*(ptr++) == ',')
857 if (hexToInt(&ptr,&length))
858 if (*(ptr++) == ':')
859 {
860 mem_err = 0;
861 hex2mem(ptr, (char*) addr, length, 1);
862
863 if (mem_err)
864 {
865 strcpy (remcomOutBuffer, "E03");
866 debug_error ("memory fault");
867 }
868 else
869 {
870 strcpy(remcomOutBuffer,"OK");
871 }
872
873 ptr = 0;
874 }
875 if (ptr)
876 {
877 strcpy(remcomOutBuffer,"E02");
878 debug_error("malformed write memory command: %s",remcomInBuffer);
879 }
880 break;
881
882 case 'c':
883 case 's':
884 /* cAA..AA Continue at address AA..AA(optional) */
885 /* sAA..AA Step one instruction from AA..AA(optional) */
886 /* try to read optional parameter, pc unchanged if no parm */
887 ptr = &remcomInBuffer[1];
888 if (hexToInt(&ptr,&addr))
889 registers[ PC ] = addr;
890
891 newPC = registers[ PC];
892
893 /* clear the trace bit */
894 registers[ PS ] &= 0xfffffeff;
895
896 /* set the trace bit if we're stepping */
897 if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100;
898
899 registers_to_frame (registers, frame);
900 return RETURN_TO_PROGRAM;
901
902 case 'k':
903 /* kill the program */
904 KillMe (handle);
905 ResumeThread (mainthread);
906 return RETURN_TO_PROGRAM;
907 }
908
909 /* reply to the request */
910 if (! putpacket(remcomOutBuffer))
911 return RETURN_TO_NEXT_DEBUGGER;
912 }
913 }
914
915 /* Start up. The main thread opens the named serial I/O port, loads
916 the named NLM module and then goes to sleep. The serial I/O port
917 is named as a board number and a port number. It would be more DOS
918 like to provide a menu of available serial ports, but I don't want
919 to have to figure out how to do that. */
920
921 int
922 main (argc, argv)
923 int argc;
924 char **argv;
925 {
926 int hardware, board, port;
927 LONG err;
928 struct debuggerStructure s;
929 char *cmdlin;
930 int i;
931
932 /* Create a screen for the debugger. */
933 console_screen = CreateScreen ("System Console", 0);
934 if (DisplayScreen (console_screen) != ESUCCESS)
935 fprintf (stderr, "DisplayScreen failed\n");
936
937 if (argc < 4)
938 {
939 fprintf (stderr,
940 "Usage: load gdbserver board port program [arguments]\n");
941 exit (1);
942 }
943
944 hardware = -1;
945 board = strtol (argv[1], (char **) NULL, 0);
946 port = strtol (argv[2], (char **) NULL, 0);
947
948 err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
949 if (err != AIO_SUCCESS)
950 {
951 switch (err)
952 {
953 case AIO_PORT_NOT_AVAILABLE:
954 fprintf (stderr, "Port not available\n");
955 break;
956
957 case AIO_BOARD_NUMBER_INVALID:
958 case AIO_PORT_NUMBER_INVALID:
959 fprintf (stderr, "No such port\n");
960 break;
961
962 default:
963 fprintf (stderr, "Could not open port: %d\n", err);
964 break;
965 }
966
967 exit (1);
968 }
969
970 err = AIOConfigurePort (AIOhandle, AIO_BAUD_9600, AIO_DATA_BITS_8,
971 AIO_STOP_BITS_1, AIO_PARITY_NONE,
972 AIO_HARDWARE_FLOW_CONTROL_OFF);
973 if (err != AIO_SUCCESS)
974 {
975 fprintf (stderr, "Could not configure port: %d\n", err);
976 AIOReleasePort (AIOhandle);
977 exit (1);
978 }
979
980 /* Register ourselves as an alternate debugger. */
981 memset (&s, 0, sizeof s);
982 s.DDSResourceTag = ((struct ResourceTagStructure *)
983 AllocateResourceTag (GetNLMHandle (),
984 "gdbserver",
985 DebuggerSignature));
986 if (s.DDSResourceTag == 0)
987 {
988 fprintf (stderr, "AllocateResourceTag failed\n");
989 AIOReleasePort (AIOhandle);
990 exit (1);
991 }
992 s.DDSdebuggerEntry = handle_exception;
993 s.DDSFlags = TSS_FRAME_BIT;
994
995 err = RegisterDebuggerRTag (&s, AT_FIRST);
996 if (err != 0)
997 {
998 fprintf (stderr, "RegisterDebuggerRTag failed\n");
999 AIOReleasePort (AIOhandle);
1000 exit (1);
1001 }
1002
1003 /* Get the command line we were invoked with, and advance it past
1004 our name and the board and port arguments. */
1005 cmdlin = getcmd ((char *) NULL);
1006 for (i = 0; i < 2; i++)
1007 {
1008 while (! isspace (*cmdlin))
1009 ++cmdlin;
1010 while (isspace (*cmdlin))
1011 ++cmdlin;
1012 }
1013
1014 /* In case GDB is started before us, ack any packets (presumably
1015 "$?#xx") sitting there. */
1016 if (! putDebugChar ('+'))
1017 {
1018 fprintf (stderr, "putDebugChar failed\n");
1019 UnRegisterDebugger (&s);
1020 AIOReleasePort (AIOhandle);
1021 exit (1);
1022 }
1023
1024 mainthread = GetThreadID ();
1025 handle = NULL;
1026 talking = 0;
1027
1028 if (remote_debug > 0)
1029 ConsolePrintf ("About to call LoadModule with \"%s\" %d %d\r\n",
1030 cmdlin, console_screen, __GetScreenID (console_screen));
1031
1032 /* Start up the module to be debugged. */
1033 err = LoadModule ((struct ScreenStruct *) __GetScreenID (console_screen),
1034 cmdlin, LO_DEBUG);
1035 if (err != 0)
1036 {
1037 fprintf (stderr, "LoadModule failed: %d\n", err);
1038 UnRegisterDebugger (&s);
1039 AIOReleasePort (AIOhandle);
1040 exit (1);
1041 }
1042
1043 /* By the time we reach this point in the code the debugger thread
1044 should have received a START_NLM_EVENT and gone to sleep. */
1045 if (remote_debug > 0)
1046 ConsolePrintf ("Resuming %d, suspending %d\r\n", debugthread, mainthread);
1047 ResumeThread (debugthread);
1048 SuspendThread (mainthread);
1049
1050 /* If we are woken up, print an optional error message, deregister
1051 ourselves and exit. */
1052 if (error_message != NULL)
1053 fprintf (stderr, "%s\n", error_message);
1054 UnRegisterDebugger (&s);
1055 AIOReleasePort (AIOhandle);
1056 exit (0);
1057 }
This page took 0.057825 seconds and 5 git commands to generate.