|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
imagehlp.c
Abstract:
This function implements a generic simple symbol handler.
Author:
Wesley Witt (wesw) 1-Sep-1994
Environment:
User Mode
--*/ #ifdef __cplusplus
extern "C" { #endif
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#ifdef __cplusplus
} #endif
#include "private.h"
#include <globals.h>
#ifdef IMAGEHLP_BUILD
#define HEAP_SIZE 0
__inline BOOL tlsAlloc() { return TRUE; }
__inline void tlsFree() { }
__inline void tlsMemFree() { }
#else
#define HEAP_SIZE 0x100000
__inline BOOL tlsAlloc() { g.tlsIndex = TlsAlloc(); return (g.tlsIndex == (DWORD)-1) ? FALSE : TRUE; }
__inline void tlsFree() { if (g.tlsIndex != (DWORD)-1) TlsFree(g.tlsIndex); }
__inline void tlsMemFree() { PVOID ptls;
ptls = TlsGetValue(g.tlsIndex); MemFree(ptls); }
#endif
DWORD DllMain( HINSTANCE hInstance, DWORD Reason, LPVOID Context )
/*++
Routine Description:
DLL initialization function.
Arguments:
hInstance - Instance handle Reason - Reason for the entrypoint being called Context - Context record
Return Value:
TRUE - Initialization succeeded FALSE - Initialization failed
--*/
{ switch (Reason) { case DLL_PROCESS_ATTACH: g.hinst = hInstance; g.OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&g.OSVerInfo); DisableThreadLibraryCalls( hInstance ); HeapInitList(&g.HeapHeader); g.hHeap = HeapCreate(0, HEAP_SIZE, 0); if (!tlsAlloc()) return FALSE; return (g.hHeap != NULL);
case DLL_PROCESS_DETACH: tlsFree(); HeapDump("DLL_PROCESS_DETACH\n"); // If this is a process shutdown, don't bother to
// kill the heap. The OS will do it for us. This
// allows us to be called from other DLLs' DLLMain
// DLL_PROCESS_DETACH handler.
if ( !Context && g.hHeap ) HeapDestroy( g.hHeap ); break;
case DLL_THREAD_DETACH: tlsMemFree(); break; }
return TRUE; }
#ifdef IMAGEHLP_HEAP_DEBUG
BOOL pCheckHeap( PVOID MemPtr, ULONG Line, LPSTR File ) { CHAR buf[256]; CHAR ext[4];
if (!HeapValidate( g.hHeap, 0, MemPtr )) { sprintf( buf, "IMAGEHLP: heap corruption - " ); _splitpath( File, NULL, NULL, &buf[strlen(buf)], ext ); strcat( buf, ext ); sprintf( &buf[strlen(buf)], " @ %d\n", Line ); OutputDebugString( buf ); PrintAllocations(); DebugBreak(); return FALSE; }
return TRUE; }
BOOL pHeapDump( LPSTR sz, ULONG line, LPSTR file ) { BOOL rc;
if (sz && *sz) OutputDebugString(sz); rc = CheckHeap(NULL); if (rc) PrintAllocations();
return rc; } #endif
PVOID pMemReAlloc( PVOID OldAlloc, ULONG_PTR AllocSize #ifdef IMAGEHLP_HEAP_DEBUG
, ULONG Line, LPSTR File #endif
) { #ifdef IMAGEHLP_HEAP_DEBUG
PVOID NewAlloc; PHEAP_BLOCK hb; if (!OldAlloc) { return NULL; } hb = (PHEAP_BLOCK) ((PUCHAR)OldAlloc - sizeof(HEAP_BLOCK)); if (hb->Signature != HEAP_SIG) { OutputDebugString( "IMAGEHLP: Corrupt heap block\n" ); DebugBreak(); } NewAlloc = pMemAlloc(AllocSize, Line, File); if (!NewAlloc) return NULL; memcpy(NewAlloc, OldAlloc, min(hb->Size, AllocSize)); RemoveEntryList( &hb->ListEntry ); g.TotalMemory -= hb->Size; g.TotalAllocs -= 1; HeapFree( g.hHeap, 0, (PVOID) hb ); return NewAlloc; #else
return(HeapReAlloc(g.hHeap, HEAP_ZERO_MEMORY, OldAlloc, AllocSize)); #endif
}
PVOID pMemAlloc( ULONG_PTR AllocSize #ifdef IMAGEHLP_HEAP_DEBUG
, ULONG Line, LPSTR File #endif
) { #ifdef IMAGEHLP_HEAP_DEBUG
PHEAP_BLOCK hb; CHAR ext[4]; hb = (PHEAP_BLOCK) HeapAlloc( g.hHeap, HEAP_ZERO_MEMORY, AllocSize + sizeof(HEAP_BLOCK) ); if (hb) { g.TotalMemory += AllocSize; g.TotalAllocs += 1; InsertTailList( &g.HeapHeader, &hb->ListEntry ); hb->Signature = HEAP_SIG; hb->Size = AllocSize; hb->Line = Line; _splitpath( File, NULL, NULL, hb->File, ext ); strcat( hb->File, ext ); return (PVOID) ((PUCHAR)hb + sizeof(HEAP_BLOCK)); } return NULL; #else
return HeapAlloc( g.hHeap, HEAP_ZERO_MEMORY, AllocSize ); #endif
}
VOID pMemFree( PVOID MemPtr #ifdef IMAGEHLP_HEAP_DEBUG
, ULONG Line, LPSTR File #endif
) { #ifdef IMAGEHLP_HEAP_DEBUG
PHEAP_BLOCK hb; if (!MemPtr) { return; } pCheckHeap(NULL, Line, File); hb = (PHEAP_BLOCK) ((PUCHAR)MemPtr - sizeof(HEAP_BLOCK)); if (hb->Signature != HEAP_SIG) { OutputDebugString( "IMAGEHLP: Corrupt heap block\n" ); DebugBreak(); } RemoveEntryList( &hb->ListEntry ); g.TotalMemory -= hb->Size; g.TotalAllocs -= 1; HeapFree( g.hHeap, 0, (PVOID) hb ); #else
if (!MemPtr) { return; } HeapFree( g.hHeap, 0, MemPtr ); #endif
}
ULONG_PTR pMemSize( PVOID MemPtr ) { return HeapSize(g.hHeap, 0, MemPtr); }
#ifdef IMAGEHLP_HEAP_DEBUG
VOID PrintAllocations( VOID ) { PLIST_ENTRY Next; PHEAP_BLOCK hb; CHAR buf[256]; LARGE_INTEGER PerfFreq;
Next = g.HeapHeader.Flink; if (!Next) { return; }
OutputDebugString( "-----------------------------------------------------------------------------\n" ); sprintf( buf, "Memory Allocations for Heap 0x%08x, Allocs=%d, TotalMem=%I64d\n", (ULONG_PTR)g.hHeap, g.TotalAllocs, g.TotalMemory ); OutputDebugString( buf ); OutputDebugString( "-----------------------------------------------------------------------------\n" ); OutputDebugString( "*\n" );
while ((ULONG_PTR)Next != (ULONG_PTR)&g.HeapHeader) { hb = CONTAINING_RECORD( Next, HEAP_BLOCK, ListEntry ); Next = hb->ListEntry.Flink; sprintf( buf, "%8d %16s @ %5d\n", hb->Size, hb->File, hb->Line ); OutputDebugString( buf ); }
OutputDebugString( "*\n" );
return; } #endif
DWORD ImagepSetLastErrorFromStatus( IN DWORD Status ) { DWORD dwErrorCode;
// dwErrorCode = RtlNtStatusToDosError( Status );
dwErrorCode = Status; SetLastError( dwErrorCode ); return( dwErrorCode ); }
/////////////////////////////////////////////////////////////////////////////
/*
****************************************************************************** On a Hydra System, we don't want imaghlp.dll to load user32.dll since it prevents CSRSS from exiting when running a under a debugger. The following two functions have been copied from user32.dll so that we don't link to user32.dll. ****************************************************************************** */ ////////////////////////////////////////////////////////////////////////////
LPSTR CharNext( LPCSTR lpCurrentChar) { if (IsDBCSLeadByte(*lpCurrentChar)) { lpCurrentChar++; } /*
* if we have only DBCS LeadingByte, we will point string-terminaler. */
if (*lpCurrentChar) { lpCurrentChar++; } return (LPSTR)lpCurrentChar; }
LPSTR CharPrev( LPCSTR lpStart, LPCSTR lpCurrentChar) { if (lpCurrentChar > lpStart) { LPCSTR lpChar; BOOL bDBC = FALSE;
for (lpChar = --lpCurrentChar - 1 ; lpChar >= lpStart ; lpChar--) { if (!IsDBCSLeadByte(*lpChar)) break; bDBC = !bDBC; }
if (bDBC) lpCurrentChar--; } return (LPSTR)lpCurrentChar; }
void * __cdecl AllocIt(unsigned int cb) { return (MemAlloc(cb)); }
void __cdecl FreeIt(void * p) { MemFree(p); }
DWORD IMAGEAPI WINAPI UnDecorateSymbolName( LPCSTR name, LPSTR outputString, DWORD maxStringLength, DWORD flags ) { static HMODULE hMsvcrt = 0; static BOOL fLoadMsvcrtDLL = FALSE; static PUNDNAME pfUnDname = NULL; DWORD rc;
// this prevents an AV in __unDName
if (!name) { SetLastError(ERROR_INVALID_PARAMETER); return 0; }
//
// can't undecorate into a zero length buffer
//
if (maxStringLength < 2) { SetLastError(ERROR_INVALID_PARAMETER); return 0; }
if (!fLoadMsvcrtDLL) { // The first time we run, see if we can find the system undname. Use
// GetModuleHandle to avoid any additionally overhead.
hMsvcrt = GetModuleHandle("msvcrt.dll");
if (hMsvcrt) { pfUnDname = (PUNDNAME) GetProcAddress(hMsvcrt, "__unDName"); } fLoadMsvcrtDLL = TRUE; }
rc = 0; // Assume failure
__try { if (pfUnDname) { if (flags & UNDNAME_NO_ARGUMENTS) { flags |= UNDNAME_NAME_ONLY; flags &= ~UNDNAME_NO_ARGUMENTS; }
if (flags & UNDNAME_NO_SPECIAL_SYMS) { flags &= ~UNDNAME_NO_SPECIAL_SYMS; } if (pfUnDname(outputString, name, maxStringLength-1, AllocIt, FreeIt, (USHORT)flags)) { rc = strlen(outputString); } } else { rc = strlen(strncpy(outputString, "Unable to load msvcrt!__unDName", maxStringLength)); } } __except(EXCEPTION_EXECUTE_HANDLER) { }
if (!rc) { SetLastError(ERROR_INVALID_PARAMETER); } return rc; }
DWORD IMAGEAPI GetTimestampForLoadedLibrary( HMODULE Module ) { PIMAGE_DOS_HEADER DosHdr; DWORD dwTimeStamp;
__try { DosHdr = (PIMAGE_DOS_HEADER) Module; if (DosHdr->e_magic == IMAGE_DOS_SIGNATURE) { dwTimeStamp = ((PIMAGE_NT_HEADERS32) ((LPBYTE)Module + DosHdr->e_lfanew))->FileHeader.TimeDateStamp; } else if (DosHdr->e_magic == IMAGE_NT_SIGNATURE) { dwTimeStamp = ((PIMAGE_NT_HEADERS32) DosHdr)->FileHeader.TimeDateStamp; } else { dwTimeStamp = 0; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwTimeStamp = 0; }
return dwTimeStamp; }
VOID EnsureTrailingBackslash( LPSTR sz ) { int i;
assert(sz);
i = lstrlen(sz); if (!i) return;
if (sz[i - 1] == '\\') return;
sz[i] = '\\'; sz[i + 1] = '\0'; }
#if DBG
VOID __cdecl dbPrint( LPCSTR fmt, ... )
/*++
This function replaces ntdll!DbgPrint(). We need this to keep from linking to ntdll so that this library will run on Windows.
--*/
{ CHAR text[_MAX_PATH];
va_list vaList;
assert(fmt);
va_start(vaList, fmt); vsprintf(text, fmt, vaList); va_end(vaList);
OutputDebugString(text); }
#endif
|