|
|
#include <private.h>
#include <dbgimage.h>
#if defined(use_SplitSymbolsX)
#include <splitsymx.h>
#endif // use_SplitSymbolsX
#define CLEAN_PD(addr) ((addr) & ~0x3)
#define CLEAN_PD64(addr) ((addr) & ~0x3UI64)
#if defined(use_SplitSymbolsX)
BOOL SplitSymbolsX( LPSTR ImageName, LPSTR SymbolsPath, LPSTR SymbolFilePath, ULONG Flags, PCHAR RSDSDllToLoad, LPSTR DestinationSymbol, DWORD LenDestSymbolBuffer )
#else
BOOL IMAGEAPI SplitSymbols( LPSTR ImageName, LPSTR SymbolsPath, LPSTR SymbolFilePath, ULONG Flags )
#endif // use_SplitSymbolsX
{ // UnSafe...
HANDLE FileHandle, SymbolFileHandle; HANDLE hMappedFile; LPVOID ImageBase; PIMAGE_NT_HEADERS32 NtHeaders; LPSTR ImageFileName; DWORD SizeOfSymbols; ULONG_PTR ImageNameOffset; ULONG_PTR 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 = NULL, Src, Dst; DWORD i, j, RvaOffset, ExportDirectorySize; PFPO_DATA FpoTable = NULL; DWORD FpoTableSize; PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable, pSrc; DWORD RuntimeFunctionTableSize; PIMAGE_FUNCTION_ENTRY FunctionTable = NULL, pDst; DWORD FunctionTableSize; ULONG NumberOfFunctionTableEntries, DbgOffset; DWORD SavedErrorCode; BOOL InsertExtensionSubDir; LPSTR ImageFilePathToSaveInImage; BOOL MiscInRdata = FALSE; BOOL DiscardFPO = Flags & SPLITSYM_EXTRACT_ALL; BOOL MiscDebugFound, OtherDebugFound, PdbDebugFound; BOOL fNewCvData = FALSE; PCHAR NewDebugData = NULL; CHAR AltPdbPath[_MAX_PATH]; PIMAGE_FILE_HEADER FileHeader; PIMAGE_OPTIONAL_HEADER32 OptionalHeader; PIMAGE_SECTION_HEADER Sections; PCVDD pDebugCV;
if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) { strncpy(AltPdbPath, SymbolFilePath, sizeof(AltPdbPath)); }
ImageFileName = ImageName + strlen( ImageName ); while (ImageFileName > ImageName) { if (*ImageFileName == '\\' || *ImageFileName == '/' || *ImageFileName == ':' ) { ImageFileName = CharNext(ImageFileName); break; } else { ImageFileName = CharPrev(ImageName, ImageFileName); } }
if (SymbolsPath == NULL || SymbolsPath[ 0 ] == '\0' || SymbolsPath[ 0 ] == '.' ) { strncpy( SymbolFilePath, ImageName, (int)(ImageFileName - ImageName) ); SymbolFilePath[ ImageFileName - ImageName ] = '\0'; InsertExtensionSubDir = FALSE; } else { strcpy( SymbolFilePath, SymbolsPath ); InsertExtensionSubDir = TRUE; }
Dst = SymbolFilePath + strlen( SymbolFilePath ); if (Dst > SymbolFilePath && *CharPrev(SymbolFilePath, Dst) != '\\' && *CharPrev(SymbolFilePath, Dst) != '/' && *CharPrev(SymbolFilePath, Dst) != ':') { *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" );
#ifdef _WIN64
return TRUE; #else
// 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 ); CloseHandle( hMappedFile ); if (!ImageBase) { CloseHandle( FileHandle ); return FALSE; }
//
// Everything is mapped. Now check the image and find nt image headers
//
NtHeaders = ImageNtHeader( ImageBase ); if (NtHeaders == NULL) { FileHeader = (PIMAGE_FILE_HEADER)ImageBase; OptionalHeader = ((PIMAGE_OPTIONAL_HEADER32)((ULONG_PTR)FileHeader+IMAGE_SIZEOF_FILE_HEADER)); // One last check
if (OptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) goto HeaderOk; HeaderBad: UnmapViewOfFile( ImageBase ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; } else { FileHeader = &NtHeaders->FileHeader; OptionalHeader = &NtHeaders->OptionalHeader; if (OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) goto HeaderBad; }
HeaderOk:
if ((OptionalHeader->MajorLinkerVersion < 3) && (OptionalHeader->MinorLinkerVersion < 5) ) { UnmapViewOfFile( ImageBase ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
{ DWORD dwCertificateSize; PVOID pCertificates; pCertificates = ImageDirectoryEntryToData(ImageBase, FALSE, IMAGE_DIRECTORY_ENTRY_SECURITY, &dwCertificateSize); if (pCertificates || dwCertificateSize) { // This image has been signed. Can't strip the symbols w/o invalidating the certificate.
UnmapViewOfFile( ImageBase ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; } }
if (FileHeader->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { // The symbols have already been stripped. No need to continue.
UnmapViewOfFile( ImageBase ); 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( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
// See if there's a MISC debug dir and if not, there s/b ONLY a CV data or it's an error.
MiscDebugFound = FALSE; OtherDebugFound = FALSE; for (i=0,DebugDirectory=DebugDirectories; i<NumberOfDebugDirectories; i++,DebugDirectory++) { switch (DebugDirectory->Type) { case IMAGE_DEBUG_TYPE_MISC: MiscDebugFound = TRUE; break;
case IMAGE_DEBUG_TYPE_CODEVIEW: pDebugCV = ( PCVDD ) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase); if (pDebugCV->dwSig == '01BN') { PdbDebugFound = TRUE; } #if defined(use_SplitSymbolsX)
if (pDebugCV->dwSig == 'SDSR') { PdbDebugFound = TRUE; } #endif
break;
default: OtherDebugFound = TRUE; break; } }
if (OtherDebugFound && !MiscDebugFound) { UnmapViewOfFile( ImageBase ); CloseHandle( FileHandle ); SetLastError( ERROR_BAD_EXE_FORMAT ); return FALSE; }
if (PdbDebugFound && !OtherDebugFound && (OptionalHeader->MajorLinkerVersion >= 6)) { // This is a VC6 generated image. Don't create a .dbg file.
MiscDebugFound = FALSE; }
// Make sure we can open the .dbg file before we continue...
if (!MakeSureDirectoryPathExists( SymbolFilePath )) { return FALSE; }
if (MiscDebugFound) { // Try to open the symbol file
SymbolFileHandle = CreateFile( SymbolFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); if (SymbolFileHandle == INVALID_HANDLE_VALUE) { goto nosyms; } }
// 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.
{ if (NtHeaders) { Sections = IMAGE_FIRST_SECTION( NtHeaders ); } else { Sections = (PIMAGE_SECTION_HEADER) ((ULONG_PTR)ImageBase + ((PIMAGE_FILE_HEADER)ImageBase)->SizeOfOptionalHeader + IMAGE_SIZEOF_FILE_HEADER ); }
for (SectionNumber = 0; SectionNumber < 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 to the static CV data and save the new size...
pDebugCV = ( PCVDD ) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase); if (pDebugCV->dwSig == '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]; BOOL rc;
memset(PdbName, 0, sizeof(PdbName)); memcpy(PdbName, ((PCHAR)pDebugCV)+ sizeof(NB10IH), DebugDirectory->SizeOfData - sizeof(NB10IH));
_splitpath(PdbName, NULL, NULL, Filename, FileExt); _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL); _makepath(NewPdbName, Drive, Dir, Filename, FileExt); #if defined(use_SplitSymbolsX)
if (DestinationSymbol) { strncpy(DestinationSymbol, NewPdbName, LenDestSymbolBuffer); DestinationSymbol[LenDestSymbolBuffer-1] = '\0'; // ensure termination
} rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL); #else
rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE); #endif
if (!rc) { if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) { // Try the AltPdbPath.
strcpy(PdbName, AltPdbPath); strcat(PdbName, Filename); strcat(PdbName, FileExt); #if defined(use_SplitSymbolsX)
rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL); #else
rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE); #endif
}
if ( !rc) { // 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); #if defined(use_SplitSymbolsX)
rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL); #else
rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE); #endif
} }
if (rc) { SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
// Change the data so only the pdb name is in the .dbg file (no path).
if (MiscDebugFound) { NewDebugSize = sizeof(NB10IH) + strlen(Filename) + strlen(FileExt) + 1; #if defined(use_SplitSymbolsX)
NewDebugData = (PCHAR) malloc( NewDebugSize ); #else
NewDebugData = (PCHAR) MemAlloc( NewDebugSize ); #endif
((PCVDD)NewDebugData)->nb10ih = pDebugCV->nb10ih; strcpy(NewDebugData + sizeof(NB10IH), Filename); strcat(NewDebugData + sizeof(NB10IH), FileExt);
DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase); DebugDirectory->SizeOfData = NewDebugSize; } else { strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename); strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt); } } else { // Replace <Path>\<filename>.<ext> with just <filename>.<ext> in the debug data
strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename); strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt); DebugDirectory->SizeOfData = sizeof(NB10IH) + strlen(Filename) + strlen(FileExt) + 1; }
#if defined(use_SplitSymbolsX)
} else if ( pDebugCV->dwSig == 'SDSR') { // Got a PDB. The name immediately follows the signature.
CHAR PdbName[sizeof(((PRSDSI)(0))->szPdb)]; CHAR NewPdbName[_MAX_PATH]; CHAR Drive[_MAX_DRIVE]; CHAR Dir[_MAX_DIR]; CHAR Filename[_MAX_FNAME]; CHAR FileExt[_MAX_EXT]; BOOL rc;
ZeroMemory(PdbName, sizeof(PdbName)); memcpy(PdbName, ((PCHAR)pDebugCV)+ sizeof(RSDSIH), __min(DebugDirectory->SizeOfData - sizeof(RSDSIH), sizeof(PdbName)));
_splitpath(PdbName, NULL, NULL, Filename, FileExt); _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL); _makepath(NewPdbName, Drive, Dir, Filename, FileExt); if (DestinationSymbol) { strncpy(DestinationSymbol, NewPdbName, LenDestSymbolBuffer); DestinationSymbol[LenDestSymbolBuffer-1] = '\0'; // ensure termination
} rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad);
if (!rc) { if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) { // Try the AltPdbPath.
strcpy(PdbName, AltPdbPath); strcat(PdbName, Filename); strcat(PdbName, FileExt); rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad); }
if ( !rc) { // 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); rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad); } }
if (rc) { SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
// Change the data so only the pdb name is in the .dbg file (no path).
if (MiscDebugFound) { NewDebugSize = sizeof(RSDSIH) + strlen(Filename) + strlen(FileExt) + 1; NewDebugData = (PCHAR) malloc( NewDebugSize ); ((PCVDD)NewDebugData)->rsdsih = pDebugCV->rsdsih; strcpy(NewDebugData + sizeof(RSDSIH), Filename); strcat(NewDebugData + sizeof(RSDSIH), FileExt);
DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase); DebugDirectory->SizeOfData = NewDebugSize; } else { strcpy(((PCHAR)pDebugCV) + sizeof(RSDSIH), Filename); strcat(((PCHAR)pDebugCV) + sizeof(RSDSIH), FileExt); } } else { // Replace <Path>\<filename>.<ext> with just <filename>.<ext> in the debug data
strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename); strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt); DebugDirectory->SizeOfData = sizeof(RSDSIH) + strlen(Filename) + strlen(FileExt) + 1; }
#endif
} else { if (Flags & SPLITSYM_REMOVE_PRIVATE) { if (RemovePrivateCvSymbolicEx(DebugDirectory->PointerToRawData + (PCHAR)ImageBase, DebugDirectory->SizeOfData, &NewDebugData, &NewDebugSize)) { if (DebugDirectory->PointerToRawData != (ULONG) (NewDebugData - (PCHAR)ImageBase)) { DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase); DebugDirectory->SizeOfData = NewDebugSize; } else { NewDebugData = NULL; } } } } }
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->SizeOfData && (DebugDirectory->PointerToRawData < DebugSectionStart)) { DebugSectionStart = DebugDirectory->PointerToRawData; }
// Nothing else to special case...
break; }
SizeOfSymbols += (DebugDirectory->SizeOfData + 3) & ~3; // Minimally align it all.
}
if (!MiscDebugFound) { NewFileSize = GetFileSize(FileHandle, NULL);
CheckSumMappedFile( ImageBase, NewFileSize, &HeaderSum, &CheckSum ); OptionalHeader->CheckSum = CheckSum;
goto nomisc; }
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; #if defined(use_SplitSymbolsX)
FpoTable = (PFPO_DATA) malloc( FpoTableSize ); #else
FpoTable = (PFPO_DATA) MemAlloc( FpoTableSize ); #endif
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 = (ULONG_PTR) ImageDirectoryEntryToData( ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirectorySize ) - (ULONG_PTR)ImageBase;
pp = (LPDWORD)((ULONG_PTR)ExportDirectory + (ULONG_PTR)ExportDirectory->AddressOfNames - RvaOffset );
ExportedNamesSize = 1; for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((ULONG_PTR)ExportDirectory + *pp++ - RvaOffset); ExportedNamesSize += strlen( Src ) + 1; } ExportedNamesSize = (ExportedNamesSize + 16) & ~15;
#if defined(use_SplitSymbolsX)
Dst = (LPSTR) malloc( ExportedNamesSize ); #else
Dst = (LPSTR) MemAlloc( ExportedNamesSize ); #endif
if (Dst != NULL) { ExportedNames = Dst; pp = (LPDWORD)((ULONG_PTR)ExportDirectory + (ULONG_PTR)ExportDirectory->AddressOfNames - RvaOffset ); for (i=0; i<ExportDirectory->NumberOfNames; i++) { Src = (LPSTR)((ULONG_PTR)ExportDirectory + *pp++ - RvaOffset); while (*Dst++ = *Src++) { ; } } } } else { ExportedNamesSize = 0; }
RuntimeFunctionTable = (PIMAGE_ALPHA_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_ALPHA_RUNTIME_FUNCTION_ENTRY ); FunctionTableSize = NumberOfFunctionTableEntries * sizeof( IMAGE_FUNCTION_ENTRY ); #if defined(use_SplitSymbolsX)
FunctionTable = (PIMAGE_FUNCTION_ENTRY) malloc( FunctionTableSize ); #else
FunctionTable = (PIMAGE_FUNCTION_ENTRY) MemAlloc( FunctionTableSize ); #endif
if (FunctionTable == NULL) { goto nosyms; }
pSrc = RuntimeFunctionTable; pDst = FunctionTable; for (i=0; i<NumberOfFunctionTableEntries; i++) { //
// Make .pdata entries in .DBG file relative.
//
pDst->StartingAddress = CLEAN_PD(pSrc->BeginAddress) - OptionalHeader->ImageBase; pDst->EndingAddress = CLEAN_PD(pSrc->EndAddress) - OptionalHeader->ImageBase; pDst->EndOfPrologue = CLEAN_PD(pSrc->PrologEndAddress) - OptionalHeader->ImageBase; pSrc += 1; pDst += 1; } }
DbgFileHeaderSize = sizeof( DbgFileHeader ) + ((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) { FileHeader->PointerToSymbolTable = 0; FileHeader->NumberOfSymbols = 0; FileHeader->Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
if (DebugSection != NULL) { OptionalHeader->SizeOfImage = DebugSection->VirtualAddress; OptionalHeader->SizeOfInitializedData -= DebugSection->SizeOfRawData; 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 = (ULONG_PTR) ((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 = (ULONG_PTR) ((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
#if defined(use_SplitSymbolsX)
DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) malloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) ); #else
DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) MemAlloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) ); #endif
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[DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)] = FpoDebugDirectory; DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY); }
// Zero out remaining slots in image.
if (NumberOfDebugDirectories < (DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY))) { ZeroMemory(&DebugDirectories[DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)], NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) - DebugDirectorySize); }
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 ); OptionalHeader->CheckSum = CheckSum;
DbgFileHeader.Signature = IMAGE_SEPARATE_DEBUG_SIGNATURE; DbgFileHeader.Flags = 0; DbgFileHeader.Machine = FileHeader->Machine; DbgFileHeader.Characteristics = FileHeader->Characteristics; DbgFileHeader.TimeDateStamp = FileHeader->TimeDateStamp; DbgFileHeader.CheckSum = CheckSum; DbgFileHeader.ImageBase = OptionalHeader->ImageBase; DbgFileHeader.SizeOfImage = OptionalHeader->SizeOfImage; DbgFileHeader.ExportedNamesSize = ExportedNamesSize; DbgFileHeader.DebugDirectorySize = NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY); if (FunctionTable) { DbgFileHeader.DebugDirectorySize += sizeof (IMAGE_DEBUG_DIRECTORY); } DbgFileHeader.NumberOfSections = FileHeader->NumberOfSections; memset( DbgFileHeader.Reserved, 0, sizeof( DbgFileHeader.Reserved ) ); DbgFileHeader.SectionAlignment = OptionalHeader->SectionAlignment;
SetFilePointer( SymbolFileHandle, 0, NULL, FILE_BEGIN ); WriteFile( SymbolFileHandle, &DbgFileHeader, sizeof( DbgFileHeader ), &BytesWritten, NULL ); if (NtHeaders) { Sections = IMAGE_FIRST_SECTION( NtHeaders ); } else { Sections = (PIMAGE_SECTION_HEADER) ((ULONG_PTR)ImageBase + ((PIMAGE_FILE_HEADER)ImageBase)->SizeOfOptionalHeader + IMAGE_SIZEOF_FILE_HEADER ); } WriteFile( SymbolFileHandle, (PVOID)Sections, sizeof( IMAGE_SECTION_HEADER ) * 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 );
nomisc:
FlushViewOfFile( ImageBase, NewFileSize ); UnmapViewOfFile( ImageBase );
SetFilePointer( FileHandle, NewFileSize, NULL, FILE_BEGIN ); SetEndOfFile( FileHandle );
TouchFileTimes( FileHandle, NULL ); CloseHandle( FileHandle );
if (ExportedNames) { #if defined(use_SplitSymbolsX)
free( ExportedNames ); #else
MemFree( ExportedNames ); #endif
}
if (FpoTable) { #if defined(use_SplitSymbolsX)
free( FpoTable ); #else
MemFree( FpoTable ); #endif
}
if (FunctionTable) { #if defined(use_SplitSymbolsX)
free( FunctionTable ); #else
MemFree( FunctionTable ); #endif
}
if (NewDebugData) { #if defined(use_SplitSymbolsX)
free(NewDebugData); #else
MemFree(NewDebugData); #endif
}
if (DbgDebugDirectories) { #if defined(use_SplitSymbolsX)
free(DbgDebugDirectories); #else
MemFree(DbgDebugDirectories); #endif
}
return TRUE;
} else { CloseHandle( SymbolFileHandle ); DeleteFile( SymbolFilePath ); }
nosyms: SavedErrorCode = GetLastError(); if (ExportedNames != NULL) { #if defined(use_SplitSymbolsX)
free( ExportedNames ); #else
MemFree( ExportedNames ); #endif
}
if (FpoTable != NULL) { #if defined(use_SplitSymbolsX)
free( FpoTable ); #else
MemFree( FpoTable ); #endif
}
if (FunctionTable != NULL) { #if defined(use_SplitSymbolsX)
free( FunctionTable ); #else
MemFree( FunctionTable ); #endif
}
UnmapViewOfFile( ImageBase ); CloseHandle( FileHandle ); SetLastError( SavedErrorCode ); return FALSE; #endif
}
#if defined(use_SplitSymbolsX)
LPSTR CharNext( LPCSTR lpCurrentChar) { if (IsDBCSLeadByte(*lpCurrentChar)) { lpCurrentChar++; } /*
* if we have only DBCS LeadingByte, we will point string-terminaler. */
if (*lpCurrentChar) { lpCurrentChar++; } return (LPSTR)lpCurrentChar; }
LPSTR CharPrev( LPCSTR lpStart, LPCSTR lpCurrentChar) { if (lpCurrentChar > lpStart) { LPCSTR lpChar; BOOL bDBC = FALSE;
for (lpChar = --lpCurrentChar - 1 ; lpChar >= lpStart ; lpChar--) { if (!IsDBCSLeadByte(*lpChar)) break; bDBC = !bDBC; }
if (bDBC) lpCurrentChar--; } return (LPSTR)lpCurrentChar; } #endif
|