|
|
/*++
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>
API_VERSION ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), API_VERSION_NUMBER, 0 };
//
// If the app does not call ImagehlpApiVersionEx, always assume
// that it is version 3.
//
API_VERSION AppVersion = { 3, 5, 3, 0 };
LPSTR GetEnvVariable( IN LPSTR VariableName );
#define ROUNDUP(x, y) ((x + (y-1)) & ~(y-1))
BOOL SplitSymbols( LPSTR ImageName, LPSTR SymbolsPath, LPSTR SymbolFilePath, ULONG Flags ) { HANDLE FileHandle, SymbolFileHandle; HANDLE hMappedFile; LPVOID ImageBase; PIMAGE_NT_HEADERS NtHeaders; LPSTR ImageFileName; DWORD SizeOfSymbols, ImageNameOffset, DebugSectionStart; PIMAGE_SECTION_HEADER DebugSection = NULL; DWORD SectionNumber, BytesWritten, NewFileSize, HeaderSum, CheckSum; PIMAGE_DEBUG_DIRECTORY DebugDirectory, DebugDirectories, DbgDebugDirectories = NULL; IMAGE_DEBUG_DIRECTORY MiscDebugDirectory = {0}; IMAGE_DEBUG_DIRECTORY FpoDebugDirectory = {0}; IMAGE_DEBUG_DIRECTORY FunctionTableDir; PIMAGE_DEBUG_DIRECTORY pFpoDebugDirectory = NULL; DWORD DebugDirectorySize, DbgFileHeaderSize, NumberOfDebugDirectories; IMAGE_SEPARATE_DEBUG_HEADER DbgFileHeader; PIMAGE_EXPORT_DIRECTORY ExportDirectory; DWORD ExportedNamesSize; LPDWORD pp; LPSTR ExportedNames, Src, Dst; DWORD i, j, RvaOffset, ExportDirectorySize; PFPO_DATA FpoTable; DWORD FpoTableSize; PIMAGE_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable, pSrc; DWORD RuntimeFunctionTableSize; PIMAGE_FUNCTION_ENTRY FunctionTable, pDst; DWORD FunctionTableSize; ULONG NumberOfFunctionTableEntries, DbgOffset; DWORD SavedErrorCode; BOOL InsertExtensionSubDir; LPSTR ImageFilePathToSaveInImage; BOOL MiscInRdata = FALSE; BOOL DiscardFPO = Flags & SPLITSYM_EXTRACT_ALL; BOOL fNewCvData = FALSE; PCHAR NewDebugData = NULL;
ImageFileName = ImageName + strlen( ImageName ); while (ImageFileName > ImageName) { if (ImageFileName[ -1 ] == '\\' || ImageFileName[ -1 ] == '/' || ImageFileName[ -1 ] == ':' ) { break; } else { ImageFileName -= 1; } }
if (SymbolsPath == NULL || SymbolsPath[ 0 ] == '\0' || SymbolsPath[ 0 ] == '.' ) { strncpy( SymbolFilePath, ImageName, ImageFileName - ImageName ); SymbolFilePath[ ImageFileName - ImageName ] = '\0'; InsertExtensionSubDir = FALSE; } else { strcpy( SymbolFilePath, SymbolsPath ); InsertExtensionSubDir = TRUE; }
Dst = SymbolFilePath + strlen( SymbolFilePath ); if ((Dst > SymbolFilePath) && (Dst[-1] != '\\') && (Dst[-1] != '/') && (Dst[-1] != ':') ) { *Dst++ = '\\'; } ImageFilePathToSaveInImage = Dst; Src = strrchr( ImageFileName, '.' ); if (Src != NULL && InsertExtensionSubDir) { while (*Dst = *++Src) { Dst += 1; } *Dst++ = '\\'; }
strcpy( Dst, ImageFileName ); Dst = strrchr( Dst, '.' ); if (Dst == NULL) { Dst = SymbolFilePath + strlen( SymbolFilePath ); } strcpy( Dst, ".dbg" );
// Make sure we can open the .dbg file before we continue...
if (!MakeSureDirectoryPathExists( SymbolFilePath )) return FALSE;
// Now, open and map the input file.
FileHandle = CreateFile( ImageName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if (FileHandle == INVALID_HANDLE_VALUE) { return FALSE; }
hMappedFile = CreateFileMapping( FileHandle, NULL, PAGE_READWRITE, 0, 0, NULL ); if (!hMappedFile) { CloseHandle( FileHandle ); return FALSE; }
ImageBase = MapViewOfFile( hMappedFile, FILE_MAP_WRITE, 0, 0, 0 ); if (!ImageBase) { CloseHandle( hMappedFile ); CloseHandle( FileHandle ); return FALSE; }
//
// Everything is mapped. Now check the image and find nt image headers
//
NtHeaders = ImageNtHeader( ImageBase ); if (NtHeaders == NULL) { UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
if ((NtHeaders->OptionalHeader.MajorLinkerVersion < 3) && (NtHeaders->OptionalHeader.MinorLinkerVersion < 5) ) { UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { // The symbols have already been stripped. No need to continue.
UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile ); CloseHandle( FileHandle ); SetLastError( ERROR_ALREADY_ASSIGNED ); return FALSE; }
DebugDirectories = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( ImageBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugDirectorySize ); if (!DebugDirectoryIsUseful(DebugDirectories, DebugDirectorySize)) { UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
// Try to open the symbol file
SymbolFileHandle = CreateFile( SymbolFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); if (SymbolFileHandle == INVALID_HANDLE_VALUE) goto nosyms;
NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
// The entire file is mapped so we don't have to care if the rva's
// are correct. It is interesting to note if there's a debug section
// we need to whack before terminating, though.
{ PIMAGE_SECTION_HEADER Sections; Sections = IMAGE_FIRST_SECTION( NtHeaders );
for (SectionNumber = 0; SectionNumber < NtHeaders->FileHeader.NumberOfSections; SectionNumber++ ) {
if (Sections[ SectionNumber ].PointerToRawData != 0 && !_stricmp( (char *) Sections[ SectionNumber ].Name, ".debug" )) { DebugSection = &Sections[ SectionNumber ]; } } }
FpoTable = NULL; ExportedNames = NULL; DebugSectionStart = 0xffffffff;
//
// Find the size of the debug section.
//
SizeOfSymbols = 0;
for (i=0,DebugDirectory=DebugDirectories; i<NumberOfDebugDirectories; i++,DebugDirectory++) {
switch (DebugDirectory->Type) { case IMAGE_DEBUG_TYPE_MISC :
// Save it away.
MiscDebugDirectory = *DebugDirectory;
// check to see if the misc debug data is in some other section.
// If Address Of Raw Data is cleared, it must be in .debug (there's no such thing as not-mapped rdata)
// If it's set and there's no debug section, it must be somewhere else.
// If it's set and there's a debug section, check the range.
if ((DebugDirectory->AddressOfRawData != 0) && ((DebugSection == NULL) || (((DebugDirectory->PointerToRawData < DebugSection->PointerToRawData) || (DebugDirectory->PointerToRawData >= DebugSection->PointerToRawData + DebugSection->SizeOfRawData) ) ) ) ) { MiscInRdata = TRUE; } else { if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; } }
break;
case IMAGE_DEBUG_TYPE_FPO: if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// Save it away.
FpoDebugDirectory = *DebugDirectory; pFpoDebugDirectory = DebugDirectory; break;
case IMAGE_DEBUG_TYPE_CODEVIEW: { ULONG NewDebugSize;
if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// If private's are removed, do so and save the new size...
if (Flags & SPLITSYM_REMOVE_PRIVATE) { if (RemovePrivateCvSymbolic(DebugDirectory->PointerToRawData + (PCHAR)ImageBase, &NewDebugData, &NewDebugSize)) { DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase); DebugDirectory->SizeOfData = NewDebugSize; } }
if (DebugDirectory->SizeOfData && DebugDirectory->PointerToRawData) {
// If there's a .pdb, copy it to the same location as the .dbg file.
typedef struct NB10I // NB10 debug info
{ DWORD nb10; // NB10
DWORD off; // offset, always 0
DWORD sig; DWORD age; } NB10I;
NB10I *pNB10Info;
pNB10Info = (NB10I *) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase); if (pNB10Info->nb10 == '01BN') { // Got a PDB. The name immediately follows the signature.
CHAR PdbName[_MAX_PATH]; CHAR NewPdbName[_MAX_PATH]; CHAR Drive[_MAX_DRIVE]; CHAR Dir[_MAX_DIR]; CHAR Filename[_MAX_FNAME]; CHAR FileExt[_MAX_EXT];
memset(PdbName, 0, sizeof(PdbName)); memcpy(PdbName, ((PCHAR)pNB10Info) + sizeof(NB10I), DebugDirectory->SizeOfData - sizeof(NB10I));
_splitpath(PdbName, NULL, NULL, Filename, FileExt); _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL); _makepath(NewPdbName, Drive, Dir, Filename, FileExt);
if ( !CopyFile(PdbName, NewPdbName, FALSE)) { // It's possible the name in the pdb isn't in the same location as it was when built. See if we can
// find it in the same dir as the image...
_splitpath(ImageName, Drive, Dir, NULL, NULL); _makepath(PdbName, Drive, Dir, Filename, FileExt);
CopyFile(PdbName, NewPdbName, FALSE); }
SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
// Change the data so only the pdb name is in the .dbg file (no path).
NewDebugSize = sizeof(NB10I) + strlen(Filename) + strlen(FileExt) + 1;
NewDebugData = (PCHAR) MemAlloc( NewDebugSize ); *(NB10I *)NewDebugData = *pNB10Info; strcpy(NewDebugData + sizeof(NB10I), Filename); strcat(NewDebugData + sizeof(NB10I), FileExt);
DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase); DebugDirectory->SizeOfData = NewDebugSize; } } }
break;
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// W/o the OMAP, FPO is useless.
DiscardFPO = TRUE; break;
case IMAGE_DEBUG_TYPE_FIXUP: if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// If all PRIVATE debug is removed, don't send FIXUP along.
if (Flags & SPLITSYM_REMOVE_PRIVATE) { DebugDirectory->SizeOfData = 0; } break;
default: if (DebugDirectory->PointerToRawData < DebugSectionStart) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// Nothing else to special case...
break; }
SizeOfSymbols += (DebugDirectory->SizeOfData + 3) & ~3; // Minimally align it all.
}
if (DiscardFPO) { pFpoDebugDirectory = NULL; }
if (pFpoDebugDirectory) { // If FPO stays here, make a copy so we don't need to worry about stomping on it.
FpoTableSize = pFpoDebugDirectory->SizeOfData; FpoTable = (PFPO_DATA) MemAlloc( FpoTableSize ); if ( FpoTable == NULL ) { goto nosyms; }
RtlMoveMemory( FpoTable, (PCHAR) ImageBase + pFpoDebugDirectory->PointerToRawData, FpoTableSize ); }
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) ImageDirectoryEntryToData( ImageBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirectorySize ); if (ExportDirectory) { //
// This particular piece of magic gets us the RVA of the
// EXPORT section. Dont ask.
//
RvaOffset = (DWORD) ImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirectorySize ) - (DWORD)ImageBase;
pp = (LPDWORD)((DWORD)ExportDirectory + (DWORD)ExportDirectory->AddressOfNames - RvaOffset );
ExportedNamesSize = 1; for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((DWORD)ExportDirectory + *pp++ - RvaOffset); ExportedNamesSize += strlen( Src ) + 1; } ExportedNamesSize = (ExportedNamesSize + 16) & ~15;
Dst = (LPSTR) MemAlloc( ExportedNamesSize ); if (Dst != NULL) { ExportedNames = Dst; pp = (LPDWORD)((DWORD)ExportDirectory + (DWORD)ExportDirectory->AddressOfNames - RvaOffset ); for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((DWORD)ExportDirectory + *pp++ - RvaOffset); while (*Dst++ = *Src++) { } } } } else { ExportedNamesSize = 0; }
RuntimeFunctionTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY) ImageDirectoryEntryToData( ImageBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &RuntimeFunctionTableSize ); if (RuntimeFunctionTable == NULL) { RuntimeFunctionTableSize = 0; FunctionTableSize = 0; FunctionTable = NULL; } else { NumberOfFunctionTableEntries = RuntimeFunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); FunctionTableSize = NumberOfFunctionTableEntries * sizeof( IMAGE_FUNCTION_ENTRY ); FunctionTable = (PIMAGE_FUNCTION_ENTRY) MemAlloc( FunctionTableSize ); if (FunctionTable == NULL) { goto nosyms; }
pSrc = RuntimeFunctionTable; pDst = FunctionTable; for (i=0; i<NumberOfFunctionTableEntries; i++) { //
// Make .pdata entries in .DBG file relative.
//
pDst->StartingAddress = pSrc->BeginAddress - NtHeaders->OptionalHeader.ImageBase; pDst->EndingAddress = pSrc->EndAddress - NtHeaders->OptionalHeader.ImageBase; pDst->EndOfPrologue = pSrc->PrologEndAddress - NtHeaders->OptionalHeader.ImageBase; pSrc += 1; pDst += 1; } }
DbgFileHeaderSize = sizeof( DbgFileHeader ) + ((NtHeaders->FileHeader.NumberOfSections - (DebugSection ? 1 : 0)) * sizeof( IMAGE_SECTION_HEADER )) + ExportedNamesSize + FunctionTableSize + DebugDirectorySize;
if (FunctionTable != NULL) { DbgFileHeaderSize += sizeof( IMAGE_DEBUG_DIRECTORY ); memset( &FunctionTableDir, 0, sizeof( IMAGE_DEBUG_DIRECTORY ) ); FunctionTableDir.Type = IMAGE_DEBUG_TYPE_EXCEPTION; FunctionTableDir.SizeOfData = FunctionTableSize; FunctionTableDir.PointerToRawData = DbgFileHeaderSize - FunctionTableSize; }
DbgFileHeaderSize = ((DbgFileHeaderSize + 15) & ~15);
BytesWritten = 0;
if (SetFilePointer( SymbolFileHandle, DbgFileHeaderSize, NULL, FILE_BEGIN ) == DbgFileHeaderSize ) {
for (i=0, DebugDirectory=DebugDirectories; i < NumberOfDebugDirectories; i++, DebugDirectory++) {
DWORD WriteCount;
if (DebugDirectory->SizeOfData) { WriteFile( SymbolFileHandle, (PCHAR) ImageBase + DebugDirectory->PointerToRawData, (DebugDirectory->SizeOfData +3) & ~3, &WriteCount, NULL );
BytesWritten += WriteCount; } } }
if (BytesWritten == SizeOfSymbols) { NtHeaders->FileHeader.PointerToSymbolTable = 0; NtHeaders->FileHeader.Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
if (DebugSection != NULL) { NtHeaders->OptionalHeader.SizeOfImage = DebugSection->VirtualAddress; NtHeaders->OptionalHeader.SizeOfInitializedData -= DebugSection->SizeOfRawData; NtHeaders->FileHeader.NumberOfSections--; // NULL out that section
memset(DebugSection, 0, IMAGE_SIZEOF_SECTION_HEADER); }
NewFileSize = DebugSectionStart; // Start with no symbolic
//
// Now that the data has moved to the .dbg file, rebuild the original
// with MISC debug first and FPO second.
//
if (MiscDebugDirectory.SizeOfData) { if (MiscInRdata) { // Just store the new name in the existing misc field...
ImageNameOffset = (DWORD) ((PCHAR)ImageBase + MiscDebugDirectory.PointerToRawData + FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
RtlCopyMemory( (LPVOID) ImageNameOffset, ImageFilePathToSaveInImage, strlen(ImageFilePathToSaveInImage) + 1 ); } else { if (DebugSectionStart != MiscDebugDirectory.PointerToRawData) { RtlMoveMemory((PCHAR) ImageBase + DebugSectionStart, (PCHAR) ImageBase + MiscDebugDirectory.PointerToRawData, MiscDebugDirectory.SizeOfData); }
ImageNameOffset = (DWORD) ((PCHAR)ImageBase + DebugSectionStart + FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
RtlCopyMemory( (LPVOID)ImageNameOffset, ImageFilePathToSaveInImage, strlen(ImageFilePathToSaveInImage) + 1 );
NewFileSize += MiscDebugDirectory.SizeOfData; NewFileSize = (NewFileSize + 3) & ~3; } }
if (FpoTable) { RtlCopyMemory( (PCHAR) ImageBase + NewFileSize, FpoTable, FpoTableSize );
NewFileSize += FpoTableSize; NewFileSize = (NewFileSize + 3) & ~3; }
// Make a copy of the Debug directory that we can write into the .dbg file
DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) MemAlloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) );
RtlMoveMemory(DbgDebugDirectories, DebugDirectories, sizeof(IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories);
// Then write the MISC and (perhaps) FPO data to the image.
FpoDebugDirectory.PointerToRawData = DebugSectionStart; DebugDirectorySize = 0;
if (MiscDebugDirectory.SizeOfData != 0) { if (!MiscInRdata) { MiscDebugDirectory.PointerToRawData = DebugSectionStart; FpoDebugDirectory.PointerToRawData += MiscDebugDirectory.SizeOfData; MiscDebugDirectory.AddressOfRawData = 0; }
DebugDirectories[0] = MiscDebugDirectory; DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY); }
if (pFpoDebugDirectory) { FpoDebugDirectory.AddressOfRawData = 0; DebugDirectories[1] = FpoDebugDirectory; DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY); }
NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = DebugDirectorySize;
DbgOffset = DbgFileHeaderSize;
for (i = 0, j=0, DebugDirectory=DbgDebugDirectories; i < NumberOfDebugDirectories; i++) {
if (DebugDirectory[i].SizeOfData) { DebugDirectory[j] = DebugDirectory[i];
DebugDirectory[j].AddressOfRawData = 0; DebugDirectory[j].PointerToRawData = DbgOffset;
DbgOffset += (DebugDirectory[j].SizeOfData + 3 )& ~3; j++; } }
if (FunctionTable) { FunctionTableDir.PointerToRawData -= sizeof(IMAGE_DEBUG_DIRECTORY) * (NumberOfDebugDirectories - j); } NumberOfDebugDirectories = j;
CheckSumMappedFile( ImageBase, NewFileSize, &HeaderSum, &CheckSum ); NtHeaders->OptionalHeader.CheckSum = CheckSum;
DbgFileHeader.Signature = IMAGE_SEPARATE_DEBUG_SIGNATURE; DbgFileHeader.Flags = 0; DbgFileHeader.Machine = NtHeaders->FileHeader.Machine; DbgFileHeader.Characteristics = NtHeaders->FileHeader.Characteristics; DbgFileHeader.TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp; DbgFileHeader.CheckSum = CheckSum; DbgFileHeader.ImageBase = NtHeaders->OptionalHeader.ImageBase; DbgFileHeader.SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage; DbgFileHeader.ExportedNamesSize = ExportedNamesSize; DbgFileHeader.DebugDirectorySize = NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY); if (FunctionTable) { DbgFileHeader.DebugDirectorySize += sizeof (IMAGE_DEBUG_DIRECTORY); } DbgFileHeader.NumberOfSections = NtHeaders->FileHeader.NumberOfSections; memset( DbgFileHeader.Reserved, 0, sizeof( DbgFileHeader.Reserved ) ); DbgFileHeader.SectionAlignment = NtHeaders->OptionalHeader.SectionAlignment;
SetFilePointer( SymbolFileHandle, 0, NULL, FILE_BEGIN ); WriteFile( SymbolFileHandle, &DbgFileHeader, sizeof( DbgFileHeader ), &BytesWritten, NULL ); WriteFile( SymbolFileHandle, IMAGE_FIRST_SECTION( NtHeaders ), sizeof( IMAGE_SECTION_HEADER ) * NtHeaders->FileHeader.NumberOfSections, &BytesWritten, NULL );
if (ExportedNamesSize) { WriteFile( SymbolFileHandle, ExportedNames, ExportedNamesSize, &BytesWritten, NULL ); }
WriteFile( SymbolFileHandle, DbgDebugDirectories, sizeof (IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories, &BytesWritten, NULL );
if (FunctionTable) { WriteFile( SymbolFileHandle, &FunctionTableDir, sizeof (IMAGE_DEBUG_DIRECTORY), &BytesWritten, NULL );
WriteFile( SymbolFileHandle, FunctionTable, FunctionTableSize, &BytesWritten, NULL ); }
SetFilePointer( SymbolFileHandle, 0, NULL, FILE_END ); CloseHandle( SymbolFileHandle );
FlushViewOfFile( ImageBase, NewFileSize ); UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile );
SetFilePointer( FileHandle, NewFileSize, NULL, FILE_BEGIN ); SetEndOfFile( FileHandle );
TouchFileTimes( FileHandle, NULL ); CloseHandle( FileHandle );
if (ExportedNames != NULL) { MemFree( ExportedNames ); }
if (FpoTable != NULL) { MemFree( FpoTable ); }
if (FunctionTable != NULL) { MemFree( FunctionTable ); }
if (NewDebugData) { MemFree(NewDebugData); }
if (DbgDebugDirectories) { MemFree(DbgDebugDirectories); }
return TRUE;
} else { CloseHandle( SymbolFileHandle ); DeleteFile( SymbolFilePath ); }
nosyms: SavedErrorCode = GetLastError(); if (ExportedNames != NULL) { MemFree( ExportedNames ); }
if (FpoTable != NULL) { MemFree( FpoTable ); }
if (FunctionTable != NULL) { MemFree( FunctionTable ); }
UnmapViewOfFile( ImageBase ); CloseHandle( hMappedFile ); CloseHandle( FileHandle ); SetLastError( SavedErrorCode ); return FALSE; }
BOOL SearchTreeForFile( LPSTR RootPath, PCHAR InputPathName, PCHAR OutputPathBuffer );
HANDLE FindExecutableImage( LPSTR FileName, LPSTR SymbolPath, LPSTR ImageFilePath );
BOOL GetImageNameFromMiscDebugData( HANDLE FileHandle, PVOID MappedBase, PIMAGE_NT_HEADERS NtHeaders, PIMAGE_DEBUG_DIRECTORY DebugDirectories, ULONG NumberOfDebugDirectories, LPSTR ImageFilePath );
#define AddToDebugInfoSize(x) (DebugInfoSize += (((x + 7) & ~7)+4)) // Make sure all the con's start at a qword boundary
#define AdvanceNext(x) (Next = (PVOID)((((ULONG)Next + x) + 7) & ~7))
void ProcessDbgFile( PIMAGE_DEBUG_INFORMATION DebugInfo, PIMAGE_SEPARATE_DEBUG_HEADER DebugFileHeader, ULONG ImageBase, ULONG FunctionTableSize, ULONG DebugInfoHeaderSize ) { PVOID MappedBase, Next; PIMAGE_DEBUG_DIRECTORY DebugDirectory; ULONG i, j; ULONG NumberOfDebugDirectories; LONG BaseOffset; PIMAGE_FUNCTION_ENTRY FunctionTable;
//
// .DBG file processing
//
DebugInfo->Machine = DebugFileHeader->Machine; DebugInfo->Characteristics = DebugFileHeader->Characteristics; DebugInfo->TimeDateStamp = DebugFileHeader->TimeDateStamp; DebugInfo->CheckSum = DebugFileHeader->CheckSum; DebugInfo->ImageBase = DebugFileHeader->ImageBase; DebugInfo->SizeOfImage = DebugFileHeader->SizeOfImage; DebugInfo->NumberOfSections = DebugFileHeader->NumberOfSections; DebugInfo->Sections = (PIMAGE_SECTION_HEADER)(DebugFileHeader + 1); Next = (PVOID)(DebugInfo->Sections + DebugInfo->NumberOfSections);
DebugInfo->ExportedNamesSize = DebugFileHeader->ExportedNamesSize; if (DebugInfo->ExportedNamesSize) { DebugInfo->ExportedNames = (LPSTR)Next; Next = (PVOID)((PCHAR)Next + DebugInfo->ExportedNamesSize); }
DebugDirectory = DebugInfo->DebugDirectory; MappedBase = DebugInfo->MappedBase; NumberOfDebugDirectories = DebugFileHeader->DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY ); Next = (PVOID)((PCHAR)Next + DebugFileHeader->DebugDirectorySize);
for (i=0; i<NumberOfDebugDirectories; i++) { switch (DebugDirectory->Type) { case IMAGE_DEBUG_TYPE_EXCEPTION: DebugInfo->FunctionTableEntries = (PIMAGE_FUNCTION_ENTRY) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData);
BaseOffset = ImageBase ? ImageBase : DebugInfo->ImageBase; FunctionTable = (PIMAGE_FUNCTION_ENTRY)((ULONG)DebugInfo + DebugInfoHeaderSize); memmove( FunctionTable, DebugInfo->FunctionTableEntries, FunctionTableSize );
DebugInfo->FunctionTableEntries = FunctionTable; DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF; DebugInfo->HighestFunctionEndingAddress = 0;
for (j=0; j<DebugInfo->NumberOfFunctionTableEntries; j++) { FunctionTable->StartingAddress += BaseOffset; if (FunctionTable->StartingAddress < DebugInfo->LowestFunctionStartingAddress) { DebugInfo->LowestFunctionStartingAddress = FunctionTable->StartingAddress; }
FunctionTable->EndingAddress += BaseOffset; if (FunctionTable->EndingAddress > DebugInfo->HighestFunctionEndingAddress) { DebugInfo->HighestFunctionEndingAddress = FunctionTable->EndingAddress; }
FunctionTable->EndOfPrologue += BaseOffset; FunctionTable += 1; } break;
case IMAGE_DEBUG_TYPE_FPO: DebugInfo->NumberOfFpoTableEntries = DebugDirectory->SizeOfData / sizeof( FPO_DATA ); DebugInfo->FpoTableEntries = (PFPO_DATA) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData); break;
case IMAGE_DEBUG_TYPE_COFF: DebugInfo->SizeOfCoffSymbols = DebugDirectory->SizeOfData; DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData); break;
case IMAGE_DEBUG_TYPE_CODEVIEW: DebugInfo->SizeOfCodeViewSymbols = DebugDirectory->SizeOfData; DebugInfo->CodeViewSymbols = (PVOID) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData); break; }
DebugDirectory++; } }
PIMAGE_DEBUG_INFORMATION MapDebugInformation( HANDLE FileHandle, LPSTR FileName, LPSTR SymbolPath, ULONG ImageBase ) { ULONG NumberOfHandlesToClose; HANDLE HandlesToClose[ 4 ]; HANDLE MappingHandle; PVOID MappedBase, Next; BOOL SeparateSymbols; UCHAR ImageFilePath[ MAX_PATH ]; UCHAR DebugFilePath[ MAX_PATH ]; PIMAGE_DEBUG_INFORMATION DebugInfo; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DEBUG_DIRECTORY DebugDirectories; PIMAGE_DEBUG_DIRECTORY DebugDirectory; PIMAGE_SEPARATE_DEBUG_HEADER DebugFileHeader; PIMAGE_EXPORT_DIRECTORY ExportDirectory; PIMAGE_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable; PIMAGE_FUNCTION_ENTRY FunctionTable; ULONG NumberOfFunctionTableEntries, FunctionTableSize; PVOID DebugData; LPSTR Src, Dst; PULONG pp; ULONG RvaOffset; ULONG i, j; ULONG ExportedNamesSize; ULONG DebugInfoHeaderSize; ULONG DebugInfoSize = 0; ULONG Size; ULONG NumberOfDebugDirectories; LONG BaseOffset; HANDLE SavedImageFileHandle; BOOL RomImage = FALSE; PIMAGE_ROM_HEADERS RomHeader; ULONG FallbackChecksum; ULONG FallbackNumberOfSections; ULONG FallbackSectionSize; PIMAGE_SECTION_HEADER FallbackSections = NULL;
if (FileHandle == NULL && (FileName == NULL || FileName[ 0 ] == '\0')) { return NULL; }
DebugInfo = NULL; NumberOfHandlesToClose = 0; MappedBase = NULL; SeparateSymbols = FALSE; SavedImageFileHandle = NULL; if (FileName) { strcpy(ImageFilePath, FileName); } else { ImageFilePath[0] = '\0'; } NumberOfFunctionTableEntries = 0; FunctionTableSize = 0; FunctionTable = NULL; __try { __try { if (FileHandle == NULL) { FileHandle = FindExecutableImage( FileName, SymbolPath, (PCHAR) ImageFilePath ); if (FileHandle == NULL) { strcpy( (PCHAR) ImageFilePath, FileName ); getDebugFile: FileHandle = FindDebugInfoFile( FileName, SymbolPath, (PCHAR) DebugFilePath ); if (FileHandle == NULL) { if (SavedImageFileHandle != NULL) { FileHandle = SavedImageFileHandle; goto noDebugFile; } else { __leave; } } else { SeparateSymbols = TRUE; } } else { SavedImageFileHandle = FileHandle; }
HandlesToClose[ NumberOfHandlesToClose++ ] = FileHandle; } else { SavedImageFileHandle = FileHandle; }
//
// map image file and process enough to get the image name and capture
// stuff from header.
//
MappingHandle = CreateFileMapping( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); if (MappingHandle == NULL) { __leave; } HandlesToClose[ NumberOfHandlesToClose++ ] = MappingHandle;
MappedBase = MapViewOfFile( MappingHandle, FILE_MAP_READ, 0, 0, 0 ); if (MappedBase == NULL) { __leave; }
AddToDebugInfoSize((sizeof( *DebugInfo ) + strlen( (PCHAR) ImageFilePath ) + 1)); if (SeparateSymbols) { AddToDebugInfoSize((strlen( (PCHAR) DebugFilePath ) + 1)); }
if (!SeparateSymbols) { NtHeaders = ImageNtHeader( MappedBase ); if (NtHeaders == NULL) { if (((PIMAGE_FILE_HEADER)MappedBase)->SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) { //
// rom image
//
RomImage = TRUE; RomHeader = (PIMAGE_ROM_HEADERS) MappedBase; } else { __leave; } }
DebugDirectories = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( MappedBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &Size ); if (DebugDirectoryIsUseful(DebugDirectories, Size)) { NumberOfDebugDirectories = Size / sizeof( IMAGE_DEBUG_DIRECTORY ); } else { NumberOfDebugDirectories = 0; DebugDirectories = NULL; }
if (FileName == NULL && NtHeaders && GetImageNameFromMiscDebugData( FileHandle, MappedBase, NtHeaders, DebugDirectories, NumberOfDebugDirectories, (PCHAR) ImageFilePath ) ) { FileName = (PCHAR) ImageFilePath; AddToDebugInfoSize( strlen((PCHAR) ImageFilePath )); }
DebugInfoHeaderSize = DebugInfoSize;
FallbackChecksum = NtHeaders->OptionalHeader.CheckSum; if (RomImage) { FallbackNumberOfSections = RomHeader->FileHeader.NumberOfSections; FallbackSectionSize = FallbackNumberOfSections * sizeof(IMAGE_SECTION_HEADER); FallbackSections = (PIMAGE_SECTION_HEADER)MemAlloc( FallbackSectionSize ); if (!FallbackSections) { leave; } RtlCopyMemory(FallbackSections, (PVOID)((ULONG)MappedBase + IMAGE_SIZEOF_ROM_OPTIONAL_HEADER + IMAGE_SIZEOF_FILE_HEADER ), FallbackSectionSize); } else { FallbackNumberOfSections = NtHeaders->FileHeader.NumberOfSections; FallbackSectionSize = FallbackNumberOfSections * sizeof(IMAGE_SECTION_HEADER); FallbackSections = (PIMAGE_SECTION_HEADER)MemAlloc( FallbackSectionSize ); if (!FallbackSections) { leave; } RtlCopyMemory(FallbackSections, (PVOID)IMAGE_FIRST_SECTION( NtHeaders ), FallbackSectionSize); }
if (!RomImage && NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { goto getDebugFile; } if (NumberOfDebugDirectories == 0) { goto getDebugFile; }
noDebugFile: ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) ImageDirectoryEntryToData( MappedBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size ); if (ExportDirectory) { //
// This particular piece of magic gets us the RVA of the
// EXPORT section. Dont ask.
//
RvaOffset = (ULONG) ImageDirectoryEntryToData( MappedBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size ) - (DWORD)MappedBase;
pp = (PULONG)((ULONG)ExportDirectory + (ULONG)ExportDirectory->AddressOfNames - RvaOffset );
ExportedNamesSize = 1; for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((ULONG)ExportDirectory + *pp++ - RvaOffset); ExportedNamesSize += strlen( Src ) + 1; } ExportedNamesSize = (ExportedNamesSize + 16) & ~15; AddToDebugInfoSize(ExportedNamesSize); } else { ExportedNamesSize = 0; }
RuntimeFunctionTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY) ImageDirectoryEntryToData( MappedBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &Size ); if (RuntimeFunctionTable != NULL) { NumberOfFunctionTableEntries = Size / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY ); FunctionTableSize = NumberOfFunctionTableEntries * sizeof( IMAGE_FUNCTION_ENTRY );
AddToDebugInfoSize(FunctionTableSize); }
if (NumberOfDebugDirectories != 0) { DebugDirectory = DebugDirectories; for (i=0; i<NumberOfDebugDirectories; i++) { if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO || DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF || DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW ) { AddToDebugInfoSize(DebugDirectory->SizeOfData); }
DebugDirectory += 1; } } } else { DebugFileHeader = (PIMAGE_SEPARATE_DEBUG_HEADER)MappedBase; if (DebugFileHeader->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) { //
// Yes, .DBG file information
//
Next = (PVOID)((PIMAGE_SECTION_HEADER)(DebugFileHeader + 1) + DebugFileHeader->NumberOfSections); if (DebugFileHeader->ExportedNamesSize != 0) { Next = (PVOID)((PCHAR)Next + DebugFileHeader->ExportedNamesSize); } DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)Next; DebugDirectory = DebugDirectories; NumberOfDebugDirectories = DebugFileHeader->DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
for (i=0; i<NumberOfDebugDirectories; i++) { if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_EXCEPTION) { FunctionTableSize = DebugDirectory->SizeOfData; NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_FUNCTION_ENTRY ); break; }
DebugDirectory += 1; }
DebugInfoHeaderSize = DebugInfoSize; AddToDebugInfoSize(FunctionTableSize); } else { //
// No, some other sort of debug information
//
DebugFileHeader = NULL; DebugDirectories = NULL; DebugDirectory = NULL; NumberOfDebugDirectories = 0; //
// We need the fallback section info (add to size and remeber where
// to store our stuff relative to the rest of the info).
//
DebugInfoHeaderSize = DebugInfoSize; AddToDebugInfoSize( FallbackSectionSize );
} }
DebugInfo = (PIMAGE_DEBUG_INFORMATION) MemAlloc( DebugInfoSize ); if (DebugInfo == NULL) { __leave; }
InitializeListHead( &DebugInfo->List ); DebugInfo->Size = DebugInfoSize; DebugInfo->ImageFilePath = (LPSTR)(DebugInfo + 1); strcpy( DebugInfo->ImageFilePath, (PCHAR) ImageFilePath ); Src = strchr( DebugInfo->ImageFilePath, '\0' ); while (Src > DebugInfo->ImageFilePath) { if (Src[ -1 ] == '\\' || Src[ -1 ] == '/' || Src[ -1 ] == ':') { break; } else { Src -= 1; } } DebugInfo->ImageFileName = Src; DebugInfo->DebugFilePath = DebugInfo->ImageFilePath; if (SeparateSymbols) { DebugInfo->DebugFilePath += strlen( DebugInfo->ImageFilePath ) + 1; strcpy( DebugInfo->DebugFilePath, (PCHAR) DebugFilePath ); }
DebugInfo->MappedBase = MappedBase; DebugInfo->DebugDirectory = DebugDirectories; DebugInfo->NumberOfDebugDirectories = NumberOfDebugDirectories; DebugInfo->NumberOfFunctionTableEntries = NumberOfFunctionTableEntries;
if (SeparateSymbols) { if (DebugFileHeader) { ProcessDbgFile(DebugInfo, DebugFileHeader, ImageBase, FunctionTableSize, DebugInfoHeaderSize);
} else { //
// Some other kind of file processing
//
DebugInfo->Machine = 0; DebugInfo->Characteristics = 0; DebugInfo->TimeDateStamp = 0; DebugInfo->CheckSum = FallbackChecksum; DebugInfo->ImageBase = 0; DebugInfo->SizeOfImage = 0; DebugInfo->NumberOfSections = FallbackNumberOfSections; DebugInfo->Sections = (PIMAGE_SECTION_HEADER)((ULONG)DebugInfo + DebugInfoHeaderSize); memmove( DebugInfo->Sections, FallbackSections, FallbackSectionSize );
DebugInfo->ExportedNamesSize = 0; DebugInfo->ExportedNames = NULL; DebugInfo->NumberOfFunctionTableEntries = 0; DebugInfo->FunctionTableEntries = NULL; DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF; DebugInfo->HighestFunctionEndingAddress = 0; DebugInfo->NumberOfFpoTableEntries = 0; DebugInfo->FpoTableEntries = NULL; DebugInfo->SizeOfCoffSymbols = 0; DebugInfo->CoffSymbols = NULL; DebugInfo->SizeOfCodeViewSymbols = 0; DebugInfo->CodeViewSymbols = NULL; } } else { if (RomImage) { DebugInfo->Machine = RomHeader->FileHeader.Machine; DebugInfo->Characteristics = RomHeader->FileHeader.Characteristics; DebugInfo->TimeDateStamp = RomHeader->FileHeader.TimeDateStamp; DebugInfo->NumberOfSections = RomHeader->FileHeader.NumberOfSections; DebugInfo->CheckSum = 0; DebugInfo->ImageBase = RomHeader->OptionalHeader.BaseOfCode; DebugInfo->SizeOfImage = RomHeader->OptionalHeader.SizeOfCode; DebugInfo->Sections = (PIMAGE_SECTION_HEADER) ((ULONG)MappedBase + IMAGE_SIZEOF_ROM_OPTIONAL_HEADER + IMAGE_SIZEOF_FILE_HEADER ); } else { DebugInfo->Machine = NtHeaders->FileHeader.Machine; DebugInfo->Characteristics = NtHeaders->FileHeader.Characteristics; DebugInfo->TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp; DebugInfo->CheckSum = NtHeaders->OptionalHeader.CheckSum; DebugInfo->ImageBase = NtHeaders->OptionalHeader.ImageBase; DebugInfo->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage; DebugInfo->NumberOfSections = NtHeaders->FileHeader.NumberOfSections; DebugInfo->Sections = IMAGE_FIRST_SECTION( NtHeaders ); } Next = (PVOID)((ULONG)DebugInfo + DebugInfoHeaderSize);
DebugInfo->ExportedNamesSize = ExportedNamesSize; if (DebugInfo->ExportedNamesSize) { DebugInfo->ExportedNames = (LPSTR)Next; AdvanceNext(ExportedNamesSize);
pp = (PULONG)((ULONG)ExportDirectory + (ULONG)ExportDirectory->AddressOfNames - RvaOffset );
Dst = DebugInfo->ExportedNames; for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((ULONG)ExportDirectory + *pp++ - RvaOffset); while (*Dst++ = *Src++) ; } }
if (RuntimeFunctionTable != NULL) { BaseOffset = ImageBase ? ImageBase - DebugInfo->ImageBase : 0; DebugInfo->FunctionTableEntries = (PIMAGE_FUNCTION_ENTRY)Next; DebugInfo->NumberOfFunctionTableEntries = NumberOfFunctionTableEntries; AdvanceNext(FunctionTableSize);
DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF; DebugInfo->HighestFunctionEndingAddress = 0; FunctionTable = DebugInfo->FunctionTableEntries; for (i=0; i<NumberOfFunctionTableEntries; i++) { FunctionTable->StartingAddress = RuntimeFunctionTable->BeginAddress + BaseOffset; if (FunctionTable->StartingAddress < DebugInfo->LowestFunctionStartingAddress) { DebugInfo->LowestFunctionStartingAddress = FunctionTable->StartingAddress; }
FunctionTable->EndingAddress = RuntimeFunctionTable->EndAddress + BaseOffset; if (FunctionTable->EndingAddress > DebugInfo->HighestFunctionEndingAddress) { DebugInfo->HighestFunctionEndingAddress = FunctionTable->EndingAddress; }
FunctionTable->EndOfPrologue = RuntimeFunctionTable->PrologEndAddress + BaseOffset; RuntimeFunctionTable += 1; FunctionTable += 1; } }
DebugDirectory = DebugDirectories; if (RomImage) { if (RomHeader->FileHeader.NumberOfSymbols) {
DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER) ((ULONG)MappedBase + RomHeader->FileHeader.PointerToSymbolTable - sizeof(IMAGE_COFF_SYMBOLS_HEADER));
DebugInfo->SizeOfCoffSymbols = RomHeader->FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL;
DebugInfo->SizeOfCoffSymbols += *(ULONG UNALIGNED *)((ULONG)DebugInfo->CoffSymbols + DebugInfo->SizeOfCoffSymbols); } } else {
for (i=0; i<NumberOfDebugDirectories; i++) { if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO || (((DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) || (DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF)) && !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) ) ) { DebugData = NULL; if (DebugDirectory->AddressOfRawData == 0) { if (SetFilePointer( FileHandle, DebugDirectory->PointerToRawData, NULL, FILE_BEGIN ) == DebugDirectory->PointerToRawData ) { if (ReadFile( FileHandle, Next, DebugDirectory->SizeOfData, &Size, NULL ) && DebugDirectory->SizeOfData == Size ) { DebugData = Next; AdvanceNext(Size); } } } else { DebugData = (LPSTR)MappedBase + DebugDirectory->PointerToRawData; Size = DebugDirectory->SizeOfData; }
if (DebugData != NULL) { if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO) { DebugInfo->FpoTableEntries = (PFPO_DATA) DebugData; DebugInfo->NumberOfFpoTableEntries = Size / sizeof( FPO_DATA ); } else if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF) { DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER) DebugData; DebugInfo->SizeOfCoffSymbols = Size; } else if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) { DebugInfo->CodeViewSymbols = (PVOID) DebugData; DebugInfo->SizeOfCodeViewSymbols = Size; } } }
DebugDirectory += 1; } } } } __except( EXCEPTION_EXECUTE_HANDLER ) { if (DebugInfo != NULL) { MemFree( DebugInfo ); DebugInfo = NULL; } } } __finally { if (FallbackSections) { MemFree(FallbackSections); }
if (DebugInfo == NULL) { if (MappedBase != NULL) { UnmapViewOfFile( MappedBase ); } }
while (NumberOfHandlesToClose--) { CloseHandle( HandlesToClose[ NumberOfHandlesToClose ] ); } }
if (DebugInfo) { DebugInfo->RomImage = RomImage; }
return DebugInfo; }
BOOL UnmapDebugInformation( PIMAGE_DEBUG_INFORMATION DebugInfo ) { if (DebugInfo != NULL) { __try { UnmapViewOfFile( DebugInfo->MappedBase ); memset( DebugInfo, 0, sizeof( *DebugInfo ) ); MemFree( DebugInfo ); } __except( EXCEPTION_EXECUTE_HANDLER ) { return FALSE; } }
return TRUE; }
LPSTR ExpandPath( LPSTR lpPath ) { LPSTR p = lpPath; LPSTR newpath = (LPSTR) MemAlloc( (lpPath? strlen(lpPath): 0) + MAX_PATH ); LPSTR p1; LPSTR p2 = newpath; CHAR envvar[MAX_PATH]; CHAR envstr[MAX_PATH]; ULONG i;
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++; } } *p2++ = *p++; } *p2 = '\0';
return newpath; }
HANDLE FindExecutableImage( LPSTR FileName, LPSTR SymbolPath, LPSTR ImageFilePath ) { LPSTR Start, End; HANDLE FileHandle; UCHAR DirectoryPath[ MAX_PATH ]; LPSTR NewSymbolPath = ExpandPath(SymbolPath);
if (GetFullPathName( FileName, MAX_PATH, ImageFilePath, &Start )) { FileHandle = CreateFile( ImageFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (FileHandle != INVALID_HANDLE_VALUE) { MemFree( NewSymbolPath ); return FileHandle; } }
Start = NewSymbolPath; while (Start && *Start != '\0') { if (End = strchr( Start, ';' )) { strncpy( (PCHAR) DirectoryPath, Start, End - Start ); DirectoryPath[ End - Start ] = '\0'; End += 1; } else { strcpy( (PCHAR) DirectoryPath, Start ); }
if (SearchTreeForFile( (PCHAR) DirectoryPath, FileName, ImageFilePath )) { FileHandle = CreateFile( ImageFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (FileHandle != INVALID_HANDLE_VALUE) { MemFree( NewSymbolPath ); return FileHandle; } }
Start = End; }
MemFree( NewSymbolPath ); return NULL; }
HANDLE FindDebugInfoFile( LPSTR FileName, LPSTR SymbolPath, LPSTR DebugFilePath ) { HANDLE FileHandle; LPSTR s; LPSTR Start, End; UCHAR BaseName[ MAX_PATH ]; DWORD n; LPSTR NewSymbolPath = ExpandPath(SymbolPath); BOOL UseSymbolsDir = TRUE; LPSTR pExt = NULL;
if (!(s = strrchr( FileName, '.' )) || _stricmp( s, ".dbg" )) { if (s != NULL) { strcpy( (PCHAR) BaseName, s+1 ); strcat( (PCHAR) BaseName, "\\" ); } else { BaseName[ 0 ] = '\0'; }
s = FileName + strlen( FileName ); while (s > FileName) { if (*--s == '\\' || *s == '/' || *s == ':') { s += 1; break; } } strcat( (PCHAR) BaseName, s ); if (!(s = strrchr( (PCHAR) BaseName, '.' ))) { s = strchr( (PCHAR) BaseName, '\0' ); } strcpy( s, ".dbg" ); pExt = s; } else { strcpy( (PCHAR) BaseName, FileName ); }
try_again: Start = NewSymbolPath; while (Start && *Start != '\0') { if (End = strchr( Start, ';' )) { *End = '\0'; }
n = GetFullPathName( Start, MAX_PATH, DebugFilePath, &s ); if (End) { *End++ = ';'; } Start = End; if (n == 0) { continue; }
if (UseSymbolsDir) { if (s != NULL && !_stricmp( s, "Symbols" )) { strcat( DebugFilePath, "\\" ); } else { strcat( DebugFilePath, "\\Symbols\\" ); } } else { strcat( DebugFilePath, "\\" ); }
strcat( DebugFilePath, (PCHAR) BaseName );
FileHandle = CreateFile( DebugFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (FileHandle != INVALID_HANDLE_VALUE) { MemFree( NewSymbolPath ); return FileHandle; } }
if (pExt) { if (_stricmp(pExt,".dbg") == 0) { //
// Now Try again with .SYM
//
strcpy(pExt, ".sym"); goto try_again; }
if (_stricmp(pExt,".sym") == 0) { strcpy(pExt, ".dbg"); // Restore to pre-sym searching state
} }
if (UseSymbolsDir) { //
// this code allows the symbol file to be
// located when the symbols are placed into
// a flat directory.
//
UseSymbolsDir = FALSE; s = strrchr( (char *) BaseName, '\\' ); if (s) { strcpy( (char *) BaseName, s+1 ); } if (!(s = strrchr( (PCHAR) BaseName, '.' ))) { s = strchr( (PCHAR) BaseName, '\0' ); } pExt = s; goto try_again; }
MemFree( NewSymbolPath ); return NULL; }
BOOL GetImageNameFromMiscDebugData( IN HANDLE FileHandle, IN PVOID MappedBase, IN PIMAGE_NT_HEADERS 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;
while (NumberOfDebugDirectories) { if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) { break; } else { DebugDirectories += 1; NumberOfDebugDirectories -= 1; } }
if (NumberOfDebugDirectories == 0) { return FALSE; }
if ((NtHeaders->OptionalHeader.MajorLinkerVersion < 3) && (NtHeaders->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 SearchTreeForFile( LPSTR RootPath, LPSTR InputPathName, LPSTR OutputPathBuffer ) { 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;
strcpy( PathBuffer, RootPath ); FileName = InputPathName; while (*InputPathName) { if (*InputPathName == ':' || *InputPathName == '\\' || *InputPathName == '/') { FileName = ++InputPathName; } else { InputPathName++; } } FindFileData = (LPWIN32_FIND_DATA)FindFileBuffer; Depth = 0; Result = FALSE; while (TRUE) { startDirectorySearch: PathTail[ Depth ] = strchr( PathBuffer, '\0' ); if (PathTail[ Depth ] > PathBuffer && PathTail[ Depth ][ -1 ] != '\\') { *(PathTail[ Depth ])++ = '\\'; }
strcpy( PathTail[ Depth ], "*.*" ); FindHandle[ Depth ] = (PCHAR) FindFirstFile( PathBuffer, FindFileData );
if (FindHandle[ Depth ] == INVALID_HANDLE_VALUE) { return FALSE; }
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 ); Result = TRUE; }
restartDirectorySearch: if (Result) { break; } } while (FindNextFile( FindHandle[ Depth ], FindFileData )); FindClose( FindHandle[ Depth ] );
if (Depth == 0) { break; }
Depth--; goto restartDirectorySearch; }
return Result; }
BOOL 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++; }
// Advance over it.
if (*p) { p++; }
// Skip until we hit the second "\" (\\Server\Share\).
while (*p && *p != '\\') { 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 = GetFileAttributes(DirCopy); // Nothing exists with this name. Try to make the directory name and error if unable to.
if ( dw == 0xffffffff ) { if ( !CreateDirectory(DirCopy,NULL) ) { 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++; } } __except (EXCEPTION_EXECUTE_HANDLER) { SetLastError( GetExceptionCode() ); MemFree(DirCopy); return(FALSE); }
MemFree(DirCopy); return TRUE; }
BOOL UpdateDebugInfoFile( LPSTR ImageFileName, LPSTR SymbolPath, LPSTR DebugFilePath, PIMAGE_NT_HEADERS NtHeaders ) { return UpdateDebugInfoFileEx( ImageFileName, SymbolPath, DebugFilePath, NtHeaders, NtHeaders->OptionalHeader.CheckSum); }
BOOL UpdateDebugInfoFileEx( LPSTR ImageFileName, LPSTR SymbolPath, LPSTR DebugFilePath, PIMAGE_NT_HEADERS NtHeaders, DWORD OldCheckSum ) { HANDLE hDebugFile, hMappedFile; PVOID MappedAddress; PIMAGE_SEPARATE_DEBUG_HEADER DbgFileHeader;
hDebugFile = FindDebugInfoFile( ImageFileName, SymbolPath, DebugFilePath ); if ( hDebugFile == NULL ) { return FALSE; } CloseHandle(hDebugFile);
hDebugFile = CreateFile( DebugFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if ( hDebugFile == INVALID_HANDLE_VALUE ) { return FALSE; }
hMappedFile = CreateFileMapping( hDebugFile, NULL, PAGE_READWRITE, 0, 0, NULL ); if ( !hMappedFile ) { CloseHandle(hDebugFile); return FALSE; }
MappedAddress = MapViewOfFile(hMappedFile, FILE_MAP_WRITE, 0, 0, 0 ); CloseHandle(hMappedFile); if ( !MappedAddress ) { CloseHandle(hDebugFile); return FALSE; }
DbgFileHeader = (PIMAGE_SEPARATE_DEBUG_HEADER)MappedAddress; if (DbgFileHeader->ImageBase != NtHeaders->OptionalHeader.ImageBase || DbgFileHeader->CheckSum != NtHeaders->OptionalHeader.CheckSum ) { DbgFileHeader->ImageBase = NtHeaders->OptionalHeader.ImageBase; DbgFileHeader->CheckSum = NtHeaders->OptionalHeader.CheckSum; DbgFileHeader->TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp; if (OldCheckSum != NtHeaders->OptionalHeader.CheckSum) { DbgFileHeader->Flags |= IMAGE_SEPARATE_DEBUG_MISMATCH; SetLastError(ERROR_INVALID_DATA); } else { SetLastError(ERROR_SUCCESS); } UnmapViewOfFile(MappedAddress); FlushViewOfFile(MappedAddress,0); TouchFileTimes(hDebugFile,NULL); CloseHandle(hDebugFile); return TRUE; } else { UnmapViewOfFile(MappedAddress); FlushViewOfFile(MappedAddress,0); CloseHandle(hDebugFile); return FALSE; } }
LPAPI_VERSION ImagehlpApiVersion( VOID ) { return &ApiVersion; }
LPAPI_VERSION ImagehlpApiVersionEx( LPAPI_VERSION av ) { AppVersion = *av; return &ApiVersion; }
DWORD GetTimestampForLoadedLibrary( HMODULE Module ) { PIMAGE_DOS_HEADER DosHdr; PIMAGE_NT_HEADERS NtHdr;
DosHdr = (PIMAGE_DOS_HEADER) Module; if (DosHdr->e_magic == IMAGE_DOS_SIGNATURE) { NtHdr = (PIMAGE_NT_HEADERS) ((LPBYTE)Module + DosHdr->e_lfanew); } else if (DosHdr->e_magic == IMAGE_NT_SIGNATURE) { NtHdr = (PIMAGE_NT_HEADERS) DosHdr; } else { return 0; }
return NtHdr->FileHeader.TimeDateStamp; }
BOOL RemovePrivateCvSymbolic( PCHAR DebugData, PCHAR * NewDebugData, ULONG * NewDebugSize ) { OMFSignature *CvDebugData, *NewStartCvSig, *NewEndCvSig; OMFDirEntry *CvDebugDirEntry; OMFDirHeader *CvDebugDirHead; unsigned int i, j; PCHAR NewCvData; ULONG NewCvSize = 0, NewCvOffset; BOOL RC = FALSE;
__try { CvDebugDirHead = NULL; CvDebugDirEntry = NULL; CvDebugData = (OMFSignature *)DebugData;
if ((((*(PULONG)(CvDebugData->Signature)) == '90BN') || ((*(PULONG)(CvDebugData->Signature)) == '80BN')) && ((CvDebugDirHead = (OMFDirHeader *)((PUCHAR) CvDebugData + CvDebugData->filepos)) != NULL) && ((CvDebugDirEntry = (OMFDirEntry *)((PUCHAR) CvDebugDirHead + CvDebugDirHead->cbDirHeader)) != NULL)) {
// Walk the directory. Keep what we want, zero out the rest.
for (i=0, j=0; i < CvDebugDirHead->cDir; i++) { switch (CvDebugDirEntry[i].SubSection) { case sstSegMap: case sstSegName: case sstOffsetMap16: case sstOffsetMap32: case sstModule: case SSTMODULE: case SSTPUBLIC: case sstPublic: case sstPublicSym: case sstGlobalPub: CvDebugDirEntry[j] = CvDebugDirEntry[i]; NewCvSize += CvDebugDirEntry[j].cb; NewCvSize = (NewCvSize + 3) & ~3; if (i != j++) { // Clear the old entry.
RtlZeroMemory(&CvDebugDirEntry[i], CvDebugDirHead->cbDirEntry); } break;
default: RC = TRUE; RtlZeroMemory(CvDebugDirEntry[i].lfo + (PUCHAR) CvDebugData, CvDebugDirEntry[i].cb); RtlZeroMemory(&CvDebugDirEntry[i], CvDebugDirHead->cbDirEntry); break; } }
// Now, allocate the new cv data.
CvDebugDirHead->cDir = j;
NewCvSize += (j * CvDebugDirHead->cbDirEntry) + // The directory itself
CvDebugDirHead->cbDirHeader + // The directory header
(sizeof(OMFSignature) * 2); // The signature/offset pairs at each end.
NewCvData = (PCHAR) MemAlloc( NewCvSize );
// And move the stuff we kept into the new section.
NewCvOffset = sizeof(OMFSignature);
RtlCopyMemory(NewCvData + NewCvOffset, CvDebugDirHead, CvDebugDirHead->cbDirHeader);
CvDebugDirHead = (OMFDirHeader *) (NewCvData + NewCvOffset);
NewCvOffset += CvDebugDirHead->cbDirHeader;
RtlCopyMemory(NewCvData + NewCvOffset, CvDebugDirEntry, CvDebugDirHead->cDir * CvDebugDirHead->cbDirEntry);
CvDebugDirEntry = (OMFDirEntry *)(NewCvData + NewCvOffset);
NewCvOffset += (CvDebugDirHead->cbDirEntry * CvDebugDirHead->cDir);
for (i=0; i < CvDebugDirHead->cDir; i++) { RtlCopyMemory(NewCvData + NewCvOffset, CvDebugDirEntry[i].lfo + (PCHAR) CvDebugData, CvDebugDirEntry[i].cb); CvDebugDirEntry[i].lfo = NewCvOffset; NewCvOffset += (CvDebugDirEntry[i].cb + 3) & ~3; }
// Re-do the start/end signatures
NewStartCvSig = (OMFSignature *) NewCvData; NewEndCvSig = (OMFSignature *) ((PCHAR)NewCvData + NewCvOffset); *(PULONG)(NewStartCvSig->Signature) = *(PULONG)(CvDebugData->Signature); NewStartCvSig->filepos = (PCHAR)CvDebugDirHead - (PCHAR)NewStartCvSig; *(PULONG)(NewEndCvSig->Signature) = *(PULONG)(CvDebugData->Signature); NewCvOffset += sizeof(OMFSignature); NewEndCvSig->filepos = (LONG)NewCvOffset;
// Set the return values appropriately
*NewDebugData = NewCvData; *NewDebugSize = NewCvSize;
} else {
// Not NB09 or NB08. Forget we ever heard of it.
// UNDONE: What we really need to do here is write a new pdb file with just the
// public info...
*NewDebugData = NULL; *NewDebugSize = 0; RC = TRUE; }
} __except(EXCEPTION_EXECUTE_HANDLER) { RC = FALSE; }
return(RC); }
VOID RemoveRelocations( PCHAR ImageName ) { LOADED_IMAGE li; IMAGE_SECTION_HEADER RelocSectionHdr, *Section, *pRelocSecHdr; PIMAGE_DEBUG_DIRECTORY DebugDirectory; ULONG DebugDirectorySize, i, RelocSecNum;
if (!MapAndLoad(ImageName, NULL, &li, FALSE, FALSE)) { return; }
// See if the image has already been stripped or there are no relocs.
if ((li.FileHeader->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || (!li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) { UnMapAndLoad(&li); return; }
for (Section = li.Sections, i = 0; i < li.NumberOfSections; Section++, i++) { if (Section->PointerToRawData != 0) { if (!_stricmp( (char *) Section->Name, ".reloc" )) { RelocSectionHdr = *Section; pRelocSecHdr = Section; RelocSecNum = i + 1; } } }
RelocSectionHdr.Misc.VirtualSize = ROUNDUP(RelocSectionHdr.Misc.VirtualSize, li.FileHeader->OptionalHeader.SectionAlignment); RelocSectionHdr.SizeOfRawData = ROUNDUP(RelocSectionHdr.SizeOfRawData, li.FileHeader->OptionalHeader.FileAlignment);
if (RelocSecNum != li.NumberOfSections) { // Move everything else up and fixup old addresses.
for (i = RelocSecNum - 1, Section = pRelocSecHdr;i < li.NumberOfSections - 1; Section++, i++) { *Section = *(Section + 1); Section->VirtualAddress -= RelocSectionHdr.Misc.VirtualSize; Section->PointerToRawData -= RelocSectionHdr.SizeOfRawData; } }
// Zero out the last one.
RtlZeroMemory(Section, sizeof(IMAGE_SECTION_HEADER));
// Reduce the section count.
li.FileHeader->FileHeader.NumberOfSections--;
// Set the strip bit in the header
li.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
// If there's a pointer to the coff symbol table, move it back.
if (li.FileHeader->FileHeader.PointerToSymbolTable) { li.FileHeader->FileHeader.PointerToSymbolTable -= RelocSectionHdr.SizeOfRawData; }
// Clear out the base reloc entry in the data dir.
li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0; li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
// Reduce the Init Data size.
li.FileHeader->OptionalHeader.SizeOfInitializedData -= RelocSectionHdr.Misc.VirtualSize;
// Reduce the image size.
li.FileHeader->OptionalHeader.SizeOfImage -= ((RelocSectionHdr.SizeOfRawData + (li.FileHeader->OptionalHeader.SectionAlignment - 1) ) & ~(li.FileHeader->OptionalHeader.SectionAlignment - 1));
// Move the debug info up (if there is any).
DebugDirectory = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( li.MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugDirectorySize ); if (DebugDirectoryIsUseful(DebugDirectory, DebugDirectorySize)) { for (i = 0; i < (DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)); i++) { RtlMoveMemory(li.MappedAddress + DebugDirectory->PointerToRawData - RelocSectionHdr.SizeOfRawData, li.MappedAddress + DebugDirectory->PointerToRawData, DebugDirectory->SizeOfData);
DebugDirectory->PointerToRawData -= RelocSectionHdr.SizeOfRawData;
if (DebugDirectory->AddressOfRawData) { DebugDirectory->AddressOfRawData -= RelocSectionHdr.Misc.VirtualSize; }
DebugDirectory++; } }
// Truncate the image size
li.SizeOfImage -= RelocSectionHdr.SizeOfRawData;
// And we're done.
UnMapAndLoad(&li); }
|