mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1032 lines
23 KiB
1032 lines
23 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
|
|
*
|
|
* File: image.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* This file contains functions that manipulate the image data structure.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
#include "image_.h" // private definitions
|
|
|
|
|
|
const BYTE DosHeaderArray[] = {
|
|
0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
|
|
0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
#ifdef JAPAN
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
|
|
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x82, 0xb1,
|
|
0x82, 0xcc, 0x83, 0x76, 0x83, 0x8d, 0x83, 0x4f, 0x83, 0x89, 0x83, 0x80, 0x82, 0xcd, 0x81, 0x41,
|
|
0x4d, 0x53, 0x2d, 0x44, 0x4f, 0x53, 0x20, 0x83, 0x82, 0x81, 0x5b, 0x83, 0x68, 0x82, 0xc5, 0x82,
|
|
0xcd, 0x8e, 0xc0, 0x8d, 0x73, 0x82, 0xc5, 0x82, 0xab, 0x82, 0xdc, 0x82, 0xb9, 0x82, 0xf1, 0x81,
|
|
0x42, 0x20, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
#else // !JAPAN
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
|
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
|
|
'i', 's', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
|
|
't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
|
|
'm', 'o', 'd', 'e', 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
#endif // !JAPAN
|
|
|
|
0x50, 0x45, 0x00, 0x00 // PE Signature
|
|
};
|
|
|
|
#define cbDosHeaderArray sizeof(DosHeaderArray)
|
|
|
|
const LONG DosHeaderSize = cbDosHeaderArray;
|
|
|
|
static const BYTE MacDosHeaderArray[] = {
|
|
0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
|
|
0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
|
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
|
|
'i', 's', ' ', 'p', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'i', 's', ' ', 'a', ' ',
|
|
'M', 'a', 'c', 'i', 'n', 't', 'o', 's', 'h', ' ', 'E', 'X', 'E', 0x2e, 0x0d, 0x0d,
|
|
0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x50, 0x45, 0x00, 0x00 // PE Signature
|
|
};
|
|
|
|
#define cbMacDosHeaderArray sizeof(MacDosHeaderArray);
|
|
|
|
|
|
void
|
|
InitImage (
|
|
IN OUT PPIMAGE ppimage,
|
|
IN IMAGET imaget
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an IMAGE structure.
|
|
|
|
Arguments:
|
|
|
|
ppimage - pointer to an image struct ptr.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
// Alloc space & initialize image struct
|
|
|
|
*ppimage = (PIMAGE) Calloc(1, sizeof(IMAGE));
|
|
|
|
(*ppimage)->imaget = imaget;
|
|
|
|
// initialize headers/switches with default values
|
|
|
|
(*ppimage)->pvBase = *ppimage;
|
|
(*ppimage)->MajVersNum = INCDB_MAJVERSNUM;
|
|
(*ppimage)->MinVersNum = INCDB_MINVERSNUM;
|
|
strcpy((*ppimage)->Sig, INCDB_SIGNATURE);
|
|
(*ppimage)->ImgFileHdr = DefImageFileHdr;
|
|
(*ppimage)->ImgOptHdr = DefImageOptionalHdr;
|
|
(*ppimage)->Switch = DefSwitch;
|
|
(*ppimage)->SwitchInfo = DefSwitchInfo;
|
|
|
|
// initialize the symbol table
|
|
InitExternalSymbolTable(&(*ppimage)->pst, celementInChunkSym, cchunkInDirSym);
|
|
InitExternalSymbolTable(&(*ppimage)->pstDirective,
|
|
celementInChunkDirective, cchunkInDirDirective);
|
|
|
|
// initialize libs
|
|
InitLibs(&(*ppimage)->libs);
|
|
|
|
// initialize section list
|
|
(*ppimage)->secs.psecHead = NULL;
|
|
(*ppimage)->secs.ppsecTail = &(*ppimage)->secs.psecHead;
|
|
|
|
switch (imaget) {
|
|
case imagetPE:
|
|
(*ppimage)->pbDosHeader = DosHeaderArray;
|
|
(*ppimage)->cbDosHeader = cbDosHeaderArray;
|
|
(*ppimage)->CbHdr = CbHdrPE;
|
|
(*ppimage)->WriteSectionHeader = WriteSectionHeaderPE;
|
|
(*ppimage)->WriteHeader = WriteHeaderPE;
|
|
break;
|
|
|
|
case imagetVXD:
|
|
(*ppimage)->pbDosHeader = DosHeaderArray;
|
|
(*ppimage)->cbDosHeader = cbDosHeaderArray - 4; // no "PE00" needed
|
|
(*ppimage)->CbHdr = CbHdrVXD;
|
|
(*ppimage)->WriteSectionHeader = WriteSectionHeaderVXD;
|
|
(*ppimage)->WriteHeader = WriteHeaderVXD;
|
|
InitImageVXD(*ppimage);
|
|
break;
|
|
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
}
|
|
|
|
void
|
|
SetMacImage(PIMAGE pimage)
|
|
{
|
|
pimage->pbDosHeader = MacDosHeaderArray;
|
|
pimage->cbDosHeader = cbMacDosHeaderArray;
|
|
}
|
|
|
|
|
|
// incremental init of image
|
|
|
|
void
|
|
IncrInitImage (
|
|
IN OUT PPIMAGE ppimage
|
|
)
|
|
{
|
|
assert(ppimage);
|
|
assert(*ppimage);
|
|
assert((*ppimage)->pst);
|
|
|
|
// init symbol tables
|
|
|
|
IncrInitExternalSymbolTable(&(*ppimage)->pst);
|
|
IncrInitExternalSymbolTable(&(*ppimage)->pstDirective);
|
|
|
|
imodidx = (*ppimage)->imodidx;
|
|
}
|
|
|
|
|
|
// get next addr for Win95
|
|
PVOID
|
|
NextMapAddrWin95 (
|
|
PVOID pvCur
|
|
)
|
|
{
|
|
if (!pvCur) {
|
|
return (PVOID) 0x90000000;
|
|
}
|
|
|
|
if (pvCur < (PVOID) 0xC0000000) {
|
|
return (PVOID) ((BYTE *) pvCur + ILKMAP_MAX);
|
|
} else {
|
|
return (PVOID) (-1);
|
|
}
|
|
}
|
|
|
|
|
|
// return map address for NT
|
|
PVOID
|
|
NextMapAddrWinNT (
|
|
PVOID pvCur
|
|
)
|
|
{
|
|
if (!pvCur) {
|
|
return (PVOID) 0x3FFF0000;
|
|
}
|
|
|
|
if (pvCur < (PVOID) 0x7FFFFFFF) {
|
|
return (PVOID)((BYTE *) pvCur+ILKMAP_MAX);
|
|
} else {
|
|
return (PVOID)(-1);
|
|
}
|
|
}
|
|
|
|
|
|
// returns the next map address to try
|
|
PVOID
|
|
NextMapAddr (
|
|
BOOL fOnWin95,
|
|
PVOID pvCur
|
|
)
|
|
{
|
|
return (fOnWin95 ? NextMapAddrWin95(pvCur) : NextMapAddrWinNT(pvCur));
|
|
}
|
|
|
|
|
|
BOOL
|
|
FVerifyEXE(
|
|
const char *szExe,
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verifies size & timestamp of EXE.
|
|
|
|
Arguments:
|
|
|
|
szExe - name of EXE.
|
|
|
|
pimage - ptr to IMAGE struct.
|
|
|
|
Return Value:
|
|
|
|
TRUE if EXE verified as what was left during previous link.
|
|
|
|
--*/
|
|
|
|
{
|
|
struct _stat statfile;
|
|
|
|
if (_stat(szExe, &statfile) == -1) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "didn't find exe - %s", szExe);
|
|
#endif // INSTRUMENT
|
|
return(FALSE);
|
|
}
|
|
if (pimage->tsExe != (DWORD)statfile.st_mtime ||
|
|
pimage->cbExe != (DWORD)statfile.st_size) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "exe size or timestamp differ - %s", szExe);
|
|
#endif // INSTRUMENT
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
// figure out if we are running on NT
|
|
BOOL
|
|
IsOSWin95 (
|
|
VOID
|
|
)
|
|
{
|
|
DWORD dw = GetVersion();
|
|
|
|
return ( (HIWORD(dw) & ~(0x7FFF)) &&
|
|
(LOBYTE(LOWORD(dw)) >= 0x4) );
|
|
}
|
|
|
|
|
|
void
|
|
DetachMiscFromHeap (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the reverse of AppendMiscToHeap(). Anything
|
|
that could be realloc'ed for instance needs to be
|
|
detached from the heap.
|
|
|
|
The order in which things get detached should be the
|
|
reverse of their attachment.
|
|
|
|
Currently only the string block is detached
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to an image.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BYTE *pbNew;
|
|
|
|
// empty string table
|
|
if (!pimage->pst->blkStringTable.cb) {
|
|
return;
|
|
}
|
|
|
|
// alloc space
|
|
pbNew = (BYTE *) PvAlloc(pimage->pst->blkStringTable.cbAlloc);
|
|
|
|
// copy from heap
|
|
memcpy(pbNew, pimage->pst->blkStringTable.pb,
|
|
pimage->pst->blkStringTable.cb);
|
|
|
|
// free up heap space
|
|
Free(pimage->pst->blkStringTable.pb, Align(sizeof(DWORD),pimage->pst->blkStringTable.cb));
|
|
|
|
// update string blk
|
|
pimage->pst->blkStringTable.pb = pbNew;
|
|
}
|
|
|
|
// sets up for a full ilink
|
|
void
|
|
SetupForFullIlinkBuild (
|
|
PPIMAGE ppimage
|
|
)
|
|
{
|
|
PIMAGE pimageO = (*ppimage); // save a pointer to image on heap
|
|
BOOL fOnWin95 = IsOSWin95(); // figure out if we are on NT
|
|
PVOID pvCur = (PVOID)0;
|
|
DWORD dwErr = 0;
|
|
|
|
// create the private heap
|
|
while ((pvCur = NextMapAddr(fOnWin95, pvCur)) != (PVOID)-1) {
|
|
|
|
if (CreateHeap(pvCur, 0, TRUE, &dwErr) == (PVOID)-1) {
|
|
switch (dwErr) {
|
|
case ERROR_DISK_FULL:
|
|
Warning(NULL, LOWSPACE);
|
|
fINCR = FALSE;
|
|
return;
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
Fatal(NULL, CANTOPENFILE, OutFilename);
|
|
|
|
default: // address busy etc.
|
|
// for Win95 only
|
|
if (fOnWin95 && !FFreeDiskSpace(cbInitialILKMapSize)) {
|
|
Warning(NULL, LOWSPACE);
|
|
fINCR = FALSE;
|
|
return;
|
|
}
|
|
continue;
|
|
} // end switch
|
|
} else {
|
|
break;
|
|
}
|
|
} // end while
|
|
|
|
// check to see if we succeeded in creating the map
|
|
if (pvCur == (PVOID)-1) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "failed to create heap");
|
|
#endif // INSTRUMENT
|
|
PostNote(NULL, UNABLETOCREATEMAP);
|
|
fINCR = FALSE;
|
|
return;
|
|
}
|
|
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "created heap at 0x%.8lx", pvCur);
|
|
#endif // INSTRUMENT
|
|
|
|
// create and initialize image on private heap
|
|
InitImage(ppimage, pimageO->imaget);
|
|
|
|
// transfer switches & related info to image on private heap
|
|
TransferLinkerSwitchValues((*ppimage), pimageO);
|
|
|
|
// free the image on ordinary heap
|
|
FreeImage(&pimageO, FALSE);
|
|
}
|
|
|
|
|
|
// sets up for an incremental ilink
|
|
void
|
|
SetupForIncrIlinkBuild (
|
|
PPIMAGE ppimage,
|
|
PVOID pvbase,
|
|
DWORD cbLen
|
|
)
|
|
{
|
|
PVOID pv;
|
|
PIMAGE pimageN = (*ppimage); // save a pointer to new image on heap
|
|
PST pst;
|
|
DWORD dwErr;
|
|
|
|
// try to create private heap at base specified
|
|
if ((pv = CreateHeap(pvbase, cbLen, FALSE, &dwErr)) == (PVOID)-1) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "failed to create heap at 0x%.8lx", pvbase);
|
|
#endif // INSTRUMENT
|
|
|
|
if (fTest) {
|
|
PostNote(NULL, UNABLETOLOADILK);
|
|
}
|
|
|
|
// failed to create heap at base: try to do a full ilink
|
|
SetupForFullIlinkBuild(ppimage);
|
|
return;
|
|
}
|
|
|
|
// set the base map address
|
|
*ppimage = (PIMAGE) pv;
|
|
|
|
// check the string table ptr and verify nothing beyond it.
|
|
pst = (*ppimage)->pst;
|
|
if (pst->blkStringTable.cb &&
|
|
(!FValidPtrInfo((DWORD)pv, cbLen, (DWORD)pst->blkStringTable.pb, pst->blkStringTable.cb)
|
|
|| (Align(sizeof(DWORD),((DWORD)pst->blkStringTable.pb+pst->blkStringTable.cb-(DWORD)pv)) != cbLen))) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "inavlid ptrs in symbol table");
|
|
#endif // INSTRUMENT
|
|
|
|
if (fTest) {
|
|
PostNote(NULL, CORRUPTILK);
|
|
}
|
|
|
|
// cannot do an incr ilink; try to do a full ilink
|
|
FreeHeap();
|
|
(*ppimage) = pimageN;
|
|
SetupForFullIlinkBuild(ppimage);
|
|
return;
|
|
}
|
|
|
|
// detach string table etc from heap
|
|
DetachMiscFromHeap(*ppimage);
|
|
|
|
// compare switches to see if we can continue
|
|
if (!CheckAndUpdateLinkerSwitches(pimageN, (*ppimage))) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "incompatible switches");
|
|
#endif // INSTRUMENT
|
|
// cannot do an incr ilink; try to do a full ilink
|
|
|
|
if (fTest) {
|
|
PostNote(NULL, LNKOPTIONSCHNG);
|
|
}
|
|
|
|
FreeHeap();
|
|
(*ppimage) = pimageN;
|
|
SetupForFullIlinkBuild(ppimage);
|
|
return;
|
|
}
|
|
|
|
// OK to proceed with incr ilink
|
|
FreeImage(&pimageN, FALSE);
|
|
fIncrDbFile = TRUE;
|
|
}
|
|
|
|
|
|
char *
|
|
SzGenIncrDbFilename (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generates the ILK filename.
|
|
|
|
Either uses -out: specified by user or first name of
|
|
obj file & then uses default name. Incr db name may
|
|
not match output filename if it is specified via
|
|
a directive in one of the objs.
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to an image.
|
|
|
|
Return Value:
|
|
|
|
Pointer to (malloc'ed) name of incr db filename
|
|
|
|
--*/
|
|
{
|
|
char szDrive[_MAX_DRIVE];
|
|
char szDir[_MAX_DIR];
|
|
char szFname[_MAX_FNAME];
|
|
char szIncrDbPath[_MAX_PATH];
|
|
|
|
// Generate incr db filename
|
|
|
|
if (OutFilename == NULL) {
|
|
DWORD i;
|
|
PARGUMENT_LIST arg;
|
|
|
|
// Capture first object name for output filename.
|
|
|
|
for (i = 0, arg = FilenameArguments.First;
|
|
i < FilenameArguments.Count;
|
|
i++, arg = arg->Next) {
|
|
INT Handle;
|
|
BOOL fArchive;
|
|
|
|
Handle = FileOpen(arg->OriginalName, O_RDONLY | O_BINARY, 0);
|
|
fArchive = IsArchiveFile(arg->OriginalName, Handle);
|
|
FileClose(Handle, FALSE);
|
|
|
|
if (fArchive) {
|
|
continue;
|
|
}
|
|
|
|
SetDefaultOutFilename(pimage, arg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (OutFilename == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
assert(OutFilename);
|
|
|
|
_splitpath(OutFilename, szDrive, szDir, szFname, NULL);
|
|
_makepath(szIncrDbPath, szDrive, szDir, szFname, INCDB_EXT);
|
|
|
|
return(SzDup(szIncrDbPath));
|
|
}
|
|
|
|
|
|
void
|
|
SaveStringTable (
|
|
IN PST pst
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Saves the string table.
|
|
|
|
Arguments:
|
|
|
|
pst - pointer to symbol table whose string table is to be saved.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BYTE *pb;
|
|
|
|
// empty string table
|
|
if (!pst->blkStringTable.cb) {
|
|
return;
|
|
}
|
|
|
|
// append long name string table
|
|
pb = (BYTE *) Malloc(pst->blkStringTable.cb);
|
|
memcpy(pb, pst->blkStringTable.pb,
|
|
pst->blkStringTable.cb);
|
|
pst->blkStringTable.pb = pb;
|
|
}
|
|
|
|
|
|
void
|
|
AppendMiscToHeap (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Appends anything that could not be allocated on the heap
|
|
to during the link process. Currently only the long name
|
|
table is appended.
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to an image.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
// save the string table holding all the directives (full-link only)
|
|
if (!fIncrDbFile) {
|
|
SaveStringTable(pimage->pstDirective);
|
|
}
|
|
|
|
// save the string table of the symbols
|
|
SaveStringTable(pimage->pst);
|
|
}
|
|
|
|
|
|
void
|
|
WriteIncrDbFile (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes out an image to database. Assumes that file is open
|
|
if it already existed. Currently simply writes out entire
|
|
image.
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to an image.
|
|
|
|
fExists - TRUE if incr db file already exists.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
assert(FileIncrDbHandle);
|
|
|
|
// copy over long name table (etc.) to heap
|
|
AppendMiscToHeap(pimage);
|
|
|
|
// do cleanup
|
|
CloseHeap();
|
|
|
|
// write out & close file
|
|
FileClose(FileIncrDbHandle, TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
ReadIncrDbFile (
|
|
PPIMAGE ppimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads in an image database. Reads in header alone,
|
|
verifies, read in rest of db.
|
|
|
|
Arguments:
|
|
|
|
ppimage - pointer to an image struct pointer
|
|
|
|
Handle - handle of image file
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
struct _stat statfile;
|
|
IMAGE image;
|
|
HANDLE hFile;
|
|
|
|
// establish name of the db file
|
|
|
|
szIncrDbFilename = SzGenIncrDbFilename(*ppimage);
|
|
if (!szIncrDbFilename) {
|
|
fINCR = FALSE;
|
|
return;
|
|
}
|
|
|
|
// verify that ILK file exists and is valid
|
|
if (!FValidILKFile(szIncrDbFilename, TRUE, &image, &statfile)) {
|
|
// full build possible if ILK is corrupt or has an old format etc.
|
|
if (fINCR) {
|
|
SetupForFullIlinkBuild(ppimage);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// ensure that the previously built EXE is valid and still around.
|
|
assert(OutFilename);
|
|
if (!FVerifyEXE(OutFilename, &image)) {
|
|
PostNote(NULL, FILECHANGED, OutFilename);
|
|
(*ppimage)->Switch.Link.fNotifyFullBuild = FALSE;
|
|
SetupForFullIlinkBuild(ppimage);
|
|
return;
|
|
}
|
|
|
|
// check to see if file isn't locked by another process
|
|
hFile = CreateFile(OutFilename,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
FatalNoDelete(NULL, INVALID_FILEPERM, OutFilename);
|
|
exit(INVALID_FILEPERM);
|
|
} else {
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (image.Switch.Link.DebugInfo != None) {
|
|
// Ensure that the PDB file exists and has the right permissions
|
|
char *szPdb;
|
|
|
|
szPdb = DeterminePDBFilename(OutFilename, PdbFilename);
|
|
|
|
if (_access(szPdb, 0) == -1) {
|
|
PostNote(NULL, PDBMISSING, szPdb);
|
|
FreePv(szPdb);
|
|
SetupForFullIlinkBuild(ppimage);
|
|
return;
|
|
}
|
|
|
|
if (_access(szPdb, 2) == -1) {
|
|
FatalNoDelete(NULL, INVALID_FILEPERM, szPdb);
|
|
exit(INVALID_FILEPERM);
|
|
}
|
|
|
|
PdbFilename = szPdb;
|
|
}
|
|
|
|
// set up for an incr ilink.
|
|
SetupForIncrIlinkBuild(ppimage, image.pvBase, (DWORD)statfile.st_size);
|
|
if (!fIncrDbFile) {
|
|
return;
|
|
}
|
|
|
|
// incremental initialization
|
|
IncrInitImage(ppimage);
|
|
|
|
DBEXEC(DB_DUMPIMAGE, DumpImage(*ppimage));
|
|
}
|
|
|
|
|
|
BOOL
|
|
FValidPtrInfo (
|
|
IN DWORD pvBase,
|
|
IN DWORD fileLen,
|
|
IN DWORD ptr,
|
|
IN DWORD cbOffset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensures that the ptr and offset are valid.
|
|
|
|
Arguments:
|
|
|
|
pvBase - base of image.
|
|
|
|
fileLen - length of file.
|
|
|
|
ptr - ptr to validate.
|
|
|
|
cbOffset - cbOffset from ptr that has to be valid as well.
|
|
|
|
Return Value:
|
|
|
|
TRUE if info is valid.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ptr <= (DWORD)pvBase) {
|
|
// Invalid ptr?
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
ptr -= (DWORD) pvBase; // take out the base value
|
|
|
|
if ((ptr + cbOffset) <= fileLen) {
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
void
|
|
FreeImage (
|
|
PPIMAGE ppimage,
|
|
BOOL fIncrBuild
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free space occupied by image blowing away structures as needed
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to image struct pointer
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
// free stuff according to whether it is an incr build
|
|
if (fIncrBuild) {
|
|
FreeHeap();
|
|
} else {
|
|
// FreeImageMap(ppimage);
|
|
FreeExternalSymbolTable(&((*ppimage)->pst));
|
|
|
|
// UNDONE: This memory is allocated via Calloc() and isn't safe to free
|
|
|
|
free(*ppimage);
|
|
}
|
|
|
|
// done
|
|
*ppimage = NULL;
|
|
}
|
|
|
|
|
|
void
|
|
SaveEXEInfo(
|
|
const char *szExe,
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Saves size & timestamp of EXE.
|
|
|
|
Arguments:
|
|
|
|
szExe - name of EXE.
|
|
|
|
pimage - ptr to IMAGE struct.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
struct _stat statfile;
|
|
|
|
if (_stat(szExe, &statfile) == -1) {
|
|
Fatal(NULL, CANTOPENFILE, szExe);
|
|
}
|
|
pimage->tsExe = statfile.st_mtime;
|
|
pimage->cbExe = statfile.st_size;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FValidILKFile (
|
|
const char *szIncrDbFilename,
|
|
BOOL fIlink,
|
|
PIMAGE pimage,
|
|
struct _stat *pstat
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verifies that file is a valid ILK file.
|
|
|
|
Arguments:
|
|
|
|
szIncrDbFilename - name of ILK file.
|
|
|
|
fIlink - is TRUE if we are attempting to do an ilink.
|
|
|
|
pimage - ptr to IMAGE struct.
|
|
|
|
pstat - ptr to a statfile struct.
|
|
|
|
Return Value:
|
|
|
|
TRUE if file is a valid ILK file.
|
|
|
|
--*/
|
|
|
|
{
|
|
// stat the incremental db file to make sure it is around.
|
|
if (_stat(szIncrDbFilename, pstat)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// the ILK file is around and so we are not doing a full link
|
|
// if we do, the resulting warning will let the user know about anyway.
|
|
pimage->Switch.Link.fNotifyFullBuild = FALSE;
|
|
|
|
// make sure the file is of proper size
|
|
if (pstat->st_size < sizeof(IMAGE) || pstat->st_size > ILKMAP_MAX) {
|
|
if (fIlink) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "invalid size for a ILK file");
|
|
#endif // INSTRUMENT
|
|
Warning(NULL, INVALID_DBFILE, szIncrDbFilename);
|
|
fINCR = FALSE;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
// make sure file has proper permissions.
|
|
if ((pstat->st_mode & (S_IREAD | S_IWRITE)) != (S_IREAD | S_IWRITE)) {
|
|
if (fIlink) {
|
|
Warning(NULL, INVALID_FILE_ATTRIB, szIncrDbFilename);
|
|
fINCR = FALSE;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// open the incremental db file
|
|
FileIncrDbHandle = FileOpen(szIncrDbFilename, O_RDWR | O_BINARY, 0);
|
|
|
|
// read in just the image structure
|
|
if (FileRead(FileIncrDbHandle, pimage, sizeof(IMAGE)) != sizeof(IMAGE)) {
|
|
FileClose(FileIncrDbHandle, TRUE);
|
|
if (fIlink) {
|
|
Warning(NULL, INVALID_DBFILE, szIncrDbFilename);
|
|
fINCR = FALSE;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// close the incremental db file
|
|
FileClose(FileIncrDbHandle, TRUE);
|
|
FileIncrDbHandle = 0;
|
|
|
|
// look for the incr db signature
|
|
if (strcmp(pimage->Sig, INCDB_SIGNATURE)) {
|
|
if (fIlink) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "invalid sig found");
|
|
#endif // INSTRUMENT
|
|
Warning(NULL, INVALID_DBFILE, szIncrDbFilename);
|
|
fINCR = FALSE;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// if not doing an ilink, just verifying the signature will do for now
|
|
if (!fIlink) {
|
|
return(TRUE);
|
|
}
|
|
|
|
// verify the version numbers; mimatch => do a full inc build
|
|
if (pimage->MajVersNum != INCDB_MAJVERSNUM) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "invalid version found");
|
|
#endif // INSTRUMENT
|
|
|
|
if (fTest) {
|
|
PostNote(NULL, INVALIDILKFORMAT);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// verify ptrs in image struct
|
|
if (!FValidPtrInfo((DWORD)pimage->pvBase, (DWORD)pstat->st_size, (DWORD)pimage->secs.psecHead, sizeof(SEC)) ||
|
|
!FValidPtrInfo((DWORD)pimage->pvBase, (DWORD)pstat->st_size, (DWORD)pimage->libs.plibHead, sizeof(LIB)) ||
|
|
!FValidPtrInfo((DWORD)pimage->pvBase, (DWORD)pstat->st_size, (DWORD)pimage->plibCmdLineObjs, sizeof(LIB)) ||
|
|
!FValidPtrInfo((DWORD)pimage->pvBase, (DWORD)pstat->st_size, (DWORD)pimage->pst, sizeof(ST))) {
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, NULL, letypeEvent, "invalid ptrs found in image struct");
|
|
#endif // INSTRUMENT
|
|
|
|
if (fTest) {
|
|
PostNote(NULL, CORRUPTILK);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
void
|
|
DumpImage (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps an image. Others dump routines may be added
|
|
as required.
|
|
|
|
Arguments:
|
|
|
|
pimage - pointer to an image.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
assert(pimage);
|
|
assert(pimage->secs.psecHead);
|
|
assert(pimage->libs.plibHead);
|
|
assert(pimage->pst);
|
|
assert(pimage->pst->pht);
|
|
|
|
DBPRINT("---------------- IMAGE DUMP ----------------\n");
|
|
|
|
DBPRINT("Image Base...........0x%.8lx\n\n",(LONG)(pimage->pvBase));
|
|
DumpImageMap(&pimage->secs);
|
|
DumpDriverMap(pimage->libs.plibHead);
|
|
Statistics_HT(pimage->pst->pht);
|
|
Dump_HT(pimage->pst->pht, &pimage->pst->blkStringTable);
|
|
|
|
DBPRINT("------------ END IMAGE DUMP ----------------\n");
|
|
}
|
|
|
|
#endif // DBG
|