mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
1321 lines
37 KiB
C
1321 lines
37 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/kd64/kdapi.c
|
|
* PURPOSE: KD64 Public Routines and Internal Support
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;
|
|
STRING Header;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
/* Validate the address space */
|
|
if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)
|
|
{
|
|
/* Check if this is process memory */
|
|
if ((PVOID)(LONG_PTR)Memory->Address < MmHighestUserAddress)
|
|
{
|
|
/* It is */
|
|
Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;
|
|
}
|
|
else
|
|
{
|
|
/* FIXME: Check if it's session space */
|
|
Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;
|
|
}
|
|
|
|
/* Set flags */
|
|
Memory->Flags = DBGKD_QUERY_MEMORY_READ |
|
|
DBGKD_QUERY_MEMORY_WRITE |
|
|
DBGKD_QUERY_MEMORY_EXECUTE;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid */
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Return structure */
|
|
State->ReturnStatus = Status;
|
|
Memory->Reserved = 0;
|
|
|
|
/* Build header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
|
|
/* Send the packet */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
NULL,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;
|
|
STRING Header;
|
|
|
|
/* Build header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
ASSERT(Data->Length == 0);
|
|
|
|
/* Create the breakpoint */
|
|
Breakpoint->BreakPointHandle =
|
|
KdpAddBreakpoint((PVOID)(LONG_PTR)Breakpoint->BreakPointAddress);
|
|
if (!Breakpoint->BreakPointHandle)
|
|
{
|
|
/* We failed */
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
/* Success! */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Send the packet */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
NULL,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DumpTraceData(IN PSTRING TraceData)
|
|
{
|
|
/* Update the buffer */
|
|
TraceDataBuffer[0] = TraceDataBufferPosition;
|
|
|
|
/* Setup the trace data */
|
|
TraceData->Length = TraceDataBufferPosition * sizeof(ULONG);
|
|
TraceData->Buffer = (PCHAR)TraceDataBuffer;
|
|
|
|
/* Reset the buffer location */
|
|
TraceDataBufferPosition = 1;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpGetStateChange(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PKPRCB Prcb;
|
|
ULONG i;
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(State->u.Continue2.ContinueStatus))
|
|
{
|
|
/* Check if we're tracing */
|
|
if (State->u.Continue2.ControlSet.TraceFlag)
|
|
{
|
|
/* Enable TF */
|
|
Context->EFlags |= EFLAGS_TF;
|
|
}
|
|
else
|
|
{
|
|
/* Remove it */
|
|
Context->EFlags &= ~EFLAGS_TF;
|
|
}
|
|
|
|
/* Loop all processors */
|
|
for (i = 0; i < KeNumberProcessors; i++)
|
|
{
|
|
/* Get the PRCB and update DR7 and DR6 */
|
|
Prcb = KiProcessorBlock[i];
|
|
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
|
|
State->u.Continue2.ControlSet.Dr7;
|
|
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0;
|
|
}
|
|
|
|
/* Check if we have new symbol information */
|
|
if (State->u.Continue2.ControlSet.CurrentSymbolStart != 1)
|
|
{
|
|
/* Update it */
|
|
KdpCurrentSymbolStart =
|
|
State->u.Continue2.ControlSet.CurrentSymbolStart;
|
|
KdpCurrentSymbolEnd= State->u.Continue2.ControlSet.CurrentSymbolEnd;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSetCommonState(IN ULONG NewState,
|
|
IN PCONTEXT Context,
|
|
IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
|
|
{
|
|
USHORT InstructionCount;
|
|
BOOLEAN HadBreakpoints;
|
|
|
|
/* Setup common stuff available for all CPU architectures */
|
|
WaitStateChange->NewState = NewState;
|
|
WaitStateChange->ProcessorLevel = KeProcessorLevel;
|
|
WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
|
|
WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
|
|
WaitStateChange->Thread = (ULONG)(LONG_PTR)KeGetCurrentThread();
|
|
WaitStateChange->ProgramCounter = (ULONG)(LONG_PTR)Context->Eip;
|
|
|
|
/* Zero out the Control Report */
|
|
RtlZeroMemory(&WaitStateChange->ControlReport,
|
|
sizeof(DBGKD_CONTROL_REPORT));
|
|
|
|
/* Now copy the instruction stream and set the count */
|
|
RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
|
|
(PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
|
|
DBGKD_MAXSTREAM);
|
|
InstructionCount = DBGKD_MAXSTREAM;
|
|
WaitStateChange->ControlReport.InstructionCount = InstructionCount;
|
|
|
|
/* Clear all the breakpoints in this region */
|
|
HadBreakpoints =
|
|
KdpDeleteBreakpointRange((PVOID)(LONG_PTR)WaitStateChange->ProgramCounter,
|
|
(PVOID)((ULONG)WaitStateChange->ProgramCounter +
|
|
WaitStateChange->ControlReport.InstructionCount - 1));
|
|
if (HadBreakpoints)
|
|
{
|
|
/* Copy the instruction stream again, this time without breakpoints */
|
|
RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
|
|
(PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
|
|
WaitStateChange->ControlReport.InstructionCount);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSetContextState(IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
|
|
/* Copy i386 specific debug registers */
|
|
WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.
|
|
KernelDr6;
|
|
WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.
|
|
KernelDr7;
|
|
|
|
/* Copy i386 specific segments */
|
|
WaitStateChange->ControlReport.SegCs = (USHORT)Context->SegCs;
|
|
WaitStateChange->ControlReport.SegDs = (USHORT)Context->SegDs;
|
|
WaitStateChange->ControlReport.SegEs = (USHORT)Context->SegEs;
|
|
WaitStateChange->ControlReport.SegFs = (USHORT)Context->SegFs;
|
|
|
|
/* Copy EFlags */
|
|
WaitStateChange->ControlReport.EFlags = Context->EFlags;
|
|
|
|
/* Set Report Flags */
|
|
WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS;
|
|
if (WaitStateChange->ControlReport.SegCs == KGDT_R0_CODE)
|
|
{
|
|
WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_CS;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
|
|
{
|
|
/* Copy the version block */
|
|
RtlCopyMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
|
|
{
|
|
STRING Header;
|
|
|
|
/* Fill out the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
|
|
/* Get the version block */
|
|
KdpSysGetVersion(&State->u.GetVersion64);
|
|
|
|
/* Fill out the state */
|
|
State->ApiNumber = DbgKdGetVersionApi;
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
|
|
/* Send the packet */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
NULL,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
STRING Header;
|
|
ULONG Length = State->u.ReadMemory.TransferCount;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
/* Validate length */
|
|
if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
|
|
{
|
|
/* Overflow, set it to maximum possible */
|
|
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
|
|
}
|
|
|
|
#if 0
|
|
if (!MmIsAddressValid((PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress))
|
|
{
|
|
Ke386SetCr2(State->u.ReadMemory.TargetBaseAddress);
|
|
while (TRUE);
|
|
}
|
|
#endif
|
|
|
|
if (!State->u.ReadMemory.TargetBaseAddress)
|
|
{
|
|
Length = 0;
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(Data->Buffer,
|
|
(PVOID)(ULONG_PTR)State->u.ReadMemory.TargetBaseAddress,
|
|
Length);
|
|
}
|
|
|
|
/* Fill out the header */
|
|
Data->Length = Length;
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
|
|
/* Fill out the state */
|
|
State->ReturnStatus = Status;
|
|
State->u.ReadMemory.ActualBytesRead = Length;
|
|
|
|
/* Send the packet */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
Data,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
|
|
STRING Header;
|
|
ULONG Length, RealLength;
|
|
PVOID ControlStart;
|
|
|
|
/* Setup the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
ASSERT(Data->Length == 0);
|
|
|
|
/* Check the length requested */
|
|
Length = ReadMemory->TransferCount;
|
|
if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
|
|
{
|
|
/* Use maximum allowed */
|
|
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
|
|
}
|
|
|
|
/* Make sure that this is a valid request */
|
|
if (((ULONG)ReadMemory->TargetBaseAddress < sizeof(KPROCESSOR_STATE)) &&
|
|
(State->Processor < KeNumberProcessors))
|
|
{
|
|
/* Get the actual length */
|
|
RealLength = sizeof(KPROCESSOR_STATE) -
|
|
(ULONG_PTR)ReadMemory->TargetBaseAddress;
|
|
if (RealLength < Length) Length = RealLength;
|
|
|
|
/* Set the proper address */
|
|
ControlStart = (PVOID)((ULONG_PTR)ReadMemory->TargetBaseAddress +
|
|
(ULONG_PTR)&KiProcessorBlock[State->Processor]->
|
|
ProcessorState);
|
|
|
|
/* Copy the memory */
|
|
RtlCopyMemory(Data->Buffer, ControlStart, Length);
|
|
Data->Length = Length;
|
|
|
|
/* Finish up */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
ReadMemory->ActualBytesRead = Data->Length;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid request */
|
|
Data->Length = 0;
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
ReadMemory->ActualBytesRead = 0;
|
|
}
|
|
|
|
/* Send the reply */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
Data,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
|
|
STRING Header;
|
|
ULONG Length;
|
|
PVOID ControlStart;
|
|
|
|
/* Setup the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
|
|
/* Make sure that this is a valid request */
|
|
Length = WriteMemory->TransferCount;
|
|
if ((((ULONG)WriteMemory->TargetBaseAddress + Length) <=
|
|
sizeof(KPROCESSOR_STATE)) &&
|
|
(State->Processor < KeNumberProcessors))
|
|
{
|
|
/* Set the proper address */
|
|
ControlStart = (PVOID)((ULONG_PTR)WriteMemory->TargetBaseAddress +
|
|
(ULONG_PTR)&KiProcessorBlock[State->Processor]->
|
|
ProcessorState);
|
|
|
|
/* Copy the memory */
|
|
RtlCopyMemory(ControlStart, Data->Buffer, Data->Length);
|
|
Length = Data->Length;
|
|
|
|
/* Finish up */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
WriteMemory->ActualBytesWritten = Length;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid request */
|
|
Data->Length = 0;
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
WriteMemory->ActualBytesWritten = 0;
|
|
}
|
|
|
|
/* Send the reply */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
Data,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
|
|
STRING Header;
|
|
|
|
/* Fill out the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
ASSERT(Data->Length == 0);
|
|
|
|
/* Get the version block */
|
|
if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
|
|
{
|
|
/* We're all good */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* We failed */
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Send the packet */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
NULL,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
STRING Header;
|
|
PVOID ControlStart;
|
|
|
|
/* Setup the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
ASSERT(Data->Length == 0);
|
|
|
|
/* Make sure that this is a valid request */
|
|
if (State->Processor < KeNumberProcessors)
|
|
{
|
|
/* Check if the request is for this CPU */
|
|
if (State->Processor == KeGetCurrentPrcb()->Number)
|
|
{
|
|
/* We're just copying our own context */
|
|
ControlStart = Context;
|
|
}
|
|
else
|
|
{
|
|
/* SMP not yet handled */
|
|
ControlStart = NULL;
|
|
while (TRUE);
|
|
}
|
|
|
|
/* Copy the memory */
|
|
RtlCopyMemory(Data->Buffer, ControlStart, sizeof(CONTEXT));
|
|
Data->Length = sizeof(CONTEXT);
|
|
|
|
/* Finish up */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid request */
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Send the reply */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
Data,
|
|
&KdpContext);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
|
|
IN PSTRING Data,
|
|
IN PCONTEXT Context)
|
|
{
|
|
STRING Header;
|
|
PVOID ControlStart;
|
|
|
|
/* Setup the header */
|
|
Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)State;
|
|
ASSERT(Data->Length == sizeof(CONTEXT));
|
|
|
|
/* Make sure that this is a valid request */
|
|
if (State->Processor < KeNumberProcessors)
|
|
{
|
|
/* Check if the request is for this CPU */
|
|
if (State->Processor == KeGetCurrentPrcb()->Number)
|
|
{
|
|
/* We're just copying our own context */
|
|
ControlStart = Context;
|
|
}
|
|
else
|
|
{
|
|
/* SMP not yet handled */
|
|
ControlStart = NULL;
|
|
while (TRUE);
|
|
}
|
|
|
|
/* Copy the memory */
|
|
RtlCopyMemory(ControlStart, Data->Buffer, sizeof(CONTEXT));
|
|
|
|
/* Finish up */
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid request */
|
|
State->ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Send the reply */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
Data,
|
|
&KdpContext);
|
|
}
|
|
|
|
KCONTINUE_STATUS
|
|
NTAPI
|
|
KdpSendWaitContinue(IN ULONG PacketType,
|
|
IN PSTRING SendHeader,
|
|
IN PSTRING SendData OPTIONAL,
|
|
IN OUT PCONTEXT Context)
|
|
{
|
|
STRING Data, Header;
|
|
DBGKD_MANIPULATE_STATE64 ManipulateState;
|
|
ULONG Length;
|
|
KDSTATUS RecvCode;
|
|
|
|
/* Setup the Manipulate State structure */
|
|
Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
|
|
Header.Buffer = (PCHAR)&ManipulateState;
|
|
Data.MaximumLength = sizeof(KdpMessageBuffer);
|
|
Data.Buffer = KdpMessageBuffer;
|
|
//KdpContextSent = FALSE;
|
|
|
|
SendPacket:
|
|
/* Send the Packet */
|
|
KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
|
|
|
|
/* If the debugger isn't present anymore, just return success */
|
|
if (KdDebuggerNotPresent) return ContinueSuccess;
|
|
|
|
/* Main processing Loop */
|
|
for (;;)
|
|
{
|
|
/* Receive Loop */
|
|
do
|
|
{
|
|
/* Wait to get a reply to our packet */
|
|
RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
&Data,
|
|
&Length,
|
|
&KdpContext);
|
|
|
|
/* If we got a resend request, do it */
|
|
if (RecvCode == KdPacketNeedsResend) goto SendPacket;
|
|
} while (RecvCode == KdPacketTimedOut);
|
|
|
|
/* Now check what API we got */
|
|
switch (ManipulateState.ApiNumber)
|
|
{
|
|
case DbgKdReadVirtualMemoryApi:
|
|
|
|
/* Read virtual memory */
|
|
KdpReadVirtualMemory(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdWriteVirtualMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdGetContextApi:
|
|
|
|
/* Get the current context */
|
|
KdpGetContext(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdSetContextApi:
|
|
|
|
/* Set a new context */
|
|
KdpSetContext(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdWriteBreakPointApi:
|
|
|
|
/* Write the breakpoint */
|
|
KdpWriteBreakpoint(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdRestoreBreakPointApi:
|
|
|
|
/* FIXME: TODO */
|
|
KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdContinueApi:
|
|
|
|
/* Simply continue */
|
|
return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
|
|
|
|
case DbgKdReadControlSpaceApi:
|
|
|
|
/* Read control space */
|
|
KdpReadControlSpace(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdWriteControlSpaceApi:
|
|
|
|
/* FIXME: TODO */
|
|
KdpWriteControlSpace(&ManipulateState, &Data, Context);
|
|
break;
|
|
|
|
case DbgKdReadIoSpaceApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdReadIoSpaceApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdWriteIoSpaceApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWriteIoSpaceApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdRebootApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdRebootApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdContinueApi2:
|
|
|
|
/* Check if caller reports success */
|
|
if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
|
|
{
|
|
/* Update the state */
|
|
KdpGetStateChange(&ManipulateState, Context);
|
|
return ContinueSuccess;
|
|
}
|
|
else
|
|
{
|
|
/* Return an error */
|
|
return ContinueError;
|
|
}
|
|
break;
|
|
|
|
case DbgKdReadPhysicalMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
goto fail;
|
|
Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdWritePhysicalMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdQuerySpecialCallsApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdQuerySpecialCallsApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdSetSpecialCallApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSetSpecialCallApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdClearSpecialCallsApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdClearSpecialCallsApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdSetInternalBreakPointApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSetInternalBreakPointApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdGetInternalBreakPointApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdGetInternalBreakPointApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdReadIoSpaceExtendedApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdWriteIoSpaceExtendedApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdGetVersionApi:
|
|
|
|
/* Get version data */
|
|
KdpGetVersion(&ManipulateState);
|
|
break;
|
|
|
|
case DbgKdWriteBreakPointExApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWriteBreakPointExApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdRestoreBreakPointExApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdRestoreBreakPointExApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdCauseBugCheckApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdCauseBugCheckApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdSwitchProcessor:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSwitchProcessor);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdPageInApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdPageInApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdReadMachineSpecificRegister:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdReadMachineSpecificRegister);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdWriteMachineSpecificRegister:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdWriteMachineSpecificRegister);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case OldVlm1:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(OldVlm1);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case OldVlm2:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(OldVlm2);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdSearchMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSearchMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdGetBusDataApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdGetBusDataApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdSetBusDataApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSetBusDataApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdCheckLowMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdCheckLowMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdClearAllInternalBreakpointsApi:
|
|
|
|
/* Just clear the counter */
|
|
KdpNumInternalBreakpoints = 0;
|
|
break;
|
|
|
|
case DbgKdFillMemoryApi:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdFillMemoryApi);
|
|
while (TRUE);
|
|
break;
|
|
|
|
case DbgKdQueryMemoryApi:
|
|
|
|
/* Query memory */
|
|
KdpQueryMemory(&ManipulateState, Context);
|
|
break;
|
|
|
|
case DbgKdSwitchPartition:
|
|
|
|
/* FIXME: TODO */
|
|
Ke386SetCr2(DbgKdSwitchPartition);
|
|
while (TRUE);
|
|
break;
|
|
|
|
/* Unsupported Message */
|
|
default:
|
|
|
|
/* Setup an empty message, with failure */
|
|
while (TRUE);
|
|
fail:
|
|
Data.Length = 0;
|
|
ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
/* Send it */
|
|
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
&Header,
|
|
&Data,
|
|
&KdpContext);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
|
|
IN PKD_SYMBOLS_INFO SymbolInfo,
|
|
IN BOOLEAN Unload,
|
|
IN OUT PCONTEXT Context)
|
|
{
|
|
PSTRING ExtraData;
|
|
STRING Data, Header;
|
|
DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
|
|
KCONTINUE_STATUS Status;
|
|
|
|
/* Start wait loop */
|
|
do
|
|
{
|
|
/* Build the architecture common parts of the message */
|
|
KdpSetCommonState(DbgKdLoadSymbolsStateChange,
|
|
Context,
|
|
&WaitStateChange);
|
|
|
|
/* Now finish creating the structure */
|
|
KdpSetContextState(&WaitStateChange, Context);
|
|
|
|
/* Fill out load data */
|
|
WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
|
|
WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONGLONG)(LONG_PTR)SymbolInfo->BaseOfDll;
|
|
WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
|
|
WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
|
|
WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
|
|
|
|
/* Check if we have a symbol name */
|
|
if (PathName)
|
|
{
|
|
/* Setup the information */
|
|
WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
|
|
RtlCopyMemory(KdpPathBuffer, PathName->Buffer, PathName->Length);
|
|
Data.Buffer = KdpPathBuffer;
|
|
Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
|
|
ExtraData = &Data;
|
|
}
|
|
else
|
|
{
|
|
/* No name */
|
|
WaitStateChange.u.LoadSymbols.PathNameLength = 0;
|
|
ExtraData = NULL;
|
|
}
|
|
|
|
/* Setup the header */
|
|
Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
|
|
Header.Buffer = (PCHAR)&WaitStateChange;
|
|
|
|
/* Send the packet */
|
|
Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
|
|
&Header,
|
|
ExtraData,
|
|
Context);
|
|
} while(Status == ContinueProcessorReselected);
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN OUT PCONTEXT Context,
|
|
IN BOOLEAN SecondChanceException)
|
|
{
|
|
STRING Header, Data;
|
|
DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
|
|
BOOLEAN Status;
|
|
|
|
/* Start report loop */
|
|
do
|
|
{
|
|
/* Build the architecture common parts of the message */
|
|
KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
|
|
|
|
/* Convert the exception record to 64-bits and set First Chance flag */
|
|
ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
|
|
&WaitStateChange.u.Exception.ExceptionRecord);
|
|
WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
|
|
|
|
/* Now finish creating the structure */
|
|
KdpSetContextState(&WaitStateChange, Context);
|
|
|
|
/* Setup the actual header to send to KD */
|
|
Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
|
|
Header.Buffer = (PCHAR)&WaitStateChange;
|
|
|
|
/* Setup the trace data */
|
|
DumpTraceData(&Data);
|
|
|
|
/* Send State Change packet and wait for a reply */
|
|
Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
|
|
&Header,
|
|
&Data,
|
|
Context);
|
|
} while (Status == KdPacketNeedsResend);
|
|
|
|
/* Return */
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2)
|
|
{
|
|
LONG OldSlip, NewSlip, PendingSlip;
|
|
|
|
/* Get the current pending slip */
|
|
PendingSlip = KdpTimeSlipPending;
|
|
do
|
|
{
|
|
/* Save the old value and either disable or enable it now. */
|
|
OldSlip = PendingSlip;
|
|
NewSlip = OldSlip > 1 ? 1 : 0;
|
|
|
|
/* Try to change the value */
|
|
} while (InterlockedCompareExchange(&KdpTimeSlipPending,
|
|
NewSlip,
|
|
OldSlip) != OldSlip);
|
|
|
|
/* If the New Slip value is 1, then do the Time Slipping */
|
|
if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpTimeSlipWork(IN PVOID Context)
|
|
{
|
|
KIRQL OldIrql;
|
|
LARGE_INTEGER DueTime;
|
|
|
|
/* Update the System time from the CMOS */
|
|
ExAcquireTimeRefreshLock(FALSE);
|
|
ExUpdateSystemTimeFromCmos(FALSE, 0);
|
|
ExReleaseTimeRefreshLock();
|
|
|
|
/* Check if we have a registered Time Slip Event and signal it */
|
|
KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
|
|
if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
|
|
KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
|
|
|
|
/* Delay the DPC until it runs next time */
|
|
DueTime.QuadPart = -1800000000;
|
|
KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
|
|
IN OUT PCONTEXT ContextRecord,
|
|
IN BOOLEAN SecondChanceException)
|
|
{
|
|
BOOLEAN Status;
|
|
|
|
/* Save the port data */
|
|
KdSave(FALSE);
|
|
|
|
/* Report a state change */
|
|
Status = KdpReportExceptionStateChange(ExceptionRecord,
|
|
ContextRecord,
|
|
SecondChanceException);
|
|
|
|
/* Restore the port data and return */
|
|
KdRestore(FALSE);
|
|
return Status;
|
|
}
|
|
|
|
LARGE_INTEGER
|
|
NTAPI
|
|
KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
|
|
{
|
|
LARGE_INTEGER Null = {{0}};
|
|
|
|
/* Check if interrupts were disabled */
|
|
if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
|
|
{
|
|
/* Nothing to return */
|
|
return Null;
|
|
}
|
|
|
|
/* Otherwise, do the call */
|
|
return KeQueryPerformanceCounter(NULL);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
|
|
IN PKEXCEPTION_FRAME ExceptionFrame)
|
|
{
|
|
BOOLEAN Entered;
|
|
|
|
/* Check if we have a trap frame */
|
|
if (TrapFrame)
|
|
{
|
|
/* Calculate the time difference for the enter */
|
|
KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
|
|
KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
|
|
KdTimerStart.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
/* No trap frame, so can't calculate */
|
|
KdTimerStop.QuadPart = 0;
|
|
}
|
|
|
|
/* Save the current IRQL */
|
|
KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
|
|
|
|
/* Freeze all CPUs */
|
|
Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
|
|
|
|
/* Lock the port, save the state and set debugger entered */
|
|
KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
|
|
KdSave(FALSE);
|
|
KdEnteredDebugger = TRUE;
|
|
|
|
/* Check freeze flag */
|
|
if (KiFreezeFlag & 1)
|
|
{
|
|
/* Print out errror */
|
|
DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
|
|
}
|
|
|
|
/* Check processor state */
|
|
if (KiFreezeFlag & 2)
|
|
{
|
|
/* Print out errror */
|
|
DbgPrint("Some processors not frozen in debugger!\n");
|
|
}
|
|
|
|
/* Make sure we acquired the port */
|
|
if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
|
|
|
|
/* Return enter state */
|
|
return Entered;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdExitDebugger(IN BOOLEAN Entered)
|
|
{
|
|
ULONG TimeSlip;
|
|
|
|
/* Restore the state and unlock the port */
|
|
KdRestore(FALSE);
|
|
if (KdpPortLocked) KdpPortUnlock();
|
|
|
|
/* Unfreeze the CPUs */
|
|
KeThawExecution(Entered);
|
|
|
|
/* Compare time with the one from KdEnterDebugger */
|
|
if (!KdTimerStop.QuadPart)
|
|
{
|
|
/* We didn't get a trap frame earlier in so never got the time */
|
|
KdTimerStart = KdTimerStop;
|
|
}
|
|
else
|
|
{
|
|
/* Query the timer */
|
|
KdTimerStart = KeQueryPerformanceCounter(NULL);
|
|
}
|
|
|
|
/* Check if a Time Slip was on queue */
|
|
TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
|
|
if (TimeSlip == 1)
|
|
{
|
|
/* Queue a DPC for the time slip */
|
|
InterlockedIncrement(&KdpTimeSlipPending);
|
|
KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KdEnableDebuggerWithLock(BOOLEAN NeedLock)
|
|
{
|
|
KIRQL OldIrql = PASSIVE_LEVEL;
|
|
|
|
/* Check if we need to acquire the lock */
|
|
if (NeedLock)
|
|
{
|
|
/* Lock the port */
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
KdpPortLock();
|
|
}
|
|
|
|
/* Check if we're not disabled */
|
|
if (!KdDisableCount)
|
|
{
|
|
/* Check if we had locked the port before */
|
|
if (NeedLock)
|
|
{
|
|
/* Do the unlock */
|
|
KeLowerIrql(OldIrql);
|
|
KdpPortUnlock();
|
|
}
|
|
|
|
/* Fail: We're already enabled */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Decrease the disable count */
|
|
if (!(--KdDisableCount))
|
|
{
|
|
/* We're now enabled again! Were we enabled before, too? */
|
|
if (KdPreviouslyEnabled)
|
|
{
|
|
/* Reinitialize the Debugger */
|
|
KdInitSystem(0, NULL) ;
|
|
KdpRestoreAllBreakpoints();
|
|
}
|
|
}
|
|
|
|
/* Check if we had locked the port before */
|
|
if (NeedLock)
|
|
{
|
|
/* Yes, now unlock it */
|
|
KeLowerIrql(OldIrql);
|
|
KdpPortUnlock();
|
|
}
|
|
|
|
/* We're done */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KdEnableDebugger(VOID)
|
|
{
|
|
/* Use the internal routine */
|
|
while (TRUE);
|
|
return KdEnableDebuggerWithLock(TRUE);
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KdSystemDebugControl(IN SYSDBG_COMMAND Command,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN OUT PULONG ReturnLength,
|
|
IN KPROCESSOR_MODE PreviousMode)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KdChangeOption(IN KD_OPTION Option,
|
|
IN ULONG InBufferBytes OPTIONAL,
|
|
IN PVOID InBuffer,
|
|
IN ULONG OutBufferBytes OPTIONAL,
|
|
OUT PVOID OutBuffer,
|
|
OUT PULONG OutBufferNeeded OPTIONAL)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KdPowerTransition(IN DEVICE_POWER_STATE NewState)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KdDisableDebugger(VOID)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NtQueryDebugFilterState(ULONG ComponentId,
|
|
ULONG Level)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSetDebugFilterState(ULONG ComponentId,
|
|
ULONG Level,
|
|
BOOLEAN State)
|
|
{
|
|
/* HACK */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|