/* * to build module list * * */ #undef FAR #include #include #include "compact.h" #include "exehdr.h" #include "writebuf.h" #define IMAGE_DEBUG_TYPE_MISC 4 #define FileAlign(a) (((a) + 511) & ~511) enum SIG { SIG02 = 0, // NB02 signature SIG05, // NB05 signature SIG06 // NB06 signature }; uchar Signature[4]; uchar NewSig[ 8] = "NB08"; ushort ModuleIndex; uchar fLinearExe = FALSE; OMFDirEntry * pDir; _vmhnd_t Libraries = _VM_NULL; _vmhnd_t SegMap = _VM_NULL; _vmhnd_t SegName = _VM_NULL; ulong LibSize = 0; ulong SegMapSize = 0; ulong SegNameSize = 0; ushort cMod = 0; OMFDirHeader DirHead = {0}; ulong SeekCount; PMOD ModuleList = NULL; extern ushort NewIndex; ushort Sig; // signature enumeration long cbSrcModule = 0; PACKDATA *PackOrder = NULL; ulong lfoObject; ulong lfoHeader; LOCAL ushort CheckSignature (void); LOCAL int _CRTAPI1 modsort02 (const void *, const void *); LOCAL int _CRTAPI1 modsort (const void *, const void *); LOCAL int _CRTAPI1 sstsort (const void *, const void *); LOCAL ulong WriteTypes (void); LOCAL void WriteSST (ulong); LOCAL void ReadNB02 (void); LOCAL void ReadNB05 (bool_t); #if defined (INCREMENTAL) LOCAL void ReadNB06 (void); LOCAL void RestoreNB05 (void); LOCAL void RestoreGlobalTypes (OMFDirEntry *); LOCAL void RestoreGlobalPub (OMFDirEntry *); LOCAL void RestoreGlobalSym (OMFDirEntry *); LOCAL void RestoreTable (PMOD, OMFDirEntry *); #endif LOCAL void SetTableSizes (void); LOCAL void CopyTable (OMFDirEntry *, _vmhnd_t *, ulong *); LOCAL ulong lfoDbgDirBase; // table for sorting NB02 subsection tables int MapArray02 [9][9] = { { 0, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 0, 1, -1, -1, -1, -1, -1, -1}, { 1, -1, 0, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 0, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 0, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 0, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 0, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 0, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 0} }; // table for sorting NB05 subsection tables int MapArray [17][17] = { { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, }; char Zero[4] = {0}; int PadCount; IMAGE_SECTION_HEADER secHdrDebug; // .debug section header BOOL bDebugDirPresent = FALSE; struct { BOOL exists; IMAGE_DEBUG_DIRECTORY dbgDir; IMAGE_COFF_SYMBOLS_HEADER dbgInfo; ULONG lfo; ULONG cb; char * pb; } DbgDataCoff; struct { BOOL exists; IMAGE_DEBUG_DIRECTORY dbgDir; ULONG lfo; ULONG cb; char * pb; } DbgDataFpo; struct { BOOL exists; IMAGE_DEBUG_DIRECTORY dbgDir; ULONG lfo; ULONG cb; char * pb; } DbgDataMisc; /** 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 */ void ReadDir (void) { long dlfaBase; ushort segremain = 0; struct exe_hdr exehdr; IMAGE_NT_HEADERS pehdr; ulong cbCur = 0; ulong i; uint cbAlloc; ulong loc; /* * Try reading in a DOS (MZ) header */ filepos = 0; if ((lseek (exefile, 0L, SEEK_SET) == -1L) || (read (exefile, &exehdr, sizeof (struct exe_hdr)) != sizeof (struct exe_hdr))) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } if (exehdr.e_magic == EMAGIC) { /* * Got a DOS header now see if there is a pointer to a newer * header. We are specifically looking for a PE header as * the rules for finding the debug informationare different. */ if ((lseek (exefile, exehdr.e_lfanew, SEEK_SET) != -1L) && (read (exefile, &pehdr, sizeof (pehdr)) == sizeof (pehdr))) { if (pehdr.Signature == IMAGE_NT_SIGNATURE) { fLinearExe = TRUE; } lfoHeader = exehdr.e_lfanew; } } /* * It may be that there was not dos header and the exe started with * a PE image header. */ else if (exehdr.e_magic == IMAGE_NT_SIGNATURE) { lseek( exefile, 0, SEEK_SET); if (read(exefile, &pehdr, sizeof(pehdr)) != sizeof(pehdr)) { ErrorExit(ERR_INVALIDEXE, NULL, NULL); } if (pehdr.Signature == IMAGE_NT_SIGNATURE) { fLinearExe = TRUE; } else { ErrorExit(ERR_INVALIDEXE, NULL, NULL); } lfoHeader = exehdr.e_lfanew; } /* * Move the file pointer to the debug information. For non-PE files * this is simple. Seek to the end of the file and look for the * CVInfo signature. For PE files we need to process through the * header looking for the section with the debug information descriptors */ if (fLinearExe) { int cObjs; IMAGE_SECTION_HEADER secHdr; IMAGE_DEBUG_DIRECTORY dbgDir; ULONG offDbgDir; ULONG lfoObjDir = tell(exefile); if (pehdr.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) { lseek( exefile, pehdr.FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER), SEEK_CUR); } /* * find the .debug section as save it away. it will be needed when the * coff & fpo data is written out so that the debug directory entries * can be fixup to have the correct file pointer and virtual address */ for (cObjs = pehdr.FileHeader.NumberOfSections; cObjs != 0; cObjs -= 1) { if (read(exefile, &secHdrDebug, sizeof(secHdrDebug)) != sizeof(secHdrDebug)) { ErrorExit( ERR_INVALIDEXE, NULL, NULL); } if (strncmp(".debug", secHdrDebug.Name, 6) == 0) { bDebugDirPresent = TRUE; break; } } lseek(exefile, lfoObjDir, SEEK_SET); if (pehdr.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) { lseek( exefile, pehdr.FileHeader.SizeOfOptionalHeader - sizeof(IMAGE_OPTIONAL_HEADER), SEEK_CUR); } /* ** Now at the table of object descriptors, scan through each ** descriptor looking for the debug information */ for (cObjs = pehdr.FileHeader.NumberOfSections; cObjs != 0; cObjs -= 1) { if (read(exefile, &secHdr, sizeof(secHdr)) != sizeof(secHdr)) { ErrorExit( ERR_INVALIDEXE, NULL, NULL); } if ((secHdr.VirtualAddress <= pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) && (pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress < secHdr.VirtualAddress + secHdr.SizeOfRawData)) { break; } } if (cObjs == 0) { ErrorExit( ERR_INVALIDEXE, NULL, NULL); } /* * Seek to the point where the debug directory is and read it in * looking for a CV4 debug info directory entry. */ offDbgDir = secHdr.PointerToRawData + pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress - secHdr.VirtualAddress; if (lseek(exefile, offDbgDir, SEEK_SET) == -1L) { ErrorExit( ERR_INVALIDEXE, NULL, NULL); } for (i=0; i 0x10000 / sizeof (PACKDATA)) { // for dos only (mikeol) if (cMod > 0x10000) { DASSERT (FALSE); ErrorExit (ERR_INVALIDEXE, NULL, NULL); } if ((PackOrder = (PACKDATA *)CAlloc (cMod * sizeof (PACKDATA))) == 0) { ErrorExit (ERR_NOMEM, NULL, NULL); } iMod = 0; iPData = 0; if (fPreComp == TRUE) { // 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: // precomp is not allowed with an NB02 linker DASSERT (FALSE); ErrorExit (ERR_INVALIDEXE, NULL, NULL); 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, TRUE); iPData++; break; default: break; } } } for (i = 0; i < cSST; i++) { // now sweep through the directory and add all modules that were // not added in the first pass switch (pDir[i].SubSection) { case SSTMODULE: case 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, TRUE); iPData++; } break; default: break; } } } /** 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)VmAlloc (pDir->cb)) == _VM_NULL) { ErrorExit (ERR_NOMEM, NULL, NULL); } if ((pTable = (char *)VmLoad (TableAddr, _VM_DIRTY)) == NULL) { ErrorExit (ERR_NOMEM, NULL, NULL); } lseek (exefile, pDir->lfo + lfoBase, SEEK_SET); if (read (exefile, pTable, pDir->cb) != (int)pDir->cb) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } *pAddr = TableAddr; *pSize = pDir->cb; } /** Get module - find or create module entry in list * * pMod = GetModule (iMod, fAdd) * * 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, bool_t fAdd) { 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); } else if (ptr->ModuleIndex > iMod) { break; } prev = ptr; ptr = ptr->next; } // since the module was not found, create a blank ModuleList entry if (fAdd == TRUE) { new = (PMOD) malloc (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); } else { ErrorExit (ERR_NEWMOD, NULL, NULL); } } /** FixupExeFile - write new Debug OMF to exe * * FixupExeFile () * * Entry * * Exit * * Returns none */ void FixupExeFile () { long newDlfaBase; long newLfoDir; PMOD mod; ulong i; ulong cbDbgInfo; DWORD dwVirtualAddress = 0; DWORD dwPointerToRawData = 0; dwVirtualAddress = secHdrDebug.VirtualAddress; dwPointerToRawData = secHdrDebug.PointerToRawData; /* * Write out any MISC debug information which may * have been saved */ if (DbgDataMisc.exists) { if (lseek(exefile, dwPointerToRawData, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } if (write(exefile, DbgDataMisc.pb, DbgDataMisc.cb) != (int) DbgDataMisc.cb) { ErrorExit(ERR_NOSPACE, NULL, NULL); } lfoBase = lseek(exefile, 0, SEEK_CUR); if (lseek(exefile, DbgDataMisc.lfo, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } DbgDataMisc.dbgDir.AddressOfRawData = dwVirtualAddress; DbgDataMisc.dbgDir.PointerToRawData = dwPointerToRawData; if (bDebugDirPresent) { dwVirtualAddress += DbgDataMisc.dbgDir.SizeOfData; } dwPointerToRawData += DbgDataMisc.dbgDir.SizeOfData; if (write(exefile, &DbgDataMisc.dbgDir, sizeof(DbgDataMisc.dbgDir)) != sizeof(DbgDataMisc.dbgDir)) { ErrorExit(ERR_NOSPACE, NULL, NULL); } } /* * Write out any FPO debug information which may * have been saved */ if (DbgDataFpo.exists) { if (lseek(exefile, dwPointerToRawData, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } if (write(exefile, DbgDataFpo.pb, DbgDataFpo.cb) != (int) DbgDataFpo.cb) { ErrorExit(ERR_NOSPACE, NULL, NULL); } lfoBase = lseek(exefile, 0, SEEK_CUR); if (lseek(exefile, DbgDataFpo.lfo, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } DbgDataFpo.dbgDir.AddressOfRawData = dwVirtualAddress; DbgDataFpo.dbgDir.PointerToRawData = dwPointerToRawData; if (bDebugDirPresent) { dwVirtualAddress += DbgDataFpo.dbgDir.SizeOfData; } dwPointerToRawData += DbgDataFpo.dbgDir.SizeOfData; if (write(exefile, &DbgDataFpo.dbgDir, sizeof(DbgDataFpo.dbgDir)) != sizeof(DbgDataFpo.dbgDir)) { ErrorExit(ERR_NOSPACE, NULL, NULL); } } /* * Write out any COFF debug information which may have been saved * * The pointer to raw data and address of raw data fields will not * be changed. Only the size of data field should be changes. * * Size of data includes both the data and the header. */ if (DbgDataCoff.exists) { IMAGE_DEBUG_DIRECTORY dbgDir = {0}; IMAGE_NT_HEADERS pehdr; if ((lseek(exefile, lfoHeader, SEEK_SET) == -1) || (read(exefile, &pehdr, sizeof(pehdr)) != sizeof(pehdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } if (lseek(exefile, dwPointerToRawData, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } DbgDataCoff.dbgInfo.LvaToFirstSymbol = sizeof(DbgDataCoff.dbgInfo); DbgDataCoff.dbgInfo.NumberOfLinenumbers = 0; DbgDataCoff.dbgInfo.LvaToFirstLinenumber = 0; if (write(exefile, &DbgDataCoff.dbgInfo, sizeof(DbgDataCoff.dbgInfo)) != sizeof(DbgDataCoff.dbgInfo)) { ErrorExit(ERR_NOSPACE, NULL, NULL); } pehdr.FileHeader.PointerToSymbolTable = lseek(exefile, 0, SEEK_CUR); if (write(exefile, DbgDataCoff.pb, DbgDataCoff.cb) != (int) DbgDataCoff.cb) { ErrorExit(ERR_NOSPACE, NULL, NULL); } lfoBase = lseek(exefile, 0, SEEK_CUR); DbgDataCoff.dbgDir.SizeOfData = DbgDataCoff.cb + sizeof(DbgDataCoff.dbgInfo); DbgDataCoff.dbgDir.AddressOfRawData = dwVirtualAddress; DbgDataCoff.dbgDir.PointerToRawData = dwPointerToRawData; if (bDebugDirPresent) { dwVirtualAddress += DbgDataCoff.dbgDir.SizeOfData; } dwPointerToRawData += DbgDataCoff.dbgDir.SizeOfData; if (lseek(exefile, DbgDataCoff.lfo, SEEK_SET) == -1) { ErrorExit(ERR_NOSPACE, NULL, NULL); } if (write(exefile, &DbgDataCoff.dbgDir, sizeof(DbgDataCoff.dbgDir)) != sizeof(DbgDataCoff.dbgDir)) { ErrorExit(ERR_NOSPACE, NULL, NULL); } /* * */ if ((lseek(exefile, lfoHeader, SEEK_SET) == -1) || (write(exefile, &pehdr, sizeof(pehdr)) != sizeof(pehdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } } /* * */ 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++; } } #ifndef WINDOWS if (logo == TRUE) { printf ("Line/Address size = %8.ld\n", cbSrcModule); } #endif // 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 (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 (); for (i = 0; i < cSST; i++) { filepos = BTell (); DASSERT ((filepos % sizeof (ulong)) == 0); WriteSST (i); } filepos = BTell (); WritePublics (&pDir[cSST], filepos - lfoBase); cSST++; filepos = BTell (); DASSERT ((filepos % sizeof (ulong)) == 0); WriteGlobalSym (&pDir[cSST], filepos - lfoBase); cSST++; // write libraries SST filepos = BTell (); 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 (); DASSERT ((filepos % sizeof (ulong)) == 0); cSST++; pDir[cSST].SubSection = sstGlobalTypes; pDir[cSST].iMod = (ushort) -1; pDir[cSST].cb = WriteTypes (); pDir[cSST].lfo = filepos - lfoBase; #ifndef WINDOWS if (logo == TRUE) { printf ("Initial type size = %8.ld\n", InitialTypeInfoSize); printf ("Compacted type size = %8.ld\n", pDir[cSST].cb); } #endif // write sstSegMap table if (SegMap != _VM_NULL) { filepos = BTell (); 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 != _VM_NULL) { filepos = BTell (); 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); } filepos = BTell (); 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 () - 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 () + 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); filepos = tell (exefile); DASSERT ((filepos % sizeof (ulong)) == 0); cbDbgInfo = filepos - lfoBase; if (fLinearExe) { filepos = (filepos + 511) & ~(512-1); } /* * Grab the number of bytes in the debug info section */ #ifdef HACK _chsize (exefile, filepos); #else lseek(exefile, filepos, SEEK_SET); SetEndOfFile((HANDLE) _get_osfhandle(exefile)); #endif if ((lseek (exefile, lfoBase + sizeof (long), SEEK_SET) == -1L) || (write (exefile, (char *)&newLfoDir, sizeof (long)) != sizeof (long))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } /* * If we are a PE exe file then there are two things that need to be * done. In all cases we must rewrite the debug directory entry * to reflect the fact that the cvinfo has been packed. Additionally * if the file is using mapped debug information (i.e. it is part * of a section) then we must update the appropirate header structures. */ if (fLinearExe) { IMAGE_SECTION_HEADER secHdr; IMAGE_DEBUG_DIRECTORY dbgDir; long cbDbgInfoDelta; /* * Update the size of the debug info in the debug header record */ if ((lseek(exefile, lfoDbgDirBase, SEEK_SET) == -1) || (read(exefile, &dbgDir, sizeof(dbgDir)) != sizeof(dbgDir))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } cbDbgInfoDelta = cbDbgInfo - dbgDir.SizeOfData; dbgDir.SizeOfData = cbDbgInfo; dbgDir.PointerToRawData = lfoBase; if (bDebugDirPresent) { dbgDir.AddressOfRawData = dwVirtualAddress; } if ((lseek(exefile, lfoDbgDirBase, SEEK_SET) == -1) || (write(exefile, &dbgDir, sizeof(dbgDir)) != sizeof(dbgDir))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } if (dbgDir.AddressOfRawData != 0) { IMAGE_NT_HEADERS pehdr; /* * Update the Object section header. The fields to be changed * are: Size of Raw Data */ if ((lseek(exefile, lfoObject, SEEK_SET) == -1L) || (read(exefile, &secHdr, sizeof(secHdr)) != sizeof(secHdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } secHdr.Misc.VirtualSize = secHdr.SizeOfRawData = filepos - secHdr.PointerToRawData; if ((lseek(exefile, lfoObject, SEEK_SET) == -1L) || (write(exefile, &secHdr, sizeof(secHdr)) != sizeof(secHdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } /* * */ if ((lseek(exefile, lfoHeader, SEEK_SET) == -1) || (read(exefile, &pehdr, sizeof(pehdr)) != sizeof(pehdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } pehdr.OptionalHeader.SizeOfInitializedData += secHdr.SizeOfRawData; pehdr.OptionalHeader.SizeOfImage = secHdr.VirtualAddress + secHdr.SizeOfRawData; pehdr.OptionalHeader.SizeOfImage = (pehdr.OptionalHeader.SizeOfImage + pehdr.OptionalHeader.SectionAlignment - 1) & ~(pehdr.OptionalHeader.SectionAlignment - 1); if ((lseek(exefile, lfoHeader, SEEK_SET) == -1) || (write(exefile, &pehdr, sizeof(pehdr)) != sizeof(pehdr))) { ErrorExit(ERR_NOSPACE, NULL, NULL); } } } } LOCAL void WriteSST (ulong i) { char *addr; if (pDir[i].cb) { if ((addr = (char *) VmLoad ((_vmhnd_t)pDir[i].lfo, (size_t)pDir[i].cb)) == _VM_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); } } /** CheckSignature - check file signature * * Sig = CheckSignature () * * Entry none * * Exit none * * Return SIG02 if exe has NB02 signature * SIG05 if exe has NB05 signature * SIG06 if exe has NB06 signature * aborts if any other signature */ LOCAL ushort CheckSignature (void) { if (read (exefile, Signature, 4) == 4) { if ((Signature[0] != 'N') || (Signature[1] != 'B') || (Signature[2] != '0') || (Signature[3] < '2') || (Signature[3] == '3') || (Signature[3] == '4') || (Signature[3] == '7')) { ErrorExit (ERR_RELINK, NULL, NULL); } if (Signature[3] == '8') { Warn (WARN_PACKED, NULL, NULL); exit (0); } if (Signature[3] == '2') { return (SIG02); } else if (Signature[3] == '5') { return (SIG05); } #if defined (INCREMENTAL) else if (Signature[3] == '6') { return (SIG06); } #else ErrorExit (ERR_RELINK, NULL, NULL); #endif } ErrorExit (ERR_INVALIDEXE, NULL, NULL); } LOCAL ulong WriteTypes () { ulong FinalInfoSize; VBlock * TypeBlock; ulong TypeEntries = NewIndex - 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; #if 0 ulong **pBuf; ulong cnt; #endif OMFTypeFlags flags = {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 # for (i=0; iAddress, pchEnd = TypeBlock->Address + TypeBlock->Size; pchType < pchEnd; ) { usTotal = ((TYPPTR)pchType)->len + LNGTHSZ; // Write the type string if (!BWrite (pchType, usTotal)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } // Write any padding necessary usPad = PAD4 (usTotal); 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); } /** modsort02 - sort module table for NB02 signature files * */ LOCAL int _CRTAPI1 modsort02 (const void * pv1, const void * pv2) { OMFDirEntry *d1 = (OMFDirEntry *) pv1; OMFDirEntry *d2 = (OMFDirEntry *) pv2; ushort i1; ushort i2; // sort by module index if (d1->iMod < d2->iMod) { return (-1); } else if (d1->iMod > d2->iMod) { return (1); } // if the module indices are equal, sort into order // module, types, symbols, publics, srclnseg i1 = (d1->SubSection) - SSTMODULE; i2 = (d2->SubSection) - SSTMODULE; return (MapArray02[i1][i2]); } LOCAL int _CRTAPI1 sstsort (const void * pv1, const void * pv2) { OMFDirEntry *d1 = (OMFDirEntry *) pv1; OMFDirEntry *d2 = (OMFDirEntry *) pv2; 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); } else if ((d1->SubSection != sstModule) && (d2->SubSection == sstModule)) { return (1); } } // sort by module if (d1->iMod < d2->iMod) { return (-1); } else 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); } else if (d1->SubSection > d2->SubSection) { return (1); } return (0); } LOCAL int _CRTAPI1 modsort (const void * pv1, const void * pv2) { OMFDirEntry *d1 = (OMFDirEntry *) pv1; OMFDirEntry *d2 = (OMFDirEntry *) pv2; ushort i1; ushort i2; // sort by module index DASSERT ((d1->SubSection >= sstModule) && (d1->SubSection <= sstPreCompMap)); DASSERT ((d2->SubSection >= sstModule) && (d2->SubSection <= sstPreCompMap)); if (d1->iMod < d2->iMod) { return (-1); } else if (d1->iMod > d2->iMod) { return (1); } // if the module indices are equal, sort into order // module, types, symbols, publics, srclnseg i1 = (d1->SubSection) - sstModule; i2 = (d2->SubSection) - sstModule; return (MapArray[i1][i2]); } /** ReadNB02 - read file with NB02 signature * * */ LOCAL void ReadNB02 (void) { ulong i; DirEntry Dir; ulong cnt; // locate directory, read number of entries, allocate space, read // directory entries and sort into ascending module index order if ((read (exefile, (char *)&lfoDir, sizeof (long)) != sizeof (long)) || (lseek (exefile, lfoDir + lfoBase, SEEK_SET) == -1L) || (read (exefile, (char *)&cSST, 2) != 2)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } // reformat directory entries one entry at a time cnt = (cSST + 6) * sizeof (OMFDirEntry); DASSERT (cnt <= UINT_MAX); if ((pDir = (OMFDirEntry *)malloc ((size_t)cnt)) == NULL) { ErrorExit (ERR_NOMEM, NULL, NULL); } for (i = 0; i < cSST; i++) { if (read (exefile, (char *)&Dir, sizeof (DirEntry)) != sizeof (DirEntry)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } pDir[i].SubSection = Dir.SubSectionType; pDir[i].iMod = Dir.ModuleIndex; pDir[i].lfo = Dir.lfoStart; pDir[i].cb = (ulong)Dir.Size; } qsort (pDir, (size_t)cSST, sizeof (OMFDirEntry), modsort02); } /** ReadNB05 - read file with NB05 signature * * */ LOCAL void ReadNB05 (bool_t fSort) { 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 ((read (exefile, (char *)&lfoDir, sizeof (long)) != sizeof (long)) || (lseek (exefile, lfoDir + lfoBase, SEEK_SET) == -1L) || (read (exefile, (char *)&DirHead, sizeof (DirHead)) != sizeof (OMFDirHeader))) { 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 *)malloc ((size_t)cnt)) == NULL) { ErrorExit (ERR_NOMEM, NULL, NULL); } if (read (exefile, (char *)pDir, (size_t)(sizeof (OMFDirEntry) * cSST)) != (int)(sizeof (OMFDirEntry) * cSST)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } if (fSort) { 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; } else { tMod = pDir[i].iMod; } } } } if (i != cSST) { qsort (pDir, (size_t)cSST, sizeof (OMFDirEntry), modsort); } } } /** ReadNB06 - read next directory from file with NB06 signature * * */ LOCAL void ReadNB06 (void) { // locate directory, read number of entries, read directory // entries and sort into ascending module index order if ((lseek (exefile, lfoBase + DirHead.lfoNextDir, SEEK_SET) == -1L) || (read (exefile, (char *)&DirHead, sizeof (DirHead)) != sizeof (OMFDirHeader))) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } if (cSST < DirHead.cDir) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cSST = DirHead.cDir; // read directory into memory and then sort into ascending module order if (read (exefile, (char *)pDir, (size_t)(sizeof (OMFDirEntry) * cSST)) != (int)(sizeof (OMFDirEntry) * cSST)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } qsort (pDir, (size_t)cSST, sizeof (OMFDirEntry), modsort); } #if defined (INCREMENTAL) /** RestoreNB05 - restore original cvpack tables * * RestoreNB05 () * * Entry pDir = pointer to directory table * * Exit cMod = number of modules * 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 * For other valid tables, the module table entry is built, * the table is read into memory and the prober values established * * Returns none */ LOCAL void RestoreNB05 (void) { ushort i; ushort oldMod; PMOD pMod; // determine number of modules in file. Remember that module indices // of 0 and 0xffff are not for actual modules cMod = 0; for (i = 0; i < cSST; i++) { if ((pDir[i].iMod != 0) && (pDir[i].iMod != 0xffff)) { if (pDir[i].iMod != oldMod) { oldMod = pDir[i].iMod; pMod = GetModule (pDir[i].iMod, TRUE); } } switch (pDir[i].SubSection) { case sstModule: cMod++; case sstAlignSym: case sstSrcModule: RestoreTable (pMod, &pDir[i]); break; case sstGlobalTypes: RestoreGlobalTypes (&pDir[i]); break; case sstGlobalSym: RestoreGlobalSym (&pDir[i]); break; case sstGlobalPub: RestoreGlobalPub(&pDir[i]); 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); } } } /** RestoreTable - copy table to VM * * RestoreTable (pMod, pDir); * * Entry pMod = pointer to module table entry * pDir = address of directory entry * * Exit pDir->lfo = address of rewritten table * pDir->Size = size of rewritten table * * Return none * */ LOCAL void RestoreTable (PMOD pMod, OMFDirEntry *pDir) { _vmhnd_t TableAddr; char *pTable; if ((TableAddr = (_vmhnd_t)VmAlloc (pDir->cb)) == _VM_NULL) { ErrorExit (ERR_NOVM, NULL, NULL); } if ((pTable = (char *)VmLoad (TableAddr, _VM_DIRTY)) == NULL) { ErrorExit (ERR_NOVM, NULL, NULL); } lseek (exefile, pDir->lfo + lfoBase, SEEK_SET); if (read (exefile, pTable, pDir->cb) != (int)pDir->cb) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } switch (pDir->SubSection) { case sstModule: pMod->ModulesAddr = (ulong)TableAddr; pMod->ModuleSize = pDir->cb; break; case sstAlignSym: pMod->SymbolSize = pDir->cb; pMod->SymbolsAddr = (ulong)TableAddr; break; case sstSrcModule: pMod->SrcLnAddr = (ulong)TableAddr; pMod->SrcLnSize = pDir->cb; break; } } LOCAL void RestoreGlobalTypes (OMFDirEntry *pDir) { long cType; long cbType; ushort cb; long pos; size_t pad; long temp; plfClass plf; uchar **pBuf; TYPPTR pType; CV_typ_t i; if ((lseek (exefile, pDir->lfo + lfoBase, SEEK_SET) == -1L) || (read (exefile, (char *)&cType, sizeof (cType)) != sizeof (cType))) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbType = pDir->cb - sizeof (ulong) * (cType + 1); if (lseek (exefile, cType * sizeof (ulong), SEEK_CUR) == -1L) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } while (cbType > 0) { cType--; if (read (exefile, &cb, sizeof (cb)) != sizeof (cb)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbType -= cb + sizeof (cb); RestoreIndex (cb); pos = tell (exefile); if ((pad = (size_t)PAD4 (pos)) != 0) { read (exefile, (char *)&temp, pad); cbType -= pad; } } for (i = CV_FIRST_NONPRIM; i < NewIndex; i++) { pBuf = pGType[(i - CV_FIRST_NONPRIM) / GTYPE_INC]; pType = (TYPPTR)pBuf[(i - CV_FIRST_NONPRIM) % GTYPE_INC]; if ((pType->leaf == LF_CLASS) || (pType->leaf == LF_STRUCTURE)) { plf = (plfClass)&(pType->leaf); DoDerivationList (i, plf->field); } } } LOCAL void RestoreGlobalPub (OMFDirEntry *pDir) { OMFSymHash hash; long cbSym; uchar SymBuf[512]; int cb; if ((lseek (exefile, pDir->lfo + lfoBase, SEEK_SET) == -1L) || (read (exefile, (char *)&hash, sizeof (OMFSymHash)) != sizeof (OMFSymHash))) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbSym = hash.cbSymbol; while (cbSym > 0) { if (read (exefile, &cb, sizeof (cb)) != sizeof (cb)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } *(ushort *)&SymBuf = cb; if (read (exefile, &SymBuf[2], cb) != cb) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbSym -= cb + sizeof (cb); if (PackPublic ((SYMPTR)&SymBuf, HASHFUNCTION) != GPS_added) { DASSERT (FALSE); ErrorExit (ERR_INVALIDEXE, NULL, NULL); } } } LOCAL void RestoreGlobalSym (OMFDirEntry *pDir) { OMFSymHash hash; long cbSym; uchar SymBuf[512]; int cb; if ((lseek (exefile, pDir->lfo + lfoBase, SEEK_SET) == -1L) || (read (exefile, (char *)&hash, sizeof (OMFSymHash)) != sizeof (OMFSymHash))) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbSym = hash.cbSymbol; while (cbSym > 0) { if (read (exefile, &cb, sizeof (cb)) != sizeof (cb)) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } *(ushort *)&SymBuf = cb; if (read (exefile, &SymBuf[2], cb) != cb) { ErrorExit (ERR_INVALIDEXE, NULL, NULL); } cbSym -= cb + sizeof (cb); if (PackSymbol ((SYMPTR)&SymBuf, HASHFUNCTION) != GPS_added) { DASSERT (FALSE); ErrorExit (ERR_INVALIDEXE, NULL, NULL); } } } #endif