659 lines
13 KiB
Plaintext
659 lines
13 KiB
Plaintext
|
||
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name
|
||
|
||
wcall.c
|
||
|
||
Abstract:
|
||
|
||
Windows version: diplay system calls
|
||
|
||
Author:
|
||
|
||
Mark Enstrom (marke) 13-Dec-1995
|
||
|
||
Enviornment:
|
||
|
||
User Mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <commdlg.h>
|
||
#include <assert.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include "wcall.h"
|
||
#include "resource.h"
|
||
|
||
WCALL_CONTEXT wCxt;
|
||
|
||
|
||
|
||
int PASCAL
|
||
WinMain(
|
||
HINSTANCE hInst,
|
||
HINSTANCE hPrev,
|
||
LPSTR szCmdLine,
|
||
int cmdShow
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process messages.
|
||
|
||
Arguments:
|
||
|
||
hWnd - window hande
|
||
msg - type of message
|
||
wParam - additional information
|
||
lParam - additional information
|
||
|
||
Return Value:
|
||
|
||
status of operation
|
||
|
||
|
||
Revision History:
|
||
|
||
02-17-91 Initial code
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
MSG msg;
|
||
WNDCLASS wc;
|
||
|
||
wCxt.hInstMain = hInst;
|
||
|
||
//
|
||
// Create (if no prev instance) and Register the class
|
||
//
|
||
|
||
if (!hPrev)
|
||
{
|
||
wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
|
||
wc.hIcon = (HICON)NULL;
|
||
wc.lpszMenuName = MAKEINTRESOURCE(IDR_WCALL_MENU);
|
||
wc.lpszClassName = "wcallClass";
|
||
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
|
||
wc.hInstance = hInst;
|
||
wc.style = CS_OWNDC;
|
||
wc.lpfnWndProc = WndProc;
|
||
wc.cbWndExtra = 0;
|
||
wc.cbClsExtra = 0;
|
||
|
||
if (!RegisterClass(&wc))
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Create and show the main window
|
||
//
|
||
|
||
wCxt.hWndMain = CreateWindow ("wcallClass",
|
||
"System Call Count",
|
||
WS_OVERLAPPEDWINDOW,
|
||
50,
|
||
50,
|
||
450,
|
||
350,
|
||
(HWND)NULL,
|
||
(HMENU)NULL,
|
||
(HINSTANCE)hInst,
|
||
(LPSTR)NULL
|
||
);
|
||
|
||
if (wCxt.hWndMain == NULL)
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Show the window
|
||
//
|
||
|
||
ShowWindow(wCxt.hWndMain,cmdShow);
|
||
UpdateWindow(wCxt.hWndMain);
|
||
SetFocus(wCxt.hWndMain);
|
||
|
||
//
|
||
// Main message loop
|
||
//
|
||
|
||
while (GetMessage(&msg,(HWND)NULL,0,0))
|
||
{
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
|
||
return msg.wParam;
|
||
}
|
||
|
||
|
||
|
||
LONG FAR
|
||
PASCAL WndProc(
|
||
HWND hWnd,
|
||
unsigned msg,
|
||
UINT wParam,
|
||
LONG lParam)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Windows Proc
|
||
|
||
Arguments
|
||
|
||
hWnd - window hande
|
||
msg - type of message
|
||
wParam - additional information
|
||
lParam - additional information
|
||
|
||
Return Value
|
||
|
||
standard
|
||
|
||
--*/
|
||
{
|
||
switch (msg) {
|
||
|
||
case WM_CREATE:
|
||
{
|
||
//
|
||
// mark as no current data
|
||
//
|
||
|
||
wCxt.NumberOfCounts = 0;
|
||
|
||
|
||
DialogBox(wCxt.hInstMain, (LPSTR)IDD_RESULTS, hWnd, (DLGPROC)ResultsDlgProc);
|
||
|
||
SendMessage(hWnd,WM_CLOSE,0,0L);
|
||
}
|
||
break;
|
||
|
||
case WM_COMMAND:
|
||
{
|
||
|
||
switch (LOWORD(wParam)){
|
||
case IDM_EXIT:
|
||
{
|
||
SendMessage(hWnd,WM_CLOSE,0,0L);
|
||
}
|
||
break;
|
||
|
||
//
|
||
// sample system call counts and save as
|
||
// the base counts for future calls to
|
||
// GET_CURRENT
|
||
//
|
||
|
||
case IDM_SAVE_CALLS:
|
||
{
|
||
}
|
||
break;
|
||
|
||
|
||
//
|
||
// read system call counts, then subtract from
|
||
// the baseline value and display highest values
|
||
//
|
||
|
||
case IDM_GET_CURRENT:
|
||
{
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case WM_PAINT:
|
||
{
|
||
PAINTSTRUCT ps;
|
||
HDC hDC = BeginPaint(hWnd,&ps);
|
||
EndPaint(hWnd,&ps);
|
||
}
|
||
break;
|
||
|
||
case WM_DESTROY:
|
||
PostQuitMessage(0);
|
||
break;
|
||
default:
|
||
|
||
//
|
||
// Passes message on if unproccessed
|
||
//
|
||
|
||
return (DefWindowProc(hWnd, msg, wParam, lParam));
|
||
}
|
||
|
||
return ((LONG)NULL);
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Save results to file
|
||
|
||
Arguments
|
||
|
||
none
|
||
|
||
Return Value
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
|
||
void WriteResults(HFILE hFile)
|
||
{
|
||
}
|
||
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
|
||
Arguments
|
||
|
||
|
||
|
||
Return Value
|
||
|
||
|
||
|
||
--*/
|
||
|
||
|
||
VOID
|
||
SaveResults()
|
||
{
|
||
static OPENFILENAME ofn;
|
||
static char szFilename[80];
|
||
char szT[80];
|
||
int i, hfile;
|
||
FILE *fpOut;
|
||
|
||
for (i = 0; i < sizeof(ofn); i++)
|
||
{
|
||
//
|
||
// clear out the OPENFILENAME struct
|
||
//
|
||
|
||
((char *)&ofn)[i] = 0;
|
||
}
|
||
|
||
ofn.lStructSize = sizeof(ofn);
|
||
ofn.hwndOwner = wCxt.hWndMain;
|
||
ofn.hInstance = wCxt.hInstMain;
|
||
|
||
ofn.lpstrFilter = "SysCall (*.log)\0*.log;\0All Files\0*.*\0\0";
|
||
ofn.lpstrCustomFilter = NULL;
|
||
ofn.nMaxCustFilter = 0;
|
||
ofn.nFilterIndex = 0;
|
||
ofn.lpstrFileTitle = NULL;
|
||
ofn.nMaxFileTitle = 0;
|
||
ofn.lpstrInitialDir = "C:\\";
|
||
ofn.Flags = 0;
|
||
ofn.lpstrDefExt = NULL;
|
||
ofn.lCustData = 0;
|
||
ofn.lpfnHook = NULL;
|
||
ofn.lpTemplateName = NULL;
|
||
|
||
lstrcpy(szFilename, "syscall.log");
|
||
|
||
ofn.lpstrFile = szFilename;
|
||
ofn.nMaxFile = sizeof(szFilename);
|
||
ofn.lpstrTitle = "Save As";
|
||
|
||
if (!GetSaveFileName(&ofn))
|
||
{
|
||
return;
|
||
}
|
||
|
||
fpOut = fopen(szFilename, "w+");
|
||
|
||
if (fpOut)
|
||
{
|
||
ULONG ix;
|
||
|
||
for (ix = 0; ix < TOP_CALLS; ix++)
|
||
{
|
||
//
|
||
// stop if count is 0
|
||
//
|
||
|
||
if (wCxt.CallData[wCxt.Index[ix]] == 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
fprintf(fpOut,"%8ld %s\n",
|
||
wCxt.CallData[wCxt.Index[ix]],
|
||
CallTable[wCxt.Index[ix]]);
|
||
}
|
||
|
||
fclose(fpOut);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
APIENTRY
|
||
ResultsDlgProc(
|
||
HWND hwnd,
|
||
UINT msg,
|
||
UINT wParam,
|
||
LONG lParam)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Show results (Interactive Mode Dialog)
|
||
|
||
Arguments
|
||
|
||
Std dlg
|
||
|
||
Return Value
|
||
|
||
Status
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG ix;
|
||
char szT[80];
|
||
BOOL fResults;
|
||
int aiT[2];
|
||
|
||
switch (msg) {
|
||
case WM_INITDIALOG:
|
||
{
|
||
LONG NumCounts;
|
||
|
||
aiT[0] = 40;
|
||
aiT[1] = 140;
|
||
SendDlgItemMessage(hwnd, IDC_RESULTSLIST, LB_SETTABSTOPS, 2,
|
||
(LONG)(LPSTR)aiT);
|
||
//
|
||
// get initial kmode call count
|
||
//
|
||
|
||
NumCounts = ReadCallCountInfo(
|
||
(PSYSTEM_CALL_COUNT_INFORMATION)&wCxt.CountBuffer1);
|
||
|
||
if (NumCounts > 0)
|
||
{
|
||
wCxt.NumberOfCounts = NumCounts;
|
||
}
|
||
else
|
||
{
|
||
MessageBox(NULL,"ReadCallCountInfo failed","Error",MB_OK);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case WM_COMMAND:
|
||
switch (LOWORD(wParam)) {
|
||
case IDOK:
|
||
EndDialog(hwnd, 0);
|
||
break;
|
||
|
||
case IDM_SAVERESULTS:
|
||
SaveResults();
|
||
break;
|
||
|
||
case IDM_RESTART:
|
||
{
|
||
int ix;
|
||
|
||
//
|
||
// Gat call counts
|
||
//
|
||
|
||
LONG NumCounts = ReadCallCountInfo(
|
||
(PSYSTEM_CALL_COUNT_INFORMATION)&wCxt.CountBuffer1);
|
||
|
||
if (NumCounts > 0)
|
||
{
|
||
wCxt.NumberOfCounts = NumCounts;
|
||
}
|
||
else
|
||
{
|
||
MessageBox(NULL,"ReadCallCountInfo failed","Error",MB_OK);
|
||
}
|
||
|
||
//
|
||
// Delete old strings
|
||
//
|
||
|
||
for (ix = 0; ix < TOP_CALLS; ix++)
|
||
{
|
||
SendDlgItemMessage(hwnd, IDC_RESULTSLIST, LB_DELETESTRING,0,0);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case IDM_SAMPLE:
|
||
if (wCxt.NumberOfCounts > 0)
|
||
{
|
||
|
||
int ix;
|
||
|
||
LONG NumberOfCounts = ReadCallCountInfo(
|
||
(PSYSTEM_CALL_COUNT_INFORMATION)&wCxt.CountBuffer2);
|
||
|
||
if (NumberOfCounts == wCxt.NumberOfCounts)
|
||
{
|
||
//
|
||
// Compute number of system calls for each service, the total
|
||
// number of system calls, and the total time for each serviced.
|
||
//
|
||
|
||
ULONG TotalSystemCalls = 0;
|
||
ULONG i;
|
||
|
||
PULONG CallCountTable[2];
|
||
|
||
PULONG CurrentCallCountTable;
|
||
PSYSTEM_CALL_COUNT_INFORMATION CallCountInfo[2];
|
||
|
||
PULONG PreviousCallCountTable;
|
||
|
||
CallCountInfo[0] = (PVOID)wCxt.CountBuffer1;
|
||
CallCountInfo[1] = (PVOID)wCxt.CountBuffer2;
|
||
CallCountTable[0] = (PULONG)(CallCountInfo[0] + 1) + NUMBER_SERVICE_TABLES;
|
||
CallCountTable[1] = (PULONG)(CallCountInfo[1] + 1) + NUMBER_SERVICE_TABLES;
|
||
|
||
PreviousCallCountTable = CallCountTable[0];
|
||
CurrentCallCountTable = CallCountTable[1];
|
||
|
||
|
||
for (i = 0; i < NumberOfCounts; i += 1) {
|
||
wCxt.CallData[i] = CurrentCallCountTable[i] - PreviousCallCountTable[i];
|
||
TotalSystemCalls += wCxt.CallData[i];
|
||
}
|
||
|
||
//
|
||
// Sort the system call data.
|
||
//
|
||
|
||
SortUlongData(NumberOfCounts, &wCxt.Index[0],&wCxt.CallData[0]);
|
||
|
||
//
|
||
// Delete old strings
|
||
//
|
||
|
||
for (ix = 0; ix < TOP_CALLS; ix++)
|
||
{
|
||
SendDlgItemMessage(hwnd, IDC_RESULTSLIST, LB_DELETESTRING,0,0);
|
||
}
|
||
|
||
//
|
||
// display new strings
|
||
//
|
||
|
||
for (ix = 0; ix < TOP_CALLS; ix++)
|
||
{
|
||
//
|
||
// stop if count is 0
|
||
//
|
||
|
||
if (wCxt.CallData[wCxt.Index[ix]] == 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
sprintf(szT,"%8ld %s",
|
||
wCxt.CallData[wCxt.Index[ix]],
|
||
CallTable[wCxt.Index[ix]]);
|
||
|
||
SendDlgItemMessage(hwnd, IDC_RESULTSLIST, LB_ADDSTRING, 0,
|
||
(LONG)(LPSTR)szT);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox(NULL,"ReadCallCountInfo returned different number of counts than initial sample","Error",MB_OK);
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Read system call count info into buffer and return number of counts
|
||
|
||
Arguments
|
||
|
||
pCurrentCallCountInfo - buffer for results (BUFFER_SIZE)
|
||
|
||
Return Value
|
||
|
||
Number of counts or negative status value on error
|
||
|
||
--*/
|
||
|
||
int
|
||
ReadCallCountInfo(
|
||
PSYSTEM_CALL_COUNT_INFORMATION pCurrentCallCountInfo
|
||
)
|
||
{
|
||
KPRIORITY SetBasePriority;
|
||
NTSTATUS status;
|
||
PULONG p;
|
||
ULONG i;
|
||
int NumberOfCounts;
|
||
|
||
SetBasePriority = (KPRIORITY)12;
|
||
|
||
NtSetInformationProcess(
|
||
NtCurrentProcess(),
|
||
ProcessBasePriority,
|
||
(PVOID) &SetBasePriority,
|
||
sizeof(SetBasePriority)
|
||
);
|
||
|
||
//
|
||
// Query system information and get the initial call count data.
|
||
//
|
||
|
||
status = NtQuerySystemInformation(SystemCallCountInformation,
|
||
(PVOID)pCurrentCallCountInfo,
|
||
BUFFER_SIZE * sizeof(ULONG),
|
||
NULL);
|
||
|
||
if (NT_SUCCESS(status) == FALSE){
|
||
return(-1);
|
||
}
|
||
|
||
//
|
||
// Make sure that the number of tables reported by the kernel matches
|
||
// our list.
|
||
//
|
||
|
||
if (pCurrentCallCountInfo->NumberOfTables != NUMBER_SERVICE_TABLES) {
|
||
return(-2);
|
||
}
|
||
|
||
//
|
||
// Make sure call count information is available for base services.
|
||
//
|
||
|
||
p = (PULONG)(pCurrentCallCountInfo + 1);
|
||
|
||
if (p[0] == 0) {
|
||
return(-3);
|
||
}
|
||
|
||
//
|
||
// If there is a hole in the count information (i.e., one set of services
|
||
// doesn't have counting enabled, but a subsequent one does, then our
|
||
// indexes will be off, and we'll display the wrong service names.
|
||
//
|
||
|
||
for ( i = 2; i < NUMBER_SERVICE_TABLES; i++ ) {
|
||
if ((p[i] != 0) && (p[i-1] == 0)) {
|
||
return(-4);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Determine number of counts and return
|
||
//
|
||
|
||
NumberOfCounts = (pCurrentCallCountInfo->Length
|
||
- sizeof(SYSTEM_CALL_COUNT_INFORMATION)
|
||
- NUMBER_SERVICE_TABLES * sizeof(ULONG)) / sizeof(ULONG);
|
||
|
||
return(NumberOfCounts);
|
||
}
|