2020-09-30 17:12:32 +02:00

2909 lines
81 KiB
Plaintext

// loadomf.cxx - load
//
// Copyright <C> 1989-94, Microsoft Corporation
//
// Purpose:
//
// 10-Nov-94 BryanT
// Merge in NT changes.
// Change the load code so we first call the Shell to see
// if the symbol load s/b deferred or ignored.
// Functions changed: OLStart, OLLoadOmf
// New Functions: OLContinue (the part of OLStart that determines)
// what type of file we're looking at).
// LoadOmfForReal (the part of OLLoadOmf that actually
// performs the symbol load)
// Replace all the hexg param's with lpexg's. We have it everywhere
// it's needed and every function calls LLLock/LLUnlock to get it...
// Define UnloadOmf.
//
// 07-Jan-96 BryanT
//
#include "shinc.hpp"
#pragma hdrstop
#include <imagehlp.h>
// The exe file information
static LSZ lszFName; // file name
static LONG lfaBase; // offset of directory info from end of file
static ULONG cDir; // number of directory entries
static OMFDirEntry *lpdss; // pointer to directory table
static OMFDirEntry *lpdssCur; // pointer to current directory entry
static LONG lcbFilePos;
static WORD csegExe;
static PIMAGE_SECTION_HEADER SecHdr;
static unsigned int SecCount;
static DWORD ImageAlign;
static WORD btAlign; // Alignment bit
extern HLLI HlliExgExe;
BOOL FKillLazyLoad;
HANDLE HthdLazyLoad;
HANDLE HevntLazyLoad;
CRITICAL_SECTION CsExeModify;
typedef struct _PDB_INFO {
SIG sig;
AGE age;
char sz[_MAX_PATH];
} PDB_INFO;
static PDB_INFO pdbInfo;
const ULONG sigNB11 = '11BN';
const ULONG sigNB10 = '01BN';
const ULONG sigNB09 = '90BN';
const ULONG sigNB08 = '80BN';
const ULONG sigNB07 = '70BN';
const ULONG sigNB06 = '60BN';
const ULONG sigNB05 = '50BN';
// compile time assert
#if !defined(cassert)
#define cassert(x) extern char dummyAssert[ (x) ]
#endif
LOCAL SHE CheckSignature (INT , OMFSignature *, PDB_INFO *);
LOCAL SHE OLStart (LPEXG);
LOCAL BOOL OLMkSegDir (WORD, LPSGD *, LPSGE *, LPEXG);
LOCAL SHE OLLoadTypes (LPEXG);
LOCAL SHE OLLoadSym (LPEXG);
LOCAL SHE OLLoadSrc (LPEXG);
LOCAL SHE OLGlobalPubs (LPEXG);
LOCAL SHE OLGlobalSym (LPEXG);
LOCAL SHE OLStaticSym (LPEXG);
LOCAL SHE OLLoadSegMap (LPEXG);
LOCAL SHE OLLoadNameIndex (LPEXG);
LOCAL LPCH OLRwrSrcMod (OMFSourceModule *);
LOCAL BOOL OLLoadHashSubSec (LPGST, LPB, WidenTi * =0);
LOCAL SHE NB10LoadOmf (LPEXG, HEXG);
LOCAL SHE LoadPdb (LPEXG, PDB_INFO *);
LOCAL SHE NB10LoadModules (LPEXG, ULONG*, HEXG);
LOCAL VOID LoadSymbols(HEXG, BOOL);
LOCAL SHE LoadOmfForReal(LPEXG, HEXG);
LOCAL SHE LoadFpo(LPEXG, int, PIMAGE_DEBUG_DIRECTORY);
LOCAL SHE LoadPdata(LPEXG, int, ULONG, ULONG, ULONG, ULONG, BOOL);
LOCAL SHE LoadOmap(LPEXG, int, PIMAGE_DEBUG_DIRECTORY);
LOCAL int OLMkModule(LPEXG, HEXG);
LOCAL SHE OLValidate(int, void *, LPSTR);
LOCAL SHE SheFixupConvertedSyms(LPEXG);
LOCAL void ConvertGlobal16bitSyms(WidenTi*, LPGST, PB, ULONG);
#define MAX_SEARCH_PATH_LEN 512
// This is hard-coded name of the registry location where setup will put the
// pdb path. This should be changed when we have a general mechanism for the debugger
// dlls to get the IDE's root registry key name.
static TCHAR szDefaultKeyName[300];
const TCHAR szKeySuffix[] =
_T("Build System\\Components\\Platforms\\Win32 (x86)\\Directories");
static const TCHAR szPdbDirs[] = "Pdb Dirs";
TCHAR szSearchPath[MAX_SEARCH_PATH_LEN];
BOOL fQueriedRegistry;
// CFile is a simple helper class which will force its file to be closed
// as soon as the CFile object is destructed.
class CFile {
public:
INT m_hfile;
CFile() { m_hfile = -1; }
void ReInit() {
if (m_hfile != -1) {
SYClose(m_hfile);
m_hfile = -1;
}
}
INT Open(LSZ lszName) {
m_hfile = SYOpen(lszName);
return(m_hfile);
}
~CFile() {
if(m_hfile != -1) {
SYClose (m_hfile);
m_hfile = -1;
}
}
operator INT&() { return m_hfile; }
};
VOID
LoadDefered(
HEXG hexg
)
{
LoadSymbols(hexg, TRUE);
return;
}
VOID
UnloadDefered(
HEXG hexg
)
{
return;
}
SHE UnloadNow(HEXG hexg)
{
LPEXG lpexg;
lpexg = (LPEXG) LLLock(hexg);
OLUnloadOmf(lpexg);
VoidCaches();
lpexg->fOmfDefered = TRUE;
lpexg->sheLoad = sheDeferSyms;
LLUnlock(hexg);
return sheNone;
}
inline BOOL
fSheGoodReturn(SHE she)
{
return ((she == sheNone) ||
(she == sheSymbolsConverted) ||
(she == sheConvertTIs));
}
// OLLoadOmf - load omf information from exe
//
// error = OLLoadOmf (hexg)
//
// Entry hexg = handle to executable information struct
//
// Exit
//
// Returns An error code suitable for errno.
SHE
OLLoadOmf(
HEXG hexg,
VLDCHK *pVldChk,
DWORD dllLoadAddress
)
{
SHE sheRet = sheNone;
LSZ lszFname = NULL;
LPEXG lpexg = (LPEXG) LLLock (hexg);
if (lpexg->fOmfLoaded) {
return sheNone;
}
// Query the shell and see if we should load this one now.
lszFname = lpexg->lszName;
// SYGetDefaultShe () always returns TRUE and leavs the parameters
// unchanged; so this bit of code is dead.
#ifndef NT_BUILD_ONLY
#undef SYGetDefaultShe
#define SYGetDefaultShe(a, b) ((*b=sheNone), TRUE)
#endif // NT_BUILD_ONLY
if (!SYGetDefaultShe(lszFname, &sheRet)) {
if (lpexg->lszAltName) {
lszFname = lpexg->lszAltName;
if (!SYGetDefaultShe(lszFname, &sheRet)) {
SYGetDefaultShe(NULL, &sheRet);
lszFname = lpexg->lszName;
}
} else {
SYGetDefaultShe(NULL, &sheRet);
}
}
// SYGetDefaultShe is expected to return one of the following
// values:
//
// sheSuppressSyms - Don't load, just keep track of the name/start
// sheNoSymbols - This module has already been processed and there are no symbols
// sheDeferSyms - Defer symbol loading until needed
// sheSymbolsConverted - The symbols are already loaded
// sheNone - Go ahead and load the symbols now.
// Regardless of the load type, save some stuff
lpexg->LoadAddress = dllLoadAddress;
lpexg->ulTimeStamp = pVldChk->TimeDateStamp;
lpexg->sheLoad = sheRet;
//
switch( sheRet ) {
case sheNone:
case sheSymbolsConverted:
//
// If we made it this far, we must load the symbols
//
LoadSymbols(hexg, FALSE);
if (lpexg->fOmfMissing)
sheRet = sheNoSymbols;
else if (lpexg->fOmfSkipped)
sheRet = sheSuppressSyms;
else if (lpexg->fOmfDefered)
sheRet = sheDeferSyms;
lpexg->sheLoad = sheRet;
break;
case sheNoSymbols:
lpexg->fOmfMissing = TRUE;
break;
case sheSuppressSyms:
lpexg->fOmfSkipped = TRUE;
break;
case sheDeferSyms:
lpexg->fOmfDefered = TRUE;
SetEvent(HevntLazyLoad);
break;
}
LLUnlock(hexg);
return sheRet;
}
// LoadSymbols
//
// Purpose: This function loads a defered module's symbols. After
// the symbols are loaded the shell is notified of the completed
// module load.
//
// Input: hpds - Handle to process to load the symbols for
// hexg - exg handle for the module to be added
// fNotifyShell - Should shell be notified on load.
//
// Return: None
VOID
LoadSymbols(
HEXG hexg,
BOOL fNotifyShell
)
{
SHE sheRet;
LPEXG lpexg = NULL;
LPSTR lpname = NULL;
HPDS hpdsLast;
Retry:
EnterCriticalSection( &CsExeModify );
// lock down the necessary data structure
lpexg = (LPEXG) LLLock(hexg);
if (!lpexg) {
goto done;
}
//
// We need to find out if the symbols are already being loaded by
// somebody else. If so then we need wait for them to finish what
// we need done.
//
if (lpexg->fOmfLoading) {
//
// Somebody beat us to it. Need to wait for them
//
LLUnlock(hexg);
LeaveCriticalSection(&CsExeModify);
Sleep(1000);
goto Retry;
}
// mark the module as being loaded
lpexg->fOmfLoading = TRUE;
LeaveCriticalSection( &CsExeModify );
// load the symbols (yes, pass both lpexg and hexg.
// OlMkModule needs hexg for creating the lpmds)
sheRet = LoadOmfForReal(lpexg, hexg);
EnterCriticalSection( &CsExeModify );
switch (sheRet) {
case sheNoSymbols:
lpexg->fOmfMissing = TRUE;
break;
case sheSuppressSyms:
lpexg->fOmfSkipped = TRUE;
break;
case sheNone:
case sheSymbolsConverted:
lpexg->fOmfLoaded = TRUE;
break;
default:
lpexg->fOmfMissing = TRUE;
break;
}
if (fNotifyShell) {
//
// notify the shell that symbols have been loaded
//
if (lpexg->lszAltName) {
lpname = lpexg->lszAltName;
} else {
lpname = lpexg->lszName;
}
DLoadedSymbols(sheRet, lpname);
}
// update the module flags
lpexg->fOmfDefered = FALSE;
lpexg->fOmfLoading = FALSE;
done:
LeaveCriticalSection( &CsExeModify );
// free resources
if (lpexg) {
LLUnlock(hexg);
}
return;
}
// LoadOmfForReal
//
// Purpose: Here's where the symbolic is actually loaded from the image.
//
// Input: lpexg - The pointer to the exg structure
// hexg - The handle of the exg structure
//
// Return: Standard she error codes.
SHE
LoadOmfForReal(
LPEXG lpexg,
HEXG hexg
)
{
SHE sheRet = sheNone;
SHE sheRetSymbols = sheNone;
WORD cbMod = 0;
ULONG cMod;
ULONG iDir;
csegExe = 0;
__try {
// Open and verify the exe.
sheRet = sheRetSymbols = OLStart(lpexg);
// If there was an error, bail.
// (sheNone doesn't mean "no symbols", it means "error None")
if (!fSheGoodReturn(sheRet)) {
goto returnhere;
}
if (lpexg->ppdb) {
sheRet = NB10LoadOmf(lpexg, hexg);
goto returnhere;
}
if (sheRet == sheConvertTIs) {
// set up to do the conversions
if (!WidenTi::fCreate(lpexg->pwti)) {
sheRet = sheOutOfMemory;
goto returnhere;
}
}
btAlign = (WORD)(lfaBase & 1);
lpdssCur = lpdss;
iDir = 0;
// Load up the module table.
// First, count up how many sstModule entries we have. The spec
// requires all the sstModules to be before any other.
while (iDir < cDir && lpdssCur->SubSection == sstModule) {
lpdssCur++;
iDir++;
}
// If there's no modules, there's no sense continuing.
if (iDir == 0) {
sheRet = sheNoSymbols;
goto returnhere;
}
lpexg->cMod = cMod = iDir;
// Allocate the rgMod buffer and load each dir entry in.
lpexg->rgMod = (LPMDS)MHAlloc((cMod+2) * sizeof(MDS));
if (lpexg->rgMod == NULL) {
sheRet = sheOutOfMemory;
goto returnhere;
}
memset(lpexg->rgMod, 0, sizeof(MDS)*(cMod+2));
lpexg->rgMod[cMod+1].imds = (WORD) -1;
// Go through the list of directory entries and process all of the sstModule records.
for (iDir = 0, lpdssCur = lpdss;
iDir < cMod;
iDir += 1, lpdssCur++) {
if (!OLMkModule (lpexg, hexg)) {
sheRet = sheOutOfMemory;
goto returnhere;
}
}
// Set up map of modules. This function is used to create a map
// of contributer segments to modules. This is then used when
// determining which module is used for an address.
lpexg->csgd = csegExe;
if (!OLMkSegDir (csegExe, &lpexg->lpsgd, &lpexg->lpsge, lpexg)) {
sheRet = sheOutOfMemory;
goto returnhere;
}
// continue through the directory entries
for (; iDir < cDir; lpdssCur++, iDir++) {
if (lpdssCur->cb == 0) {
// if nothing in this entry
continue;
}
switch (lpdssCur->SubSection) {
case sstSrcModule:
sheRet = OLLoadSrc(lpexg);
break;
case sstAlignSym:
sheRet = OLLoadSym(lpexg);
break;
case sstGlobalTypes:
sheRet = OLLoadTypes(lpexg);
break;
case sstGlobalPub:
sheRet = OLGlobalPubs(lpexg);
break;
case sstGlobalSym:
sheRet = OLGlobalSym(lpexg);
break;
case sstSegMap:
sheRet = OLLoadSegMap(lpexg);
break;
case sstLibraries: // ignore this table
case sstMPC: // until this table is implemented
case sstSegName: // until this table is implemented
case sstModule: // Handled elsewhere
break;
case sstFileIndex:
sheRet = OLLoadNameIndex(lpexg);
break;
case sstStaticSym:
sheRet = OLStaticSym(lpexg);
break;
default:
sheRet = sheCorruptOmf;
break;
}
if (sheRet == sheCorruptOmf) {
sheRet = sheNoSymbols;
}
}
if (lpexg->pwti) {
sheRet = SheFixupConvertedSyms(lpexg);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
sheRet = sheNoSymbols;
}
returnhere:
if (SecHdr) {
MHFree(SecHdr);
SecHdr = NULL;
SecCount = 0;
}
return sheRet;
}
LOCAL SHE
NB10LoadOmf(
LPEXG lpexg,
HEXG hexg
)
{
SHE sheRet = sheNone;
WORD cbMod = 0;
ULONG ModCnt = 0;
btAlign = (WORD)(lfaBase & 1);
// we need to allocate a buffer large enough to read the largest module
// table entry
if ((sheRet = NB10LoadModules (lpexg, &ModCnt, hexg)) != sheNone) {
return sheRet;
}
if (ModCnt == 0L) {
// if no symbols found
return sheNoSymbols;
}
lpexg->cMod = ModCnt;
if(!DBIOpenGlobals(lpexg->pdbi, &(lpexg->pgsiGlobs)) ||
!DBIOpenPublics(lpexg->pdbi, &(lpexg->pgsiPubs)))
{
return sheOutOfMemory;
}
if((sheRet = OLLoadSegMap(lpexg)) != sheNone ||
(sheRet = OLLoadNameIndex(lpexg)) != sheNone)
{
return sheRet;
}
return sheRet;
}
#define cbFileMax (_MAX_CVFNAME + _MAX_CVEXT)
// OLStart - get exe debug information
//
// Purpose: To open the file specified and get the offset to the directory
// and get the base that everyone is offset from.
//
// Entry hexg = handle to exe to get info for
//
// Exit lfaBase = base offset of debug information
// cDir = count of number of directory entries
// lpdss = directory entries
//
// Returns file open status
#define UNKNOWN_IMAGE 0
#define DOS_IMAGE 1
#define VCDBG_IMAGE 2
#define WIN16_IMAGE 3
#define PE_IMAGE 4
#define ROM_IMAGE 5
#define NTDBG_IMAGE 6
LOCAL SHE
OLStart(
LPEXG lpexg
)
{
SHE sheRet;
ULONG DirSize;
OMFSignature Signature;
OMFDirHeader DirHeader;
IMAGE_DOS_HEADER doshdr; // Old format MZ header
IMAGE_NT_HEADERS pehdr;
IMAGE_ROM_HEADERS romhdr;
IMAGE_SEPARATE_DEBUG_HEADER sepHdr;
PIMAGE_FILE_HEADER pfile;
IMAGE_DEBUG_DIRECTORY dbgDir;
IMAGE_DEBUG_DIRECTORY cvDbgDir;
DWORD cbData;
DWORD dllLoadAddress;
DWORD ul;
VLDCHK vldChk;
LSZ szFName = NULL;
char szNewName[_MAX_PATH];
int ImageType = UNKNOWN_IMAGE;
DWORD cDebugDir;
DWORD offDbgDir;
DWORD cObjs;
CFile hfile;
if (lpexg->lszAltName) {
szFName = lpexg->lszAltName;
} else {
szFName = lpexg->lszName;
}
// lpexg->lszDebug is the file where we pull the symbolic from.
dllLoadAddress = lpexg->LoadAddress;
vldChk.TimeDateStamp = lpexg->ulTimeStamp;
ImageAlign = 0;
hfile.Open(szFName);
if (hfile == -1) {
retry:
if (lpexg->lszDebug) {
MHFree(lpexg->lszDebug);
lpexg->lszDebug = 0;
}
hfile = SYFindExeFile(szFName, szNewName, sizeof(szNewName), &vldChk, (PFNVALIDATEEXE)OLValidate);
if (hfile == -1) {
sheRet = sheFileOpen;
goto ReturnHere;
}
if ( ! ( lpexg->lszDebug = (LSZ) MHAlloc ( _ftcslen ( szNewName ) + 1 ) ) ) {
sheRet = sheOutOfMemory;
goto ReturnHere;
}
_tcscpy ( lpexg->lszDebug, szNewName );
} else {
// Assert that the input file is OK. We only get here
// when using the file name as passed in from the DM.
sheRet = OLValidate(hfile, &vldChk, NULL);
if ((sheRet == sheBadChecksum) ||
(sheRet == sheBadTimeStamp) ||
(sheRet == sheNoSymbols))
{
hfile.ReInit();
goto retry;
}
if ( ! ( lpexg->lszDebug = (LSZ) MHAlloc ( _ftcslen ( szFName ) + 1 ) ) ) {
sheRet = sheOutOfMemory;
goto ReturnHere;
}
_tcscpy ( lpexg->lszDebug, szFName );
}
// HACK: If we are pre-loading symbols lpexg->[ulTimeStamp|ulCheckSum] will be 0
// at this point. However vldChk will be updated to have the appropriate
// information. Update the lpexg structures with the right value.
if (lpexg->ulTimeStamp == 0) {
lpexg->ulTimeStamp = vldChk.TimeDateStamp;
}
// Now figure out what we're looking at. Here are the possible formats:
// 1. Image starts with a DOS MZ header and e_lfanew is zero
// - Standard DOS exe.
// 2. Image starts with a DOS NE header and e_lfanew is non-zero
// - If e_lfanew points to a PE header, this is a PE image
// - Otherwise, it's probably a Win16 image.
// 3. Image starts with a PE header.
// - Image is a PE image built with -stub:none
// 4. Image starts with a ROM PE header.
// - Image is a ROM image. If characteristics flag
// doesn't have IMAGE_FILE_DEBUG_STRIPPED set, the debug
// directory is at the start of rdata.
// 5. Image starts with a DBG file header
// - Image is an NT DBG file (symbols only).
// 6. None of the signatures match.
// - This may be a Languages DBG file. Seek to the end
// of the file and attempt to read the CV signature/offset
// from there (a Languages DBG file is made by chopping an
// image at the start of the debug data and writing the end
// in a new file. In the CV format, the signature/offset at the
// end of the file points back to the beginning of the data).
if ((SYSeek(hfile, 0, SEEK_SET) == 0) &&
sizeof(doshdr) == SYReadFar (hfile, (LPB) &doshdr, sizeof(doshdr)))
{
switch (doshdr.e_magic) {
case IMAGE_DOS_SIGNATURE:
// This is a DOS NE header.
if (doshdr.e_lfanew == 0) {
ImageType = DOS_IMAGE;
} else {
if ((SYSeek(hfile, doshdr.e_lfanew, SEEK_SET) == doshdr.e_lfanew) &&
(SYReadFar(hfile, (LPB) &pehdr, sizeof(pehdr)) == sizeof(pehdr)))
{
if (pehdr.Signature == IMAGE_NT_SIGNATURE) {
ImageType = PE_IMAGE;
ImageAlign = pehdr.OptionalHeader.SectionAlignment;
pfile = &pehdr.FileHeader;
} else {
ImageType = WIN16_IMAGE;
}
} else {
// No luck reading from the image. Must be corrupt.
sheRet = sheCorruptOmf;
goto ReturnHere;
}
}
break;
case IMAGE_NT_SIGNATURE:
// This image is a PE image w/o a stub (most likely a ROM image). Read in the header.
if ((SYSeek(hfile, 0, SEEK_SET) == 0) &&
(SYReadFar(hfile, (LPB) &pehdr, sizeof(pehdr)) == sizeof(pehdr)))
{
ImageType = PE_IMAGE;
ImageAlign = pehdr.OptionalHeader.SectionAlignment;
pfile = &pehdr.FileHeader;
} else {
// No luck reading from the image. Must be corrupt.
sheRet = sheCorruptOmf;
goto ReturnHere;
}
break;
case IMAGE_SEPARATE_DEBUG_SIGNATURE:
// This image is an NT DBG file.
ImageType = NTDBG_IMAGE;
if ((SYSeek(hfile, 0, SEEK_SET) != 0) ||
(SYReadFar(hfile, (LPB) &sepHdr, sizeof(sepHdr)) != sizeof(sepHdr)))
{
// No luck reading from the image. Must be corrupt.
sheRet = sheCorruptOmf;
goto ReturnHere;
}
// If there's no debug info, we can't continue further.
if (sepHdr.DebugDirectorySize / sizeof(dbgDir) == 0) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
break;
default:
// None of the above. See if it's a ROM image.
// Note: The only way we think we're working on a ROM image
// is if the optional header size is correct. Not really foolproof.
if ((SYSeek(hfile, 0, SEEK_SET) == 0) &&
(SYReadFar(hfile, (LPB) &romhdr, sizeof(romhdr)) == sizeof(romhdr)))
{
if (romhdr.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
// If we think we have a ROM image, make sure there's
// symbolic to look for.
if (romhdr.FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
sheRet = sheNoSymbols;
goto ReturnHere;
} else {
ImageType = ROM_IMAGE;
pfile = &romhdr.FileHeader;
}
} else {
ImageType = VCDBG_IMAGE;
}
} else {
// No luck reading from the image. Must be corrupt.
sheRet = sheCorruptOmf;
goto ReturnHere;
}
break;
}
} else {
// No luck reading from the image. Must be corrupt.
sheRet = sheCorruptOmf;
goto ReturnHere;
}
// Now, we know what kind of image we're looking at.
// Either obtain the pointer to the CV debug data (and other
// relevant data along the way) or convert whatever we do find
// to CV debug data.
lpexg->fSymConverted = FALSE;
switch (ImageType) {
case DOS_IMAGE:
case VCDBG_IMAGE:
case WIN16_IMAGE:
// Easy. Skip to the end and look back.
ul = SYSeek (hfile, -((LONG)sizeof (OMFSignature)), SEEK_END);
if ((sheRet = CheckSignature (hfile, &Signature, &pdbInfo)) == sheNone) {
// seek to the base and read in the new key
lfaBase = SYSeek (hfile, -Signature.filepos, SEEK_END);
sheRet = CheckSignature(hfile, &Signature, &pdbInfo);
cbData = ul - lfaBase;
}
// If the CV signature is invalid, see if we can convert what we do
// have (perhaps a .sym file?)
if (sheRet != sheNone) {
if (pfConvertSymbolsForImage) {
lpexg->lpbData = (LPB) (pfConvertSymbolsForImage)(
(HANDLE)(int)hfile, lpexg->lszDebug);
}
// If no symbols converted, bail. Nothing more we can do.
if (lpexg->lpbData == 0) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
Signature = *(OMFSignature*)lpexg->lpbData;
lpexg->fSymConverted = TRUE;
}
break;
case PE_IMAGE:
case ROM_IMAGE:
// In both the PE image and ROM image, we're past the FILE
// and OPTIONAL header by now. Walk through the section
// headers and pick up interesting data. We make a
// a copy of the section headers in case we need to
// reconstruct the original values for a Lego'd image
cObjs = pfile->NumberOfSections;
SecCount = pfile->NumberOfSections;
ul = SecCount * sizeof(IMAGE_SECTION_HEADER);
// Note: SecHdr is free'd by LoadOmfForReal.
SecHdr = (PIMAGE_SECTION_HEADER) MHAlloc(ul);
if (!SecHdr) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
if (SYReadFar(hfile, (LPB) SecHdr, ul) != ul) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
if (ImageType == PE_IMAGE) {
// look for the .pdata section on RISC platforms
if ((pfile->Machine == IMAGE_FILE_MACHINE_ALPHA) ||
(pfile->Machine == IMAGE_FILE_MACHINE_R4000) ||
(pfile->Machine == IMAGE_FILE_MACHINE_R10000) ||
(pfile->Machine == IMAGE_FILE_MACHINE_POWERPC))
{
for (ul=0; ul < cObjs; ul++) {
if (_tcscmp((char *) SecHdr[ul].Name, ".pdata") == 0) {
LoadPdata(lpexg,
hfile,
dllLoadAddress,
pehdr.OptionalHeader.ImageBase,
SecHdr[ul].PointerToRawData,
SecHdr[ul].SizeOfRawData,
FALSE);
lpexg->debugData.lpOriginalRtf = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
(pehdr.OptionalHeader.ImageBase +
SecHdr[ul].VirtualAddress);
break;
}
}
}
// If the debug info has been stripped, close this handle
// and look for the .dbg file...
if (pfile->Characteristics & IMAGE_FILE_DEBUG_STRIPPED){
// The debug info has been stripped from this image.
// Close this file handle and look for the .DBG file.
hfile.ReInit();
ImageType = UNKNOWN_IMAGE;
MHFree(SecHdr);
SecHdr = 0;
goto retry;
}
// Find the debug directory and the number of entries in it.
// For PE images, walk the section headers looking for the
// one that's got the debug directory.
for (ul=0; ul < cObjs; ul++) {
if ((SecHdr[ul].VirtualAddress <=
pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) &&
(pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress <
SecHdr[ul].VirtualAddress + SecHdr[ul].SizeOfRawData)) {
// This calculation really isn't necessary nor is the range test
// above. Like ROM images, it s/b at the beginning of .rdata. The
// only time it won't be is when a pre NT 1.0 image is split sym'd
// creating a new MISC debug entry and relocating the directory
// to the DEBUG section...
offDbgDir = SecHdr[ul].PointerToRawData +
pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress -
SecHdr[ul].VirtualAddress;
cDebugDir = pehdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
sizeof(IMAGE_DEBUG_DIRECTORY);
break;
}
}
} else {
// For ROM images, there's much less work to do. We only
// need to search for the .rdata section. There's no need
// to look for .pdata (it will never exist) or worry about
// stripped debug symbolic (that case was already handled above).
for (ul=0; ul < cObjs; ul++) {
if (!_tcscmp((char *)SecHdr[ul].Name, ".rdata")) {
offDbgDir = SecHdr[ul].PointerToRawData;
if (SYSeek(hfile, offDbgDir, SEEK_SET) != (LONG) offDbgDir) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
// The linker stores an empty directory entry for ROM
// images to terminate the list.
cDebugDir = 0;
do {
if (SYReadFar(hfile, (LPB) &dbgDir, sizeof(dbgDir)) != sizeof(dbgDir)) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
cDebugDir++;
} while (dbgDir.Type != 0);
break;
}
}
}
// Assuming we haven't exhausted the list of section headers,
// we should have the debug directory now.
if (ul == cObjs) {
// We didn't find any CV info. Try converting what we did
// find.
if (pfConvertSymbolsForImage) {
lpexg->lpbData = (LPB)(pfConvertSymbolsForImage)( (HANDLE)(int)hfile, lpexg->lszDebug);
}
if (lpexg->lpbData == 0) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
Signature = *(OMFSignature*)lpexg->lpbData;
lpexg->fSymConverted = TRUE;
break;
}
// Now search the debug directory for relevant entries.
if (SYSeek(hfile, offDbgDir, SEEK_SET) != (LONG) offDbgDir) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
ZeroMemory(&cvDbgDir, sizeof(cvDbgDir) );
for (ul=0; ul < cDebugDir; ul++) {
if (SYReadFar(hfile, (LPB) &dbgDir, sizeof(dbgDir)) != sizeof(dbgDir)) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
cvDbgDir = dbgDir;
continue;
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_FPO) {
LoadFpo(lpexg, hfile, &dbgDir);
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC ||
dbgDir.Type == IMAGE_DEBUG_TYPE_OMAP_TO_SRC) {
LoadOmap(lpexg, hfile, &dbgDir);
}
}
if (cvDbgDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
// We didn't find any CV info. Try converting what we did
// find.
if (pfConvertSymbolsForImage) {
lpexg->lpbData = (LPB)(pfConvertSymbolsForImage)( (HANDLE)(int)hfile, lpexg->lszDebug);
}
if (lpexg->lpbData == 0) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
Signature = *(OMFSignature*)lpexg->lpbData;
lpexg->fSymConverted = TRUE;
} else {
// Otherwise, calculate the location/size so we can load it.
lfaBase = cvDbgDir.PointerToRawData;
cbData = cvDbgDir.SizeOfData;
if (SYSeek(hfile, lfaBase, SEEK_SET) != lfaBase) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
sheRet = CheckSignature (hfile, &Signature, &pdbInfo);
if ((sheRet != sheNone) && (sheRet != sheConvertTIs)) {
goto ReturnHere;
}
}
break;
case NTDBG_IMAGE:
SecCount = sepHdr.NumberOfSections;
if (sepHdr.SectionAlignment) {
// The first reserved slot hold the original image alignment
// for use with recreating the pre-lego section headers.
ImageAlign = sepHdr.SectionAlignment;
}
ul = SecCount * sizeof(IMAGE_SECTION_HEADER);
// Note: SecHdr is free'd by LoadOmfForReal.
SecHdr = (PIMAGE_SECTION_HEADER) MHAlloc(ul);
if (!SecHdr) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
// Read in the section headers.
if (SYReadFar(hfile, (LPB) SecHdr, ul) != ul) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
// Skip over the exported names.
SYSeek(hfile, sepHdr.ExportedNamesSize, SEEK_CUR);
// Look for the interesting debug data.
ZeroMemory(&cvDbgDir, sizeof(cvDbgDir));
for (ul=0; ul < (sepHdr.DebugDirectorySize/sizeof(dbgDir)); ul++) {
if (SYReadFar(hfile, (LPB) &dbgDir, sizeof(dbgDir)) != sizeof(dbgDir)) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
switch (dbgDir.Type) {
case IMAGE_DEBUG_TYPE_CODEVIEW :
cvDbgDir = dbgDir;
break;
case IMAGE_DEBUG_TYPE_FPO :
LoadFpo(lpexg, hfile, &dbgDir);
break;
case IMAGE_DEBUG_TYPE_EXCEPTION :
// UNDONE: We can eliminate this load for images
// that we've already processed the pdata from the
// real image...
LoadPdata(lpexg,
hfile,
dllLoadAddress,
sepHdr.ImageBase,
dbgDir.PointerToRawData,
dbgDir.SizeOfData,
TRUE);
ULONG ul2;
for (ul2=0; ul2 < cObjs; ul2++) {
if (_tcscmp((char *) SecHdr[ul2].Name, ".pdata") == 0) {
lpexg->debugData.lpOriginalRtf = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
SecHdr[ul].PointerToRawData;
break;
}
}
break;
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC :
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC :
LoadOmap(lpexg, hfile, &dbgDir);
break;
}
}
if (cvDbgDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
if (pfConvertSymbolsForImage) {
lpexg->lpbData = (LPB)(pfConvertSymbolsForImage)( (HANDLE)(int)hfile, lpexg->lszDebug);
}
if (lpexg->lpbData == 0) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
Signature = *(OMFSignature*)lpexg->lpbData;
lpexg->fSymConverted = TRUE;
} else {
lfaBase = cvDbgDir.PointerToRawData;
cbData = cvDbgDir.SizeOfData;
if (SYSeek(hfile, lfaBase, SEEK_SET) != lfaBase) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
sheRet = CheckSignature (hfile, &Signature, &pdbInfo);
if ((sheRet != sheNone) && (sheRet != sheConvertTIs))
{
goto ReturnHere;
}
}
break;
default:
// No way we should get here, but assert if we do.
assert(FALSE);
}
// O.K. Everything's loaded. If we're looking at a pdb file,
// load it and get out.
if ((*(LONG UNALIGNED *)(Signature.Signature)) == sigNB10) {
sheRet = LoadPdb(lpexg, &pdbInfo);
} else {
// No PDB.
// If the symbols weren't synthesized, allocate a buffer and
// copy them in...
if (!lpexg->fSymConverted) {
HANDLE hMap;
HANDLE hFileMap;
hFileMap = CreateFile(lpexg->lszDebug,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFileMap != INVALID_HANDLE_VALUE) {
hMap = CreateFileMapping(hFileMap,
NULL,
PAGE_WRITECOPY,
0,
0,
NULL);
if (hMap != NULL) {
// Map in the symbolic (only).
SYSTEM_INFO si;
DWORD dwAllocStart, dwAllocDiff;
GetSystemInfo(&si);
dwAllocStart = lfaBase & (~(si.dwAllocationGranularity - 1));
dwAllocDiff = lfaBase - dwAllocStart;
lpexg->pvSymMappedBase = MapViewOfFile(hMap,
FILE_MAP_COPY,
0,
dwAllocStart,
cbData + dwAllocDiff);
if (lpexg->pvSymMappedBase) {
lpexg->lpbData = ((BYTE *) lpexg->pvSymMappedBase) + dwAllocDiff;
}
CloseHandle(hMap);
}
CloseHandle(hFileMap);
}
if (lpexg->lpbData == NULL) {
// Unable to map the image. Read the whole blob in from disk.
lpexg->lpbData = (LPB)MHAlloc(cbData);
if (!lpexg->lpbData) {
sheRet = sheNoSymbols;
goto ReturnHere;
}
if ((SYSeek (hfile, lfaBase, SEEK_SET) != lfaBase) ||
(SYReadFar (hfile, lpexg->lpbData, cbData) != cbData))
{
// Failed to read in the data... Must be corrupt.
MHFree(lpexg->lpbData);
lpexg->lpbData = 0;
sheRet = sheCorruptOmf;
goto ReturnHere;
}
}
}
// We now have a pointer to the CV debug data. Setup the
// pointers to the CV Directory header and return.
LPB lpb;
lpexg->ppdb = NULL;
lpexg->ptpi = NULL;
lpexg->pdbi = NULL;
lpb = Signature.filepos + lpexg->lpbData;
DirHeader = *(OMFDirHeader *) lpb;
cDir = DirHeader.cDir;
// check to make sure somebody has not messed with omf structure
if (DirHeader.cbDirEntry != sizeof (OMFDirEntry)) {
sheRet = sheCorruptOmf;
goto ReturnHere;
}
lpdss = (OMFDirEntry *)(lpb + sizeof(DirHeader));
if (lpexg->fSymConverted) {
sheRet = sheSymbolsConverted;
goto ReturnHere;
}
if (sheRet == sheConvertTIs) {
goto ReturnHere;
}
sheRet = sheNone;
}
ReturnHere:
lpexg->sheLoad = sheRet;
return sheRet;
}
SHE
LoadFpo(
LPEXG lpexg,
int hfile,
PIMAGE_DEBUG_DIRECTORY dbgDir
)
{
LONG fpos;
fpos = SYTell(hfile);
lpexg->fIsRisc = FALSE;
if (SYSeek(hfile, dbgDir->PointerToRawData, SEEK_SET) != (LONG) dbgDir->PointerToRawData) {
return(sheCorruptOmf);
}
if(!(lpexg->debugData.lpFpo = (PFPO_DATA) MHAlloc(dbgDir->SizeOfData)))
return sheOutOfMemory;
SYReadFar(hfile, (LPB) lpexg->debugData.lpFpo, dbgDir->SizeOfData);
lpexg->debugData.cRtf = dbgDir->SizeOfData / SIZEOF_RFPO_DATA;
SYSeek(hfile, fpos, SEEK_SET);
return sheNone;
}
SHE
LoadOmap(
LPEXG lpexg,
int hfile,
PIMAGE_DEBUG_DIRECTORY dbgDir
)
{
LONG fpos;
LPVOID lpOmap;
DWORD dwCount;
fpos = SYTell(hfile);
if (SYSeek(hfile, dbgDir->PointerToRawData, SEEK_SET) != (LONG) dbgDir->PointerToRawData) {
return(sheCorruptOmf);
}
if(!(lpOmap = (LPVOID) MHAlloc(dbgDir->SizeOfData)))
return sheOutOfMemory;
SYReadFar(hfile, (LPB) lpOmap, dbgDir->SizeOfData);
dwCount = dbgDir->SizeOfData / sizeof(OMAP);
SYSeek(hfile, fpos, SEEK_SET);
if(dbgDir->Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC) {
lpexg->debugData.lpOmapFrom = (LPOMAP) lpOmap;
lpexg->debugData.cOmapFrom = dwCount;
} else
if(dbgDir->Type == IMAGE_DEBUG_TYPE_OMAP_TO_SRC) {
lpexg->debugData.lpOmapTo = (LPOMAP) lpOmap;
lpexg->debugData.cOmapTo = dwCount;
} else {
MHFree(lpOmap);
}
return sheNone;
}
SHE
LoadPdata(
LPEXG lpexg,
int hfile,
ULONG loadAddress,
ULONG imageBase,
ULONG start,
ULONG size,
BOOL fDbgFile
)
{
ULONG cFunc;
LONG diff;
ULONG index;
PIMAGE_RUNTIME_FUNCTION_ENTRY rf;
PIMAGE_RUNTIME_FUNCTION_ENTRY tf;
PIMAGE_FUNCTION_ENTRY dbgRf;
LONG fpos;
lpexg->debugData.lpRtf = NULL;
lpexg->debugData.cRtf = 0;
if(size == 0) {
return sheNone; // No data to read... Just return.
}
if(fDbgFile) {
cFunc = size / sizeof(IMAGE_FUNCTION_ENTRY);
diff = 0;
} else {
cFunc = size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
if (loadAddress) {
diff = loadAddress - imageBase;
} else {
diff = 0;
}
}
lpexg->fIsRisc = TRUE;
fpos = SYTell(hfile);
if (SYSeek(hfile, start, SEEK_SET) != (LONG) start) {
return(sheCorruptOmf);
}
if(fDbgFile) {
if(!(dbgRf = (PIMAGE_FUNCTION_ENTRY) MHAlloc(size))) {
return sheOutOfMemory;
}
SYReadFar(hfile, (LPB)dbgRf, size);
size = cFunc * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
if(!(tf = rf = (PIMAGE_RUNTIME_FUNCTION_ENTRY) MHAlloc(size))) {
MHFree(dbgRf);
return sheOutOfMemory;
}
//
// This fixes up the function table to look as it does in the un-fixed up image.
//
for (index=0; index<cFunc; index++) {
rf[index].BeginAddress = dbgRf[index].StartingAddress + imageBase;
rf[index].EndAddress = dbgRf[index].EndingAddress + imageBase;
rf[index].PrologEndAddress = dbgRf[index].EndOfPrologue + imageBase;
rf[index].ExceptionHandler = 0;
rf[index].HandlerData = 0;
}
MHFree(dbgRf);
} else {
if(!(tf = rf = (PIMAGE_RUNTIME_FUNCTION_ENTRY) MHAlloc(size))) {
return sheOutOfMemory;
}
SYReadFar(hfile, (LPB)rf, size);
}
// If this is an ilink'd image, there'll be padding at the end of the pdata section
// (to allow for insertion later). Shrink the table if this is true.
// Find the start of the padded page (end of the real data)
for(index=0; index<cFunc && tf->BeginAddress; tf++,index++) {
;
}
if(index < cFunc) {
cFunc = index;
size = index * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
if(!(rf = (PIMAGE_RUNTIME_FUNCTION_ENTRY) MHRealloc(rf, size))) {
return sheOutOfMemory;
}
}
if (diff != 0) {
for (index=0; index<cFunc; index++) {
rf[index].BeginAddress += diff;
rf[index].EndAddress += diff;
rf[index].PrologEndAddress += diff;
rf[index].ExceptionHandler = 0;
rf[index].HandlerData = 0;
}
}
lpexg->debugData.lpRtf = rf;
lpexg->debugData.cRtf = cFunc;
SYSeek(hfile, fpos, SEEK_SET);
return sheNone;
}
// CheckSignature - check file signature
//
// she = CheckSignature (INT hfile, OMFSignature *pSig)
//
// Entry hfile = handle to file
// pSig = location where signature should be written to
// ppdb = PDB information.
//
// Exit none
//
// Return sheNoSymbols if exe has no signature
// sheMustRelink if exe has NB00 to NB06 or NB07 (qcwin) signature
// sheNotPacked if exe has NB08 signature
// sheNone if exe has NB11 signature
// sheConvertTIs if exe has NB09 signature
// sheFutureSymbols if exe has NB12 to NB99 signature
LOCAL SHE
CheckSignature(
INT hfile,
OMFSignature *pSig,
PDB_INFO *ppdb
)
{
UINT uSig;
if ((SYReadFar (hfile, (LPB) pSig, sizeof (*pSig)) != sizeof (*pSig)) ||
(pSig->Signature[0] != 'N') ||
(pSig->Signature[1] != 'B') ||
(!isdigit(pSig->Signature[2])) ||
(!isdigit(pSig->Signature[3]))) {
return sheNoSymbols;
}
switch (*(LONG UNALIGNED *)(pSig->Signature)) {
case sigNB05:
case sigNB06:
case sigNB07:
return sheMustRelink;
case sigNB08:
return sheNotPacked;
case sigNB09:
return sheConvertTIs;
case sigNB10:
SYReadFar(hfile, (LPB)ppdb, sizeof(PDB_INFO));
case sigNB11:
return sheNone;
default:
return sheFutureSymbols;
}
}
// OLMkSegDir - MakeSegment directory
//
// Entry
//
// Returns non-zero for success
BOOL
OLMkSegDir(
WORD csgd,
LPSGD *lplpsgd,
LPSGE *lplpsge,
LPEXG lpexg
)
{
LPSGD lpsgd;
LPSGE lpsge = NULL;
int *lpisge;
int csgc = 0;
int isge = 0;
int isgd = 0;
DWORD iMod;
if (!(lpsgd = (LPSGD) MHAlloc (csgd * sizeof (SGD)))) {
return FALSE;
}
if (!(lpisge = (int *) MHAlloc (csgd * sizeof (int)))) {
MHFree(lpsgd);
return FALSE;
}
memset(lpsgd, 0, csgd * sizeof(SGD));
memset(lpisge, 0, csgd * sizeof(int));
// Count the number of contributers per segment
for (iMod = 1; iMod <= lpexg->cMod; iMod++) {
LPMDS lpmds = &lpexg->rgMod[iMod];
int cseg = lpmds->csgc;
int iseg = 0;
int isegT = 0;
for (iseg = 0; iseg < cseg; iseg++) {
isegT = lpmds->lpsgc [ iseg ].seg;
if (isegT != 0) {
lpsgd [ isegT - 1 ].csge += 1;
csgc += 1;
}
}
}
// Allocate subtable for each all segments
lpsge = (LPSGE) MHAlloc (csgc * sizeof (SGE));
if (!lpsge) {
MHFree (lpsgd);
MHFree (lpisge);
return FALSE;
}
// Set up sgd's with pointers into appropriate places in the sge table
isge = 0;
for (isgd = 0; isgd < (int) csgd; isgd++) {
lpsgd[ isgd ].lpsge = lpsge + isge;
isge += lpsgd[ isgd ].csge;
}
// Fill in the sge table
for (iMod = 1; iMod <= lpexg->cMod; iMod += 1) {
LPMDS lpmds = &lpexg->rgMod[iMod];
int cseg = lpmds->csgc;
int iseg = 0;
for (iseg = 0; iseg < cseg; iseg++) {
int isgeT = lpmds->lpsgc[ iseg ].seg - 1;
if (isgeT != -1) {
lpsgd[ isgeT ].lpsge[ lpisge[ isgeT ]].sgc =
lpmds->lpsgc[ iseg ];
lpsgd[ isgeT ].lpsge[ lpisge[ isgeT ]].hmod =
(HMOD)lpmds;
lpisge[ isgeT ] += 1;
}
}
}
MHFree (lpisge);
*lplpsge = lpsge;
*lplpsgd = lpsgd;
return TRUE;
}
// OLMkModule - make module entries for module
//
// Entry lpexg - Supplies the pointer to the EXG structure for current exe
// hexg - Supplies the handle EXG structure
//
// Returns non-zero for success
LOCAL int
OLMkModule(
LPEXG lpexg,
HEXG hexg
)
{
LSZ lszModName;
LPMDS lpmds;
LPB lpbName;
WORD cbName;
WORD i;
OMFModule *pMod;
// Point to the OMFModule table. This structure describes the name and
// segments for the current Module being processed. There is a one to one
// correspondance of modules to object files.
pMod = (OMFModule *) (lpexg->lpbData + lpdssCur->lfo);
// Point to the name field in the module table. This location is variable
// and is dependent on the number of contributuer segments for the module.
lpbName = ((LPB)pMod) +
offsetof (OMFModule, SegInfo[0]) +
(sizeof (OMFSegDesc) * pMod->cSeg);
cbName = *((LPB)lpbName)++;
lszModName = (LPCH) MHAlloc (cbName + 1);
memmove(lszModName, lpbName, cbName);
*(lszModName + cbName) = 0;
lpmds = &lpexg->rgMod[lpdssCur->iMod];
lpmds->imds = lpdssCur->iMod;
lpmds->hexg = hexg;
lpmds->name = lszModName;
// step thru making the module entries
//
// NOTENOTE -- This can most likely be optimized as the data
// is just being copied from the debug data.
lpmds->csgc = pMod->cSeg;
lpmds->lpsgc = (LPSGC)MHAlloc ( pMod->cSeg * sizeof ( SGC ) );
for ( i = 0; i < pMod->cSeg; i++ ) {
if ( pMod->SegInfo[i].Seg > csegExe ) {
csegExe = pMod->SegInfo[i].Seg;
}
lpmds->lpsgc[i].seg = pMod->SegInfo[i].Seg;
lpmds->lpsgc[i].off = pMod->SegInfo[i].Off;
lpmds->lpsgc[i].cb = pMod->SegInfo[i].cbSeg;
}
return TRUE;
}
LOCAL SHE
NB10LoadModules(
LPEXG lpexg,
ULONG* pcMods,
HEXG hexg
)
{
Mod* pmod = NULL;
ULONG cMod = 0;
IMOD imod;
// First count up the number of Mods
while (DBIQueryNextMod(lpexg->pdbi, pmod, &pmod) && pmod) {
if(!ModQueryImod(pmod, &imod))
return sheCorruptOmf;
if(imod > *pcMods)
cMod = imod;
}
*pcMods = cMod;
// Got the count. Allocate rgMod.
lpexg->rgMod = (LPMDS) MHAlloc((cMod+2) * sizeof(MDS));
if (lpexg->rgMod == NULL) {
return sheOutOfMemory;
}
memset(lpexg->rgMod, 0, sizeof(MDS)*(cMod+2));
lpexg->rgMod[cMod+1].imds = (WORD) -1;
// Now fill in the blanks.
pmod = NULL;
for (; cMod; cMod--) {
LPMDS lpmds;
LPCH lpchName;
CB cbName;
DBIQueryNextMod(lpexg->pdbi, pmod, &pmod);
if(!ModQueryImod(pmod, &imod))
return sheCorruptOmf;
lpmds = &lpexg->rgMod[imod];
lpmds->imds = imod;
lpmds->pmod = pmod;
lpmds->hexg = hexg;
if(!ModQueryName(pmod, NULL, &cbName))
return sheCorruptOmf;
lpmds->name = (LSZ) MHAlloc(cbName);
if(!lpmds->name)
return sheOutOfMemory;
if(!ModQueryName(pmod, lpmds->name, &cbName))
return sheCorruptOmf;
if(!ModSetPvClient(pmod, lpmds))
return sheCorruptOmf;
}
return sheNone;
}
LOCAL BOOL
OLLoadHashTable(
LPB lpbData,
ULONG cbTable,
LPSHT lpsht,
BOOL fDWordChains
)
{
WORD ccib = 0;
LPUL rgib = NULL;
LPUL rgcib = NULL;
ULONG cbHeader = 0;
LPB lpHashStart = lpbData;
memset(lpsht, 0, sizeof(SHT));
ccib = *(WORD *)lpbData; // First, get the hash bucket counts
lpbData += 4; // the 2 byte hash count and 2 bytes padding
rgib = (LPUL) lpbData;
lpbData += ccib * sizeof(ULONG);
rgcib = (LPUL) lpbData;
lpbData += ccib * sizeof(ULONG);
// Subtract off what we've processed already.
cbTable -= (lpbData - lpHashStart);
lpsht->ccib = ccib;
lpsht->rgib = rgib;
lpsht->rgcib = rgcib;
lpsht->lpalm = BuildALM(FALSE,
btAlign,
lpbData,
cbTable,
cbAlign);
if (lpsht->lpalm == NULL) {
return FALSE;
}
return TRUE;
}
LOCAL BOOL
OLLoadHashSubSec(
LPGST lpgst,
LPB lpbData,
WidenTi * pwti
)
{
LPB lpbTbl = NULL;
OMFSymHash hash;
ULONG cbSymbol;
BOOL fRet = TRUE;
LPSHT lpshtName = &lpgst->shtName;
LPSHT lpshtAddr = &lpgst->shtAddr;
memset(lpshtAddr, 0, sizeof(SHT));
memset(lpshtName, 0, sizeof(SHT));
hash = *(OMFSymHash *)lpbData;
lpbData += sizeof (OMFSymHash);
cbSymbol = hash.cbSymbol;
if (pwti) {
ConvertGlobal16bitSyms(pwti, lpgst, lpbData, cbSymbol);
}
else
{
lpgst->lpalm = BuildALM(TRUE,
btAlign,
lpbData,
cbSymbol,
cbAlign);
}
if (lpgst->lpalm == NULL) {
return FALSE;
}
lpbData += cbSymbol;
// if (hash.symhash == 6 || hash.symhash == 10) {
if (hash.symhash == 10) {
fRet = OLLoadHashTable(lpbData,
hash.cbHSym,
&lpgst->shtName,
hash.symhash == 10);
lpgst->shtName.HashIndex = hash.symhash;
}
lpbData += hash.cbHSym;
// if (hash.addrhash == 8 || hash.addrhash == 12) {
if (hash.addrhash == 12) {
fRet = OLLoadHashTable(lpbData,
hash.cbHAddr,
&lpgst->shtAddr,
hash.addrhash == 12);
lpgst->shtAddr.HashIndex = hash.addrhash;
}
return fRet;
}
// OLLoadTypes - load compacted types table
//
// Input: lpexg - Pointer to exg we're working on.
//
// Returns: - An error code
LOCAL SHE
OLLoadTypes(
LPEXG lpexg
)
{
LPB pTyp;
LPB pTypes;
OMFTypeFlags flags;
DWORD cType = 0;
DWORD *rgitd = NULL;
DWORD ibType = 0;
pTyp = pTypes = lpexg->lpbData + lpdssCur->lfo;
flags = *(OMFTypeFlags *) pTypes;
pTypes += sizeof(OMFTypeFlags);
cType = *(ULONG *) pTypes;
pTypes += sizeof(ULONG);
if (!cType) {
return sheNone;
}
// Point to the array of pointers to types
rgitd = (DWORD *) pTypes;
// Move past them
pTypes += cType * sizeof(ULONG);
// Read in the type index table
ibType = pTypes - pTyp;
lpexg->lpalmTypes = BuildALM (FALSE,
btAlign,
pTypes,
lpdssCur->cb - ibType,
cbAlignType);
if (lpexg->lpalmTypes == NULL) {
return sheOutOfMemory;
}
lpexg->rgitd = rgitd;
lpexg->citd = cType;
return sheNone;
}
// OLLoadSym - load symbol information
//
// error = OLLoadSym (pMod)
//
// Entry lpexg - Pointer to exg structure to use.
//
// Returns sheNone if symbols loaded
SHE
OLLoadSym(
LPEXG lpexg
)
{
// UNDONE: If we run into problems with a stale VC, we'll have to
// revert to reading the file on demand. The expectation is that the
// mapped I/O code will just work.
// lpexg->rgMod[lpdssCur->iMod].symbols = NULL;
if (lpexg->pwti) {
// we be converting 16-bit symbols to 32-bit versions.
SHE sheRet = sheOutOfMemory;
WidenTi * pwti = lpexg->pwti;
PMDS pmod = &lpexg->rgMod[lpdssCur->iMod];
SymConvertInfo & sci = pmod->sci;
PB pbSyms = lpexg->lpbData + lpdssCur->lfo;
CB cbSyms = lpdssCur->cb;
// Remember the signature!
if (pwti->fQuerySymConvertInfo (sci, pbSyms, cbSyms, sizeof ULONG)) {
sci.pbSyms = PB(MHAlloc (sci.cbSyms));
sci.rgOffMap = POffMap(MHAlloc (sci.cSyms * sizeof OffMap));
if (sci.pbSyms && sci.rgOffMap) {
memset (sci.pbSyms, 0, sci.cbSyms);
memset (sci.rgOffMap, 0, sci.cSyms * sizeof OffMap);
if (pwti->fConvertSymbolBlock (sci, pbSyms, cbSyms, sizeof ULONG) ) {
pmod->symbols = sci.pbSyms;
*(ULONG*)pmod->symbols = CV_SIGNATURE_C11;
pmod->cbSymbols = sci.cbSyms;
// REVIEW: What about pmod->ulsym? how is it used?
sheRet = sheNone;
}
else {
sheRet = sheCorruptOmf;
}
}
}
return sheRet;
}
else
{
lpexg->rgMod[lpdssCur->iMod].symbols = lpexg->lpbData + lpdssCur->lfo;
lpexg->rgMod[lpdssCur->iMod].cbSymbols = lpdssCur->cb;
lpexg->rgMod[lpdssCur->iMod].ulsym = lpdssCur->lfo;
return sheNone;
}
}
__inline SHE
OLLoadSrc(
LPEXG lpexg
)
{
lpexg->rgMod[lpdssCur->iMod].hst = (HST) (lpexg->lpbData + lpdssCur->lfo);
return sheNone;
}
__inline SHE
OLGlobalPubs(
LPEXG lpexg
)
{
SHE she = sheNone;
if (!OLLoadHashSubSec (&lpexg->gstPublics,
lpexg->lpbData + lpdssCur->lfo,
lpexg->pwti)) {
she = sheOutOfMemory;
}
return she;
}
__inline SHE
OLGlobalSym(
LPEXG lpexg
)
{
SHE she = sheNone;
if (!OLLoadHashSubSec (&lpexg->gstGlobals,
lpexg->lpbData + lpdssCur->lfo,
lpexg->pwti)) {
she = sheOutOfMemory;
}
return she;
}
LOCAL SHE
OLLoadSegMap(
LPEXG lpexg
)
{
LPB lpb;
SHE sheRet = sheNone;
if(lpexg->pdbi) {
CB cb;
// load from the pdb
if(!DBIQuerySecMap(lpexg->pdbi, NULL, &cb) ||
!(lpb = (LPB) MHAlloc (cb))) {
sheRet = sheOutOfMemory;
} else
if(!DBIQuerySecMap(lpexg->pdbi, lpb, &cb)) {
MHFree(lpb);
lpb = NULL;
sheRet = sheOutOfMemory;
}
} else {
lpb = lpexg->lpbData + lpdssCur->lfo;
}
lpexg->lpgsi = lpb;
return sheRet;
}
LOCAL SHE
OLLoadNameIndex(
LPEXG lpexg
)
{
OMFFileIndex * lpefi;
WORD cmod = 0;
WORD cfile = 0;
CB cb;
if(lpexg->pdbi) {
if(!DBIQueryFileInfo(lpexg->pdbi, 0, &cb)) {
return sheNoSymbols;
}
else if(!(lpefi = (OMFFileIndex *) MHAlloc(cb))) {
return sheOutOfMemory;
}
else if(!DBIQueryFileInfo(lpexg->pdbi, (PB)lpefi, &cb)) {
MHFree(lpefi);
return sheNoSymbols;
}
} else {
lpefi = (OMFFileIndex *)(lpexg->lpbData + lpdssCur->lfo);
cb = (CB)lpdssCur->cb;
}
cmod = lpefi->cmodules;
// Make sure we found as many sstModule entries as we should have.
assert(cmod == lpexg->cMod);
// lpexg->cmod = cmod;
cfile = lpefi->cfilerefs;
lpexg->lpefi = (LPB) lpefi;
lpexg->rgiulFile = lpefi->modulelist;
lpexg->rgculFile = &lpefi->modulelist [cmod];
lpexg->rgichFile = (LPUL) &lpefi->modulelist [cmod * 2];
lpexg->lpchFileNames = (LPCH) &lpefi->modulelist [cmod * 2 + cfile * 2];
lpexg->cbFileNames =
(ULONG)(cb - ((LPB)lpexg->lpchFileNames - (LPB)lpefi + 1));
return sheNone;
}
LOCAL SHE
OLStaticSym(
LPEXG lpexg
)
{
SHE she = sheNone;
if (!OLLoadHashSubSec (&lpexg->gstStatics,
lpexg->lpbData + lpdssCur->lfo,
lpexg->pwti)) {
she = sheOutOfMemory;
}
return she;
}
const SHE mpECToShe[] = {
sheNone, // EC_OK
sheNoSymbols, // EC_USAGE (invalid parameter of call order)
sheOutOfMemory, // EC_OUT_OF_MEMORY (-, out of RAM)
sheNoSymbols, // EC_FILE_SYSTEM (pdb name, can't write file, out of disk, etc)
shePdbNotFound, // EC_NOT_FOUND (PDB file not found)
shePdbBadSig, // EC_INVALID_SIG (PDB::OpenValidate() and its clients only)
shePdbInvalidAge, // EC_INVALID_AGE (PDB::OpenValidate() and its clients only)
sheNoSymbols, // EC_PRECOMP_REQUIRED (obj name, Mod::AddTypes only)
sheNoSymbols, // EC_OUT_OF_TI (pdb name, TPI::QueryTiForCVRecord() only)
sheNoSymbols, // EC_NOT_IMPLEMENTED
sheNoSymbols, // EC_V1_PDB (pdb name, PDB::Open() only)
shePdbOldFormat, // EC_FORMAT (accessing pdb with obsolete format)
sheNoSymbols, // EC_LIMIT,
sheNoSymbols, // EC_CORRUPT, // cv info corrupt, recompile mod
sheNoSymbols, // EC_TI16, // no 16-bit type interface present
sheNoSymbols, // EC_ACCESS_DENIED, // "pdb name", PDB file read-only
};
// Get the name of the pdb file (OMF name) for the specified exe. If the
// LoadPdb hasn't been called on this exe OR it's not NB10, this will return
// an empty string! Note: There will only be an lszPdbName if there was
// an error loading the pdb
VOID LOADDS
SHPdbNameFromExe(
LSZ lszExe,
LSZ lszPdbName,
UINT cbMax
)
{
HEXE hexe;
// Zero out the destination
memset(lszPdbName, 0, cbMax);
// Look up the exe
if (hexe = SHGethExeFromName(lszExe)) {
HEXG hexg = ((LPEXE)LLLock(hexe))->hexg;
LPEXG lpexg = (LPEXG)LLLock(hexg);
// Only copy if there's a pdbname
if (lpexg->lszPdbName) {
_tcsncpy(lszPdbName, lpexg->lszPdbName, cbMax);
}
// Clean up
LLUnlock(hexg);
LLUnlock(hexe);
}
}
BOOL
GetDefaultKeyName(
LPCTSTR KeySuffix,
LPTSTR KeyBuffer,
DWORD nLength
)
{
DWORD lnLength = nLength;
if (!GetRegistryRoot (KeyBuffer, &lnLength))
return FALSE;
if (KeyBuffer [lnLength - 1] != '\\') {
KeyBuffer [lnLength++] = '\\';
KeyBuffer [lnLength] = '\000';
}
assert (*KeySuffix != '\\');
_tcscpy (&KeyBuffer [lnLength], KeySuffix);
return TRUE;
}
LOCAL SHE
LoadPdb(
LPEXG lpexg,
PDB_INFO *ppdb
)
{
EC ec;
char szRefPath[_MAX_PATH];
char szPDBOut[cbErrMax];
assert(lpexg);
// figure out the home directory of the EXE/DLL or DBG file - pass that along to
// OpenValidate this will direct to dbi to search for it in that directory.
_fullpath(szRefPath, lpexg->lszDebug ? lpexg->lszDebug : lpexg->lszName, _MAX_PATH);
char *pcEndOfPath = _tcsrchr(szRefPath, '\\');
*pcEndOfPath = '\0'; // null terminate it
*szPDBOut = '\0';
#ifdef NT_BUILD_ONLY
ULONG cbRet;
if (!SYGetProfileString(szPdbDirs,
szSearchPath,
sizeof(szSearchPath),
&cbRet)) {
szSearchPath[0] = 0;
}
#else
HKEY hSectionKey = NULL;
DWORD nType = REG_SZ;
DWORD nSize = sizeof(szSearchPath);
if (*szDefaultKeyName == '\000') {
GetDefaultKeyName (szKeySuffix, szDefaultKeyName, sizeof (szDefaultKeyName));
}
if (!fQueriedRegistry) {
RegOpenKeyEx(HKEY_CURRENT_USER, szDefaultKeyName, 0, KEY_READ, &hSectionKey);
if ((hSectionKey == NULL) ||
(RegQueryValueEx(hSectionKey,
(char *)szPdbDirs,
NULL,
&nType,
(LPBYTE)szSearchPath,
&nSize) != ERROR_SUCCESS)
) {
szSearchPath[0] = 0;
}
fQueriedRegistry = TRUE;
}
#endif
BOOL fOpenValidate = PDBOpenValidateEx(ppdb->sz,
szRefPath,
szSearchPath,
pdbRead,
ppdb->sig,
ppdb->age,
&ec,
szPDBOut,
&(lpexg->ppdb));
if (!fOpenValidate) {
// Save the name of the pdb with the error
if (!(lpexg->lszPdbName = (LSZ)MHAlloc(_tcslen(szPDBOut) + 1))) {
return sheOutOfMemory;
}
_tcscpy(lpexg->lszPdbName, szPDBOut);
return mpECToShe[ec];
}
// Store the name of the pdb in lszDebug.
char *szPdb = PDBQueryPDBName(lpexg->ppdb, (char *)szPDBOut);
assert(szPdb);
// Save the name of the PDB
if (lpexg->lszDebug) {
MHFree(lpexg->lszDebug);
lpexg->lszDebug = 0;
}
if (!(lpexg->lszDebug = (LSZ)MHAlloc(_tcslen(szPDBOut) + 1))) {
return sheOutOfMemory;
}
_tcscpy(lpexg->lszDebug, szPDBOut);
if (!PDBOpenTpi(lpexg->ppdb, pdbRead, &(lpexg->ptpi))) {
ec = PDBQueryLastError(lpexg->ppdb, NULL);
return mpECToShe[ec];
}
if (!PDBOpenDBIEx(lpexg->ppdb, pdbRead, lpexg->lszName, &(lpexg->pdbi), pSYFindDebugInfoFile)) {
ec = PDBQueryLastError(lpexg->ppdb, NULL);
return mpECToShe[ ec ];
}
if (!STABOpen(&(lpexg->pstabUDTSym)))
return sheOutOfMemory;
return sheNone;
}
// Routine Description:
//
// This routine is used to validate that the debug information
// in a file matches the debug information requested
//
// Arguments:
//
// hFile - Supplies the file handle to be validated
// lpv - Supplies a pointer to the information to used in vaidation
//
// Return Value:
//
// TRUE if matches and FALSE otherwise
LOCAL SHE
OLValidate(
int hFile,
void * lpv,
LPSTR lpszErrText
)
{
VLDCHK * pVldChk = (VLDCHK *) lpv;
IMAGE_DOS_HEADER exeHdr;
IMAGE_NT_HEADERS peHdr;
int fPeExe = FALSE;
int fPeDbg = FALSE;
if (lpszErrText) {
*lpszErrText = 0;
}
// Read in a dos exe header
if ((SYSeek(hFile, 0, SEEK_SET) != 0) ||
(SYReadFar( hFile, (LPB) &exeHdr, sizeof(exeHdr)) != sizeof(exeHdr))) {
return sheNoSymbols;
}
// See if it is a dos exe hdr
if (exeHdr.e_magic == IMAGE_DOS_SIGNATURE) {
if ((SYSeek(hFile, exeHdr.e_lfanew, SEEK_SET) == exeHdr.e_lfanew) &&
(SYReadFar(hFile, (LPB) &peHdr, sizeof(peHdr)) == sizeof(peHdr))) {
if (peHdr.Signature == IMAGE_NT_SIGNATURE) {
fPeExe = TRUE;
}
}
} else if (exeHdr.e_magic == IMAGE_NT_SIGNATURE) {
fPeExe = TRUE;
} else if (exeHdr.e_magic == IMAGE_SEPARATE_DEBUG_SIGNATURE) {
fPeDbg = TRUE;
}
if (fPeExe) {
if (pVldChk->TimeDateStamp == 0) {
// If the timestamp has not been initialized do so now.
pVldChk->TimeDateStamp = peHdr.FileHeader.TimeDateStamp;
}
if (peHdr.FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
return sheNoSymbols;
}
if ((pVldChk->TimeDateStamp != 0xffffffff) &&
(peHdr.FileHeader.TimeDateStamp != pVldChk->TimeDateStamp)) {
if (lpszErrText) {
sprintf(lpszErrText,
"*** WARNING: symbols timestamp is wrong 0x%08x 0x%08x",
peHdr.FileHeader.TimeDateStamp,
pVldChk->TimeDateStamp);
}
return sheBadTimeStamp;
}
} else if (fPeDbg) {
IMAGE_SEPARATE_DEBUG_HEADER sepHdr;
if ((SYSeek(hFile, 0, SEEK_SET) != 0) ||
(SYReadFar(hFile, (LPB) &sepHdr, sizeof(sepHdr)) != sizeof(sepHdr))) {
return sheNoSymbols;
}
if ((pVldChk->TimeDateStamp != 0xffffffff) &&
(sepHdr.TimeDateStamp != pVldChk->TimeDateStamp)) {
if (lpszErrText) {
sprintf(lpszErrText,
"*** WARNING: symbols timestamp is wrong 0x%08x 0x%08x",
sepHdr.TimeDateStamp,
pVldChk->TimeDateStamp);
}
return sheBadTimeStamp;
}
} else {
// zzFix: For debugging ROM image, we need the following codes
// which are in build 1381.
char rgch[4];
if ((SYSeek(hFile, -8, SEEK_END) == -1) ||
(SYReadFar(hFile, (LPB)rgch, sizeof(rgch)) != sizeof(rgch))) {
return sheNoSymbols;
}
if ((rgch[0] != 'N') || (rgch[1] != 'B')) {
return sheNoSymbols;
}
// return sheNoSymbols;
}
return sheNone;
}
BOOL
OLUnloadOmf(
LPEXG lpexg
)
{
ULONG i;
// Cleanup the Module table;
for (i = 0; i < lpexg->cMod; i++) {
KillMdsNode(&lpexg->rgMod[i]);
}
if (lpexg->rgMod) {
MHFree(lpexg->rgMod);
lpexg->rgMod = NULL;
lpexg->cMod = 0;
}
// module map info
if (lpexg->lpsgd) {
MHFree(lpexg->lpsgd);
lpexg->lpsgd = NULL;
lpexg->csgd = 0;
}
//
if (lpexg->lpsge) {
MHFree(lpexg->lpsge);
lpexg->lpsge = NULL;
}
if (lpexg->lpbData) {
// Depending on how we got the data, free it.
if (lpexg->pvSymMappedBase) {
// Mapped view of file.
UnmapViewOfFile(lpexg->pvSymMappedBase);
lpexg->pvSymMappedBase = NULL;
} else {
if (lpexg->fSymConverted) {
// Converted from coff/sym file
LocalFree(lpexg->lpbData);
} else {
// Read the blob in from disk
MHFree(lpexg->lpbData);
}
}
lpexg->lpbData = NULL;
}
// OSDebug 4 FPO info
if (lpexg->debugData.lpRtf) {
MHFree(lpexg->debugData.lpRtf);
lpexg->debugData.lpRtf = NULL;
}
if (lpexg->debugData.lpOmapFrom) {
MHFree(lpexg->debugData.lpOmapFrom);
lpexg->debugData.lpOmapFrom = NULL;
}
if (lpexg->debugData.lpOmapTo) {
MHFree(lpexg->debugData.lpOmapTo);
lpexg->debugData.lpOmapTo = NULL;
}
if (lpexg->debugData.lpSecStart) {
MHFree(lpexg->debugData.lpSecStart);
lpexg->debugData.lpSecStart = NULL;
}
// Segment map info
if (lpexg->lpgsi) {
if (lpexg->ppdb) {
MHFree (lpexg->lpgsi);
}
lpexg->lpgsi = NULL;
}
// Source Module information
if (lpexg->lpefi) {
if (lpexg->ppdb) {
MHFree(lpexg->lpefi);
}
lpexg->lpefi = NULL;
}
// Type Info array
lpexg->citd = 0;
lpexg->rgitd = NULL;
// Publics, Globals, and Statics
KillGst(&lpexg->gstPublics);
KillGst(&lpexg->gstGlobals);
KillGst(&lpexg->gstStatics);
// If there's PDB info, clean up and close
if (lpexg->ppdb) {
if (lpexg->pgsiPubs) {
if (!GSIClose(lpexg->pgsiPubs)) {
assert(FALSE);
}
lpexg->pgsiPubs = 0;
}
if (lpexg->pgsiGlobs) {
if (!GSIClose(lpexg->pgsiGlobs)) {
assert(FALSE);
}
lpexg->pgsiGlobs = 0;
}
if (lpexg->pdbi) {
if (!DBIClose(lpexg->pdbi)) {
assert(FALSE);
}
lpexg->pdbi = 0;
}
if (lpexg->ptpi) {
if (!TypesClose(lpexg->ptpi)) {
assert(FALSE);
}
lpexg->ptpi = 0;
}
if (lpexg->pstabUDTSym) {
STABClose(lpexg->pstabUDTSym);
lpexg->pstabUDTSym = 0;
}
if (!PDBClose(lpexg->ppdb)) {
assert(FALSE);
}
lpexg->ppdb = 0;
}
lpexg->fOmfLoaded = 0;
return TRUE;
}
cassert(offsetof(OffMap,offOld) == 0);
LOCAL int __cdecl
sgnCompareOffsFromOffMap(
const void * pOff1,
const void * pOff2
)
{
ULONG off1 = POffMap(pOff1)->offOld;
ULONG off2 = POffMap(pOff2)->offOld;
if (off1 < off2)
return -1;
if (off1 > off2)
return 1;
return 0;
}
LOCAL void
FixupHash(
SymConvertInfo & sci,
SHT & sht
)
{
// for every offset in the hash, we need to fixup the offset which
// references the old 16-bit pool with the associated new one for the
// new pool of 32-bit types.
assert(sht.HashIndex);
assert(sci.cSyms);
assert(sci.rgOffMap);
unsigned iBucketMax = sht.ccib;
for (unsigned iBucket = 0; iBucket < iBucketMax; iBucket++) {
unsigned offChain = sht.rgib[iBucket];
unsigned iulpMax = sht.rgcib[iBucket];
for (unsigned iulp = 0; iulp < iulpMax; iulp++, offChain += sizeof ULP ) {
LPULP pulp = LPULP(LpvFromAlmLfo(sht.lpalm, offChain));
POffMap poffmap = POffMap(
bsearch(
&pulp->ib,
sci.rgOffMap,
sci.cSyms,
sizeof OffMap,
sgnCompareOffsFromOffMap
)
);
// we should always find it
//assert(poffmap);
if (poffmap) {
pulp->ib = poffmap->offNew;
}
}
}
}
//
// this routine will do all the post processing for the inter-relationships
// that exist between the module symbols and the global syms. The global
// syms include procref and dataref records that include offsets into the
// module symbols. We have to fix up those offsets to refer to the new
// offsets. Each of these mappings is stored in the MDS structure and can
// be released after this operation.
//
// the hash offsets for the globals, publics, and statics are also fixed up here
//
LOCAL void
FixupGst(
LPEXG pexg,
GST & gst,
BOOL fFixupRefSyms
)
{
assert(pexg->pwti);
if (!gst.lpalm)
return;
// first off, we check to see if we need to and can fixup the refsyms
// that may be present.
if (fFixupRefSyms) {
for (
SYMPTR psym = SYMPTR(gst.lpalm->pbData);
psym;
psym = GetNextSym(psym, gst.lpalm)
) {
unsigned rectyp = psym->rectyp;
if (rectyp == S_PROCREF || rectyp == S_LPROCREF || rectyp == S_DATAREF) {
// fix up the ibSym from the module's array of offset mappings
REFSYM & refsym = *(REFSYM *)psym;
SymConvertInfo & sci = pexg->rgMod[refsym.imod].sci;
POffMap poffmap = POffMap(
bsearch(
&refsym.ibSym,
sci.rgOffMap,
sci.cSyms,
sizeof OffMap,
sgnCompareOffsFromOffMap
)
);
// we should always find it.
assert(poffmap);
if (poffmap) {
refsym.ibSym = poffmap->offNew;
}
}
}
}
// next, we check our hash tables and fix up all of the offsets there.
if (gst.shtName.HashIndex) {
// fixup name hash
FixupHash(gst.sci, gst.shtName);
}
if (gst.shtAddr.HashIndex) {
// fixup address hash
FixupHash(gst.sci, gst.shtAddr);
}
}
LOCAL SHE
SheFixupConvertedSyms(
LPEXG pexg
)
{
// for each of the symbol blocks, iterate over all symbols,
// and if they are REFSYMs of some sort, we go to the appropriate
// module's sci.rgoffmap to find what new offset we need to plug into
// the REFSYM.ibSym field.
FixupGst(pexg, pexg->gstGlobals, TRUE);
FixupGst(pexg, pexg->gstStatics, TRUE);
FixupGst(pexg, pexg->gstPublics, FALSE);
// we can safely get rid of all of our offmap buffers.
// first, the module ones.
unsigned imod = 0;
unsigned imodMax = pexg->cMod;
while (imod < imodMax) {
MDS & mds = pexg->rgMod[imod];
if (mds.sci.rgOffMap) {
MHFree(mds.sci.rgOffMap);
mds.sci.rgOffMap = 0;
}
imod++;
}
// now, the gst versions
if (pexg->gstGlobals.sci.rgOffMap) {
MHFree(pexg->gstGlobals.sci.rgOffMap);
pexg->gstGlobals.sci.rgOffMap = 0;
}
if (pexg->gstStatics.sci.rgOffMap) {
MHFree(pexg->gstStatics.sci.rgOffMap);
pexg->gstStatics.sci.rgOffMap = 0;
}
if (pexg->gstPublics.sci.rgOffMap) {
MHFree(pexg->gstPublics.sci.rgOffMap);
pexg->gstPublics.sci.rgOffMap = 0;
}
return sheNone;
}
LOCAL void
ConvertGlobal16bitSyms(
WidenTi * pwti,
LPGST pgst,
PB pbSymSrc,
ULONG cbSymSrc
)
{
SymConvertInfo & sci = pgst->sci;
memset ( &sci, 0, sizeof sci );
if (pwti->fQuerySymConvertInfo(sci, pbSymSrc, cbSymSrc)) {
// allocate the needed memory
sci.pbSyms = PB(MHAlloc(sci.cbSyms));
sci.rgOffMap = POffMap(MHAlloc(sci.cSyms * sizeof OffMap));
if (sci.pbSyms && sci.rgOffMap) {
memset(sci.pbSyms, 0, sci.cbSyms);
memset(sci.rgOffMap, 0, sci.cSyms * sizeof OffMap);
if (pwti->fConvertSymbolBlock(sci, pbSymSrc, cbSymSrc)) {
// all cool, set up the ALM.
pgst->lpalm = BuildALM(
FALSE,
0,
sci.pbSyms,
sci.cbSyms,
cbAlign);
}
}
}
}
//// LazyLoader
//
// Description:
// This routine is used to do lazy loads and unloads of debug
// information.
DWORD
LazyLoader(
LPVOID
)
{
BOOL fNoChanges;
FILETIME ftNow;
LONGLONG llNow;
HEXG hexg;
LPEXG pexg;
//
// We loop forever until told to die
//
for (; TRUE; ) {
//
// Wait for someone to tell us that we some work to do, or
// a suffient amount of time has passed that we should go
// out and check for defered unloads
//
// Current time out on lazy unloads is 10 minutes
//
if (WaitForSingleObject(HevntLazyLoad, 1000*60*10) == WAIT_OBJECT_0) {
//
// If we have been told to die -- die
//
if (FKillLazyLoad) {
break;
}
//
// We were just told that a dll has been loaded and we should
// check symbols -- wait for a minute just incase the symbols
// are immeadiately demand loaded
//
Sleep(10*1000);
}
//
// Walk the entire list of exe's looking for modules to be loaded
// and modules to be unloaded.
//
GetSystemTimeAsFileTime(&ftNow);
memcpy(&llNow, &ftNow, sizeof(LONGLONG));
do {
hexg = LLFind(HlliExgExe, 0, &llNow, 2);
if (hexg != NULL) {
pexg = (LPEXG) LLLock(hexg);
//
// Check for defer load modules
//
if (pexg->fOmfDefered) {
LLUnlock(hexg);
LoadSymbols(hexg, TRUE);
}
//
// Check for defered unload of symbols
else if (pexg->llUnload != 0) {
LLUnlock(hexg);
LLDelete(HlliExgExe, hexg);
}
}
} while (hexg != NULL);
}
return 1;
}
BOOL
StartLazyLoader(
void
)
{
//
// Setup the items used for lazy load of symbols
//
InitializeCriticalSection(&CsExeModify);
HevntLazyLoad = CreateEvent(NULL, FALSE, FALSE, NULL);
//HthdLazyLoad = CreateThread(NULL, 0, LazyLoader, NULL, 0, NULL);
// SetThreadPriority(HthdLazyLoad, THREAD_PRIORITY_IDLE);
return TRUE;
}
VOID
StopLazyLoader(
void
)
{
//
// Tell the lazy loader it is suppose to die and then start the thread
// going again
//
FKillLazyLoad = TRUE;
SetEvent(HevntLazyLoad);
//
// Wait for the lazy loaded to die
//
//WaitForSingleObject(HthdLazyLoad, INFINITE);
//
// Close and zero the handles
//
CloseHandle(HevntLazyLoad);
HevntLazyLoad = NULL;
//CloseHandle(HthdLazyLoad);
HthdLazyLoad = NULL;
DeleteCriticalSection(&CsExeModify);
return;
}