📄 logger.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
Abstract:
This file implements the NK kernel logging support.
Functions:
Notes:
--*/
#define C_ONLY
#include "kernel.h"
#include "altimports.h"
// Pointers to the current DLL entry points.
// No DLLs loaded: These will be NULL.
// Only a single DLL loaded: These will be the entry points for that DLL.
// More than one DLL loaded: These will be the broadcast functions.
// These pointers are not strictly necessary since the list could be used to
// figure everything out, but they make the accesses faster.
void (*g_pfnCeLogData)(); // Receives CeLogData calls
static PFNVOID g_pfnCeLogInterrupt; // Receives CeLogInterrupt calls
// Cannot use a global pointer for CeLogSetZones because we always need to
// use the broadcast function, in order to recalculate zones
static DWORD g_dwCeLogTimerFrequency; // Most recent nonzero timer frequency
// The overall zones are a union of all DLL zone settings
static DWORD g_dwZoneUser;
static DWORD g_dwZoneCE;
static DWORD g_dwZoneProcess;
// List of active DLLs
typedef struct CeLogDLLInfo_t {
struct CeLogDLLInfo_t *pNext; // The next DLL in the list
// Pointers to the export functions and data
PFNVOID pfnCeLogData; // Receives CeLogData calls (REQUIRED)
PFNVOID pfnCeLogInterrupt; // Receives CeLogInterrupt calls (OPTIONAL)
PFNVOID pfnCeLogSetZones; // Receives CeLogSetZones calls (OPTIONAL)
FARPROC pfnCeLogQueryZones; // Receives CeLogGetZones calls, minus last param (OPTIONAL)
DWORD dwCeLogTimerFrequency; // Less than or equal to QueryPerformanceFrequency()
// Zone info for this DLL
DWORD dwZoneUser;
DWORD dwZoneCE;
DWORD dwZoneProcess;
} CeLogDLLInfo;
static CeLogDLLInfo *g_pCeLogList; // The head of the list
static DWORD g_dwCeLogDLLCount; // Number of DLLs in the list
// Using a type 2 heap object to track this info
ERRFALSE(sizeof(CeLogDLLInfo) <= HEAP_SIZE2);
// Simple protection around CeLog DLL registration; calls will simply fail
// instead of block if they can't get the "CS"
static DWORD g_dwCeLogRegisterCS;
// Set by the TLB miss handler
DWORD dwCeLogTLBMiss;
// OEM can override these globals to control CeLog behavior
DWORD dwCeLogLargeBuf;
DWORD dwCeLogSmallBuf;
// AppVerifier shim globals
PFN_SHIMINITMODULE g_pfnShimInitModule;
PFN_SHIMWHICHMOD g_pfnShimWhichMod;
PFN_SHIMUNDODEPENDS g_pfnShimUndoDepends;
PFN_SHIMIOCONTROL g_pfnShimIoControl;
PFN_SHIMGETPROCMODLIST g_pfnShimGetProcModList;
PFN_SHIMCLOSEMODULE g_pfnShimCloseModule;
PFN_SHIMCLOSEPROCESS g_pfnShimCloseProcess;
//------------------------------------------------------------------------------
//
//
// APPVERIFIER SHIM DLL REGISTRATION
//
//
//------------------------------------------------------------------------------
BOOL FreeOneLibrary (PMODULE, BOOL);
extern CRITICAL_SECTION ModListcs;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL KernelLibIoControl_Verifier(
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned
)
{
switch (dwIoControlCode) {
case IOCTL_VERIFIER_IMPORT: {
VerifierImportTable *pImports = (VerifierImportTable*)lpInBuf;
extern const PFNVOID Win32Methods[];
extern void* KmodeEntries(void);
// extern const PFNVOID ExtraMethods[];
if ((nInBufSize != sizeof(VerifierImportTable))
|| (pImports->dwVersion != VERIFIER_IMPORT_VERSION)) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return FALSE;
}
pImports->dwVersion = VERIFIER_IMPORT_VERSION;
pImports->pWin32Methods = (FARPROC*) Win32Methods;
pImports->NKDbgPrintfW = (FARPROC) NKDbgPrintfW;
pImports->pExtraMethods = (FARPROC*) KmodeEntries();
pImports->pKData = &KData;
pImports->KAsciiToUnicode = (FARPROC) KAsciiToUnicode;
pImports->LoadOneLibraryW = (FARPROC) LoadOneLibraryW;
pImports->FreeOneLibrary = (FARPROC) FreeOneLibrary;
pImports->AllocMem = (FARPROC) AllocMem;
pImports->FreeMem = (FARPROC) FreeMem;
pImports->AllocName = (FARPROC) AllocName;
pImports->InitializeCriticalSection = (FARPROC) InitializeCriticalSection;
pImports->EnterCriticalSection = (FARPROC) EnterCriticalSection;
pImports->LeaveCriticalSection = (FARPROC) LeaveCriticalSection;
pImports->pModListcs = & ModListcs;
break;
}
case IOCTL_VERIFIER_REGISTER: {
VerifierExportTable *pExports = (VerifierExportTable*)lpInBuf;
if ((nInBufSize != sizeof(VerifierExportTable))
|| (pExports->dwVersion != VERIFIER_EXPORT_VERSION)) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return FALSE;
}
// Hook up the logging function pointers
g_pfnShimInitModule = (PFN_SHIMINITMODULE) pExports->pfnShimInitModule;
g_pfnShimWhichMod = (PFN_SHIMWHICHMOD) pExports->pfnShimWhichMod;
g_pfnShimUndoDepends = (PFN_SHIMUNDODEPENDS) pExports->pfnShimUndoDepends;
g_pfnShimIoControl = (PFN_SHIMIOCONTROL) pExports->pfnShimIoControl;
g_pfnShimGetProcModList = (PFN_SHIMGETPROCMODLIST) pExports->pfnShimGetProcModList;
g_pfnShimCloseModule = (PFN_SHIMCLOSEMODULE) pExports->pfnShimCloseModule;
g_pfnShimCloseProcess = (PFN_SHIMCLOSEPROCESS) pExports->pfnShimCloseProcess;
break;
}
default:
if (g_pfnShimIoControl) {
return g_pfnShimIoControl (dwIoControlCode, lpInBuf, nInBufSize, lpOutBuf, nOutBufSize, lpBytesReturned);
}
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
//
//
// CELOG DLL REGISTRATION
//
//
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static _inline BOOL EnterCeLogRegisterCS()
{
// Cannot use true critical sections to protect registration because they
// would generate calls into CeLog. Instead the caller does not block, it
// simply fails if it cannot get the CS.
if (InterlockedCompareExchange(&g_dwCeLogRegisterCS, 1, 0) == 0) {
return TRUE;
}
KSetLastError(pCurThread, ERROR_SHARING_VIOLATION);
return FALSE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static _inline VOID LeaveCeLogRegisterCS()
{
g_dwCeLogRegisterCS = 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Add a DLL to the list and recalculate globals
static BOOL AddCeLogDLL(
CeLogExportTable *pExports
)
{
CeLogDLLInfo *pDLL;
// Check whether it is already registered. We could use a refcount to
// allow multiple loads for the same struct but as of now there's no need
// to be that sophisticated.
for (pDLL = g_pCeLogList; pDLL; pDLL = pDLL->pNext) {
if ((pDLL->pfnCeLogData == pExports->pfnCeLogData)
&& (pDLL->pfnCeLogInterrupt == pExports->pfnCeLogInterrupt)
&& (pDLL->pfnCeLogSetZones == pExports->pfnCeLogSetZones)
&& (pDLL->pfnCeLogQueryZones == pExports->pfnCeLogQueryZones)) {
KSetLastError(pCurThread, ERROR_ALREADY_EXISTS);
return FALSE;
}
}
// CeLogData export is required; all others are optional
if (pExports->pfnCeLogData == NULL) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return FALSE;
}
// Alloc a new struct to hold the DLL info
pDLL = AllocMem(HEAP_CELOGDLLINFO);
if (!pDLL) {
KSetLastError(pCurThread, ERROR_OUTOFMEMORY);
return FALSE;
}
pDLL->pfnCeLogData = pExports->pfnCeLogData;
pDLL->pfnCeLogInterrupt = pExports->pfnCeLogInterrupt;
pDLL->pfnCeLogSetZones = pExports->pfnCeLogSetZones;
pDLL->pfnCeLogQueryZones = pExports->pfnCeLogQueryZones;
pDLL->dwCeLogTimerFrequency = pExports->dwCeLogTimerFrequency;
// Set global timer frequency if necessary
if (pDLL->dwCeLogTimerFrequency != 0) {
DEBUGMSG(g_dwCeLogTimerFrequency
&& (g_dwCeLogTimerFrequency != pDLL->dwCeLogTimerFrequency),
(TEXT("CeLog: Timer frequency changing from 0x%08x to 0x%08x\r\n"),
g_dwCeLogTimerFrequency, pDLL->dwCeLogTimerFrequency));
g_dwCeLogTimerFrequency = pDLL->dwCeLogTimerFrequency;
}
// Query the DLL zone settings
if (pDLL->pfnCeLogQueryZones) {
pDLL->pfnCeLogQueryZones(&(pDLL->dwZoneUser), &(pDLL->dwZoneCE), &(pDLL->dwZoneProcess));
} else {
pDLL->dwZoneUser = 0;
pDLL->dwZoneCE = 0;
pDLL->dwZoneProcess = 0;
}
// Add the DLL's zones to the global zone settings
g_dwZoneUser |= pDLL->dwZoneUser;
g_dwZoneCE |= pDLL->dwZoneCE;
g_dwZoneProcess |= pDLL->dwZoneProcess;
// Add to the head of the list
pDLL->pNext = g_pCeLogList;
g_pCeLogList = pDLL;
g_dwCeLogDLLCount++;
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Remove a DLL from the list and recalculate globals
static BOOL
RemoveCeLogDLL(
CeLogExportTable *pExports
)
{
CeLogDLLInfo *pDLL, *pPrevDLL;
BOOL fFound = FALSE;
// We will have to walk the whole list to recalculate the zones and timer freq
g_dwZoneUser = 0;
g_dwZoneCE = 0;
g_dwZoneProcess = 0;
if ((pExports->dwCeLogTimerFrequency != 0)
&& (g_dwCeLogTimerFrequency == pExports->dwCeLogTimerFrequency)) {
g_dwCeLogTimerFrequency = 0;
}
pPrevDLL = NULL;
pDLL = g_pCeLogList;
while (pDLL) {
if (!fFound
&& (pDLL->pfnCeLogData == pExports->pfnCeLogData)
&& (pDLL->pfnCeLogInterrupt == pExports->pfnCeLogInterrupt)
&& (pDLL->pfnCeLogSetZones == pExports->pfnCeLogSetZones)
&& (pDLL->pfnCeLogQueryZones == pExports->pfnCeLogQueryZones)) {
CeLogDLLInfo *pTemp = pDLL; // temp holder
// Found it
fFound = TRUE;
// Remove from the list
if (pPrevDLL == NULL) {
// Removing the head of the list
g_pCeLogList = pDLL->pNext;
} else {
pPrevDLL->pNext = pDLL->pNext;
}
g_dwCeLogDLLCount--;
// Continue iteration -- pPrevDLL does not change
pDLL = pDLL->pNext;
// Free the DLL info
if (IsValidKPtr(pTemp)) {
FreeMem(pTemp, HEAP_CELOGDLLINFO);
}
} else {
// Add the DLL's zones to the global zone settings
g_dwZoneUser |= pDLL->dwZoneUser;
g_dwZoneCE |= pDLL->dwZoneCE;
g_dwZoneProcess |= pDLL->dwZoneProcess;
// Use the first nonzero timer frequency in the list
if ((g_dwCeLogTimerFrequency == 0) && (pDLL->dwCeLogTimerFrequency != 0)) {
DEBUGMSG(pExports->dwCeLogTimerFrequency
&& (pExports->dwCeLogTimerFrequency != pDLL->dwCeLogTimerFrequency),
(TEXT("CeLog: Timer frequency changing from 0x%08x to 0x%08x\r\n"),
pExports->dwCeLogTimerFrequency, pDLL->dwCeLogTimerFrequency));
g_dwCeLogTimerFrequency = pDLL->dwCeLogTimerFrequency;
}
pPrevDLL = pDLL;
pDLL = pDLL->pNext;
}
}
if (!fFound) {
KSetLastError(pCurThread, ERROR_MOD_NOT_FOUND);
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void
BroadcastCeLogData(
BOOL fTimeStamp,
WORD wID,
VOID *pData,
WORD wLen,
DWORD dwZoneUser,
DWORD dwZoneCE,
WORD wFlag,
BOOL fFlagged
)
{
CeLogDLLInfo *pDLL;
for (pDLL = g_pCeLogList; pDLL; pDLL = pDLL->pNext) {
pDLL->pfnCeLogData(fTimeStamp, wID, pData, wLen, dwZoneUser, dwZoneCE,
wFlag, fFlagged);
}
}
#ifdef NKPROF
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void
BroadcastCeLogInterrupt(
DWORD dwLogValue
)
{
CeLogDLLInfo *pDLL;
for (pDLL = g_pCeLogList; pDLL; pDLL = pDLL->pNext) {
if (pDLL->pfnCeLogInterrupt) {
pDLL->pfnCeLogInterrupt(dwLogValue);
}
}
}
#endif // NKPROF
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -