NT4/private/sdktools/vctools/cvpack/module.c

1418 lines
32 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*
* to build module list
*
* History:
* 01-Feb-1994 HV Move messages to external file.
*
*/
#include "compact.h"
#include "exehdr.h"
#include <getmsg.h> // external error message file
#include "writebuf.h"
enum SIG {
SIG05, // NB05 signature
};
uchar Signature[4];
uchar NewSig[8] = "NB09";
uchar fLinearExe;
OMFDirEntry *pDir;
_vmhnd_t Libraries;
_vmhnd_t SegMap;
_vmhnd_t SegName;
ulong LibSize;
ulong SegMapSize;
ulong SegNameSize;
ushort cMod;
OMFDirHeader DirHead;
PMOD ModuleList;
extern ushort NewIndex;
ushort Sig; // signature enumeration
long cbSrcModule;
PACKDATA *PackOrder;
ulong lfoOldEnd;
ulong lfoNewEnd;
ulong lfoDebugObject;
ulong lfoDebugSection;
ulong lfoPEOptHeader;
ulong dwPECheckSum;
ulong rvaDebugDir;
IMAGE_FILE_HEADER PEHeader;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
char Zero[4] = {0};
int PadCount;
/** CheckSignature - check file signature
*
* Sig = CheckSignature ()
*
* Entry none
*
* Exit none
*
* Return SIG05 if exe has NB05 signature
* aborts if any other signature
*/
LOCAL ushort CheckSignature(void)
{
if (link_read (exefile, Signature, 4) == 4) {
if ((Signature[0] != 'N') || (Signature[1] != 'B')) {
ErrorExit(ERR_RELINK, NULL, NULL);
}
if (Signature[2] == '0') {
if (Signature[3] == '5') {
return(SIG05);
}
}
if ((Signature[2] == '0' && Signature[3] == '9') ||
(Signature[2] == '1' && Signature[3] == '0')) {
// Just return a zero here when stripping.
// They just have to match until we strip
if (strip) {
return(0);
}
Warn(WARN_PACKED, NULL, NULL);
AppExit(0);
}
ErrorExit(ERR_RELINK, NULL, NULL);
}
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
const int mpsstiOrder[] =
{
1, // sstModule
2, // sstTypes
0, // sstPublic Not emitted by linker
4, // sstPublicSym
3, // sstSymbols
0, // sstAlignSym Not emitted by linker
0, // sstSrcLnSeg Not emitted by linker
5, // sstSrcModule
0, // sstLibraries Module index is -1
0, // sstGlobalSym Not emitted by linker
0, // sstGlobalPub Not emitted by linker
0, // sstGlobalTypes Not emitted by linker
0, // sstMPC Not emitted by linker
0, // sstSegMap Module index is -1
0, // sstSegName Module index is -1
2, // sstPreComp
};
LOCAL int __cdecl modsort(const OMFDirEntry *d1, const OMFDirEntry *d2)
{
int i1;
int i2;
// First order by module index
if (d1->iMod < d2->iMod) {
return (-1);
}
if (d1->iMod > d2->iMod) {
return (1);
}
// Within a module, order by subsection type.
// Desired order is module, types, symbols, publics, srclnseg
DASSERT(d1->SubSection >= sstModule);
DASSERT(d1->SubSection <= sstPreComp);
DASSERT(d2->SubSection >= sstModule);
DASSERT(d2->SubSection <= sstPreComp);
i1 = mpsstiOrder[d1->SubSection - sstModule];
i2 = mpsstiOrder[d2->SubSection - sstModule];
if (i1 < i2) {
return (-1);
}
if (i1 > i2) {
return (1);
}
return(0);
}
/** ReadNB05 - read file with NB05 signature
*
*
*/
LOCAL void ReadNB05(void)
{
ulong cnt;
ushort tMod = 0;
ulong i;
// locate directory, read number of entries, allocate space, read
// directory entries and sort into ascending module index order
if ((link_read (exefile, (char *)&lfoDir, sizeof (long)) != sizeof (long)) ||
(link_lseek (exefile, lfoDir + lfoBase, SEEK_SET) == -1L) ||
(link_read (exefile, (char *)&DirHead, sizeof (DirHead)) !=
sizeof (OMFDirHeader))) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (!DirHead.cDir) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
cSST = DirHead.cDir;
// read directory into local memory to sort, then copy to far memory buffer
cnt = (cSST + 6) * sizeof (OMFDirEntry);
DASSERT(cnt <= UINT_MAX);
if ((pDir = (OMFDirEntry *)TrapMalloc ((size_t)cnt)) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
if (link_read (exefile, (char *)pDir, (size_t)(sizeof (OMFDirEntry) * cSST)) !=
(sizeof (OMFDirEntry) * cSST)) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
for (i = 0; i < cSST; i++) {
if ((pDir[i].iMod != 0) && (pDir[i].iMod != 0xffff)) {
if (pDir[i].iMod != tMod) {
if (pDir[i].SubSection != sstModule) {
// module entry not first, need to sort
break;
}
tMod = pDir[i].iMod;
}
}
}
if (i != cSST) {
qsort(pDir, (size_t) cSST, sizeof(OMFDirEntry), modsort);
}
}
/** CopyTable - copy table to VM
*
* CopyTable (pDir);
*
* Entry pDir = address of directory entry
*
* Exit pDir->lfo = address of rewritten table
* pDir->Size = size of rewritten table
*
* Return none
*
*/
LOCAL void CopyTable(OMFDirEntry *pDir, _vmhnd_t *pAddr, ulong *pSize)
{
_vmhnd_t TableAddr;
char *pTable;
if ((TableAddr = (_vmhnd_t)TrapMalloc (pDir->cb)) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
pTable = (char *) TableAddr;
link_lseek(exefile, pDir->lfo + lfoBase, SEEK_SET);
if (link_read(exefile, pTable, pDir->cb) != pDir->cb) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
*pAddr = TableAddr;
*pSize = pDir->cb;
}
/** Get module - find or create module entry in list
*
* pMod = GetModule (iMod)
*
* Entry iMod = module index
* fAdd = TRUE if module to be added to list
*
* Exit new module structure added if iMod not in list
*
* Returns pointer to module structure
*/
PMOD GetModule(ushort iMod)
{
PMOD new;
PMOD prev;
PMOD ptr;
prev = NULL;
ptr = ModuleList;
// search to end of module list
while (ptr != NULL) {
if (ptr->ModuleIndex == iMod) {
return(ptr);
}
if (ptr->ModuleIndex > iMod) {
break;
}
prev = ptr;
ptr = ptr->next;
}
// since the module was not found, create a blank ModuleList entry
new = (PMOD) TrapMalloc(sizeof(MOD));
memset(new, 0, sizeof(MOD));
new->ModuleIndex = iMod;
// Do sorted list insertion into ModuleList
if (prev == NULL) {
ModuleList = new;
} else {
prev->next = new;
}
new->next = ptr;
return(new);
}
/** SetTableSizes - set maximum sizes of tables
*
* SetTableSizes ()
*
* Entry none
*
* Exit cMod = number of modules
* maxSSTMod = maximum old module table size
* maxPublics = maximum public symblol table size
* maxSrcLn = maximum line number table size
* maxSymbol = maximum symbol table size
* Libraries = address of read sstLibraries table
* LibrariesSize = size of sstLibraries table
* SegMap = address of read sstSegMap table if encountered
* SegMapSize = size of sstSegMap table
* SegName = address of sstSegName table if encountered
* SegNameSize = address of sstSegName table
* PackOrder = pointer to array of packing data in pack order
*
* Returns none
*/
LOCAL void SetTableSizes(void)
{
ulong i;
ushort iPData;
ushort j;
long iDir;
ushort iMod;
PACKDATA *pPData;
bool_t fPreComp = FALSE;
// determine number of modules in file. Remember that module indices
// of 0 and 0xffff are not for actual modules
cMod = 0;
maxTypes = 0;
maxPublics = 0;
maxSymbols = 0;
maxSrcLn = 0;
maxMod = 0;
for (i = 0; i < cSST; i++) {
switch (pDir[i].SubSection) {
case sstModule:
if (pDir[i].iMod != 0xffff) {
cMod++;
}
break;
case sstTypes:
maxTypes = max(maxTypes, pDir[i].cb);
break;
case sstPreComp:
fPreComp = TRUE;
maxTypes = max(maxTypes, pDir[i].cb);
break;
case sstPublicSym:
maxPublics = max(maxPublics, pDir[i].cb);
break;
case sstSymbols:
maxSymbols = max(maxSymbols, pDir[i].cb);
break;
case sstSrcModule:
maxSrcLn = max(maxSrcLn, pDir[i].cb);
break;
case sstLibraries:
CopyTable(&pDir[i], &Libraries, &LibSize);
break;
case sstSegMap:
CopyTable(&pDir[i], &SegMap, &SegMapSize);
break;
case sstSegName:
CopyTable(&pDir[i], &SegName, &SegNameSize);
break;
default:
ErrorExit(ERR_RELINK, NULL, NULL);
}
}
if ((PackOrder = (PACKDATA *) CAlloc(cMod * sizeof(PACKDATA))) == 0) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
iMod = 0;
iPData = 0;
if (fPreComp) {
// precompiled types were encountered in the scan above
// sweep through the directory and put all modules with
// precompiled types in the pack order array
for (i = 0; i < cSST; i++) {
switch (pDir[i].SubSection) {
case sstModule:
if ((pDir[i].iMod != 0xffff) && (pDir[i].iMod != 0)) {
// save the module index and the starting directory entry
iDir = i;
}
break;
case sstPreComp:
pPData = PackOrder + iPData;
pPData->iMod = pDir[i].iMod;
pPData->iDir = iDir;
pPData->pMod = GetModule(pDir[i].iMod);
iPData++;
break;
}
}
}
for (i = 0; i < cSST; i++) {
// now sweep through the directory and add all modules that were
// not added in the first pass
if (pDir[i].SubSection == sstModule) {
for (j = 0; j < iPData; j++) {
pPData = PackOrder + j;
if (pPData->iMod == pDir[i].iMod) {
break;
}
}
if (j == iPData) {
// we did not find the module in the pack order array
pPData = PackOrder + iPData;
pPData->iMod = pDir[i].iMod;
pPData->iDir = i;
pPData->pMod = GetModule(pDir[i].iMod);
iPData++;
}
}
}
}
/** ReadDir - read subsection directory from exe
*
* ReadDir ()
*
* Entry exefile = file handle for .exe
*
* Exit cSST = count of number of subsection entries
* cMod = number of modules in file
* pDir = pointer to subsection directories
* subsection entries sorted into ascending module order
*
* Returns none
*/
#define DBGBUFSIZE 0x1000
void ReadDir(void)
{
long dlfaBase;
IMAGE_OPTIONAL_HEADER PEOptHeader;
uint cbAlloc;
filepos = 0;
if (link_lseek(exefile, 0L, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
for (;;)
{
DWORD cbRead;
struct exe_hdr hdr;
DWORD dwSignature;
// With one exception, the following algorithm is the
// same as that used by LoadExeHeader in Windows 3.10.
cbRead = link_read(exefile, &hdr, sizeof(hdr));
if (cbRead < offsetof(struct exe_hdr, e_lfarlc) + sizeof(hdr.e_lfarlc)) {
// The file isn't large enough to contain a valid DOS EXE header.
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (hdr.e_magic != EMAGIC) {
// The file does not contain a valid DOS EXE header.
// It could be a Windows NT ROM image or a PE image w/o a stub.
// Seek back and see.
if (link_lseek(exefile, 0L, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
link_read(exefile, &dwSignature, sizeof(dwSignature));
if (dwSignature != IMAGE_NT_SIGNATURE) {
// Not a no-stub PE. Must be a ROM image. Assume so
// and back up one more time.
if (link_lseek(exefile, 0L, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
}
fLinearExe = TRUE;
break;
}
// Check to see if this is an NE or PE format image
if (cbRead < offsetof(struct exe_hdr, e_lfanew) + sizeof(hdr.e_lfanew)) {
// The header isn't large enough to point to an NE or PE header
break;
}
if (hdr.e_lfanew == 0) {
// There is no pointer to an NE or PE header
break;
}
if (link_lseek(exefile, hdr.e_lfanew, SEEK_SET) == -1) {
// The file isn't large enough to contain an NE or PE header
break;
}
// Read the first DWORD of the NE or PE header.
// Note: Windows 3.1 reads a new_exe structure at this point
cbRead = link_read(exefile, &dwSignature, sizeof(DWORD));
if (cbRead < sizeof(DWORD)) {
// The file isn't large enough to contain an NE or PE header
break;
}
if (dwSignature == IMAGE_NT_SIGNATURE) {
/* We found an PE header */
fLinearExe = TRUE;
break;
}
// Well, it's still a valid DOS EXE
break; // Break out of for loop
}
if (fLinearExe) {
int cObjs;
int cDirs;
IMAGE_SECTION_HEADER o32obj;
IMAGE_DEBUG_DIRECTORY dbgDir;
if (link_read(exefile, &PEHeader, sizeof(IMAGE_FILE_HEADER)) !=
sizeof(IMAGE_FILE_HEADER)) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
// No sense going further if there's nothing there...
if (PEHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
ErrorExit(ERR_NOINFO, NULL, NULL);
}
// save away the location of the PE Optional Header so that
// we can modify this header in FixupExeFile
lfoPEOptHeader = link_tell(exefile);
// Seek past the optional header to the object descriptors.
if (link_read(exefile, &PEOptHeader, PEHeader.SizeOfOptionalHeader) !=
PEHeader.SizeOfOptionalHeader) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
MajorLinkerVersion = PEOptHeader.MajorLinkerVersion;
MinorLinkerVersion = PEOptHeader.MinorLinkerVersion;
cObjs = PEHeader.NumberOfSections;
if (PEHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
// ROM images store the debug directory at the beginning of .rdata.
for (; cObjs != 0; cObjs -= 1) {
lfoDebugObject = link_tell(exefile);
if (link_read(exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER) !=
IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (!strncmp(o32obj.Name, ".rdata", 5)) {
break;
}
}
if (cObjs == 0) {
ErrorExit(ERR_NOINFO, NULL, NULL);
}
if (link_lseek(exefile, o32obj.PointerToRawData, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
do {
if (link_read(exefile, &dbgDir, sizeof(IMAGE_DEBUG_DIRECTORY)) !=
sizeof(IMAGE_DEBUG_DIRECTORY)) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
break;
rvaDebugDir += sizeof(IMAGE_DEBUG_DIRECTORY);
} while (dbgDir.Type != 0);
} else {
// Save away the checksum for later use...
dwPECheckSum = PEOptHeader.CheckSum;
// First, see if there's any directories.
cDirs = PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
sizeof(IMAGE_DEBUG_DIRECTORY);
if (cDirs == 0) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
// Then see if we have a debug directory that will need to be updated on close.
lfoDebugObject = link_tell(exefile);
for (; cObjs != 0; cObjs -= 1) {
if (link_read(exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER) !=
IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (!strncmp(o32obj.Name, ".debug", 6)) {
lfoDebugSection = link_tell(exefile) - IMAGE_SIZEOF_SECTION_HEADER;
break;
}
}
// A really lame test to see if the cObj's was wrong...
if (link_lseek(exefile, 0L, SEEK_END) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
lfoOldEnd = link_tell(exefile);
if (link_lseek(exefile, lfoDebugObject, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
// Then, using the debug data directory, find the section that holds the debug
// directory.
cObjs = PEHeader.NumberOfSections;
for (; cObjs != 0; cObjs -= 1) {
lfoDebugObject = link_tell(exefile);
if ( link_read(exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER) !=
IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if ((PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress >=
o32obj.VirtualAddress) &&
(PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress <
o32obj.VirtualAddress + o32obj.SizeOfRawData)
) {
rvaDebugDir =
PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress -
o32obj.VirtualAddress;
break;
}
}
if (cObjs == 0) {
ErrorExit( ERR_NOINFO, NULL, NULL);
}
// Finally, walk the debug directory list looking for CV info to pack.
if (link_lseek(exefile, o32obj.PointerToRawData + rvaDebugDir, SEEK_SET) == -1L) {
ErrorExit( ERR_INVALIDEXE, NULL, NULL);
}
for (; cDirs != 0; cDirs--) {
if (link_read(exefile, &dbgDir, sizeof (IMAGE_DEBUG_DIRECTORY )) !=
sizeof(IMAGE_DEBUG_DIRECTORY)) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
break;
rvaDebugDir += sizeof(IMAGE_DEBUG_DIRECTORY);
}
}
if (dbgDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
ErrorExit(ERR_NOINFO, NULL, NULL);
}
lfoBase = dbgDir.PointerToRawData;
if (link_lseek(exefile, lfoBase, SEEK_SET) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
Sig = CheckSignature();
} else {
if (link_lseek(exefile, -8L, SEEK_END) == -1L) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
Sig = CheckSignature();
if ((link_read(exefile, (char *)&dlfaBase, sizeof (long)) != sizeof (long)) ||
(link_lseek(exefile, -dlfaBase, SEEK_END) == -1L)) {
ErrorExit(ERR_NOINFO, NULL, NULL);
}
lfoBase = link_tell(exefile);
if (CheckSignature() != Sig) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
}
// if we are stripping - just truncate the exe at the lfobase and exit
// sps 9/10/92
if (strip) {
if (pDbgFilename != NULL) {
int dbgFile;
LONG cbDbg;
PUCHAR pbMapExe;
PUCHAR pbMapDbg;
// have a dbgfile - copy debug info to it
pDbgFilename = BuildFilename(pDbgFilename, ".dbg");
if ((dbgFile = link_open (pDbgFilename, O_WRONLY | O_BINARY | O_CREAT, S_IWRITE )) == -1) {
if ((dbgFile = link_open (pDbgFilename, O_RDONLY | O_BINARY, 0)) == -1) {
ErrorExit (ERR_EXEOPEN, pDbgFilename, NULL);
}
else {
ErrorExit (ERR_READONLY, pDbgFilename, NULL);
}
}
cbDbg = FileLength(exefile) - lfoBase;
pbMapExe = PbMappedRegion(exefile, lfoBase, cbDbg);
pbMapDbg = PbMappedRegion(dbgFile, 0, cbDbg);
if (pbMapExe && pbMapDbg) {
memcpy(pbMapDbg, pbMapExe, cbDbg);
}
else {
char dbgBuf[DBGBUFSIZE];
int numRead;
LONG ltmp;
link_lseek(exefile, lfoBase, SEEK_SET);
for (ltmp = cbDbg; ltmp > 0; ltmp -= numRead) {
numRead = link_read(exefile, dbgBuf, DBGBUFSIZE);
if (link_write(dbgFile, dbgBuf, numRead) != (ULONG) numRead) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
if (numRead < 0) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
}
}
if( link_chsize( dbgFile, cbDbg ) == -1 ) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
link_close(dbgFile);
}
if( link_chsize( exefile, lfoBase ) == -1 ) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
AppExit(0);
}
// locate directory, read number of entries, allocate space, read
// directory entries and sort into ascending module index order
ReadNB05();
if (DirHead.lfoNextDir != 0) {
ErrorExit(ERR_INVALIDEXE, NULL, NULL);
}
SetTableSizes();
maxPublicsSub = maxPublics;
maxSymbolsSub = maxSymbols;
maxSrcLnSub = maxSrcLn;
maxModSub = maxMod;
if ((maxModSub != 0) &&
((pSSTMOD = (oldsmd *)TrapMalloc (maxModSub)) == NULL)) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
if ((pPublics = TrapMalloc (maxPublicsSub)) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
if ((pSymbols = TrapMalloc (maxSymbolsSub)) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
if ((pSrcLn = TrapMalloc (maxSrcLnSub)) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
// pad size up by possibly missing signature for C6 objects
maxTypes += sizeof (ulong);
cTypeSeg = (ushort)(maxTypes / _HEAP_MAXREQ + 2);
if ((pTypeSeg = CAlloc (cTypeSeg * sizeof (char *))) == 0) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
// allocate only first type segment
cbAlloc = (uint)min (maxTypes, _HEAP_MAXREQ);
if ((pTypeSeg[iTypeSeg] = TrapMalloc (cbAlloc)) == 0) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
}
LOCAL int __cdecl sstsort(const OMFDirEntry *d1, const OMFDirEntry *d2)
{
if ((d1->SubSection == sstModule) || (d2->SubSection == sstModule)) {
// we alway sort the module subsections to the top in order
// of the module index
if ((d1->SubSection == sstModule) && (d2->SubSection != sstModule)) {
return(-1);
}
if ((d1->SubSection != sstModule) && (d2->SubSection == sstModule)) {
return(1);
}
}
// sort by module
if (d1->iMod < d2->iMod) {
return(-1);
}
if (d1->iMod > d2->iMod) {
return(1);
}
// if the modules are the same, sort by subsection type index
if (d1->SubSection < d2->SubSection) {
return(-1);
}
if (d1->SubSection > d2->SubSection) {
return(1);
}
return(0);
}
LOCAL ulong WriteTypes(void)
{
ulong FinalInfoSize;
VBlock * TypeBlock;
ulong TypeEntries = (CV_typ_t)(NewIndex - (CV_typ_t)CV_FIRST_NONPRIM);
ulong ulZero = 0; // Used for writing pad bytes
ushort usTotal; // Size of type record including length field
ushort usPad; // Number of bytes necessary to pad type
uchar * pchType; // The type string to write
uchar * pchEnd; // The end of the global type block
ulong i = 0;
ulong **pBuf;
ulong cnt;
OMFTypeFlags flags = {0};
ushort cb = 0;
flags.sig = CV_SIGNATURE_C7;
PrepareGlobalTypeTable();
// Write the flag word and number of types to disk
if (!BWrite ((char *)&flags, sizeof (OMFTypeFlags)))
ErrorExit (ERR_NOSPACE, NULL, NULL);
if (!BWrite ((char *) &TypeEntries, sizeof (ulong)))
ErrorExit (ERR_NOSPACE, NULL, NULL);
FinalInfoSize = 2 * sizeof (ulong);
// Write the global type table to disk
// (Global type table gives file offset from type #
while (i < TypeEntries) {
cnt = min (GTYPE_INC, TypeEntries - i);
DASSERT (cnt * sizeof (ulong) <= UINT_MAX);
pBuf = (ulong **)pGType[i / GTYPE_INC];
if (!BWrite ((char *) pBuf, (size_t)(cnt * sizeof (ulong))))
ErrorExit (ERR_NOSPACE, NULL, NULL);
i += cnt;
}
FinalInfoSize += sizeof (ulong) * TypeEntries;
// Write the compacted type strings in virtual memory to disk.
#if DBG
i = CV_FIRST_NONPRIM;
#endif
for (TypeBlock = VBufFirstBlock (&TypeBuf);
TypeBlock;
TypeBlock = VBufNextBlock (TypeBlock)) {
for (pchType = TypeBlock->Address,
pchEnd = TypeBlock->Address + TypeBlock->Size; pchType < pchEnd; ) {
usTotal = ((TYPPTR)pchType)->len + LNGTHSZ;
usPad = PAD4 (usTotal);
if ( cb + usTotal + usPad > cbTypeAlign ) {
ushort cbT = cbTypeAlign - cb;
FinalInfoSize += cbT;
DASSERT ( cbT % sizeof ( ulong ) == 0 );
while ( cbT > 0 ) {
if (!BWrite ((uchar *)&ulZero, sizeof ( ulong ))) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
cbT -= sizeof ( ulong );
}
cb = 0;
}
cb += usTotal + usPad;
#if DBG
if (DbArray[8])
DumpPartialType((ushort) i, (TYPPTR) pchType, FALSE);;
i++;
#endif
// Write the type string
if (!BWrite (pchType, usTotal)) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
// Write any padding necessary
if (usPad){
if (!BWrite ((uchar *)&ulZero, usPad)) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
}
// Move to the next type
pchType += usTotal;
FinalInfoSize += usTotal + usPad;
}
}
PadCount = (int)(sizeof(ulong) - (FinalInfoSize % sizeof(ulong)));
if ((PadCount != 4) && !BWrite(&Zero, PadCount)) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
return(FinalInfoSize);
}
LOCAL void WriteSST(ulong i)
{
char *addr;
if (pDir[i].cb) {
if ((addr = (char *) pDir[i].lfo) == NULL) {
ErrorExit(ERR_NOMEM, NULL, NULL);
}
if (!BWrite(addr, pDir[i].cb)) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
}
pDir[i].lfo = filepos - lfoBase;
PadCount = (int)(sizeof(ulong) - (pDir[i].cb % sizeof(ulong)));
if ((PadCount != 4) && !BWrite(&Zero, PadCount)) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
}
/** FixupExeFile - write new Debug OMF to exe
*
* FixupExeFile ()
*
* Entry
*
* Exit
*
* Returns none
*/
void FixupExeFile(void)
{
IMAGE_OPTIONAL_HEADER PEOptHeader;
long newDlfaBase;
long newLfoDir;
PMOD mod;
ulong i;
DASSERT (cSST < UINT_MAX);
// sweep module table and count number of directory entries needed
i = 0;
for (mod = ModuleList; mod != NULL; mod = mod->next) {
i++;
// publics are accumulated and written out later
if (mod->SymbolSize != 0) {
i++;
}
if (mod->SrcLnSize != 0) {
i++;
}
}
// make sure the number of subsections did not increase during the pack.
// Note that the size of the directory is actuall four larger than cSST
// to contain global publics, global symbols, global types and libraries.
DASSERT (i < cSST);
cSST = i;
i = 0;
// sweep the module list and create the directory entries that
// will be written out. Publics are accumulated and written out later
for (mod = ModuleList; mod != NULL; mod = mod->next) {
pDir[i].SubSection = sstModule;
pDir[i].iMod = mod->ModuleIndex;
pDir[i].lfo = (ulong)mod->ModulesAddr;
pDir[i].cb = mod->ModuleSize;
i++;
if (mod->SymbolSize != 0) {
pDir[i].SubSection = sstAlignSym;
pDir[i].iMod = mod->ModuleIndex;
pDir[i].cb = mod->SymbolSize;
pDir[i].lfo = (ulong)mod->SymbolsAddr;
i++;
}
if (mod->SrcLnSize != 0) {
pDir[i].SubSection = sstSrcModule;
pDir[i].iMod = mod->ModuleIndex;
pDir[i].cb = mod->SrcLnSize;
pDir[i].lfo = (ulong)mod->SrcLnAddr;
cbSrcModule += mod->SrcLnSize;
i++;
}
}
if (verbose) {
printf(get_err(MSG_LASIZE), "\t\t", cbSrcModule, '\n');
}
// sort directory by type placing module entries first
qsort(pDir, (size_t) cSST, sizeof(OMFDirEntry), sstsort);
// round up base address
lfoBase = ((lfoBase + sizeof (ulong) - 1) / sizeof (ulong)) * sizeof (ulong);
if (link_lseek (exefile, lfoBase, SEEK_SET) == -1L) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
// CAUTION:
// We are doing buffering of our writes from this call
// InitWriteBuf() to nearly the end of the function when
// CloseWriteBuf() is called. Between this points there should
// be no writing to the exefile except via BWrite(). Also, it
// is assumed that all these writes that are taking place are
// consecutive writes. So there should not be any lseek between
// these two points.
InitWriteBuf (exefile);
if (!BWrite ((char *)NewSig, 8)) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
// write out all subsection tables except accumulated publics table,
// the global symbol table, the libraries table and the compacted
// types table.
filepos = Btell (exefile);
for (i = 0; i < cSST; i++) {
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
/*
** If this sstSection is too large just elmininate it
*/
if (!fLinearExe && pDir[i].cb > 0xFFFF) {
PMOD pModT;
for ( pModT = ModuleList; pModT; pModT = pModT->next ) {
if ( pModT->ModuleIndex == pDir[i].iMod ) {
break;
}
}
switch ( pDir[i].SubSection ) {
case sstAlignSym :
Warn ( WARN_SECTIONLONG, "symbols", FormatMod ( pModT ) );
break;
case sstSrcModule :
Warn ( WARN_SECTIONLONG, "source lines", FormatMod ( pModT ) );
break;
default :
Warn ( WARN_SECTIONLONG, NULL, FormatMod ( pModT ) );
}
pDir[i].cb = 0;
}
WriteSST (i);
}
filepos = Btell (exefile);
WritePublics (&pDir[cSST], filepos - lfoBase);
cSST++;
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
WriteGlobalSym (&pDir[cSST], filepos - lfoBase);
cSST++;
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
WriteStaticSym (&pDir[cSST], filepos - lfoBase);
cSST++;
// write libraries SST
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
pDir[cSST].SubSection = sstLibraries;
pDir[cSST].iMod = (ushort) -1;
pDir[cSST].lfo = (ulong)Libraries;
pDir[cSST].cb = LibSize;
WriteSST (cSST);
// write compacted types table
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
cSST++;
pDir[cSST].SubSection = sstGlobalTypes;
pDir[cSST].iMod = (ushort) -1;
pDir[cSST].cb = WriteTypes ();
pDir[cSST].lfo = filepos - lfoBase;
if (verbose) {
printf(get_err(MSG_TYPESIZE), "\t\t", InitialTypeInfoSize, '\n', "\t\t", pDir[cSST].cb, '\n');
}
// write sstSegMap table
if (SegMap != NULL) {
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
cSST++;
pDir[cSST].SubSection = sstSegMap;
pDir[cSST].iMod = (ushort) -1;
pDir[cSST].lfo = (ulong)SegMap;
pDir[cSST].cb = SegMapSize;
WriteSST (cSST);
}
// write sstSegName table
if (SegName != NULL) {
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
cSST++;
pDir[cSST].SubSection = sstSegName;
pDir[cSST].iMod = (ushort) -1;
pDir[cSST].lfo = (ulong)SegName;
pDir[cSST].cb = SegNameSize;
WriteSST (cSST);
}
// Write sstFileIndex table
if (FileIndex != NULL) {
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
cSST++;
pDir[cSST].SubSection = sstFileIndex;
pDir[cSST].iMod = (ushort) -1;
pDir[cSST].lfo = (ulong)FileIndex;
pDir[cSST].cb = FileIndexSize;
WriteSST (cSST);
}
filepos = Btell (exefile);
DASSERT ((filepos % sizeof (ulong)) == 0);
cSST++;
// write out number of pDir entries and pDir entries
DirHead.cbDirHeader = sizeof (OMFDirHeader);
DirHead.cbDirEntry = sizeof (OMFDirEntry);
DirHead.cDir = cSST;
DirHead.lfoNextDir = 0;
DirHead.flags = 0;
newLfoDir = Btell (exefile) - lfoBase;
DASSERT ((newLfoDir % sizeof (ulong)) == 0);
if (!BWrite ((char *)&DirHead, sizeof (OMFDirHeader)) ||
!BWrite ((char *) pDir, (sizeof (OMFDirEntry) * DirHead.cDir))) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
newDlfaBase = Btell (exefile) + 8 - lfoBase;
DASSERT ((newDlfaBase % sizeof (ulong)) == 0);
if ((!BWrite ((char *)&NewSig, sizeof (long))) ||
(!BWrite ((char *)&newDlfaBase, sizeof (long)))) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
// Write Buffering ends.
if (!CloseWriteBuf ())
ErrorExit (ERR_NOSPACE, NULL, NULL);
lfoNewEnd = link_tell (exefile);
if (fLinearExe) {
IMAGE_SECTION_HEADER o32obj;
IMAGE_DEBUG_DIRECTORY dbgDir;
ULONG dwFileAlign;
if ( lfoDebugSection ) {
if (link_lseek(exefile, lfoPEOptHeader, SEEK_SET) == -1L) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_read(exefile, &PEOptHeader, PEHeader.SizeOfOptionalHeader) !=
PEHeader.SizeOfOptionalHeader) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
dwFileAlign = PEOptHeader.FileAlignment;
if (lfoNewEnd % dwFileAlign) {
lfoNewEnd = (lfoNewEnd + dwFileAlign - 1) & ~(dwFileAlign -1);
newDlfaBase = lfoNewEnd - lfoBase;
if ( (link_lseek( exefile,
lfoNewEnd - (2 * sizeof(long)),
SEEK_SET) == -1L) ||
(link_write( exefile,
&NewSig,
sizeof(long)) != sizeof(long)) ||
(link_write( exefile,
&newDlfaBase,
sizeof(long)) != sizeof(long))) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
}
}
if ( link_lseek ( exefile, lfoDebugObject, SEEK_SET ) == -1L ) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if ( link_read ( exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER )
!= IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if ( link_lseek (
exefile,
o32obj.PointerToRawData + rvaDebugDir,
SEEK_SET ) == -1L
) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_read(exefile, &dbgDir, sizeof (IMAGE_DEBUG_DIRECTORY )) !=
sizeof (IMAGE_DEBUG_DIRECTORY)) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
dbgDir.SizeOfData = newDlfaBase;
if ( link_lseek (
exefile,
o32obj.PointerToRawData + rvaDebugDir,
SEEK_SET ) == -1L
) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_write(exefile, &dbgDir, sizeof (IMAGE_DEBUG_DIRECTORY)) !=
sizeof (IMAGE_DEBUG_DIRECTORY )) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
// Write modified header that defines the total size of the
// image.
// Modify the debug section information since we have changed
// size of the raw data
if ( lfoDebugSection ) {
LONG dbSizeRaw = lfoNewEnd - lfoOldEnd;
ULONG dwSizeImage;
ULONG dwSectAlign;
if (link_lseek(exefile, lfoDebugSection, SEEK_SET) == -1L) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_read(exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER )
!= IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
o32obj.SizeOfRawData = lfoNewEnd - o32obj.PointerToRawData;
o32obj.Misc.VirtualSize = o32obj.SizeOfRawData;
if (link_lseek(exefile, lfoDebugSection, SEEK_SET) == -1L) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_write(exefile, &o32obj, IMAGE_SIZEOF_SECTION_HEADER) !=
IMAGE_SIZEOF_SECTION_HEADER) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
dwSizeImage = o32obj.Misc.VirtualSize + o32obj.VirtualAddress;
dwSectAlign = PEOptHeader.SectionAlignment;
if ( dwSizeImage % dwSectAlign ) {
dwSizeImage += dwSectAlign - ( dwSizeImage % dwSectAlign );
}
PEOptHeader.SizeOfImage = dwSizeImage;
if (link_lseek(exefile, lfoPEOptHeader, SEEK_SET) == -1L) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
if (link_write(exefile, &PEOptHeader, PEHeader.SizeOfOptionalHeader) !=
PEHeader.SizeOfOptionalHeader) {
ErrorExit(ERR_NOSPACE, NULL, NULL);
}
}
}
DASSERT ((lfoNewEnd % sizeof (ulong)) == 0);
link_chsize (exefile, lfoNewEnd);
if ((link_lseek (exefile, lfoBase + sizeof (long), SEEK_SET) == -1L) ||
(link_write (exefile, (char *)&newLfoDir, sizeof (long)) != sizeof (long))) {
ErrorExit (ERR_NOSPACE, NULL, NULL);
}
}