NT4/private/sdktools/imagehlp/debug.c

2338 lines
81 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*++
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);
}