windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/imagehlp.c
2020-09-26 16:20:57 +08:00

547 lines
11 KiB
C

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