Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2551 lines
72 KiB

// 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 = 0;
static WORD csegExe = 0;
static PIMAGE_SECTION_HEADER SecHdr;
static unsigned int SecCount;
static DWORD ImageAlign;
static WORD btAlign = 0; // Alignment bit
typedef struct _PDB_INFO {
SIG sig;
AGE age;
char sz[_MAX_PATH];
} PDB_INFO;
static PDB_INFO pdbInfo;
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);
LOCAL SHE NB10LoadOmf (LPEXG, HEXG);
LOCAL SHE LoadPdb (LPEXG, PDB_INFO *);
LOCAL SHE NB10LoadModules (LPEXG, ULONG*, HEXG);
LOCAL VOID LoadSymbols(HPDS, 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);
#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[] =
"Software\\Microsoft\\Developer\\Build System\\Components\\Platforms\\"
#ifdef TARGMAC68K
"Macintosh"
#elif defined (TARGMACPPC)
"Power Macintosh"
#elif defined (TARGALPHA)
"Win32 (ALPHA)"
#elif defined (_MIPS_)
"Win32 (MIPS)"
#else // This must be x86.
"Win32 (x86)"
#endif
"\\Directories" ;
static TCHAR szPdbDirs[] = "Pdb Dirs";
TCHAR rgSearchPath[MAX_SEARCH_PATH_LEN];
BOOL fQueriedRegistry = FALSE;
// 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(hpdsCur, hexg, TRUE);
return;
}
VOID
UnloadDefered(
HEXG hexg
)
{
return;
}
// 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 *vldChk,
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;
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 = vldChk->TimeDateStamp;
lpexg->ulCheckSum = vldChk->CheckSum;
lpexg->debugData.she = sheRet;
if ((sheRet != sheNone) && (sheRet != sheSymbolsConverted)) {
if (sheRet == sheNoSymbols) {
lpexg->fOmfMissing = TRUE;
} else if (sheRet == sheSuppressSyms) {
lpexg->fOmfSkipped = TRUE;
} else if ( sheRet == sheDeferSyms) {
lpexg->fOmfDefered = TRUE;
// ShAddBkgrndSymbolLoad(hexg);
}
LLUnlock (hexg);
return sheRet;
}
LLUnlock(hexg);
// If we made it this far, we must load the symbols
LoadSymbols(hpdsCur, hexg, FALSE);
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(
HPDS hpds,
HEXG hexg,
BOOL fNotifyShell
)
{
SHE sheRet;
HEXE hexe;
LPEXG lpexg = NULL;
LPPDS lppds = NULL;
LPEXE lpexe = NULL;
LPSTR lpname = NULL;
HPDS hpdsLast;
// EnterCriticalSection( &CsSymbolLoad );
// find the exe for this exg
hexe = NULL;
while ((hexe=SHGetNextExe(hexe))) {
lpexe = (LPEXE) LLLock(hexe);
if ((hexg == lpexe->hexg) &&
(hpds == lpexe->hpds))
{
break;
} else {
LLUnlock(hexe);
}
}
if (!hexe) {
goto done; // didn't find a hexg/hpds match
}
// lock down the necessary data structures
lpexg = (LPEXG) LLLock(hexg);
if (!lpexg) {
goto done;
}
lppds = (LPPDS) LLLock(lpexe->hpds);
if (!lppds) {
goto done;
}
// mark the module as being loaded
lpexg->fOmfLoading = TRUE;
// LeaveCriticalSection( &CsSymbolLoad );
// load the symbols (yes, pass both lpexg and hexg.
// OlMkModule needs hexg for creating the lpmds)
sheRet = LoadOmfForReal(lpexg, hexg);
// EnterCriticalSection( &CsSymbolLoad );
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;
}
// hpdsLast = SHChangeProcess(hpds, TRUE);
hpdsLast = SHChangeProcess(hpds);
DLoadedSymbols(sheRet, lppds->hpid, lpname);
// SHChangeProcess(hpdsLast, FALSE);
SHChangeProcess(hpdsLast);
}
// update the module flags
lpexg->fOmfDefered = FALSE;
lpexg->fOmfLoading = FALSE;
done:
// LeaveCriticalSection( &CsSymbolLoad );
// free resources
if (lpexe) {
if (lppds) {
LLUnlock(lpexe->hpds);
}
LLUnlock(hexe);
}
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 ((sheRet != sheNone) && (sheRet != sheSymbolsConverted)) {
goto returnhere;
}
if (lpexg->ppdb) {
sheRet = NB10LoadOmf(lpexg, hexg);
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;
}
}
} __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;
}
// OLOPENDBGFILE
//
// PURPOSE:
// Helper function to open the .dbg file it the debug info from the
// original one has been stripped. We might want to make this a callback
// implemented by the kernel.
//
// INPUT:
// lpszModName -- name of the .dll being loaded
// lpszDbgName -- Buffer to which the path of the .dbg file is written
// lpVldChk -- pointer to a validity check structure which is used
// to ascertain that we have the correct .dbg file.
// OUTPUT:
// File handle if a .dbg file was opened succesufully.
// -1 otherwise
//
// EXCEPTIONS:
//
// IMPLEMENTATION:
// Look for the .dbg file in the following order
// a) The directory which the dll was found in.
// b) Along the _NT_ALT_SYMBOL_PATH environment variable
// c) Along the _NT_SYMBOL_PATH environment variable.
// d) in the %SystemRoot%\symbols\dll directory
HFILE
OLOpenDbgFile(
LSZ lpszModName,
LSZ lpszDbgName,
LPVLDCHK lpVldChk
)
{
INT hFile = -1;
TCHAR szDrive[_MAX_CVDRIVE];
TCHAR szDir[_MAX_CVDIR];
TCHAR szName[_MAX_CVFNAME];
TCHAR szExt[_MAX_CVEXT];
TCHAR szSearchPath[MAX_SEARCH_PATH_LEN];
TCHAR szRelName[_MAX_CVFNAME]; // typically something like symbols\dll\foo.dbg
TCHAR szTmpDbgName[_MAX_CVPATH];
TCHAR szDbgExt[] = __T(".DBG");
TCHAR szSymbols[] = __T("SYMBOLS\\");
// We will look for the .dbg file along these environment variables in
// order.
TCHAR * rgszDbgPath[] = {
__T("_NT_ALT_SYMBOL_PATH"),
__T("_NT_SYMBOL_PATH"),
__T("SystemRoot"),
};
TCHAR pathSep = __T('\\'); // Separates dir names within the PATH env variable
assert(lpszModName != NULL);
assert(lpszDbgName != NULL);
_tsplitpath(lpszModName, szDrive, szDir, szName, szExt);
// First look for the dbg file in the same directory as the .dll
_tmakepath(szTmpDbgName, szDrive, szDir, szName, szDbgExt);
hFile = (INT) SYOpen(szTmpDbgName);
if (hFile == -1) {
TCHAR * lpszCurr = szRelName;
int i;
// create the symbols\ext\file.dbg part of the filename
_tcscpy(lpszCurr, szSymbols);
lpszCurr += _tcslen(szSymbols);
_tcscpy(lpszCurr, (szExt + 1));
lpszCurr += _tcslen(szExt + 1);
*lpszCurr++ = pathSep;
_tcscpy(lpszCurr, szName);
lpszCurr += _tcslen(szName);
_tcscpy(lpszCurr, szDbgExt);
for (i = 0; i < sizeof(rgszDbgPath)/sizeof(rgszDbgPath[0]); i++) {
DWORD cbStr;
if ((cbStr = GetEnvironmentVariable(rgszDbgPath[i], szSearchPath,
MAX_SEARCH_PATH_LEN)) != 0) {
if(cbStr > MAX_SEARCH_PATH_LEN) {
assert(FALSE); // Shouldn't happen in nature.
return -1 ;
}
if ((cbStr = SearchPath(szSearchPath, szRelName, NULL,
_MAX_CVPATH, szTmpDbgName, NULL)) != 0) {
if (cbStr > _MAX_CVPATH) {
return -1;
}
hFile = SYOpen(szTmpDbgName);
if (hFile != -1) {
break;
}
}
}
}
}
if (hFile != -1) {
IMAGE_SEPARATE_DEBUG_HEADER sephdr;
// Read the header and do the validity check. Note that it we accept
// the checksum not matching if the timestamp matches. This is for
// cases where the NT setup program patches dlls at setup time.
// the file is re-checksumed but the timedatestamp on the dll and
// dbg will still be the same.
if (SYReadFar(hFile, (LPB)&sephdr, sizeof(sephdr)) != sizeof(sephdr) ||
(sephdr.Signature != IMAGE_SEPARATE_DEBUG_SIGNATURE) ||
((lpVldChk->CheckSum != sephdr.CheckSum) &&
(lpVldChk->TimeDateStamp != sephdr.TimeDateStamp)
)
) {
SYClose(hFile);
hFile = -1;
} else {
_tcscpy(lpszDbgName, szTmpDbgName);
}
}
return (hFile);
}
#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;
vldChk.CheckSum = lpexg->ulCheckSum;
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;
}
lpexg->lszDebug = _strdup(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;
}
lpexg->lszDebug = _strdup(szFName);
}
// 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. 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 (strcmp((char *) SecHdr[ul].Name, ".pdata") == 0) {
LoadPdata(lpexg,
hfile,
dllLoadAddress,
pehdr.OptionalHeader.ImageBase,
SecHdr[ul].PointerToRawData,
SecHdr[ul].SizeOfRawData,
FALSE);
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 (!strcmp((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;
}
if ((sheRet = CheckSignature (hfile, &Signature, &pdbInfo)) != sheNone) {
goto ReturnHere;
}
}
break;
case NTDBG_IMAGE:
SecCount = sepHdr.NumberOfSections;
if (sepHdr.SectionAlignment) {
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;
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
cvDbgDir = dbgDir;
continue;
}
if (dbgDir.Type == IMAGE_DEBUG_TYPE_FPO) {
LoadFpo(lpexg, hfile, &dbgDir);
}
// UNDONE: We can eliminate this load for images
// that we've already processed the pdata from the
// real image...
if (dbgDir.Type == IMAGE_DEBUG_TYPE_EXCEPTION) {
LoadPdata(lpexg,
hfile,
dllLoadAddress,
sepHdr.ImageBase,
dbgDir.PointerToRawData,
dbgDir.SizeOfData,
TRUE);
}
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) {
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;
}
if ((sheRet = CheckSignature (hfile, &Signature, &pdbInfo)) != sheNone) {
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)) == '01BN') {
// No need to keep the debug image filename any longer since
// LoadPdb will store the pdb filename anyway.
// UNDONE: If we get the name from the .dbg file, the pdb should
// be in the same subdir. Can we optimize this load to account
// for it? Should we still clear lszDebug?
if (lpexg->lszDebug) {
MHFree(lpexg->lszDebug);
lpexg->lszDebug = 0;
}
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;
}
sheRet = sheNone;
}
ReturnHere:
lpexg->debugData.she = 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);
diff = loadAddress - imageBase;
}
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;
}
for(index=0; index<cFunc; index++) {
rf[index].BeginAddress = dbgRf[index].StartingAddress + loadAddress;
rf[index].EndAddress = dbgRf[index].EndingAddress + loadAddress;
rf[index].PrologEndAddress = dbgRf[index].EndOfPrologue + loadAddress;
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 NB09 signature
// sheFutureSymbols if exe has NB10 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 '50BN':
case '60BN':
case '70BN':
return sheMustRelink;
case '80BN':
return sheNotPacked;
case '01BN':
SYReadFar(hfile, (LPB)ppdb, sizeof(PDB_INFO));
case '90BN':
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;
// cbHeader = sizeof (ccib) + sizeof (WORD);
// Read the segment table offsets and counts
// if (!(rgib = (LPUL) MHAlloc (ccib * sizeof (ULONG)))) {
// return FALSE;
// }
// if (!(rgcib = (LPUL) MHAlloc (ccib * sizeof (ULONG)))) {
// MHFree(rgib);
// return FALSE;
// }
// memmove(rgib, lpbData, ccib * sizeof(ULONG));
lpbData += ccib * sizeof(ULONG);
rgcib = (LPUL) lpbData;
// UNDONE: If/when non-DWORD packing isn't interesting, the
// extra allocations above can be elminated and rgcib/rgib
// can just be pointes into the lpbData buffer.
// if (fDWordChains) {
// memmove(rgcib, lpbData, ccib * sizeof (ULONG));
lpbData += ccib * sizeof(ULONG);
// } else {
// // If not DWORD chains, copy from the end of the word
// // array to the end of the DWORD array so later code
// // doesn't have to special case it...
//
// LPW rgw = (LPW) rgcib;
// WORD icib = ccib;
//
// memmove(rgcib, lpbData, ccib * sizeof (WORD));
// lpbData += ccib * sizeof(WORD);
//
// while (icib > 0) {
// icib -= 1;
// rgcib [ icib ] = (ULONG) rgw [ icib ];
// }
// }
// 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) {
// MHFree(rgib);
// MHFree(rgcib);
return FALSE;
}
// *lplpbData = lpbData;
return TRUE;
}
LOCAL BOOL
OLLoadHashSubSec(
LPGST lpgst,
LPB lpbData
)
{
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;
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
__inline 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;
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)) {
she = sheOutOfMemory;
}
return she;
}
__inline SHE
OLGlobalSym(
LPEXG lpexg
)
{
SHE she = sheNone;
if (!OLLoadHashSubSec (&lpexg->gstGlobals,
lpexg->lpbData + lpdssCur->lfo)) {
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)) {
she = sheOutOfMemory;
}
return she;
}
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)
};
// 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);
}
}
LOCAL SHE
LoadPdb(
LPEXG lpexg,
PDB_INFO *ppdb
)
{
EC ec;
char szExePath[_MAX_PATH];
char szPDBOut[cbErrMax];
char *pcEndOfPath;
BOOL fOpenValidate;
assert(lpexg);
// figure out the home directory of the exe file - pass that along to
// OpenValidate this will direct to dbi to search for it in that
// directory if it fails to find the pdb.
_fullpath(szExePath, lpexg->lszName, _MAX_PATH);
pcEndOfPath = _tcsrchr(szExePath, '\\');
*pcEndOfPath = '\0'; // null terminate it
*szPDBOut = '\0';
HKEY hSectionKey = NULL;
DWORD nType = REG_SZ;
DWORD nSize = sizeof(rgSearchPath);
if (!fQueriedRegistry) {
RegOpenKeyEx(HKEY_CURRENT_USER, szDefaultKeyName, 0, KEY_READ, &hSectionKey);
if ((hSectionKey == NULL) ||
(RegQueryValueEx(hSectionKey,
(char *)szPdbDirs,
NULL,
&nType,
(LPBYTE)rgSearchPath,
&nSize) != ERROR_SUCCESS)
) {
rgSearchPath[0] = 0;
}
fQueriedRegistry = TRUE;
}
fOpenValidate = PDBOpenValidateEx(ppdb->sz,
szExePath,
rgSearchPath,
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);
assert(lpexg->lszDebug == NULL);
// Save the name of the pdb.
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(!PDBOpenDBI(lpexg->ppdb, pdbRead, lpexg->lszName, &(lpexg->pdbi))) {
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_NT_HEADERS peHdr;
IMAGE_DOS_HEADER exeHdr;
int fPeExe = FALSE;
int fPeDbg = FALSE;
IMAGE_SEPARATE_DEBUG_HEADER sepHdr;
char rgch[4];
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 (peHdr.FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
return sheNoSymbols;
}
if (peHdr.OptionalHeader.CheckSum != pVldChk->CheckSum) {
if (lpszErrText) {
sprintf(lpszErrText,"*** WARNING: symbols checksum is wrong 0x%08x 0x%08x",
peHdr.OptionalHeader.CheckSum,pVldChk->CheckSum);
}
return sheBadCheckSum;
}
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) {
if ((SYSeek(hFile, 0, SEEK_SET) != 0) ||
(SYReadFar(hFile, (LPB) &sepHdr, sizeof(sepHdr)) != sizeof(sepHdr))) {
return sheNoSymbols;
}
if (sepHdr.CheckSum != pVldChk->CheckSum) {
if (lpszErrText) {
sprintf(lpszErrText,"*** WARNING: symbols checksum is wrong 0x%08x 0x%08x",
sepHdr.CheckSum,pVldChk->CheckSum);
}
return sheBadCheckSum;
}
} else {
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 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
VirtualFree(lpexg->lpbData, 0, MEM_RELEASE);
} 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;
}