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

Generated on Sun May 27 2012 04:37:20 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.