📄 caplog.c
字号:
0, PUB_VAR(dwCeLogLargeBuf), DATAMAP_NAME));
if (RingBuf.hMap) {
RingBuf.pHeader = (PMAPHEADER)PUB_FUNC(MapViewOfFile,
(RingBuf.hMap, FILE_MAP_ALL_ACCESS,
0, 0, PUB_VAR(dwCeLogLargeBuf)));
if (RingBuf.pHeader) {
// We can't take page faults during the logging so lock the pages.
fRet = (BOOL) PUB_FUNC(LockPages,
(RingBuf.pHeader, PUB_VAR(dwCeLogLargeBuf),
NULL, LOCKFLAG_WRITE | LOCKFLAG_READ));
if (fRet) {
// Success!
break;
}
PUB_FUNC(UnmapViewOfFile, (RingBuf.pHeader));
RingBuf.pHeader = NULL;
}
PUB_FUNC(CloseHandle, (RingBuf.hMap));
RingBuf.hMap = 0;
}
// Keep trying smaller buffer sizes until we succeed
PUB_VAR(dwCeLogLargeBuf) /= 2;
if (PUB_VAR(dwCeLogLargeBuf) < PAGE_SIZE) {
RETAILMSG(1, (MODNAME TEXT(": Large Buffer alloc failed\r\n")));
goto error;
}
} while (PUB_VAR(dwCeLogLargeBuf) >= PAGE_SIZE);
// Explicitly map the pointer to the kernel. Kernel isn't always the current
// process during the logging, but will have permissions.
RingBuf.pHeader = (PMAPHEADER)PUB_FUNC(MapPtrToProcess,
((PVOID) RingBuf.pHeader, GetCurrentProcess()));
DEBUGMSG(ZONE_VERBOSE, (MODNAME TEXT(": RingBuf (VA) 0x%08X\r\n"), RingBuf.pHeader));
RingBuf.dwSize = PUB_VAR(dwCeLogLargeBuf) - sizeof(MAPHEADER);
RingBuf.pBuffer = RingBuf.pWrite = RingBuf.pRead
= (LPBYTE)RingBuf.pHeader + sizeof(MAPHEADER);
RingBuf.pWrap = (LPBYTE)RingBuf.pBuffer + RingBuf.dwSize;
RingBuf.dwBytesLeft = 0; // not used
// Initialize the header on the map
RingBuf.pHeader->dwBufSize = RingBuf.dwSize;
RingBuf.pHeader->pWrite = RingBuf.pWrite;
RingBuf.pHeader->pRead = RingBuf.pRead;
RingBuf.pHeader->fSetEvent = TRUE;
RingBuf.pHeader->dwLostBytes = 0;
//
// Initialize the immediate buffer (small).
//
pCelBuf = &CelBuf;
// Allocate the buffer
pCelBuf->pBuffer = (PDWORD)INT_AllocBuffer(PUB_VAR(dwCeLogSmallBuf), &dwBufSize);
if ((pCelBuf->pBuffer == NULL) || (dwBufSize < PUB_VAR(dwCeLogSmallBuf))) {
DEBUGMSG(1, (MODNAME TEXT(": Small buffer alloc failed\r\n")));
goto error;
}
pCelBuf->pWrite = pCelBuf->pBuffer;
pCelBuf->dwSize = dwBufSize;
pCelBuf->dwBytesLeft = pCelBuf->dwSize;
// CAPLog zones are hard-coded and never change
pCelBuf->dwMaskUser = 0;
pCelBuf->dwMaskCE = CAPLOG_ZONES;
pCelBuf->dwMaskProcess = (DWORD)-1;
//
// Final init stuff
//
// Create the event to flag when the buffer is getting full
// (Must be auto-reset so we can call SetEvent during a flush!)
g_hFillEvent = (HANDLE)PUB_FUNC(CreateEventW, (NULL, FALSE, FALSE, FILLEVENT_NAME));
if (g_hFillEvent == NULL) {
DEBUGMSG(1, (MODNAME TEXT(": Fill event creation failed\r\n")));
goto error;
}
DEBUGMSG(1, (MODNAME TEXT(": -Init\r\n")));
return TRUE;
error:
// Dealloc buffers
if (RingBuf.pHeader) {
PUB_FUNC(UnlockPages, (RingBuf.pHeader, PUB_VAR(dwCeLogLargeBuf)));
PUB_FUNC(UnmapViewOfFile, (RingBuf.pHeader));
}
if (RingBuf.hMap) {
PUB_FUNC(CloseHandle, (RingBuf.hMap));
}
if (pCelBuf) {
if (pCelBuf->pBuffer) {
PUB_FUNC(VirtualFree, (pCelBuf->pBuffer, 0, MEM_DECOMMIT));
}
pCelBuf = NULL;
}
return FALSE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Called by CeLogGetZones to retrieve the current zone settings.
BOOL
EXT_QueryZones(
LPDWORD lpdwZoneUser,
LPDWORD lpdwZoneCE,
LPDWORD lpdwZoneProcess
)
{
// Check whether the library has been initialized. Use pCelBuf instead of
// g_fInit because CeLogQueryZones is called during IOCTL_CELOG_REGISTER
// before g_fInit is set.
if (!pCelBuf) {
return FALSE;
}
if (lpdwZoneUser)
*lpdwZoneUser = pCelBuf->dwMaskUser;
if (lpdwZoneCE)
*lpdwZoneCE = pCelBuf->dwMaskCE;
if (lpdwZoneProcess)
*lpdwZoneProcess = pCelBuf->dwMaskProcess;
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
EXT_LogData(
BOOL fTimeStamp,
WORD wID,
VOID *pData,
WORD wLen,
DWORD dwZoneUser,
DWORD dwZoneCE,
WORD wFlag,
BOOL fFlagged
)
{
LARGE_INTEGER liPerfCount;
DWORD dwLen, dwHeaderLen;
WORD wFlagID = 0;
BOOL fWasIntEnabled;
if (!g_fInit) {
//
// we either failed the init, or haven't been initialized yet!
//
return;
}
// Better provide data if wLen > 0
if ((pData == NULL) && (wLen != 0)) {
DEBUGCHK(0);
return;
}
DEBUGCHK(wID < CELID_MAX); // Out of range
DEBUGCHK(dwZoneCE || dwZoneUser); // Need to provide some zone.
fWasIntEnabled = PRIV_FUNC(INTERRUPTS_ENABLE, (FALSE));
if (wID == CELID_THREAD_SWITCH) {
//
// We handle thread switches specially. Flush the immediate buffer.
//
if (PUB_FUNC(InSysCall, ())) {
INT_FlushBuffer();
} else {
PRIV_FUNC(KCall, ((PKFN)INT_FlushBuffer));
}
}
if (!(pCelBuf->dwMaskCE & dwZoneCE)) {
//
// This zone(s) is disabled.
//
PRIV_FUNC(INTERRUPTS_ENABLE, (fWasIntEnabled));
return;
}
//
// DWORD-aligned length
//
dwLen = (wLen + 3) & ~3;
dwHeaderLen = 8 + (fFlagged ? 4 : 0);
if (pCelBuf->dwBytesLeft < (dwLen + dwHeaderLen)) {
if (PUB_FUNC(InSysCall, ())) {
INT_FlushBuffer();
} else {
PRIV_FUNC(KCall, ((PKFN)INT_FlushBuffer));
}
}
// Must get timestamp AFTER the flushbuffer call, because CeLog calls can
// be generated by the flush itself, and appear out-of-order.
if (fTimeStamp) {
if (PUB_FUNC(QueryPerformanceCounter, (&liPerfCount))) {
liPerfCount.QuadPart >>= g_dwPerfTimerShift;
} else {
// Call failed; caller is probably not trusted
fTimeStamp = FALSE;
}
}
// Header for unflagged data:
// <---------------- 1 DWORD ----------------->
// |T|R| ID | Len |
// | Timestamp | (if T=1)
// | Data... | (etc)
// Header for flagged data:
// <---------------- 1 DWORD ----------------->
// |T|R| CELID_FLAGGED | Len |
// | Timestamp | (if T=1)
// | ID | Flag |
// | Data... | (etc)
// If the data has a flag, use the ID CELID_FLAGGED and move the real ID
// inside the data.
if (fFlagged) {
wFlagID = wID;
wID = CELID_FLAGGED;
}
*pCelBuf->pWrite++ = fTimeStamp << 31 | wID << 16 | wLen;
pCelBuf->dwBytesLeft -= sizeof(DWORD);
if (fTimeStamp) {
*pCelBuf->pWrite++ = liPerfCount.LowPart;
pCelBuf->dwBytesLeft -= sizeof(DWORD);
}
if (fFlagged) {
*pCelBuf->pWrite++ = wFlagID << 16 | wFlag;
pCelBuf->dwBytesLeft -= sizeof(DWORD);
}
if (pData && wLen) {
memcpy(pCelBuf->pWrite, pData, wLen);
}
pCelBuf->pWrite += (dwLen >> 2);
pCelBuf->dwBytesLeft -= dwLen;
PRIV_FUNC(INTERRUPTS_ENABLE, (fWasIntEnabled));
}
//------------------------------------------------------------------------------
// Hook up function pointers and initialize logging
//------------------------------------------------------------------------------
BOOL static
INT_InitLibrary(
FARPROC pfnKernelLibIoControl
)
{
CeLogExportTable exports;
LARGE_INTEGER liPerfFreq;
//
// KernelLibIoControl provides the back doors we need to obtain kernel
// function pointers and register logging functions.
//
// Get public imports from kernel
g_PubImports.dwVersion = CELOG_IMPORT_VERSION;
if (!pfnKernelLibIoControl((HANDLE)KMOD_CELOG, IOCTL_CELOG_IMPORT, &g_PubImports,
sizeof(CeLogImportTable), NULL, 0, NULL)) {
// Can't DEBUGMSG or anything here b/c we need the import table to do that
return FALSE;
}
// CAPLog requires MapViewOfFile
if (g_PubImports.pMapViewOfFile == NULL) {
DEBUGMSG(1, (MODNAME TEXT(": Error, cannot run because this kernel does not support memory-mapped files\r\n")));
PUB_FUNC(SetLastError, (ERROR_NOT_SUPPORTED));
return FALSE;
}
// Get private imports from kernel
g_PrivImports.dwVersion = CELOG_PRIVATE_IMPORT_VERSION;
if (!pfnKernelLibIoControl((HANDLE)KMOD_CELOG, IOCTL_CELOG_IMPORT_PRIVATE, &g_PrivImports,
sizeof(CeLogPrivateImports), NULL, 0, NULL)) {
DEBUGMSG(1, (MODNAME TEXT(": Error, private import failed\r\n")));
PUB_FUNC(SetLastError, (ERROR_NOT_SUPPORTED));
return FALSE;
}
// Now initialize logging
if (!INT_Init()) {
return FALSE;
}
// Get the high-performance timer's frequency
PUB_FUNC(QueryPerformanceFrequency, (&liPerfFreq));
g_dwPerfTimerShift = 0;
while (liPerfFreq.QuadPart > MAX_ROLLOVER_COUNT) {
g_dwPerfTimerShift++;
liPerfFreq.QuadPart >>= 1;
}
// Register logging functions with the kernel
exports.dwVersion = 2; // Hard-code so this code doesn't have to
// change if CELOG_EXPORT_VERSION changes
exports.pfnCeLogData = EXT_LogData;
exports.pfnCeLogInterrupt = NULL; // Not supported, interrupt data ignored
exports.pfnCeLogSetZones = NULL; // Not supported, zones are static
exports.pfnCeLogQueryZones = EXT_QueryZones;
// The exported frequency is only used by the kernel to set the frequency
// in the sync header during CeLogReSync().
exports.dwCeLogTimerFrequency = 0;
if (!pfnKernelLibIoControl((HANDLE)KMOD_CELOG, IOCTL_CELOG_REGISTER, &exports,
sizeof(CeLogExportTable), NULL, 0, NULL)) {
DEBUGMSG(1, (MODNAME TEXT(": Unable to register logging functions with kernel\r\n")));
return FALSE;
}
g_fInit = TRUE;
// Now that logging functions are registered, request a resync
DEBUGMSG(ZONE_VERBOSE, (TEXT("CeLog resync\r\n")));
PUB_FUNC(CeLogReSync, ());
return TRUE;
}
//------------------------------------------------------------------------------
// DLL entry
//------------------------------------------------------------------------------
BOOL WINAPI
CAPLogDLLEntry(HINSTANCE DllInstance, INT Reason, LPVOID Reserved)
{
switch (Reason) {
case DLL_PROCESS_ATTACH:
if (!g_fInit) {
if (Reserved) {
// Reserved parameter is a pointer to KernelLibIoControl function
return INT_InitLibrary((FARPROC)Reserved);
}
// Loaded via LoadLibrary instead of LoadKernelLibrary?
return FALSE;
}
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -