windows-nt/Source/XPSP1/NT/drivers/wdm/input/hidclass/debug.c

645 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
debug.c
Abstract
Debug/performance routines
Author:
Ervin P.
Environment:
Kernel mode only
Revision History:
--*/
#include "pch.h"
#if DBG
// can poke this in the debugger to trap for warnings
BOOLEAN dbgTrapOnWarn = FALSE;
BOOLEAN dbgTrapOnSS = FALSE;
BOOLEAN dbgVerbose = FALSE;
BOOLEAN dbgInfo = TRUE;
BOOLEAN dbgSkipSecurity = FALSE;
BOOLEAN dbgTrapOnHiccup = FALSE;
ULONG dbgLastEntry = 0;
ULONG dbgInHidclass = 0;
VOID DbgCommonEntryExit(BOOLEAN isEntering)
{
if (isEntering){
dbgInHidclass++;
#ifdef _X86_
_asm nop
_asm mov eax, [ebp+4] /* <- set breakpt here */
_asm mov dbgLastEntry, eax
#endif
}
else {
dbgInHidclass--;
}
}
VOID InitFdoExtDebugInfo(PHIDCLASS_DEVICE_EXTENSION hidclassExt)
{
FDO_EXTENSION *fdoExt = &hidclassExt->fdoExt;
NTSTATUS status;
ULONG actualLen;
status = IoGetDeviceProperty( hidclassExt->hidExt.PhysicalDeviceObject,
DevicePropertyDriverKeyName,
sizeof(fdoExt->dbgDriverKeyName),
fdoExt->dbgDriverKeyName,
&actualLen);
if (!NT_SUCCESS(status)) {
//
// We couldn't get the driver key name. This will happen during
// textmode setup on NT, for example, when we're loaded as part of
// bootstrapping the system (long before the device installer/class
// installer have run).
//
// Simply initialize the driver key name field to an empty string.
//
*(fdoExt->dbgDriverKeyName) = L'\0';
}
}
ULONG dbgMinInterruptDelta = 0x0fffffff;
ULONG dbgMaxInterruptsPerSecond = 0;
ULONG dbgShortestInt = 0x0fffffff;
ULONG dbgLongestInt = 0;
LARGE_INTEGER dbgLastIntStart = {0};
ULONG dbgAveIntTime = 0;
VOID DbgLogIntStart()
{
static ULONG dbgInterruptsThisSecond = 0;
static ULONG dbgThisSecondStartTime = 0;
LARGE_INTEGER timeNow;
ULONG lastTimeMilliSec, timeNowMilliSec;
KeQuerySystemTime(&timeNow);
// convert from usec to millisec
timeNowMilliSec = timeNow.LowPart/10000;
lastTimeMilliSec = dbgLastIntStart.LowPart/10000;
if (timeNow.HighPart == dbgLastIntStart.HighPart){
ULONG delta = timeNowMilliSec - lastTimeMilliSec;
if (delta < dbgMinInterruptDelta){
dbgMinInterruptDelta = delta;
}
if (timeNowMilliSec - dbgThisSecondStartTime < 1000){
dbgInterruptsThisSecond++;
if (dbgInterruptsThisSecond > dbgMaxInterruptsPerSecond){
dbgMaxInterruptsPerSecond = dbgInterruptsThisSecond;
}
}
else {
dbgThisSecondStartTime = timeNowMilliSec;
dbgInterruptsThisSecond = 0;
}
}
else {
// this case is harder so skip it
dbgThisSecondStartTime = timeNowMilliSec;
dbgInterruptsThisSecond = 0;
}
dbgLastIntStart = timeNow;
}
VOID DbgLogIntEnd()
{
LARGE_INTEGER timeNow;
KeQuerySystemTime(&timeNow);
if (timeNow.HighPart == dbgLastIntStart.HighPart){
ULONG timeNowMilliSec = timeNow.LowPart/10000;
ULONG intStartTimeMilliSec = dbgLastIntStart.LowPart/10000;
ULONG delta = timeNowMilliSec - intStartTimeMilliSec;
if (delta < dbgShortestInt){
dbgShortestInt = delta;
}
else if (delta > dbgLongestInt){
dbgLongestInt = delta;
}
{
static ULONG dbgIntCount = 0;
static ULONG dbgTimeLast1000Ints = 0;
if (dbgIntCount < 1000){
dbgIntCount++;
dbgTimeLast1000Ints += delta;
}
else {
dbgAveIntTime = dbgTimeLast1000Ints/1000;
dbgTimeLast1000Ints = 0;
dbgIntCount = 0;
}
}
}
else {
// This is harder so we just skip it
}
}
NTSTATUS DbgTestGetDeviceStringCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
ExFreePool(Irp->UserBuffer);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID DbgTestGetDeviceString(PFDO_EXTENSION fdoExt)
{
PIRP Irp;
const ULONG inputLen = 200;
Irp = IoAllocateIrp(fdoExt->fdo->StackSize, FALSE);
if (Irp){
Irp->UserBuffer = ALLOCATEPOOL(NonPagedPool, inputLen);
if (Irp->UserBuffer){
ULONG stringId = HID_STRING_ID_IMANUFACTURER;
ULONG languageId = 0x0409; // English
PIO_STACK_LOCATION currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->MdlAddress->MappedSystemVa = Irp->UserBuffer;
Irp->MdlAddress->MdlFlags |= MDL_SOURCE_IS_NONPAGED_POOL;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
currentIrpSp->Parameters.DeviceIoControl.OutputBufferLength = inputLen;
IoSetCompletionRoutine( Irp,
DbgTestGetDeviceStringCompletion,
(PVOID)NULL,
TRUE,
TRUE,
TRUE);
HidpGetDeviceString(fdoExt, Irp, stringId, languageId);
}
}
}
VOID DbgTestGetIndexedString(PFDO_EXTENSION fdoExt)
{
PIRP Irp;
const ULONG inputLen = 200;
Irp = IoAllocateIrp(fdoExt->fdo->StackSize, FALSE);
if (Irp){
Irp->UserBuffer = ALLOCATEPOOL(NonPagedPool, inputLen);
if (Irp->UserBuffer){
ULONG stringIndex = 1; // ???
ULONG languageId = 0x0409; // English
PIO_STACK_LOCATION currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->MdlAddress->MappedSystemVa = Irp->UserBuffer;
Irp->MdlAddress->MdlFlags |= MDL_SOURCE_IS_NONPAGED_POOL;
currentIrpSp->Parameters.DeviceIoControl.InputBufferLength = inputLen;
IoSetCompletionRoutine( Irp,
DbgTestGetDeviceStringCompletion,
(PVOID)NULL,
TRUE,
TRUE,
TRUE);
HidpGetIndexedString(fdoExt, Irp, stringIndex, languageId);
}
}
}
#define DBG_MAX_DEVOBJ_RECORDS 100
dbgDevObjRecord dbgDevObjs[DBG_MAX_DEVOBJ_RECORDS] = {0};
VOID DbgRecordDevObj(PDEVICE_OBJECT devObj, PCHAR str)
{
ULONG i;
for (i = 0; i < DBG_MAX_DEVOBJ_RECORDS; i++){
if (!ISPTR(dbgDevObjs[i].devObj)){
break;
}
else if (dbgDevObjs[i].devObj == devObj){
// already there
break;
}
}
if ((i < DBG_MAX_DEVOBJ_RECORDS) && !dbgDevObjs[i].devObj){
ULONG j;
dbgDevObjs[i].devObj = devObj;
for (j = 0; str[j] && (j < dbgDevObjRecord_STRINGSIZE); j++){
dbgDevObjs[i].str[j] = str[j];
}
}
}
#define DBG_MAX_FEATURE_RECORDS 0x1000
dbgFeatureRecord dbgFeatures[DBG_MAX_FEATURE_RECORDS] = {0};
ULONG dbgFeatureFirstFreeIndex = 0;
VOID DbgRecordReport(ULONG reportId, ULONG controlCode, BOOLEAN isComplete)
{
ULONG typeId;
switch (controlCode){
case IOCTL_HID_GET_FEATURE: typeId = (ULONG)'fteG'; break;
case IOCTL_HID_SET_FEATURE: typeId = (ULONG)'fteS'; break;
case IOCTL_HID_GET_INPUT_REPORT: typeId = (ULONG)'iteG'; break;
case IOCTL_HID_SET_OUTPUT_REPORT: typeId = (ULONG)'oteS'; break;
default: typeId = (ULONG)'xxxx'; TRAP; break;
}
if (isComplete){
LONG i;
// step back to find the report that got completed
// assumes no overlapped calls to same feature
ASSERT(dbgFeatureFirstFreeIndex > 0);
i = dbgFeatureFirstFreeIndex-1;
while ((i >= 0) &&
((dbgFeatures[i].reportId != reportId) ||
(dbgFeatures[i].type != typeId) ||
dbgFeatures[i].completed)){
i--;
}
ASSERT(i >= 0);
if (i >= 0){
dbgFeatures[i].completed = 1;
}
}
else {
if (dbgFeatureFirstFreeIndex >= DBG_MAX_FEATURE_RECORDS){
RtlZeroMemory(dbgFeatures, sizeof(dbgFeatures));
dbgFeatureFirstFreeIndex = 0;
}
dbgFeatures[dbgFeatureFirstFreeIndex].marker = (ULONG)'taeF';
dbgFeatures[dbgFeatureFirstFreeIndex].reportId = reportId;
dbgFeatures[dbgFeatureFirstFreeIndex].type = typeId;
dbgFeatures[dbgFeatureFirstFreeIndex].completed = 0;
dbgFeatureFirstFreeIndex++;
}
}
#define DBG_MAX_READ_RECORDS 0x1000
dbgReadRecord dbgReads[DBG_MAX_READ_RECORDS] = {0};
VOID DbgRecordRead(PIRP irp, ULONG length, ULONG reportId, ULONG completed)
{
LONG i;
for (i = 0;
(i < DBG_MAX_READ_RECORDS) &&
dbgReads[i].irpPtr &&
((dbgReads[i].irpPtr != (ULONG_PTR)irp) || dbgReads[i].completed);
i++){
}
if (i < DBG_MAX_READ_RECORDS){
if (dbgReads[i].irpPtr){
ASSERT(dbgReads[i].irpPtr == (ULONG_PTR)irp);
ASSERT(!dbgReads[i].completed);
ASSERT(completed);
dbgReads[i].length = length;
dbgReads[i].reportId = reportId;
dbgReads[i].completed = completed;
}
else {
dbgReads[i].irpPtr = (ULONG_PTR)irp;
dbgReads[i].length = length;
dbgReads[i].reportId = reportId;
dbgReads[i].completed = completed;
}
}
}
VOID DbgLogIrpMajor(ULONG_PTR irpPtr, ULONG majorFunc, ULONG isForCollectionPdo, ULONG isComplete, ULONG status)
{
if (dbgVerbose){
char *funcName;
switch (majorFunc){
#undef MAKE_CASE
#define MAKE_CASE(fnc) case fnc: funcName = #fnc; break;
MAKE_CASE(IRP_MJ_CREATE)
MAKE_CASE(IRP_MJ_CREATE_NAMED_PIPE)
MAKE_CASE(IRP_MJ_CLOSE)
MAKE_CASE(IRP_MJ_READ)
MAKE_CASE(IRP_MJ_WRITE)
MAKE_CASE(IRP_MJ_QUERY_INFORMATION)
MAKE_CASE(IRP_MJ_SET_INFORMATION)
MAKE_CASE(IRP_MJ_QUERY_EA)
MAKE_CASE(IRP_MJ_SET_EA)
MAKE_CASE(IRP_MJ_FLUSH_BUFFERS)
MAKE_CASE(IRP_MJ_QUERY_VOLUME_INFORMATION)
MAKE_CASE(IRP_MJ_SET_VOLUME_INFORMATION)
MAKE_CASE(IRP_MJ_DIRECTORY_CONTROL)
MAKE_CASE(IRP_MJ_FILE_SYSTEM_CONTROL)
MAKE_CASE(IRP_MJ_DEVICE_CONTROL)
MAKE_CASE(IRP_MJ_INTERNAL_DEVICE_CONTROL)
MAKE_CASE(IRP_MJ_SHUTDOWN)
MAKE_CASE(IRP_MJ_LOCK_CONTROL)
MAKE_CASE(IRP_MJ_CLEANUP)
MAKE_CASE(IRP_MJ_CREATE_MAILSLOT)
MAKE_CASE(IRP_MJ_QUERY_SECURITY)
MAKE_CASE(IRP_MJ_SET_SECURITY)
MAKE_CASE(IRP_MJ_POWER)
MAKE_CASE(IRP_MJ_SYSTEM_CONTROL)
MAKE_CASE(IRP_MJ_DEVICE_CHANGE)
MAKE_CASE(IRP_MJ_QUERY_QUOTA)
MAKE_CASE(IRP_MJ_SET_QUOTA)
MAKE_CASE(IRP_MJ_PNP)
default: funcName = NULL; break;
}
if (isComplete){
if (funcName){
DBGOUT(("< %s for %s status=%xh (irp=%ph)",
funcName,
isForCollectionPdo ? "collection" : "device",
status,
irpPtr));
}
else {
DBGOUT(("< ????<majorFunc=%xh> for %s status=%xh (irp=%ph)",
majorFunc,
isForCollectionPdo ? "collection" : "device",
status,
irpPtr));
}
}
else {
if (funcName){
DBGOUT(("> %s (irp=%xh)", funcName, irpPtr));
}
else {
DBGOUT(("> ????<majorFunc=%xh> (irp=%xh)", majorFunc, irpPtr));
}
}
}
}
#define DBG_MAX_PNP_IRP_RECORDS 0x1000
dbgPnPIrpRecord dbgPnPIrps[DBG_MAX_PNP_IRP_RECORDS] = {0};
VOID DbgLogPnpIrp(ULONG_PTR irpPtr, ULONG minorFunc, ULONG isForCollectionPdo, ULONG isComplete, ULONG status)
{
char *funcName;
ULONG funcShortName;
int i;
switch (minorFunc){
#undef MAKE_CASE
#define MAKE_CASE(fnc) case fnc: funcName = #fnc; funcShortName = *(ULONG *)(funcName+7); break;
MAKE_CASE(IRP_MN_START_DEVICE)
MAKE_CASE(IRP_MN_QUERY_REMOVE_DEVICE)
MAKE_CASE(IRP_MN_REMOVE_DEVICE)
MAKE_CASE(IRP_MN_CANCEL_REMOVE_DEVICE)
MAKE_CASE(IRP_MN_STOP_DEVICE)
MAKE_CASE(IRP_MN_QUERY_STOP_DEVICE)
MAKE_CASE(IRP_MN_CANCEL_STOP_DEVICE)
MAKE_CASE(IRP_MN_QUERY_DEVICE_RELATIONS)
MAKE_CASE(IRP_MN_QUERY_INTERFACE)
MAKE_CASE(IRP_MN_QUERY_CAPABILITIES)
MAKE_CASE(IRP_MN_QUERY_RESOURCES)
MAKE_CASE(IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
MAKE_CASE(IRP_MN_QUERY_DEVICE_TEXT)
MAKE_CASE(IRP_MN_READ_CONFIG)
MAKE_CASE(IRP_MN_WRITE_CONFIG)
MAKE_CASE(IRP_MN_EJECT)
MAKE_CASE(IRP_MN_SET_LOCK)
MAKE_CASE(IRP_MN_QUERY_ID)
MAKE_CASE(IRP_MN_QUERY_PNP_DEVICE_STATE)
MAKE_CASE(IRP_MN_QUERY_BUS_INFORMATION)
MAKE_CASE(IRP_MN_DEVICE_USAGE_NOTIFICATION)
MAKE_CASE(IRP_MN_SURPRISE_REMOVAL)
#ifndef IRP_MN_QUERY_LEGACY_BUS_INFORMATION
#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18
#endif // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
MAKE_CASE(IRP_MN_QUERY_LEGACY_BUS_INFORMATION)
default: funcName = NULL; funcShortName = (ULONG)'\?\?\?\?'; break;
}
if (dbgVerbose){
if (isComplete){
if (funcName){
DBGOUT((" < %s for %s status=%xh (irp=%ph)",
funcName,
isForCollectionPdo ? "collection" : "device",
status,
irpPtr));
}
else {
DBGOUT((" < ?? <minorFunc=%xh> for %s status=%xh (irp=%ph)",
minorFunc,
isForCollectionPdo ? "collection" : "device",
status,
irpPtr));
}
}
else {
if (funcName){
DBGOUT((" > %s for %s (irp=%xh)",
funcName,
isForCollectionPdo ? "collection" : "device",
irpPtr));
}
else {
DBGOUT((" > ?? <minorFunc=%xh> for %s (irp=%xh)",
minorFunc,
isForCollectionPdo ? "collection" : "device",
irpPtr));
}
}
}
if (isComplete){
for (i = 0; (i < DBG_MAX_PNP_IRP_RECORDS) && dbgPnPIrps[i].irpPtr; i++){
if ((dbgPnPIrps[i].irpPtr == irpPtr) &&
((dbgPnPIrps[i].status == 0xFFFFFFFF) || (dbgPnPIrps[i].status == STATUS_PENDING))){
dbgPnPIrps[i].status = status;
break;
}
}
}
else {
for (i = 0; i < DBG_MAX_PNP_IRP_RECORDS; i++){
if (!dbgPnPIrps[i].irpPtr){
dbgPnPIrps[i].irpPtr = irpPtr;
dbgPnPIrps[i].func = funcShortName;
dbgPnPIrps[i].isForCollectionPdo = isForCollectionPdo;
dbgPnPIrps[i].status = 0xFFFFFFFF;
break;
}
}
}
}
VOID DbgLogPowerIrp(PVOID devExt, UCHAR minorFunc, ULONG isClientPdo, ULONG isComplete, PCHAR type, ULONG powerState, ULONG status)
{
char *funcName;
switch (minorFunc){
#undef MAKE_CASE
#define MAKE_CASE(fnc) case fnc: funcName = #fnc; break;
MAKE_CASE(IRP_MN_WAIT_WAKE)
MAKE_CASE(IRP_MN_POWER_SEQUENCE)
MAKE_CASE(IRP_MN_SET_POWER)
MAKE_CASE(IRP_MN_QUERY_POWER)
default: funcName = "????"; break;
}
if (dbgVerbose){
if (isComplete){
DBGOUT((" < %s for %s(ext=%ph) status=%xh ",
funcName,
isClientPdo ? "collection" : "device",
devExt,
status));
}
else if (minorFunc == IRP_MN_SET_POWER){
DBGOUT((" > %s for %s(ext=%ph) type=%s, powerState=%ph",
funcName,
isClientPdo ? "collection" : "device",
devExt,
type,
powerState));
}
else {
DBGOUT((" > %s for %s(ext=%ph) ",
funcName,
isClientPdo ? "collection" : "device",
devExt));
}
}
}
#define DBG_MAX_REPORT_RECORDS 0x100
dbgReportRecord dbgReportRecords[DBG_MAX_REPORT_RECORDS] = { 0 };
ULONG dbgCurrentReportRecord = 0;
VOID DbgLogReport(ULONG collectionNumber, ULONG numRecipients, ULONG numPending, ULONG numFailed, PUCHAR report, ULONG reportLength)
{
ASSERT(dbgCurrentReportRecord <= DBG_MAX_REPORT_RECORDS);
if (dbgCurrentReportRecord == DBG_MAX_REPORT_RECORDS){
RtlZeroMemory(dbgReportRecords, DBG_MAX_REPORT_RECORDS*sizeof(dbgReportRecord));
dbgCurrentReportRecord = 0;
}
dbgReportRecords[dbgCurrentReportRecord].collectionNumber = (UCHAR)collectionNumber;
dbgReportRecords[dbgCurrentReportRecord].numRecipients = (UCHAR)numRecipients;
if (reportLength > sizeof(dbgReportRecords[dbgCurrentReportRecord].reportBytes)){
reportLength = sizeof(dbgReportRecords[dbgCurrentReportRecord].reportBytes);
}
RtlCopyMemory((PUCHAR)dbgReportRecords[dbgCurrentReportRecord].reportBytes, report, reportLength);
dbgCurrentReportRecord++;
if (dbgVerbose){
ULONG i;
DBGOUT(("Report (cltn #%d, %d recipients; %d pending, %d failed):", collectionNumber, numRecipients, numPending, numFailed));
DbgPrint("'\t report bytes: \t");
for (i = 0; i < reportLength; i++){
DbgPrint("%02x ", report[i]);
}
DbgPrint("\n");
}
}
VOID DbgLogIoctl(ULONG_PTR fdo, ULONG ioControlCode, ULONG status)
{
if (dbgVerbose){
PCHAR ioctlStr;
switch (ioControlCode){
#undef MAKE_CASE
#define MAKE_CASE(ioctl) case ioctl: ioctlStr = #ioctl; break;
MAKE_CASE(IOCTL_HID_GET_DRIVER_CONFIG)
MAKE_CASE(IOCTL_HID_SET_DRIVER_CONFIG)
MAKE_CASE(IOCTL_HID_GET_POLL_FREQUENCY_MSEC)
MAKE_CASE(IOCTL_HID_SET_POLL_FREQUENCY_MSEC)
MAKE_CASE(IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS)
MAKE_CASE(IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS)
MAKE_CASE(IOCTL_HID_GET_COLLECTION_INFORMATION)
MAKE_CASE(IOCTL_HID_GET_COLLECTION_DESCRIPTOR)
MAKE_CASE(IOCTL_HID_FLUSH_QUEUE)
MAKE_CASE(IOCTL_HID_SET_FEATURE)
MAKE_CASE(IOCTL_HID_GET_FEATURE)
MAKE_CASE(IOCTL_GET_PHYSICAL_DESCRIPTOR)
MAKE_CASE(IOCTL_HID_GET_HARDWARE_ID)
MAKE_CASE(IOCTL_HID_GET_MANUFACTURER_STRING)
MAKE_CASE(IOCTL_HID_GET_PRODUCT_STRING)
MAKE_CASE(IOCTL_HID_GET_SERIALNUMBER_STRING)
MAKE_CASE(IOCTL_HID_GET_INDEXED_STRING)
MAKE_CASE(IOCTL_INTERNAL_HID_SET_BLUESCREEN)
default: ioctlStr = "???"; break;
}
DBGOUT(("IOCTL %s (%xh) status=%xh (fdo=%ph)",
ioctlStr, ioControlCode, status, fdo));
}
}
#endif