📄 gdbstub.c
字号:
ExAcquireFastMutex(&GspLock);
DPRINT("Thread %p acquired mutex\n", PsGetCurrentThread());
/* Disable hardware debugging while we are inside the stub */
Ke386SetDr7(0);
GspUnloadBreakpoints(TrapFrame);
/* Make sure we're debugging the current thread. */
if (NULL != GspDbgThread)
{
DPRINT1("Internal error: entering stub with non-NULL GspDbgThread\n");
ObDereferenceObject(GspDbgThread);
GspDbgThread = NULL;
}
/* ugly hack to avoid attempting to send status at the very
* beginning, right when GDB is trying to query the stub */
if (gdb_attached_yet)
{
LONG Esp;
stop_reply:
/* reply to host that an exception has occurred */
SigVal = GspComputeSignal(ExceptionRecord->ExceptionCode);
ptr = GspOutBuffer;
*ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
*ptr++ = HexChars[(SigVal >> 4) & 0xf];
*ptr++ = HexChars[SigVal & 0xf];
*ptr++ = HexChars[ESP];
*ptr++ = ':';
Esp = GspGetEspFromTrapFrame(TrapFrame); /* SP */
ptr = GspMem2Hex((PCHAR) &Esp, ptr, 4, 0);
*ptr++ = ';';
*ptr++ = HexChars[EBP];
*ptr++ = ':';
ptr = GspMem2Hex((PCHAR) &TrapFrame->Ebp, ptr, 4, 0); /* FP */
*ptr++ = ';';
*ptr++ = HexChars[PC];
*ptr++ = ':';
ptr = GspMem2Hex((PCHAR) &TrapFrame->Eip, ptr, 4, 0); /* PC */
*ptr++ = ';';
*ptr = '\0';
GspPutPacket(&GspOutBuffer[0]);
}
else
{
gdb_attached_yet = 1;
}
Stepping = FALSE;
while (TRUE)
{
/* Zero the buffer now so we don't have to worry about the terminating zero character */
memset(GspOutBuffer, 0, sizeof(GspInBuffer));
ptr = GspGetPacket();
switch(*ptr++)
{
case '?':
/* a little hack to send more complete status information */
goto stop_reply;
GspOutBuffer[0] = 'S';
GspOutBuffer[1] = HexChars[SigVal >> 4];
GspOutBuffer[2] = HexChars[SigVal % 16];
GspOutBuffer[3] = 0;
break;
case 'd':
GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
break;
case 'g': /* return the value of the CPU Registers */
GspGetRegisters(GspOutBuffer, TrapFrame);
break;
case 'G': /* set the value of the CPU Registers - return OK */
if (NULL != GspDbgThread)
{
GspSetRegistersInTrapFrame(ptr, Context, GspDbgThread->Tcb.TrapFrame);
}
else
{
GspSetRegistersInTrapFrame(ptr, Context, TrapFrame);
}
strcpy(GspOutBuffer, "OK");
break;
case 'P': /* set the value of a single CPU register - return OK */
{
LONG Register;
if ((GspHex2Long(&ptr, &Register)) && (*ptr++ == '='))
{
if ((Register >= 0) && (Register < NUMREGS))
{
if (GspDbgThread)
{
GspSetSingleRegisterInTrapFrame(ptr, Register,
Context,
GspDbgThread->Tcb.TrapFrame);
}
else
{
GspSetSingleRegisterInTrapFrame(ptr, Register,
Context, TrapFrame);
}
strcpy(GspOutBuffer, "OK");
break;
}
}
strcpy(GspOutBuffer, "E01");
break;
}
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
case 'm':
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
if (GspHex2Long(&ptr, &Address) &&
*(ptr++) == ',' &&
GspHex2Long(&ptr, &Length))
{
PEPROCESS DbgProcess = NULL;
ptr = NULL;
if (NULL != GspDbgThread &&
PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
{
DbgProcess = GspDbgThread->ThreadsProcess;
KeAttachProcess(&DbgProcess->Pcb);
}
GspMemoryError = FALSE;
GspMem2Hex((PCHAR) Address, GspOutBuffer, Length, 1);
if (NULL != DbgProcess)
{
KeDetachProcess();
}
if (GspMemoryError)
{
strcpy(GspOutBuffer, "E03");
DPRINT("Fault during memory read\n");
}
}
if (NULL != ptr)
{
strcpy(GspOutBuffer, "E01");
}
break;
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
case 'M':
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
if (GspHex2Long(&ptr, &Address))
{
if (*(ptr++) == ',' &&
GspHex2Long(&ptr, &Length) &&
*(ptr++) == ':')
{
PEPROCESS DbgProcess = NULL;
if (NULL != GspDbgThread &&
PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
{
DbgProcess = GspDbgThread->ThreadsProcess;
KeAttachProcess(&DbgProcess->Pcb);
}
GspMemoryError = FALSE;
GspHex2Mem(ptr, (PCHAR) Address, Length, TRUE);
if (NULL != DbgProcess)
{
KeDetachProcess();
}
if (GspMemoryError)
{
strcpy(GspOutBuffer, "E03");
DPRINT("Fault during memory write\n");
}
else
{
strcpy(GspOutBuffer, "OK");
}
ptr = NULL;
}
}
if (NULL != ptr)
{
strcpy(GspOutBuffer, "E02");
}
break;
/* cAA..AA Continue at address AA..AA(optional) */
/* sAA..AA Step one instruction from AA..AA(optional) */
case 's':
Stepping = TRUE;
case 'c':
{
ULONG BreakpointNumber;
ULONG dr6_;
/* try to read optional parameter, pc unchanged if no parm */
if (GspHex2Long (&ptr, &Address))
{
Context->Eip = Address;
}
NewPC = Context->Eip;
/* clear the trace bit */
Context->EFlags &= 0xfffffeff;
/* set the trace bit if we're Stepping */
if (Stepping)
{
Context->EFlags |= 0x100;
}
#if defined(__GNUC__)
asm volatile ("movl %%db6, %0\n" : "=r" (dr6_) : );
#elif defined(_MSC_VER)
__asm mov eax, dr6 __asm mov dr6_, eax;
#else
#error Unknown compiler for inline assembler
#endif
if (!(dr6_ & 0x4000))
{
for (BreakpointNumber = 0; BreakpointNumber < 4; ++BreakpointNumber)
{
if (dr6_ & (1 << BreakpointNumber))
{
if (GspHwBreakpoints[BreakpointNumber].Type == 0)
{
/* Set restore flag */
Context->EFlags |= 0x10000;
break;
}
}
}
}
GspLoadBreakpoints(TrapFrame);
#if defined(__GNUC__)
asm volatile ("movl %0, %%db6\n" : : "r" (0));
#elif defined(_MSC_VER)
__asm mov eax, 0 __asm mov dr6, eax;
#else
#error Unknown compiler for inline assembler
#endif
if (NULL != GspDbgThread)
{
ObDereferenceObject(GspDbgThread);
GspDbgThread = NULL;
}
DPRINT("Thread %p releasing mutex\n", PsGetCurrentThread());
ExReleaseFastMutex(&GspLock);
DPRINT("Thread %p leaving stub\n", PsGetCurrentThread());
return kdContinue;
break;
}
case 'k': /* kill the program */
strcpy(GspOutBuffer, "OK");
break;
/* kill the program */
case 'H': /* Set thread */
GspSetThread(ptr);
break;
case 'q': /* Query */
GspQuery(ptr);
break;
case 'T': /* Query thread status */
GspQueryThreadStatus(ptr);
break;
case 'Z':
{
LONG Type;
LONG Address;
LONG Length;
GspHex2Long(&ptr, &Type);
ptr++;
GspHex2Long(&ptr, &Address);
ptr++;
GspHex2Long(&ptr, &Length);
if (0 == Type)
{
GspSetSwBreakpoint((ULONG_PTR) Address);
}
else
{
GspSetHwBreakpoint(Type, (ULONG_PTR) Address, Length);
}
break;
}
case 'z':
{
LONG Type;
LONG Address;
LONG Length;
GspHex2Long(&ptr, &Type);
ptr++;
GspHex2Long(&ptr, &Address);
ptr++;
GspHex2Long(&ptr, &Length);
if (0 == Type)
{
GspRemoveSwBreakpoint((ULONG_PTR) Address);
}
else
{
GspRemoveHwBreakpoint(Type, (ULONG_PTR) Address, Length);
}
break;
}
default:
break;
}
/* reply to the request */
GspPutPacket(GspOutBuffer);
}
/* not reached */
ASSERT(0);
}
if (NULL != GspDbgThread)
{
ObDereferenceObject(GspDbgThread);
GspDbgThread = NULL;
}
return kdContinue;
}
BOOLEAN
STDCALL
GspBreakIn(PKINTERRUPT Interrupt,
PVOID ServiceContext)
{
PKTRAP_FRAME TrapFrame;
BOOLEAN DoBreakIn;
CONTEXT Context;
KIRQL OldIrql;
UCHAR Value;
DPRINT("Break In\n");
DoBreakIn = FALSE;
while (KdPortGetByteEx(&GdbPortInfo, &Value))
{
if (Value == 0x03)
{
DoBreakIn = TRUE;
}
}
if (!DoBreakIn)
{
return TRUE;
}
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
KeTrapFrameToContext(TrapFrame, NULL, &Context);
KdpGdbEnterDebuggerException(NULL, &Context, TrapFrame);
KeContextToTrapFrame(&Context, NULL, TrapFrame, Context.ContextFlags, KernelMode);
KeLowerIrql(OldIrql);
return TRUE;
}
VOID
STDCALL
KdpGdbDebugPrint(PCH Message, ULONG Length)
{
}
/* Initialize the GDB stub */
VOID
STDCALL
KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable,
ULONG BootPhase)
{
if (!KdDebuggerEnabled || !KdpDebugMode.Gdb)
{
return;
}
if (BootPhase == 0)
{
ExInitializeFastMutex(&GspLock);
/* Write out the functions that we support for now */
WrapperTable->KdpInitRoutine = KdpGdbStubInit;
WrapperTable->KdpPrintRoutine = KdpGdbDebugPrint;
WrapperTable->KdpExceptionRoutine = KdpGdbEnterDebuggerException;
/* Initialize the Port */
KdPortInitializeEx(&GdbPortInfo, 0, 0);
KdpPort = GdbPortInfo.ComPort;
}
else if (BootPhase == 1)
{
GspInitialized = TRUE;
GspRunThread = NULL;
GspDbgThread = NULL;
GspEnumThread = NULL;
HalDisplayString("Waiting for GDB to attach\n");
DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}
else if (BootPhase == 2)
{
HalDisplayString("\n GDB debugging enabled\n\n");
}
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -