/*++ 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() */