]> Git Repo - binutils.git/blob - gdb/i386-nlmstub.c
Change the stream argument to _filtered to GDB_FILE *.
[binutils.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 /* This information is from Novell.  It is not in any of the standard
83    NetWare header files.  */
84
85 struct DBG_LoadDefinitionStructure
86 {
87         void *reserved1[4];
88         LONG reserved5;
89         LONG LDCodeImageOffset;
90         LONG LDCodeImageLength;
91         LONG LDDataImageOffset;
92         LONG LDDataImageLength;
93         LONG LDUninitializedDataLength;
94         LONG LDCustomDataOffset;
95         LONG LDCustomDataSize;
96         LONG reserved6[2];
97         LONG (*LDInitializationProcedure)(void);
98 };
99
100 #define LO_NORMAL               0x0000
101 #define LO_STARTUP              0x0001
102 #define LO_PROTECT              0x0002
103 #define LO_DEBUG                0x0004
104 #define LO_AUTO_LOAD            0x0008
105
106 /* Loader returned error codes */
107 #define LOAD_COULD_NOT_FIND_FILE                        1
108 #define LOAD_ERROR_READING_FILE                         2
109 #define LOAD_NOT_NLM_FILE_FORMAT                        3
110 #define LOAD_WRONG_NLM_FILE_VERSION                     4
111 #define LOAD_REENTRANT_INITIALIZE_FAILURE       5
112 #define LOAD_CAN_NOT_LOAD_MULTIPLE_COPIES       6
113 #define LOAD_ALREADY_IN_PROGRESS                        7
114 #define LOAD_NOT_ENOUGH_MEMORY                          8
115 #define LOAD_INITIALIZE_FAILURE                         9
116 #define LOAD_INCONSISTENT_FILE_FORMAT           10
117 #define LOAD_CAN_NOT_LOAD_AT_STARTUP            11
118 #define LOAD_AUTO_LOAD_MODULES_NOT_LOADED       12
119 #define LOAD_UNRESOLVED_EXTERNAL                        13
120 #define LOAD_PUBLIC_ALREADY_DEFINED                     14
121 /****************************************************/
122
123 /* The main thread ID.  */
124 static int mainthread;
125
126 /* The LoadDefinitionStructure of the NLM being debugged.  */
127 static struct DBG_LoadDefinitionStructure *handle;
128
129 /* Whether we have connected to gdb.  */
130 static int talking;
131
132 /* The actual first instruction in the program.  */
133 static unsigned char first_insn;
134
135 /* An error message for the main thread to print.  */
136 static char *error_message;
137
138 /* The AIO port handle.  */
139 static int AIOhandle;
140
141 /* The console screen.  */
142 static int console_screen;
143
144 /* BUFMAX defines the maximum number of characters in inbound/outbound
145    buffers.  At least NUMREGBYTES*2 are needed for register packets */
146 #define BUFMAX 400
147
148 /* remote_debug > 0 prints ill-formed commands in valid packets and
149    checksum errors. */
150 static int remote_debug = 1;
151
152 static const char hexchars[] = "0123456789abcdef";
153
154 /* Number of bytes of registers.  */
155 #define NUMREGBYTES 64
156 enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
157                PC /* also known as eip */,
158                PS /* also known as eflags */,
159                CS, SS, DS, ES, FS, GS};
160
161 /* Register values.  */
162 static int registers[NUMREGBYTES/4];
163
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
167 static int
168 getDebugChar ()
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
192 static int
193 putDebugChar (c)
194      unsigned char c;
195 {
196   int err;
197   LONG put;
198
199   err = AIOWriteData (AIOhandle, (char *) &c, 1, &put);
200   if (err != 0 || put != 1)
201     {
202       error_message = "AIOWriteData failed";
203       ResumeThread (mainthread);
204       return 0;
205     }
206   return 1;
207 }
208
209 /* Get the registers out of the frame information.  */
210
211 static void
212 frame_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
236 static void
237 registers_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
261 static int
262 hex (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
277 static int
278 getpacket (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             {
324               fprintf_unfiltered(gdb_stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
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
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       fprintf_unfiltered (gdb_stderr, format, parm);
417       fprintf_unfiltered (gdb_stderr, "\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      char *mem;
468      char *buf;
469      int count;
470      int may_fault;
471 {
472   int i;
473   unsigned char ch;
474
475   mem_may_fault = may_fault;
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;
485   mem_may_fault = 0;
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
492 static char *
493 hex2mem (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
502   mem_may_fault = may_fault;
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     }
511   mem_may_fault = 0;
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
518 static int
519 computeSignal (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 /**********************************************/
550 static int
551 hexToInt(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
581 static LONG
582 handle_exception (T_StackFrame *old_frame)
583 {
584   T_TSS_StackFrame *frame = (T_TSS_StackFrame *) old_frame;
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     {
596       ConsolePrintf ("vector=%d: %s, sr=0x%x, pc=0x%x, thread=%d\r\n",
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     {
610       handle = ((struct DBG_LoadDefinitionStructure *)
611                 frame->ExceptionErrorCode);
612       first_insn = *(char *) handle->LDInitializationProcedure;
613       *(unsigned char *) handle->LDInitializationProcedure = 0xcc;
614       return RETURN_TO_PROGRAM;
615     }
616
617   /* After we've reached the initial breakpoint, reset it.  */
618   if (frame->ExceptionEIP == (LONG) handle->LDInitializationProcedure + 1
619       && *(unsigned char *) handle->LDInitializationProcedure == 0xcc)
620     {
621       *(char *) handle->LDInitializationProcedure = first_insn;
622       frame->ExceptionEIP = (LONG) handle->LDInitializationProcedure;
623     }
624
625   /* Pass some events on to the next debugger, in case it will handle
626      them.  */
627   if (frame->ExceptionNumber == ENTER_DEBUGGER_EVENT
628       || frame->ExceptionNumber == KEYBOARD_BREAK_EVENT)
629     return RETURN_TO_NEXT_DEBUGGER;
630
631   /* At the moment, we don't care about most of the unusual NetWare
632      exceptions.  */
633   if (frame->ExceptionNumber != TERMINATE_NLM_EVENT
634       && frame->ExceptionNumber > 31)
635     return RETURN_TO_PROGRAM;
636
637   /* If we get a GP fault, and mem_may_fault is set, and the
638      instruction pointer is near set_char or get_char, then we caused
639      the fault ourselves accessing an illegal memory location.  */
640   if (mem_may_fault
641       && (frame->ExceptionNumber == 11
642           || frame->ExceptionNumber == 13
643           || frame->ExceptionNumber == 14)
644       && ((frame->ExceptionEIP >= (long) &set_char
645            && frame->ExceptionEIP < (long) &set_char + 50)
646           || (frame->ExceptionEIP >= (long) &get_char
647               && frame->ExceptionEIP < (long) &get_char + 50)))
648     {
649       mem_err = 1;
650       /* Point the instruction pointer at an assembly language stub
651          which just returns from the function.  */
652       frame->ExceptionEIP = (long) &just_return;
653       /* Keep going.  This will act as though it returned from
654          set_char or get_char.  The calling routine will check
655          mem_err, and do the right thing.  */
656       return RETURN_TO_PROGRAM;
657     }
658
659   /* FIXME: How do we know that this exception has anything to do with
660      the program we are debugging?  We can check whether the PC is in
661      the range of the module we are debugging, but that doesn't help
662      much since an error could occur in a library routine.  */
663
664   frame_to_registers (frame, registers);
665
666   /* reply to host that an exception has occurred */
667   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
668     {
669       /* There is no way to get the exit status.  */
670       remcomOutBuffer[0] = 'W';
671       remcomOutBuffer[1] = hexchars[0];
672       remcomOutBuffer[2] = hexchars[0];
673       remcomOutBuffer[3] = 0;
674     }
675   else
676     {
677       sigval = computeSignal (frame->ExceptionNumber);
678       remcomOutBuffer[0] = 'N';
679       remcomOutBuffer[1] =  hexchars[sigval >> 4];
680       remcomOutBuffer[2] =  hexchars[sigval % 16];
681       sprintf (remcomOutBuffer + 3, "0x%x;0x%x;0x%x",
682                handle->LDCodeImageOffset,
683                handle->LDDataImageOffset,
684                handle->LDDataImageOffset + handle->LDDataImageLength);
685     }
686
687   if (! putpacket(remcomOutBuffer))
688     return RETURN_TO_NEXT_DEBUGGER;
689
690   if (frame->ExceptionNumber == TERMINATE_NLM_EVENT)
691     {
692       ResumeThread (mainthread);
693       return RETURN_TO_PROGRAM;
694     }
695
696   while (1)
697     {
698       error = 0;
699       remcomOutBuffer[0] = 0;
700       if (! getpacket (remcomInBuffer))
701         return RETURN_TO_NEXT_DEBUGGER;
702       talking = 1;
703       switch (remcomInBuffer[0])
704         {
705         case '?':
706           sigval = computeSignal (frame->ExceptionNumber);
707           remcomOutBuffer[0] = 'N';
708           remcomOutBuffer[1] =  hexchars[sigval >> 4];
709           remcomOutBuffer[2] =  hexchars[sigval % 16];
710           sprintf (remcomOutBuffer + 3, "0x%x;0x%x;0x%x",
711                    handle->LDCodeImageOffset,
712                    handle->LDDataImageOffset,
713                    handle->LDDataImageOffset + handle->LDDataImageLength);
714           break;
715         case 'd':
716           remote_debug = !(remote_debug); /* toggle debug flag */
717           break;
718         case 'g':
719           /* return the value of the CPU registers */
720           mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES, 0);
721           break;
722         case 'G':
723           /* set the value of the CPU registers - return OK */
724           hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0);
725           strcpy(remcomOutBuffer,"OK");
726           break;
727
728         case 'm':
729           /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
730           /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
731           ptr = &remcomInBuffer[1];
732           if (hexToInt(&ptr,&addr))
733             if (*(ptr++) == ',')
734               if (hexToInt(&ptr,&length))
735                 {
736                   ptr = 0;
737                   mem_err = 0;
738                   mem2hex((char*) addr, remcomOutBuffer, length, 1);
739                   if (mem_err)
740                     {
741                       strcpy (remcomOutBuffer, "E03");
742                       debug_error ("memory fault");
743                     }
744                 }
745
746           if (ptr)
747             {
748               strcpy(remcomOutBuffer,"E01");
749               debug_error("malformed read memory command: %s",remcomInBuffer);
750             }
751           break;
752
753         case 'M':
754           /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
755           /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
756           ptr = &remcomInBuffer[1];
757           if (hexToInt(&ptr,&addr))
758             if (*(ptr++) == ',')
759               if (hexToInt(&ptr,&length))
760                 if (*(ptr++) == ':')
761                   {
762                     mem_err = 0;
763                     hex2mem(ptr, (char*) addr, length, 1);
764
765                     if (mem_err)
766                       {
767                         strcpy (remcomOutBuffer, "E03");
768                         debug_error ("memory fault");
769                       }
770                     else
771                       {
772                         strcpy(remcomOutBuffer,"OK");
773                       }
774
775                     ptr = 0;
776                   }
777           if (ptr)
778             {
779               strcpy(remcomOutBuffer,"E02");
780               debug_error("malformed write memory command: %s",remcomInBuffer);
781             }
782           break;
783
784         case 'c':
785         case 's':
786           /* cAA..AA    Continue at address AA..AA(optional) */
787           /* sAA..AA   Step one instruction from AA..AA(optional) */
788           /* try to read optional parameter, pc unchanged if no parm */
789           ptr = &remcomInBuffer[1];
790           if (hexToInt(&ptr,&addr))
791             registers[ PC ] = addr;
792
793           newPC = registers[ PC];
794
795           /* clear the trace bit */
796           registers[ PS ] &= 0xfffffeff;
797
798           /* set the trace bit if we're stepping */
799           if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100;
800
801           registers_to_frame (registers, frame);
802           return RETURN_TO_PROGRAM;
803
804         case 'k':
805           /* kill the program */
806           KillMe (handle);
807           ResumeThread (mainthread);
808           return RETURN_TO_PROGRAM;
809         }
810
811       /* reply to the request */
812       if (! putpacket(remcomOutBuffer))
813         return RETURN_TO_NEXT_DEBUGGER;
814     }
815 }
816
817 /* Start up.  The main thread opens the named serial I/O port, loads
818    the named NLM module and then goes to sleep.  The serial I/O port
819    is named as a board number and a port number.  It would be more DOS
820    like to provide a menu of available serial ports, but I don't want
821    to have to figure out how to do that.  */
822
823 int
824 main (argc, argv)
825      int argc;
826      char **argv;
827 {
828   int hardware, board, port;
829   LONG err;
830   struct debuggerStructure s;
831   char *cmdlin;
832   int i;
833
834   /* Create a screen for the debugger.  */
835   console_screen = CreateScreen ("System Console", 0);
836   if (DisplayScreen (console_screen) != ESUCCESS)
837     fprintf_unfiltered (gdb_stderr, "DisplayScreen failed\n");
838
839   if (argc < 4)
840     {
841       fprintf_unfiltered (gdb_stderr,
842                "Usage: load gdbserver board port program [arguments]\n");
843       exit (1);
844     }
845
846   hardware = -1;
847   board = strtol (argv[1], (char **) NULL, 0);
848   port = strtol (argv[2], (char **) NULL, 0);
849
850   err = AIOAcquirePort (&hardware, &board, &port, &AIOhandle);
851   if (err != AIO_SUCCESS)
852     {
853       switch (err)
854         {
855         case AIO_PORT_NOT_AVAILABLE:
856           fprintf_unfiltered (gdb_stderr, "Port not available\n");
857           break;
858
859         case AIO_BOARD_NUMBER_INVALID:
860         case AIO_PORT_NUMBER_INVALID:
861           fprintf_unfiltered (gdb_stderr, "No such port\n");
862           break;
863
864         default:
865           fprintf_unfiltered (gdb_stderr, "Could not open port: %d\n", err);
866           break;
867         }
868
869       exit (1);
870     }
871
872   err = AIOConfigurePort (AIOhandle, AIO_BAUD_9600, AIO_DATA_BITS_8,
873                           AIO_STOP_BITS_1, AIO_PARITY_NONE,
874                           AIO_HARDWARE_FLOW_CONTROL_OFF);
875   if (err != AIO_SUCCESS)
876     {
877       fprintf_unfiltered (gdb_stderr, "Could not configure port: %d\n", err);
878       AIOReleasePort (AIOhandle);
879       exit (1);
880     }
881
882   /* Register ourselves as an alternate debugger.  */
883   memset (&s, 0, sizeof s);
884   s.DDSResourceTag = ((struct ResourceTagStructure *)
885                       AllocateResourceTag (GetNLMHandle (),
886                                            "gdbserver",
887                                            DebuggerSignature));
888   if (s.DDSResourceTag == 0)
889     {
890       fprintf_unfiltered (gdb_stderr, "AllocateResourceTag failed\n");
891       AIOReleasePort (AIOhandle);
892       exit (1);
893     }
894   s.DDSdebuggerEntry = handle_exception;
895   s.DDSFlags = TSS_FRAME_BIT;
896
897   err = RegisterDebuggerRTag (&s, AT_FIRST);
898   if (err != 0)
899     {
900       fprintf_unfiltered (gdb_stderr, "RegisterDebuggerRTag failed\n");
901       AIOReleasePort (AIOhandle);
902       exit (1);
903     }
904
905   /* Get the command line we were invoked with, and advance it past
906      our name and the board and port arguments.  */
907   cmdlin = getcmd ((char *) NULL);
908   for (i = 0; i < 2; i++)
909     {
910       while (! isspace (*cmdlin))
911         ++cmdlin;
912       while (isspace (*cmdlin))
913         ++cmdlin;
914     }
915   
916   /* In case GDB is started before us, ack any packets (presumably
917      "$?#xx") sitting there.  */
918   if (! putDebugChar ('+'))
919     {
920       fprintf_unfiltered (gdb_stderr, "putDebugChar failed\n");
921       UnRegisterDebugger (&s);
922       AIOReleasePort (AIOhandle);
923       exit (1);
924     }
925
926   mainthread = GetThreadID ();
927   handle = NULL;
928   talking = 0;
929
930   if (remote_debug > 0)
931     ConsolePrintf ("About to call LoadModule with \"%s\" %d %d\r\n",
932                    cmdlin, console_screen, __GetScreenID (console_screen));
933
934   /* Start up the module to be debugged.  */
935   err = LoadModule ((struct ScreenStruct *) __GetScreenID (console_screen),
936                     cmdlin, LO_DEBUG);
937   if (err != 0)
938     {
939       fprintf_unfiltered (gdb_stderr, "LoadModule failed: %d\n", err);
940       UnRegisterDebugger (&s);
941       AIOReleasePort (AIOhandle);
942       exit (1);
943     }
944
945   /* Wait for the debugger to wake us up.  */
946   if (remote_debug > 0)
947     ConsolePrintf ("Suspending main thread (%d)\r\n", mainthread);
948   SuspendThread (mainthread);
949   if (remote_debug > 0)
950     ConsolePrintf ("Resuming main thread (%d)\r\n", mainthread);
951
952   /* If we are woken up, print an optional error message, deregister
953      ourselves and exit.  */
954   if (error_message != NULL)
955     fprintf_unfiltered (gdb_stderr, "%s\n", error_message);
956   UnRegisterDebugger (&s);
957   AIOReleasePort (AIOhandle);
958   exit (0);
959 }
This page took 0.078457 seconds and 4 git commands to generate.