/*++ Copyright (c) 1990 Microsoft Corporation Module Name: memtrace.c Abstract: This function contains an extension to NTSD that allows tracing of memory usage when ULIB objects are compiled with the MEMLEAK flag defined. Author: Barry Gilhuly (W-Barry) 25-July-91 Revision History: --*/ #include #include #include #include #include #include #include "memtrace.h" VOID DumpToFile( char *OutString, ... ) { DWORD bytes; bytes = strlen( OutString ); WriteFile( hFile, OutString, bytes, &bytes, NULL ); return; } VOID MemTrace( HANDLE hCurrentProcess, HANDLE hCurrentThread, DWORD dwCurrentPc, PNTSD_EXTENSION_APIS lpExtensionApis, LPSTR lpArgumentString ) /*++ Routine Description: This function is called as an NTSD extension to format and dump the current contents of the Mem list. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). CurrentPc - Supplies the current pc at the time the extension is called. lpExtensionApis - Supplies the address of the functions callable by this extension. lpArgumentString - Supplies the asciiz string that describes the critical section to be dumped (e.g. ntdll!FastPebLock, csrsrv!CsrProcessStructureLock...). Return Value: None. --*/ { DWORD AddrMem; BOOL b; DWORD i; PMEM_BLOCK MemListNext; MEM_BLOCK MemObject; CHAR Symbol[64]; CHAR Buffer[ 128 ]; DWORD Displacement; PNTSD_OUTPUT_ROUTINE lpOutputRoutine; PNTSD_OUTPUT_ROUTINE lpAlternateOutputRoutine; PNTSD_GET_EXPRESSION lpGetExpressionRoutine; PNTSD_GET_SYMBOL lpGetSymbolRoutine; UNREFERENCED_PARAMETER(hCurrentThread); UNREFERENCED_PARAMETER(dwCurrentPc); UNREFERENCED_PARAMETER(lpArgumentString); lpOutputRoutine = lpExtensionApis->lpOutputRoutine; lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine; lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; // // Attempt to use the input string as a file name... // if( ( hFile = CreateFile( lpArgumentString, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ) ) == (HANDLE)-1 ) { // // Unable to open the file - send all output to the screen. // lpAlternateOutputRoutine = lpExtensionApis->lpOutputRoutine; } else { lpAlternateOutputRoutine = DumpToFile; } // // Get the address of the head of the memleak list... // AddrMem = (lpGetExpressionRoutine)("Ulib!pmemHead"); if ( !AddrMem ) { (lpOutputRoutine)( "Unable to find the head of the Mem List!\n" ); if( hFile != (HANDLE)-1 ) { CloseHandle( hFile ); } return; } if( !ReadProcessMemory( hCurrentProcess, (LPVOID)AddrMem, &MemListNext, sizeof( PMEM_BLOCK ), NULL ) ) { if( hFile != (HANDLE)-1 ) { CloseHandle( hFile ); } return; } // // Traverse the list of Mem blocks stopping when the head hits the // tail...At this point, the head of the list should be indicated // by MemListHead and the tail by MemListTail. Since the first element // in the list is a dummy entry, it can be skipped... // do { if( !ReadProcessMemory( hCurrentProcess, (LPVOID)MemListNext, &MemObject, sizeof( MEM_BLOCK ), NULL ) ) { return; } if( MemObject.memsig != Signature ) { // // This is an unrecognized memory block - die... // (lpOutputRoutine)( "Invalid block found!\n" ); return; } // // Display the stored info - First the File, Line and Size of the // memory block allocated. Then the stack trace... // sprintf( Buffer, "File: %s, Line: %ld, Size: %ld\n", MemObject.file, MemObject.line, MemObject.size ); ( lpAlternateOutputRoutine )( Buffer ); // // This should dump the stack trace which was stored... // for( i = 0; ( i < MaxCallStack ) && ( MemObject.call[ i ] != 0 ); i++ ) { (lpGetSymbolRoutine)( ( LPVOID )( MemObject.call[ i ] ), Symbol, &Displacement ); sprintf( Buffer, "\t%s\n", Symbol ); ( lpAlternateOutputRoutine )( Buffer ); } ( lpAlternateOutputRoutine )( "\n" ); } while( ( MemListNext = MemObject.pmemNext ) != NULL ); (lpOutputRoutine)( "\n...End of List...\n" ); if( hFile != (HANDLE)-1 ) { ( lpAlternateOutputRoutine )( "\n...End of List...\n" ); CloseHandle( hFile ); } return; }