Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1045 lines
33 KiB

/*++
Module Description:
chrono.c
Revision History:
2-Feb-94 a-robw (Bob Watson)
Added this module header
Replaced DbgPrint functions with CapDbgPrint for Windows95
compatiblity.
--*/
#include "cap.h"
//+-------------------------------------------------------------------------
//
// Function: DumpChronoFuncs
//
// Synopsis: Dump the function chrono listings
//
// Arguments: [pThdblk] -- Pointer to current thread block
// [lpstrBuff] -- Buffer to print from
//
// Returns: nothing
//
// History: 05/31/92 HoiV Created
//
// Notes:
//
//--------------------------------------------------------------------------
void DumpChronoFuncs(PTHDBLK pthdblk, LPSTR lpstrBuff)
{
PCHRONOCELL pChronoCell;
TCHAR ptchSym [FILENAMELENGTH];
PTCHAR ptchFuncName;
PTCHAR ptchModule;
ULONG ulTotalCalls;
int iNest;
PTCHAR ptchChronoModule;
PTCHAR ptchChronoFuncName;
PTCHAR ptchMatch;
LONGLONG liTime;
TCHAR chRuntimeSuffix;
if (cChars) // if Count is not 0, we have to flush everything
{
if ( !WriteFile (hOutFile, lpstrBuff, cChars, &cChars, NULL) )
{
CapDbgPrint ("CAP: DumpChronoFuncs() - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
}
//CalcIncompleteChronoCalls(pthdblk);
GetTotalRuntime(pthdblk);
cChars = sprintf (lpstrBuff,
"\r\n\n_________________________________"
"________________________________________________"
"________________________________________________"
"________________________________________\r\n\n\n\n"
"CHRONOLOGICAL FUNCTION LISTINGS\r\n"
"===============================\r\n");
if (fChronoDump)
{
pChronoCell = pthdblk->pChronoHeadCell;
while (pChronoCell->ulSymbolAddr != 0L)
{
//
// Get the symbol name using the function address
//
strcpy(ptchSym, GetFunctionName (pChronoCell->ulSymbolAddr,
ulLocProfBlkOff,
NULL));
_strupr(ptchSym);
_strupr(ptchChronoFuncs);
ptchFuncName = strchr(ptchSym, ':') + 1;
ptchModule = ptchSym;
// ???? Check ptchFuncName
*(ptchFuncName - 1) = '\0';
if (ptchChronoFuncs[0] != EMPTY_STRING) // Empty list ?
{
ptchChronoModule = (PTCHAR) ptchChronoFuncs;
while (*ptchChronoModule != '\0')
{
ptchChronoFuncName = strchr(ptchChronoModule, INI_DELIM) + 1;
*(ptchChronoFuncName - 1) = '\0';
// Look for the Module name
ptchMatch = strstr(ptchModule, ptchChronoModule);
if (ptchMatch && (*(ptchMatch - 1) != COMMENT_CHAR))
{
// We have found the module, now check the func name
if (strstr(ptchFuncName, ptchChronoFuncName))
{
*(ptchChronoFuncName - 1) = INI_DELIM;
// Dump everything call from this cell only
// until the nesting depth is < or == to this cell
//
DumpChronoEntry(pthdblk,
lpstrBuff,
&pChronoCell,
FALSE);
// if found then break out of the
// while (ptchChronoModule) loop
break;
}
}
// If we get here that means we fail to match a module
// name and the func name in the [CHRONO FUNCS] section.
// Just bump to next entry
//
*(ptchChronoFuncName - 1) = INI_DELIM;
ptchChronoModule += strlen(ptchChronoModule) + 1;
}
if (*ptchChronoModule == '\0') // If we did not match
{ // anything then bump to
pChronoCell++; // next cell
}
}
else
{
// Dump everything
DumpChronoEntry(pthdblk, lpstrBuff, &pChronoCell, TRUE);
}
// At this point, pChronoCell has been incremented correctly
// by DumpChronoEntry or inside the searching loop for
// " while (* ptchChronoListItem != EMPTY_STRING) ".
// We just need to loop back.
}
}
else
{
cChars += sprintf (
lpstrBuff + cChars,
"\n\n <<< CHRONO INFO COLLECTED BUT NOT DUMPED >>>\n\n"
"================================="
"================================================"
"================================================"
"========================================\r\n\n\n");
}
cChars += sprintf(lpstrBuff + cChars,
"\n\n______________________________________\n\n\n"
" Summary Statistics\n"
" ==================\n\n\n");
ulTotalCalls = 0L; // Reset our total count for each thread
for (iNest = 0 ;
( (iNest < MAX_NESTING) &&
(pthdblk->aulDepth[iNest] != 0) ) ;
iNest++)
{
ulTotalCalls += pthdblk->aulDepth[iNest];
cChars += sprintf(lpstrBuff + cChars,
" Total calls Depth [%3d] = [%8lu]\n",
iNest,
pthdblk->aulDepth[iNest]);
}
liTime = liTotalRunTime;
AdjustTime(&liTime, &chRuntimeSuffix);
cChars += sprintf(lpstrBuff + cChars,
"\n\n______________________________________\n\n"
" Total Calls = [ %8lu]\n"
" Total Time-Callees = [%9lu]%1c\n\n",
ulTotalCalls,
(ULONG)liTime,
chRuntimeSuffix);
} /* DumpChronoFuncs */
//+-------------------------------------------------------------------------
//
// Function: GetTotalRuntime
//
// Synopsis: Compute the total time the program is running.
//
// Arguments: [pThdblk] -- Pointer to current thread block
//
// Returns: nothing
//
// History: 05/31/92 HoiV Created
//
// Notes:
//
//--------------------------------------------------------------------------
void GetTotalRuntime(PTHDBLK pthdblk)
{
LONGLONG liElapsed,
liRealTime,
liSaveRealTime;
CHAR chRealTimeSuffix;
PCHRONOCELL pChronoCell;
pChronoCell = pthdblk->pChronoHeadCell;
do
{
liElapsed = pChronoCell->liElapsed;
if (liElapsed == 0L)
{
liRealTime = liElapsed;
}
else
{
liRealTime = liElapsed - pChronoCell->liCallees;
}
liSaveRealTime = liRealTime;
AdjustTime (&liRealTime, &chRealTimeSuffix);
if (chRealTimeSuffix != 'o' ||
chRealTimeSuffix != 'u') // don't add if Under/Overflow
{
liTotalRunTime += liSaveRealTime;
}
pChronoCell++; // bump to next entry
} while (pChronoCell->ulSymbolAddr != 0L);
}
//+-------------------------------------------------------------------------
//
// Function: DumpChronoEntry
//
// Synopsis: Dump the Calls listings starting from one particular entry
// and stops only when the depth is greater or end of list.
//
// Arguments: [pThdblk] -- Pointer to current thread block
// [lpstrBuff] -- Buffer to print from
//
// Returns: nothing
//
// History: 05/31/92 HoiV Created
//
// Notes:
//
//--------------------------------------------------------------------------
void DumpChronoEntry(PTHDBLK pthdblk,
LPSTR lpstrBuff,
PCHRONOCELL * ppChronoCell,
BOOL fDumpAll)
{
PCHRONOCELL pChronoCell;
LONGLONG liElapsed,
liRealTime;
TCHAR chElapsedSuffix,
chRealTimeSuffix;
TCHAR pIndentation [MAX_NESTING * 2];
TCHAR ptchSym [FILENAMELENGTH];
int i;
int iMinimumDepth;
// TCHAR ptchCallerSym [FILENAMELENGTH];
ULONG ulSymbolAddress;
if (fDumpAll)
{
pChronoCell = pthdblk->pChronoHeadCell;
cChars += sprintf(lpstrBuff + cChars,
"\n\n------------------------------------------------"
"------------------------------------------------"
"----------------------------------------\r\n\n"
" Complete Dump of Chronological Listings\n\n"
" Sym Address [+Callee] [-Callee] Nesting Depth"
" <RepCnt> - Symbol Name\n"
" ___________ _________ _________ _____________"
" ______________________\n\n");
}
else
{
pChronoCell = * ppChronoCell;
cChars += sprintf(lpstrBuff + cChars,
"\n\n------------------------------------------------"
"------------------------------------------------"
"----------------------------------------\r\n\n"
" Dump Chrono listing for Entry:"
" %-*.*s\n\n"
" Sym Address [+Callee] [-Callee] Nesting Depth"
" <RepCnt> - Symbol Name\n"
" ___________ _________ _________ _____________"
" ______________________\n\n",
iNameLength,
iNameLength,
GetFunctionName(pChronoCell->ulSymbolAddr,
ulLocProfBlkOff,
NULL));
}
iMinimumDepth = pChronoCell->nNestedCalls;
do
{
//
// Get the symbol name using the function address
//
strcpy(ptchSym, GetFunctionName (pChronoCell->ulSymbolAddr,
ulLocProfBlkOff,
&ulSymbolAddress));
// The following caller's symbol somehow could not currently be
// correctly resolved. More investigation to figure out how
// BUGBUG
// strcpy(ptchCallerSym, GetFunctionName (
// pChronoCell->ulCallRetAddr,
// MKPPROFBLK(ulLocProfBlkOff)));
pIndentation[0] = '\0';
for (i = 0 ; i < pChronoCell->nNestedCalls ; i++)
{
strcat(pIndentation, " ");
}
liElapsed = pChronoCell->liElapsed;
if (liElapsed == 0L)
{
liRealTime = liElapsed;
}
else
{
liRealTime = liElapsed - pChronoCell->liCallees;
}
AdjustTime (&liRealTime, &chRealTimeSuffix);
AdjustTime (&liElapsed, &chElapsedSuffix);
// Setup our string
cChars += sprintf (
lpstrBuff + cChars,
" <%8lx> %9lu%1c %9lu%1c%s%3d "
"<%2d> %-*.*s\n",
ulSymbolAddress,
(ULONG)liElapsed, chElapsedSuffix,
(ULONG)liRealTime, chRealTimeSuffix,
pIndentation,
pChronoCell->nNestedCalls,
pChronoCell->nRepetitions,
iNameLength,
iNameLength,
ptchSym);
if (cChars > BUFFER_SIZE)
{
if ( !WriteFile(hOutFile, lpstrBuff, cChars, &cChars, NULL))
{
CapDbgPrint ("CAP: DumpChronoFuncs() - ChronoDump - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
}
pChronoCell++;
}
while ( (pChronoCell->ulSymbolAddr != 0L) && // End Of list?
((pChronoCell->nNestedCalls > iMinimumDepth) || // Nest ?
(fDumpAll)) ); // Override
if (cChars) // if Count is not 0, we have to flush everything
{
if ( !WriteFile (hOutFile, lpstrBuff, cChars, &cChars, NULL) )
{
CapDbgPrint ("CAP: DumpChronoFuncs() - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
}
*ppChronoCell = pChronoCell;
} /* DumpChronoEntry */
#ifdef NOT_YET
//+-------------------------------------------------------------------------
//
// Function: CalcIncompleteChronoCalls
//
// Synopsis: Takes care of imcomplete chono cells which are not finished
// by using liIncompleteTicks as the end time.
//
// Arguments: [pThdblk] -- Pointer to current thread block
// [lpstrBuff] -- Buffer to print from
//
// Returns: nothing
//
// History: 05/31/92 HoiV Created
//
// Notes:
//
//--------------------------------------------------------------------------
void CalcIncompleteChronoCalls (PTHDBLK pthdblk)
{
LONGLONG liElapsed = 0L;
PCHRONOCELL pChronoCell;
// Start at the last one
pChronoCell = pthdblk->pCurrentChronoCell;
//
// Check the chrono cells that have incomplete timings.
//
while (pChronoCell != pthdblk->pChronoHeadCell == 0L)
{
if (pChronoCell->liElapsed == 0L)
{
//
// Get the difference in ticks
//
liElapsed = liIncompleteTicks - pdatacell->liStartCount;
//
// Subtract the overhead and any waste time for this call
//
liElapsed -= liCalibTicks;
liElapsed -= pthdblk->liWasteCount;
if (liElapsed < 0L)
{
liElapsed = 0L;
}
}
pChronoCell--;
}
//
// Make recursive calls
//
if (pdatacell->ulNestedCell != 0L)
{
CalcIncompleteChronoCalls (pthdblk, pdatacell->ulNestedCell);
}
if (pdatacell->ulNextCell != 0L)
{
CalcIncompleteChronoCalls (pthdblk, pdatacell->ulNextCell);
}
} /* CalcIncompleteChronoCalls() */
#endif
//+-------------------------------------------------------------------------
//
// Function: DumpFuncCalls
//
// Synopsis: Dump the Calls listings per function
//
// Arguments: [pThdblk] -- Pointer to current thread block
// [lpstrBuff] -- Buffer to print from
//
// Returns: nothing
//
// History: 05/31/92 HoiV Created
//
// Notes:
//
//--------------------------------------------------------------------------
void DumpFuncCalls(PTHDBLK pthdblk, LPSTR lpstrBuff)
{
PCHRONOCELL pChronoCell, pCurrentChronoCell;
ULONG ulTotalCalls;
ULONG ulCurrentSymbol;
LONGLONG liTotalElapsed,
liTotalRealTime;
DOUBLE dblTotalPercentage,
dblSinglePercentage;
TCHAR chElapsedSuffix,
chRealTimeSuffix,
chTotalRuntimeSuffix;
ULONG ulTotalPercentage,
ulSinglePercentage;
AdjustTime(&liTotalRunTime, &chTotalRuntimeSuffix);
cChars += sprintf (lpstrBuff + cChars,
"\r\n\n_________________________________"
"________________________________________________"
"________________________________________________"
"________________________________________\r\n\n\n\n"
" SUMMARY OF CALLS PER FUNCTION\r\n"
" =============================\r\n\n\n\n"
" Count [+Callee] [-Callee] %%Total | %%Single "
" Function Name\n"
" __________ _________ _________ __________________ "
"_______________\n\n");
if ( !WriteFile (hOutFile, lpstrBuff, cChars, &cChars, NULL) )
{
CapDbgPrint ("CAP: DumpFuncCalls() - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
ulTotalCalls = 0L;
pChronoCell = pthdblk->pChronoHeadCell;
while (pChronoCell->ulSymbolAddr != 0L)
{
liTotalRealTime = 0L;
liTotalElapsed = 0L;
ulCurrentSymbol = pChronoCell->ulSymbolAddr;
pCurrentChronoCell = pChronoCell;
pChronoCell->nNestedCalls = pChronoCell->nRepetitions;
liTotalRealTime += pChronoCell->liCallees;
liTotalElapsed += pChronoCell->liElapsed;
pCurrentChronoCell++;
// Walk the list and accumulate the counts
while (pCurrentChronoCell->ulSymbolAddr != 0L)
{
if (pCurrentChronoCell->ulSymbolAddr == ulCurrentSymbol)
{
pChronoCell->nNestedCalls += pCurrentChronoCell->nRepetitions;
liTotalRealTime += pCurrentChronoCell->liCallees;
liTotalElapsed += pCurrentChronoCell->liElapsed;
// Set to 0xffffffff to indicate it has been processed
pCurrentChronoCell->ulSymbolAddr = 0xffffffff;
}
pCurrentChronoCell++;
}
if (liTotalElapsed == 0 )
{
liTotalRealTime = liTotalElapsed;
}
else
{
liTotalRealTime = liTotalElapsed - liTotalRealTime;
}
AdjustTime (&liTotalElapsed, &chElapsedSuffix);
AdjustTime (&liTotalRealTime, &chRealTimeSuffix);
ulTotalCalls += pChronoCell->nNestedCalls;
if (liTotalRunTime != 0L )
{
dblTotalPercentage = (100.0 * liTotalRealTime) /
liTotalRunTime;
dblSinglePercentage = dblTotalPercentage /
pChronoCell->nNestedCalls;
// BUGBUG! This "sometimes" does not produce correct results
// for some reasons...
//
// dblSinglePercentage =
// (100.0 * liTotalRealTime.LowPart) /
// (liTotalRunTime.LowPart * pChronoCell->nNestedCalls);
}
else
{
dblTotalPercentage = 0.0;
dblSinglePercentage = 0.0;
}
ulTotalPercentage = (ULONG) (dblTotalPercentage * 1000.0);
ulSinglePercentage = (ULONG) (dblSinglePercentage * 1000.0);
cChars += sprintf(lpstrBuff + cChars,
// " <%8lu> %9lu%1c %9lu%1c %7.3f|%7.3f %-*.*s\n",
" <%8lu> %9lu%1c %9lu%1c %3lu.%03lu | %3lu.%03lu %-*.*s\n",
pChronoCell->nNestedCalls,
(ULONG)liTotalElapsed,
chElapsedSuffix,
(ULONG)liTotalRealTime,
chRealTimeSuffix,
ulTotalPercentage / 1000,
ulTotalPercentage % 1000,
ulSinglePercentage / 1000,
ulSinglePercentage % 1000,
iNameLength,
iNameLength,
GetFunctionName (pChronoCell->ulSymbolAddr,
ulLocProfBlkOff,
NULL));
if (cChars > BUFFER_SIZE)
{
if ( !WriteFile(hOutFile, lpstrBuff, cChars, &cChars, NULL))
{
CapDbgPrint ("CAP: DumpFuncCalls() - ChronoDump - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
}
pChronoCell++;
while (pChronoCell->ulSymbolAddr == 0xffffffff)
{
pChronoCell++;
}
}
cChars += sprintf(lpstrBuff + cChars,
"\n\n ________________________________ \n\n "
"<%8lu> %9lu%1c\n\n"
"\r\n\n================================="
"================================================"
"================================================"
"========================================\r\n\n\n",
ulTotalCalls,
(ULONG)liTotalRunTime,
chTotalRuntimeSuffix);
if ( !WriteFile (hOutFile, lpstrBuff, cChars, &cChars, NULL) )
{
CapDbgPrint ("CAP: DumpFuncCalls() - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
cChars = 0;
} /* DumpFuncCalls */
/******************* D u m p P r o f i l e d B i n a r y *******************
*
* DumpProfiledBinary (ptchDumpExt) -
* Dumps the BINARY profiled data to the specified output file.
*
* ENTRY ptchDumpExt - Dump file name extension
*
* EXIT -none-
*
* RETURN -none-
*
* WARNING:
* -none-
*
* COMMENT:
* Profiling is stopped while data is dumped.
*
*/
void DumpProfiledBinary (PTCHAR ptchDumpExt)
{
NTSTATUS Status;
PTCHAR ptchExtension;
PTCHAR ptchSubDir;
int iLength;
DWORD dwFilePtr;
LPSTR lpstrBuff;
HANDLE hMem;
PCHRONOCELL pChronoCell;
int iThread;
BINFILE_HEADER_INFO BinHeader;
BINFILE_THREAD_INFO ThreadHeader;
BINFILE_CELL_INFO BinChronoCell;
ULONG ulBlkOff;
PPROFBLK pProfBlk;
PROFBLOCK_INFO ProfBlkInfo;
//
// Get the GLOBAL semaphore.. (valid accross all process contexts)
//
if (WAIT_FAILED == WaitForSingleObject (hGlobalSem, INFINITE))
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"ERROR - Wait for GLOBAL semaphore failed - 0x%lx\n",
GetLastError());
}
//
// Allocate memory for building output data
//
hMem = GlobalAlloc (GMEM_FIXED, BUFFER_SIZE + MAXNAMELENGTH+ 300);
if (hMem == NULL)
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error allocating global memory - 0x%lx\n",
GetLastError());
ReleaseSemaphore (hGlobalSem, 1, NULL);
return;
}
lpstrBuff = GlobalLock (hMem);
if (lpstrBuff == NULL)
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error locking global memory - 0x%lx\n",
GetLastError());
ReleaseSemaphore (hGlobalSem, 1, NULL);
return;
}
//
// Get the current date/time
//
GetLocalTime ((SYSTEMTIME * UNALIGNED)&BinHeader.SysTime);
//
// Build the call profiler output file name
//
hOutFile = INVALID_HANDLE_VALUE;
if (ptchOutputFile[0] != EMPTY_STRING)
{
strcpy ((PCHAR)atchOutFileName, (PCHAR)ptchOutputFile);
hOutFile = CreateFile(atchOutFileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hOutFile == INVALID_HANDLE_VALUE)
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"ERROR - Could not create %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
}
// If hOutFile has an INVALID_HANDLE_VALUE then either we have a bad
// filename in section [OUTPUT FILE] or we don't have an entry in
// [OUTPUT FILE].
if (hOutFile == INVALID_HANDLE_VALUE)
{
ptchExtension = strrchr (ptchFullAppImageName, '.');
ptchSubDir = strrchr (ptchFullAppImageName, '\\');
//
// If there in no '.' or found one in sub-dir names, use the whole path
//
if ( (ptchExtension == NULL) || (ptchExtension < ptchSubDir) )
{
iLength = sizeof(TCHAR) * strlen(ptchFullAppImageName);
}
else
{
iLength = (int)((DWORD)ptchExtension - (DWORD)ptchFullAppImageName);
}
iLength = min (iLength, FILENAMELENGTH-5);
memcpy (atchOutFileName, ptchFullAppImageName, iLength);
atchOutFileName[iLength] = '\0';
strcat (atchOutFileName, ptchDumpExt);
hOutFile = CreateFile(atchOutFileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hOutFile == INVALID_HANDLE_VALUE)
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"ERROR - Could not create %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
}
//
// Move to the end of the output file..
//
dwFilePtr = SetFilePointer (hOutFile, 0L, NULL, FILE_END);
if (dwFilePtr == (DWORD)INVALID_HANDLE_VALUE)
{
CapDbgPrint ("CAP: DumpProfiledBinary() - ERROR -"
"Could not move to the end of the output file - 0x%lx\n",
GetLastError());
}
cChars = 0;
memset((void *)BinHeader.ptchProfilingBinaryName,
(int)NULL,
FILENAMELENGTH);
strcpy((PCHAR UNALIGNED)BinHeader.ptchProfilingBinaryName,
ptchBaseAppImageName);
BinHeader.ulCalibTime = ulCalibTime;
BinHeader.ulCalibNestedTime = ulCalibNestedTime;
BinHeader.iTotalThreads = iThdCnt;
BinHeader.ulCairoFlags = 0xffffffff;
// Write out the BinHeader
cChars = sizeof(BINFILE_HEADER_INFO);
if ( !WriteFile (hOutFile,
(PCHAR UNALIGNED)&BinHeader,
cChars,
&cChars,
NULL) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() of BinHeader - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
// Loop through all profblks and dump out the characteristics of
// each one
ulBlkOff = ulLocProfBlkOff;
while (ulBlkOff != 0)
{
pProfBlk = MKPPROFBLK(ulBlkOff);
// Write it out
ProfBlkInfo.ImageBase = pProfBlk->ImageBase;
ProfBlkInfo.CodeStart = pProfBlk->CodeStart;
ProfBlkInfo.CodeLength = pProfBlk->CodeLength;
strcpy((PCHAR UNALIGNED)ProfBlkInfo.pImageName,
(PCHAR UNALIGNED)pProfBlk->atchImageName);
cChars = sizeof(PROFBLOCK_INFO);
if ( !WriteFile (hOutFile,
(PCHAR UNALIGNED)&ProfBlkInfo,
cChars,
&cChars,
NULL) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() of BinHeader - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
// Bump to next ProfBlk
ulBlkOff = pProfBlk->ulNxtBlk;
}
// Write out the last dummy ProfBlock to signal the last one
ProfBlkInfo.ImageBase = NULL;
ProfBlkInfo.CodeStart = NULL;
ProfBlkInfo.CodeLength = STUB_SIGNATURE;
cChars = sizeof(PROFBLOCK_INFO);
if ( !WriteFile (hOutFile,
(PCHAR UNALIGNED)&ProfBlkInfo,
cChars,
&cChars,
NULL) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() of BinHeader - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
// Loop through all threads and write out all ChronoData
for (iThread = 0; iThread < iThdCnt; iThread++)
{
// Write out the Section header
cChars = sizeof(BINFILE_THREAD_INFO);
ThreadHeader.hPid = aSecInfo[iThread].hPid;
ThreadHeader.hTid = aSecInfo[iThread].hTid;
ThreadHeader.hClientPid = aSecInfo[iThread].hClientPid;
ThreadHeader.hClientTid = aSecInfo[iThread].hClientTid;
ThreadHeader.ulTotalCells = aSecInfo[iThread].pthdblk->ulTotalChronoCells;
if ( !WriteFile (hOutFile,
(PCHAR UNALIGNED)&ThreadHeader,
cChars,
&cChars,
NULL) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() of ThreadHeader - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
// Write out all ChronoCells for this Section (or Thread)
pChronoCell = aSecInfo[iThread].pthdblk->pChronoHeadCell;
while (pChronoCell->ulSymbolAddr != 0L)
{
ULONG ulRealFuncAddr = pChronoCell->ulSymbolAddr;
// Dump out each chronocell
#ifdef i386
// If this is a stub, find out the real address
if (*((PDWORD)(pChronoCell->ulSymbolAddr + 7)) == STUB_SIGNATURE)
{
ulRealFuncAddr = (ULONG)
(*(PDWORD)(pChronoCell->ulSymbolAddr + 1));
}
#endif
#ifdef MIPS
{
ULONG ulOffsetFromTopRoutine;
ULONG ulFuncAddr = pChronoCell->ulSymbolAddr;
#ifdef MIPS_VC40_INTERFACE
// Check for stub signature at end of stub patch
if (*((PULONG)ulFuncAddr + 5) == STUB_SIGNATURE)
{
PATCHCODE *pPatchStub;
// extract real function address from stub
pPatchStub = (PPATCHCODE)(ulFuncAddr - 5 * INST_SIZE);
ulFuncAddr = (pPatchStub->Lui_t0 << 16);
ulFuncAddr |= (pPatchStub->Ori_t0 & 0x0000ffff);
}
else
{
// Normal function - subtract offset of penter call
ulFuncAddr = ulFuncAddr - 12;
}
#else
//
// Compute the real address of the function since the penter
// stub is not located at the beginning of the code as in x86
//
ulOffsetFromTopRoutine = *((PULONG) (ulFuncAddr - INST_SIZE));
ulOffsetFromTopRoutine &= 0x000ff00;
ulOffsetFromTopRoutine >>= 8;
ulRealFuncAddr = ulFuncAddr - ulOffsetFromTopRoutine;
// We have to distinguish between a stub and a regular function
// since a stub has a different setup than a regular function.
if (*( (PULONG) ulRealFuncAddr - 1 +
(sizeof(PATCHCODE) / INST_SIZE) ) == STUB_SIGNATURE)
{
PATCHCODE *pPatchStub;
// These are the stubs we made up for Dll Patching
pPatchStub = (PPATCHCODE) ulRealFuncAddr;
ulRealFuncAddr = (pPatchStub->Lui_t0 << 16);
ulRealFuncAddr |= (pPatchStub->Ori_t0 & 0x0000ffff);
}
#endif // MIPS_VC40_INTERFACE
}
#endif // MIPS
BinChronoCell.liElapsed = pChronoCell->liElapsed;
BinChronoCell.liCallees = pChronoCell->liCallees;
BinChronoCell.ulSymbolAddr = ulRealFuncAddr;
BinChronoCell.ulCallRetAddr = pChronoCell->ulCallRetAddr;
BinChronoCell.nNestedCalls = pChronoCell->nNestedCalls;
BinChronoCell.nRepetitions = pChronoCell->nRepetitions;
cChars = sizeof(BINFILE_CELL_INFO);
if ( !WriteFile (hOutFile,
(PCHAR UNALIGNED)&BinChronoCell,
cChars,
&cChars,
NULL) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() of ChronoCell - "
"Error writing to %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
pChronoCell++;
}
}
if ( !CloseHandle (hOutFile) )
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error closing %s - 0x%lx\n",
atchOutFileName, GetLastError());
}
//
// Free allocated memory for building output data
//
if (!GlobalUnlock (hMem))
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error ulocking global memory - 0x%lx\n",
GetLastError());
}
if (GlobalFree (hMem))
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error freeing global memory - 0x%lx\n",
GetLastError());
}
SETUPPrint (("CAP: DumpProfiledBinary() - ...done\n"));
//
// Release the GLOBAL semaphore so other processes can dump data
//
Status = ReleaseSemaphore (hGlobalSem, 1, NULL);
if (!NT_SUCCESS(Status))
{
CapDbgPrint ("CAP: DumpProfiledBinary() - "
"Error releasing GLOBAL semaphore - 0x%lx\n", Status);
}
} /* DumpProfiledBinary() */