You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
732 lines
23 KiB
732 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1992-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbgctrl.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the NtDebugControl service
|
|
|
|
Author:
|
|
|
|
Chuck Lenzmeier (chuckl) 2-Dec-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "exp.h"
|
|
|
|
#pragma hdrstop
|
|
#include "kdp.h"
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE, NtSystemDebugControl)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NtSystemDebugControl (
|
|
IN SYSDBG_COMMAND Command,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function controls the system debugger.
|
|
|
|
Arguments:
|
|
|
|
Command - The command to be executed. One of the following:
|
|
|
|
SysDbgQueryTraceInformation
|
|
SysDbgSetTracepoint
|
|
SysDbgSetSpecialCall
|
|
SysDbgClearSpecialCalls
|
|
SysDbgQuerySpecialCalls
|
|
|
|
InputBuffer - A pointer to a buffer describing the input data for
|
|
the request, if any. The structure of this buffer varies
|
|
depending upon Command.
|
|
|
|
InputBufferLength - The length in bytes of InputBuffer.
|
|
|
|
OutputBuffer - A pointer to a buffer that is to receive the output
|
|
data for the request, if any. The structure of this buffer
|
|
varies depending upon Command.
|
|
|
|
OutputBufferLength - The length in bytes of OutputBuffer.
|
|
|
|
ReturnLength - A optional pointer to a ULONG that is to receive the
|
|
output data length for the request.
|
|
|
|
Return Value:
|
|
|
|
Returns one of the following status codes:
|
|
|
|
STATUS_SUCCESS - normal, successful completion.
|
|
|
|
STATUS_INVALID_INFO_CLASS - The Command parameter did not
|
|
specify a valid value.
|
|
|
|
STATUS_INFO_LENGTH_MISMATCH - The value of the Length field in the
|
|
Parameters buffer was not correct.
|
|
|
|
STATUS_ACCESS_VIOLATION - Either the Parameters buffer pointer
|
|
or a pointer within the Parameters buffer specified an
|
|
invalid address.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
|
for this request to complete.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG length = 0;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PVOID LockedBuffer = NULL;
|
|
PVOID LockVariable = NULL;
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
|
|
if (!SeSinglePrivilegeCheck( SeDebugPrivilege, PreviousMode)) {
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// Operate within a try block in order to catch errors.
|
|
//
|
|
|
|
try {
|
|
|
|
//
|
|
// Probe input and output buffers, if previous mode is not
|
|
// kernel.
|
|
//
|
|
|
|
if ( PreviousMode != KernelMode ) {
|
|
|
|
if ( InputBufferLength != 0 ) {
|
|
ProbeForRead( InputBuffer, InputBufferLength, sizeof(ULONG) );
|
|
}
|
|
|
|
if ( OutputBufferLength != 0 ) {
|
|
ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(ULONG) );
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(ReturnLength) ) {
|
|
ProbeForWriteUlong( ReturnLength );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Switch on the command code.
|
|
//
|
|
|
|
switch ( Command ) {
|
|
|
|
#if i386
|
|
|
|
case SysDbgQueryTraceInformation:
|
|
|
|
status = KdGetTraceInformation(
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
&length
|
|
);
|
|
|
|
break;
|
|
|
|
case SysDbgSetTracepoint:
|
|
|
|
if ( InputBufferLength != sizeof(DBGKD_MANIPULATE_STATE64) ) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
KdSetInternalBreakpoint( InputBuffer );
|
|
|
|
break;
|
|
|
|
case SysDbgSetSpecialCall:
|
|
|
|
if ( InputBufferLength != sizeof(PVOID) ) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
KdSetSpecialCall( InputBuffer, NULL );
|
|
|
|
break;
|
|
|
|
case SysDbgClearSpecialCalls:
|
|
|
|
KdClearSpecialCalls( );
|
|
|
|
break;
|
|
|
|
case SysDbgQuerySpecialCalls:
|
|
|
|
status = KdQuerySpecialCalls(
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
&length
|
|
);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case SysDbgBreakPoint:
|
|
if (KdDebuggerEnabled) {
|
|
DbgBreakPointWithStatus(DBG_STATUS_DEBUG_CONTROL);
|
|
} else {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
break;
|
|
|
|
case SysDbgQueryVersion:
|
|
if (OutputBufferLength != sizeof(DBGKD_GET_VERSION64)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
KdpSysGetVersion((PDBGKD_GET_VERSION64)OutputBuffer);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SysDbgReadVirtual:
|
|
if (InputBufferLength != sizeof(SYSDBG_VIRTUAL)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_VIRTUAL Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_VIRTUAL)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoWriteAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpCopyMemoryChunks((ULONG_PTR)Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
0,
|
|
0,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWriteVirtual:
|
|
if (InputBufferLength != sizeof(SYSDBG_VIRTUAL)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_VIRTUAL Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_VIRTUAL)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoReadAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpCopyMemoryChunks((ULONG_PTR)Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
0,
|
|
MMDBG_COPY_WRITE,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgReadPhysical:
|
|
if (InputBufferLength != sizeof(SYSDBG_PHYSICAL)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_PHYSICAL Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_PHYSICAL)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoWriteAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpCopyMemoryChunks(Cmd.Address.QuadPart,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
0,
|
|
MMDBG_COPY_PHYSICAL,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWritePhysical:
|
|
if (InputBufferLength != sizeof(SYSDBG_PHYSICAL)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_PHYSICAL Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_PHYSICAL)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoReadAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpCopyMemoryChunks(Cmd.Address.QuadPart,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
0,
|
|
MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgReadControlSpace:
|
|
if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_CONTROL_SPACE Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_CONTROL_SPACE)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoWriteAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysReadControlSpace(Cmd.Processor,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWriteControlSpace:
|
|
if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_CONTROL_SPACE Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_CONTROL_SPACE)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoReadAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysWriteControlSpace(Cmd.Processor,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgReadIoSpace:
|
|
if (InputBufferLength != sizeof(SYSDBG_IO_SPACE)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_IO_SPACE Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_IO_SPACE)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoWriteAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysReadIoSpace(Cmd.InterfaceType,
|
|
Cmd.BusNumber,
|
|
Cmd.AddressSpace,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWriteIoSpace:
|
|
if (InputBufferLength != sizeof(SYSDBG_IO_SPACE)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_IO_SPACE Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_IO_SPACE)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoReadAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysWriteIoSpace(Cmd.InterfaceType,
|
|
Cmd.BusNumber,
|
|
Cmd.AddressSpace,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgReadMsr:
|
|
if (InputBufferLength != sizeof(SYSDBG_MSR)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
PSYSDBG_MSR Cmd = (PSYSDBG_MSR)InputBuffer;
|
|
|
|
status = KdpSysReadMsr(Cmd->Msr, &Cmd->Data);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWriteMsr:
|
|
if (InputBufferLength != sizeof(SYSDBG_MSR)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
PSYSDBG_MSR Cmd = (PSYSDBG_MSR)InputBuffer;
|
|
|
|
status = KdpSysWriteMsr(Cmd->Msr, &Cmd->Data);
|
|
}
|
|
break;
|
|
|
|
case SysDbgReadBusData:
|
|
if (InputBufferLength != sizeof(SYSDBG_BUS_DATA)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_BUS_DATA Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_BUS_DATA)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoWriteAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysReadBusData(Cmd.BusDataType,
|
|
Cmd.BusNumber,
|
|
Cmd.SlotNumber,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgWriteBusData:
|
|
if (InputBufferLength != sizeof(SYSDBG_BUS_DATA)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
{
|
|
SYSDBG_BUS_DATA Cmd;
|
|
|
|
//
|
|
// Capture the user information so a malicious app cannot
|
|
// change it on us after we validate it.
|
|
//
|
|
|
|
Cmd = *(PSYSDBG_BUS_DATA)InputBuffer;
|
|
|
|
if (Cmd.Request == 0) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
status = ExLockUserBuffer(Cmd.Buffer,
|
|
Cmd.Request,
|
|
PreviousMode,
|
|
IoReadAccess,
|
|
&LockedBuffer,
|
|
&LockVariable);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
status = KdpSysWriteBusData(Cmd.BusDataType,
|
|
Cmd.BusNumber,
|
|
Cmd.SlotNumber,
|
|
Cmd.Address,
|
|
LockedBuffer,
|
|
Cmd.Request,
|
|
&length);
|
|
}
|
|
break;
|
|
|
|
case SysDbgCheckLowMemory:
|
|
status = KdpSysCheckLowMemory(0);
|
|
break;
|
|
|
|
case SysDbgEnableKernelDebugger:
|
|
status = KdEnableDebugger();
|
|
break;
|
|
|
|
case SysDbgDisableKernelDebugger:
|
|
status = KdDisableDebugger();
|
|
break;
|
|
|
|
case SysDbgGetAutoKdEnable:
|
|
if (OutputBufferLength != sizeof(BOOLEAN)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
*(PBOOLEAN)OutputBuffer = KdAutoEnableOnEvent;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SysDbgSetAutoKdEnable:
|
|
if (InputBufferLength != sizeof(BOOLEAN)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (KdPitchDebugger) {
|
|
status = STATUS_ACCESS_DENIED;
|
|
} else {
|
|
KdAutoEnableOnEvent = *(PBOOLEAN)InputBuffer;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case SysDbgGetPrintBufferSize:
|
|
if (OutputBufferLength != sizeof(ULONG)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (KdPitchDebugger) {
|
|
*(PULONG)OutputBuffer = 0;
|
|
} else {
|
|
*(PULONG)OutputBuffer = KdPrintBufferSize;
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SysDbgSetPrintBufferSize:
|
|
if (InputBufferLength != sizeof(ULONG)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
status = KdSetDbgPrintBufferSize(*(PULONG)InputBuffer);
|
|
break;
|
|
|
|
case SysDbgGetKdUmExceptionEnable:
|
|
if (OutputBufferLength != sizeof(BOOLEAN)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// Reverse sense of flag from enable-um-exceptions
|
|
// to ignore-um-exceptions.
|
|
*(PBOOLEAN)OutputBuffer = KdIgnoreUmExceptions ? FALSE : TRUE;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case SysDbgSetKdUmExceptionEnable:
|
|
if (InputBufferLength != sizeof(BOOLEAN)) {
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
|
|
if (KdPitchDebugger) {
|
|
status = STATUS_ACCESS_DENIED;
|
|
} else {
|
|
// Reverse sense of flag from enable-um-exceptions
|
|
// to ignore-um-exceptions.
|
|
KdIgnoreUmExceptions = *(PBOOLEAN)InputBuffer ? FALSE : TRUE;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Invalid Command.
|
|
//
|
|
|
|
status = STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(ReturnLength) ) {
|
|
*ReturnLength = length;
|
|
}
|
|
}
|
|
|
|
except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
status = GetExceptionCode();
|
|
|
|
}
|
|
|
|
if (LockedBuffer) {
|
|
ExUnlockUserBuffer(LockVariable);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // NtSystemDebugControl
|