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.
 
 
 
 
 
 

1033 lines
24 KiB

//////////////////////////////////////////////////////////////////////////////
// PDB Debug Information API GSI Implementation
#include "pdbimpl.h"
#include "dbiimpl.h"
#include "cvinfo.h"
typedef unsigned long UOFF;
GSI1::GSI1 (PDB1* ppdb1_, DBI1* pdbi1_, TPI* ptpi_)
: ppdb1(ppdb1_), pdbi1(pdbi1_), ptpi(ptpi_)
{
memset(rgphrBuckets, 0, sizeof(rgphrBuckets));
}
BOOL GSI1::Close()
{
delete this;
return TRUE;
}
GSI1::~GSI1()
{
}
BOOL GSI1::fInit(SN sn)
{
if (!pdbi1->fReadSymRecs())
return FALSE;
return readStream(sn);
}
BOOL GSI1::readHash(SN sn, OFF offPoolInStream, CB cb)
{
// must allocate the buffer for the records before we read in the buckets or
// the fix up routines will generate garbage
cb = cb - sizeof(rgphrBuckets);
expect(fAlign(cb));
int nEntries = cb / sizeof(HRFile);
CB cbHR = nEntries * sizeof(HR);
// allocate one record of slop at the beginning so we can step backwards thru
// the begining of the hashrecs in fixHashIn without a memory violation
PB pbHR = (PB) new (poolSymHash) BYTE[cbHR + sizeof(HR)];
if (!pbHR) {
ppdb1->setOOMError();
return FALSE;
}
pbHR += sizeof(HR);
CB iphrMax = sizeof(rgphrBuckets);
// funny deal - read in the pool of HR's then the buckets
if (!MSFReadStream2(ppdb1->pmsf, sn, offPoolInStream, pbHR, &cb) ||
!MSFReadStream2(ppdb1->pmsf, sn, offPoolInStream + cb, rgphrBuckets, &iphrMax)){
ppdb1->setReadError();
return FALSE;
}
fixHashIn(pbHR, nEntries);
fixSymRecs((void*)1, pdbi1->bufSymRecs.Start());
return TRUE;
}
BOOL GSI1::readStream(SN sn)
{
if (sn == snNil)
return TRUE; // nothing to read
// read in the hash bucket table from the dbi stream
CB cb = MSFGetCbStream(ppdb1->pmsf, sn);
if (cb == cbNil)
return TRUE; // nothing to read
return readHash(sn, 0, cb);
}
BOOL GSI1::fSave(SN* psn)
{
return writeStream(psn);
}
BOOL GSI1::writeStream(SN* psn)
{
if (!fEnsureSn(psn)) {
ppdb1->setLastError(EC_LIMIT);
return FALSE;
}
// ptrs in the stream are offsets biased by one to distinguish null ptrs/offsets
fixSymRecs(pdbi1->bufSymRecs.Start(), (void*)1);
expect(fAlign(sizeof(rgphrBuckets)));
// need to do a dummy replace here because fWriteHash just appends
if (!MSFReplaceStream(ppdb1->pmsf, *psn, NULL, 0) ||
!fWriteHash(*psn, NULL)){
ppdb1->setWriteError();
return FALSE;
}
return TRUE;
}
INTV GSI1::QueryInterfaceVersion()
{
return intv;
}
IMPV GSI1::QueryImplementationVersion(){
return impv;
}
PSYM GSI1::psymForPhr (HR *phr) {
if (pdbi1->fReadSymRec(phr->psym))
return phr->psym;
else
return NULL;
}
PB GSI1::NextSym(PB pbSym)
{
PSYM psym = (PSYM)pbSym;
HR* phr = 0;
int iphr = -1;
if (psym && last.phr && last.phr->psym == psym) {
// cache of position of last answer valid
iphr = last.iphr;
phr = last.phr;
}
else if (psym) {
ST st;
if (!fGetSymName(psym, &st)) {
dassert(FALSE);
return NULL;
}
iphr = hashSt(st);
for (phr = rgphrBuckets[iphr]; phr; phr = phr->pnext)
if (phr->psym == psym)
break;
if (!phr) {
dassert(FALSE);
return NULL;
}
}
// at this point, phr and iphr address the symbol that was last returned
// advance to the next phr, if any
if (phr)
phr = phr->pnext;
if (!phr)
while (++iphr < iphrHash && !(phr = rgphrBuckets[iphr]))
;
if (phr) {
// success: save this last answer position for the next call
last.iphr = iphr;
last.phr = phr;
return (PB)psymForPhr(phr);
}
// no more entries; return no symbol
return NULL;
}
inline static int caseInsensitiveComparePchPchCchCch(PCCH pch1, PCCH pch2, CB cb1, CB cb2)
{
if (cb1 < cb2)
return -1;
else if (cb1 > cb2)
return 1;
else
return _memicmp(pch1, pch2, cb1);
}
PB GSI1::HashSym(SZ_CONST szName, PB pbSym)
{
PSYM psym = (PSYM)pbSym;
HR* phr;
int iphr;
if (psym) {
// Find the next sym after this one...
if (last.phr && last.phr->psym == psym) {
// cache of position of last answer valid
phr = last.phr;
iphr = last.iphr;
}
else {
// cache miss, find the sym on its bucket
iphr = hashSz(szName);
for (phr = rgphrBuckets[iphr]; phr; phr = phr->pnext)
if (phr->psym == psym)
break;
if (!phr) {
// incoming sym not in this symbol table - start from scratch
goto nosym;
}
}
// we have reestablished phr; now advance it to next potential sym
dassert(phr);
phr = phr->pnext;
}
else {
nosym:
iphr = hashSz(szName);
phr = rgphrBuckets[iphr];
}
// At this point, phr may be 0, may address the next sym with the same name,
// or may address some sym on the hash bucket before the HR we're looking for.
// Search the HRs for the next sym with matching name, and return it, or 0
// if not found.
//
// Note that since HR entries are sorted by memcmp of their syms' names, we
// can exit early if the current HR is >= the name we're looking for.
for ( ; phr; phr = phr->pnext) {
ST st;
PSYM psymPhr = psymForPhr(phr);
if (!psymPhr)
return 0;
if (!fGetSymName(psymPhr, &st)) {
dassert(FALSE);
return 0;
}
int icmp = caseInsensitiveComparePchPchCchCch(st + 1, szName, cbForSt(st) - 1, strlen(szName));
if (icmp == 0) {
// success: save this last answer position for the next call
last.phr = phr;
last.iphr = iphr;
return (PB)psymForPhr(phr);
}
else if (icmp > 0)
return 0;
}
return 0;
}
// we have read in a list of dbi symrecs offsets and a rphrbuckets of offsets into
// this first table - we need to walk thru this abbreviated hash structure backwards
// and reconstruct a linked list hash table
void GSI1::fixHashIn(PB pb, int nEntries)
{
int i;
nEntries--;
for (i=iphrFree; i >= 0; i--){
HR* phrTail = NULL;
if ((OFF)rgphrBuckets[i] != -1) {
rgphrBuckets[i] = (HR*) (pb + (OFF)rgphrBuckets[i]);
HR* phr;
for (phr = (HR*)pb + nEntries;
phr >= rgphrBuckets[i];
phr = (HR*)pb + --nEntries) {
HRFile* phrFile = (HRFile*)pb + nEntries;
phr->psym = phrFile->psym;
phr->cRef = phrFile->cRef;
phr->pnext = phrTail;
phrTail = phr;
}
}
else
rgphrBuckets[i] = NULL;
}
assert(nEntries == -1);
}
BOOL GSI1::fWriteHash(SN sn, CB* pcb)
{
int i;
OFF off = 0;
CB cb = 0;
Buffer buffer;
// allocate size of buffer based on size of poolSymHash
if (poolSymHash.cbTotal > 0 ) {
CB cbBuffer = (poolSymHash.cbTotal / sizeof(HR)) * sizeof(HRFile);
if (!buffer.SetInitAlloc(cbBuffer)) {
ppdb1->setOOMError();
return FALSE;
}
}
// write out all the buckets except for the free list - lose them
for (i=0; i < iphrHash; i++)
if (rgphrBuckets[i]) {
HR* phr = rgphrBuckets[i];
*((OFF *)&rgphrBuckets[i]) = off;
for (; phr; phr = phr->pnext) {
if (!buffer.Append((PB) &(phr->psym), sizeof(HRFile))) {
ppdb1->setOOMError();
return FALSE;
}
off += sizeof(HR);
cb += sizeof(HRFile);
}
}
else
*((OFF *)&rgphrBuckets[i]) = -1; // neg one for null
*((OFF *)&rgphrBuckets[iphrFree]) = -1; // lose the free bucket
if (!MSFAppendStream(ppdb1->pmsf, sn, buffer.Start(), buffer.Size()) ||
!MSFAppendStream(ppdb1->pmsf, sn, rgphrBuckets, sizeof(rgphrBuckets))) {
return FALSE;
}
expect(fAlign(cb + sizeof(rgphrBuckets)));
if (pcb)
*pcb = cb + sizeof(rgphrBuckets);
return TRUE;
}
void GSI1::fixSymRecs (void* pOld, void* pNew)
{
int i;
CB cbDelta = (CB)((PB)pNew - (PB)pOld);
for (i=0; i < iphrMax; i++){
HR* phr;
for (phr = rgphrBuckets[i]; phr; phr = phr->pnext)
if (phr->psym)
phr->psym = (PSYM) ((PB)phr->psym + cbDelta);
}
}
HASH GSI1::hashSt(ST st)
{
return HashPbCb((PB)st + 1, cbForSt(st) - 1, iphrHash);
}
HASH GSI1::hashSz(SZ_CONST sz)
{
return HashPbCb((PB)sz, strlen(sz), iphrHash);
}
BOOL GSI1::fGetFreeHR(HR** pphr) {
HR** pphrFree = &rgphrBuckets[iphrFree];
if (*pphrFree) {
*pphr = *pphrFree;
*pphrFree = (*pphrFree)->pnext; // unlink from free list
return TRUE;
}
else
return FALSE;
}
void* HR::operator new(size_t size, GSI1* pgsi1) {
assert(size == sizeof(HR));
HR* phr;
if (pgsi1->fGetFreeHR(&phr))
return phr;
else
return new (pgsi1->poolSymHash) BYTE[sizeof(HR)];
}
BOOL GSI1::fInsertNewSym(HR** pphr, PSYM psym, OFF *poff)
{
dassert(pphr);
dassert(psym);
HR* phr = new (this) HR(*pphr, 0);
if (!phr) {
ppdb1->setOOMError();
return FALSE;
}
if (!pdbi1->fAddSym(psym, &(phr->psym)) ||
!addToAddrMap(phr->psym))
return FALSE;
phr->pnext = *pphr;
*pphr = phr;
if (poff)
*poff = offForSym(phr->psym);
return TRUE;
}
// unlink the HR from its hash table chain and add it to the free list
inline BOOL GSI1::fUnlinkHR(HR** pphr)
{
HR* phr = *pphr;
*pphr = (*pphr)->pnext;
phr->pnext = rgphrBuckets[iphrFree];
rgphrBuckets[iphrFree] = phr;
return delFromAddrMap(phr->psym);
}
void GSI1::incRefCnt(HR** pphr)
{
assert(pphr);
assert(*pphr);
(*pphr)->cRef++;
}
BOOL GSI1::decRefCnt(OFF off)
{
// off is an offset into the pdb's bufSymRec - we need get the symrec
// from the pool and do a findsym to get the hr of the symbol so
// we can dec the refcnt in the hr
PSYM psym = 0;
ST st = 0;
HR** pphr = 0;
if (!(pdbi1->fpsymFromOff(off, &psym)) || !psym ||
!fGetSymName(psym, &st) || !st)
return FALSE;
while (fFindRec(st, &pphr)) {
PSYM psymPhr = psymForPhr(*pphr);
if (!psymPhr)
return FALSE;
if (!memcmp(psym, psymPhr, *((USHORT *)psym))) {
// we found a match decrement the use count and return
if (--((*pphr)->cRef) <= 0) {
// refcnt is zero - put on the free list
return fUnlinkHR(pphr);
}
return TRUE;
}
}
return FALSE;
}
BOOL GSI1::packProcRef(PSYM psym, IMOD imod, OFF off, OFF *poff)
{
UCHAR rgbProcrecBuff[sizeof(REFSYM) + 256];
ST st;
BOOL fTmp = fGetSymName(psym, &st);
dassert(fTmp);
// form procref record
REFSYM* pRefSym = (REFSYM*) rgbProcrecBuff;
pRefSym->reclen = sizeof(REFSYM) - sizeof(USHORT);
pRefSym->rectyp = (fSymIsGlobal(psym)) ? S_PROCREF : S_LPROCREF;
pRefSym->sumName = 0;
pRefSym->ibSym = off;
pRefSym->imod = ximodForImod(imod);
pRefSym->usFill = 0;
CB cbSt = cbForSt(st);
memcpy((PB)pRefSym + sizeof(REFSYM), st, cbSt);//copy length preceeded name
memset((PB)pRefSym + sizeof(REFSYM) + cbSt, 0, dcbAlign(cbSt)); //align pad with zeros
return packSym((PSYM)pRefSym, poff);
}
BOOL GSI1::packSym (PSYM psym, OFF *poff)
{
ST st;
if (!fGetSymName(psym, &st))
return FALSE;
HR** pphr = 0;
if (!st)
return FALSE;
while (fFindRec(st, &pphr)) {
PSYM psymPhr = psymForPhr(*pphr);
if (!psymPhr)
return FALSE;
if (!memcmp(psym, psymPhr, *((USHORT *)psym))) {
// we found a match increment/decrement the use count and return
incRefCnt(pphr);
*poff = offForSym(psymPhr);
return TRUE;
}
// we found a match name but not a matching record - if the record sought
// is of global scope insert it before any of its matching local records
if (fSymIsGlobal(psym) && !fSymIsGlobal(psymPhr)) {
return fInsertNewSym(pphr, psym, poff);
}
}
return fInsertNewSym(pphr, psym, poff);
}
BOOL GSI1::fFindRec(ST st, OUT HR*** ppphr)
{
HR** pphr = *ppphr;
BOOL retval = FALSE;
if (!pphr)
pphr = &rgphrBuckets[hashSt(st)];
else
pphr = &((*pphr)->pnext);
while (*pphr) {
ST stTab;
PSYM psymPhr = psymForPhr(*pphr);
if (!psymPhr)
return FALSE;
if (fGetSymName(psymPhr, &stTab)) {
dassert(stTab);
int icmp = caseInsensitiveComparePchPchCchCch(stTab + 1, st + 1, cbForSt(stTab) - 1, cbForSt(st) - 1);
if (icmp == 0) {
retval = TRUE;
break;
}
else if (icmp > 0)
break;
}
pphr = &((*pphr)->pnext);
}
*ppphr = pphr;
return retval;
}
BOOL GSI1::delFromAddrMap(PSYM psym)
{
return TRUE; // no AddrMap here
}
BOOL GSI1::addToAddrMap(PSYM psym)
{
return TRUE; // no AddrMap here
}
// PUBLIC GSI specific methods
inline int cmpAddrMap(ISECT isect1, UOFF uoff1, ISECT isect2, UOFF uoff2)
{
dassert(sizeof(UOFF) == sizeof(long));
dassert(sizeof(ISECT) == sizeof(short));
return (isect1 == isect2) ? (long)uoff1 - (long)uoff2 : (short)isect1 - (short)isect2;
}
inline ISECT isectForPub(PSYM psym)
{
dassert(psym->rectyp == S_PUB32);
return (ISECT) ((PUBSYM32*)psym)->seg;
}
inline UOFF uoffForPub(PSYM psym)
{
dassert(psym->rectyp == S_PUB32);
return (UOFF) ((PUBSYM32*)psym)->off;
}
inline int cmpAddrMap(ISECT isect, UOFF uoff, PSYM psym)
{
return cmpAddrMap(isect, uoff, isectForPub(psym), uoffForPub(psym));
}
inline int __cdecl cmpAddrMap(const void* pelem1, const void* pelem2)
{
PSYM psym1 = *(PSYM*)pelem1;
PSYM psym2 = *(PSYM*)pelem2;
return cmpAddrMap(isectForPub(psym1), uoffForPub(psym1), psym2);
}
PB PSGSI1::NearestSym (ISECT isect, OFF off, OUT OFF* pdisp)
{
if (bufCurAddrMap.Size() == 0)
return NULL;
PB pb;
if ((pb = pbInThunkTable(isect, off, pdisp)) != NULL)
return pb;
PSYM* ppsymLo = (PSYM*)bufCurAddrMap.Start();
PSYM* ppsymHi = (PSYM*)bufCurAddrMap.End() - 1;
while (ppsymLo < ppsymHi) {
PSYM* ppsym = ppsymLo + ((ppsymHi - ppsymLo + 1) >> 1);
pdbi1->fReadSymRec(*ppsym); // load sym if reqd
int cmp = cmpAddrMap(isect, (UOFF)off, *ppsym);
if (cmp < 0)
ppsymHi = ppsym - 1;
else if (cmp > 0)
ppsymLo = ppsym;
else
ppsymLo = ppsymHi = ppsym;
}
// Boundary conditions.
// Example: given publics at (a=1:10, b=1:20, c=2:10, d=2:20),
// search for (1: 9) returns (a,-1)
// for (1:11) returns (a,1)
// for (1:21) returns (b,1)
// for (2: 9) returns (c,-1)
// for (2:11) returns (c,1)
// for (2:21) returns (d,1)]
// so, for cases (2:9), we must advance ppsymLo from (1:21) to (2:9)
//
pdbi1->fReadSymRec(*ppsymLo); // load sym if reqd
if (isectForPub(*ppsymLo) < isect && ppsymLo < ((PSYM*)bufCurAddrMap.End() - 1))
++ppsymLo;
*pdisp = (OFF) ((UOFF)off - uoffForPub(*ppsymLo));
return (PB)(*ppsymLo);
}
BOOL PSGSI1::fInit(SN sn_) {
if (!pdbi1->fReadSymRecs())
return FALSE;
sn = sn_; // need to remember stream for incremental merge
return readStream();
}
BOOL PSGSI1::readStream()
{
if (sn == snNil) {
fCreate = TRUE;
return TRUE; // nothing to read
}
// read in the hash bucket table from the dbi stream
CB cb = MSFGetCbStream(ppdb1->pmsf, sn);
if (cb == cbNil)
return TRUE; // nothing to read
// read in the header
CB cbHdr = sizeof(PSGSIHDR);
if (!MSFReadStream2(ppdb1->pmsf, sn, 0, &psgsihdr, &cbHdr)) {
ppdb1->setReadError();
return FALSE;
}
if (!readHash(sn, sizeof(PSGSIHDR), psgsihdr.cbSymHash))
return FALSE;
// if we are updating a pdb don't bother to read in the AddrMap until we are
// ready to save the Publics
return (fWrite || readAddrMap());
}
BOOL PSGSI1::readAddrMap()
{
if (sn == snNil)
return FALSE;
if (!psgsihdr.cbAddrMap)
return TRUE;
expect(fAlign(psgsihdr.cbAddrMap));
if (!bufCurAddrMap.Reserve(psgsihdr.cbAddrMap)) {
ppdb1->setOOMError();
return FALSE;
}
if (!MSFReadStream2(ppdb1->pmsf, sn, sizeof(PSGSIHDR) + psgsihdr.cbSymHash, bufCurAddrMap.Start(),
&(psgsihdr.cbAddrMap))) {
ppdb1->setReadError();
return FALSE;
}
fixupAddrMap(bufCurAddrMap, (OFF) (pdbi1->bufSymRecs.Start()));
return TRUE;
}
BOOL PSGSI1::readThunkMap()
{
if (bufThunkMap.Start())
return TRUE; // already read it - return
if (sn == snNil)
return FALSE;
dassert(psgsihdr.nThunks);
CB cbThunkMap;
CB cbSectMap;
if (!bufThunkMap.Reserve(cbThunkMap = cbSizeOfThunkMap()) ||
!bufSectMap.Reserve(cbSectMap = cbSizeOfSectMap())) {
ppdb1->setOOMError();
return FALSE;
}
expect(fAlign(cbThunkMap));
expect(fAlign(cbSectMap));
if (!MSFReadStream2(ppdb1->pmsf, sn, sizeof(PSGSIHDR) + psgsihdr.cbSymHash + psgsihdr.cbAddrMap,
bufThunkMap.Start(), &cbThunkMap) ||
(!MSFReadStream2(ppdb1->pmsf, sn, sizeof(PSGSIHDR) + psgsihdr.cbSymHash + psgsihdr.cbAddrMap + cbThunkMap,
bufSectMap.Start(), &cbSectMap))) {
ppdb1->setReadError();
return FALSE;
}
return TRUE;
}
BOOL PSGSI1::fSave(SN* psn)
{
sortBuf(bufNewAddrMap);
if (fCreate)
// just write out all the records we have collected
return writeStream(psn, bufNewAddrMap);
//incremental
if (mergeAddrMap())
return writeStream(psn, bufResultAddrMap);
return FALSE;
}
BOOL PSGSI1::Close()
{
delete this;
return TRUE;
}
PSGSI1::~PSGSI1()
{
}
// mergeAddrMap
// need to do a three way merge for the incremental update of the AddrMap.
// bufCurAddrMap should be read here - it actually represents a sorted list of
// the previous AddrMap. bufNewAddrMap is an unsorted list of the new additions
// and bufDelAddrMap is an unsorted list of those entries that should be deleted.
// the result of the merge will be a sorted AddrMap in bufResultAddrMap
BOOL PSGSI1::mergeAddrMap()
{
// read in the previous addr map - it is sorted
if (!readAddrMap())
return FALSE;
// ensure that all sym records pointed to are loaded
if (!readSymsInAddrMap(bufCurAddrMap) ||
!readSymsInAddrMap(bufDelAddrMap))
return FALSE;
// just need to sort the deleted records all of the new records should have
// been sorted by fSave
sortBuf(bufDelAddrMap);
PSYM* ppsymNew;
PSYM* ppsymDel;
PSYM* ppsymCur;
BOOL curValid, newValid, delValid;
for (
// for init;
ppsymNew = (PSYM*) bufNewAddrMap.Start(),
newValid = (PB) ppsymNew < bufNewAddrMap.End(),
ppsymDel = (PSYM*) bufDelAddrMap.Start(),
delValid = (PB) ppsymDel < bufDelAddrMap.End(),
ppsymCur = (PSYM*) bufCurAddrMap.Start(),
curValid = (PB) ppsymCur < bufCurAddrMap.End();
// loop condition
curValid || newValid ;
// no step
){
expect(fAlign(ppsymNew));
expect(fAlign(ppsymDel));
expect(fAlign(ppsymCur));
if (curValid) {
if (newValid && (cmpAddrMap(ppsymNew, ppsymCur) <= 0)) {
if (!appendResult(&ppsymNew, bufNewAddrMap, &newValid))
return FALSE;
} else {
if (delValid && (cmpAddrMap(ppsymDel, ppsymCur) == 0)) {
// found a match in the to be deleted syms - skip this cur and del
delValid = (PB) (++ppsymDel) < bufDelAddrMap.End();
curValid = (PB) (++ppsymCur) < bufCurAddrMap.End();
} else {
if (!appendResult(&ppsymCur, bufCurAddrMap, &curValid))
return FALSE;
}
}
} else {
//just append the rest of new to the result
while (newValid && appendResult(&ppsymNew, bufNewAddrMap, &newValid));
}
} // end for
return TRUE;
}
void PSGSI1::sortBuf(Buffer& buf)
{
if (buf.Size()) {
fixupAddrMap(buf, (OFF) (pdbi1->bufSymRecs.Start()));
qsort(buf.Start(), buf.Size()/sizeof(PSYM), sizeof(PSYM), cmpAddrMap);
}
}
BOOL PSGSI1::appendResult(PSYM** pppsym, Buffer& buf, BOOL* pValid)
{
expect(fAlign(*pppsym));
if (!bufResultAddrMap.Append((PB) *pppsym, sizeof(PSYM)))
return FALSE;
*pValid = (PB)(++(*pppsym)) < buf.End();
return TRUE;
}
BOOL PSGSI1::writeStream(SN* psn, Buffer& bufAddrMap)
{
if (!fEnsureSn(psn)) {
ppdb1->setLastError(EC_LIMIT);
return FALSE;
}
fixupAddrMap(bufAddrMap, -(OFF)(pdbi1->bufSymRecs.Start()));
// ptrs in the stream are offsets biased by one to distinguish null ptrs/offsets
fixSymRecs(pdbi1->bufSymRecs.Start(), (void*)1);
psgsihdr.cbAddrMap = bufAddrMap.Size();
expect(fAlign(sizeof(psgsihdr)));
expect(fAlign(sizeof(rgphrBuckets)));
expect(fAlign(psgsihdr.cbSymHash));
expect(fAlign(psgsihdr.cbAddrMap));
if (!MSFReplaceStream(ppdb1->pmsf, *psn, &psgsihdr, sizeof(psgsihdr)) ||
!fWriteHash(*psn, &psgsihdr.cbSymHash) ||
!MSFAppendStream(ppdb1->pmsf, *psn, bufAddrMap.Start(), bufAddrMap.Size()) ||
!MSFAppendStream(ppdb1->pmsf, *psn, bufThunkMap.Start(), bufThunkMap.Size()) ||
!MSFAppendStream(ppdb1->pmsf, *psn, bufSectMap.Start(), bufSectMap.Size()) ||
!MSFWriteStream(ppdb1->pmsf, *psn, 0, &psgsihdr, sizeof(psgsihdr))) {
ppdb1->setWriteError();
return FALSE;
}
return TRUE;
}
BOOL PSGSI1::addToAddrMap(PSYM psym)
{
OFF off = (PB)psym - (PB)(pdbi1->bufSymRecs.Start());
return bufNewAddrMap.Append((PB) &off, sizeof(OFF));
}
BOOL PSGSI1::delFromAddrMap(PSYM psym)
{
if (fCreate)
return TRUE; // don't bother
OFF off = (PB)psym - pdbi1->bufSymRecs.Start();
return bufDelAddrMap.Append((PB) &off, sizeof(OFF));
}
void PSGSI1::fixupAddrMap(Buffer& buf, OFF doff)
{
for (OFF* poff = (OFF*)buf.Start(); poff < (OFF*)buf.End(); poff++)
*poff += doff;
}
BOOL PSGSI1::readSymsInAddrMap (Buffer& buf)
{
for (PSYM* ppsym = (PSYM*)buf.Start(); ppsym < (PSYM*)buf.End(); ppsym++)
if (!pdbi1->fReadSymRec(*ppsym))
return FALSE;
return TRUE;
}
// Pack new public symbol into the publics table.
//
// (as of 11/93:)
// Unlike GSI1::packSym, we are called only with new public definitions.
// We are not given an opportunity to delete obsolete publics.
// Therefore, we must use this algorithm:
// (Treating public names as case sensitive:)
// If the public exists and is unchanged, do nothing.
// If the public exists and is different, delete the existing public
// and insert one for the new symbol.
// If the public does not yet exist, insert one for the new symbol.
//
// One complication: we are obliged to return symbols from HashSym using a
// case insensitive search. This obliges them to be stored using a case
// insensitive ordering scheme. This obliges all code which operates upon
// them to use a case insensitive iteration mechanism. This complicates
// our search code which must treat public names case sensitively.
//
BOOL PSGSI1::packSym(PSYM psym)
{
PUBSYM32* ppub = (PUBSYM32*)psym;
dassert(ppub->rectyp == S_PUB32);
HR** pphrFirst = 0;
if (fFindRec((ST)ppub->name, &pphrFirst)) {
// Loop on every public with same name (case insensitive),
// searching for one with same name (case sensitive).
HR** pphr = pphrFirst;
do {
PUBSYM32* ppubHR = (PUBSYM32*)(psymForPhr(*pphr));
dassert(ppubHR->rectyp == S_PUB32);
if (memcmp(ppub->name + 1, ppubHR->name + 1, *(PB)ppub->name) == 0) {
// found a public with same name (case sensitive)
dassert(ppub->reclen == ppubHR->reclen);
if (memcmp(ppub, ppubHR, ppub->reclen) == 0) {
// record contents match: the existing public stands as is
return TRUE;
}
else {
// record contents differ: the new public must *replace*
// the existing public
return fUnlinkHR(pphr) && fInsertNewSym(pphr, psym);
}
}
} while (fFindRec((ST)ppub->name, &pphr));
// Not found: there were some publics with the same name (case insensitive)
// but none with the same name (case sensitive). Fall through...
}
// Brand new public
return fInsertNewSym(pphrFirst, psym);
}
BOOL PSGSI1::addThunkMap(OFF* poffThunkMap, UINT nThunks, CB cbSizeOfThunk,
SO* psoSectMap, UINT nSects, ISECT isectThunkTable, OFF offThunkTable)
{
psgsihdr.nThunks = nThunks;
psgsihdr.cbSizeOfThunk = cbSizeOfThunk,
psgsihdr.isectThunkTable = isectThunkTable;
psgsihdr.offThunkTable = offThunkTable;
psgsihdr.nSects = nSects;
if (!bufThunkMap.Append((PB) poffThunkMap, cbSizeOfThunkMap()) ||
!bufSectMap.Append((PB) psoSectMap, cbSizeOfSectMap())) {
ppdb1->setOOMError();
return FALSE;
}
return TRUE;
}
// prepare the thunk sym template
BYTE PSGSI1::rgbThunkSym[sizeof(PUBSYM32) + 356]; // 100 bytes of slop for name
PB PSGSI1::pbInThunkTable (ISECT isect, OFF off, OUT OFF* pdisp)
{
if (!fInThunkTable(isect, off) ||
!readThunkMap())
return NULL;
OFF offTarget = offThunkMap(off);
ISECT isectTarget;
mapOff(offTarget, &isectTarget, &offTarget);
if (fInThunkTable(isectTarget, offTarget))
return NULL; // stop any recursion here
PB pb = NearestSym(isectTarget, offTarget, pdisp);
OFF disp = *pdisp;
*pdisp = 0;
return pbFakePubdef(pb, isect, off, disp);
}
BOOL PSGSI1::fInThunkTable(ISECT isect, OFF off)
{
if ((off >= psgsihdr.offThunkTable) &&
(off < psgsihdr.offThunkTable + cbSizeOfThunkTable()) &&
(isect == psgsihdr.isectThunkTable))
return TRUE;
return FALSE;
}
OFF PSGSI1::offThunkMap(OFF off)
{
UINT ui = (off - psgsihdr.offThunkTable) / psgsihdr.cbSizeOfThunk;
dassert(psgsihdr.nThunks > ui);
dassert(bufThunkMap.Start());
return(*((OFF*)bufThunkMap.Start() + ui));
}
void PSGSI1::mapOff(OFF off, OUT ISECT * pisect, OUT OFF* poff)
{
unsigned int i;
SO* pso = (SO*) bufSectMap.Start();
for (i = 0; i < (psgsihdr.nSects - 1); i++, pso++) {
if ((off >= pso->off) && (off < (pso+1)->off)) {
*pisect = pso->isect;
*poff = off - pso->off;
return;
}
}
if (i) pso++;
*pisect = pso->isect;
*poff = off - pso->off;
}
PB PSGSI1::pbFakePubdef(PB pb, ISECT isectThunk, OFF offThunk, OFF disp)
{
if (!pb)
return NULL;
PUBSYM32* psymTarget = (PUBSYM32*) pb;
PUBSYM32* psymFake = (PUBSYM32*) &rgbThunkSym[0];
memcpy(rgbThunkSym, pb, sizeof(PUBSYM32));
psymFake->off = offThunk;
psymFake->seg = isectThunk;
sprintf((char*)&psymFake->name[1], "@ILT+%d(", offThunk - psgsihdr.offThunkTable);
CB cb = strlen((char*) &psymFake->name[1]);
memcpy(&psymFake->name[1 + cb], &psymTarget->name[1], (CB) psymTarget->name[0]);
cb += psymFake->name[0];
if (disp) {
sprintf((char*)&psymFake->name[cb + 1], "+%d)", disp);
cb += strlen((char*)&psymFake->name[cb + 1]);
}
else {
psymFake->name[++cb] = ')';
}
psymFake->name[0] = __min(cb, 255);
psymFake->reclen += psymFake->name[0] - psymTarget->name[0];
return &rgbThunkSym[0];
}