mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1458 lines
40 KiB
1458 lines
40 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
// DBI: Debug Information API Implementation
|
|
|
|
#include "pdbimpl.h"
|
|
#include "dbiimpl.h"
|
|
#include "cvexefmt.h"
|
|
|
|
static inline void szFullPathFromST(ST stName, SZ buf);
|
|
|
|
|
|
#ifdef INSTRUMENTED
|
|
void DBI1::DumpSymbolPages()
|
|
{
|
|
char szBuf[256];
|
|
unsigned int iPg;
|
|
int ich;
|
|
int cPgLoaded=0;
|
|
|
|
sprintf(szBuf, "\n\n**** Symbol page dump for %s ****\r\n", ppdb1->szPDBName);
|
|
OutputDebugString(szBuf);
|
|
|
|
if (cSymRecPgs == 0)
|
|
{
|
|
sprintf(szBuf, "(No pages)");
|
|
OutputDebugString(szBuf);
|
|
return;
|
|
}
|
|
|
|
for (iPg=0, ich=0; iPg < cSymRecPgs; iPg++)
|
|
{
|
|
// Is page loaded?
|
|
if (pbvSymRecPgs->fTestBit(iPg))
|
|
{
|
|
szBuf[ich++] = 'X';
|
|
cPgLoaded++;
|
|
}
|
|
else
|
|
{
|
|
szBuf[ich++] = '-';
|
|
}
|
|
|
|
// Output 50 pages per line (200K per line)
|
|
if (ich == 49)
|
|
{
|
|
szBuf[ich++] = '\r';
|
|
szBuf[ich++] = '\n';
|
|
szBuf[ich++] = '\0';
|
|
OutputDebugString(szBuf);
|
|
ich = 0;
|
|
}
|
|
}
|
|
|
|
if (ich != 0)
|
|
{
|
|
szBuf[ich++] = '\r';
|
|
szBuf[ich++] = '\n';
|
|
szBuf[ich++] = '\0';
|
|
OutputDebugString(szBuf);
|
|
}
|
|
|
|
sprintf(szBuf, "%d out of %d pages are loaded (%d%%)\r\n", cPgLoaded, cSymRecPgs, (cPgLoaded*100)/cSymRecPgs);
|
|
OutputDebugString(szBuf);
|
|
}
|
|
#endif
|
|
|
|
#pragma warning(4:4355) // 'this' used in member init list...
|
|
|
|
DBI1::DBI1(PDB1* ppdb1_, BOOL fWrite_, BOOL fCreate_)
|
|
: bufGpmodi(fixBufGpmodi, (void*)this, fWrite_), // don't alloc extra padding for read-only
|
|
bufRgpmodi(fixBufBase, (void*)&rgpmodi),
|
|
bufSymRecs(!fWrite_, fixSymRecs, this),
|
|
bufSC(0, 0, fWrite_), // don't alloc extra padding for read-only
|
|
bufSecMap(0, 0, fWrite_) // don't alloc extra padding for read-only
|
|
{
|
|
ppdb1 = ppdb1_;
|
|
fWrite = fWrite_;
|
|
fCreate = fCreate_;
|
|
pgsiGS = 0;
|
|
pgsiPS = 0;
|
|
potmTSHead = 0;
|
|
potmPCTHead = 0;
|
|
#ifdef INSTRUMENTED
|
|
log = 0;
|
|
#endif
|
|
imodMac = 0;
|
|
fSCCleared = FALSE;
|
|
rgpmodi = (MODI**)bufRgpmodi.Start();
|
|
expect(fAlign(rgpmodi));
|
|
pbvSymRecPgs = 0;
|
|
fUDTOutsideRef = FALSE;
|
|
}
|
|
#pragma warning(default:4355)
|
|
|
|
void DBI1::fixBufGpmodi(void* pDbi1, void* pOld, void* pNew)
|
|
{
|
|
if (pOld && pNew) {
|
|
DBI1* pdbi1 = (DBI1*)pDbi1;
|
|
CB dcb = (long)pNew - (long)pOld;
|
|
for (IMOD imod = 0; imod < pdbi1->imodMac; imod++)
|
|
pdbi1->rgpmodi[imod] = (MODI*)((PB)pdbi1->rgpmodi[imod] + dcb);
|
|
}
|
|
}
|
|
|
|
void DBI1::fixBufBase(void* pv, void* pvOld, void* pvNew)
|
|
{
|
|
*(void**)pv = pvNew;
|
|
}
|
|
|
|
BOOL DBI1::fInit()
|
|
{
|
|
#if defined(INSTRUMENTED)
|
|
if (fWrite)
|
|
log = LogOpen();
|
|
if (log)
|
|
LogNoteEvent(log, "DBI", 0, letypeBegin, 0);
|
|
#endif
|
|
CB cbDbiStream = MSFGetCbStream(ppdb1->pmsf, snDbi);
|
|
|
|
if (cbDbiStream > 0) {
|
|
CB cbdbihdr = sizeof(dbihdr);
|
|
OFF off = 0;
|
|
if (!MSFReadStream2(ppdb1->pmsf, snDbi, 0, &(dbihdr), &cbdbihdr)) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
off += sizeof(dbihdr);
|
|
|
|
dassert(cbDbiStream == cbdbihdr + dbihdr.cbGpModi + dbihdr.cbSC +
|
|
dbihdr.cbSecMap + dbihdr.cbFileInfo);
|
|
|
|
if (fWrite && (ppdb1->pdbStream.impv == PDB1::impvVC4)) {
|
|
// can't incremental link a vc4 format pdb, we have introduced
|
|
// new scheme to track refcounts on promoted global syms - return
|
|
// a format error here so that we force a full link and rewrite of
|
|
// all of the mods streams
|
|
// sps 8/14/95
|
|
if (fCreate)
|
|
// ok we are rewritting this as a vc 4.1 dbi
|
|
ppdb1->pdbStream.impv = PDB1::impv;
|
|
else {
|
|
ppdb1->setLastError(EC_FORMAT, 0);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// read in the gpmodi substream
|
|
if (dbihdr.cbGpModi > 0) {
|
|
expect(fAlign(dbihdr.cbGpModi));
|
|
// load gpmodi
|
|
PB pb;
|
|
|
|
if (ppdb1->pdbStream.impv == PDB1::impvVC2) {
|
|
// read in v2 modi into temp table and do initial alloc of
|
|
// bufGpmodi which will hold the converted v4 modi
|
|
Buffer bufGpV2modi;
|
|
PB pbV2;
|
|
|
|
if (!bufGpmodi.SetInitAlloc(dbihdr.cbGpModi) ||
|
|
!bufGpV2modi.Reserve(dbihdr.cbGpModi, &pbV2)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
else if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, pbV2, &(dbihdr.cbGpModi))) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
|
|
// pass thru v2 modi table and copy/convert into v4 modi table
|
|
for (PB pbEnd = bufGpV2modi.End(), pbV2EndRec = ((MODI*)pbV2)->pbV2End();
|
|
pbV2 < pbEnd;
|
|
pbV2 = pbV2EndRec, pbV2EndRec = ((MODI*)pbV2)->pbV2End())
|
|
{
|
|
CB cb;
|
|
DWORD dwDummy = 0;
|
|
#pragma warning(disable:4101)
|
|
MODI *pmodiDummy = 0;
|
|
|
|
// copy up to the missing dwCharacteristics field
|
|
bufGpmodi.Append(pbV2,
|
|
cb = sizeof(pmodiDummy->pmod) + sizeof(pmodiDummy->sc.isect) +
|
|
sizeof(pmodiDummy->sc.off) + sizeof(pmodiDummy->sc.cb));
|
|
// insert the missing dwCharacteristics field
|
|
bufGpmodi.Append((PB)&dwDummy, sizeof(pmodiDummy->sc.dwCharacteristics));
|
|
pbV2 += cb;
|
|
// copy the rest of the record
|
|
bufGpmodi.Append(pbV2, pbV2EndRec - pbV2);
|
|
}
|
|
|
|
pb = bufGpmodi.Start();
|
|
off += dbihdr.cbGpModi;
|
|
dbihdr.cbGpModi = bufGpmodi.Size();
|
|
}
|
|
else {
|
|
if (!bufGpmodi.Reserve(dbihdr.cbGpModi, &pb)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
else if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, pb, &(dbihdr.cbGpModi))) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
off += dbihdr.cbGpModi;
|
|
}
|
|
|
|
|
|
// build rgpmodi
|
|
for (PB pbEnd = bufGpmodi.End(); pb < pbEnd;
|
|
pb = ((MODI*)pb)->pbEnd(), imodMac++)
|
|
{
|
|
expect(fAlign(pb));
|
|
MODI* pmodi = (MODI*)pb;
|
|
pmodi->pmod = 0;
|
|
pmodi->fWritten = FALSE;
|
|
pmodi->ifileMac = 0;
|
|
pmodi->mpifileichFile = 0;
|
|
if (!bufRgpmodi.Append((PB)&pmodi, sizeof pmodi)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
expect(fAlign(&(rgpmodi[imodMac])));
|
|
assert(rgpmodi[imodMac] == pmodi);
|
|
}
|
|
}
|
|
|
|
// read in the Section Contribution substream
|
|
if (dbihdr.cbSC > 0) {
|
|
expect(fAlign(dbihdr.cbSC));
|
|
|
|
if (ppdb1->pdbStream.impv == PDB1::impvVC2) {
|
|
// Convert VC++ 2.0 SC entries to VC++ 4.0 format
|
|
|
|
unsigned csc = dbihdr.cbSC / sizeof(SC20);
|
|
|
|
CB cb = csc * sizeof(SC);
|
|
|
|
if (!bufSC.Reserve(cb)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
pscEnd = (SC *) bufSC.Start();
|
|
|
|
cb = sizeof(SC20);
|
|
while (csc--) {
|
|
|
|
SC20 sc20;
|
|
if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, &sc20, &cb)) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
|
|
pscEnd->isect = sc20.isect;
|
|
pscEnd->off = sc20.off;
|
|
pscEnd->cb = sc20.cb;
|
|
pscEnd->dwCharacteristics = 0;
|
|
pscEnd->imod = sc20.imod;
|
|
|
|
off += sizeof(SC20);
|
|
pscEnd++;
|
|
}
|
|
} else {
|
|
if (!bufSC.Reserve(dbihdr.cbSC)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, bufSC.Start(), &(dbihdr.cbSC))) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
off += dbihdr.cbSC;
|
|
pscEnd = (SC*)(bufSC.End());
|
|
}
|
|
}
|
|
|
|
// read in the Section Map substream only if we are not writing
|
|
if (dbihdr.cbSecMap && !fWrite) {
|
|
expect(fAlign(dbihdr.cbSecMap));
|
|
if (!bufSecMap.Reserve(dbihdr.cbSecMap)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
else if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, bufSecMap.Start(), &(dbihdr.cbSecMap))) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
off += dbihdr.cbSecMap;
|
|
|
|
if (dbihdr.cbFileInfo > 0) {
|
|
expect(fAlign(dbihdr.cbFileInfo));
|
|
Buffer bufFileInfo;
|
|
if (!bufFileInfo.Reserve(dbihdr.cbFileInfo)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
else if (!MSFReadStream2(ppdb1->pmsf, snDbi, off, bufFileInfo.Start(), &dbihdr.cbFileInfo)) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
off += dbihdr.cbFileInfo;
|
|
reloadFileInfo(bufFileInfo.Start());
|
|
}
|
|
}
|
|
|
|
// for now we will completely delete old Mod info from previous builds on
|
|
// a dbi creation. later we may want to perform this instead of trying to
|
|
// perform any garbage collection.
|
|
|
|
#pragma message ("todo - temporary clear dbi on create")
|
|
if (fCreate && !clearDBI())
|
|
return FALSE;
|
|
|
|
if (fWrite) {
|
|
// open the global and public symbol tables
|
|
GSI* pgsigs_;
|
|
GSI* pgsips_;
|
|
|
|
if (!OpenGlobals(&pgsigs_) || !OpenPublics(&pgsips_))
|
|
return FALSE;
|
|
|
|
pgsiGS = (GSI1*) pgsigs_;
|
|
pgsiPS = (PSGSI1*) pgsips_;
|
|
|
|
// just allocate the seg descriptor counters
|
|
OMFSegMap omfsegmap = {0, 0};
|
|
expect(fAlign(sizeof(omfsegmap)));
|
|
if (!bufSecMap.Append((PB)&omfsegmap, sizeof(omfsegmap))) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL nullifyStream(MSF* pmsf, SN* psn) {
|
|
dassert(psn);
|
|
if (*psn == snNil)
|
|
return TRUE;
|
|
|
|
dassert(pmsf);
|
|
if (!MSFDeleteStream(pmsf, *psn))
|
|
return FALSE;
|
|
|
|
*psn = snNil;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::clearDBI() {
|
|
// delete all mod streams
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
MODI* pmodi = rgpmodi[imod];
|
|
if (!nullifyStream(ppdb1->pmsf, &pmodi->sn)) {
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// delete sym records stream
|
|
if (!nullifyStream(ppdb1->pmsf, &dbihdr.snSymRecs) ||
|
|
!nullifyStream(ppdb1->pmsf, &dbihdr.snGSSyms) ||
|
|
!nullifyStream(ppdb1->pmsf, &dbihdr.snPSSyms))
|
|
{
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
|
|
// commit these changes to recover their free pages
|
|
// (Necessary to avoid doubling the pdb size.)
|
|
if ((MSFGetCbStream(ppdb1->pmsf, snDbi) != cbNil && !MSFDeleteStream(ppdb1->pmsf, snDbi)) ||
|
|
!MSFCommit(ppdb1->pmsf))
|
|
{
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
|
|
// clear out all buffers and tables
|
|
imodMac = 0;
|
|
bufGpmodi.Clear();
|
|
bufRgpmodi.Clear();
|
|
bufSC.Clear();
|
|
pscEnd = (SC*)bufSC.End();
|
|
fSCCleared = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL DBI1::writeSymRecs() {
|
|
expect(fAlign(bufSymRecs.Size()));
|
|
if (dbihdr.snSymRecs == snNil) {
|
|
dbihdr.snSymRecs = MSFGetFreeSn(ppdb1->pmsf);
|
|
|
|
if (dbihdr.snSymRecs == snNil){
|
|
ppdb1->setLastError(EC_LIMIT);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!MSFReplaceStream(ppdb1->pmsf, dbihdr.snSymRecs, bufSymRecs.Start(),
|
|
bufSymRecs.Size())) {
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// just append whatever is new
|
|
CB cb = MSFGetCbStream(ppdb1->pmsf, dbihdr.snSymRecs);
|
|
dassert(bufSymRecs.Size() >= cb);
|
|
if (!MSFAppendStream(ppdb1->pmsf, dbihdr.snSymRecs, bufSymRecs.Start() + cb,
|
|
bufSymRecs.Size() - cb)) {
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int __cdecl SCCmp (const void* elem1, const void* elem2)
|
|
{
|
|
SC* psc1 = (SC*) elem1;
|
|
SC* psc2 = (SC*) elem2;
|
|
|
|
if (psc1->isect != psc2->isect)
|
|
return (psc1->isect > psc2->isect) ? 1 : -1;
|
|
|
|
if (psc1->off != psc2->off)
|
|
return (psc1->off > psc2->off) ? 1 : -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL DBI1::fSave()
|
|
{
|
|
// output the any deferred udt defns from foreign type servers
|
|
|
|
int doCount = 0;
|
|
|
|
do {
|
|
fUDTOutsideRef = FALSE;
|
|
for (OTM *potm = potmTSHead ; potm; potm = potm->pNext) {
|
|
if (potm->ptm)
|
|
if (!potm->ptm->fPackDeferredUDTDefns())
|
|
return FALSE;
|
|
}
|
|
expect(doCount < 2);
|
|
doCount++;
|
|
} while (fUDTOutsideRef);
|
|
|
|
if (
|
|
!pgsiGS->fSave(&(dbihdr.snGSSyms)) ||
|
|
!pgsiPS->fSave(&(dbihdr.snPSSyms)) ||
|
|
!writeSymRecs())
|
|
return FALSE;
|
|
|
|
if (pscEnd) {
|
|
// sort entries in the SC
|
|
qsort(bufSC.Start(), pscEnd - (SC*)bufSC.Start(), sizeof(SC), SCCmp);
|
|
}
|
|
|
|
// record lengths of the gpmodi and sc substreams in the header and then
|
|
// emit the dbi stream
|
|
dbihdr.cbGpModi = bufGpmodi.Size();
|
|
dbihdr.cbSC = (PB)pscEnd - bufSC.Start();
|
|
dbihdr.cbSecMap = bufSecMap.Size();
|
|
expect(fAlign(dbihdr.cbGpModi));
|
|
expect(fAlign(dbihdr.cbSC));
|
|
expect(fAlign(dbihdr.cbSecMap));
|
|
|
|
// Convert the file info in the gpmodi into sstFileIndex format
|
|
// and save that!
|
|
Buffer bufFileInfo;
|
|
if (!QueryFileInfo(0, &dbihdr.cbFileInfo) ||
|
|
!bufFileInfo.Reserve(dbihdr.cbFileInfo) ||
|
|
!QueryFileInfo(bufFileInfo.Start(), &dbihdr.cbFileInfo))
|
|
return FALSE;
|
|
|
|
expect(fAlign(sizeof(dbihdr)));
|
|
expect(fAlign(dbihdr.cbFileInfo));
|
|
if (!MSFReplaceStream(ppdb1->pmsf, snDbi, &dbihdr, sizeof (dbihdr)) ||
|
|
!MSFAppendStream(ppdb1->pmsf, snDbi, bufGpmodi.Start(), dbihdr.cbGpModi) ||
|
|
!MSFAppendStream(ppdb1->pmsf, snDbi, bufSC.Start(), dbihdr.cbSC) ||
|
|
!MSFAppendStream(ppdb1->pmsf, snDbi, bufSecMap.Start(), dbihdr.cbSecMap) ||
|
|
!MSFAppendStream(ppdb1->pmsf, snDbi, bufFileInfo.Start(), dbihdr.cbFileInfo)){
|
|
ppdb1->setWriteError();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
INTV DBI1::QueryInterfaceVersion()
|
|
{
|
|
return intv;
|
|
}
|
|
|
|
IMPV DBI1::QueryImplementationVersion()
|
|
{
|
|
return impv;
|
|
}
|
|
|
|
void DBI1:: NoteModCloseForImod(IMOD imod)
|
|
{
|
|
assert(0 <= imod && imod < imodMac);
|
|
|
|
MODI *pmodi = rgpmodi[imod];
|
|
pmodi->pmod = NULL;
|
|
}
|
|
|
|
IMOD DBI1::imodForModName(SZ_CONST szModule, SZ_CONST szObjFile)
|
|
{
|
|
if (imodMac == 0)
|
|
return imodNil;
|
|
|
|
// performance heuristic: search for module starting from last search
|
|
// index, rather than from 0.
|
|
static IMOD imodLast = imodNil;
|
|
if (imodLast == imodNil || imodLast >= imodMac)
|
|
imodLast = 0;
|
|
IMOD imod = imodLast;
|
|
do {
|
|
assert(0 <= imod && imod < imodMac);
|
|
MODI* pmodi = rgpmodi[imod];
|
|
if (_tcsicmp(pmodi->szModule(), szModule) == 0 &&
|
|
(!szObjFile || _tcsicmp(pmodi->szObjFile(), szObjFile) == 0))
|
|
return imodLast = imod;
|
|
imod = (imod + 1) % imodMac;
|
|
} while (imod != imodLast);
|
|
return imodNil;
|
|
}
|
|
|
|
BOOL DBI1::OpenMod(SZ_CONST szModule, SZ_CONST szObjFile, OUT Mod** ppmod)
|
|
{
|
|
dassert(szModule);
|
|
dassert(ppmod);
|
|
|
|
IMOD imod = imodForModName(szModule, szObjFile);
|
|
if (imod == imodNil) {
|
|
if (!fCheckReadWriteMode(TRUE))
|
|
return FALSE;
|
|
dassert(szObjFile);
|
|
MODI* pmodi = new (bufGpmodi, szModule, szObjFile) MODI(szModule, szObjFile);
|
|
if (!pmodi)
|
|
return FALSE;
|
|
if (!bufRgpmodi.Append((PB)&pmodi, sizeof pmodi))
|
|
return FALSE;
|
|
imod = imodMac++;
|
|
expect(fAlign(&(rgpmodi[imod])));
|
|
assert(pmodiForImod(imod) == pmodi);
|
|
}
|
|
return openModByImod(imod, ppmod);
|
|
}
|
|
|
|
BOOL DBI1::openModByImod(IMOD imod, OUT Mod** ppmod)
|
|
{
|
|
if (imod == imodNil || imod >= imodMac)
|
|
return FALSE;
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
if (!pmodi->pmod) {
|
|
// module is not yet "open"...open it
|
|
Mod1* pmod_;
|
|
if (!(pmod_ = new (ppdb1) Mod1(ppdb1, this, imod)))
|
|
return FALSE;
|
|
|
|
if (!(pmod_->fInit()))
|
|
return FALSE;
|
|
|
|
pmodi->pmod = (Mod*) pmod_;
|
|
}
|
|
else {
|
|
// must not reopen a module if writing
|
|
assert(!fWrite);
|
|
}
|
|
|
|
*ppmod = pmodi->pmod;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::DeleteMod(SZ_CONST szModule)
|
|
{
|
|
dassert(szModule);
|
|
#pragma message("TODO return FALSE when implemented")
|
|
return TRUE;
|
|
}
|
|
|
|
#if 0 // NYI
|
|
BOOL DBI1::QueryCountMod(long *pcMod)
|
|
{
|
|
assert(pcMod);
|
|
*pcMod = imodMac;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
BOOL DBI1::QueryNextMod(Mod* pmod, Mod** ppmodNext)
|
|
{
|
|
MODI* pmodi;
|
|
|
|
IMOD imod = (IMOD)-1;
|
|
|
|
// establish imod to be the imod of pmod
|
|
if (pmod) {
|
|
if (imodLast != imodNil &&
|
|
!!(pmodi = pmodiForImod(imodLast)) && pmodi->pmod == pmod) {
|
|
// cache hit
|
|
imod = imodLast;
|
|
}
|
|
else {
|
|
// cache miss, search MODI table for it
|
|
for (imod = 0; imod < imodMac; imod++)
|
|
if (!!(pmodi = pmodiForImod(imod)) && pmodi->pmod == pmod)
|
|
break;
|
|
if (imod >= imodMac) {
|
|
ppdb1->setUsageError();
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
// at this point, imod address the previous modi, or -1.
|
|
|
|
// advance to the next modi, if any
|
|
if (++imod < imodMac) {
|
|
if (!openModByImod(imod, ppmodNext))
|
|
return FALSE;
|
|
imodLast = imod; // update cache
|
|
}
|
|
else {
|
|
// no more modules; return success but no symbol
|
|
*ppmodNext = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::OpenGlobals(OUT GSI** ppgsi)
|
|
{
|
|
dassert (ppgsi);
|
|
|
|
if (pgsiGS) {
|
|
// already opened - just return
|
|
*ppgsi = pgsiGS;
|
|
return TRUE;
|
|
}
|
|
|
|
TPI* ptpi;
|
|
if (!ppdb1->OpenTpi(fWrite ? pdbWrite : pdbRead, &ptpi))
|
|
return FALSE;
|
|
GSI1* pgsi = new GSI1(ppdb1, this, ptpi);
|
|
|
|
if (!pgsi) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
if (pgsi->fInit(dbihdr.snGSSyms)) {
|
|
*ppgsi = pgsiGS = pgsi;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#pragma message("TODO: lots of ERRRRORS setting via CreateDBI")
|
|
|
|
BOOL DBI1::OpenPublics(OUT GSI** ppgsi)
|
|
{
|
|
dassert (ppgsi);
|
|
|
|
if (pgsiPS) {
|
|
// already opened - just return
|
|
*ppgsi = pgsiPS;
|
|
return TRUE;
|
|
}
|
|
|
|
TPI* ptpi;
|
|
if (!ppdb1->OpenTpi(fWrite ? pdbWrite : pdbRead, &ptpi))
|
|
return FALSE;
|
|
|
|
PSGSI1* ppsgsi = new PSGSI1(ppdb1, this, ptpi, fWrite);
|
|
|
|
if (!ppsgsi) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
if (ppsgsi->fInit(dbihdr.snPSSyms)) {
|
|
*ppgsi = pgsiPS = ppsgsi;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DBI1::AddSec(ISECT isect, USHORT flags, OFF off, CB cb)
|
|
{
|
|
if (!fWrite) {
|
|
ppdb1->setUsageError();
|
|
return FALSE;
|
|
}
|
|
|
|
OMFSegMapDesc* pOMFSegMapDesc;
|
|
if (!bufSecMap.Reserve(sizeof(OMFSegMapDesc), (PB*) &pOMFSegMapDesc)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
pOMFSegMapDesc->flags = flags;
|
|
pOMFSegMapDesc->ovl = 0;
|
|
pOMFSegMapDesc->group = 0;
|
|
pOMFSegMapDesc->frame = isect;
|
|
pOMFSegMapDesc->iSegName = 0xffff;
|
|
pOMFSegMapDesc->iClassName = 0xffff;
|
|
pOMFSegMapDesc->offset = off;
|
|
pOMFSegMapDesc->cbSeg = cb;
|
|
|
|
OMFSegMap* pOMFSegMap = (OMFSegMap*)bufSecMap.Start();
|
|
dassert(pOMFSegMap);
|
|
pOMFSegMap->cSeg++;
|
|
pOMFSegMap->cSegLog++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::AddPublic(SZ_CONST szPublic, ISECT isect, OFF off)
|
|
{
|
|
MP* pmp = (MP*) new (ppdb1, szPublic) MP(szPublic, isect, off);
|
|
if (!pmp)
|
|
return FALSE;
|
|
|
|
BOOL fOK = packSymToPS((PSYM)pmp);
|
|
delete pmp;
|
|
return fOK;
|
|
}
|
|
|
|
BOOL DBI1::QuerySecMap(OUT PB pb, CB* pcb)
|
|
{
|
|
if (!bufSecMap.Start())
|
|
return FALSE;
|
|
|
|
dassert(pcb);
|
|
|
|
*pcb = bufSecMap.Size();
|
|
|
|
if (pb) {
|
|
memcpy (pb, bufSecMap.Start(), *pcb);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL DBI1::QueryModFromAddr(ISECT isect, OFF off, OUT Mod** ppmod,
|
|
OUT ISECT* pisect, OUT OFF* poff, OUT CB* pcb)
|
|
{
|
|
SC* pscLo = (SC*) bufSC.Start();
|
|
SC* pscHi = pscEnd;
|
|
SC* psc;
|
|
|
|
// binary search for containing SC
|
|
while (pscLo < pscHi) {
|
|
psc = pscLo + ((pscHi - pscLo) / 2);
|
|
int iResult = psc->IsAddrInSC(isect, off);
|
|
if (iResult < 0 )
|
|
pscHi = psc;
|
|
else if (iResult > 0)
|
|
pscLo = psc + 1;
|
|
else {
|
|
// we found it
|
|
BOOL fOK = TRUE;
|
|
if (ppmod)
|
|
fOK = openModByImod(psc->imod, ppmod);
|
|
if (pisect) *pisect = psc->isect;
|
|
if (poff) *poff = psc->off;
|
|
if (pcb) *pcb = psc->cb;
|
|
return fOK;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline int SC::IsAddrInSC(ISECT isect_, OFF off_)
|
|
{
|
|
if (isect == isect_) {
|
|
if (off_ < off)
|
|
return -1;
|
|
if (off_ < off + cb)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
else
|
|
return (isect_ - isect);
|
|
}
|
|
|
|
BOOL DBI1::Close()
|
|
{
|
|
if (fWrite && !fSave())
|
|
return FALSE;
|
|
delete this;
|
|
return TRUE;
|
|
}
|
|
|
|
DBI1::~DBI1()
|
|
{
|
|
#if defined(INSTRUMENTED)
|
|
if (log) {
|
|
LogNoteEvent(log, "DBI", 0, letypeEvent,
|
|
"cModules:%d cSymbols:%d cTypesMapped:%d",
|
|
info.cModules, info.cSymbols, info.cTypesMapped);
|
|
LogNoteEvent(log, "DBI", 0, letypeEvent,
|
|
"cTypesMappedRec.:%d cTypesQueried:%d cTypesAdded:%d",
|
|
info.cTypesMappedRecursively, info.cTypesQueried, info.cTypesAdded);
|
|
LogNoteEvent(log, "DBI", 0, letypeEvent, "cTMTS:%d cTMR:%d cTMPCT:%d",
|
|
info.cTMTS, info.cTMR, info.cTMPCT);
|
|
LogNoteEvent(log, "DBI", 0, letypeEnd, 0);
|
|
LogClose(log);
|
|
}
|
|
#endif
|
|
|
|
#ifdef INSTRUMENTED
|
|
DumpSymbolPages();
|
|
#endif
|
|
|
|
if (potmTSHead)
|
|
delete potmTSHead;
|
|
if (potmPCTHead)
|
|
delete potmPCTHead;
|
|
|
|
// dtor pmodi's
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
if (pmodi)
|
|
pmodi->~MODI();
|
|
}
|
|
|
|
if (pbvSymRecPgs)
|
|
delete pbvSymRecPgs;
|
|
}
|
|
|
|
// Get a TMTS for the TypeServer PDB referenced by the lfTypeServer record.
|
|
// Return this TMTS in *ptm, except (*ptm == 0) when the referenced PDB
|
|
// corresponds to the project (output) PDB. Return TRUE if successful.
|
|
//
|
|
// Note that subsequent calls upon fGetTmts, for the same PDB, from subsequent
|
|
// modules in this DBI, will return the same TMTS.
|
|
//
|
|
BOOL DBI1::fGetTmts(lfTypeServer* pts, SZ_CONST szObjFile, TM** pptm)
|
|
{
|
|
dassert(pts && pptm);
|
|
|
|
// Consult the open TMTS list to determine if an existing TMTS matches the
|
|
// referenced PDB.
|
|
if (fFindTm(potmTSHead, (ST)pts->name, pts->signature, pptm))
|
|
return TRUE;
|
|
|
|
// open a TMTS
|
|
if (!fOpenTmts(pts, szObjFile, pptm))
|
|
return FALSE;
|
|
|
|
// add this TMTS the open TMTS list
|
|
SZ szName = szCopySt((ST)pts->name);
|
|
if (!szName ||
|
|
!(potmTSHead = new OTM(potmTSHead, szName, pts->signature, *pptm)))
|
|
{
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Open the TypeServer referenced by *pts and initialize a TMTS from it.
|
|
// Set *ptm and return TRUE if successful, FALSE otherwise.
|
|
//
|
|
BOOL DBI1::fOpenTmts(lfTypeServer* pts, SZ_CONST szObjFile, TM** pptm)
|
|
{
|
|
#pragma message("TODO - DBCS")
|
|
*pptm = 0; // 0 means use 'to' PDB
|
|
|
|
char szPDBTo[_MAX_PATH];
|
|
ppdb1->QueryPDBName(szPDBTo);
|
|
|
|
if (_strnicmp(szPDBTo, (char*)(pts->name + 1), *(PB)pts->name) == 0) {
|
|
// PDB filenames match, reference to the 'to' PDB
|
|
return TRUE;
|
|
}
|
|
|
|
char szPDBFrom[_MAX_PATH];
|
|
strncpy(szPDBFrom, (char*)(pts->name + 1), *(PB)pts->name);
|
|
szPDBFrom[*(PB)pts->name] = 0;
|
|
|
|
if (pts->signature == ppdb1->QuerySignature() && pts->age <= ppdb1->QueryAge()) {
|
|
// PDB signature and age match; this 'from' PDB must contain equivalent
|
|
// information (even if it is a copy on some other path). However, we
|
|
// may have the highly unlikely case of distinct PDBs with equal
|
|
// signatures; to feel better about this case, we won't conclude
|
|
// equivalence unless the PDB base names also match. In practice this
|
|
// should be exactly conservative enough to avoid false positives and
|
|
// yet prevent accidental reopening of the 'to' PDB.
|
|
#pragma message("TODO: DBCS review")
|
|
char* pchBaseFrom = strrchr(szPDBFrom, '\\'); // REVIEW: international?
|
|
char* pchBaseTo = strrchr(szPDBTo, '\\');
|
|
if (_tcsicmp(pchBaseFrom, pchBaseTo) == 0) {
|
|
// even the base names match; reference to the 'to' PDB
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Alas, probably a reference to a different type server. Open it.
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
PDB* ppdbFrom;
|
|
char szPathBuf[_MAX_PATH+_MAX_DRIVE];
|
|
char szFullPath[_MAX_PATH+_MAX_DRIVE];
|
|
|
|
_fullpath(szFullPath, szObjFile, _MAX_PATH+_MAX_DRIVE);
|
|
_splitpath(szFullPath, szPathBuf, szPathBuf + _MAX_DRIVE, NULL, NULL);
|
|
SZ szPath;
|
|
if (szPathBuf[0] == 0) {
|
|
// no drive spec - set up path without it
|
|
szPath = szPathBuf + _MAX_DRIVE;
|
|
}
|
|
else {
|
|
// concatenate drive and dir to form full path
|
|
szPathBuf[2] = szPathBuf[1];
|
|
szPathBuf[1] = szPathBuf[0];
|
|
szPath = szPathBuf + 1;
|
|
}
|
|
if (!PDB::OpenValidate(szPDBFrom, szPath, ppdb1->fFullBuild ? (pdbRead pdbGetRecordsOnly pdbFullBuild) :(pdbRead pdbGetRecordsOnly),
|
|
pts->signature, pts->age, &ec, szError, &ppdbFrom)) {
|
|
ppdb1->setLastError(ec, szError);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check again that the PDB we found along the lib path is the same as the
|
|
// target PDB.
|
|
ppdbFrom->QueryPDBName(szPDBFrom);
|
|
if (_tcsicmp(szPDBTo, szPDBFrom) == 0) {
|
|
// PDB filenames match, reference to the 'to' PDB
|
|
ppdbFrom->Close();
|
|
return TRUE;
|
|
}
|
|
|
|
// Create and initialize the TMTS.
|
|
TMTS* ptmts = new TMTS(ppdb1, this, ppdb1->ptpi1);
|
|
if (!ptmts) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
if (!ptmts->fInit(ppdbFrom))
|
|
return FALSE;
|
|
|
|
*pptm = ptmts;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::fGetTmpct(lfPreComp* ppc, TMPCT** pptmpct)
|
|
{
|
|
dassert(ppc && pptmpct);
|
|
|
|
// Consult the open TMPCT list to determine which existing TMPCT corresponds
|
|
// to the given module name and signature.
|
|
return fFindTm(potmPCTHead, (ST)ppc->name, ppc->signature, (TM**)pptmpct, TRUE);
|
|
}
|
|
|
|
BOOL DBI1::fAddTmpct(lfEndPreComp* pepc, SZ_CONST szModule_, TMPCT* ptmpct)
|
|
{
|
|
SZ szLocal = new char[_MAX_PATH];
|
|
|
|
if (!szLocal ||
|
|
!_fullpath(szLocal, szModule_, _MAX_PATH) ||
|
|
!(potmPCTHead = new OTM(potmPCTHead, szLocal, pepc->signature, (TM*)ptmpct))) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::fAddTmpct(SZ_CONST szModule_, SZ_CONST szInternalName, TM* ptm)
|
|
{
|
|
SZ szLocal = new char[_MAX_PATH];
|
|
|
|
// make sure we have the external & internal name
|
|
if (!szLocal ||
|
|
!_fullpath(szLocal, szModule_, _MAX_PATH) ||
|
|
!szInternalName) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
// local and internal pct obj names match - nothing to do
|
|
if (_tcsicmp(szLocal, szInternalName) == 0)
|
|
return TRUE;
|
|
|
|
// find the potm that matches with the external filename
|
|
OTM *potm = potmPCTHead;
|
|
for ( ; potm; potm = potm->pNext) {
|
|
if ( potm->signature == ((TMR *)ptm)->Sig() &&
|
|
_tcsicmp(potm->szName, szLocal) == 0){
|
|
break;
|
|
}
|
|
}
|
|
|
|
// add a potm (alias) with the internal name
|
|
if (potm &&
|
|
!(potmPCTHead = new OTM(potmPCTHead, (char *)szInternalName, potm->signature, potm->ptm, TRUE))) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Search this OTM and the rest of the OTM list it heads for one which
|
|
// matches the name and signature. If found, set *pptm to the corresponding
|
|
// TM and return TRUE, else FALSE.
|
|
//
|
|
BOOL DBI1::fFindTm(OTM* potm, ST stName, SIG signature, TM** pptm, BOOL fCanonName)
|
|
{
|
|
// canonilize to a full path name for comparisons
|
|
char rgbBuffer[_MAX_PATH + 1];
|
|
if (fCanonName)
|
|
szFullPathFromST(stName, rgbBuffer);
|
|
else {
|
|
memcpy(rgbBuffer, stName + 1, *(PB)stName);
|
|
rgbBuffer[*(PB)stName] = 0;
|
|
}
|
|
|
|
|
|
for ( ; potm; potm = potm->pNext) {
|
|
if (potm->signature == signature &&
|
|
_tcsicmp(potm->szName, rgbBuffer) == 0)
|
|
{
|
|
*pptm = potm->ptm;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
OTM::OTM(OTM* pNext_, SZ szName_, SIG signature_, TM* ptm_, BOOL fAlias_)
|
|
: pNext(pNext_), szName(szName_), signature(signature_), ptm(ptm_), fAlias(fAlias_)
|
|
{
|
|
}
|
|
|
|
OTM::~OTM()
|
|
{
|
|
if (szName)
|
|
freeSz(szName);
|
|
if (fAlias && pNext) {// alias node
|
|
delete pNext;
|
|
return;
|
|
}
|
|
if (ptm)
|
|
ptm->endDBI();
|
|
if (pNext)
|
|
delete pNext;
|
|
}
|
|
|
|
void DBI1::fixSymRecs (void* pdbi, void* pOld, void* pNew)
|
|
{
|
|
DBI1* pdbi1 = (DBI1*)pdbi;
|
|
if (pdbi1->pgsiGS)
|
|
pdbi1->pgsiGS->fixSymRecs(pOld, pNew);
|
|
if (pdbi1->pgsiPS)
|
|
pdbi1->pgsiPS->fixSymRecs(pOld, pNew);
|
|
}
|
|
|
|
BOOL DBI1::fReadSymRecPage (unsigned int iPg) {
|
|
|
|
assert(iPg < cSymRecPgs);
|
|
|
|
// page already read in
|
|
if (pbvSymRecPgs->fTestBit(iPg))
|
|
return TRUE;
|
|
|
|
// Calculate the offset for the start of page.
|
|
// We must commit the virtual memory for this page if bufSymRecs is
|
|
// using virtual memory (if not this is a noop).
|
|
OFF off = iPg * cbPage;
|
|
bufSymRecs.Commit(bufSymRecs.Start() + off, cbPage);
|
|
|
|
// compute size to read in & read in the chunk of sym recs
|
|
CB cb;
|
|
if (iPg == cSymRecPgs - 1) { // last page?
|
|
cb = MSFGetCbStream(ppdb1->pmsf, dbihdr.snSymRecs) % cbPage;
|
|
cb = cb ? cb : cbPage;
|
|
} else {
|
|
cb = cbPage;
|
|
}
|
|
|
|
CB cbRead = cb;
|
|
if (!(MSFReadStream2(ppdb1->pmsf, dbihdr.snSymRecs, off, bufSymRecs.Start() + off,
|
|
&cbRead)) && cbRead != cb) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
|
|
// mark page as read in
|
|
pbvSymRecPgs->fSetBit(iPg);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::fpsymFromOff(OFF off, PSYM *ppsym)
|
|
{
|
|
*ppsym = (PSYM)(bufSymRecs.Start() + off);
|
|
return fReadSymRec(*ppsym);
|
|
}
|
|
|
|
BOOL DBI1::fReadSymRec (PSYM psym) {
|
|
|
|
// no sym recs were ever loaded
|
|
if (!pbvSymRecPgs)
|
|
return TRUE;
|
|
|
|
// if psym is not part of lazy load area return
|
|
if ((PB)psym < bufSymRecs.Start() ||
|
|
(PB)psym >= (PB)bufSymRecs.Start() + MSFGetCbStream(ppdb1->pmsf, dbihdr.snSymRecs))
|
|
return TRUE;
|
|
|
|
// read in first page in which sym rec starts
|
|
unsigned int iSymRecPgFirst = ((PB)psym - bufSymRecs.Start()) / cbPage;
|
|
assert(iSymRecPgFirst < cSymRecPgs);
|
|
|
|
// If this page is already loaded this is almost a noop
|
|
if (!fReadSymRecPage(iSymRecPgFirst))
|
|
return FALSE;
|
|
|
|
// sanity check before we can reference psym->reclen:
|
|
// 1) reclen should be the first field in the SYM struct,
|
|
// 2) reclen should be two bytes
|
|
// 3) both bytes of the reclen field should be in the page we just
|
|
// loaded (is it possible to have odd record sizes??)
|
|
assert((PB)psym == (PB)&psym->reclen);
|
|
assert(sizeof(psym->reclen) == 2);
|
|
assert( (UINT)(((PB)psym + 1 - bufSymRecs.Start()) / cbPage) == iSymRecPgFirst);
|
|
|
|
// make sure we read in all pages that this sym rec spans
|
|
unsigned int iSymRecPgLast = (((PB)psym - bufSymRecs.Start()) + psym->reclen
|
|
+ sizeof(psym->reclen) - 1) / cbPage;
|
|
assert(iSymRecPgLast < cSymRecPgs);
|
|
|
|
unsigned int iPg = iSymRecPgFirst + 1;
|
|
|
|
for (; iPg <= iSymRecPgLast; iPg++) {
|
|
if (!fReadSymRecPage(iPg))
|
|
return FALSE;
|
|
}
|
|
|
|
// check for special sym recs S_PROCREF & S_LPROCREF
|
|
// - for these we may have to read in more stuff
|
|
if ((psym->rectyp == S_PROCREF) || (psym->rectyp == S_LPROCREF)) {
|
|
iSymRecPgFirst = (((PB)psym - bufSymRecs.Start()) + psym->reclen
|
|
+ sizeof(psym->reclen) + 1) / cbPage;
|
|
|
|
if (!fReadSymRecPage(iSymRecPgFirst))
|
|
return FALSE;
|
|
|
|
iSymRecPgLast = (((PB)psym - bufSymRecs.Start()) + cbForSym(psym) - 1) / cbPage;
|
|
|
|
iPg = iSymRecPgFirst + 1;
|
|
for (; iPg <= iSymRecPgLast; iPg++) {
|
|
if (!fReadSymRecPage(iPg))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::fReadSymRecs()
|
|
{
|
|
// check and see if we have to read in the Symrecs Stream for this DBI
|
|
if (!(bufSymRecs.Start()) && (dbihdr.snSymRecs != snNil)) {
|
|
CB cbSymRecs = MSFGetCbStream(ppdb1->pmsf, dbihdr.snSymRecs);
|
|
if (cbSymRecs != cbNil){
|
|
expect(fAlign(cbSymRecs));
|
|
if (!bufSymRecs.Reserve(cbSymRecs)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
// for full link case simply read in all syms
|
|
if (ppdb1->fFullBuild) {
|
|
CB cbRead = cbSymRecs;
|
|
if (!(MSFReadStream2(ppdb1->pmsf, dbihdr.snSymRecs, 0, bufSymRecs.Start(),
|
|
&cbRead)) && cbRead != cbSymRecs) {
|
|
ppdb1->setReadError();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// alloc a bitvec to keep track of pages loaded
|
|
cSymRecPgs = (cbSymRecs + cbPage - 1) / cbPage;
|
|
pbvSymRecPgs = new BITVEC;
|
|
if (!pbvSymRecPgs) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pbvSymRecPgs->fAlloc(cSymRecPgs)) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
// we will lazy load sym recs
|
|
return TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::fCheckReadWriteMode(BOOL fWrite_)
|
|
{
|
|
if (fWrite_ != fWrite) {
|
|
ppdb1->setUsageError();
|
|
return FALSE;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::addSecContrib(SC& scIn)
|
|
{
|
|
if (!fWrite)
|
|
return FALSE;
|
|
|
|
#pragma message("Steve: please review with me. -Jan")
|
|
if (((PB)pscEnd == bufSC.End()) &&
|
|
(!bufSC.Reserve(sizeof(SC), (PB*)&pscEnd))) {
|
|
ppdb1->setOOMError();
|
|
return FALSE;
|
|
}
|
|
|
|
expect(fAlign(pscEnd));
|
|
*pscEnd = scIn;
|
|
|
|
pscEnd++;
|
|
dassert((PB)(pscEnd) <= bufSC.End());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::invalidateSCforMod(IMOD imod) {
|
|
if (fSCCleared)
|
|
return TRUE; // the SC was cleared when the DBI was open - do nothing
|
|
|
|
// scan the SC looking for matching imods and invalidate the entry
|
|
for (SC* psc = (SC*) bufSC.Start();
|
|
psc < pscEnd;
|
|
)
|
|
{
|
|
expect(fAlign(psc));
|
|
if (psc->imod == imod) {
|
|
// move bottom of the table into this spot
|
|
dassert ((PB)pscEnd > bufSC.Start())
|
|
*psc = *(--pscEnd);
|
|
}
|
|
else
|
|
psc++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::initFileInfo(IMOD imod, IFILE ifileMac)
|
|
{
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
if (!pmodi)
|
|
return FALSE;
|
|
if (ifileMac > pmodi->ifileMac) {
|
|
// need more space than we currently have
|
|
if (!(pmodi->mpifileichFile = new ICH[ifileMac]))
|
|
return FALSE;
|
|
}
|
|
pmodi->ifileMac = ifileMac;
|
|
memset(pmodi->mpifileichFile, 0, ifileMac * sizeof(ICH));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::addFileInfo(IMOD imod, IFILE ifile, ST stFile)
|
|
{
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
if (!pmodi)
|
|
return FALSE;
|
|
ICH ich;
|
|
if (!addFilename(stFile, &ich))
|
|
return FALSE;
|
|
pmodi->mpifileichFile[ifile] = ich;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::addFilename(ST stFile, ICH *pich)
|
|
{
|
|
// search bufFilenames, the catenation of filenames, for szFile
|
|
for (ST st = (ST)bufFilenames.Start(), stEnd = (ST)bufFilenames.End(); st < stEnd; st += cbForSt(st)) {
|
|
if (memcmp(st, stFile, cbForSt(st)) == 0) {
|
|
// found
|
|
*pich = st - (ST)bufFilenames.Start();
|
|
return TRUE;
|
|
}
|
|
}
|
|
// not found: append the new name
|
|
*pich = bufFilenames.Size();
|
|
if (!bufFilenames.Reserve(cbForSt(stFile), (PB*)&st))
|
|
return FALSE;
|
|
memcpy(st, stFile, cbForSt(stFile));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::reloadFileInfo(PB pb)
|
|
{
|
|
if (*((IMOD*&)pb)++ != imodMac)
|
|
return FALSE;
|
|
|
|
USHORT cRefs = *((USHORT*&)pb)++;
|
|
USHORT* mpimodiref = (USHORT*)pb;
|
|
USHORT* mpimodcref = (USHORT*)((PB)mpimodiref + sizeof(USHORT)*imodMac);
|
|
ICH* mpirefichFile = (ICH*) ((PB)mpimodcref + sizeof(USHORT)*imodMac);
|
|
PCH rgchNames = (PCH) ((PB)mpirefichFile + sizeof(ICH)*cRefs);
|
|
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
if (!initFileInfo(imod, mpimodcref[imod]))
|
|
return FALSE;
|
|
for (IFILE ifile = 0; ifile < mpimodcref[imod]; ifile++) {
|
|
UINT iref = mpimodiref[imod] + ifile;
|
|
ICH ich = mpirefichFile[iref];
|
|
if (!addFileInfo(imod, ifile, &rgchNames[ich]))
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DBI1::QueryFileInfo(OUT PB pb, CB* pcb)
|
|
{
|
|
debug(PB pbSave = pb);
|
|
|
|
// count refs
|
|
int cRefs = 0;
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
if (!pmodi)
|
|
return FALSE;
|
|
cRefs += pmodi->ifileMac;
|
|
}
|
|
|
|
CB cb = cbAlign(2*sizeof(USHORT) + 2*sizeof(USHORT)*imodMac + sizeof(ULONG)*cRefs + bufFilenames.Size());
|
|
if (!pb) {
|
|
*pcb = cb;
|
|
return TRUE;
|
|
}
|
|
else if (pb && *pcb != cb)
|
|
return FALSE;
|
|
|
|
// form sstFileIndex record
|
|
*((USHORT*&)pb)++ = imodMac;
|
|
*((USHORT*&)pb)++ = cRefs;
|
|
USHORT irefStart = 0;
|
|
for (imod = 0; imod < imodMac; imod++) {
|
|
*((USHORT*&)pb)++ = irefStart;
|
|
irefStart += pmodiForImod(imod)->ifileMac;
|
|
}
|
|
for (imod = 0; imod < imodMac; imod++)
|
|
*((USHORT*&)pb)++ = pmodiForImod(imod)->ifileMac;
|
|
for (imod = 0; imod < imodMac; imod++) {
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
for (IFILE ifile = 0; ifile < pmodi->ifileMac; ifile++)
|
|
*((ICH*&)pb)++ = pmodi->mpifileichFile[ifile];
|
|
}
|
|
memcpy(pb, bufFilenames.Start(), bufFilenames.Size());
|
|
pb += bufFilenames.Size();
|
|
|
|
debug(assert(pbSave + cb == (PB) cbAlign((long)pb)));
|
|
return TRUE;
|
|
}
|
|
|
|
void DBI1::DumpMods()
|
|
{
|
|
printf("%-20.20s %-30.30s sn cbSyms cbLines cbFpo\n", "module", "file");
|
|
for (IMOD imod = 0; imod < imodMac; imod++) {
|
|
MODI* pmodi = pmodiForImod(imod);
|
|
printf("%-20.20s %-30.30s %3d %6ld %7ld %5ld\n",
|
|
pmodi->szModule(), pmodi->szObjFile(), (short)pmodi->sn,
|
|
pmodi->cbSyms, pmodi->cbLines, pmodi->cbFpo);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
void DBI1::DumpSecContribs()
|
|
{
|
|
printf("Section Contributions\nisect\toff\t\tcb\t\tdwChar\t\timod\n");
|
|
for (SC* psc=(SC*)(bufSC.Start()); psc < pscEnd; psc++) {
|
|
printf("0x%4.4x\t0x%8.8x\t0x%8.8x\t0x%08lx\t0x%4.4x\n",
|
|
psc->isect, psc->off, psc->cb, psc->dwCharacteristics, psc->imod);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
void DBI1::DumpSecMap()
|
|
{
|
|
if (!bufSecMap.Start())
|
|
return;
|
|
|
|
OMFSegMap* phdr = (OMFSegMap*) bufSecMap.Start();
|
|
printf("Section Map cSeg = 0x%4.4x, cSegLog = 0x%4.4x\n", phdr->cSeg, phdr->cSegLog);
|
|
printf("flags\tovl\tgroup\tframe\tsegname\tclass\toffset\t\tcbseg\n");
|
|
for (OMFSegMapDesc* pDesc =(OMFSegMapDesc*)(bufSecMap.Start() + sizeof (OMFSegMap));
|
|
(PB) pDesc < bufSecMap.End();
|
|
pDesc++) {
|
|
printf("0x%4.4x\t0x%4.4x\t0x%4.4x\t0x%4.4x\t0x%4.4x\t0x%4.4x\t0x%8.8x\t0x%8.8x\n",
|
|
pDesc->flags, pDesc->ovl, pDesc->group, pDesc->frame, pDesc->iSegName,
|
|
pDesc->iClassName, pDesc->offset, pDesc->cbSeg);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
BOOL DBI1::AddThunkMap(OFF* poffThunkMap, UINT nThunks, CB cbSizeOfThunk,
|
|
SO* psoSectMap, UINT nSects, ISECT isectThunkTable, OFF offThunkTable)
|
|
{
|
|
dassert(pgsiPS);
|
|
return pgsiPS->addThunkMap(poffThunkMap, nThunks, cbSizeOfThunk, psoSectMap, nSects, isectThunkTable, offThunkTable);
|
|
}
|
|
|
|
void szFullPathFromST(ST stName, SZ szFullPath)
|
|
{
|
|
char rgbName[_MAX_PATH];
|
|
|
|
memcpy(rgbName, stName + 1, *(PB)stName);
|
|
rgbName[*(PB)stName] = 0;
|
|
_fullpath(szFullPath, rgbName, _MAX_PATH);
|
|
}
|
|
|
|
BOOL DBI1::QueryTiForUDT(SZ sz, BOOL fCase, OUT TI* pti, OUT TM** pptm)
|
|
{
|
|
static TM* ptmCache = 0;
|
|
|
|
if (ptmCache && ptmCache->QueryTiForUDT(sz, fCase, pti)) {
|
|
fUDTOutsideRef = TRUE;
|
|
*pptm = ptmCache;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
for (OTM *potm = potmTSHead ; potm; potm = potm->pNext) {
|
|
if (potm->ptm && potm->ptm->QueryTiForUDT(sz, fCase, pti)) {
|
|
fUDTOutsideRef = TRUE;
|
|
ptmCache = potm->ptm;
|
|
*pptm = ptmCache;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|