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