/*++ 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 #include #include #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 :. 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. \Symbols\\.dbg 3. \\.dbg 5. \.dbg 7. \.dbg Arguments: FileName - Supplies a file name in one of three forms: fully qualified, \.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: // \symbols\\.ext InitialPath = SymPathStart; Sub1 = "symbols"; Sub2 = ExtDir; break; case 1: // \\.ext InitialPath = SymPathStart; Sub1 = ""; Sub2 = ExtDir; break; case 2: // \.ext InitialPath = SymPathStart; Sub1 = ""; Sub2 = ""; break; case 3: // \.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 : 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; }