Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1578 lines
43 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
symdbg.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))
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#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 idd;
PPIDI pPIDI;
DWORD sections;
BOOL SymbolsLoaded;
HANDLE hProcess;
LPSTR sz;
HANDLE hdb;
DWORD dw;
DWORD len;
hProcess = GetCurrentProcess();
idd = GetIDD(FileHandle, FileName, SymbolPath, ImageBase, NO_PE64_IMAGES);
if (!idd)
return NULL;
pPIDI = (PPIDI)MemAlloc(sizeof(PIDI));
if (!pPIDI)
return NULL;
ZeroMemory(pPIDI, sizeof(PIDI));
pIDI = &pPIDI->idi;
pPIDI->hdr.idd = idd;
pIDI->ReservedSize = sizeof(IMAGE_DEBUG_INFORMATION);
pIDI->ReservedMachine = idd->Machine;
pIDI->ReservedCharacteristics = (USHORT)idd->Characteristics;
pIDI->ReservedCheckSum = idd->CheckSum;
pIDI->ReservedTimeDateStamp = idd->TimeDateStamp;
pIDI->ReservedRomImage = idd->fROM;
// read info
InitializeListHead( &pIDI->List );
pIDI->ImageBase = (ULONG)idd->ImageBaseFromImage;
len = strlen(idd->ImageFilePath) + 1;
pIDI->ImageFilePath = (PSTR)MemAlloc(len);
if (pIDI->ImageFilePath) {
CopyString(pIDI->ImageFilePath, idd->ImageFilePath, len);
}
len = strlen(idd->OriginalImageFileName) + 1;
pIDI->ImageFileName = (PSTR)MemAlloc(len);
if (pIDI->ImageFileName) {
CopyString(pIDI->ImageFileName, idd->OriginalImageFileName, len);
}
if (idd->pMappedCoff) {
pIDI->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER)MemAlloc(idd->cMappedCoff);
if (pIDI->CoffSymbols) {
memcpy(pIDI->CoffSymbols, idd->pMappedCoff, idd->cMappedCoff);
}
pIDI->SizeOfCoffSymbols = idd->cMappedCoff;
}
if (idd->pFpo) {
pIDI->ReservedNumberOfFpoTableEntries = idd->cFpo;
pIDI->ReservedFpoTableEntries = (PFPO_DATA)idd->pFpo;
}
pIDI->SizeOfImage = idd->SizeOfImage;
if (idd->DbgFilePath && *idd->DbgFilePath) {
len = strlen(idd->DbgFilePath) + 1;
pIDI->ReservedDebugFilePath = (PSTR)MemAlloc(len);
if (pIDI->ReservedDebugFilePath) {
CopyString(pIDI->ReservedDebugFilePath, idd->DbgFilePath, len);
}
}
if (idd->pMappedCv) {
pIDI->ReservedCodeViewSymbols = idd->pMappedCv;
pIDI->ReservedSizeOfCodeViewSymbols = idd->cMappedCv;
}
// for backwards compatibility
if (idd->ImageMap) {
sections = (DWORD)((char *)idd->pCurrentSections - (char *)idd->ImageMap);
pIDI->ReservedMappedBase = MapItRO(idd->ImageFileHandle);
if (pIDI->ReservedMappedBase) {
pIDI->ReservedSections = (PIMAGE_SECTION_HEADER)idd->pCurrentSections;
pIDI->ReservedNumberOfSections = idd->cCurrentSections;
if (idd->ddva) {
pIDI->ReservedDebugDirectory = (PIMAGE_DEBUG_DIRECTORY)((PCHAR)pIDI->ReservedMappedBase + idd->ddva);
pIDI->ReservedNumberOfDebugDirectories = idd->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.idd, 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
CheckDirForFile(
char *srchpath,
char *found,
DWORD size,
PFINDFILEINPATHCALLBACK callback,
PVOID context
)
{
char path[MAX_PATH + 1];
char file[MAX_PATH + 1];
char fname[_MAX_FNAME + 1] = "";
char ext[_MAX_EXT + 1];
WIN32_FIND_DATA fd;
HANDLE hfind;
HANDLE hfile = 0;
BOOL rc;
ShortFileName(srchpath, path, DIMA(path));
EnsureTrailingBackslash(path);
CatStrArray(path, "*");
ZeroMemory(&fd, sizeof(fd));
hfind = FindFirstFile(path, &fd);
if (hfind == INVALID_HANDLE_VALUE)
return false;
ShortFileName(srchpath, path, DIMA(path));
_splitpath(path, NULL, NULL, fname, ext);
do {
if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
continue;
CopyStrArray(file, path);
EnsureTrailingBackslash(file);
CatStrArray(file, fd.cFileName);
if (isdir(file)) {
EnsureTrailingBackslash(file);
CatStrArray(file, fname);
CatStrArray(file, ext);
if (!fileexists(file))
continue;
}
CopyString(found, file, MAX_PATH + 1);
if (!callback)
break;
// otherwise call the callback
rc = callback(found, context);
// if it returns false, quit...
if (!rc)
return true;
// otherwise continue
*found = 0;
} while (FindNextFile(hfind, &fd));
// If there is no match, but a file exists in the symbol subdir with
// a matching name, make sure that is what will be picked.
CopyStrArray(file, srchpath);
EnsureTrailingBackslash(file);
CatStrArray(file, fname);
CatStrArray(file, ext);
if (fileexists(file))
CopyStrArray(found, file);
return false;
}
BOOL
IMAGEAPI
SymFindFileInPath(
HANDLE hprocess,
LPSTR SearchPath,
LPSTR FileName,
PVOID id,
DWORD two,
DWORD three,
DWORD flags,
LPSTR FoundFile,
PFINDFILEINPATHCALLBACK callback,
PVOID context
)
{
PPROCESS_ENTRY pe = NULL;
char path[MAX_PATH + 1];
char dirpath[MAX_PATH + 1];
char fname[MAX_PATH + 1];
char token[MAX_PATH + 1];
char *next;
LPSTR emark;
LPSTR spath;
GUID guid;
GUID *pguid;
BOOL rc;
LPSTR p;
DWORD err;
BOOL ssrv = true;
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;
}
}
#ifdef DEBUG
if (traceSubName(FileName)) // for setting debug breakpoints from DBGHELP_TOKEN
dtrace("debug(%s)\n", FileName);
#endif
// 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
*FoundFile = 0;
spath = NULL;
if (hprocess)
pe = FindProcessEntry(hprocess);
if (!SearchPath || !*SearchPath) {
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
for (next = TokenFromSymbolPath(spath, path, MAX_PATH + 1);
*path;
next = TokenFromSymbolPath(next, path, MAX_PATH + 1))
{
// look for the file in this node
if (ssrv && symsrvPath(path)) {
err = symsrvGetFile(pe,
path,
FileName,
pguid,
two,
three,
FoundFile);
if (err == ERROR_NO_DATA)
ssrv = false;
} else {
EnsureTrailingBackslash(path);
CopyStrArray(dirpath, path);
CatStrArray(dirpath, FileName);
rc = CheckDirForFile(dirpath, FoundFile, MAX_PATH + 1, callback, context);
if (rc) {
pprint(pe, "%s - ", FoundFile);
break;
}
CatStrArray(path, FileName);
if (fileexists(path))
strcpy(FoundFile, path); // SECURITY: Don't know size of buffer.
}
// if we find a file, process it.
if (*FoundFile) {
// if no callback is specified, return with the filename filled in
pprint(pe, "%s - ", FoundFile);
if (!callback)
break;
// otherwise call the callback
rc = callback(FoundFile, context);
// if it returns false, quit...
if (!rc)
break;
// otherwise continue
peprint(pe, "mismatched\n");
*FoundFile = 0;
}
}
if (*FoundFile) {
peprint(pe, "OK\n");
return true;
}
return 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(
LPCSTR Path,
PFIND_EXE_FILE_CALLBACK Callback,
PVOID CallerData,
DWORD flags
)
{
HANDLE FileHandle;
char TmpPath[MAX_PATH + 1];
PIMGHLP_DEBUG_DATA idd;
PPROCESS_ENTRY pe = NULL;
SetCriticalErrorMode();
idd = (PIMGHLP_DEBUG_DATA)CallerData;
if (idd && (idd->SizeOfStruct == sizeof(IMGHLP_DEBUG_DATA)))
pe = idd->pe;
if (!CopyStrArray(TmpPath, Path))
return INVALID_HANDLE_VALUE;
pprint(pe, "%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, TmpPath, CallerData)) {
if (!(flags & SYMOPT_LOAD_ANYTHING)) {
pprint(pe, "%s - mismatched timestamp OK\n", Path);
CloseHandle(FileHandle);
FileHandle = INVALID_HANDLE_VALUE;
} else
pprint(pe, "%s - mismatched timestamp\n", Path);
}
}
if (FileHandle != INVALID_HANDLE_VALUE) {
pprint(pe, "%s - OK\n", Path);
}
} else {
peprint(pe, "%s\n", errortext(GetLastError()));
}
ResetCriticalErrorMode();
return FileHandle;
}
typedef struct _FEIEP_STATE
{
PFIND_EXE_FILE_CALLBACK UserCb;
PVOID UserCbData;
DWORD flags;
HANDLE Return;
} FEIEP_STATE;
BOOL
CALLBACK
FindExSearchTreeCallback(
LPCSTR 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;
}
BOOL
CheckDirForExecutable(
char *srchpath,
char *filename,
char *found,
PENUMDIRTREE_CALLBACK callback,
PVOID context
)
{
char tmp[MAX_PATH + 1];
char path[MAX_PATH + 1];
char file[MAX_PATH + 1];
char fname[_MAX_FNAME + 1] = "";
char ext[_MAX_EXT + 1];
WIN32_FIND_DATA fd;
HANDLE hfind;
HANDLE hfile = 0;
BOOL rc;
CopyStrArray(tmp, srchpath);
EnsureTrailingBackslash(tmp);
CatStrArray(tmp, filename);
ShortFileName(tmp, path, DIMA(path));
EnsureTrailingBackslash(path);
CatStrArray(path, "*");
ZeroMemory(&fd, sizeof(fd));
hfind = FindFirstFile(path, &fd);
if (hfind == INVALID_HANDLE_VALUE)
return false;
CopyStrArray(tmp, srchpath);
EnsureTrailingBackslash(tmp);
CatStrArray(tmp, filename);
ShortFileName(tmp, path, DIMA(path));
_splitpath(path, NULL, NULL, fname, ext);
do {
if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
continue;
CopyStrArray(file, path);
EnsureTrailingBackslash(file);
CatStrArray(file, fd.cFileName);
if (isdir(file)) {
EnsureTrailingBackslash(file);
CatStrArray(file, fname);
CatStrArray(file, ext);
if (!fileexists(file))
continue;
}
CopyString(found, file, MAX_PATH + 1);
if (!callback)
break;
// otherwise call the callback
rc = callback(found, context);
// if it returns false, quit...
if (rc)
return true;
// otherwise continue
*found = 0;
} while (FindNextFile(hfind, &fd));
// If there is no match, but a file exists in the symbol subdir with
// a matching name, make sure that is what will be picked.
CopyStrArray(file, path);
EnsureTrailingBackslash(file);
CatStrArray(file, fname);
CatStrArray(file, ext);
if (fileexists(file))
CopyStrArray(found, file);
return false;
}
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 + 1];
LPSTR NewSymbolPath = NULL;
PIMGHLP_DEBUG_DATA idd;
PPROCESS_ENTRY pe = NULL;
idd = (PIMGHLP_DEBUG_DATA)CallerData;
if (idd && (idd->SizeOfStruct == sizeof(IMGHLP_DEBUG_DATA)))
pe = idd->pe;
__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, ';' )) {
CopyNStrArray(DirectoryPath, Start, (ULONG)(End - Start));
End += 1;
} else {
CopyStrArray(DirectoryPath, Start);
}
trim(DirectoryPath);
if (symsrvPath(DirectoryPath))
goto next;
SearchTreeState.UserCb = Callback;
SearchTreeState.UserCbData = CallerData;
SearchTreeState.flags = flags;
if (CheckDirForExecutable(DirectoryPath, FileName, ImageFilePath, FindExSearchTreeCallback, &SearchTreeState)) {
pprint(pe, "%s found\n", ImageFilePath);
MemFree( NewSymbolPath );
return SearchTreeState.Return;
}
if (EnumDirTree(INVALID_HANDLE_VALUE, DirectoryPath, FileName, ImageFilePath, FindExSearchTreeCallback, &SearchTreeState )) {
pprint(pe, "%s found\n", ImageFilePath);
MemFree( NewSymbolPath );
return SearchTreeState.Return;
} else {
pprint(pe, "%s not found in %s\n", FileName, DirectoryPath);
}
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); // SECURITY: Don't know size of target buffer.
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 (option(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);
}
void dbgerror(PPROCESS_ENTRY pe)
{
DWORD err = GetLastError();
switch (err)
{
case ERROR_FILE_NOT_FOUND:
peprint(pe, "file not found\n");
break;
case ERROR_PATH_NOT_FOUND:
peprint(pe, "path not found\n");
break;
case ERROR_NOT_READY:
peprint(pe, "drive not ready\n");
break;
case ERROR_ACCESS_DENIED:
peprint(pe, "access is denied\n");
break;
default:
peprint(pe, "file error 0x%x\n", err);
break;
}
}
HANDLE
OpenDbg(
PPROCESS_ENTRY pe,
char *dbgpath,
char *found,
DWORD size,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData
)
{
HANDLE fh;
static DWORD attrib = (DWORD)-1;
if (attrib == (DWORD)-1) {
if (g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
attrib = (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE);
} else {
attrib = (FILE_SHARE_READ | FILE_SHARE_WRITE);
}
}
if (!*dbgpath || !size)
return INVALID_HANDLE_VALUE;
fh = CreateFile(dbgpath,
GENERIC_READ,
attrib,
NULL,
OPEN_EXISTING,
0,
NULL);
if (fh == INVALID_HANDLE_VALUE) {
pprint(pe, "%s - %s\n", dbgpath, errortext(GetLastError())); // dbgerror(pe);
return fh;
}
if (Callback && !Callback(fh, dbgpath, CallerData)) {
pprint(pe, "%s - mismatched timestamp\n", dbgpath);
CloseHandle(fh);
fh = INVALID_HANDLE_VALUE;
if (!*found)
CopyString(found, dbgpath, size);
return fh;
}
CopyString(found, dbgpath, size);
// Don't display the okay message, if we are within modload().
// We can tell if pe was set to anything but null.
if (!pe)
pprint(pe, "%s - OK", dbgpath);
return fh;
}
HANDLE
CheckDirForDbgs(
PPROCESS_ENTRY pe,
char *dbgpath,
char *found,
DWORD size,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData
)
{
char path[MAX_PATH + 1];
char dbg[MAX_PATH + 1];
char fname[_MAX_FNAME + 1] = "";
char ext[_MAX_EXT + 1];
WIN32_FIND_DATA fd;
HANDLE hfind;
HANDLE hfile;
ShortFileName(dbgpath, path, DIMA(path));
EnsureTrailingBackslash(path);
CatStrArray(path, "*");
ZeroMemory(&fd, sizeof(fd));
hfind = FindFirstFile(path, &fd);
if (hfind == INVALID_HANDLE_VALUE)
return hfind;
do {
if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))
continue;
CopyStrArray(dbg, dbgpath);
EnsureTrailingBackslash(dbg);
CatStrArray(dbg, fd.cFileName);
if (GetFileAttributes(dbg) & FILE_ATTRIBUTE_DIRECTORY) {
if (!*fname)
_splitpath(dbgpath, NULL, NULL, fname, ext);
EnsureTrailingBackslash(dbg);
CatStrArray(dbg, fname);
CatStrArray(dbg, ext);
} else {
if (!IsDbg(dbg))
continue;
}
hfile = OpenDbg(pe, dbg, found, size, Callback, CallerData);
if (hfile != INVALID_HANDLE_VALUE) {
CopyString(dbgpath, dbg, MAX_PATH + 1);
return hfile;
}
} while (FindNextFile(hfind, &fd));
return INVALID_HANDLE_VALUE;
}
HANDLE
IMAGEAPI
FindDebugInfoFileEx(
IN LPSTR FileName,
IN LPSTR SymbolPath,
OUT LPSTR DebugFilePath,
IN PFIND_DEBUG_FILE_CALLBACK Callback,
IN PVOID CallerData
)
/*++
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.
Return Value:
The name of the .dbg file and a handle to that file.
--*/
{
HANDLE fh = INVALID_HANDLE_VALUE;
char *espath = NULL;
char dbgfile[MAX_PATH + 1];
char dirbuf[_MAX_DIR];
char fname[_MAX_FNAME + 1];
char extbuf[_MAX_EXT + 1];
char *ext;
char token[MAX_PATH + 1];
char *next;
DWORD pass;
char dbgpath[MAX_PATH + 1];
char found[MAX_PATH + 1];
DWORD junkbuf;
DWORD *imageSrc = &junkbuf;
DWORD err;
BOOL ssrv = true;
PIMGHLP_DEBUG_DATA idd;
PPROCESS_ENTRY pe = NULL;
char sympath[MAX_PATH * 6];
char drive[_MAX_DRIVE + 1];
char dir[_MAX_DIR + 1];
assert(DebugFilePath);
CopyStrArray(sympath, (SymbolPath) ? SymbolPath : "");
idd = (PIMGHLP_DEBUG_DATA)CallerData;
if (idd && (idd->SizeOfStruct == sizeof(IMGHLP_DEBUG_DATA))) {
pe = idd->pe;
*drive = 0;
*dir = 0;
_splitpath(idd->ImageFilePath, drive, dir, NULL, NULL);
if (*drive || *dir) {
RemoveTrailingBackslash(dir);
CatStrArray(sympath, ";");
CatStrArray(sympath, drive);
CatStrArray(sympath, dir);
}
}
__try {
*DebugFilePath = 0;
*found = 0;
// Step 1. What do we have?
_splitpath(FileName, NULL, dirbuf, fname, extbuf);
if (!_stricmp(extbuf, ".dbg")) {
// We got a filename of the form: ext\filename.dbg. Dir holds the extension already.
ext = dirbuf;
} else {
// Otherwise, skip the period and null out the Dir.
ext = CharNext(extbuf);
}
// if we were passed no file extension, try to calculate it from the idd
if (CallerData) {
if (idd->SizeOfStruct == sizeof(IMGHLP_DEBUG_DATA)) {
if (!*ext) {
if (*idd->ImageFilePath) {
_splitpath(idd->ImageFilePath, NULL, NULL, NULL, extbuf);
} else if (*idd->ImageName) {
_splitpath(idd->ImageName, NULL, NULL, NULL, extbuf);
}
ext = CharNext(extbuf);
}
imageSrc = &idd->ImageSrc;
} else
idd = NULL;
}
espath = ExpandPath(sympath);
if (!espath)
return NULL;
SetCriticalErrorMode();
// okay, let's walk through the directories in the symbol path
next = TokenFromSymbolPath(espath, token, MAX_PATH + 1);
while (*token) {
fh = INVALID_HANDLE_VALUE;
for (pass = 0; pass < 3; pass++) {
*dbgpath = 0;
if (symsrvPath(token)) {
if (pass || !idd || !ssrv)
break;
*imageSrc = srcSymSrv;
CopyStrArray(dbgfile, fname);
CatStrArray(dbgfile, ".dbg");
err = symsrvGetFileMultiIndex(NULL,
token,
dbgfile,
idd->TimeDateStamp,
idd->DbgTimeDateStamp,
idd->SizeOfImage,
0,
dbgpath);
if (err == ERROR_NO_DATA)
ssrv = false;
} else {
if (pass && !*ext)
break;
*imageSrc = srcSearchPath;
if (!CreateSymbolPath(pass, token, ext, fname, ".dbg", dbgpath, DIMA(dbgpath)))
break;
}
// try to open the file
if (*dbgpath) {
if (!pass)
fh = CheckDirForDbgs(pe, dbgpath, found, DIMA(found), Callback, CallerData);
if (fh == INVALID_HANDLE_VALUE)
fh = OpenDbg(pe, dbgpath, found, DIMA(found), Callback, CallerData);
if (fh != INVALID_HANDLE_VALUE)
break;
}
}
if (fh != INVALID_HANDLE_VALUE)
break;
next = TokenFromSymbolPath(next, token, MAX_PATH + 1);
}
MemFree(espath);
// if mismatched dbgs are okay and if we found something earlier, then open it
if (!option(SYMOPT_EXACT_SYMBOLS) || option(SYMOPT_LOAD_ANYTHING)) {
if ((!fh || fh == INVALID_HANDLE_VALUE) && *found) {
// try again without timestamp checking
*imageSrc = srcSearchPath;
CopyStrArray(dbgpath, found);
fh = OpenDbg(pe, dbgpath, found, DIMA(found), NULL, NULL);
}
}
ResetCriticalErrorMode();
if (fh == INVALID_HANDLE_VALUE)
fh = NULL;
if (fh)
strcpy(DebugFilePath, dbgpath);
} __except(EXCEPTION_EXECUTE_HANDLER) {
if (fh != INVALID_HANDLE_VALUE)
CloseHandle(fh);
fh = NULL;
}
return fh;
}
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
EnumDirTree(
HANDLE hProcess,
PSTR RootPath,
PSTR InputPathName,
PSTR OutputPathBuffer,
PENUMDIRTREE_CALLBACK Callback,
PVOID CallbackData
)
{
// UnSafe...
PCHAR FileName;
PUCHAR Prefix = (PUCHAR) "";
CHAR PathBuffer[ MAX_PATH+1 ];
ULONG Depth;
PCHAR PathTail[ MAX_DEPTH ];
PCHAR FindHandle[ MAX_DEPTH ];
LPWIN32_FIND_DATA FindFileData;
UCHAR FindFileBuffer[ MAX_PATH + sizeof( WIN32_FIND_DATA ) ];
BOOL Result;
DWORD len;
PPROCESS_ENTRY pe;
SetCriticalErrorMode();;
pe = FindProcessEntry(hProcess);
if (!CopyStrArray(PathBuffer, RootPath))
return false;
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' );
len = DIMA(PathBuffer)
- (DWORD)((DWORD_PTR)PathTail[ Depth ] - (DWORD_PTR)PathBuffer);
if (PathTail[ Depth ] > PathBuffer
&& *CharPrev(PathBuffer, PathTail[ Depth ]) != '\\') {
*(PathTail[ Depth ])++ = '\\';
}
CopyString( PathTail[ Depth ], "*.*", len );
FindHandle[ Depth ] = (PCHAR) FindFirstFile( PathBuffer, FindFileData );
if (GetLastError() == ERROR_NOT_READY) {
pprint(pe, "%s - drive not ready\n", PathBuffer);
break;
}
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
) {
CopyString(PathTail[ Depth ], FindFileData->cFileName, len);
CatString(PathTail[ Depth ], "\\", len);
Depth++;
goto startDirectorySearch;
}
} else
if (!_stricmp( FindFileData->cFileName, FileName )) {
CopyString( PathTail[ Depth ], FindFileData->cFileName, len );
if (OutputPathBuffer)
strcpy( OutputPathBuffer, PathBuffer ); // SECURITY: Don't know size of target buffer.
if (Callback != NULL) {
Result = Callback((LPCSTR)PathBuffer, CallbackData);
} else {
Result = true;
}
}
restartDirectorySearch:
if (Result)
break;
// poll for ctrl-c
if (DoCallback(pe, CBA_DEFERRED_SYMBOL_LOAD_CANCEL, NULL))
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 EnumDirTree(INVALID_HANDLE_VALUE, RootPath, InputPathName, OutputPathBuffer, NULL, NULL);
}
BOOL
IMAGEAPI
MakeSureDirectoryPathExists(
LPCSTR DirPath
)
{
LPSTR p, DirCopy;
DWORD len;
DWORD dw;
// Make a copy of the string for editing.
__try {
len = strlen(DirPath) + 1;
DirCopy = (LPSTR) MemAlloc(len);
if (!DirCopy) {
return false;
}
CopyString(DirCopy, DirPath, len);
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
)
{
__try {
g.AppVersion = *av;
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
if (g.AppVersion.Revision < 6) {
//
// For older debuggers, just tell them what they want to hear.
//
g.ApiVersion = g.AppVersion;
}
return &g.ApiVersion;
}