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

1357 lines
36 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
checksum.c
Abstract:
This module implements functions for splitting debugging information
out of an image file and into a separate .DBG file.
Author:
Steven R. Wood (stevewo) 4-May-1993
Revision History:
--*/
#include <private.h>
#include <symbols.h>
#include <globals.h>
#define ROUNDUP(x, y) ((x + (y-1)) & ~(y-1))
typedef BOOL
(CALLBACK *PSEARCH_TREE_FOR_FILE_EX_CALLBACK)(
LPSTR FilePath,
PVOID CallerData
);
BOOL
IMAGEAPI
SearchTreeForFileEx(
PSTR RootPath,
PSTR InputPathName,
PSTR OutputPathBuffer,
PSEARCH_TREE_FOR_FILE_EX_CALLBACK Callback,
PVOID CallbackData
);
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if !defined(_WIN64)
PIMAGE_DEBUG_INFORMATION
IMAGEAPI
MapDebugInformation(
HANDLE FileHandle,
LPSTR FileName,
LPSTR SymbolPath,
ULONG ImageBase
)
// Here's what we're going to try. MapDebugInformation was only
// documented as returning COFF symbolic and every user I can find
// in the tree uses COFF exclusively. Rather than try to make this
// api do everything possible, let's just leave it as a COFF only thing.
// The new debug info api (GetDebugData) will be internal only.
{
PIMAGE_DEBUG_INFORMATION pIDI;
CHAR szName[_MAX_FNAME];
CHAR szExt[_MAX_EXT];
PIMGHLP_DEBUG_DATA pIDD;
PPIDI pPIDI;
DWORD sections;
BOOL SymbolsLoaded;
HANDLE hProcess;
LPSTR sz;
HANDLE hdb;
DWORD dw;
hProcess = GetCurrentProcess();
pIDD = GetDebugData(NULL, FileHandle, FileName, SymbolPath, ImageBase, NULL, NO_PE64_IMAGES);
if (!pIDD)
return NULL;
pPIDI = (PPIDI)MemAlloc(sizeof(PIDI));
if (!pPIDI)
return NULL;
ZeroMemory(pPIDI, sizeof(PIDI));
pIDI = &pPIDI->idi;
pPIDI->hdr.pIDD = pIDD;
pIDI->ReservedSize = sizeof(IMAGE_DEBUG_INFORMATION);
pIDI->ReservedMachine = pIDD->Machine;
pIDI->ReservedCharacteristics = (USHORT)pIDD->Characteristics;
pIDI->ReservedCheckSum = pIDD->CheckSum;
pIDI->ReservedTimeDateStamp = pIDD->TimeDateStamp;
pIDI->ReservedRomImage = pIDD->fROM;
// read info
InitializeListHead( &pIDI->List );
pIDI->ImageBase = (ULONG)pIDD->ImageBaseFromImage;
pIDI->ImageFilePath = (PSTR)MemAlloc(strlen(pIDD->ImageFilePath)+1);
if (pIDI->ImageFilePath) {
strcpy( pIDI->ImageFilePath, pIDD->ImageFilePath );
}
pIDI->ImageFileName = (PSTR)MemAlloc(strlen(pIDD->OriginalImageFileName)+1);
if (pIDI->ImageFileName) {
strcpy(pIDI->ImageFileName, pIDD->OriginalImageFileName);
}
if (pIDD->pMappedCoff) {
pIDI->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER)MemAlloc(pIDD->cMappedCoff);
if (pIDI->CoffSymbols) {
memcpy(pIDI->CoffSymbols, pIDD->pMappedCoff, pIDD->cMappedCoff);
}
pIDI->SizeOfCoffSymbols = pIDD->cMappedCoff;
}
if (pIDD->pFpo) {
pIDI->ReservedNumberOfFpoTableEntries = pIDD->cFpo;
pIDI->ReservedFpoTableEntries = (PFPO_DATA)pIDD->pFpo;
}
pIDI->SizeOfImage = pIDD->SizeOfImage;
if (pIDD->DbgFilePath && *pIDD->DbgFilePath) {
pIDI->ReservedDebugFilePath = (PSTR)MemAlloc(strlen(pIDD->DbgFilePath)+1);
if (pIDI->ReservedDebugFilePath) {
strcpy(pIDI->ReservedDebugFilePath, pIDD->DbgFilePath);
}
}
if (pIDD->pMappedCv) {
pIDI->ReservedCodeViewSymbols = pIDD->pMappedCv;
pIDI->ReservedSizeOfCodeViewSymbols = pIDD->cMappedCv;
}
// for backwards compatibility
if (pIDD->ImageMap) {
sections = (DWORD)((char *)pIDD->pCurrentSections - (char *)pIDD->ImageMap);
pIDI->ReservedMappedBase = MapItRO(pIDD->ImageFileHandle);
if (pIDI->ReservedMappedBase) {
pIDI->ReservedSections = (PIMAGE_SECTION_HEADER)pIDD->pCurrentSections;
pIDI->ReservedNumberOfSections = pIDD->cCurrentSections;
if (pIDD->ddva) {
pIDI->ReservedDebugDirectory = (PIMAGE_DEBUG_DIRECTORY)((PCHAR)pIDI->ReservedMappedBase + pIDD->ddva);
pIDI->ReservedNumberOfDebugDirectories = pIDD->cdd;
}
}
}
return pIDI;
}
BOOL
UnmapDebugInformation(
PIMAGE_DEBUG_INFORMATION pIDI
)
{
PPIDI pPIDI;
if (!pIDI)
return TRUE;
if (pIDI->ImageFileName){
MemFree(pIDI->ImageFileName);
}
if (pIDI->ImageFilePath) {
MemFree(pIDI->ImageFilePath);
}
if (pIDI->ReservedDebugFilePath) {
MemFree(pIDI->ReservedDebugFilePath);
}
if (pIDI->CoffSymbols) {
MemFree(pIDI->CoffSymbols);
}
if (pIDI->ReservedMappedBase) {
UnmapViewOfFile(pIDI->ReservedMappedBase);
}
pPIDI = (PPIDI)(PCHAR)((PCHAR)pIDI - sizeof(PIDI_HEADER));
ReleaseDebugData(pPIDI->hdr.pIDD, IMGHLP_FREE_ALL);
MemFree(pPIDI);
return TRUE;
}
#endif
LPSTR
ExpandPath(
LPSTR lpPath
)
{
LPSTR p, newpath, p1, p2, p3;
CHAR envvar[MAX_PATH];
CHAR envstr[MAX_PATH];
ULONG i, PathMax;
if (!lpPath) {
return(NULL);
}
p = lpPath;
PathMax = strlen(lpPath) + MAX_PATH + 1;
p2 = newpath = (LPSTR) MemAlloc( PathMax );
if (!newpath) {
return(NULL);
}
while( p && *p) {
if (*p == '%') {
i = 0;
p++;
while (p && *p && *p != '%') {
envvar[i++] = *p++;
}
p++;
envvar[i] = '\0';
p1 = envstr;
*p1 = 0;
GetEnvironmentVariable( envvar, p1, MAX_PATH );
while (p1 && *p1) {
*p2++ = *p1++;
if (p2 >= newpath + PathMax) {
PathMax += MAX_PATH;
p3 = (LPSTR)MemReAlloc(newpath, PathMax);
if (!p3) {
MemFree(newpath);
return(NULL);
} else {
p2 = p3 + (p2 - newpath);
newpath = p3;
}
}
}
}
*p2++ = *p++;
if (p2 >= newpath + PathMax) {
PathMax += MAX_PATH;
p3 = (LPSTR)MemReAlloc(newpath, PathMax);
if (!p3) {
MemFree(newpath);
return(NULL);
} else {
p2 = p3 + (p2 - newpath);
newpath = p3;
}
}
}
*p2 = '\0';
return newpath;
}
BOOL
IMAGEAPI
SymFindFileInPath(
HANDLE hprocess,
LPSTR SearchPath,
LPSTR FileName,
PVOID id,
DWORD two,
DWORD three,
DWORD flags,
LPSTR FilePath,
PFINDFILEINPATHCALLBACK callback,
PVOID context
)
{
PPROCESS_ENTRY pe;
char path[MAX_PATH];
LPSTR emark;
LPSTR spath;
GUID guid;
GUID *pguid;
BOOL rc;
LPSTR p;
if (!FileName || !*FileName) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// ignore the path...
for (p = FileName + strlen(FileName); p >= FileName; p--) {
if (*p == '\\') {
FileName = p + 1;
break;
}
}
if (traceSubName(FileName)) // for setting debug breakpoints from DBGHELP_TOKEN
dprint("debug(%s)\n", FileName);
// prepare identifiers for symbol server
if (flags & SSRVOPT_GUIDPTR) {
pguid = (GUID *)id;
} else {
pguid = &guid;
ZeroMemory(pguid, sizeof(GUID));
if (!flags || (flags & SSRVOPT_DWORD))
pguid->Data1 = PtrToUlong(id);
else if (flags & SSRVOPT_DWORDPTR)
pguid->Data1 = *(DWORD *)id;
}
// setup local copy of the symbol path
*FilePath = 0;
spath = NULL;
if (!SearchPath || !*SearchPath) {
if (hprocess) {
pe = FindProcessEntry(hprocess);
if (pe && pe->SymbolSearchPath) {
spath = pe->SymbolSearchPath;
}
}
} else {
spath = SearchPath;
}
if (!spath || !*spath) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// for each node in the search path, look
// for the file, or for it's symsrv entry
do {
emark = strchr(spath, ';');
if (emark) {
memcpy(path, spath, emark - spath);
path[emark - spath] = 0;
emark++;
} else {
strcpy(path, spath);
}
// look for the file in this node
if (!_strnicmp(path, "SYMSRV*", 7)) {
GetFileFromSymbolServer(path,
FileName,
pguid,
two,
three,
FilePath);
} else {
EnsureTrailingBackslash(path);
strcat(path, FileName);
if (fileexists(path))
strcpy(FilePath, path);
}
// if we find a file, process it.
if (*FilePath) {
// if no callback is specified, return with the filename filled in
if (!callback)
break;
// otherwise call the callback
rc = callback(FilePath, context);
// if it returns FALSE, quit...
if (!rc)
break;
// otherwise continue
*FilePath = 0;
}
// continue to the next node
spath = emark;
} while (emark);
return (*FilePath) ? TRUE : FALSE;
}
BOOL
IMAGEAPI
FindFileInPath(
HANDLE hprocess,
LPSTR SearchPath,
LPSTR FileName,
PVOID id,
DWORD two,
DWORD three,
DWORD flags,
LPSTR FilePath
)
{
return SymFindFileInPath(hprocess, SearchPath, FileName, id, two, three, flags, FilePath, NULL, NULL);
}
BOOL
IMAGEAPI
FindFileInSearchPath(
HANDLE hprocess,
LPSTR SearchPath,
LPSTR FileName,
DWORD one,
DWORD two,
DWORD three,
LPSTR FilePath
)
{
return FindFileInPath(hprocess, SearchPath, FileName, UlongToPtr(one), two, three, SSRVOPT_DWORD, FilePath);
}
HANDLE
IMAGEAPI
FindExecutableImage(
LPSTR FileName,
LPSTR SymbolPath,
LPSTR ImageFilePath
)
{
return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL);
}
HANDLE
CheckExecutableImage(
LPSTR Path,
PFIND_EXE_FILE_CALLBACK Callback,
PVOID CallerData,
DWORD flags
)
{
HANDLE FileHandle;
SetCriticalErrorMode();
dprint("FindExecutableImageEx-> Looking for %s... ", Path);
FileHandle = CreateFile( Path,
GENERIC_READ,
g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ?
(FILE_SHARE_DELETE | FILE_SHARE_READ |
FILE_SHARE_WRITE) :
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL,
OPEN_EXISTING,
0,
NULL
);
if (FileHandle != INVALID_HANDLE_VALUE) {
if (Callback) {
if (!Callback(FileHandle, Path, CallerData)) {
eprint("mismatched timestamp ");
if (!(flags & SYMOPT_LOAD_ANYTHING)) {
eprint("\n");
CloseHandle(FileHandle);
FileHandle = INVALID_HANDLE_VALUE;
}
}
}
if (FileHandle != INVALID_HANDLE_VALUE) {
eprint("OK\n");
}
} else {
eprint("no file\n");
}
ResetCriticalErrorMode();
return FileHandle;
}
typedef struct _FEIEP_STATE
{
PFIND_EXE_FILE_CALLBACK UserCb;
PVOID UserCbData;
DWORD flags;
HANDLE Return;
} FEIEP_STATE;
BOOL
CALLBACK
FindExSearchTreeCallback(
LPSTR FilePath,
PVOID CallerData
)
{
FEIEP_STATE* State = (FEIEP_STATE*)CallerData;
State->Return =
CheckExecutableImage(FilePath, State->UserCb, State->UserCbData,
State->flags);
return State->Return != INVALID_HANDLE_VALUE;
}
HANDLE
IMAGEAPI
FindExecutableImageExPass(
LPSTR FileName,
LPSTR SymbolPath,
LPSTR ImageFilePath,
PFIND_EXE_FILE_CALLBACK Callback,
PVOID CallerData,
DWORD flags
)
{
LPSTR Start, End;
HANDLE FileHandle = NULL;
CHAR DirectoryPath[ MAX_PATH ];
LPSTR NewSymbolPath = NULL;
__try {
__try {
if (GetFullPathName( FileName, MAX_PATH, ImageFilePath, &Start )) {
FileHandle = CheckExecutableImage(ImageFilePath, Callback, CallerData, flags);
if (FileHandle != INVALID_HANDLE_VALUE)
return FileHandle;
}
NewSymbolPath = ExpandPath(SymbolPath);
Start = NewSymbolPath;
while (Start && *Start != '\0') {
FEIEP_STATE SearchTreeState;
if (End = strchr( Start, ';' )) {
int Len = (int)(End - Start);
Len = (int)min(Len, sizeof(DirectoryPath)-1);
strncpy( (PCHAR) DirectoryPath, Start, Len );
DirectoryPath[ Len ] = '\0';
End += 1;
} else {
strcpy( (PCHAR) DirectoryPath, Start );
}
if (!_strnicmp(DirectoryPath, "SYMSRV*", 7)) {
goto next;
}
dprint("FindExecutableImageEx-> Searching %s for %s... ", DirectoryPath, FileName);
SearchTreeState.UserCb = Callback;
SearchTreeState.UserCbData = CallerData;
SearchTreeState.flags = flags;
if (SearchTreeForFileEx( (PCHAR) DirectoryPath, FileName, ImageFilePath, FindExSearchTreeCallback, &SearchTreeState )) {
eprint("found\n");
MemFree( NewSymbolPath );
return SearchTreeState.Return;
} else {
eprint("no file\n");
}
next:
Start = End;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_PARAMETER);
}
ImageFilePath[0] = '\0';
} __except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_PARAMETER);
}
if (FileHandle) {
CloseHandle(FileHandle);
}
if (NewSymbolPath) {
MemFree( NewSymbolPath );
}
return NULL;
}
HANDLE
IMAGEAPI
FindExecutable(
LPSTR FileName,
LPSTR SymbolPath,
LPSTR ImageFilePath,
PFIND_EXE_FILE_CALLBACK Callback,
PVOID CallerData,
DWORD flags
)
{
BOOL FullPath = FALSE;
BOOL PathComponents = FALSE;
HANDLE FileHandle;
if (!FileName || !*FileName) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
//
// The filename may or may not contain path components.
// Determine what kind of path it is.
//
if ((((FileName[0] >= 'a' && FileName[0] <= 'z') ||
(FileName[0] >= 'A' && FileName[0] <= 'Z')) &&
FileName[1] == ':') ||
FileName[0] == '\\' ||
FileName[0] == '/') {
FullPath = TRUE;
PathComponents = TRUE;
} else if (strchr(FileName, '\\') ||
strchr(FileName, '/')) {
PathComponents = TRUE;
}
// If the filename is a full path then it can be checked
// for existence directly; there's no need to search
// along any paths.
if (FullPath) {
__try {
FileHandle = CheckExecutableImage(FileName, Callback, CallerData, flags);
if (FileHandle != INVALID_HANDLE_VALUE) {
strcpy(ImageFilePath, FileName);
return FileHandle;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
} else {
// If it's not a full path we need to do a first pass
// with the filename as given. This handles relative
// paths and bare filenames.
FileHandle = FindExecutableImageExPass(FileName, SymbolPath,
ImageFilePath, Callback,
CallerData, flags);
if (FileHandle != NULL) {
return FileHandle;
}
}
// If we still haven't found it and the given filename
// has path components we need to strip off the path components
// and try again with just the base filename.
if (PathComponents) {
LPSTR BaseFile;
BaseFile = strrchr(FileName, '\\');
if (BaseFile == NULL) {
BaseFile = strrchr(FileName, '/');
if (BaseFile == NULL) {
// Must be <drive>:.
BaseFile = FileName + 1;
}
}
// Skip path character to point to base file.
BaseFile++;
return FindExecutableImageExPass(BaseFile, SymbolPath,
ImageFilePath, Callback,
CallerData, flags);
}
return NULL;
}
HANDLE
IMAGEAPI
FindExecutableImageEx(
LPSTR FileName,
LPSTR SymbolPath,
LPSTR ImageFilePath,
PFIND_EXE_FILE_CALLBACK Callback,
PVOID CallerData
)
{
HANDLE hrc;
hrc = FindExecutable(FileName,
SymbolPath,
ImageFilePath,
Callback,
CallerData,
0);
if (hrc)
return hrc;
if (g.SymOptions & SYMOPT_LOAD_ANYTHING)
hrc = FindExecutable(FileName,
SymbolPath,
ImageFilePath,
Callback,
CallerData,
SYMOPT_LOAD_ANYTHING);
return hrc;
}
HANDLE
IMAGEAPI
FindDebugInfoFile(
LPSTR FileName,
LPSTR SymbolPath,
LPSTR DebugFilePath
)
{
return FindDebugInfoFileEx(FileName, SymbolPath, DebugFilePath, NULL, NULL);
}
HANDLE
IMAGEAPI
FindDebugInfoFileEx(
IN LPSTR FileName,
IN LPSTR SymbolPath,
OUT LPSTR DebugFilePath,
IN PFIND_DEBUG_FILE_CALLBACK Callback,
IN PVOID CallerData
)
{
DWORD flag;
if (g.SymOptions & SYMOPT_LOAD_ANYTHING)
flag = fdifRECURSIVE;
else
flag = 0;
if (flag)
dprint("RECURSIVE %s\n", FileName);
return fnFindDebugInfoFileEx(FileName,
SymbolPath,
DebugFilePath,
Callback,
CallerData,
flag);
}
HANDLE
IMAGEAPI
fnFindDebugInfoFileEx(
IN LPSTR FileName,
IN LPSTR SymbolPath,
OUT LPSTR DebugFilePath,
IN PFIND_DEBUG_FILE_CALLBACK Callback,
IN PVOID CallerData,
IN DWORD flag
)
/*++
Routine Description:
The rules are:
Look for
1. <SymbolPath>\Symbols\<ext>\<filename>.dbg
3. <SymbolPath>\<ext>\<filename>.dbg
5. <SymbolPath>\<filename>.dbg
7. <FileNamePath>\<filename>.dbg
Arguments:
FileName - Supplies a file name in one of three forms: fully qualified,
<ext>\<filename>.dbg, or just filename.dbg
SymbolPath - semi-colon delimited
DebugFilePath -
Callback - May be NULL. Callback that indicates whether the Symbol file is valid, or whether
the function should continue searching for another Symbol file.
The callback returns TRUE if the Symbol file is valid, or FALSE if the function should
continue searching.
CallerData - May be NULL. Data passed to the callback.
Flag - indicates that PDBs shouldn't be searched for
Return Value:
The name of the .dbg file and a handle to that file.
--*/
{
HANDLE FileHandle = INVALID_HANDLE_VALUE;
LPSTR ExpSymbolPath = NULL, SymPathStart, PathEnd;
DWORD ShareAttributes, cnt;
LPSTR InitialPath, Sub1, Sub2, FileExt;
CHAR FilePath[_MAX_PATH + 1];
CHAR Drive[_MAX_DRIVE], Dir[_MAX_DIR], SubDirPart[_MAX_DIR], FilePart[_MAX_FNAME], Ext[_MAX_EXT];
CHAR *ExtDir;
DWORD i;
PIMGHLP_DEBUG_DATA pIDD;
BOOL found = FALSE;
DWORD err = 0;
GUID guid;
BOOL ssrv;
assert(DebugFilePath);
*DebugFilePath = 0;
ZeroMemory(&guid, sizeof(GUID));
if (g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
ShareAttributes = (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE);
} else {
ShareAttributes = (FILE_SHARE_READ | FILE_SHARE_WRITE);
}
__try {
*DebugFilePath = '\0';
// Step 1. What do we have?
_splitpath(FileName, Drive, Dir, FilePart, Ext);
if (!_stricmp(Ext, ".dbg")) {
// We got a filename of the form: ext\filename.dbg. Dir holds the extension already.
ExtDir = Dir;
} else {
// Otherwise, skip the period and null out the Dir.
ExtDir = CharNext(Ext);
}
ExpSymbolPath = ExpandPath(SymbolPath);
if (!ExpSymbolPath)
return NULL;
SetCriticalErrorMode();
SymPathStart = ExpSymbolPath;
cnt = 0;
do {
if (PathEnd = strchr( SymPathStart, ';' )) {
*PathEnd = '\0';
}
ssrv = FALSE;
pIDD = (PIMGHLP_DEBUG_DATA)CallerData;
if (!_strnicmp(SymPathStart, "SYMSRV*", 7)) {
*DebugFilePath = 0;
if (!cnt && CallerData) {
ssrv = TRUE;
strcpy(FilePath, FilePart);
strcat(FilePath, ".dbg");
guid.Data1 = pIDD->TimeDateStamp;
GetFileFromSymbolServer(SymPathStart,
FilePath,
&guid,
pIDD->SizeOfImage,
0,
DebugFilePath);
}
} else {
switch (cnt) {
case 0: // <SymbolPath>\symbols\<ext>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = "symbols";
Sub2 = ExtDir;
break;
case 1: // <SymbolPath>\<ext>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = "";
Sub2 = ExtDir;
break;
case 2: // <SymbolPath>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = "";
Sub2 = "";
break;
case 3: // <FileNamePath>\<filename>.ext - A.K.A. what was passed to us
InitialPath = Drive;
Sub1 = "";
Sub2 = Dir;
// this stops us from checking out everything in the sympath
cnt++;
break;
}
// build fully-qualified filepath to look for
strcpy(FilePath, InitialPath);
EnsureTrailingBackslash(FilePath);
strcat(FilePath, Sub1);
EnsureTrailingBackslash(FilePath);
strcat(FilePath, Sub2);
EnsureTrailingBackslash(FilePath);
strcat(FilePath, FilePart);
strcpy(DebugFilePath, FilePath);
strcat(DebugFilePath, ".dbg");
}
// try to open the file
if (*DebugFilePath) {
dprint("FindDebugInfoFileEx-> Looking for %s... ", DebugFilePath);
FileHandle = CreateFile(DebugFilePath,
GENERIC_READ,
ShareAttributes,
NULL,
OPEN_EXISTING,
0,
NULL);
// if the file opens, bail from this loop
if (FileHandle != INVALID_HANDLE_VALUE) {
found = TRUE;
if (pIDD) {
pIDD->ImageSrc = (ssrv) ? srcSymSrv : srcSearchPath;
}
if (!Callback) {
break;
} else if (Callback(FileHandle, DebugFilePath, CallerData)) {
break;
} else {
eprint("mismatched timestamp\n");
CloseHandle(FileHandle);
FileHandle = INVALID_HANDLE_VALUE;
}
} else {
err = GetLastError();
switch (err)
{
case ERROR_FILE_NOT_FOUND:
eprint("file not found\n");
break;
case ERROR_PATH_NOT_FOUND:
eprint("path not found\n");
break;
default:
eprint("file error 0x%x\n", err);
break;
}
}
// if file is open, bail from this loop too - else continue
if (FileHandle != INVALID_HANDLE_VALUE)
break;
}
// go to next item in the sympath
if (PathEnd) {
*PathEnd = ';';
SymPathStart = PathEnd + 1;
} else {
SymPathStart = ExpSymbolPath;
cnt++;
}
} while (cnt < 4);
} __except(EXCEPTION_EXECUTE_HANDLER) {
if (FileHandle != INVALID_HANDLE_VALUE) {
CloseHandle(FileHandle);
}
FileHandle = INVALID_HANDLE_VALUE;
}
if (ExpSymbolPath) {
MemFree(ExpSymbolPath);
}
if (FileHandle == INVALID_HANDLE_VALUE) {
FileHandle = NULL;
DebugFilePath[0] = '\0';
} else {
eprint("OK\n");
}
if (!FileHandle // if we didn't get the right file...
&& found // but we found some file...
&& (flag & fdifRECURSIVE)) // and we were told to run recursively...
{
// try again without timestamp checking
FileHandle = fnFindDebugInfoFileEx(FileName,
SymbolPath,
FilePath,
NULL,
0,
flag);
if (FileHandle && FileHandle != INVALID_HANDLE_VALUE)
strcpy(DebugFilePath, FilePath);
}
ResetCriticalErrorMode();
return FileHandle;
}
BOOL
GetImageNameFromMiscDebugData(
IN HANDLE FileHandle,
IN PVOID MappedBase,
IN PIMAGE_NT_HEADERS32 NtHeaders,
IN PIMAGE_DEBUG_DIRECTORY DebugDirectories,
IN ULONG NumberOfDebugDirectories,
OUT LPSTR ImageFilePath
)
{
IMAGE_DEBUG_MISC TempMiscData;
PIMAGE_DEBUG_MISC DebugMiscData;
ULONG BytesToRead, BytesRead;
BOOLEAN FoundImageName;
LPSTR ImageName;
PIMAGE_OPTIONAL_HEADER32 OptionalHeader32 = NULL;
PIMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NULL;
while (NumberOfDebugDirectories) {
if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) {
break;
} else {
DebugDirectories += 1;
NumberOfDebugDirectories -= 1;
}
}
if (NumberOfDebugDirectories == 0) {
return FALSE;
}
OptionalHeadersFromNtHeaders(NtHeaders, &OptionalHeader32, &OptionalHeader64);
if ((OPTIONALHEADER(MajorLinkerVersion) < 3) &&
(OPTIONALHEADER(MinorLinkerVersion) < 36) ) {
BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Reserved );
} else {
BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Data );
}
DebugMiscData = NULL;
FoundImageName = FALSE;
if (MappedBase == 0) {
if (SetFilePointer( FileHandle,
DebugDirectories->PointerToRawData,
NULL,
FILE_BEGIN
) == DebugDirectories->PointerToRawData
) {
if (ReadFile( FileHandle,
&TempMiscData,
BytesToRead,
&BytesRead,
NULL
) &&
BytesRead == BytesToRead
) {
DebugMiscData = &TempMiscData;
if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
BytesToRead = DebugMiscData->Length - BytesToRead;
BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
if (ReadFile( FileHandle,
ImageFilePath,
BytesToRead,
&BytesRead,
NULL
) &&
BytesRead == BytesToRead
) {
FoundImageName = TRUE;
}
}
}
}
} else {
DebugMiscData = (PIMAGE_DEBUG_MISC)((PCHAR)MappedBase +
DebugDirectories->PointerToRawData );
if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
ImageName = (PCHAR)DebugMiscData + BytesToRead;
BytesToRead = DebugMiscData->Length - BytesToRead;
BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
if (*ImageName != '\0' ) {
memcpy( ImageFilePath, ImageName, BytesToRead );
FoundImageName = TRUE;
}
}
}
return FoundImageName;
}
#define MAX_DEPTH 32
BOOL
IMAGEAPI
SearchTreeForFileEx(
LPSTR RootPath,
LPSTR InputPathName,
LPSTR OutputPathBuffer,
PSEARCH_TREE_FOR_FILE_EX_CALLBACK Callback,
PVOID CallbackData
)
{
// UnSafe...
PCHAR FileName;
PUCHAR Prefix = (PUCHAR) "";
CHAR PathBuffer[ MAX_PATH ];
ULONG Depth;
PCHAR PathTail[ MAX_DEPTH ];
PCHAR FindHandle[ MAX_DEPTH ];
LPWIN32_FIND_DATA FindFileData;
UCHAR FindFileBuffer[ MAX_PATH + sizeof( WIN32_FIND_DATA ) ];
BOOL Result;
SetCriticalErrorMode();;
strcpy( PathBuffer, RootPath );
FileName = InputPathName;
while (*InputPathName) {
if (*InputPathName == ':' || *InputPathName == '\\' || *InputPathName == '/') {
FileName = ++InputPathName;
} else {
InputPathName = CharNext(InputPathName);
}
}
FindFileData = (LPWIN32_FIND_DATA)FindFileBuffer;
Depth = 0;
Result = FALSE;
while (TRUE) {
startDirectorySearch:
PathTail[ Depth ] = strchr( PathBuffer, '\0' );
if (PathTail[ Depth ] > PathBuffer
&& *CharPrev(PathBuffer, PathTail[ Depth ]) != '\\') {
*(PathTail[ Depth ])++ = '\\';
}
strcpy( PathTail[ Depth ], "*.*" );
FindHandle[ Depth ] = (PCHAR) FindFirstFile( PathBuffer, FindFileData );
if (FindHandle[ Depth ] == INVALID_HANDLE_VALUE) {
goto nextDirectory;
}
do {
if (FindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp( FindFileData->cFileName, "." ) &&
strcmp( FindFileData->cFileName, ".." ) &&
Depth < MAX_DEPTH
) {
strcpy(PathTail[ Depth ], FindFileData->cFileName);
strcat(PathTail[ Depth ], "\\");
Depth++;
goto startDirectorySearch;
}
} else
if (!_stricmp( FindFileData->cFileName, FileName )) {
strcpy( PathTail[ Depth ], FindFileData->cFileName );
strcpy( OutputPathBuffer, PathBuffer );
if (Callback != NULL) {
Result = Callback(OutputPathBuffer, CallbackData);
} else {
Result = TRUE;
}
}
restartDirectorySearch:
if (Result) {
break;
}
}
while (FindNextFile( FindHandle[ Depth ], FindFileData ));
FindClose( FindHandle[ Depth ] );
nextDirectory:
if (Depth == 0) {
break;
}
Depth--;
goto restartDirectorySearch;
}
ResetCriticalErrorMode();
return Result;
}
BOOL
IMAGEAPI
SearchTreeForFile(
LPSTR RootPath,
LPSTR InputPathName,
LPSTR OutputPathBuffer
)
{
return SearchTreeForFileEx(RootPath, InputPathName, OutputPathBuffer,
NULL, NULL);
}
BOOL
IMAGEAPI
MakeSureDirectoryPathExists(
LPCSTR DirPath
)
{
LPSTR p, DirCopy;
DWORD dw;
// Make a copy of the string for editing.
__try {
DirCopy = (LPSTR) MemAlloc(strlen(DirPath) + 1);
if (!DirCopy) {
return FALSE;
}
strcpy(DirCopy, DirPath);
p = DirCopy;
// If the second character in the path is "\", then this is a UNC
// path, and we should skip forward until we reach the 2nd \ in the path.
if ((*p == '\\') && (*(p+1) == '\\')) {
p++; // Skip over the first \ in the name.
p++; // Skip over the second \ in the name.
// Skip until we hit the first "\" (\\Server\).
while (*p && *p != '\\') {
p = CharNext(p);
}
// Advance over it.
if (*p) {
p++;
}
// Skip until we hit the second "\" (\\Server\Share\).
while (*p && *p != '\\') {
p = CharNext(p);
}
// Advance over it also.
if (*p) {
p++;
}
} else
// Not a UNC. See if it's <drive>:
if (*(p+1) == ':' ) {
p++;
p++;
// If it exists, skip over the root specifier
if (*p && (*p == '\\')) {
p++;
}
}
while( *p ) {
if ( *p == '\\' ) {
*p = '\0';
dw = fnGetFileAttributes(DirCopy);
// Nothing exists with this name. Try to make the directory name and error if unable to.
if ( dw == 0xffffffff ) {
if ( !CreateDirectory(DirCopy,NULL) ) {
if( GetLastError() != ERROR_ALREADY_EXISTS ) {
MemFree(DirCopy);
return FALSE;
}
}
} else {
if ( (dw & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ) {
// Something exists with this name, but it's not a directory... Error
MemFree(DirCopy);
return FALSE;
}
}
*p = '\\';
}
p = CharNext(p);
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() );
MemFree(DirCopy);
return(FALSE);
}
MemFree(DirCopy);
return TRUE;
}
LPAPI_VERSION
IMAGEAPI
ImagehlpApiVersion(
VOID
)
{
//
// don't tell old apps about the new version. It will
// just scare them.
//
return &g.AppVersion;
}
LPAPI_VERSION
IMAGEAPI
ImagehlpApiVersionEx(
LPAPI_VERSION av
)
{
LPAPI_VERSION ver;
__try {
ver = av;
} __except (EXCEPTION_EXECUTE_HANDLER) {
ver = &g.AppVersion;
}
if (ver->Revision < 6) {
//
// For older debuggers, just tell them what they want to hear.
//
return ver;
}
return &g.ApiVersion;
}