1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
33 * Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
35 * To enable debugger support, two things need to happen. One, setting
36 * up a routine so that it is in the exception path, is necessary in order
37 * to allow any breakpoints or error conditions to be properly intercepted
38 * and reported to gdb.
39 * Two, a breakpoint needs to be generated to begin communication.
41 * Because gdb will sometimes write to the stack area to execute function
42 * calls, this program cannot rely on using the supervisor stack so it
43 * uses it's own stack area.
47 * The following gdb commands are supported:
49 * command function Return value
51 * g return the value of the CPU Registers hex data or ENN
52 * G set the value of the CPU Registers OK or ENN
54 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
55 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 * c Resume at current address SNN ( signal NN)
58 * cAA..AA Continue at address AA..AA SNN
60 * s Step one instruction SNN
61 * sAA..AA Step one instruction from AA..AA SNN
65 * ? What was the last sigval ? SNN (signal NN)
67 * All commands and responses are sent with a packet which includes a
68 * Checksum. A packet consists of
70 * $<packet info>#<Checksum>.
73 * <packet info> :: <characters representing the command or response>
74 * <Checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
76 * When a packet is received, it is first acknowledged with either '+' or '-'.
77 * '+' indicates a successful transfer. '-' indicates a failed transfer.
82 * $m0,10#2a +$00010203040506070809101112131415#42
84 ****************************************************************************/
87 #include <internal/kd.h>
88 #include <internal/ke.h>
89 #include <internal/ps.h>
90 #include <internal/module.h>
91 #include <internal/ldr.h>
94 #include <internal/debug.h>
96 extern LIST_ENTRY PiThreadListHead;
99 /************************************************************************/
100 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
101 /* at least NUMREGBYTES*2 are needed for register packets */
104 static BOOLEAN GspInitialized;
106 static PKINTERRUPT GspInterrupt;
109 static BOOLEAN GspRemoteDebug;
111 static CONST CHAR HexChars[]="0123456789abcdef";
113 static PETHREAD GspRunThread; /* NULL means run all threads */
114 static PETHREAD GspDbgThread;
115 static PETHREAD GspEnumThread;
117 /* Number of Registers. */
122 EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
123 PC /* also known as eip */,
124 PS /* also known as eflags */,
125 CS, SS, DS, ES, FS, GS
128 typedef struct _CPU_REGISTER
132 DWORD OffsetInContext;
133 BOOLEAN SetInContext;
134 } CPU_REGISTER, *PCPU_REGISTER;
136 #define KTRAP_FRAME_X86 KTRAP_FRAME
140 static CPU_REGISTER GspRegisters[NUMREGS] =
142 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eax), FIELD_OFFSET (CONTEXT, Eax), TRUE },
143 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ecx), FIELD_OFFSET (CONTEXT, Ecx), TRUE },
144 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edx), FIELD_OFFSET (CONTEXT, Edx), FALSE },
145 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebx), FIELD_OFFSET (CONTEXT, Ebx), TRUE },
146 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esp), FIELD_OFFSET (CONTEXT, Esp), TRUE },
147 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebp), FIELD_OFFSET (CONTEXT, Ebp), TRUE },
148 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esi), FIELD_OFFSET (CONTEXT, Esi), TRUE },
149 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edi), FIELD_OFFSET (CONTEXT, Edi), TRUE },
150 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eip), FIELD_OFFSET (CONTEXT, Eip), TRUE },
151 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eflags), FIELD_OFFSET (CONTEXT, EFlags), TRUE },
152 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Cs), FIELD_OFFSET (CONTEXT, SegCs), TRUE },
153 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ss), FIELD_OFFSET (CONTEXT, SegSs), TRUE },
154 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ds), FIELD_OFFSET (CONTEXT, SegDs), TRUE },
155 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Es), FIELD_OFFSET (CONTEXT, SegEs), TRUE },
156 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Fs), FIELD_OFFSET (CONTEXT, SegFs), TRUE },
157 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Gs), FIELD_OFFSET (CONTEXT, SegGs), TRUE }
160 static PCHAR GspThreadStates[THREAD_STATE_MAX] =
162 "Initialized", /* THREAD_STATE_INITIALIZED */
163 "Ready", /* THREAD_STATE_READY */
164 "Running", /* THREAD_STATE_RUNNING */
165 "Suspended", /* THREAD_STATE_SUSPENDED */
166 "Frozen", /* THREAD_STATE_FROZEN */
167 "Terminated 1", /* THREAD_STATE_TERMINATED_1 */
168 "Terminated 2", /* THREAD_STATE_TERMINATED_2 */
169 "Blocked" /* THREAD_STATE_BLOCKED */
173 strtok(char *s, const char *delim)
181 if (s == NULL && (s = last) == NULL)
185 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
189 for (spanp = delim; (sc = *spanp++) != 0;) {
194 if (c == 0) { /* no non-delimiter characters */
201 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
202 * Note that delim must have one NUL; we stop if we see that, too.
208 if ((sc = *spanp++) == c) {
225 if ((ch >= '0') && (ch <= '9')) return (ch - '0');
226 if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
227 if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
231 static CHAR GspInBuffer[BUFMAX];
232 static CHAR GspOutBuffer[BUFMAX];
234 /* scan for the sequence $<data>#<Checksum> */
239 PCHAR Buffer = &GspInBuffer[0];
247 /* wait around for the start character, ignore all other characters */
248 while ((ch = KdGetChar ()) != '$');
255 /* now, read until a # or end of Buffer is found */
256 while (Count < BUFMAX)
263 Checksum = Checksum + ch;
272 XmitChecksum = HexValue (ch) << 4;
274 XmitChecksum += HexValue (ch);
276 if (Checksum != XmitChecksum)
278 KdPutChar ('-'); /* failed checksum */
282 KdPutChar ('+'); /* successful transfer */
284 /* if a sequence char is present, reply the sequence ID */
285 if (Buffer[2] == ':')
287 KdPutChar (Buffer[0]);
288 KdPutChar (Buffer[1]);
299 /* send the packet in Buffer. */
302 GspPutPacket (PCHAR Buffer)
308 /* $<packet info>#<Checksum>. */
315 while ((ch = Buffer[Count]))
323 KdPutChar (HexChars[(Checksum >> 4) & 0xf]);
324 KdPutChar (HexChars[Checksum & 0xf]);
326 while (KdGetChar () != '+');
331 GspPutPacketNoWait (PCHAR Buffer)
337 /* $<packet info>#<Checksum>. */
342 while ((ch = Buffer[Count]))
350 KdPutChar (HexChars[(Checksum >> 4) & 0xf]);
351 KdPutChar (HexChars[Checksum & 0xf]);
354 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
356 static volatile BOOLEAN GspMemoryError = FALSE;
357 static volatile void *GspAccessLocation = NULL;
360 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
361 /* Return a pointer to the last char put in Buffer (null) */
362 /* If MayFault is TRUE, then we should set GspMemoryError in response to
363 a fault; if FALSE treat a fault like any other fault in the stub. */
365 GspMem2Hex (PCHAR Address,
373 if (NULL == Address && MayFault)
375 GspMemoryError = TRUE;
379 for (i = 0; i < (ULONG) Count; i++)
382 GspAccessLocation = Address;
384 GspAccessLocation = NULL;
385 if (MayFault && GspMemoryError)
387 *Buffer++ = HexChars[(ch >> 4) & 0xf];
388 *Buffer++ = HexChars[ch & 0xf];
396 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
397 /* Return a pointer to the character AFTER the last byte read from Buffer */
399 GspHex2Mem (PCHAR Buffer,
412 while ( current < Address + Count )
414 page = (PCHAR)PAGE_ROUND_DOWN (current);
415 if (Address + Count <= page + PAGE_SIZE)
417 /* Fits in this page */
422 /* Flows into next page, handle only current page in this iteration */
423 countinpage = PAGE_SIZE - (Address - page);
427 oldprot = MmGetPageProtect (NULL, Address);
428 MmSetPageProtect (NULL, Address, PAGE_EXECUTE_READWRITE);
431 for (i = 0; i < countinpage && ! GspMemoryError; i++)
433 ch = HexValue (*Buffer++) << 4;
434 ch = ch + HexValue (*Buffer++);
436 GspAccessLocation = Address;
438 GspAccessLocation = NULL;
443 MmSetPageProtect (NULL, page, oldprot);
453 /* This function takes the 386 exception vector and attempts to
454 translate this number into a unix compatible signal value */
456 GspComputeSignal (NTSTATUS ExceptionCode)
460 switch (ExceptionCode)
462 case STATUS_INTEGER_DIVIDE_BY_ZERO:
464 break; /* divide by zero */
465 case STATUS_SINGLE_STEP:
466 /* debug exception */
467 case STATUS_BREAKPOINT:
469 break; /* breakpoint */
470 case STATUS_INTEGER_OVERFLOW:
471 /* into instruction (overflow) */
472 case STATUS_ARRAY_BOUNDS_EXCEEDED:
474 break; /* bound instruction */
475 case STATUS_ILLEGAL_INSTRUCTION:
477 break; /* Invalid opcode */
479 case STATUS_FLT_INVALID_OPERATION:
481 break; /* coprocessor not available */
483 case STATUS_STACK_OVERFLOW:
484 /* stack exception */
485 case STATUS_DATATYPE_MISALIGNMENT:
487 case STATUS_ACCESS_VIOLATION:
488 SigVal = 11; /* access violation */
491 SigVal = 7; /* "software generated" */
497 /**********************************************/
498 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
499 /* RETURN NUMBER OF CHARS PROCESSED */
500 /**********************************************/
502 GspHex2Long (PCHAR *Address,
512 Hex = HexValue (**Address);
515 *Value = (*Value << 4) | Hex;
529 GspLong2Hex (PCHAR *Address,
534 Save = (((Value >> 0) & 0xff) << 24) |
535 (((Value >> 8) & 0xff) << 16) |
536 (((Value >> 16) & 0xff) << 8) |
537 (((Value >> 24) & 0xff) << 0);
538 *Address = GspMem2Hex ((PCHAR) &Save, *Address, 4, FALSE);
543 * Esp is not stored in the trap frame, although there is a member with it's name.
544 * Instead, it was pointing to the location of the TrapFrame Esp member when the
548 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame)
550 return (LONG) &TrapFrame->Esp;
555 GspGetRegistersFromTrapFrame(PCHAR Address,
557 PKTRAP_FRAME TrapFrame)
565 for (i = 0; i < sizeof (GspRegisters) / sizeof (GspRegisters[0]); i++)
571 Value = GspGetEspFromTrapFrame (TrapFrame);
575 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
579 else if (i == EIP_REGNO)
582 * This thread has not been sheduled yet so assume it
583 * is still in PsBeginThreadWithContextInternal().
585 Value = (ULONG) PsBeginThreadWithContextInternal;
591 Buffer = GspMem2Hex ((PCHAR) &Value, Buffer, GspRegisters[i].Size, FALSE);
597 GspSetRegistersInTrapFrame(PCHAR Address,
599 PKTRAP_FRAME TrapFrame)
610 for (i = 0; i < NUMREGS; i++)
612 if (GspRegisters[i].SetInContext)
613 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[i].OffsetInContext);
615 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
617 Buffer = GspHex2Mem (Buffer, (PCHAR) &Value, GspRegisters[i].Size, FALSE);
624 GspSetSingleRegisterInTrapFrame(PCHAR Address,
627 PKTRAP_FRAME TrapFrame)
635 if (GspRegisters[Number].SetInContext)
636 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[Number].OffsetInContext);
638 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[Number].OffsetInTF);
640 GspHex2Mem (Address, (PCHAR) &Value, GspRegisters[Number].Size, FALSE);
646 GspFindThread(PCHAR Data,
649 PETHREAD ThreadInfo = NULL;
651 if (strcmp (Data, "-1") == 0)
656 else if (strcmp (Data, "0") == 0)
658 /* Pick any thread, pick the first thread,
659 * which is what most people are interested in
661 ThreadInfo = CONTAINING_RECORD (PiThreadListHead.Flink,
662 ETHREAD, Tcb.ThreadListEntry);
667 PCHAR ptr = &Data[0];
669 GspHex2Long (&ptr, (PLONG) &ThreadId);
671 if (!NT_SUCCESS (PsLookupThreadByThreadId ((PVOID) ThreadId, &ThreadInfo)))
677 *Thread = ThreadInfo;
683 GspSetThread(PCHAR Request)
686 PCHAR ptr = &Request[1];
690 case 'c': /* Run thread */
691 if (GspFindThread (ptr, &ThreadInfo))
693 GspOutBuffer[0] = 'O';
694 GspOutBuffer[1] = 'K';
696 if(GspRunThread) ObDereferenceObject(GspRunThread);
698 GspRunThread = ThreadInfo;
702 GspOutBuffer[0] = 'E';
705 case 'g': /* Debug thread */
706 if (GspFindThread (ptr, &ThreadInfo))
708 GspOutBuffer[0] = 'O';
709 GspOutBuffer[1] = 'K';
711 if(GspDbgThread) ObDereferenceObject(GspDbgThread);
713 GspDbgThread = ThreadInfo;
717 GspOutBuffer[0] = 'E';
727 GspQuery(PCHAR Request)
732 Command = strtok (Request, ",");
733 if (strncmp (Command, "C", 1) == 0)
735 PCHAR ptr = &GspOutBuffer[2];
737 /* Get current thread id */
738 GspOutBuffer[0] = 'Q';
739 GspOutBuffer[1] = 'C';
740 if (NULL != GspDbgThread)
742 Value = (ULONG) GspDbgThread->Cid.UniqueThread;
746 Value = (ULONG) PsGetCurrentThread()->Cid.UniqueThread;
748 GspLong2Hex (&ptr, Value);
750 else if (strncmp (Command, "fThreadInfo", 11) == 0)
752 PCHAR ptr = &GspOutBuffer[1];
754 /* Get first thread id */
755 GspOutBuffer[0] = 'm';
756 GspEnumThread = CONTAINING_RECORD (PiThreadListHead.Flink,
757 ETHREAD, Tcb.ThreadListEntry);
758 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
759 GspLong2Hex (&ptr, Value);
761 else if (strncmp (Command, "sThreadInfo", 11) == 0)
763 PCHAR ptr = &GspOutBuffer[1];
765 /* Get next thread id */
766 if ((GspEnumThread) && (GspEnumThread->Tcb.ThreadListEntry.Flink != PiThreadListHead.Flink))
768 GspEnumThread = CONTAINING_RECORD (GspEnumThread->Tcb.ThreadListEntry.Flink,
769 ETHREAD, Tcb.ThreadListEntry);
770 GspOutBuffer[0] = 'm';
771 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
772 GspLong2Hex (&ptr, Value);
776 GspOutBuffer[0] = 'l';
779 else if (strncmp (Command, "ThreadExtraInfo", 15) == 0)
782 PCHAR ptr = &Command[15];
784 /* Get thread information */
785 if (GspFindThread (ptr, &ThreadInfo))
787 PCHAR String = GspThreadStates[ThreadInfo->Tcb.State];
789 ObDereferenceObject(ThreadInfo);
791 GspMem2Hex (String, &GspOutBuffer[0], strlen (String), FALSE);
795 else if (strncmp (Command, "L", 1) == 0)
797 PLIST_ENTRY CurrentEntry;
799 ULONG MaxThreads = 0;
801 ULONG ThreadCount = 0;
804 GspHex2Mem (&Request[1], (PCHAR) &MaxThreads, 2, TRUE);
805 GspHex2Mem (&Request[3], (PCHAR) &Value, 4, TRUE);
806 GspHex2Mem (&Request[11], (PCHAR) &ThreadId, 4, TRUE);
808 GspOutBuffer[0] = 'q';
809 GspOutBuffer[1] = 'M';
811 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[5], 4, TRUE);
812 GspMem2Hex ((PCHAR) &ThreadId, &GspOutBuffer[13], 4, TRUE);
814 CurrentEntry = PiThreadListHead.Flink;
815 while ((CurrentEntry != &PiThreadListHead) && (ThreadCount < MaxThreads))
817 Current = CONTAINING_RECORD (CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
819 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16], 4, TRUE);
820 Value = (ULONG) Current->Cid.UniqueThread;
821 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16+8], 4, TRUE);
822 CurrentEntry = CurrentEntry->Flink;
826 if (CurrentEntry != &PiThreadListHead)
828 GspOutBuffer[4] = '0';
832 GspOutBuffer[4] = '1';
835 GspMem2Hex ((PCHAR) &ThreadCount, &GspOutBuffer[2], 1, TRUE);
838 else if (strncmp (Command, "Offsets", 7) == 0)
840 strcpy (GspOutBuffer, "Text=0;Data=0;Bss=0");
845 GspQueryThreadStatus(PCHAR Request)
848 PCHAR ptr = &Request[0];
850 if (GspFindThread (ptr, &ThreadInfo))
852 ObDereferenceObject(ThreadInfo);
854 GspOutBuffer[0] = 'O';
855 GspOutBuffer[1] = 'K';
856 GspOutBuffer[2] = '\0';
860 GspOutBuffer[0] = 'E';
861 GspOutBuffer[1] = '\0';
866 typedef struct _GsHwBreakPoint
874 GsHwBreakPoint GspBreakpoints[4] =
883 GspCorrectHwBreakpoint()
885 ULONG BreakpointNumber;
891 "movl %%db7, %0\n" : "=r" (dr7) : );
894 ULONG addr0, addr1, addr2, addr3;
901 : "=r" (addr0), "=r" (addr1),
902 "=r" (addr2), "=r" (addr3) : );
905 for (BreakpointNumber = 0; BreakpointNumber < 3; BreakpointNumber++)
907 Bit = 2 << (BreakpointNumber << 1);
908 if (!(dr7 & Bit) && GspBreakpoints[BreakpointNumber].Enabled) {
911 dr7 &= ~(0xf0000 << (BreakpointNumber << 2));
912 dr7 |= (((GspBreakpoints[BreakpointNumber].Length << 2) |
913 GspBreakpoints[BreakpointNumber].Type) << 16) << (BreakpointNumber << 2);
914 switch (BreakpointNumber) {
916 asm volatile ("movl %0, %%dr0\n"
917 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
921 asm volatile ("movl %0, %%dr1\n"
922 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
926 asm volatile ("movl %0, %%dr2\n"
927 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
931 asm volatile ("movl %0, %%dr3\n"
932 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
936 else if ((dr7 & Bit) && !GspBreakpoints[BreakpointNumber].Enabled)
940 dr7 &= ~(0xf0000 << (BreakpointNumber << 2));
945 asm volatile ( "movl %0, %%db7\n" : : "r" (dr7));
950 GspRemoveHwBreakpoint(ULONG BreakpointNumber)
952 if (!GspBreakpoints[BreakpointNumber].Enabled)
956 GspBreakpoints[BreakpointNumber].Enabled = 0;
962 GspSetHwBreakpoint(ULONG BreakpointNumber,
967 if (GspBreakpoints[BreakpointNumber].Enabled)
971 GspBreakpoints[BreakpointNumber].Enabled = TRUE;
972 GspBreakpoints[BreakpointNumber].Type = Type;
973 GspBreakpoints[BreakpointNumber].Length = Length;
974 GspBreakpoints[BreakpointNumber].Address = Address;
980 * This function does all command procesing for interfacing to gdb.
983 KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
985 PKTRAP_FRAME TrapFrame)
995 /* FIXME: Stop on other CPUs too */
996 /* Disable hardware debugging while we are inside the stub */
997 __asm__("movl %0,%%db7" : /* no output */ : "r" (0));
999 if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode &&
1000 NULL != GspAccessLocation &&
1001 (ULONG_PTR) GspAccessLocation ==
1002 (ULONG_PTR) ExceptionRecord->ExceptionInformation[1])
1004 GspAccessLocation = NULL;
1005 GspMemoryError = TRUE;
1010 /* reply to host that an exception has occurred */
1011 SigVal = GspComputeSignal (ExceptionRecord->ExceptionCode);
1013 ptr = &GspOutBuffer[0];
1015 *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
1016 *ptr++ = HexChars[(SigVal >> 4) & 0xf];
1017 *ptr++ = HexChars[SigVal & 0xf];
1019 *ptr++ = HexChars[ESP];
1022 Esp = GspGetEspFromTrapFrame (TrapFrame); /* SP */
1023 ptr = GspMem2Hex ((PCHAR) &Esp, ptr, 4, 0);
1026 *ptr++ = HexChars[EBP];
1028 ptr = GspMem2Hex ((PCHAR) &TrapFrame->Ebp, ptr, 4, 0); /* FP */
1031 *ptr++ = HexChars[PC];
1033 ptr = GspMem2Hex((PCHAR) &TrapFrame->Eip, ptr, 4, 0); /* PC */
1038 GspPutPacket (&GspOutBuffer[0]);
1044 /* Zero the buffer now so we don't have to worry about the terminating zero character */
1045 memset (GspOutBuffer, 0, sizeof (GspInBuffer));
1046 ptr = GspGetPacket ();
1051 GspOutBuffer[0] = 'S';
1052 GspOutBuffer[1] = HexChars[SigVal >> 4];
1053 GspOutBuffer[2] = HexChars[SigVal % 16];
1054 GspOutBuffer[3] = 0;
1057 GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
1059 case 'g': /* return the value of the CPU Registers */
1061 GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, GspDbgThread->Tcb.TrapFrame);
1063 GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, TrapFrame);
1065 case 'G': /* set the value of the CPU Registers - return OK */
1067 /* GspSetRegistersInTrapFrame (ptr, Context, GspDbgThread->Tcb.TrapFrame);*/
1068 GspSetRegistersInTrapFrame (ptr, Context, TrapFrame);
1070 GspSetRegistersInTrapFrame (ptr, Context, TrapFrame);
1071 strcpy (GspOutBuffer, "OK");
1073 case 'P': /* set the value of a single CPU register - return OK */
1077 if ((GspHex2Long (&ptr, &Register)) && (*ptr++ == '='))
1078 if ((Register >= 0) && (Register < NUMREGS))
1081 /* GspSetSingleRegisterInTrapFrame (ptr, Register,
1082 Context, GspDbgThread->Tcb.TrapFrame);*/
1083 GspSetSingleRegisterInTrapFrame (ptr, Register, Context, TrapFrame);
1085 GspSetSingleRegisterInTrapFrame (ptr, Register, Context, TrapFrame);
1086 strcpy (GspOutBuffer, "OK");
1090 strcpy (GspOutBuffer, "E01");
1094 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1096 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1097 if (GspHex2Long (&ptr, &Address))
1098 if (*(ptr++) == ',')
1099 if (GspHex2Long (&ptr, &Length))
1102 GspMemoryError = FALSE;
1103 GspMem2Hex ((PCHAR) Address, GspOutBuffer, Length, 1);
1106 strcpy (GspOutBuffer, "E03");
1107 DPRINT ("Fault during memory read\n");
1112 strcpy (GspOutBuffer, "E01");
1115 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1117 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1118 if (GspHex2Long (&ptr, &Address))
1119 if (*(ptr++) == ',')
1120 if (GspHex2Long (&ptr, &Length))
1121 if (*(ptr++) == ':')
1123 GspMemoryError = FALSE;
1124 GspHex2Mem (ptr, (PCHAR) Address, Length, TRUE);
1128 strcpy (GspOutBuffer, "E03");
1129 DPRINT ("Fault during memory write\n");
1133 strcpy (GspOutBuffer, "OK");
1139 strcpy (GspOutBuffer, "E02");
1142 /* cAA..AA Continue at address AA..AA(optional) */
1143 /* sAA..AA Step one instruction from AA..AA(optional) */
1148 ULONG BreakpointNumber;
1151 /* try to read optional parameter, pc unchanged if no parm */
1152 if (GspHex2Long (&ptr, &Address))
1153 Context->Eip = Address;
1155 NewPC = Context->Eip;
1157 /* clear the trace bit */
1158 Context->EFlags &= 0xfffffeff;
1160 /* set the trace bit if we're Stepping */
1162 Context->EFlags |= 0x100;
1164 asm volatile ("movl %%db6, %0\n" : "=r" (dr6) : );
1165 if (!(dr6 & 0x4000))
1167 for (BreakpointNumber = 0; BreakpointNumber < 4; ++BreakpointNumber)
1169 if (dr6 & (1 << BreakpointNumber))
1171 if (GspBreakpoints[BreakpointNumber].Type == 0)
1173 /* Set restore flag */
1174 Context->EFlags |= 0x10000;
1180 GspCorrectHwBreakpoint();
1181 asm volatile ("movl %0, %%db6\n" : : "r" (0));
1183 return kdHandleException;
1187 case 'k': /* kill the program */
1188 strcpy (GspOutBuffer, "OK");
1190 /* kill the program */
1192 case 'H': /* Set thread */
1196 case 'q': /* Query */
1200 case 'T': /* Query thread status */
1201 GspQueryThreadStatus (ptr);
1211 ptr = &GspOutBuffer[1];
1212 GspHex2Long (&ptr, &Number);
1214 GspHex2Long (&ptr, &Type);
1216 GspHex2Long (&ptr, &Length);
1218 GspHex2Long (&ptr, &Address);
1219 if (GspSetHwBreakpoint (Number & 0x3, Type & 0x3 , Length & 0x3, Address) == 0)
1221 strcpy (GspOutBuffer, "OK");
1225 strcpy (GspOutBuffer, "E");
1230 /* Remove hardware breakpoint */
1235 ptr = &GspOutBuffer[1];
1236 GspHex2Long(&ptr, &Number);
1237 if (GspRemoveHwBreakpoint (Number & 0x3) == 0)
1239 strcpy (GspOutBuffer, "OK");
1243 strcpy (GspOutBuffer, "E");
1252 /* reply to the request */
1253 GspPutPacket (&GspOutBuffer[0]);
1257 return kdHandleException;
1263 GspBreakIn(PKINTERRUPT Interrupt,
1264 PVOID ServiceContext)
1266 PKTRAP_FRAME TrapFrame;
1272 DPRINT ("Break In\n");
1275 while (KdPortGetByteEx (&GdbPortInfo, &Value))
1284 KeRaiseIrql (HIGH_LEVEL, &OldIrql);
1286 TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
1288 KeTrapFrameToContext (TrapFrame, &Context);
1290 KdEnterDebuggerException (NULL, &Context, TrapFrame);
1292 KeContextToTrapFrame (&Context, TrapFrame);
1294 KeLowerIrql (OldIrql);
1300 extern ULONG KdpPortIrq;
1302 /* Initialize the GDB stub */
1304 KdGdbStubInit(ULONG Phase)
1315 DbgPrint("Module 'hal.dll' loaded at 0x%.08x.\n", LdrHalBase);
1317 GspInitialized = TRUE;
1318 GspRunThread = PsGetCurrentThread();
1320 ObReferenceObject(GspRunThread);
1322 /* GspDbgThread = PsGetCurrentThread(); */
1323 GspDbgThread = NULL;
1324 GspEnumThread = NULL;
1326 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
1328 else if (Phase == 1)
1331 /* Hook an interrupt handler to allow the debugger to break into
1333 MappedIrq = HalGetInterruptVector (Internal,
1340 Status = IoConnectInterrupt(&GspInterrupt,
1351 if (!NT_SUCCESS (Status))
1353 DPRINT1("Could not connect to IRQ line %d (0x%x)\n",
1354 KdpPortIrq, Status);
1358 KdPortEnableInterrupts();
1360 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
1367 KdGdbDebugPrint(LPSTR Message)
1370 /* This can be quite annoying! */
1375 GspOutBuffer[0] = 'O';
1376 GspOutBuffer[1] = '\0';
1377 strcat (&GspOutBuffer[0], Message);
1378 Length = strlen (Message);
1379 GspOutBuffer[2 + Length] = '\n';
1380 GspOutBuffer[3 + Length] = '\0';
1381 GspPutPacketNoWait (&GspOutBuffer[0]);
1384 HalDisplayString(Message);
1389 extern LIST_ENTRY ModuleListHead;
1394 PLIST_ENTRY CurrentEntry;
1395 PMODULE_OBJECT Current;
1402 CurrentEntry = ModuleListHead.Flink;
1403 while (CurrentEntry != (&ModuleListHead))
1405 Current = CONTAINING_RECORD (CurrentEntry, MODULE_OBJECT, ListEntry);
1407 DbgPrint ("Module %S Base 0x%.08x Length 0x%.08x\n",
1408 Current->BaseName.Buffer, Current->Base, Current->Length);
1411 CurrentEntry = CurrentEntry->Flink;
1414 DbgPrint ("%d modules listed\n", ModuleCount);