windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/splitsymi.c
2020-09-26 16:20:57 +08:00

1105 lines
39 KiB
C

#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