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.
1033 lines
24 KiB
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];
|
|
}
|