ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

gdbstub.c
Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003    THIS SOFTWARE IS NOT COPYRIGHTED
00004 
00005    HP offers the following for use in the public domain.  HP makes no
00006    warranty with regard to the software or it's performance and the
00007    user accepts the software "AS IS" with all faults.
00008 
00009    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
00010    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00011    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00012 
00013 ****************************************************************************/
00014 /****************************************************************************
00015  *  Contributor:     Lake Stevens Instrument Division$
00016  *
00017  *  Description:     low level support for gdb debugger. $
00018  *
00019  *  Written by:      Glenn Engel $
00020  *  ModuleState:     Experimental $
00021  *
00022  *  Modified for 386 by Jim Kingdon, Cygnus Support.
00023  *  Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
00024  *
00025  ****************************************************************************/
00026 
00027 #include <ntoskrnl.h>
00028 #define NDEBUG
00029 #include <debug.h>
00030 
00031 /************************************************************************/
00032 
00033 static BOOLEAN GspInitialized;
00034 static BOOLEAN GspRemoteDebug;
00035 
00036 static CONST CHAR HexChars[] = "0123456789abcdef";
00037 
00038 static PETHREAD GspRunThread;   /* NULL means run all threads */
00039 static PETHREAD GspDbgThread;
00040 static PETHREAD GspEnumThread;
00041 
00042 static FAST_MUTEX GspLock;
00043 
00044 extern LIST_ENTRY PsActiveProcessHead;
00045 
00046 /* FIXME hardcoded for COM2, 115200 baud */
00047 KD_PORT_INFORMATION GdbPortInfo = { 2, 115200, 0 };
00048 
00049 static CHAR GspInBuffer[1000];
00050 static CHAR GspOutBuffer[1000];
00051 
00052 /* Number of Registers.  */
00053 #define NUMREGS 16
00054 
00055 enum REGISTER_NAMES
00056 {
00057     EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
00058     PC /* also known as eip */ ,
00059     PS /* also known as eflags */ ,
00060     CS, SS, DS, ES, FS, GS
00061 };
00062 
00063 typedef struct _CPU_REGISTER
00064 {
00065     ULONG Size;
00066     ULONG OffsetInTF;
00067     ULONG OffsetInContext;
00068     BOOLEAN SetInContext;
00069 } CPU_REGISTER, *PCPU_REGISTER;
00070 
00071 static CPU_REGISTER GspRegisters[NUMREGS] =
00072 {
00073     { 4, FIELD_OFFSET(KTRAP_FRAME, Eax), FIELD_OFFSET(CONTEXT, Eax), TRUE },
00074     { 4, FIELD_OFFSET(KTRAP_FRAME, Ecx), FIELD_OFFSET(CONTEXT, Ecx), TRUE },
00075     { 4, FIELD_OFFSET(KTRAP_FRAME, Edx), FIELD_OFFSET(CONTEXT, Edx), FALSE },
00076     { 4, FIELD_OFFSET(KTRAP_FRAME, Ebx), FIELD_OFFSET(CONTEXT, Ebx), TRUE },
00077     { 4, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp), FIELD_OFFSET(CONTEXT, Esp), TRUE },
00078     { 4, FIELD_OFFSET(KTRAP_FRAME, DbgEbp), FIELD_OFFSET(CONTEXT, Ebp), TRUE },
00079     { 4, FIELD_OFFSET(KTRAP_FRAME, Esi), FIELD_OFFSET(CONTEXT, Esi), TRUE },
00080     { 4, FIELD_OFFSET(KTRAP_FRAME, Edi), FIELD_OFFSET(CONTEXT, Edi), TRUE },
00081     { 4, FIELD_OFFSET(KTRAP_FRAME, DbgEip), FIELD_OFFSET(CONTEXT, Eip), TRUE },
00082     { 4, FIELD_OFFSET(KTRAP_FRAME, EFlags), FIELD_OFFSET(CONTEXT, EFlags), TRUE },
00083     { 4, FIELD_OFFSET(KTRAP_FRAME, SegCs), FIELD_OFFSET(CONTEXT, SegCs), TRUE },
00084     { 4, FIELD_OFFSET(KTRAP_FRAME, HardwareSegSs), FIELD_OFFSET(CONTEXT, SegSs), TRUE },
00085     { 4, FIELD_OFFSET(KTRAP_FRAME, SegDs), FIELD_OFFSET(CONTEXT, SegDs), TRUE },
00086     { 4, FIELD_OFFSET(KTRAP_FRAME, SegEs), FIELD_OFFSET(CONTEXT, SegEs), TRUE },
00087     { 4, FIELD_OFFSET(KTRAP_FRAME, SegFs), FIELD_OFFSET(CONTEXT, SegFs), TRUE },
00088     { 4, FIELD_OFFSET(KTRAP_FRAME, SegGs), FIELD_OFFSET(CONTEXT, SegGs), TRUE }
00089 };
00090 
00091 static PCHAR GspThreadStates[DeferredReady + 1] =
00092 {
00093     "Initialized",
00094     "Ready",
00095     "Running",
00096     "Standby",
00097     "Terminated",
00098     "Waiting",
00099     "Transition",
00100     "DeferredReady"
00101 };
00102 
00103 LONG
00104 HexValue(CHAR ch)
00105 {
00106     if ((ch >= '0') && (ch <= '9'))
00107         return (ch - '0');
00108 
00109     if ((ch >= 'a') && (ch <= 'f'))
00110         return (ch - 'a' + 10);
00111 
00112     if ((ch >= 'A') && (ch <= 'F'))
00113         return (ch - 'A' + 10);
00114 
00115     return -1;
00116 }
00117 
00118 VOID
00119 GdbPutChar(UCHAR Value)
00120 {
00121     KdPortPutByteEx(&GdbPortInfo, Value);
00122 }
00123 
00124 UCHAR
00125 GdbGetChar(VOID)
00126 {
00127     UCHAR Value;
00128 
00129     while (!KdPortGetByteEx(&GdbPortInfo, &Value))
00130         ;
00131 
00132     return Value;
00133 }
00134 
00135 /* scan for the sequence $<data>#<Checksum> */
00136 PCHAR
00137 GspGetPacket()
00138 {
00139     PCHAR Buffer = &GspInBuffer[0];
00140     CHAR Checksum;
00141     CHAR XmitChecksum;
00142     ULONG Count;
00143     CHAR ch;
00144 
00145     while (TRUE)
00146     {
00147         /* wait around for the start character, ignore all other characters */
00148         while ((ch = GdbGetChar()) != '$')
00149             ;
00150 
00151 retry:
00152         Checksum = 0;
00153         XmitChecksum = -1;
00154         Count = 0;
00155 
00156         /* now, read until a # or end of Buffer is found */
00157         while (Count < sizeof(GspInBuffer) - 1)
00158         {
00159             ch = GdbGetChar();
00160             if (ch == '$')
00161                 goto retry;
00162 
00163             if (ch == '#')
00164                 break;
00165 
00166             Checksum = Checksum + ch;
00167             Buffer[Count] = ch;
00168             Count = Count + 1;
00169         }
00170         Buffer[Count] = 0;
00171 
00172         if (ch == '#')
00173         {
00174             ch = GdbGetChar();
00175             XmitChecksum = (CHAR)(HexValue(ch) << 4);
00176             ch = GdbGetChar();
00177             XmitChecksum += (CHAR)(HexValue(ch));
00178 
00179             if (Checksum != XmitChecksum)
00180             {
00181                 GdbPutChar('-'); /* failed checksum */
00182             }
00183             else
00184             {
00185                 GdbPutChar('+'); /* successful transfer */
00186                 return &Buffer[0];
00187             }
00188         }
00189     }
00190 }
00191 
00192 /* send the packet in Buffer. */
00193 VOID
00194 GspPutPacket(PCHAR Buffer)
00195 {
00196     CHAR Checksum;
00197     LONG Count;
00198     CHAR ch;
00199 
00200     /* $<packet info>#<Checksum>. */
00201     do
00202     {
00203         GdbPutChar('$');
00204         Checksum = 0;
00205         Count = 0;
00206 
00207         while ((ch = Buffer[Count]))
00208         {
00209             GdbPutChar(ch);
00210             Checksum += ch;
00211             Count += 1;
00212         }
00213 
00214         GdbPutChar('#');
00215         GdbPutChar(HexChars[(Checksum >> 4) & 0xf]);
00216         GdbPutChar(HexChars[Checksum & 0xf]);
00217     }
00218     while (GdbGetChar() != '+');
00219 }
00220 
00221 VOID
00222 GspPutPacketNoWait(PCHAR Buffer)
00223 {
00224     CHAR Checksum;
00225     LONG Count;
00226     CHAR ch;
00227 
00228     /* $<packet info>#<Checksum>. */
00229     GdbPutChar('$');
00230     Checksum = 0;
00231     Count = 0;
00232 
00233     while ((ch = Buffer[Count]))
00234     {
00235         GdbPutChar(ch);
00236         Checksum += ch;
00237         Count += 1;
00238     }
00239 
00240     GdbPutChar('#');
00241     GdbPutChar(HexChars[(Checksum >> 4) & 0xf]);
00242     GdbPutChar(HexChars[Checksum & 0xf]);
00243 }
00244 
00245 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an error. */
00246 static volatile BOOLEAN GspMemoryError = FALSE;
00247 
00248 static CHAR
00249 GspReadMemSafe(PCHAR Address)
00250 {
00251     CHAR ch = 0;
00252 
00253     if (!KdpSafeReadMemory((ULONG_PTR)Address, 1, &ch))
00254         GspMemoryError = TRUE;
00255 
00256     return ch;
00257 }
00258 
00259 static void
00260 GspWriteMemSafe(PCHAR Address, CHAR Ch)
00261 {
00262     if (!KdpSafeWriteMemory((ULONG_PTR)Address, 1, Ch))
00263         GspMemoryError = TRUE;
00264 }
00265 
00266 /* Convert the memory pointed to by Address into hex, placing result in Buffer
00267  * Return a pointer to the last char put in Buffer (null)
00268  * If MayFault is TRUE, then we should set GspMemoryError in response to
00269  * a fault; if FALSE treat a fault like any other fault in the stub.
00270  */
00271 static PCHAR
00272 GspMem2Hex(PCHAR Address, PCHAR Buffer, LONG Count, BOOLEAN MayFault)
00273 {
00274     ULONG i;
00275     CHAR ch;
00276 
00277     for (i = 0; i < (ULONG)Count; i++)
00278     {
00279         if (MayFault)
00280         {
00281             ch = GspReadMemSafe(Address);
00282             if (GspMemoryError)
00283                 return Buffer;
00284         }
00285         else
00286         {
00287             ch = *Address;
00288         }
00289         *Buffer++ = HexChars[(ch >> 4) & 0xf];
00290         *Buffer++ = HexChars[ch & 0xf];
00291         Address++;
00292     }
00293 
00294     *Buffer = 0;
00295     return Buffer;
00296 }
00297 
00298 static ULONG
00299 GspWriteMem(PCHAR Address, ULONG Count, BOOLEAN MayFault,
00300             CHAR (*GetContent)(PVOID Context, ULONG Offset), PVOID Context)
00301 {
00302     PCHAR Current;
00303     PCHAR Page;
00304     ULONG CountInPage;
00305     ULONG i;
00306     CHAR ch;
00307 
00308     Current = Address;
00309     while (Current < Address + Count)
00310     {
00311         Page = (PCHAR)PAGE_ROUND_DOWN(Current);
00312         if (Address + Count <= Page + PAGE_SIZE)
00313         {
00314             /* Fits in this page */
00315             CountInPage = Count;
00316         }
00317         else
00318         {
00319             /* Flows into next page, handle only current page in this iteration */
00320             CountInPage = PAGE_SIZE - (Address - Page);
00321         }
00322 
00323         for (i = 0; i < CountInPage && !GspMemoryError; i++)
00324         {
00325             ch = (*GetContent)(Context, Current - Address);
00326 
00327             if (MayFault)
00328                 GspWriteMemSafe(Current, ch);
00329             else
00330                 *Current = ch;
00331 
00332             Current++;
00333         }
00334         if (MayFault)
00335         {
00336             if (GspMemoryError)
00337                 return Current - Address;
00338         }
00339     }
00340 
00341     return Current - Address;
00342 }
00343 
00344 static CHAR
00345 GspHex2MemGetContent(PVOID Context, ULONG Offset)
00346 {
00347     return (CHAR)((HexValue(*((PCHAR)Context + 2 * Offset)) << 4) +
00348                    HexValue(*((PCHAR)Context + 2 * Offset + 1)));
00349 }
00350 
00351 /* Convert the hex array pointed to by Buffer into binary to be placed at Address
00352  * Return a pointer to the character AFTER the last byte read from Buffer */
00353 static PCHAR
00354 GspHex2Mem(PCHAR Buffer, PCHAR Address, ULONG Count, BOOLEAN MayFault)
00355 {
00356     Count = GspWriteMem(Address, Count, MayFault, GspHex2MemGetContent, Buffer);
00357     return Buffer + 2 * Count;
00358 }
00359 
00360 /**********************************************/
00361 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
00362 /* RETURN NUMBER OF CHARS PROCESSED           */
00363 /**********************************************/
00364 LONG
00365 GspHex2Long(PCHAR *Address, PLONG Value)
00366 {
00367     LONG NumChars = 0;
00368     LONG Hex;
00369 
00370     *Value = 0;
00371 
00372     while (**Address)
00373     {
00374         Hex = HexValue(**Address);
00375         if (Hex >= 0)
00376         {
00377             *Value = (*Value << 4) | Hex;
00378             NumChars++;
00379         }
00380         else
00381         {
00382             break;
00383         }
00384 
00385         (*Address)++;
00386     }
00387 
00388     return NumChars;
00389 }
00390 
00391 VOID
00392 GspLong2Hex(PCHAR *Address, LONG Value)
00393 {
00394     LONG Save;
00395 
00396     Save = (((Value >> 0) & 0xff) << 24) | (((Value >> 8) & 0xff) << 16) |
00397            (((Value >> 16) & 0xff) << 8) | (((Value >> 24) & 0xff) << 0);
00398 
00399     *Address = GspMem2Hex((PCHAR)&Save, *Address, 4, FALSE);
00400 }
00401 
00402 /*
00403  * When coming from kernel mode, Esp is not stored in the trap frame.
00404  * Instead, it was pointing to the location of the TrapFrame Esp member
00405  * when the exception occured. When coming from user mode, Esp is just
00406  * stored in the TrapFrame Esp member.
00407  */
00408 static LONG
00409 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame)
00410 {
00411     return KeGetPreviousMode() == KernelMode ?
00412            (LONG)&TrapFrame->HardwareEsp : (LONG)TrapFrame->HardwareEsp;
00413 }
00414 
00415 static VOID
00416 GspGetRegisters(PCHAR Address, PKTRAP_FRAME TrapFrame)
00417 {
00418     ULONG_PTR Value;
00419     PULONG p;
00420     ULONG i;
00421     PETHREAD Thread;
00422     ULONG_PTR *KernelStack;
00423 
00424     if (NULL == GspDbgThread)
00425     {
00426         Thread = PsGetCurrentThread();
00427     }
00428     else
00429     {
00430         TrapFrame = GspDbgThread->Tcb.TrapFrame;
00431         Thread = GspDbgThread;
00432     }
00433 
00434     if (Waiting == Thread->Tcb.State)
00435     {
00436         KernelStack = Thread->Tcb.KernelStack;
00437         for (i = 0; i < sizeof(GspRegisters) / sizeof(GspRegisters[0]); i++)
00438         {
00439             switch (i)
00440             {
00441                 case EBP:
00442                     Value = KernelStack[3];
00443                     break;
00444                 case EDI:
00445                     Value = KernelStack[4];
00446                     break;
00447                 case ESI:
00448                     Value = KernelStack[5];
00449                     break;
00450                 case EBX:
00451                     Value = KernelStack[6];
00452                     break;
00453                 case PC:
00454                     Value = KernelStack[7];
00455                     break;
00456                 case ESP:
00457                     Value = (ULONG_PTR)(KernelStack + 8);
00458                     break;
00459                 case CS:
00460                     Value = KGDT_R0_CODE;
00461                     break;
00462                 case DS:
00463                     Value = KGDT_R0_DATA;
00464                     break;
00465                 default:
00466                     Value = 0;
00467                     break;
00468             }
00469 
00470             Address = GspMem2Hex((PCHAR)&Value, Address, GspRegisters[i].Size, FALSE);
00471         }
00472     }
00473     else
00474     {
00475         for (i = 0; i < sizeof(GspRegisters) / sizeof(GspRegisters[0]); i++)
00476         {
00477             if (TrapFrame)
00478             {
00479                 if (ESP == i)
00480                 {
00481                     Value = GspGetEspFromTrapFrame(TrapFrame);
00482                 }
00483                 else
00484                 {
00485                     p = (PULONG)((ULONG_PTR)TrapFrame + GspRegisters[i].OffsetInTF);
00486                     Value = *p;
00487                 }
00488             }
00489             else if (i == PC)
00490             {
00491                 /*
00492                  * This thread has not been sheduled yet so assume it
00493                  * is still in PsBeginThreadWithContextInternal().
00494                  */
00495                 Value = (ULONG)KiThreadStartup;
00496             }
00497             else
00498             {
00499                 Value = 0;
00500             }
00501 
00502             Address = GspMem2Hex((PCHAR)&Value, Address, GspRegisters[i].Size, FALSE);
00503         }
00504     }
00505 }
00506 
00507 VOID
00508 GspSetRegistersInTrapFrame(PCHAR Address, PCONTEXT Context, PKTRAP_FRAME TrapFrame)
00509 {
00510     ULONG Value;
00511     PCHAR Buffer;
00512     PULONG p;
00513     ULONG i;
00514 
00515     if (!TrapFrame)
00516         return;
00517 
00518     Buffer = Address;
00519     for (i = 0; i < NUMREGS; i++)
00520     {
00521         if (GspRegisters[i].SetInContext)
00522         {
00523             p = (PULONG)((ULONG_PTR)Context + GspRegisters[i].OffsetInContext);
00524         }
00525         else
00526         {
00527             p = (PULONG)((ULONG_PTR)TrapFrame + GspRegisters[i].OffsetInTF);
00528         }
00529 
00530         Value = 0;
00531         Buffer = GspHex2Mem(Buffer, (PCHAR)&Value, GspRegisters[i].Size, FALSE);
00532         *p = Value;
00533     }
00534 }
00535 
00536 VOID
00537 GspSetSingleRegisterInTrapFrame(PCHAR Address, LONG Number, PCONTEXT Context, PKTRAP_FRAME TrapFrame)
00538 {
00539     ULONG Value;
00540     PULONG p;
00541 
00542     if (!TrapFrame)
00543         return;
00544 
00545     if (GspRegisters[Number].SetInContext)
00546     {
00547         p = (PULONG)((ULONG_PTR)Context + GspRegisters[Number].OffsetInContext);
00548     }
00549     else
00550     {
00551         p = (PULONG)((ULONG_PTR)TrapFrame + GspRegisters[Number].OffsetInTF);
00552     }
00553 
00554     Value = 0;
00555     GspHex2Mem(Address, (PCHAR)&Value, GspRegisters[Number].Size, FALSE);
00556     *p = Value;
00557 }
00558 
00559 BOOLEAN
00560 GspFindThread(PCHAR Data, PETHREAD *Thread)
00561 {
00562     PETHREAD ThreadInfo = NULL;
00563 
00564     if (strcmp(Data, "-1") == 0)
00565     {
00566         /* All threads */
00567         ThreadInfo = NULL;
00568     }
00569     else
00570     {
00571         ULONG uThreadId;
00572         HANDLE ThreadId;
00573         PCHAR ptr = &Data[0];
00574 
00575         GspHex2Long(&ptr, (PLONG)&uThreadId);
00576         ThreadId = (HANDLE)uThreadId;
00577 
00578         if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &ThreadInfo)))
00579         {
00580             *Thread = NULL;
00581             return FALSE;
00582         }
00583     }
00584 
00585     *Thread = ThreadInfo;
00586     return TRUE;
00587 }
00588 
00589 VOID
00590 GspSetThread(PCHAR Request)
00591 {
00592     PETHREAD ThreadInfo;
00593     PCHAR ptr = &Request[1];
00594 
00595     switch (Request[0])
00596     {
00597         case 'c': /* Run thread */
00598             if (GspFindThread(ptr, &ThreadInfo))
00599             {
00600                 GspOutBuffer[0] = 'O';
00601                 GspOutBuffer[1] = 'K';
00602 
00603                 if (NULL != GspRunThread)
00604                     ObDereferenceObject(GspRunThread);
00605 
00606                 GspRunThread = ThreadInfo;
00607 
00608                 if (NULL != GspRunThread)
00609                     ObReferenceObject(GspRunThread);
00610             }
00611             else
00612             {
00613                 GspOutBuffer[0] = 'E';
00614             }
00615             break;
00616 
00617         case 'g': /* Debug thread */
00618             if (GspFindThread(ptr, &ThreadInfo))
00619             {
00620                 GspOutBuffer[0] = 'O';
00621                 GspOutBuffer[1] = 'K';
00622 
00623                 if (NULL != GspDbgThread)
00624                     ObDereferenceObject(GspDbgThread);
00625 
00626                 if (ThreadInfo == PsGetCurrentThread())
00627                 {
00628                     GspDbgThread = NULL;
00629                     ObDereferenceObject(ThreadInfo);
00630                 }
00631                 else
00632                 {
00633                     GspDbgThread = ThreadInfo;
00634                 }
00635             }
00636             else
00637             {
00638                 GspOutBuffer[0] = 'E';
00639             }
00640             break;
00641 
00642         default:
00643             break;
00644     }
00645 }
00646 
00647 VOID
00648 GspQuery(PCHAR Request)
00649 {
00650     ULONG Value;
00651 
00652     if (strncmp(Request, "C", 1) == 0)
00653     {
00654         PCHAR ptr = &GspOutBuffer[2];
00655 
00656         /* Get current thread id */
00657         GspOutBuffer[0] = 'Q';
00658         GspOutBuffer[1] = 'C';
00659 
00660         if (NULL != GspDbgThread)
00661             Value = (ULONG)GspDbgThread->Cid.UniqueThread;
00662         else
00663             Value = (ULONG)PsGetCurrentThread()->Cid.UniqueThread;
00664 
00665         GspLong2Hex(&ptr, Value);
00666     }
00667     else if (strncmp(Request, "fThreadInfo", 11) == 0)
00668     {
00669         PEPROCESS Process;
00670         PLIST_ENTRY AThread, AProcess;
00671         PCHAR ptr = &GspOutBuffer[1];
00672 
00673         /* Get first thread id */
00674         GspEnumThread = NULL;
00675         AProcess = PsActiveProcessHead.Flink;
00676         while (AProcess != &PsActiveProcessHead)
00677         {
00678             Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
00679             AThread = Process->ThreadListHead.Flink;
00680             if (AThread != &Process->ThreadListHead)
00681             {
00682                 GspEnumThread = CONTAINING_RECORD(Process->ThreadListHead.Flink,
00683                                                   ETHREAD, ThreadListEntry);
00684                 break;
00685             }
00686             AProcess = AProcess->Flink;
00687         }
00688         if (GspEnumThread != NULL)
00689         {
00690             GspOutBuffer[0] = 'm';
00691             Value = (ULONG)GspEnumThread->Cid.UniqueThread;
00692             GspLong2Hex(&ptr, Value);
00693         }
00694         else
00695         {
00696             /* FIXME - what to do here? This case should never happen though, there
00697                should always be at least one thread on the system... */
00698             /* GspOutBuffer[0] = 'l'; */
00699         }
00700     }
00701     else if (strncmp(Request, "sThreadInfo", 11) == 0)
00702     {
00703         PEPROCESS Process;
00704         PLIST_ENTRY AThread, AProcess;
00705         PCHAR ptr = &GspOutBuffer[1];
00706 
00707         /* Get next thread id */
00708         if (GspEnumThread != NULL)
00709         {
00710             /* find the next thread */
00711             Process = GspEnumThread->ThreadsProcess;
00712             if (GspEnumThread->ThreadListEntry.Flink != &Process->ThreadListHead)
00713             {
00714                 GspEnumThread = CONTAINING_RECORD(GspEnumThread->ThreadListEntry.Flink,
00715                                                   ETHREAD, ThreadListEntry);
00716             }
00717             else
00718             {
00719                 PETHREAD Thread = NULL;
00720                 AProcess = Process->ActiveProcessLinks.Flink;
00721                 while (AProcess != &PsActiveProcessHead)
00722                 {
00723                     Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
00724                     AThread = Process->ThreadListHead.Flink;
00725                     if (AThread != &Process->ThreadListHead)
00726                     {
00727                         Thread = CONTAINING_RECORD(Process->ThreadListHead.Flink,
00728                                                    ETHREAD, ThreadListEntry);
00729                         break;
00730                     }
00731                     AProcess = AProcess->Flink;
00732                 }
00733                 GspEnumThread = Thread;
00734             }
00735 
00736             if (GspEnumThread != NULL)
00737             {
00738                 /* return the ID */
00739                 GspOutBuffer[0] = 'm';
00740                 Value = (ULONG)GspEnumThread->Cid.UniqueThread;
00741                 GspLong2Hex(&ptr, Value);
00742             }
00743             else
00744             {
00745                 GspOutBuffer[0] = 'l';
00746             }
00747         }
00748         else
00749         {
00750             GspOutBuffer[0] = 'l';
00751         }
00752     }
00753     else if (strncmp(Request, "ThreadExtraInfo", 15) == 0)
00754     {
00755         PETHREAD ThreadInfo;
00756 
00757         /* Get thread information */
00758         if (GspFindThread(Request + 16, &ThreadInfo))
00759         {
00760             char Buffer[64];
00761             PEPROCESS Proc;
00762 
00763             Proc = (PEPROCESS)ThreadInfo->ThreadsProcess;
00764 
00765             Buffer[0] = '\0';
00766 
00767             if (NULL != Proc)
00768                 sprintf(Buffer, "%s [%d:0x%x], ",
00769                         Proc->ImageFileName,
00770                         (int)Proc->UniqueProcessId,
00771                         (int)ThreadInfo->Cid.UniqueThread);
00772 
00773             strcpy(Buffer + strlen(Buffer), GspThreadStates[ThreadInfo->Tcb.State]);
00774 
00775             ObDereferenceObject(ThreadInfo);
00776 
00777             GspMem2Hex(Buffer, &GspOutBuffer[0], strlen(Buffer), FALSE);
00778         }
00779     }
00780     else if (strncmp(Request, "Supported", 9) == 0)
00781     {
00782         /* tell maximum incoming packet size */
00783         sprintf(GspOutBuffer, "PacketSize=%u", sizeof(GspInBuffer) - 1);
00784     }
00785     else if (strncmp(Request, "Rcmd,", 5) == 0)
00786     {
00787         ;
00788     }
00789 }
00790 
00791 VOID
00792 GspQueryThreadStatus(PCHAR Request)
00793 {
00794     PETHREAD ThreadInfo;
00795     PCHAR ptr = &Request[0];
00796 
00797     if (GspFindThread(ptr, &ThreadInfo))
00798     {
00799         ObDereferenceObject(ThreadInfo);
00800 
00801         GspOutBuffer[0] = 'O';
00802         GspOutBuffer[1] = 'K';
00803         GspOutBuffer[2] = '\0';
00804     }
00805     else
00806     {
00807         GspOutBuffer[0] = 'E';
00808         GspOutBuffer[1] = '\0';
00809     }
00810 }
00811 
00812 #define DR6_BS         0x00004000       /* Single step */
00813 
00814 #define DR7_L0         0x00000001       /* Local breakpoint 0 enable */
00815 #define DR7_G0         0x00000002       /* Global breakpoint 0 enable */
00816 #define DR7_L1         0x00000004       /* Local breakpoint 1 enable */
00817 #define DR7_G1         0x00000008       /* Global breakpoint 1 enable */
00818 #define DR7_L2         0x00000010       /* Local breakpoint 2 enable */
00819 #define DR7_G2         0x00000020       /* Global breakpoint 2 enable */
00820 #define DR7_L3         0x00000040       /* Local breakpoint 3 enable */
00821 #define DR7_G3         0x00000080       /* Global breakpoint 3 enable */
00822 #define DR7_LE         0x00000100       /* Local exact breakpoint enable (old) */
00823 #define DR7_GE         0x00000200       /* Global exact breakpoint enable (old) */
00824 #define DR7_GD         0x00002000       /* General detect enable */
00825 #define DR7_TYPE0_MASK 0x00030000       /* Breakpoint 0 condition */
00826 #define DR7_LEN0_MASK  0x000c0000       /* Breakpoint 0 length */
00827 #define DR7_TYPE1_MASK 0x00300000       /* Breakpoint 1 condition */
00828 #define DR7_LEN1_MASK  0x00c00000       /* Breakpoint 1 length */
00829 #define DR7_TYPE2_MASK 0x03000000       /* Breakpoint 2 condition */
00830 #define DR7_LEN2_MASK  0x0c000000       /* Breakpoint 2 length */
00831 #define DR7_TYPE3_MASK 0x30000000       /* Breakpoint 3 condition */
00832 #define DR7_LEN3_MASK  0xc0000000       /* Breakpoint 3 length */
00833 #define DR7_GLOBAL_ENABLE(Bp) (2 << (2 * (Bp)))
00834 #define DR7_TYPE(Bp, Type)    ((Type) << (16 + 4 * (Bp)))
00835 #define DR7_LEN(Bp, Len)      ((Len) << (18 + 4 * (Bp)))
00836 
00837 #define I386_BP_TYPE_EXECUTE        0
00838 #define I386_BP_TYPE_DATA_WRITE     1
00839 #define I386_BP_TYPE_DATA_READWRITE 3
00840 
00841 #define I386_OPCODE_INT3 0xcc
00842 
00843 #define GDB_ZTYPE_MEMORY_BREAKPOINT   0
00844 #define GDB_ZTYPE_HARDWARE_BREAKPOINT 1
00845 #define GDB_ZTYPE_WRITE_WATCHPOINT    2
00846 #define GDB_ZTYPE_READ_WATCHPOINT     3
00847 #define GDB_ZTYPE_ACCESS_WATCHPOINT   4
00848 
00849 typedef struct _GSPHWBREAKPOINT
00850 {
00851     ULONG Type;
00852     ULONG_PTR Address;
00853     ULONG Length;
00854 } GSPHWBREAKPOINT;
00855 
00856 #define MAX_HW_BREAKPOINTS 4
00857 static unsigned GspHwBreakpointCount = 0;
00858 static GSPHWBREAKPOINT GspHwBreakpoints[MAX_HW_BREAKPOINTS];
00859 
00860 typedef struct _GSPSWBREAKPOINT
00861 {
00862     ULONG_PTR Address;
00863     CHAR PrevContent;
00864     BOOLEAN Active;
00865 } GSPSWBREAKPOINT;
00866 
00867 #define MAX_SW_BREAKPOINTS 64
00868 static unsigned GspSwBreakpointCount = 0;
00869 static GSPSWBREAKPOINT GspSwBreakpoints[MAX_SW_BREAKPOINTS];
00870 
00871 static void
00872 GspSetHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
00873 {
00874     DPRINT("GspSetHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
00875 
00876     if (GDB_ZTYPE_READ_WATCHPOINT == Type)
00877     {
00878         DPRINT1("Read watchpoint not supported\n");
00879         strcpy(GspOutBuffer, "E22");
00880     }
00881     else if (GDB_ZTYPE_HARDWARE_BREAKPOINT == Type && 1 != Length)
00882     {
00883         DPRINT1("Invalid length %lu for hardware breakpoint\n", Length);
00884         strcpy(GspOutBuffer, "E22");
00885     }
00886     else if (1 != Length && 2 != Length && 4 != Length)
00887     {
00888         DPRINT1("Invalid length %lu for GDB Z type %lu\n", Length, Type);
00889         strcpy(GspOutBuffer, "E22");
00890     }
00891     else if (0 != (Address & (Length - 1)))
00892     {
00893         DPRINT1("Invalid alignment for address 0x%p and length %d\n", Address, Length);
00894         strcpy(GspOutBuffer, "E22");
00895     }
00896     else if (MAX_HW_BREAKPOINTS == GspHwBreakpointCount)
00897     {
00898         DPRINT1("Trying to set too many hardware breakpoints\n");
00899         strcpy(GspOutBuffer, "E22");
00900     }
00901     else
00902     {
00903         DPRINT("Stored at index %u\n", GspHwBreakpointCount);
00904         GspHwBreakpoints[GspHwBreakpointCount].Type = Type;
00905         GspHwBreakpoints[GspHwBreakpointCount].Address = Address;
00906         GspHwBreakpoints[GspHwBreakpointCount].Length = Length;
00907         GspHwBreakpointCount++;
00908         strcpy(GspOutBuffer, "OK");
00909     }
00910 }
00911 
00912 static void
00913 GspRemoveHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
00914 {
00915     unsigned Index;
00916 
00917     DPRINT("GspRemoveHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
00918     for (Index = 0; Index < GspHwBreakpointCount; Index++)
00919     {
00920         if (GspHwBreakpoints[Index].Type == Type &&
00921             GspHwBreakpoints[Index].Address == Address &&
00922             GspHwBreakpoints[Index].Length == Length)
00923         {
00924             DPRINT("Found match at index %u\n", Index);
00925             if (Index + 1 < GspHwBreakpointCount)
00926                 memmove(GspHwBreakpoints + Index,
00927                         GspHwBreakpoints + (Index + 1),
00928                         (GspHwBreakpointCount - Index - 1) * sizeof(GSPHWBREAKPOINT));
00929 
00930             GspHwBreakpointCount--;
00931             strcpy(GspOutBuffer, "OK");
00932             return;
00933         }
00934     }
00935 
00936     DPRINT1("Not found\n");
00937     strcpy(GspOutBuffer, "E22");
00938 }
00939 
00940 static BOOLEAN
00941 GspFindSwBreakpoint(ULONG_PTR Address, PULONG PIndex)
00942 {
00943     ULONG Index;
00944 
00945     for (Index = 0; Index < GspSwBreakpointCount; Index++)
00946         if (GspSwBreakpoints[Index].Address == Address)
00947         {
00948             if (PIndex)
00949                 *PIndex = Index;
00950             return TRUE;
00951         }
00952 
00953     return FALSE;
00954 }
00955 
00956 static void
00957 GspSetSwBreakpoint(ULONG_PTR Address)
00958 {
00959     DPRINT("GspSetSwBreakpoint(0x%p)\n", Address);
00960 
00961     if (MAX_SW_BREAKPOINTS == GspSwBreakpointCount)
00962     {
00963         DPRINT1("Trying to set too many software breakpoints\n");
00964         strcpy(GspOutBuffer, "E22");
00965         return;
00966     }
00967 
00968     if (GspFindSwBreakpoint(Address, NULL))
00969     {
00970         strcpy(GspOutBuffer, "E22");
00971         return;
00972     }
00973 
00974     DPRINT("Stored at index %u\n", GspSwBreakpointCount);
00975     GspSwBreakpoints[GspSwBreakpointCount].Address = Address;
00976     GspSwBreakpoints[GspSwBreakpointCount].Active = FALSE;
00977     GspSwBreakpointCount++;
00978     strcpy(GspOutBuffer, "OK");
00979 }
00980 
00981 static void
00982 GspRemoveSwBreakpoint(ULONG_PTR Address)
00983 {
00984     ULONG Index;
00985 
00986     DPRINT("GspRemoveSwBreakpoint(0x%p)\n", Address);
00987 
00988     if (GspFindSwBreakpoint(Address, &Index))
00989     {
00990         DPRINT("Found match at index %u\n", Index);
00991         ASSERT(!GspSwBreakpoints[Index].Active);
00992 
00993         if (Index + 1 < GspSwBreakpointCount)
00994             memmove(GspSwBreakpoints + Index,
00995                     GspSwBreakpoints + (Index + 1),
00996                     (GspSwBreakpointCount - Index - 1) * sizeof(GSPSWBREAKPOINT));
00997 
00998         GspSwBreakpointCount--;
00999         strcpy(GspOutBuffer, "OK");
01000         return;
01001     }
01002 
01003     DPRINT1("Not found\n");
01004     strcpy(GspOutBuffer, "E22");
01005 }
01006 
01007 static void
01008 GspLoadHwBreakpoint(PKTRAP_FRAME TrapFrame, unsigned BpIndex,
01009                     ULONG_PTR Address, ULONG Length, ULONG Type)
01010 {
01011     DPRINT("GspLoadHwBreakpoint(0x%p, %d, 0x%p, %d)\n",
01012            TrapFrame, BpIndex, Address, Type);
01013 
01014     /* Set the DR7_Gx bit to globally enable the breakpoint */
01015     TrapFrame->Dr7 |= DR7_GLOBAL_ENABLE(BpIndex) |
01016                       DR7_LEN(BpIndex, Length) |
01017                       DR7_TYPE(BpIndex, Type);
01018 
01019     switch (BpIndex)
01020     {
01021         case 0:
01022             DPRINT("Setting DR0 to 0x%p\n", Address);
01023             TrapFrame->Dr0 = Address;
01024             break;
01025 
01026         case 1:
01027             DPRINT("Setting DR1 to 0x%p\n", Address);
01028             TrapFrame->Dr1 = Address;
01029             break;
01030 
01031         case 2:
01032             DPRINT("Setting DR2 to 0x%p\n", Address);
01033             TrapFrame->Dr2 = Address;
01034             break;
01035 
01036         case 3:
01037             DPRINT("Setting DR3 to 0x%p\n", Address);
01038             TrapFrame->Dr3 = Address;
01039             break;
01040     }
01041 }
01042 
01043 static void
01044 GspLoadSwBreakpoint(ULONG Index)
01045 {
01046     GspMemoryError = FALSE;
01047 
01048     GspSwBreakpoints[Index].PrevContent = GspReadMemSafe((PCHAR)GspSwBreakpoints[Index].Address);
01049 
01050     if (!GspMemoryError)
01051         GspWriteMemSafe((PCHAR)GspSwBreakpoints[Index].Address, I386_OPCODE_INT3);
01052 
01053     GspSwBreakpoints[Index].Active = !GspMemoryError;
01054 
01055     if (GspMemoryError)
01056         DPRINT1("Failed to set software breakpoint at 0x%p\n", GspSwBreakpoints[Index].Address);
01057     else
01058         DPRINT("Successfully set software breakpoint at 0x%p\n", GspSwBreakpoints[Index].Address);
01059 }
01060 
01061 static void
01062 GspLoadBreakpoints(PKTRAP_FRAME TrapFrame)
01063 {
01064     unsigned Index;
01065     ULONG i386Type;
01066 
01067     DPRINT("GspLoadBreakpoints\n");
01068     DPRINT("DR7 on entry: 0x%08x\n", TrapFrame->Dr7);
01069 
01070     /* Remove all breakpoints */
01071     TrapFrame->Dr7 &= ~(DR7_L0 | DR7_L1 | DR7_L2 | DR7_L3 |
01072                         DR7_G0 | DR7_G1 | DR7_G2 | DR7_G3 |
01073                         DR7_TYPE0_MASK | DR7_LEN0_MASK |
01074                         DR7_TYPE1_MASK | DR7_LEN1_MASK |
01075                         DR7_TYPE2_MASK | DR7_LEN2_MASK |
01076                         DR7_TYPE3_MASK | DR7_LEN3_MASK);
01077 
01078     for (Index = 0; Index < GspHwBreakpointCount; Index++)
01079     {
01080         switch (GspHwBreakpoints[Index].Type)
01081         {
01082             case GDB_ZTYPE_HARDWARE_BREAKPOINT:
01083                 i386Type = I386_BP_TYPE_EXECUTE;
01084                 break;
01085             case GDB_ZTYPE_WRITE_WATCHPOINT:
01086                 i386Type = I386_BP_TYPE_DATA_WRITE;
01087                 break;
01088             case GDB_ZTYPE_ACCESS_WATCHPOINT:
01089                 i386Type = I386_BP_TYPE_DATA_READWRITE;
01090                 break;
01091             default:
01092                 ASSERT(FALSE);
01093                 i386Type = I386_BP_TYPE_EXECUTE;
01094                 break;
01095         }
01096 
01097         GspLoadHwBreakpoint(TrapFrame, Index, GspHwBreakpoints[Index].Address,
01098                             GspHwBreakpoints[Index].Length - 1, i386Type);
01099     }
01100 
01101     for (Index = 0; Index < GspSwBreakpointCount; Index++)
01102     {
01103         DPRINT("Using real software breakpoint\n");
01104         GspLoadSwBreakpoint(Index);
01105     }
01106 
01107     DPRINT("Final DR7 value 0x%08x\n", TrapFrame->Dr7);
01108 }
01109 
01110 static void
01111 GspUnloadBreakpoints(void)
01112 {
01113     unsigned Index;
01114 
01115     DPRINT("GspUnloadBreakpoints\n");
01116 
01117     /* Disable hardware debugging while we are inside the stub */
01118     __writedr(7, 0);
01119 
01120     for (Index = 0; Index < GspSwBreakpointCount; Index++)
01121     {
01122         if (GspSwBreakpoints[Index].Active)
01123         {
01124             GspMemoryError = FALSE;
01125             GspWriteMemSafe((PCHAR)GspSwBreakpoints[Index].Address,
01126                             GspSwBreakpoints[Index].PrevContent);
01127             GspSwBreakpoints[Index].Active = FALSE;
01128             if (GspMemoryError)
01129             {
01130                 DPRINT1("Failed to remove software breakpoint from 0x%p\n",
01131                         GspSwBreakpoints[Index].Address);
01132             }
01133             else
01134             {
01135                 DPRINT("Successfully removed software breakpoint from 0x%p\n",
01136                        GspSwBreakpoints[Index].Address);
01137             }
01138         }
01139     }
01140 }
01141 
01142 static void
01143 GspStopReply(NTSTATUS ExceptionCode, PKTRAP_FRAME TrapFrame)
01144 {
01145     PCHAR ptr = GspOutBuffer;
01146     ULONG SigVal;
01147     LONG Esp;
01148 
01149     switch (ExceptionCode)
01150     {
01151         case STATUS_INTEGER_DIVIDE_BY_ZERO:
01152             SigVal = 8; /* divide by zero */
01153             break;
01154         case STATUS_SINGLE_STEP:
01155         case STATUS_BREAKPOINT:
01156             SigVal = 5; /* breakpoint */
01157             break;
01158         case STATUS_INTEGER_OVERFLOW:
01159         case STATUS_ARRAY_BOUNDS_EXCEEDED:
01160             SigVal = 16; /* bound instruction */
01161             break;
01162         case STATUS_ILLEGAL_INSTRUCTION:
01163             SigVal = 4; /* Invalid opcode */
01164             break;
01165         case STATUS_STACK_OVERFLOW:
01166         case STATUS_DATATYPE_MISALIGNMENT:
01167         case STATUS_ACCESS_VIOLATION:
01168             SigVal = 11; /* access violation */
01169             break;
01170         default:
01171             SigVal = 7; /* "software generated" */
01172     }
01173 
01174     ptr = GspOutBuffer;
01175 
01176     *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
01177     *ptr++ = HexChars[(SigVal >> 4) & 0xf];
01178     *ptr++ = HexChars[SigVal & 0xf];
01179 
01180     *ptr++ = HexChars[ESP];
01181     *ptr++ = ':';
01182 
01183     Esp = GspGetEspFromTrapFrame(TrapFrame); /* SP */
01184     ptr = GspMem2Hex((PCHAR)&Esp, ptr, 4, 0);
01185     *ptr++ = ';';
01186 
01187     *ptr++ = HexChars[EBP];
01188     *ptr++ = ':';
01189     ptr = GspMem2Hex((PCHAR)&TrapFrame->Ebp, ptr, 4, 0); /* FP */
01190     *ptr++ = ';';
01191 
01192     *ptr++ = HexChars[PC];
01193     *ptr++ = ':';
01194     ptr = GspMem2Hex((PCHAR)&TrapFrame->Eip, ptr, 4, 0); /* PC */
01195     *ptr++ = ';';
01196 
01197     *ptr = '\0';
01198 }
01199 
01200 /*
01201  * This function does all command procesing for interfacing to GDB.
01202  */
01203 KD_CONTINUE_TYPE
01204 NTAPI
01205 KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
01206                              PCONTEXT Context,
01207                              PKTRAP_FRAME TrapFrame)
01208 {
01209     static BOOLEAN GdbAttached = FALSE;
01210     BOOLEAN Stepping = FALSE;
01211     NTSTATUS ExceptionCode;
01212     LONG Address;
01213     LONG Length;
01214     PCHAR ptr;
01215 
01216     /* FIXME: Stop on other CPUs too */
01217 
01218     DPRINT("Thread %p entering stub\n", PsGetCurrentThread());
01219     ExceptionCode = (NTSTATUS)ExceptionRecord->ExceptionCode;
01220 
01221     /* Can only debug 1 thread at a time... */
01222     ExAcquireFastMutex(&GspLock);
01223     DPRINT("Thread %p acquired mutex\n", PsGetCurrentThread());
01224 
01225     GspUnloadBreakpoints();
01226 
01227     /* Make sure we're debugging the current thread. */
01228     if (NULL != GspDbgThread)
01229     {
01230         DPRINT1("Internal error: entering stub with non-NULL GspDbgThread\n");
01231         ObDereferenceObject(GspDbgThread);
01232         GspDbgThread = NULL;
01233     }
01234 
01235     if (GdbAttached)
01236     {
01237         GspStopReply(ExceptionCode, TrapFrame);
01238         GspPutPacket(GspOutBuffer);
01239         // DbgPrint(">>> (%s) >>>\n", GspOutBuffer);
01240     }
01241     else
01242     {
01243         GdbAttached = TRUE;
01244     }
01245 
01246     while (TRUE)
01247     {
01248         /* Zero the buffer now so we don't have to worry about the terminating zero character */
01249         memset(GspOutBuffer, 0, sizeof(GspOutBuffer));
01250         ptr = GspGetPacket();
01251         // DbgPrint("<<< (%s) <<<\n", ptr);
01252 
01253         switch (*ptr++)
01254         {
01255             case '?':
01256                 /* a little hack to send more complete status information */
01257                 GspStopReply(ExceptionCode, TrapFrame);
01258                 break;
01259 
01260             case 'd':
01261                 GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
01262                 break;
01263 
01264             case 'g': /* return the value of the CPU Registers */
01265                 GspGetRegisters(GspOutBuffer, TrapFrame);
01266                 break;
01267 
01268             case 'G': /* set the value of the CPU Registers - return OK */
01269                 if (NULL != GspDbgThread)
01270                     GspSetRegistersInTrapFrame(ptr, Context, GspDbgThread->Tcb.TrapFrame);
01271                 else
01272                     GspSetRegistersInTrapFrame(ptr, Context, TrapFrame);
01273 
01274                 strcpy(GspOutBuffer, "OK");
01275                 break;
01276 
01277             case 'P': /* set the value of a single CPU register - return OK */
01278             {
01279                 LONG Register;
01280 
01281                 if ((GspHex2Long(&ptr, &Register)) && (*ptr++ == '='))
01282                 {
01283                     if ((Register >= 0) && (Register < NUMREGS))
01284                     {
01285                         if (GspDbgThread)
01286                         {
01287                             GspSetSingleRegisterInTrapFrame(ptr, Register, Context,
01288                                                             GspDbgThread->Tcb.TrapFrame);
01289                         }
01290                         else
01291                         {
01292                             GspSetSingleRegisterInTrapFrame(ptr, Register, Context, TrapFrame);
01293                         }
01294                         strcpy(GspOutBuffer, "OK");
01295                         break;
01296                     }
01297                 }
01298 
01299                 strcpy(GspOutBuffer, "E01");
01300                 break;
01301             }
01302 
01303             /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
01304             case 'm':
01305             {
01306                 /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
01307                 if (GspHex2Long(&ptr, &Address) && *(ptr++) == ',' && GspHex2Long(&ptr, &Length))
01308                 {
01309                     PEPROCESS DbgProcess = NULL;
01310 
01311                     ptr = NULL;
01312                     if (NULL != GspDbgThread &&
01313                         PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
01314                     {
01315                         DbgProcess = GspDbgThread->ThreadsProcess;
01316                         KeAttachProcess(&DbgProcess->Pcb);
01317                     }
01318 
01319                     GspMemoryError = FALSE;
01320                     GspMem2Hex((PCHAR)Address, GspOutBuffer, Length, 1);
01321 
01322                     if (NULL != DbgProcess)
01323                         KeDetachProcess();
01324 
01325                     if (GspMemoryError)
01326                     {
01327                         strcpy(GspOutBuffer, "E03");
01328                         DPRINT1("Fault during memory read\n");
01329                     }
01330                     ptr = NULL;
01331                 }
01332 
01333                 if (NULL != ptr)
01334                     strcpy(GspOutBuffer, "E01");
01335 
01336                 break;
01337             }
01338 
01339             /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
01340             case 'M':
01341             {
01342                 /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
01343                 if (GspHex2Long(&ptr, &Address))
01344                 {
01345                     if (*(ptr++) == ',' && GspHex2Long(&ptr, &Length) && *(ptr++) == ':')
01346                     {
01347                         PEPROCESS DbgProcess = NULL;
01348 
01349                         if (NULL != GspDbgThread &&
01350                             PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
01351                         {
01352                             DbgProcess = GspDbgThread->ThreadsProcess;
01353                             KeAttachProcess(&DbgProcess->Pcb);
01354                         }
01355                         GspMemoryError = FALSE;
01356                         GspHex2Mem(ptr, (PCHAR)Address, Length, TRUE);
01357                         if (NULL != DbgProcess)
01358                             KeDetachProcess();
01359 
01360                         if (GspMemoryError)
01361                         {
01362                             strcpy(GspOutBuffer, "E03");
01363                             DPRINT1("Fault during memory write\n");
01364                         }
01365                         else
01366                         {
01367                             strcpy(GspOutBuffer, "OK");
01368                         }
01369                         ptr = NULL;
01370                     }
01371                 }
01372 
01373                 if (NULL != ptr)
01374                     strcpy(GspOutBuffer, "E02");
01375 
01376                 break;
01377             }
01378 
01379             /* cAA..AA   Continue at address AA..AA */
01380             /* sAA..AA   Step one instruction from AA..AA */
01381             case 's':
01382                 Stepping = TRUE;
01383             case 'c':
01384             {
01385                 ULONG BreakpointNumber;
01386                 ULONG Dr6;
01387 
01388                 /* try to read optional parameter, pc changed if param */
01389                 if (GspHex2Long(&ptr, &Address))
01390                 {
01391                     Context->Eip = Address;
01392                 }
01393                 else if (ExceptionCode == STATUS_BREAKPOINT)
01394                 {
01395                     if (GspReadMemSafe((PCHAR)Context->Eip) == (CHAR)I386_OPCODE_INT3)
01396                         Context->Eip++;
01397                 }
01398 
01399                 /* clear the trace bit */
01400                 Context->EFlags &= ~EFLAGS_TF;
01401 
01402                 /* set the trace bit if we're Stepping */
01403                 if (Stepping)
01404                     Context->EFlags |= EFLAGS_TF;
01405 
01406                 Dr6 = __readdr(6);
01407                 if (!(Dr6 & DR6_BS))
01408                 {
01409                     for (BreakpointNumber = 0;
01410                          BreakpointNumber < MAX_HW_BREAKPOINTS;
01411                          BreakpointNumber++)
01412                     {
01413                         if (Dr6 & (1 << BreakpointNumber))
01414                         {
01415                             if (GspHwBreakpoints[BreakpointNumber].Type == I386_BP_TYPE_EXECUTE)
01416                             {
01417                                 /* Set restore flag */
01418                                 Context->EFlags |= EFLAGS_RF;
01419                                 break;
01420                             }
01421                         }
01422                     }
01423                 }
01424 
01425                 GspLoadBreakpoints(TrapFrame);
01426                 __writedr(6, 0);
01427 
01428                 if (NULL != GspDbgThread)
01429                 {
01430                     ObDereferenceObject(GspDbgThread);
01431                     GspDbgThread = NULL;
01432                 }
01433 
01434                 DPRINT("Thread %p releasing mutex\n", PsGetCurrentThread());
01435                 ExReleaseFastMutex(&GspLock);
01436                 DPRINT("Thread %p leaving stub\n", PsGetCurrentThread());
01437 
01438                 if (ExceptionCode == STATUS_BREAKPOINT ||
01439                     ExceptionCode == STATUS_SINGLE_STEP)
01440                     return kdContinue;
01441 
01442                 return kdHandleException;
01443             }
01444 
01445             case 'k': /* kill the program */
01446                 strcpy(GspOutBuffer, "OK");
01447                 break;
01448 
01449             case 'H': /* Set thread */
01450                 GspSetThread(ptr);
01451                 break;
01452 
01453             case 'q': /* Query */
01454                 GspQuery(ptr);
01455                 break;
01456 
01457             case 'T': /* Query thread status */
01458                 GspQueryThreadStatus(ptr);
01459                 break;
01460 
01461             case 'Z':
01462             {
01463                 LONG Type;
01464                 LONG Address;
01465                 LONG Length;
01466 
01467                 GspHex2Long(&ptr, &Type);
01468                 ptr++;
01469                 GspHex2Long(&ptr, &Address);
01470                 ptr++;
01471                 GspHex2Long(&ptr, &Length);
01472 
01473                 if (0 == Type)
01474                     GspSetSwBreakpoint((ULONG_PTR)Address);
01475                 else
01476                     GspSetHwBreakpoint(Type, (ULONG_PTR)Address, Length);
01477 
01478                 break;
01479             }
01480 
01481             case 'z':
01482             {
01483                 LONG Type;
01484                 LONG Address;
01485                 LONG Length;
01486 
01487                 GspHex2Long(&ptr, &Type);
01488                 ptr++;
01489                 GspHex2Long(&ptr, &Address);
01490                 ptr++;
01491                 GspHex2Long(&ptr, &Length);
01492 
01493                 if (0 == Type)
01494                     GspRemoveSwBreakpoint((ULONG_PTR)Address);
01495                 else
01496                     GspRemoveHwBreakpoint(Type, (ULONG_PTR)Address, Length);
01497 
01498                 break;
01499             }
01500 
01501             default:
01502                 break;
01503         }
01504 
01505         /* reply to the request */
01506         GspPutPacket(GspOutBuffer);
01507         // DbgPrint(">>> (%s) >>>\n",  GspOutBuffer);
01508     }
01509 }
01510 
01511 BOOLEAN
01512 NTAPI
01513 GspBreakIn(PKINTERRUPT Interrupt, PVOID ServiceContext)
01514 {
01515     PKTRAP_FRAME TrapFrame;
01516     BOOLEAN DoBreakIn;
01517     CONTEXT Context;
01518     KIRQL OldIrql;
01519     UCHAR Value;
01520 
01521     DPRINT("Break In\n");
01522 
01523     DoBreakIn = FALSE;
01524     while (KdPortGetByteEx(&GdbPortInfo, &Value))
01525     {
01526         if (Value == 0x03)
01527             DoBreakIn = TRUE;
01528     }
01529 
01530     if (!DoBreakIn)
01531         return TRUE;
01532 
01533     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
01534 
01535     TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
01536 
01537     KeTrapFrameToContext(TrapFrame, NULL, &Context);
01538 
01539     KdpGdbEnterDebuggerException(NULL, &Context, TrapFrame);
01540 
01541     KeContextToTrapFrame(&Context, NULL, TrapFrame, Context.ContextFlags, KernelMode);
01542 
01543     KeLowerIrql(OldIrql);
01544 
01545     return TRUE;
01546 }
01547 
01548 VOID
01549 NTAPI
01550 KdpGdbDebugPrint(PCH Message, ULONG Length)
01551 {
01552 }
01553 
01554 /* Initialize the GDB stub */
01555 VOID
01556 NTAPI
01557 KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable, ULONG BootPhase)
01558 {
01559     if (!KdDebuggerEnabled || !KdpDebugMode.Gdb)
01560         return;
01561 
01562     if (BootPhase == 0)
01563     {
01564         ExInitializeFastMutex(&GspLock);
01565 
01566         /* Write out the functions that we support for now */
01567         WrapperTable->KdpInitRoutine = KdpGdbStubInit;
01568         WrapperTable->KdpPrintRoutine = KdpGdbDebugPrint;
01569         WrapperTable->KdpExceptionRoutine = KdpGdbEnterDebuggerException;
01570 
01571         /* Initialize the Port */
01572         KdPortInitializeEx(&GdbPortInfo, 0, 0);
01573     }
01574     else if (BootPhase == 1)
01575     {
01576         GspInitialized = TRUE;
01577 
01578         GspRunThread = NULL;
01579         GspDbgThread = NULL;
01580         GspEnumThread = NULL;
01581 
01582         HalDisplayString("Waiting for GDB to attach\n");
01583         DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
01584     }
01585     else if (BootPhase == 2)
01586     {
01587         HalDisplayString("\n   GDB debugging enabled\n\n");
01588     }
01589 }
01590 
01591 /* EOF */

Generated on Sun May 27 2012 04:37:19 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.