Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengdbstub.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
1.7.6.1
|