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

3995 lines
120 KiB
C++

// shsymbol
// Copyright <C> 1989-94, Microsoft Corporation
// [02] 31-dec-91 DavidGra
// Add Symbol support for assembler.
// [01] 02-dec-91 DavidGra
// Pass symbol to compare function when SSTR_symboltype bit
// is set only when its rectyp field is equal to the symtype
// field in the SSTR structure.
// [00] 15-nov-91 DavidGra
// Suppress hashing when the SSTR_NoHash bit it set.
// 10-Nov-94 BryanT
// Merge in NT changes.
// Replace SPRINTF with sprintf.
// Change SHAddrFromHsym to ignore S_BPREL16/S_BPREL32/S_REGREL32
// since the address w/o the stack/register context is useless.
// SHIsAddrInMod -> IsAddrInMod
// Change SHSetCxtMod to save the previous value in CxtCache so we
// can clear it when a process is removed.
// Change SHGetCxtFromHmod to test for actual code in the mod before
// setting the context.
// Add SHGetCxtFromHexe (basically iterate over every hmod and call
// SHGetCxtFromHmod until successful or out of hmods.
// Add thunks support to SHGetNearestHsym. Add default asserts in
// case something changes.
// Attempt to simplify the code in SHIsInProlog
// Provide a shortcut out of SHGoToParent
// Rewrite SHGethExeFromName to call SHGethExeFromExeName and
// SHGethExeFromAltName. Needed for multiple names in the kernel
// debugger
// Write SHGethExeFromModuleName
// Flesh out SHCompareRE
// Delete DOS compare routines used by the EE.
// Delete SHIsEmiLoaded (not needed any longer).
// Remove fChild arg from SHFindNameInContext (all users pass in FALSE)
// Remove SHIsOmfLocked tests (hLocked was never set)
// 07-Jan-96 BryanT
// Add in the MIPS changes Roger made for nested funcs *before* the parent proc.
#include "shinc.hpp"
#pragma hdrstop
LOCAL VOID CheckHandles (PCXT);
LOCAL PCXT SHSetBlksInCXT (PCXT);
// SHAddrFromHsym - Given a symbol get the offset and seg and return
// Purpose: This function will return the address of a symbol if it has an address.
// If there is no address for the symbol then the function returns FALSE.
// Input:
// paddr - Supplies the address structure to put the address in
// hsym - Supplies the handle to the symbol to get the address for.
// Returns:
// TRUE if the symbol has an address and FALSE if there is not
// address associated with the symbol.
BOOL SHAddrFromHsym (LPADDR paddr, HSYM hsym)
{
SYMPTR psym = (SYMPTR) hsym;
switch (psym->rectyp) {
case S_GPROC16:
case S_LPROC16:
case S_BLOCK16:
SE_SetAddrOff (paddr, ((PROCPTR16) psym)->off);
SetAddrSeg (paddr, ((PROCPTR16) psym)->seg);
ADDRSEG16 (*paddr);
break;
case S_LABEL16:
SE_SetAddrOff (paddr, ((LABELPTR16) psym)->off);
SetAddrSeg (paddr, ((LABELPTR16) psym)->seg);
ADDRSEG16 (*paddr);
break;
case S_THUNK16:
SE_SetAddrOff (paddr, ((THUNKPTR16) psym)->off);
SetAddrSeg (paddr, ((THUNKPTR16) psym)->seg);
ADDRSEG16 (*paddr);
break;
case S_WITH16:
SE_SetAddrOff (paddr, ((WITHPTR16) psym)->off);
SetAddrSeg (paddr, ((WITHPTR16) psym)->seg);
ADDRSEG16 (*paddr);
break;
case S_LDATA16:
case S_GDATA16:
case S_PUB16:
SE_SetAddrOff (paddr, ((DATAPTR16) psym)->off);
SetAddrSeg (paddr, ((DATAPTR16) psym)->seg);
ADDRSEG16 (*paddr);
break;
case S_GPROC32:
case S_LPROC32:
case S_BLOCK32:
SE_SetAddrOff (paddr, ((PROCPTR32) psym)->off);
SetAddrSeg (paddr, ((PROCPTR32) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_GPROCMIPS:
case S_LPROCMIPS:
SE_SetAddrOff (paddr, (((PROCPTRMIPS) psym)->off));
SetAddrSeg (paddr, ((PROCPTRMIPS) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_GPROCIA64:
case S_LPROCIA64:
SE_SetAddrOff (paddr, (((PROCPTRIA64) psym)->off));
SetAddrSeg (paddr, ((PROCPTRIA64) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_LABEL32:
SE_SetAddrOff (paddr, (((LABELPTR32) psym)->off));
SetAddrSeg (paddr, ((LABELPTR32) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_THUNK32:
SE_SetAddrOff (paddr, (((THUNKPTR32) psym)->off));
SetAddrSeg (paddr, ((THUNKPTR32) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_WITH32:
SE_SetAddrOff (paddr, (((WITHPTR32) psym)->off));
SetAddrSeg (paddr, ((WITHPTR32) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_PUB32:
case S_LDATA32:
case S_LTHREAD32:
case S_GDATA32:
case S_GTHREAD32:
SE_SetAddrOff (paddr, ((DATAPTR32) psym)->off);
SetAddrSeg (paddr, ((DATAPTR32) psym)->seg);
ADDRLIN32 (*paddr);
break;
case S_BPREL16:
case S_BPREL32:
case S_REGREL32: // UNDONE: Can we do better simply bailing here?
default:
return FALSE;
}
ADDR_IS_LI (*paddr) = TRUE;
return TRUE;
}
// SHGetNextMod
// Purpose: To sequence through the modules. Only unique module indexes
// are checked.
// Input:
// hMod The last module, if NULL a starting point is picked
// Returns:
// The next module (hMod) in the module change or NULL if at end.
HMOD SHGetNextMod (HEXE hexe, HMOD hmod)
{
SHWantSymbols(hexe);
return SHHmodGetNext (hexe, hmod);
}
PCXT SetModule (PADDR paddr, PCXT pcxt, HEXE hexe, HMOD hmod, HGRP hgrp)
{
memset(pcxt, 0, sizeof(CXT));
*SHpADDRFrompCXT(pcxt) = *paddr;
if (!emiAddr(*paddr)) {
SHpADDRFrompCXT(pcxt)->emi = (HEMI) hexe;
}
SHHMODFrompCXT(pcxt) = hmod;
SHHGRPFrompCXT(pcxt) = hgrp;
return pcxt;
}
BOOL IsAddrInMod (LPMDS lpmds, LPADDR lpaddr, ISECT* pisect, OFF* poff, CB* pcb)
{
int isgc;
// BUGBUG DBI needs 64 bit api
if (lpmds->pmod) {
DBI* pdbi;
Mod* pmodRet;
if (!ModQueryDBI(lpmds->pmod, &pdbi) || !DBIQueryModFromAddr(pdbi, (USHORT)GetAddrSeg (*lpaddr), (DWORD)GetAddrOff (*lpaddr), &pmodRet, pisect, poff, pcb))
return FALSE;
return (pmodRet == lpmds->pmod);
} else {
for (isgc = 0; isgc < (int) lpmds->csgc; isgc++) {
if (lpmds->lpsgc[isgc].seg == GetAddrSeg (*lpaddr) && lpmds->lpsgc[isgc].off <= GetAddrOff (*lpaddr) && GetAddrOff (*lpaddr) < lpmds->lpsgc[isgc].off + lpmds->lpsgc[isgc].cb) {
if (pisect)
*pisect = (ISECT)lpmds->lpsgc[isgc].seg;
if (poff)
*poff = lpmds->lpsgc[isgc].off;
if (pcb)
*pcb = lpmds->lpsgc[isgc].cb;
return TRUE;
}
}
}
return FALSE;
}
// SHSetCxtMod
// Purpose: To set the Mod and Group of a CXT
// Input:
// paddr - The address to find
// Output:
// pcxt - The point to the CXT to make.
// Returns:
// The pointer to the CXT, NULL if failure.
// Notes:
// The CXT must be all zero or be a valid CXT. Unpredictable results
// (possible GP) if the CXT has random data in it. If the CXT is valid
// the module pointed by it will be the first module searched.
// There are no changes to the CXT if a module couldn't be found
PCXT SHSetCxtMod (LPADDR paddr, PCXT pcxt)
{
// BUGBUG: Check with WesW about this. For some reason, he
// removed the Save variables in April/1994. I replaced the with
// a Cache arg that is cleared like all the other Cache args...
// Is this why he made the change?
// If we're still in the same pds/exe/seg/range, it's the same module...
if (CxtCache.hpds == hpdsCur &&
CxtCache.hexe == (HEXE)emiAddr(*paddr) &&
CxtCache.seg == (WORD)GetAddrSeg (*paddr) &&
CxtCache.uoffBase <= GetAddrOff (*paddr) &&
CxtCache.uoffLim > GetAddrOff (*paddr))
{
return SetModule (paddr, pcxt, CxtCache.hexe, CxtCache.hmod, CxtCache.hgrp);
} else if (GetAddrSeg(*paddr)) {
HMOD hmod = hmodNull;
HEXE hexe = hexeNull;
while (hexe = SHGetNextExe (hexe)) {
if (hexe == (HEXE) emiAddr (*paddr)) {
LPEXE lpexe = (LPEXE) LLLock (hexe);
LPEXG lpexg = (LPEXG) LLLock (lpexe->hexg);
if (lpexg->ppdb) {
Mod* pmod;
CB cb;
BOOL fTmp;
assert(lpexg->pdbi);
// BUGBUG DBI needs 64 bit api
if (DBIQueryModFromAddr(lpexg->pdbi, (USHORT)GetAddrSeg(*paddr), (DWORD)GetAddrOff(*paddr), &pmod, &CxtCache.seg, (OFF *)&CxtCache.uoffBase, &cb))
{
CxtCache.uoffLim = CxtCache.uoffBase + cb;
CxtCache.hpds = hpdsCur;
fTmp = ModGetPvClient(pmod, (void **)&CxtCache.hmod);
CxtCache.hgrp = CxtCache.hmod;
assert(fTmp);
CxtCache.hexe = hexe;
return SetModule (paddr, pcxt, CxtCache.hexe, CxtCache.hmod, CxtCache.hgrp);
}
} else {
LPSGD rgsgd = lpexg->lpsgd;
LLUnlock (lpexe->hexg);
LLUnlock (hexe);
if (rgsgd == NULL) {
return SetModule(paddr, pcxt, hexe, hmodNull, hmodNull);
} else if (GetAddrSeg (*paddr) <= lpexg->csgd) {
LPSGD lpsgd = &rgsgd [GetAddrSeg (*paddr) - 1];
WORD isge = 0;
for (isge = 0; isge < lpsgd->csge; isge++) {
LPSGE lpsge = &lpsgd->lpsge [isge];
if (lpsge->sgc.seg == GetAddrSeg (*paddr) && lpsge->sgc.off <= GetAddrOff (*paddr) && GetAddrOff (*paddr) < lpsge->sgc.off + lpsge->sgc.cb) {
CxtCache.hpds = hpdsCur;
CxtCache.hmod = lpsge->hmod;
CxtCache.hgrp = lpsge->hmod;
CxtCache.hexe = hexe;
CxtCache.seg = (WORD)GetAddrSeg (*paddr);
CxtCache.uoffBase = lpsge->sgc.off;
CxtCache.uoffLim = lpsge->sgc.off + lpsge->sgc.cb;
return SetModule (paddr, pcxt, CxtCache.hexe, CxtCache.hmod, CxtCache.hgrp);
}
}
}
}
}
}
}
// In case we don't get a context match anywhere, at least init the cxt
// structure (in case the caller forgets to test the return value).
return SetModule (paddr, pcxt, hexeNull, hmodNull, hmodNull);
}
// SHSetBlksInCXT
// Purpose: To update the CXT packet with Proc, and Blk information
// based on pCXT->addr. It is possible to have a Blk record without
// a Proc.
// The Procs or Blocks will inclose the pCXT->addr. Also a
// block will never inclose a Proc.
// The updating of the ctxt will be effecient. If the packet is already
// updated or partiallly updated, the search reduced or removed.
// Input:
// pcxt - A pointer to a CXT with a valid HMOD, HGRP and addr
// Output:
// pcxt - HPROC and HBLK are all updated.
// Returns .....
// pcxt on success or NULL on failure
// Notes: This is the core address to context routine! This particular
// routine should only be used by other routines in this module
// (i.e. remain static near!). The reason for this is so symbol
// lookup can change with easy modification to this module and
// not effecting other modules.
LOCAL PCXT SHSetBlksInCXT (PCXT pcxt)
{
SYMPTR psym;
SYMPTR psymEnd;
LPB lpstart;
LPMDS lpmds;
int fGo;
UOFFSET uoffCxt;
UOFFSET uoffT;
// determine if we can find anything
if (!(pcxt->hMod && pcxt->hGrp)) {
return NULL;
}
uoffCxt = GetAddrOff(pcxt->addr);
// get the module limits
lpmds = (LPMDS) pcxt->hGrp;
if (GetSymbols(lpmds)) {
lpstart = (LPB)(lpmds->symbols);
psym = (SYMPTR) ((LPB) lpmds->symbols + sizeof (long));
psymEnd = (SYMPTR) (((LPB) psym) + lpmds->cbSymbols - sizeof (long));
} else {
psym = psymEnd = NULL;
}
pcxt->hProc = NULL;
pcxt->hBlk = NULL;
if (psym >= psymEnd) {
return(pcxt);
}
// now search the symbol tables starting at psym for the correct block.
while (psym < psymEnd) {
switch (psym->rectyp) {
// check to make sure this address starts before the address
// of interest
case S_LPROC16:
case S_GPROC16:
if (((PROCPTR16)psym)->seg != GetAddrSeg(pcxt->addr) ||
((PROCPTR16)psym)->off > (CV_uoff16_t) uoffCxt ||
((PROCPTR16)psym)->off + ((PROCPTR16)psym)->len < (CV_uoff16_t) uoffCxt)
{
psym = (SYMPTR)(lpstart + ((PROCPTR16)psym)->pEnd);
} else {
pcxt->hProc = (HPROC) psym;
pcxt->hBlk = (HBLK)NULL;
}
break;
case S_BLOCK16:
if (((BLOCKPTR16)psym)->seg != GetAddrSeg(pcxt->addr) ||
((BLOCKPTR16)psym)->off > (CV_uoff16_t) uoffCxt ||
((BLOCKPTR16)psym)->off + ((BLOCKPTR16)psym)->len < (CV_uoff16_t) uoffCxt)
{
psym = (SYMPTR)(lpstart + ((BLOCKPTR16)psym)->pEnd);
} else {
pcxt->hBlk = (HBLK)psym;
}
break;
case S_WITH16:
if (((WITHPTR16)psym)->seg == GetAddrSeg(pcxt->addr)) {
// Withs and Entry are only interesting to keep our nesting correct.
if (((WITHPTR16)psym)->off > (CV_uoff16_t) uoffCxt) {
// offsets are too high. No sense continuing.
goto returnhere;
} else if (uoffCxt >= (UOFF32) ((WITHPTR16)psym)->off + ((WITHPTR16) psym)->len) {
psym = (SYMPTR)(lpstart + ((WITHPTR16)psym)->pEnd);
}
}
break;
case S_LPROC32:
case S_GPROC32:
uoffT = ((PROCPTR32)psym)->off;
if (((PROCPTR32)psym)->seg != GetAddrSeg(pcxt->addr) || uoffT > uoffCxt || (uoffT + ((PROCPTR32)psym)->len < uoffCxt))
{
// Wrong segment/too high/too low.
psym = (SYMPTR)(lpstart + ((PROCPTR32)psym)->pEnd);
} else {
// Right proc.
pcxt->hProc = (HPROC) psym;
pcxt->hBlk = (HBLK) NULL;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
assert(!"need code for SetBlksInCxt for IA64");
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if (((PROCPTRMIPS)psym)->seg != GetAddrSeg(pcxt->addr) || ((PROCPTRMIPS)psym)->off > uoffCxt) {
// No match. Look for the next symbol.
psym = (SYMPTR)(lpstart + ((PROCPTRMIPS)psym)->pEnd);
} else {
uoffT = ((PROCPTRMIPS)psym)->off;
if (uoffCxt < (uoffT + ((PROCPTRMIPS)psym)->len)) {
// The offset is before the end of the parents range.
if (uoffCxt >= uoffT) {
// And it's after the start of the parent proc... Must be right.
psymEnd = (SYMPTR) (lpstart + ((PROCPTRMIPS)psym)->pEnd);
// MIPS can have several local functions in a module (for exception
// filters, finally clauses, etc). Make sure we're looking at
// the right one.
if ((pcxt->hProc == NULL) && (uoffCxt > (uoffT + ((PROCPTRMIPS)psym)->DbgEnd)))
{
SYMPTR psymProc = NEXTSYM (SYMPTR, psym);
BOOL fFound = FALSE;
while (psymProc < psymEnd && !fFound) {
if (psymProc->rectyp == S_LPROCMIPS) {
uoffT = ((PROCPTRMIPS)psymProc)->off;
if ((uoffCxt >= uoffT) && (uoffCxt < (uoffT + ((PROCPTRMIPS)psymProc)->len))) {
psym = psymProc;
psymEnd = (SYMPTR) (lpstart + ((PROCPTRMIPS)psymProc)->pEnd);
if (uoffCxt <= uoffT + ((PROCPTRMIPS)psymProc)->DbgEnd) {
fFound = TRUE;
}
} else {
psymProc = (SYMPTR)(lpstart + ((PROCPTRMIPS)psym)->pEnd);
}
}
psymProc = NEXTSYM (SYMPTR, psymProc);
}
}
pcxt->hProc = (HPROC) psym;
pcxt->hBlk = (HBLK) NULL;
} else {
// Not within this proc. Myst be before it.
// search for nested procs which have offsets < parent.
SYMPTR psymProc = ((SYMPTR) (((LPB) (psym)) + ((SYMPTR) (psym))->reclen + 2));
SYMPTR psymEndT = (SYMPTR) (lpstart + ((PROCPTRMIPS)psym)->pEnd);
BOOL fFound = FALSE;
while (psymProc < psymEndT) {
if (S_LPROCMIPS == psymProc->rectyp ) {
unsigned long procLen = ((PROCPTRMIPS)psymProc)->len;
uoffT = ((PROCPTRMIPS)psymProc)->off;
if ((uoffCxt >= uoffT) && (uoffCxt < (uoffT + procLen)))
{
psymEnd = (SYMPTR) (lpstart + ((PROCPTRMIPS)psym)->pEnd);
psym = psymProc;
pcxt->hProc = (HPROC) psym;
pcxt->hBlk = (HBLK) NULL;
fFound = FALSE;
break;
}
}
psymProc = ((SYMPTR) (((LPB) (psymProc)) + ((SYMPTR) (psymProc))->reclen + 2)); // 2? Why 2? BryanT 1/7/96
}
if (fFound) {
psym = (SYMPTR)(lpstart + ((PROCPTRMIPS)psym)->pEnd);
}
}
} else {
// The offset is after this symbol's range.. Keep looking.
psym = (SYMPTR)(lpstart + ((PROCPTRMIPS)psym)->pEnd);
}
}
break;
case S_BLOCK32:
if (((BLOCKPTR32)psym)->seg != GetAddrSeg(pcxt->addr) || ((BLOCKPTR32)psym)->off > uoffCxt || ((BLOCKPTR32)psym)->off + ((BLOCKPTR32)psym)->len < uoffCxt)
{
psym = (SYMPTR)(lpstart + ((BLOCKPTR32)psym)->pEnd);
} else {
pcxt->hBlk = (HBLK)psym;
}
break;
case S_WITH32:
if (((WITHPTR32)psym)->seg == GetAddrSeg(pcxt->addr)) {
if (((WITHPTR32)psym)->off > uoffCxt) {
goto returnhere;
} else if (uoffCxt >= ((WITHPTR32)psym)->off + ((WITHPTR32) psym)->len) {
psym = (SYMPTR)(lpstart + ((WITHPTR32)psym)->pEnd);
}
}
break;
}
// get the next psym address
psym = NEXTSYM (SYMPTR, psym);
}
returnhere:
return pcxt;
}
// SHSetCxt
// Purpose: To set all field in a CXT to the represent the given address
// Input: pAddr -The address to set the CXT to.
// Output: pcxt -A pointer to the CXT to fill.
// Notes: The CXT must be all zero or be a valid CXT. Unpredictable results
// (possible GP) if the CXT has random data in it. If the CXT is valid
// the module pointed by it will be the first module searched.
// There are no changes to the CXT if a module couldn't be found
PCXT SHSetCxt(LPADDR paddr, PCXT pcxt)
{
// get the module part
if (SHSetCxtMod(paddr, pcxt)) {
SHSetBlksInCXT(pcxt);
return(pcxt);
}
return NULL;
}
// SHGetCxtFromHmod
// Purpose: To make a CXT from only an hmod
// Input: hmod - The module to make
// Output: pCXT - A pointer to a CXT to initialize to this hmod
// Returns: A pointer to the CXT or NULL on error.
PCXT
SHGetCxtFromHmod (
HMOD hmod,
PCXT pcxt
)
{
LPMDS lpmds = (LPMDS) hmod;
if (!hmod) {
return(NULL);
}
if (!lpmds->pmod && !lpmds->csgc) {
return(NULL);
}
HEXE hexe = SHHexeFromHmod(hmod);
// clear the CXT
memset(pcxt, 0, sizeof(CXT));
// set the module info
pcxt->hGrp = pcxt->hMod = hmod;
// put in the address
SetAddrFromMod(lpmds, &pcxt->addr);
emiAddr(pcxt->addr) = (HEMI) hexe;
ADDR_IS_LI(pcxt->addr) = TRUE;
// Set the fFlat and fOff32 bits based on the exe
{
HEXG hexg = ((LPEXE) LLLock(hexe))->hexg;
LLUnlock (hexe);
if (((LPEXG) LLLock (hexg))->fIsPE) {
// REVIEW - billjoy - should we check machine type or something?
ADDRLIN32 (pcxt->addr);
}
else {
// REVIEW - billjoy - should we check machine type or something?
//ADDR????
}
LLUnlock (hexg);
}
return(pcxt);
}
// SHGetCxtFromHexe
// Purpose: To make a CXT from only an hexe. The first hmod with code
// will be used.
// Input: hexe - A handle to the exe in question
// Output: pCXT - A pointer to a CXT to initialize to this hmod
// Returns: A pointer to the CXT or NULL on error
// Notes: This code depends on SHGetCxtFromHmod returning NULL if
// lpmds->csgc is zero.
PCXT
SHGetCxtFromHexe (
HEXE hexe,
PCXT pcxt
)
{
HMOD hmod;
PCXT pcxtRet = NULL;
if (hexe) {
hmod = (HMOD)NULL;
while (!pcxtRet && (hmod = SHGetNextMod(hexe, hmod))) {
pcxtRet = SHGetCxtFromHmod(hmod, pcxt);
}
}
return pcxtRet;
}
// SHGetNearestHsym
// Purpose: To find the closest label/proc to the specified address is
// found and put in pch. Both the symbol table and the
// publics tables are searched.
// Input:
// pctxt - a pointer to the context, address
// and mdi must be filled in.
// fIncludeData - If true, symbol type local will be included
// in the closest symbol search.
// Output:
// pch - The name is copied here.
// Returns .....
// The difference between the address and the symbol
//Notes: If CV_MAXOFFSET is returned, there is no closest symbol
// Also all symbols in the module are searched so only the
// ctxt.addr and ctxt.mdi have meaning.
UOFF32
SHGetNearestHsym (
LPADDR paddr,
HMOD hmod,
int mDataCode,
PHSYM phSym
)
{
LBS lbs;
CV_uoff32_t doff = (CV_uoff32_t)CV_MAXOFFSET;
CV_uoff32_t doffNew = (CV_uoff32_t)CV_MAXOFFSET;
SYMPTR psym;
// get the module to search
*phSym = NULL;
if (hmod) {
// at some point we may wish to specify only a scope to search for
// a label. So we may wish to initialize the lbs differently
// get the Labels
lbs.tagMod = hmod;
lbs.addr = *paddr;
SHpSymlplLabLoc(&lbs);
// check for closest data local, if requested
if (((mDataCode & EEDATA) == EEDATA) && lbs.tagLoc) {
psym = (SYMPTR) (LPB) lbs.tagLoc;
switch (psym->rectyp) {
case S_BPREL16:
doff = (DWORD)(GetAddrOff(lbs.addr) - ((BPRELPTR16)psym)->off);
break;
case S_BPREL32:
doff = (DWORD)(GetAddrOff(lbs.addr) - ((BPRELPTR32)psym)->off);
break;
case S_REGREL32:
doff = (DWORD)(GetAddrOff(lbs.addr) - ((LPREGREL32)psym)->off);
break;
default:
assert(FALSE);
break;
}
*phSym = (HSYM) lbs.tagLoc;
}
// check for closest label
if (((mDataCode & EECODE) == EECODE) && lbs.tagLab) {
psym = (SYMPTR) (LPB) lbs.tagLab;
switch (psym->rectyp) {
case S_LABEL16:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((LABELPTR16)psym)->off) <= (UOFFSET) doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - (UOFFSET)((LABELPTR16)psym)->off);
*phSym = (HSYM) lbs.tagLab;
}
break;
case S_LABEL32:
if ((UOFFSET) (GetAddrOff(lbs.addr) - (UOFFSET)((LABELPTR32)psym)->off) <= doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - (UOFFSET)((LABELPTR32)psym)->off);
*phSym = (HSYM) lbs.tagLab;
}
break;
default:
assert(FALSE);
break;
}
}
// If a thunk is closer
if (((mDataCode & EECODE) == EECODE) && lbs.tagThunk) {
psym = (SYMPTR) (LPB) lbs.tagThunk;
switch (psym->rectyp) {
case S_THUNK16:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((THUNKPTR16)psym)->off) <= (UOFFSET)doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - (UOFFSET)((THUNKPTR16)psym)->off);
*phSym = (HSYM) lbs.tagThunk;
}
break;
case S_THUNK32:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((THUNKPTR32)psym)->off) <= doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - (UOFFSET)((THUNKPTR32)psym)->off);
*phSym = (HSYM) lbs.tagThunk;
}
break;
default:
assert(FALSE);
break;
}
}
// if the proc name is closer
if (((mDataCode & EECODE) == EECODE) && lbs.tagProc) {
psym = (SYMPTR) (LPB) lbs.tagProc;
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((PROCPTR16)psym)->off) <= (UOFFSET)doff) {
doff = (DWORD)(GetAddrOff (lbs.addr) - ((PROCPTR16)psym)->off);
*phSym = (HSYM) lbs.tagProc;
}
break;
case S_LPROC32:
case S_GPROC32:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((PROCPTR32)psym)->off) <= doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - ((PROCPTR32)psym)->off);
*phSym = (HSYM) lbs.tagProc;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((PROCPTRIA64)psym)->off) <= doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - ((PROCPTRIA64)psym)->off);
*phSym = (HSYM) lbs.tagProc;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if ((GetAddrOff(lbs.addr) - (UOFFSET)((PROCPTRMIPS)psym)->off) <= doff) {
doff = (DWORD)(GetAddrOff(lbs.addr) - ((PROCPTRMIPS)psym)->off);
*phSym = (HSYM) lbs.tagProc;
}
break;
default:
assert(FALSE);
break;
}
}
}
return doff;
}
// SHIsInProlog
// Purpose: To determine if the addr is in prolog or epilog code of the proc
// Input:
// pCXT - The context describing the state. The address here is Linker index
// based
// Returns:
// TRUE if it is in prolog or epilog code
SHFLAG
SHIsInProlog (
PCXT pcxt
)
{
SYMPTR pProc;
UOFFSET CxtOffset, ProcOffset, ProcStart, ProcEnd, ProcLen;
if (pcxt->hProc == NULL) {
return FALSE;
}
if (!ADDR_IS_LI(*SHpADDRFrompCXT(pcxt))) {
SYUnFixupAddr(SHpADDRFrompCXT(pcxt));
}
pProc = (SYMPTR) pcxt->hProc;
CxtOffset = GetAddrOff(*SHpADDRFrompCXT(pcxt));
// check to see if not within the proc
switch (pProc->rectyp) {
case S_LPROC16:
case S_GPROC16:
ProcOffset =((PROCPTR16)pProc)->off;
ProcStart = ((PROCPTR16)pProc)->DbgStart;
ProcEnd = ((PROCPTR16)pProc)->DbgEnd;
ProcLen = ((PROCPTR16)pProc)->len;
break;
case S_LPROC32:
case S_GPROC32:
ProcOffset =((PROCPTR32)pProc)->off;
ProcStart = ((PROCPTR32)pProc)->DbgStart;
ProcEnd = ((PROCPTR32)pProc)->DbgEnd;
ProcLen = ((PROCPTR32)pProc)->len;
break;
case S_LPROCIA64:
case S_GPROCIA64:
ProcOffset =((PROCPTRIA64)pProc)->off;
ProcStart = ((PROCPTRIA64)pProc)->DbgStart;
ProcEnd = ((PROCPTRIA64)pProc)->DbgEnd;
ProcLen = ((PROCPTRIA64)pProc)->len;
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
ProcOffset =((PROCPTRMIPS)pProc)->off;
ProcStart = ((PROCPTRMIPS)pProc)->DbgStart;
ProcEnd = ((PROCPTRMIPS)pProc)->DbgEnd;
ProcLen = ((PROCPTRMIPS)pProc)->len;
break;
default:
assert(FALSE);
return(FALSE);
}
assert((ProcOffset <= CxtOffset) && ((ProcOffset + ProcLen) >= CxtOffset));
return ( ((ProcOffset + ProcStart) > CxtOffset) || // Before the start
(((ProcOffset + ProcEnd) < CxtOffset) && // or after the end?
((ProcOffset + ProcLen) > CxtOffset)));
}
// SHFindNameInContext
// Purpose: To look for the name at the scoping level specified by ctxt.
// Only the specified level is searched, children may be searched
// if fChild is set.
// This routine will assume the desired scope in the following
// way. If pcxt->hBlk != NULL, use hBlk as the starting scope.
// If hBlk == NULL and pcxt->hProc != NULL use the proc scope.
// If hBlk and hProc are both NULL and pcxt->hMod !=
// NULL, use the module as the scope.
// Input:
// hSym - The starting symbol, if NULL, then the first symbol
// in the context is used. (NULL is find first).
// pcxt - The context to do the search.
// lpsstr - pointer to the search parameters (passed to the compare routine)
// fCaseSensitive - TRUE/FALSE on a case sensitive search
// pfnCmp - A pointer to the comparison routine
// fChild - TRUE if all child block are to be searched, FALSE if
// only the current block is to be searched.
// Output:
// pcxtOut - The context generated
// Returns: A handle to the symbol found, NULL if not found
// Notes:
// If an hSym is specified, the hMod, hGrp and addr MUST be
// valid and consistant with each other! If hSym is NULL only
// the hMod must be valid. The specification of an hSym
// forces a search from the next symbol to the end of the
// module scope. Continues searches may only be done at
// module scope.
// If an hGrp is given it must be consistant with the hMod!
// The level at which hSym is nested (cNest) is not passed in
// to this function, so it must be derived. Since this
// could represent a significant speed hit, the level
// of the last symbol processed is cached. This should
// take care of most cases and avoid the otherwise
// necessary looping through all the previous symbols
// in the module on each call.
HSYM
SHFindNameInContext (
HSYM hSym,
PCXT pcxt,
LPSSTR lpsstr,
SHFLAG fCase,
PFNCMP pfnCmp,
PCXT pcxtOut
)
{
LPMDS lpmds;
HMOD hmod;
HEXE hexe;
SYMPTR lpsym;
SYMPTR lpEnd;
LPB lpstart;
ULONG cbSym;
int fSkip = FALSE;
if (!ADDR_IS_LI (pcxt->addr)) {
SYUnFixupAddr (&pcxt->addr);
}
memset(pcxtOut, 0, sizeof(CXT));
if (!pcxt->hMod) { // we must always have a module
return (HSYM) FindNameInStatics(hSym, pcxt, lpsstr, fCase, pfnCmp, pcxtOut);
}
hmod = pcxt->hGrp ? pcxt->hGrp : pcxt->hMod; // Initialize the module
lpmds = (LPMDS)hmod;
pcxtOut->hMod = pcxt->hMod;
pcxtOut->hGrp = pcxt->hGrp;
hexe = SHHexeFromHmod (hmod);
#if 0
// UNDONE: This needs to be fixed to handle X86 better. >=3 means
// all mptix86 and mptm68k are flaged as ADDRSEG16. Additionally,
// I changed SYProcessor to take a hpid (or NULL). The code in windbg
// and the VC ide s/b update before enabling this code. Finally, why
// is this interesting to do at all? The only time it will stick is if
// we bail from no symbols or an existing hsym..
lpexe = (LPEXE)LLLock(hexe);
hpds = lpexe->hpds;
lppds = (LPPDS)LLLock(hpds);
if (SYProcessor (lppds->hpid) >= 3) {
ADDRLIN32 (pcxtOut->addr);
} else {
ADDRSEG16 (pcxtOut->addr);
}
LLUnlock(hexe);
LLUnlock(hpds);
lpexe = NULL;
lppds = NULL;
#else
ADDRLIN32 (pcxtOut->addr);
#endif
SetAddrFromMod(lpmds, &pcxtOut->addr);
emiAddr (pcxtOut->addr) = (HEMI) hexe;
ADDR_IS_LI(pcxtOut->addr) = TRUE;
GetSymbols(lpmds);
cbSym = lpmds->cbSymbols;
if (cbSym == 0 || lpmds->symbols == NULL) {
return NULL;
}
// Search the symbol table.
lpstart = (LPB)(lpmds->symbols);
lpsym = (SYMPTR) ((LPB) (lpmds->symbols) + sizeof(long));
lpEnd = (SYMPTR) (((LPB) lpsym + cbSym) - sizeof(long));
// now find the start address. Always skip the current symbol because
// we don't want to pick up the same name over and over again
// if the user gives the start address
if (hSym != NULL) {
pcxtOut->hProc = (HPROC) pcxt->hProc;
pcxtOut->hBlk = (HBLK) pcxt->hBlk;
SetAddrOff (&pcxtOut->addr, GetAddrOff(pcxt->addr));
SetAddrSeg (&pcxtOut->addr, GetAddrSeg(pcxt->addr));
lpsym = (SYMPTR) hSym;
switch (lpsym->rectyp) {
case S_WITH16:
case S_BLOCK16:
case S_LPROC16:
case S_GPROC16:
case S_WITH32:
case S_BLOCK32:
case S_LPROC32:
case S_GPROC32:
case S_LPROCIA64:
case S_GPROCIA64:
case S_LPROCMIPS:
case S_GPROCMIPS:
lpsym = NEXTSYM(SYMPTR, (lpstart + ((PROCPTR)lpsym)->pEnd));
break;
default:
lpsym = NEXTSYM(SYMPTR, lpsym);
}
} else if (pcxt->hBlk != NULL) { // find the start address
SYMPTR lpbsp = (SYMPTR) pcxt->hBlk;
pcxtOut->hProc = pcxt->hProc;
pcxtOut->hBlk = pcxt->hBlk;
switch (lpbsp->rectyp) {
case S_BLOCK16:
SE_SetAddrOff (&pcxtOut->addr, ((BLOCKPTR16)lpbsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((BLOCKPTR16)lpbsp)->seg);
ADDRSEG16 (pcxtOut->addr);
break;
case S_BLOCK32:
SE_SetAddrOff (&pcxtOut->addr, ((BLOCKPTR32)lpbsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((BLOCKPTR32)lpbsp)->seg);
ADDRLIN32 (pcxtOut->addr);
break;
}
lpsym = NEXTSYM(SYMPTR, lpbsp);
lpEnd = (SYMPTR)(lpstart + ((BLOCKPTR16)lpbsp)->pEnd);
} else if (pcxt->hProc != NULL) {
// UNDONE: The NT code nuked this case (return NULL).
SYMPTR lppsp = (SYMPTR) pcxt->hProc;
switch (lppsp->rectyp) {
case S_LPROC16:
case S_GPROC16:
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTR16)lppsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTR16)lppsp)->seg);
ADDRSEG16 (pcxtOut->addr);
break;
case S_LPROC32:
case S_GPROC32:
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTR32)lppsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTR32)lppsp)->seg);
ADDRLIN32 (pcxtOut->addr);
break;
case S_LPROCIA64:
case S_GPROCIA64:
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTRIA64)lppsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTRIA64)lppsp)->seg);
ADDRLIN32 (pcxtOut->addr);
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTRMIPS)lppsp)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTRMIPS)lppsp)->seg);
ADDRLIN32 (pcxtOut->addr);
break;
}
pcxtOut->hProc = pcxt->hProc;
lpsym = NEXTSYM(SYMPTR, lppsp);
lpEnd = (SYMPTR)(lpstart + ((PROCPTR16)lppsp)->pEnd);
}
while (lpsym <lpEnd && ((lpsym->rectyp != S_END))) {
assert (lpsym->reclen != 0);
switch (lpsym->rectyp) {
case S_LABEL16:
SE_SetAddrOff (&pcxtOut->addr, ((LABELPTR16)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((LABELPTR16)lpsym)->seg);
ADDRSEG16 (pcxtOut->addr);
goto symname;
case S_LPROC16:
case S_GPROC16:
pcxtOut->hBlk = NULL;
pcxtOut->hProc = (HPROC) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTR16)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTR16)lpsym)->seg);
ADDRSEG16 (pcxtOut->addr);
goto entry16;
case S_BLOCK16:
pcxtOut->hBlk = (HBLK) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((BLOCKPTR16)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((BLOCKPTR16)lpsym)->seg);
ADDRSEG16 (pcxtOut->addr);
goto entry16;
case S_THUNK16:
case S_WITH16:
ADDRSEG16 (pcxtOut->addr);
entry16:
fSkip = TRUE;
// fall thru and process the symbol
case S_BPREL16:
case S_GDATA16:
case S_LDATA16:
ADDRSEG16 (pcxtOut->addr);
goto symname;
case S_LABEL32:
SE_SetAddrOff (&pcxtOut->addr, ((LABELPTR32)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((LABELPTR32)lpsym)->seg);
ADDRLIN32 (pcxtOut->addr);
goto symname;
case S_LPROC32:
case S_GPROC32:
pcxtOut->hBlk = NULL;
pcxtOut->hProc = (HPROC) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTR32)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTR32)lpsym)->seg);
ADDRLIN32 (pcxtOut->addr);
goto entry32;
case S_LPROCIA64:
case S_GPROCIA64:
pcxtOut->hBlk = NULL;
pcxtOut->hProc = (HPROC) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTRIA64)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTRIA64)lpsym)->seg);
ADDRLIN32 (pcxtOut->addr);
goto entry32;
case S_LPROCMIPS:
case S_GPROCMIPS:
pcxtOut->hBlk = NULL;
pcxtOut->hProc = (HPROC) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((PROCPTRMIPS)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((PROCPTRMIPS)lpsym)->seg);
ADDRLIN32 (pcxtOut->addr);
goto entry32;
case S_BLOCK32:
pcxtOut->hBlk = (HBLK) lpsym;
SE_SetAddrOff (&pcxtOut->addr, ((BLOCKPTR32)lpsym)->off);
SetAddrSeg (&pcxtOut->addr, (SEGMENT)((BLOCKPTR32)lpsym)->seg);
ADDRLIN32 (pcxtOut->addr);
goto entry32;
// fall thru to the entry case
case S_THUNK32:
case S_WITH32:
ADDRLIN32 (pcxtOut->addr);
entry32:
fSkip = TRUE;
// fall thru and process the symbol
case S_BPREL32:
case S_REGREL32:
case S_GDATA32:
case S_LDATA32:
case S_GTHREAD32:
case S_LTHREAD32:
ADDRLIN32 (pcxtOut->addr);
goto symname;
case S_REGISTER:
case S_CONSTANT:
case S_UDT:
case S_COBOLUDT:
case S_COMPILE:
symname:
if ((!(lpsstr->searchmask & SSTR_symboltype) ||
(lpsym->rectyp == lpsstr->symtype)
) &&
!(*pfnCmp)(lpsstr, lpsym, (LSZ) SHlszGetSymName (lpsym), fCase)
)
{
// save the sym pointer
lpsym = (SYMPTR) lpsym;
CheckHandles (pcxtOut);
return lpsym;
}
// up the scoping level
if (fSkip) {
// Make sure the compiler did the right thing
assert(((PROCPTR16)lpsym)->pEnd != 0);
lpsym = (SYMPTR)(lpstart + ((PROCPTR16)lpsym)->pEnd);
fSkip = FALSE;
}
break;
}
lpsym = NEXTSYM (SYMPTR, lpsym);
}
return NULL;
}
LOCAL VOID
CheckHandles (
PCXT pcxt
)
{
SYMPTR psym;
// check and restore all proc and blk handles
if (pcxt->hProc != NULL) {
psym = (SYMPTR) pcxt->hProc;
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16:
if ((GetAddrOff (pcxt->addr) < ((PROCPTR16)psym)->off) ||
GetAddrOff (pcxt->addr) >= (UOFF32) (((PROCPTR16)psym)->len +
((PROCPTR16)psym)->off))
{
pcxt->hProc = NULL;
}
break;
case S_LPROC32:
case S_GPROC32:
if ((GetAddrOff (pcxt->addr) < ((PROCPTR32)psym)->off) ||
GetAddrOff (pcxt->addr) >= (((PROCPTR32)psym)->len +
((PROCPTR32)psym)->off))
{
pcxt->hProc = NULL;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if ((GetAddrOff (pcxt->addr) < ((PROCPTRIA64)psym)->off) ||
GetAddrOff (pcxt->addr) >= (((PROCPTRIA64)psym)->len +
((PROCPTRIA64)psym)->off))
{
pcxt->hProc = NULL;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if ((GetAddrOff (pcxt->addr) < ((PROCPTRMIPS)psym)->off) ||
GetAddrOff (pcxt->addr) >= (((PROCPTRMIPS)psym)->len +
((PROCPTRMIPS)psym)->off))
{
pcxt->hProc = NULL;
}
break;
}
}
if (pcxt->hBlk != NULL) {
psym = (SYMPTR) pcxt->hBlk;
switch (psym->rectyp) {
case S_BLOCK16:
if ((GetAddrOff (pcxt->addr) < ((BLOCKPTR16)psym)->off) ||
GetAddrOff (pcxt->addr) >= (UOFF32)(((BLOCKPTR16)psym)->len +
((BLOCKPTR16)psym)->off))
{
pcxt->hBlk = NULL;
}
break;
case S_BLOCK32:
if ((GetAddrOff (pcxt->addr) < ((BLOCKPTR32)psym)->off) ||
GetAddrOff (pcxt->addr) >= (((BLOCKPTR32)psym)->len +
((BLOCKPTR32)psym)->off))
{
pcxt->hBlk = NULL;
}
break;
}
}
// now fill in the proper group
// because there is not (currently) a unique emi within a
// module, use the emi set in addr
pcxt->hGrp = pcxt->hMod;
}
// SHpSymctxtParent
// Purpose: To return a pointer to the parent block of the current blk or proc.
// The CXT is updated to the parent context. This may be a new block
// Proc or module.
// Input:
// pcxt - A pointer to the child CXT.
// Output:
// pcxtOut- an updated CXT to the parent.
// Returns .....
// - a Symbol point to the first record within the parent, this
// may be pcxt->hBlk, hProc, or
// pcxt->hMod->symbols + sizeof (long) or NULL if no parent.
HSYM
SHGoToParent (
PCXT pcxt,
PCXT pcxtOut
)
{
SYMPTR lpsym = NULL;
LPMDS lpmds;
SYMPTR lpsymT;
HSYM hsym;
LPB lpstart;
if (!pcxt->hMod) {
return NULL;
}
lpmds = (LPMDS)pcxt->hMod;
lpstart = (LPB) (lpmds->symbols);
lpsymT = (SYMPTR) ((LPB) lpmds->symbols + sizeof(long));
*pcxtOut = *pcxt;
// if the block is present, go to his parent
if (pcxt->hBlk != NULL) {
// If we are the parent, No further to go.
assert(pcxt->hBlk != pcxt->hProc);
// get lpsym upto the parent
lpsym = (SYMPTR) pcxt->hBlk;
lpsym = (SYMPTR)(lpstart + ((BLOCKPTR16)lpsym)->pParent);
pcxtOut->hBlk = NULL;
} else if (pcxt->hProc != NULL) {
// otherwise check the proc's parent, and go to his parent
lpsym = (SYMPTR) pcxt->hProc; // get lpsym upto the parent
lpsym = (SYMPTR)(lpstart + (((PROCPTR16)lpsym)->pParent));
pcxtOut->hProc = NULL;
} else {
// otherwise there is no parent
return NULL;
}
// if there is a parent, set the cxt packet.
if (lpsym != (SYMPTR) lpstart) {
switch(lpsym->rectyp) {
case S_LPROC16:
case S_GPROC16:
// case S_ENTRY:
case S_LPROC32:
case S_GPROC32:
case S_LPROCIA64:
case S_GPROCIA64:
case S_LPROCMIPS:
case S_GPROCMIPS:
// UNDONE: The NT code was changed to set pcxtOut->hBlk here... Why?
pcxtOut->hProc = (HPROC) lpsym;
break;
case S_BLOCK16:
case S_WITH16:
case S_BLOCK32:
case S_WITH32:
pcxtOut->hBlk = (HBLK) lpsym;
break;
default:
return NULL;
}
return lpsym;
} else {
// return the module as the parent
hsym = (HSYM) lpsymT;
return hsym;
}
}
// SHFindSLink32
// Purpose: To return a pointer to the SLINK32 for this proc
// Input:
// pcxt - A pointer to the child CXT.
// Returns .....
// - a Symbol point to the SLINK32 record
HSYM
SHFindSLink32 (
PCXT pcxt
)
{
SYMPTR lpsym = NULL;
LPMDS lpmds;
SYMPTR lpsymT;
if (!pcxt->hMod) {
return NULL;
}
lpmds = (LPMDS) pcxt->hMod;
lpsymT = (SYMPTR) ((LPB)lpmds->symbols + sizeof(long));
if (pcxt->hProc != NULL) {
lpsym = (SYMPTR) pcxt->hProc;
} else {
return NULL; // otherwise there is no SLINK32
}
lpsym = NEXTSYM(SYMPTR, lpsym);
for (; lpsym != NULL && lpsym->rectyp != S_SLINK32;) {
switch (lpsym->rectyp) {
case S_LPROC16:
case S_GPROC16:
case S_LPROC32:
case S_GPROC32:
// case S_ENTRY:
case S_LPROCIA64:
case S_GPROCIA64:
case S_LPROCMIPS:
case S_GPROCMIPS:
case S_BLOCK16:
case S_WITH16:
case S_BLOCK32:
case S_WITH32:
case S_END:
lpsym = NULL;
break;
case S_SLINK32:
break;
default:
lpsym = NEXTSYM(SYMPTR, lpsym);
break;
}
}
return lpsym;
}
// SHHsymFromPcxt
// Purpose: To get the inner most hSym given a context
// Input:
// pcxt - A pointer to a valid CXT.
// Returns:
// HSYM of the first symbol, or NULL on Error
// Notes: Used for procedure parameter walking
HSYM
SHHsymFromPcxt(
PCXT pcxt
)
{
HSYM hsym = NULL;
LPMDS lpmds;
if (pcxt->hMod) {
if (pcxt->hBlk) {
hsym = pcxt->hBlk;
} else if (pcxt->hProc) {
hsym = pcxt->hProc;
} else {
SYMPTR lpsymT;
// get the first symbol
lpmds = (LPMDS) pcxt->hMod;
lpsymT = (SYMPTR) ((LPB) GetSymbols (lpmds) + sizeof(long));
hsym = lpsymT;
}
}
return hsym;
}
// SHNextHsym
// Purpose: To get the next symbol in the table
// Input:
// hMod -A handle to the module containing the current hSym
// hSym -The current hSym
// Returns:
// The next hSym, or NULL if no more.
HSYM
SHNextHsym (
HMOD hmod,
HSYM hSym
)
{
SYMPTR lpsym;
SYMPTR lpsymStart;
ULONG cbSym;
LPMDS lpmds;
HSYM hsymRet = (HSYM)NULL;
SYMPTR lpsymT;
if (hmod) {
// only if the symbol is valid
// get module info
lpmds = (LPMDS) hmod;
lpsymT = (SYMPTR) ((LPB) GetSymbols (lpmds) + sizeof(long));
lpsymStart = (SYMPTR) lpsymT;
cbSym = lpmds->cbSymbols;
// give him the first symbol record
if (hSym == NULL) {
// if the current handle to symbol is null, return the first
// symbol. This is actually an error condition since we don't
// have an hSym to get the next from
hsymRet = (HSYM)lpsymStart;
} else {
// get info about the sym, and then skip it
lpsym = (SYMPTR) hSym;
lpsym = NEXTSYM(SYMPTR, lpsym);
// check to see if still in symbol range
lpsymStart = (SYMPTR) lpsymStart;
if (lpsymStart <= lpsym &&
lpsym < (SYMPTR) (((LPB) lpsymStart) + cbSym)) {
hsymRet = (HSYM) lpsym;
}
}
}
return hsymRet;
}
// SHIsAddrInCxt
// Purpose: To verify weather the address is within the context
// Input:
// pCXT - The context to check against
// pADDR - The address in question
// Returns:
// TRUE if within context, FALSE otherwise.
SHFLAG
SHIsAddrInCxt (
PCXT pcxt,
LPADDR paddr
)
{
HMOD hmod;
LPMDS lpmds;
SYMPTR psym;
SHFLAG shf = (SHFLAG)FALSE;
if ((pcxt != NULL) && (pcxt->hMod != 0)) {
// get the module
if (pcxt->hGrp != 0) {
hmod = pcxt->hGrp;
} else {
hmod = pcxt->hMod;
pcxt->hGrp = hmod;
}
lpmds = (LPMDS) hmod;
// The return value is true if these three conditions are all true:
// 1. The address is in the same executable as the context
// 2. The address is in the same module as the context
// 3. Any of the following are true:
// a. There is no block or proc so the address offset
// can be anywhere
// b. The address is in the offset range of the block of
// the context
// c. The addr is in the offset range of the procedure of
// the context
if (emiAddr (*paddr) != 0 &&
emiAddr (*paddr) != (HEMI) hpidCurr &&
emiAddr (*paddr) == (HEMI) SHHexeFromHmod (hmod)
) {
// condition 1 is true
if (IsAddrInMod (lpmds, paddr, NULL, NULL, NULL)) {
// condition 2 is true
if (pcxt->hProc == NULL && pcxt->hBlk == NULL) {
// condition 3a is true
shf = TRUE;
}
if (!shf && (psym = (SYMPTR) pcxt->hBlk) != NULL) {
// we have not passed test 3a and the block
// symbol handle is not null
switch (psym->rectyp) {
case S_BLOCK16:
if ((((UOFFSET)((BLOCKPTR16)psym)->off) <= GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFF32) (((BLOCKPTR16)psym)->off +
((BLOCKPTR16)psym)->len)))
{
// case 3b is true for a 16 bit block symbol
shf = TRUE;
}
break;
case S_BLOCK32:
if ((((BLOCKPTR32) psym)->off <= GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFFSET) (((BLOCKPTR32)psym)->off +
((BLOCKPTR32)psym)->len)))
{
// case 3b is true for a 32 bit block symbol
shf = TRUE;
}
break;
}
}
if ((shf == FALSE) && ((psym = (SYMPTR) pcxt->hProc) != NULL)) {
// we have not passed tests 3a or 3b and the proc
// symbol handle is not null
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16:
if ((((PROCPTR16)psym)->off <= (CV_uoff16_t) GetAddrOff(*paddr)) &&
(GetAddrOff (*paddr) < (UOFF32) (((PROCPTR16) psym)->off +
((PROCPTR16) psym)->len)))
{
// case 3c is true for a 16 bit proc symbol
shf = TRUE;
}
break;
case S_LPROC32:
case S_GPROC32:
if ((((PROCPTR32) psym)->off <= GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFFSET) (((PROCPTR32)psym)->off +
((PROCPTR32)psym)->len)))
{
// case 3b is true for a 32 bit proc symbol
shf = TRUE;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if ((((PROCPTRIA64) psym)->off <= GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFFSET) (((PROCPTRIA64)psym)->off +
((PROCPTRIA64)psym)->len)))
{
// case 3b is true for a 32 bit proc symbol
shf = TRUE;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if ((((PROCPTRMIPS) psym)->off <= GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFFSET) (((PROCPTRMIPS)psym)->off +
((PROCPTRMIPS)psym)->len)))
{
// case 3b is true for a 32 bit proc symbol
shf = TRUE;
}
break;
}
}
}
}
}
return(shf);
}
// SHGethExeFromAltName
// Purpose: To get an Exe handle given an alternate name
// Input: szPath - The path or filename of the exe
// Returns: A handle to the exe or NULL on error
HEXE
SHGethExeFromAltName(
LPTSTR AltName
)
{
HEXE hexe;
LPTSTR p;
hexe = SHGetNextExe (NULL);
while (hexe) {
p = SHGetModNameFromHexe(hexe);
if (p && (_tcsicmp(p, AltName) == 0)) {
return hexe;
}
hexe = SHGetNextExe(hexe);
}
return NULL;
}
// SHGethExeFromExeName
// Purpose: To get an Exe handle given an Exe name
// Input: szPath - The path or filename of the exe
// Returns: A handle to the exe or NULL on error
HEXE
SHGethExeFromExeName(
LPTSTR ExeName
)
{
HEXE hexe;
_TCHAR szOMFPath[_MAX_CVPATH];
_TCHAR szOMFFile[_MAX_CVFNAME];
_TCHAR szOMFExt[_MAX_CVEXT];
_TCHAR szName[_MAX_CVPATH];
_TCHAR szFile[_MAX_CVFNAME + 16];
_TCHAR szExt[_MAX_CVEXT];
DWORD i;
// BUGBUG: See the end of the file. This is the code from the VC shsymbol.c
// that's supposed to handle long file names.
if (!_tfullpath (szName, ExeName, sizeof (szName))) {
_tcscpy(szName, ExeName);
}
i = _tcslen(szName);
if (szName[i-1] == '.') {
szName[--i] = '\0';
}
_tsplitpath(szName, NULL, NULL, szFile, szExt);
if (!szExt[0] || !szExt[1]) {
szExt[0] = '\0';
}
for (hexe = SHGetNextExe((HEXE)NULL); hexe; hexe = SHGetNextExe(hexe)) {
_tcscpy(szOMFPath, SHGetExeName(hexe));
_tsplitpath(szOMFPath, NULL, NULL, szOMFFile, szOMFExt);
if (_tcsicmp(szOMFFile, szFile) != 0) {
_tcscpy(szOMFPath, SHGetModNameFromHexe(hexe));
_tsplitpath(szOMFPath, NULL, NULL, szOMFFile, szOMFExt);
}
if (_tcsicmp(szOMFFile, szFile) == 0) {
if (szExt[0]) {
if (_tcsicmp(szExt, szOMFExt) != 0) {
continue;
}
}
return hexe;
}
}
return NULL;
}
// SHGethExeFromName
// Purpose: To get an Exe handle given a name, or partial name
// Input:
// szPath - The path or filename of the exe
// Returns:
// A handle to the exe or NULL on error
HEXE
SHGethExeFromName (
LPTSTR ltszPath
)
{
HEXE hexe;
_TCHAR szAltPath[_MAX_CVPATH];
_TCHAR szOMFPath[_MAX_CVPATH];
LSZ lpch;
DWORD i;
LPTSTR p;
LPTSTR AltName = NULL;
if (!ltszPath || !(*ltszPath)) {
return((HEXE)NULL);
}
// Parse the input string. If it starts with a '|', assume this is the
// string from the DM. The first field is the image path. The 7th is the
// alternate name.
if (*ltszPath == '|') {
i = 0;
p = ltszPath;
while (p) {
p = _tcschr(p, '|');
if (p) {
i++;
p = _tcsinc(p);
if (i == 7) {
if (p && *p) {
AltName = p;
}
break;
}
}
}
if (AltName) {
_tcscpy(szAltPath, AltName);
p = _tcschr(szAltPath, '|');
if (p) {
*p = '\0';
}
}
_tcscpy(szOMFPath, &ltszPath[1]);
for (lpch = szOMFPath; (*lpch != 0) && (*lpch != '|'); lpch = _tcsinc(lpch));
*lpch = 0;
} else {
_tcscpy(szOMFPath, ltszPath);
}
if (AltName) {
hexe = SHGethExeFromAltName(szOMFPath);
return hexe;
}
hexe = SHGethExeFromExeName(szOMFPath);
if (!hexe) {
hexe = SHGethExeFromAltName(szOMFPath);
}
return(hexe);
}
// SHGethExeFromName
// Purpose: To get an Exe handle given a module name
// Input: lszModName - The module name to lookup
// Returns: A handle to the exe or NULL on error
HEXE
SHGethExeFromModuleName(
LSZ lszModName
)
{
HEXE hexe = NULL;
HEXG hexg;
LPEXG lpexg;
LPSTR lszmod;
while (hexe = SHGetNextExe(hexe)) {
hexg = ((LPEXE) LLLock (hexe))->hexg;
lpexg = (LPEXG) LLLock(hexg);
lszmod = lpexg->lszModule;
LLUnlock (hexe);
LLUnlock (hexg);
if (_tcsicmp(lszModName, lszmod) == 0) {
return hexe;
}
}
return NULL;
}
#define CSOURCESUFFIX 6
#define CBSOURCESUFFIX 4
static _TCHAR const * const rgszSourceSuffix[CSOURCESUFFIX] = {
(_TCHAR *) _T("**.C"),
(_TCHAR *) _T(".CPP"),
(_TCHAR *) _T(".CXX"),
(_TCHAR *) _T(".ASM"),
(_TCHAR *) _T(".BAS"),
(_TCHAR *) _T(".FOR")
};
// SHGetModName
// Purpose: To get an name handle given a module handle
// Input: hmod - the module handle
// Returns: A handle to the exe or NULL on error
// Notes: The return pointer is only valid until the call to this function
LSZ
SHGetModName (
HMOD hmod
)
{
// UNDONE: The NT code was modified to eliminate the static szMODName
// and replace it with a strdup of lsz before returning... Not sure what
// the answer is here (I suspect eliminating the static is the right idea,
// but the VC ide must be modified to free the pointer when it's done.
_TCHAR szFullPath[_MAX_CVPATH];
static _TCHAR szMODName[_MAX_CVPATH];
_TCHAR szExt[_MAX_CVEXT];
LPCH lpch;
LPMDS lpmds;
LSZ lsz = NULL;
WORD iFile;
_TCHAR * lpb;
WORD iSuffix;
_TCHAR * lpbSuffix;
BOOL fMatch;
if (!hmod) {
return NULL;
}
szFullPath [0] = '\0';
lpmds = (LPMDS) hmod;
assert (lpmds);
// Try to find a familiar source suffix
iFile = 0;
while (lpb = (_TCHAR *) SLNameFromHmod (hmod, (WORD)(iFile + 1))) {
lpbSuffix = lpb + *lpb + 1 - CBSOURCESUFFIX;
for (iSuffix = 0; iSuffix < CSOURCESUFFIX; iSuffix++) {
_TCHAR *lpbTest = lpbSuffix;
_TCHAR const * pbTest = rgszSourceSuffix [ iSuffix ];
fMatch = TRUE;
while (fMatch && *pbTest) {
switch (*pbTest) {
case '*':
break;
default:
if (('a'-'A') == (*lpbTest - *pbTest))
break;
case '.':
if (*lpbTest == *pbTest)
break;
fMatch = FALSE;
}
lpbTest = _tcsinc(lpbTest);
pbTest = _tcsinc(pbTest);
}
if (fMatch) {
break;
}
}
if (fMatch) {
memmove(szFullPath, lpb + 1, *(lpb));
szFullPath[*lpb] = 0;
break;
}
iFile++;
}
// As a last resort, use the module name from the omf
if (!szFullPath[0] && lpmds->name) {
_tcscpy (szFullPath, lpmds->name);
}
if (szFullPath[0]) {
// take off the source name
if (lpch = _tcschr ((LPCH) szFullPath, '(')) {
*lpch = '\0';
}
// extract the module name (it is in the form of a path)
_tsplitpath (szFullPath, NULL, NULL, szMODName, szExt);
lsz = szMODName;
}
return lsz;
}
// SHCmpGlobName
// Purpose: Given a name, and a global symbol, determine if they match
// Input: pSym - The symbol to compare against
// lpsstr - The name we're looking for
// pfnCmp - A function to call to do the compare
// fCase - TRUE if case is important, FALSE otherwise
// Returns: TRUE - The symbol matches
LOCAL BOOL
SHCmpGlobName (
SYMPTR pSym,
LPSSTR lpsstr,
PFNCMP pfnCmp,
SHFLAG fCase
)
{
BOOL fRet = FALSE;
switch (pSym->rectyp) {
default:
assert (FALSE); // Should Never be encountered
break;
case S_CONSTANT:
case S_GDATA16:
case S_GDATA32:
case S_GTHREAD32:
case S_UDT:
case S_COBOLUDT:
fRet = (!(lpsstr->searchmask & SSTR_symboltype) ||
(pSym->rectyp == lpsstr->symtype)) &&
!(*pfnCmp)(lpsstr, pSym, (LSZ) SHlszGetSymName(pSym), fCase);
// save the sym pointer
break;
}
return fRet;
}
// SHCompareRE
// Purpose: Compare a string (case preserving or not) to a regular expression
// and return true if the string is in the regex. Note, we only care
// about '*' and '?'.
// Input: pStr - The string to compare
// pRE - A regular expression string
// fCase - TRUE if case preserving, FALSE otherwise.
// Returns: 0 for match, non-0 for no match.
SHFLAG
SHCompareRE (
LPCH pStr,
LPCH pRE,
BOOL fCase
)
{
for (;;) {
switch (*pRE) {
case 0:
// End of the pattern:
if (*pStr == 0) {
return 0;
} else {
return 1;
}
case '?':
// Match anything except EOL
if (!*pStr) {
return 1;
} else {
pRE++;
pStr++;
break;
}
case '*':
// Match 0 or more of anything
pRE++;
do {
if (!SHCompareRE(pStr, pRE, fCase)) {
return 0;
}
} while (*pStr++);
return 1;
default:
if (fCase ? (*pRE != *pStr) : (tolower(*pRE) != tolower(*pStr))) {
return 1;
} else {
pRE++;
pStr++;
break;
}
}
}
}
// SHFindBpOrReg
// Purpose: Provide a place for SHGetSymbol to lookup a stack symbol.
// Input: the address of interest, item - the BPoffset or Register
// and which item we are searching for (S_REG S_BPREL)
// Output: The buffer rgbName is filled
// Returns TRUE FALSE if found
int
SHFindBpOrReg (
LPADDR paddr,
UOFFSET item,
WORD recLoc,
LPCH rgbName
)
{
// There is only one caller of this function... Can we optimize it?
SYMPTR psym;
SYMPTR pProc;
CXT cxt;
int fGo;
SHHMODFrompCXT (&cxt) = 0;
if (SHSetCxt (paddr, &cxt) == NULL) {
return (FALSE);
}
for (;;) {
fGo = FALSE;
if (SHHBLKFrompCXT(&cxt) != 0) {
fGo = TRUE;
} else if ((pProc = (SYMPTR) SHHPROCFrompCXT (&cxt)) != NULL) {
switch (pProc->rectyp) {
case S_LPROC16:
case S_GPROC16:
if (((((PROCPTR16)pProc)->off + (CV_uoff32_t)((PROCPTR16)pProc)->DbgStart) <=
GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (UOFF32)(((PROCPTR16)pProc)->off + ((PROCPTR16)pProc)->DbgEnd))) {
fGo = TRUE;
}
break;
case S_LPROC32:
case S_GPROC32:
if (((((PROCPTR32)pProc)->off + ((PROCPTR32)pProc)->DbgStart) <=
GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (((PROCPTR32)pProc)->off + ((PROCPTR32)pProc)->DbgEnd))) {
fGo = TRUE;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if (((((PROCPTRIA64)pProc)->off + ((PROCPTRIA64)pProc)->DbgStart) <=
GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (((PROCPTRIA64)pProc)->off + ((PROCPTRIA64)pProc)->DbgEnd))) {
fGo = TRUE;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if (((((PROCPTRMIPS)pProc)->off + ((PROCPTRMIPS)pProc)->DbgStart) <=
GetAddrOff (*paddr)) &&
(GetAddrOff (*paddr) < (((PROCPTRMIPS)pProc)->off + ((PROCPTRMIPS)pProc)->DbgEnd))) {
fGo = TRUE;
}
break;
}
}
if (fGo == FALSE) {
return (FALSE);
}
if (SHHBLKFrompCXT(&cxt)) {
psym = (SYMPTR) SHHBLKFrompCXT(&cxt);
} else if (SHHPROCFrompCXT(&cxt)) {
psym = (SYMPTR) SHHPROCFrompCXT(&cxt);
}
// skip block or proc record
psym = NEXTSYM (SYMPTR, psym);
fGo = TRUE;
while(fGo) {
switch (psym->rectyp) {
case S_REGISTER:
if ((recLoc == S_REGISTER) &&
((REGPTR)psym)->reg == (WORD)item) {
_tcsncpy (rgbName,
(_TCHAR *) &((REGPTR)psym)->name[1],
(BYTE)*(((REGPTR)psym)->name));
rgbName[(BYTE)*(((REGPTR)psym)->name)] = '\0';
return(TRUE);
}
break;
case S_END:
// terminate loop
fGo = FALSE;
break;
case S_LPROC16:
case S_GPROC16:
case S_BLOCK16:
// terminate loop
fGo = FALSE;
case S_BPREL16:
if ((recLoc == S_BPREL16) &&
((UOFFSET)((BPRELPTR16)psym)->off) == item) {
_tcsncpy (rgbName,
(_TCHAR *) &((BPRELPTR16)psym)->name[1],
(BYTE)*(((BPRELPTR16)psym)->name));
rgbName[(BYTE)*(((BPRELPTR16)psym)->name)] = '\0';
return(TRUE);
}
break;
case S_LPROC32:
case S_GPROC32:
case S_BLOCK32:
case S_LPROCIA64:
case S_GPROCIA64:
case S_LPROCMIPS:
case S_GPROCMIPS:
// terminate loop
fGo = FALSE;
case S_BPREL32:
if ((recLoc == S_BPREL32) &&
((UOFFSET)((BPRELPTR32)psym)->off) == item) {
_tcsncpy (rgbName,
(_TCHAR *) &((BPRELPTR32)psym)->name[1],
(BYTE)*(((BPRELPTR32)psym)->name));
rgbName[(BYTE)*(((BPRELPTR32)psym)->name)] = '\0';
return(TRUE);
}
break;
case S_REGREL32:
if ((recLoc == S_BPREL32) &&
((UOFFSET)((LPREGREL32)psym)->off) == item) {
_tcsncpy (rgbName,
(_TCHAR *) &((LPREGREL32)psym)->name[1],
(BYTE)*(((LPREGREL32)psym)->name));
rgbName[(BYTE)*(((LPREGREL32)psym)->name)] = '\0';
return(TRUE);
}
break;
case S_LABEL16:
case S_WITH16:
case S_LDATA16:
case S_GDATA16:
case S_LABEL32:
case S_WITH32:
case S_LDATA32:
case S_GDATA32:
case S_LTHREAD32:
case S_GTHREAD32:
case S_ENDARG:
case S_CONSTANT:
case S_UDT:
case S_COBOLUDT:
break;
default:
return(FALSE); // Bad SYMBOLS data
}
psym = NEXTSYM (SYMPTR, psym);
}
// get the parent block
SHGoToParent(&cxt, &cxt);
}
return (FALSE);
}
UOFFSET
SHGetDebugStart (
HSYM hsym
)
{
SYMPTR psym = (SYMPTR) hsym;
UOFFSET uoff = 0;
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16: {
PROCPTR16 psym = (PROCPTR16) hsym;
uoff = psym->off + psym->DbgStart;
}
break;
case S_LPROC32:
case S_GPROC32: {
PROCPTR32 psym = (PROCPTR32) hsym;
uoff = psym->off + psym->DbgStart;
}
break;
case S_LPROCIA64:
case S_GPROCIA64: {
PROCPTRIA64 psym = (PROCPTRIA64) hsym;
uoff = psym->off + psym->DbgStart;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS: {
PROCPTRMIPS psym = (PROCPTRMIPS) hsym;
uoff = psym->off + psym->DbgStart;
}
break;
default:
assert (FALSE);
}
return uoff;
}
LSZ
SHGetSymName (
HSYM hsym,
LSZ lsz
)
{
SYMPTR psym = (SYMPTR) hsym;
LPCH lst = NULL;
switch (psym->rectyp) {
case S_REGISTER:
lst = (LPCH)((REGPTR) psym)->name;
break;
case S_CONSTANT:
lst = (LPCH)((CONSTPTR) psym)->name;
break;
case S_BPREL16:
lst = (LPCH)((BPRELPTR16) psym)->name;
break;
case S_GDATA16:
case S_LDATA16:
lst = (LPCH)((DATAPTR16) psym)->name;
break;
case S_PUB16:
lst = (LPCH)((PUBPTR16) psym)->name;
break;
case S_LPROC16:
case S_GPROC16:
lst = (LPCH)((PROCPTR16) psym)->name;
break;
case S_THUNK16:
lst = (LPCH)((THUNKPTR16) psym)->name;
break;
case S_BLOCK16:
lst = (LPCH)((BLOCKPTR16) psym)->name;
break;
case S_LABEL16:
lst = (LPCH)((LABELPTR16) psym)->name;
break;
case S_BPREL32:
lst = (LPCH)((BPRELPTR32) psym)->name;
break;
case S_REGREL32:
lst = (LPCH)((LPREGREL32) psym)->name;
break;
case S_GDATA32:
case S_LDATA32:
case S_GTHREAD32:
case S_LTHREAD32:
lst = (LPCH)((DATAPTR32) psym)->name;
break;
case S_PUB32:
lst = (LPCH)((PUBPTR32) psym)->name;
break;
case S_LPROC32:
case S_GPROC32:
lst = (LPCH)((PROCPTR32) psym)->name;
break;
case S_LPROCIA64:
case S_GPROCIA64:
lst = (LPCH)((PROCPTRIA64) psym)->name;
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
lst = (LPCH)((PROCPTRMIPS) psym)->name;
break;
case S_THUNK32:
lst = (LPCH)((THUNKPTR32) psym)->name;
break;
case S_BLOCK32:
lst = (LPCH)((BLOCKPTR32) psym)->name;
break;
case S_LABEL32:
lst = (LPCH)((LABELPTR32) psym)->name;
break;
}
if (lst != NULL && *lst > 0) {
_tcsncpy (lsz, lst + 1, *lst);
*(lsz + *((CHAR *)lst)) = '\0';
return lsz;
} else {
return NULL;
}
}
BOOL
SHIsLabel (
HSYM hsym
)
{
BOOL fFound = FALSE;
SYMPTR psym = (SYMPTR) hsym;
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16:
case S_LABEL16:
case S_LPROC32:
case S_GPROC32:
case S_LABEL32:
case S_LPROCIA64:
case S_GPROCIA64:
case S_LPROCMIPS:
case S_GPROCMIPS:
fFound = TRUE;
break;
}
return fFound;
}
// SHAddressToLabel
// Purpose: To find the closest label/proc to the specified address is
// found and put in pch. Both the symbol table and the
// publics tables are searched.
// Input: paddr - Pointer to the address whose label is to be found
// Output: pch - The name is copied here.
// Returns: TRUE if a label was found.
BOOL
SHAddrToLabel(
LPADDR paddr,
LSZ lsz
)
{
CXT cxt;
SYMPTR psym;
LBS lbs;
// get the module to search
*lsz = '\0';
memset((LPV) &cxt, 0, sizeof(CXT));
memset((LPV) &lbs, 0, sizeof(lbs));
lbs.addr = *paddr;
SHSetCxt (paddr, &cxt);
if (!cxt.hMod) {
return(FALSE);
}
// Get the nearest local labels in this module
lbs.tagMod = cxt.hMod;
lbs.addr.emi = cxt.addr.emi;
SHpSymlplLabLoc (&lbs);
// Check the candidates found
if (lbs.tagLab) {
psym = (SYMPTR) lbs.tagLab;
switch (psym->rectyp) {
case S_LABEL16:
if (GetAddrOff (lbs.addr) == ((LABELPTR16)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((LABELPTR16)psym)->name[1]),
(BYTE)(((LABELPTR16)psym)->name[0]));
lsz[(BYTE)(((LABELPTR16)psym)->name[0])] = '\0';
return TRUE;
}
case S_LABEL32:
if (GetAddrOff (lbs.addr) == ((LABELPTR32)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((LABELPTR32)psym)->name[1]),
(BYTE)(((LABELPTR32)psym)->name[0]));
lsz[(BYTE)(((LABELPTR32)psym)->name[0])] = '\0';
return TRUE;
}
}
}
if (lbs.tagProc) {
psym = (SYMPTR) lbs.tagProc;
switch (psym->rectyp) {
case S_LPROC16:
case S_GPROC16:
if (GetAddrOff (lbs.addr) == ((PROCPTR16)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((PROCPTR16)psym)->name[1]),
(BYTE)(((PROCPTR16)psym)->name[0]));
lsz[(BYTE)(((PROCPTR16)psym)->name[0])] = '\0';
return(TRUE);
}
break;
case S_LPROC32:
case S_GPROC32:
if (GetAddrOff (lbs.addr) == ((PROCPTR32)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((PROCPTR32)psym)->name[1]),
(BYTE)(((PROCPTR32)psym)->name[0]));
lsz[(BYTE)(((PROCPTR32)psym)->name[0])] = '\0';
return(TRUE);
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if (GetAddrOff (lbs.addr) == ((PROCPTRIA64)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((PROCPTRIA64)psym)->name[1]),
(BYTE)(((PROCPTRIA64)psym)->name[0]));
lsz[(BYTE)(((PROCPTRIA64)psym)->name[0])] = '\0';
return(TRUE);
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if (GetAddrOff (lbs.addr) == ((PROCPTRMIPS)psym)->off) {
_tcsncpy(lsz,
(_TCHAR *)&(((PROCPTRMIPS)psym)->name[1]),
(BYTE)(((PROCPTRMIPS)psym)->name[0]));
lsz[(BYTE)(((PROCPTRMIPS)psym)->name[0])] = '\0';
return(TRUE);
}
break;
}
}
// now check the publics
if (!PHGetNearestHsym(SHpADDRFrompCXT(&cxt),
SHHexeFromHmod(SHHMODFrompCXT(&cxt)),
(PHSYM) &psym)) {
switch (psym->rectyp) {
case S_PUB16:
_tcsncpy(lsz,
(_TCHAR *)&(((DATAPTR16)psym)->name[1]),
(BYTE)(((DATAPTR16)psym)->name[0]));
lsz [(BYTE)(((DATAPTR16)psym)->name[0])] = '\0';
return(TRUE);
case S_PUB32:
_tcsncpy(lsz,
(_TCHAR *)&(((DATAPTR32)psym)->name[1]),
(BYTE)(((DATAPTR32)psym)->name[0]));
lsz [(BYTE)(((DATAPTR32)psym)->name[0])] = '\0';
return(TRUE);
}
}
return(FALSE);
}
BOOL
SHFIsAddrNonVirtual(
LPADDR paddr
)
{
ADDR addr = *paddr;
// If SYFixupAddr fails, it's because the address is virtual
// (unless something is seriously wrong)
return SYFixupAddr(&addr);
}
BOOL
SHIsEmiLoaded(
HEXE hexe
)
{
BOOL fReturn = ((LPEXE)(LLLock(hexe)))->fIsLoaded;
LLUnlock(hexe);
return (fReturn);
}
BOOL
SHIsFarProc (
HSYM hsym
)
{
BOOL fReturn = FALSE;
switch (((SYMPTR) hsym)->rectyp) {
case S_LPROC16:
case S_GPROC16:
fReturn = ((PROCPTR16) hsym)->flags.CV_PFLAG_FAR;
break;
case S_LPROC32:
case S_GPROC32:
fReturn = ((PROCPTR32) hsym)->flags.CV_PFLAG_FAR;
break;
case S_LPROCIA64:
case S_GPROCIA64:
fReturn = FALSE;
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
fReturn = FALSE;
break;
}
return fReturn;
}
char *M68KRegisterName[] =
{
"D0", // 0
"D1", // 1
"D2", // 2
"D3", // 3
"D4", // 4
"D5", // 5
"D6", // 6
"D7", // 7
"A0", // 8
"A1", // 9
"A2", // 10
"A3", // 11
"A4", // 12
"A5", // 13
"A6", // 14
"A7", // 15
"CCR", // 16
"SR", // 17
"USP", // 18
"MSP", // 19
"SFC", // 20
"DFC", // 21
"CACR", // 22
"VBR", // 23
"CAAR", // 24
"ISP", // 25
"PC", // 26
"reserved", // 27
"FPCR", // 28
"FPSR", // 29
"FPIAR", // 30
"reserved", // 31
"FP0", // 32
"FP1", // 33
"FP2", // 34
"FP3", // 35
"FP4", // 36
"FP5", // 37
"FP6", // 38
"FP7", // 39
NULL
};
char *X86RegisterName[] =
{
"NONE", // 0
"AL", // 1
"CL", // 2
"DL", // 3
"BL", // 4
"AH", // 5
"CH", // 6
"DH", // 7
"BH", // 8
"AX", // 9
"CX", // 10
"DX", // 11
"BX", // 12
"SP", // 13
"BP", // 14
"SI", // 15
"DI", // 16
"EAX", // 17
"ECX", // 18
"EDX", // 19
"EBX", // 20
"ESP", // 21
"EBP", // 22
"ESI", // 23
"EDI", // 24
"ES", // 25
"CS", // 26
"SS", // 27
"DS", // 28
"FS", // 29
"GS", // 30
"IP", // 31
"FLAGS", // 32
NULL
};
typedef struct _RegInfo {
WORD wIndex;
CHAR * szName;
} REGINFO;
typedef REGINFO * LPREGINFO;
REGINFO rgRegInfoPPC[] = {
// PowerPC General Registers (User Level)
{ CV_PPC_GPR0, "GPR0" },
{ CV_PPC_GPR1, "SP" },
{ CV_PPC_GPR2, "RTOC" },
{ CV_PPC_GPR3, "GPR3" },
{ CV_PPC_GPR4, "GPR4" },
{ CV_PPC_GPR5, "GPR5" },
{ CV_PPC_GPR6, "GPR6" },
{ CV_PPC_GPR7, "GPR7" },
{ CV_PPC_GPR8, "GPR8" },
{ CV_PPC_GPR9, "GPR9" },
{ CV_PPC_GPR10, "GPR10" },
{ CV_PPC_GPR11, "GPR11" },
{ CV_PPC_GPR12, "GPR12" },
{ CV_PPC_GPR13, "GPR13" },
{ CV_PPC_GPR14, "GPR14" },
{ CV_PPC_GPR15, "GPR15" },
{ CV_PPC_GPR16, "GPR16" },
{ CV_PPC_GPR17, "GPR17" },
{ CV_PPC_GPR18, "GPR18" },
{ CV_PPC_GPR19, "GPR19" },
{ CV_PPC_GPR20, "GPR20" },
{ CV_PPC_GPR21, "GPR21" },
{ CV_PPC_GPR22, "GPR22" },
{ CV_PPC_GPR23, "GPR23" },
{ CV_PPC_GPR24, "GPR24" },
{ CV_PPC_GPR25, "GPR25" },
{ CV_PPC_GPR26, "GPR26" },
{ CV_PPC_GPR27, "GPR27" },
{ CV_PPC_GPR28, "GPR28" },
{ CV_PPC_GPR29, "GPR29" },
{ CV_PPC_GPR30, "GPR30" },
{ CV_PPC_GPR31, "GPR31" },
// PowerPC Condition Register (User Level)
{ CV_PPC_CR, "CR" },
{ CV_PPC_CR0, "CR0" },
{ CV_PPC_CR1, "CR1" },
{ CV_PPC_CR2, "CR2" },
{ CV_PPC_CR3, "CR3" },
{ CV_PPC_CR4, "CR4" },
{ CV_PPC_CR5, "CR5" },
{ CV_PPC_CR6, "CR6" },
{ CV_PPC_CR7, "CR7" },
// PowerPC Floating Point Registers (User Level)
{ CV_PPC_FPR0, "FPR0" },
{ CV_PPC_FPR1, "FPR1" },
{ CV_PPC_FPR2, "FPR2" },
{ CV_PPC_FPR3, "FPR3" },
{ CV_PPC_FPR4, "FPR4" },
{ CV_PPC_FPR5, "FPR5" },
{ CV_PPC_FPR6, "FPR6" },
{ CV_PPC_FPR7, "FPR7" },
{ CV_PPC_FPR8, "FPR8" },
{ CV_PPC_FPR9, "FPR9" },
{ CV_PPC_FPR10, "FPR10" },
{ CV_PPC_FPR11, "FPR11" },
{ CV_PPC_FPR12, "FPR12" },
{ CV_PPC_FPR13, "FPR13" },
{ CV_PPC_FPR14, "FPR14" },
{ CV_PPC_FPR15, "FPR15" },
{ CV_PPC_FPR16, "FPR16" },
{ CV_PPC_FPR17, "FPR17" },
{ CV_PPC_FPR18, "FPR18" },
{ CV_PPC_FPR19, "FPR19" },
{ CV_PPC_FPR20, "FPR20" },
{ CV_PPC_FPR21, "FPR21" },
{ CV_PPC_FPR22, "FPR22" },
{ CV_PPC_FPR23, "FPR23" },
{ CV_PPC_FPR24, "FPR24" },
{ CV_PPC_FPR25, "FPR25" },
{ CV_PPC_FPR26, "FPR26" },
{ CV_PPC_FPR27, "FPR27" },
{ CV_PPC_FPR28, "FPR28" },
{ CV_PPC_FPR29, "FPR29" },
{ CV_PPC_FPR30, "FPR30" },
{ CV_PPC_FPR31, "FPR31" },
// PowerPC Floating Point Status and Control Register (User Level)
{ CV_PPC_FPSCR, "FPSCR" },
// PowerPC Machine State Register (Supervisor Level)
{ CV_PPC_MSR, "MSR" },
// PowerPC Segment Registers (Supervisor Level)
{ CV_PPC_SR0, "SR0" },
{ CV_PPC_SR1, "SR1" },
{ CV_PPC_SR2, "SR2" },
{ CV_PPC_SR3, "SR3" },
{ CV_PPC_SR4, "SR4" },
{ CV_PPC_SR5, "SR5" },
{ CV_PPC_SR6, "SR6" },
{ CV_PPC_SR7, "SR7" },
{ CV_PPC_SR8, "SR8" },
{ CV_PPC_SR9, "SR9" },
{ CV_PPC_SR10, "SR10" },
{ CV_PPC_SR11, "SR11" },
{ CV_PPC_SR12, "SR12" },
{ CV_PPC_SR13, "SR13" },
{ CV_PPC_SR14, "SR14" },
{ CV_PPC_SR15, "SR15" },
// For all of the special purpose registers add 100 to the SPR# that the
// Motorola/IBM documentation gives with the exception of any imaginary
// registers.
// PowerPC Special Purpose Registers (User Level)
{ CV_PPC_PC, "PC" }, // PC (imaginary register)
{ CV_PPC_MQ, "MQ" }, // MPC601
{ CV_PPC_XER, "XER" },
{ CV_PPC_RTCU, "RTCU" }, // MPC601
{ CV_PPC_RTCL, "RTCL" }, // MPC601
{ CV_PPC_LR, "LR" },
{ CV_PPC_CTR, "CTR" },
// PowerPC Special Purpose Registers (Supervisor Level)
{ CV_PPC_DSISR, "DSISR" },
{ CV_PPC_DAR, "DAR" },
{ CV_PPC_DEC, "DEC" },
{ CV_PPC_SDR1, "SDR1" },
{ CV_PPC_SRR0, "SRR0" },
{ CV_PPC_SRR1, "SRR1" },
{ CV_PPC_SPRG0, "SPRG0" },
{ CV_PPC_SPRG1, "SPRG1" },
{ CV_PPC_SPRG2, "SPRG2" },
{ CV_PPC_SPRG3, "SPRG3" },
{ CV_PPC_ASR, "ASR" }, // 64-bit implementations only
{ CV_PPC_EAR, "EAR" },
{ CV_PPC_PVR, "PVR" },
{ CV_PPC_BAT0U, "BAT0U" },
{ CV_PPC_BAT0L, "BAT0L" },
{ CV_PPC_BAT1U, "BAT1U" },
{ CV_PPC_BAT1L, "BAT1L" },
{ CV_PPC_BAT2U, "BAT2U" },
{ CV_PPC_BAT2L, "BAT2L" },
{ CV_PPC_BAT3U, "BAT3U" },
{ CV_PPC_BAT3L, "BAT3L" },
{ CV_PPC_DBAT0U, "DBAT0U" },
{ CV_PPC_DBAT0L, "DBAT0L" },
{ CV_PPC_DBAT1U, "DBAT1U" },
{ CV_PPC_DBAT1L, "DBAT1L" },
{ CV_PPC_DBAT2U, "DBAT2U" },
{ CV_PPC_DBAT2L, "DBAT2L" },
{ CV_PPC_DBAT3U, "DBAT3U" },
{ CV_PPC_DBAT3L, "DBAT3L" },
// PowerPC Special Purpose Registers Implementation Dependent (Supervisor Level)
// Doesn't appear that IBM/Motorola has finished defining these.
{ CV_PPC_PMR0, "PMR0" }, // MPC620
{ CV_PPC_PMR1, "PMR1" }, // MPC620
{ CV_PPC_PMR2, "PMR2" }, // MPC620
{ CV_PPC_PMR3, "PMR3" }, // MPC620
{ CV_PPC_PMR4, "PMR4" }, // MPC620
{ CV_PPC_PMR5, "PMR5" }, // MPC620
{ CV_PPC_PMR6, "PMR6" }, // MPC620
{ CV_PPC_PMR7, "PMR7" }, // MPC620
{ CV_PPC_PMR8, "PMR8" }, // MPC620
{ CV_PPC_PMR9, "PMR9" }, // MPC620
{ CV_PPC_PMR10, "PMR10" }, // MPC620
{ CV_PPC_PMR11, "PMR11" }, // MPC620
{ CV_PPC_PMR12, "PMR12" }, // MPC620
{ CV_PPC_PMR13, "PMR13" }, // MPC620
{ CV_PPC_PMR14, "PMR14" }, // MPC620
{ CV_PPC_PMR15, "PMR15" }, // MPC620
{ CV_PPC_DMISS, "DMISS" }, // MPC603
{ CV_PPC_DCMP, "DCMP" }, // MPC603
{ CV_PPC_HASH1, "HASH1" }, // MPC603
{ CV_PPC_HASH2, "HASH2" }, // MPC603
{ CV_PPC_IMISS, "IMISS" }, // MPC603
{ CV_PPC_ICMP, "ICMP" }, // MPC603
{ CV_PPC_RPA, "RPA" }, // MPC603
{ CV_PPC_HID0, "HID0" }, // MPC601, MPC603, MPC620
{ CV_PPC_HID1, "HID1" }, // MPC601
{ CV_PPC_HID2, "HID2" }, // MPC601, MPC603, MPC620 (IABR)
{ CV_PPC_HID3, "HID3" }, // Not Defined
{ CV_PPC_HID4, "HID4" }, // Not Defined
{ CV_PPC_HID5, "HID5" }, // MPC601, MPC604, MPC620 (DABR)
{ CV_PPC_HID6, "HID6" }, // Not Defined
{ CV_PPC_HID7, "HID7" }, // Not Defined
{ CV_PPC_HID8, "HID8" }, // MPC620 (BUSCSR)
{ CV_PPC_HID9, "HID9" }, // MPC620 (L2CSR)
{ CV_PPC_HID10, "HID10" }, // Not Defined
{ CV_PPC_HID11, "HID11" }, // Not Defined
{ CV_PPC_HID12, "HID12" }, // Not Defined
{ CV_PPC_HID13, "HID13" }, // MPC604 (HCR)
{ CV_PPC_HID14, "HID14" }, // Not Defined
{ CV_PPC_HID15, "HID15" } // MPC601, MPC604, MPC620 (PIR)
};
REGINFO rgRegInfoAlpha[] = {
{ CV_ALPHA_NOREG, "NOREG" },
{ CV_ALPHA_FltF0, "F0" },
{ CV_ALPHA_FltF1, "F1" },
{ CV_ALPHA_FltF2, "F2" },
{ CV_ALPHA_FltF3, "F3" },
{ CV_ALPHA_FltF4, "F4" },
{ CV_ALPHA_FltF5, "F5" },
{ CV_ALPHA_FltF6, "F6" },
{ CV_ALPHA_FltF7, "F7" },
{ CV_ALPHA_FltF8, "F8" },
{ CV_ALPHA_FltF9, "F9" },
{ CV_ALPHA_FltF10, "F10" },
{ CV_ALPHA_FltF11, "F11" },
{ CV_ALPHA_FltF12, "F12" },
{ CV_ALPHA_FltF13, "F13" },
{ CV_ALPHA_FltF14, "F14" },
{ CV_ALPHA_FltF15, "F15" },
{ CV_ALPHA_FltF16, "F16" },
{ CV_ALPHA_FltF17, "F17" },
{ CV_ALPHA_FltF18, "F18" },
{ CV_ALPHA_FltF19, "F19" },
{ CV_ALPHA_FltF20, "F20" },
{ CV_ALPHA_FltF21, "F21" },
{ CV_ALPHA_FltF22, "F22" },
{ CV_ALPHA_FltF23, "F23" },
{ CV_ALPHA_FltF24, "F24" },
{ CV_ALPHA_FltF25, "F25" },
{ CV_ALPHA_FltF26, "F26" },
{ CV_ALPHA_FltF27, "F27" },
{ CV_ALPHA_FltF28, "F28" },
{ CV_ALPHA_FltF29, "F29" },
{ CV_ALPHA_FltF30, "F30" },
{ CV_ALPHA_FltF31, "F31" },
{ CV_ALPHA_IntV0, "V0" },
{ CV_ALPHA_IntT0, "T0" },
{ CV_ALPHA_IntT1, "T1" },
{ CV_ALPHA_IntT2, "T2" },
{ CV_ALPHA_IntT3, "T3" },
{ CV_ALPHA_IntT4, "T4" },
{ CV_ALPHA_IntT5, "T5" },
{ CV_ALPHA_IntT6, "T6" },
{ CV_ALPHA_IntT7, "T7" },
{ CV_ALPHA_IntS0, "S0" },
{ CV_ALPHA_IntS1, "S1" },
{ CV_ALPHA_IntS2, "S2" },
{ CV_ALPHA_IntS3, "S3" },
{ CV_ALPHA_IntS4, "S4" },
{ CV_ALPHA_IntS5, "S5" },
{ CV_ALPHA_IntFP, "FP" },
{ CV_ALPHA_IntA0, "A0" },
{ CV_ALPHA_IntA1, "A1" },
{ CV_ALPHA_IntA2, "A2" },
{ CV_ALPHA_IntA3, "A3" },
{ CV_ALPHA_IntA4, "A4" },
{ CV_ALPHA_IntA5, "A5" },
{ CV_ALPHA_IntT8, "T8" },
{ CV_ALPHA_IntT9, "T9" },
{ CV_ALPHA_IntT10, "T10" },
{ CV_ALPHA_IntT11, "T11" },
{ CV_ALPHA_IntRA, "RA" },
{ CV_ALPHA_IntT12, "T12" },
{ CV_ALPHA_IntAT, "AT" },
{ CV_ALPHA_IntGP, "GP" },
{ CV_ALPHA_IntSP, "SP" },
{ CV_ALPHA_IntZERO, "ZERO" },
{ CV_ALPHA_Fpcr, "FPCR" },
{ CV_ALPHA_Fir, "FIR" },
{ CV_ALPHA_Psr, "PSR" },
{ CV_ALPHA_FltFsr, "FSR" },
};
INT __cdecl
RegInfoCmp (
const VOID * lpElem1,
const VOID * lpElem2
)
{
if (((LPREGINFO)lpElem1)->wIndex < ((LPREGINFO)lpElem2)->wIndex) {
return (-1);
} else if (((LPREGINFO)lpElem1)->wIndex > ((LPREGINFO)lpElem2)->wIndex) {
return (1);
} else {
return (0);
}
}
// SHGetSymLoc
// Input:
// hSym - A handle to the symbol to get a location.
// lsz - Where to write the result.
// cbMax - Size of lsz.
// pcxt - Context.
// Output:
// lsz filled in.
// Returns - The number of bytes written to the string.
// Notes: lpSym emspage must be loaded
int
SHGetSymLoc (
HSYM hsym,
LSZ lsz,
UINT cbMax,
PCXT pcxt
)
{
SYMPTR lpsym = (SYMPTR) hsym;
char rgch[20];
MPT TargetMachine;
if (cbMax == 0) {
return 0;
}
// What machine is this?
TargetMachine = GetTargetMachine();
memset(rgch, '\0', sizeof(rgch));
switch (lpsym->rectyp) {
case S_BPREL16:
if (((BPRELPTR16) lpsym)->off >= 0) {
sprintf(rgch, "[BP+%04X]", ((BPRELPTR16) lpsym)->off);
} else {
sprintf(rgch, "[BP-%04X]", - ((BPRELPTR16) lpsym)->off);
}
break;
case S_BPREL32:
{
long off = (long) ((BPRELPTR32) lpsym)->off;
char * szFMT;
char ch;
char * szBPREG;
switch (TargetMachine) {
case mptm68k:
szBPREG = "A6";
break;
case mptmppc:
szBPREG = "[SP]";
break;
default:
szBPREG = "EBP";
break;
}
if (off < 0) {
ch = '-';
off = -off;
} else {
ch = '+';
}
if (HIWORD(off)) {
szFMT = "[%s%c%08lX]";
} else {
szFMT = "[%s%c%04lX]";
}
sprintf(rgch, szFMT, szBPREG, ch, off);
}
break;
case S_REGREL32:
{
long off = (long) ((LPREGREL32) lpsym)->off;
short reg = ((LPREGREL32)lpsym)->reg;
char *lpch = rgch;
REGINFO regInfo;
LPREGINFO lpRegInfo;
char ch;
char *szFMT;
char *szRegName;
// UNDONE: Only Alpha really does this right. Fix the rest.
switch (TargetMachine) {
case mptdaxp:
regInfo.wIndex = reg;
lpRegInfo = (LPREGINFO) bsearch(&regInfo,
rgRegInfoAlpha,
sizeof (rgRegInfoAlpha) / sizeof (rgRegInfoAlpha[0]),
sizeof (rgRegInfoAlpha[0]),
&RegInfoCmp);
assert (lpRegInfo);
szRegName = lpRegInfo->szName;
break;
case mptia64:
assert("need code for IA64");
break;
case mptmips:
switch (reg) {
case CV_M4_IntSP:
szRegName = "SP";
break;
case CV_M4_IntS8:
szRegName = "S8";
break;
case CV_M4_IntGP:
szRegName = "GP";
break;
default:
szRegName = "REG";
break;
}
break;
default:
szRegName = "REG";
}
if (off < 0) {
ch = '-';
off = -off;
} else {
ch = '+';
}
if (HIWORD(off)) {
szFMT = "[%s%c%08lX]";
} else {
szFMT = "[%s%c%04lX]";
}
sprintf(lpch, szFMT, szRegName, ch, off);
}
break;
case S_REGISTER:
{
WORD iReg1, iReg2;
REGINFO regInfo;
LPREGINFO lpRegInfo;
// UNDONE: Again, I think Alpha is the only one to do it right...
switch (TargetMachine) {
case mptm68k:
iReg1 = (((REGPTR) lpsym)->reg) & 0x00ff;
_tcscpy (rgch, M68KRegisterName [iReg1]);
break;
case mptdaxp:
iReg1 = (((REGPTR) lpsym)->reg);
regInfo.wIndex = iReg1;
lpRegInfo = (LPREGINFO) bsearch (&regInfo,
rgRegInfoAlpha,
sizeof (rgRegInfoAlpha) / sizeof (rgRegInfoAlpha[0]),
sizeof (rgRegInfoAlpha[0]),
&RegInfoCmp);
assert (lpRegInfo);
_tcscpy (rgch, lpRegInfo->szName);
break;
case mptia64:
assert("need code for IA64");
break;
case mptmppc:
case mptntppc:
iReg1 = (((REGPTR) lpsym)->reg);
regInfo.wIndex = iReg1;
lpRegInfo = (LPREGINFO) bsearch (&regInfo,
rgRegInfoPPC,
sizeof (rgRegInfoPPC) / sizeof (rgRegInfoPPC[0]),
sizeof (rgRegInfoPPC[0]),
&RegInfoCmp);
assert (lpRegInfo);
_tcscpy (rgch, lpRegInfo->szName);
break;
case mptmips:
// UNDONE: Need to add the MIPS register definitions
rgch[0] = '\0';
break;
case mptix86:
iReg1 = (((REGPTR) lpsym)->reg) & 0x00ff;
iReg2 = ((((REGPTR)lpsym)->reg) >> 8) & 0x00ff;
rgch[0] = '\0';
if (iReg2) {
_tcscat (rgch, X86RegisterName [iReg2]);
_tcscat (rgch, ":");
}
_tcscat (rgch, X86RegisterName [iReg1]);
break;
}
_tcscat (rgch, " reg");
}
break;
case S_CONSTANT: {
HTYPE htype;
lfOEM * ptype;
htype = THGetTypeFromIndex (
SHHMODFrompCXT (pcxt),
((CONSTSYM *)lpsym)->typind
);
if (htype) {
ptype = (lfOEM *)MMLock ((HDEP)htype);
ptype = (lfOEM *)&(((TYPTYPE *)ptype)->leaf);
if (ptype->cvOEM != OEM_MS_FORTRAN90) {
_tcscpy (rgch, "constant");
}
MMUnlock ((HDEP) htype);
}
break;
}
case S_PUB16:
case S_LDATA16:
case S_GDATA16:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((DATAPTR16) lpsym)->seg);
SE_SetAddrOff (&addr, ((DATAPTR16) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
sprintf(rgch, "%04X:%04X", GetAddrSeg(addr), GetAddrOff(addr));
}
}
break;
case S_PUB32:
case S_LDATA32:
case S_GDATA32:
case S_LTHREAD32:
case S_GTHREAD32:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((DATAPTR32) lpsym)->seg);
SE_SetAddrOff (&addr, ((DATAPTR32) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
// REVIEW - billjoy - not necessarily ADDRLIN32. How do we tell?
ADDRLIN32 (addr);
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
if ((GetAddrSeg(addr) != 0) && (TargetMachine == mptm68k))
sprintf(rgch, "%04X:%08lX", GetAddrSeg(addr), GetAddrOff(addr));
else
sprintf(rgch, "%08lX", GetAddrOff(addr));
}
}
break;
case S_LPROC16:
case S_GPROC16:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((PROCPTR16) lpsym)->seg);
SE_SetAddrOff (&addr, ((PROCPTR16) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
sprintf(rgch, "%04X:%04X", GetAddrSeg(addr), GetAddrOff(addr));
}
}
break;
case S_LPROC32:
case S_GPROC32:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((PROCPTR32) lpsym)->seg);
SE_SetAddrOff (&addr, ((PROCPTR32) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
// REVIEW - billjoy - not necessarily ADDRLIN32. How do we tell?
ADDRLIN32 (addr);
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
if ((GetAddrSeg(addr) != 0) && (TargetMachine == mptm68k))
sprintf(rgch, "%04X:%08lX", GetAddrSeg(addr), GetAddrOff(addr));
else
sprintf(rgch, "%08lX", GetAddrOff(addr));
}
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((PROCPTRIA64) lpsym)->seg);
SE_SetAddrOff (&addr, ((PROCPTRIA64) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
// REVIEW - billjoy - not necessarily ADDRLIN32. How do we tell?
// Do we even care here (IA64)?
ADDRLIN32 (addr);
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
sprintf(rgch, "%16I64X", GetAddrOff(addr));
}
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
{
ADDR addr = {0};
assert (pcxt->hMod != 0);
SetAddrSeg (&addr, ((PROCPTRMIPS) lpsym)->seg);
SE_SetAddrOff (&addr, ((PROCPTRMIPS) lpsym)->off);
emiAddr (addr) = (HEMI) SHHexeFromHmod (pcxt->hMod);
ADDR_IS_LI (addr) = TRUE;
// REVIEW - billjoy - not necessarily ADDRLIN32. How do we tell?
// Do we even care here (MIPS)?
ADDRLIN32 (addr);
SYFixupAddr (&addr);
if (ADDR_IS_LI (addr) != TRUE) {
if ((GetAddrSeg(addr) != 0) && (TargetMachine == mptm68k))
sprintf(rgch, "%04X:%08lX", GetAddrSeg(addr), GetAddrOff(addr));
else
sprintf(rgch, "%08lX", GetAddrOff(addr));
}
}
break;
}
_tcsncpy (lsz, rgch, cbMax);
lsz[cbMax-1] = '\0'; // ensure that it's null-terminated
return _tcslen (lsz);
}
LPV
SHLpGSNGetTable(
HEXE hexe
)
{
LPB lpb = NULL;
HEXG hexg;
if (hexe) {
// Force symbols to be loaded now
SHWantSymbols(hexe);
hexg = ((LPEXE)LLLock(hexe))->hexg;
assert(hexg);
lpb = ((LPEXG)LLLock(hexg))->lpgsi;
LLUnlock(hexe);
LLUnlock(hexg);
}
return (LPV)lpb;
}
SHFLAG PHExactCmp (HVOID, HVOID, LSZ, SHFLAG);
HSYM
SHFindSymInExe (
HEXE hexe,
LPSSTR lpsstr,
BOOL fCaseSensitive
)
{
CXT cxt = { 0 };
CXT cxtOut = { 0 };
HSYM hsym = NULL;
cxt.hMod = 0;
// First search all of the modules in the exe
while (!hsym && (cxt.hMod = SHGetNextMod (hexe, cxt.hMod)) != 0)
{
hsym = SHFindNameInContext(NULL,
&cxt,
lpsstr,
fCaseSensitive,
PHExactCmp,
&cxtOut);
}
#pragma message("REVIEW: Should SHFindSymInExe call PHFindNameInPublics???")
#if 0
// UNDONE: Perhaps for NTSD support?
// This code is very expensive and yet has no effect!!!
// It ignores the HSYM which is returned by PHFindNameInPublics!
// I'm not sure which is the best fix -- putting "hsym ="
// in front of the call to PHFindNameInPublics, or disabling
// this code entirely. Since the old way seems to have
// works fine without causing any trouble, I'm going to
// just disable it for now. But this should be revisited.
// The name of this function (SHFindSymInExe) implies
// to the caller that it searches publics as well as other
// symbols. [mikemo]
if (!hsym) {
PHFindNameInPublics (
NULL,
hexe,
lpsstr,
fCaseSensitive,
PHExactCmp
);
}
#endif
return hsym;
}
BOOL
SHFindSymbol (
LSZ lsz,
PADDR lpaddr,
LPASR lpasr
)
{
ADDR addr = *lpaddr;
CXT cxt = {0};
CXT cxtOut = {0};
SSTR sstr = {0};
HSYM hsym = NULL;
HEXE hexe = hexeNull;
BOOL fCaseSensitive = TRUE;
// Get a context for the code address that was passed in
SYUnFixupAddr (&addr);
SHSetCxt (&addr, &cxt);
hexe = SHHexeFromHmod (cxt.hMod);
// Do an outward context search
sstr.lpName = (LPB) lsz;
sstr.cb = _tcslen (lsz);
// Search all of the blocks & procs outward
while ((cxt.hBlk || cxt.hProc) && !hsym) {
hsym = SHFindNameInContext(NULL,
&cxt,
&sstr,
fCaseSensitive,
PHExactCmp,
&cxtOut);
SHGoToParent (&cxt, &cxt);
}
if (!hsym) {
hsym = SHFindSymInExe (hexe, &sstr, fCaseSensitive);
}
if (!hsym) {
hexe = hexeNull;
while (!hsym && (hexe = SHGetNextExe (hexe))) {
hsym = SHFindSymInExe (hexe, &sstr, fCaseSensitive);
}
}
if (hsym) {
// Package up the symbol and send it back
switch (((SYMPTR) hsym)->rectyp) {
case S_REGISTER:
lpasr->ast = astRegister;
lpasr->ireg = ((REGPTR) hsym)->reg;
break;
case S_BPREL16:
lpasr->ast = astBaseOff;
lpasr->off = (LONG) ((BPRELPTR16) hsym)->off;
break;
case S_BPREL32:
lpasr->ast = astBaseOff;
lpasr->off = ((BPRELPTR32) hsym)->off;
break;
case S_REGREL32:
lpasr->ast = astBaseOff;
lpasr->off = ((LPREGREL32) hsym)->off;
break;
case S_LDATA16:
case S_LDATA32:
case S_LTHREAD32:
lpasr->fcd = fcdData;
goto setaddress;
case S_GPROC16:
case S_LPROC16:
lpasr->fcd =
(((PROCPTR16) hsym)->flags.CV_PFLAG_FAR) ?
fcdFar : fcdNear;
goto setaddress;
case S_GPROC32:
case S_LPROC32:
lpasr->fcd =
(((PROCPTR32) hsym)->flags.CV_PFLAG_FAR) ?
fcdFar : fcdNear;
goto setaddress;
case S_GPROCMIPS:
case S_LPROCMIPS:
lpasr->fcd = fcdNear;
goto setaddress;
case S_GPROCIA64:
case S_LPROCIA64:
lpasr->fcd = fcdNear;
goto setaddress;
case S_LABEL16:
case S_THUNK16:
case S_WITH16:
case S_PUB16:
case S_LABEL32:
case S_THUNK32:
case S_WITH32:
case S_PUB32:
lpasr->fcd = fcdUnknown;
setaddress:
lpasr->ast = astAddress;
SHAddrFromHsym (&lpasr->addr, hsym);
emiAddr (lpasr->addr) = (HEMI) hexe;
lpasr->addr.mode.fIsLI = TRUE;
SYFixupAddr (&lpasr->addr);
break;
default:
hsym = NULL;
break;
}
}
if (hsym) {
return TRUE;
} else {
// We didn't find anything so return false
lpasr->ast = astNone;
return FALSE;
}
}
void
SetAddrFromMod(
LPMDS lpmds,
UNALIGNED ADDR* paddr
)
{
if (lpmds->pmod) {
ISECT isect;
OFF off;
BOOL fTmp = ModQuerySecContrib(lpmds->pmod, &isect, &off, NULL, NULL);
assert(fTmp);
SetAddrSeg (paddr, isect);
SE_SetAddrOff (paddr, off);
} else {
SetAddrSeg (paddr, lpmds->lpsgc[0].seg);
SE_SetAddrOff (paddr, lpmds->lpsgc[0].off);
}
}
LPVOID
SHGetDebugData(
HEXE hexe
)
{
// UNDONE: Why make the copy the debugData? BryanT - Still to resolve.
LPDEBUGDATA lpd = NULL;
if (hexe) {
LPEXE lpexe = (LPEXE) LLLock(hexe);
// If symbols are not yet loaded -- force them to load now
SHWantSymbols(hexe);
if (!lpexe->pDebugData) {
HEXG hexg;
LPEXG lpexg;
hexg = ((LPEXE)LLLock(hexe))->hexg;
assert(hexg);
lpexg = (LPEXG)LLLock(hexg);
// This is the first time the debug data was requested. Fix it up appropriately
if (lpexe->LoadAddress == lpexg->LoadAddress) {
// The address for the first image is the same as the load address.
// Nothing else to do.
lpexe->pDebugData = &lpexg->debugData;
} else {
if (lpexg->fIsRisc) {
DWORD size;
DWORD dwSizRTFEntry;
switch (lpexg->machine) {
case IMAGE_FILE_MACHINE_ALPHA:
dwSizRTFEntry = sizeof(IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY);
break;
case IMAGE_FILE_MACHINE_ALPHA64:
dwSizRTFEntry = sizeof(IMAGE_AXP64_RUNTIME_FUNCTION_ENTRY);
break;
case IMAGE_FILE_MACHINE_IA64:
dwSizRTFEntry = sizeof(IMAGE_IA64_RUNTIME_FUNCTION_ENTRY);
break;
default:
assert(!"Unsupported platform");
break;
}
lpexe->pDebugData = (LPDEBUGDATA) MHAlloc(sizeof(DEBUGDATA));
*lpexe->pDebugData = lpexg->debugData;
size = lpexe->pDebugData->cRtf * dwSizRTFEntry;;
lpexe->pDebugData->lpRtf = MHAlloc(size);
memmove(lpexe->pDebugData->lpRtf, lpexg->debugData.lpRtf, size);
// Fix up any pdata for functions that have moved.
ULONG index;
UOFFSET diff = lpexe->LoadAddress - lpexg->LoadAddress;
PVOID rf = lpexe->pDebugData->lpRtf;
lpexe->pDebugData->lpOriginalRtf = (PBYTE)lpexe->pDebugData->lpOriginalRtf + diff;
switch (lpexg->machine) {
case IMAGE_FILE_MACHINE_ALPHA:
for (index=0; index < lpexe->pDebugData->cRtf; index++) {
((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)rf)[index].BeginAddress += (DWORD)diff;
((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)rf)[index].EndAddress += (DWORD)diff;
((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)rf)[index].PrologEndAddress += (DWORD)diff;
}
break;
case IMAGE_FILE_MACHINE_ALPHA64:
for (index=0; index < lpexe->pDebugData->cRtf; index++) {
((PIMAGE_AXP64_RUNTIME_FUNCTION_ENTRY)rf)[index].BeginAddress += diff;
((PIMAGE_AXP64_RUNTIME_FUNCTION_ENTRY)rf)[index].EndAddress += diff;
((PIMAGE_AXP64_RUNTIME_FUNCTION_ENTRY)rf)[index].PrologEndAddress += diff;
}
break;
case IMAGE_FILE_MACHINE_IA64:
break;
default:
assert(!"Unsupported platform");
break;
}
} else {
lpexe->pDebugData = &lpexg->debugData;
}
}
// Make sure the machine field is set correctly
lpexe->pDebugData->machine = lpexg->machine;
LLUnlock(hexg);
}
//lpd = (LPDEBUGDATA) MHAlloc(sizeof (*lpd));
//assert(lpd);
//if (lpd != NULL) {
//*lpd = *lpexe->pDebugData;
//}
lpd = lpexe->pDebugData;
LLUnlock(hexe);
}
return (LPVOID)lpd;
}
BOOL
SHIsThunk(
HSYM hsym
)
{
SYMPTR psym = (SYMPTR) hsym;
return (psym->rectyp == S_THUNK16 || psym->rectyp == S_THUNK32);
}
#if 0
// VC 4.1 shsymbol.c version. Changed to 2 passes to support long file names
// Merge into the above code once you understand the implications...
// BryanT 1-19-96
/*** SHGethExeFromName
*
* Purpose: To get an Exe handle given a name, or partial name
*
* Input:
* szPath - The path or filename of the exe
*
* Returns:
* A handle to the exe or NULL on error
*/
HEXE LOADDS PASCAL SHGethExeFromName ( LPTSTR ltszPath ) {
HEXE hexe;
HEXE hexeEnd;
HEXE hexeMatch = (HEXE)NULL;
CHAR * szOMFPath;
CHAR szOMFFile[_MAX_CVFNAME];
CHAR szOMFExt[_MAX_CVEXT];
CHAR szName[_MAX_CVPATH];
CHAR szFile[_MAX_CVFNAME];
CHAR szExt[_MAX_CVEXT];
int iNameEnd;
LPTSTR lptchEnd = NULL;
int iPass;
WIN32_FIND_DATA wfd;
// get the start of the exe list, or return an error if we can't get one
if( !ltszPath || !(*ltszPath) ||
!(hexe = hexeEnd = SHGetNextExe ( (HEXE)NULL )) ) {
return( (HEXE)NULL );
}
/*
* Does this module come with a file handle attached to it? If so,
* copy the path into the buffer where the path is to go and get
* the full path name for the file.
*/
if (*ltszPath == '|') {
ltszPath++;
lptchEnd = _ftcschr(ltszPath, '|');
assert(lptchEnd);
if (lptchEnd)
*lptchEnd = '\0';
}
// split it to the root name and extension
SHSplitPath ( ltszPath, NULL, NULL, szFile, szExt );
if ( !szExt[0] || !szExt[1] ) {
szExt[0] = '\0';
}
// we haven't yet determined the full path of the input name
szName[0] = '\0';
// Make two passes thru the exes - the second pass checks for matching
// alternate (long vs 8.3) names
for (iPass=0; iPass < 2; iPass++)
{
if (iPass == 1)
{
if ( !_tfullpath ( szName, ltszPath, sizeof ( szName ) ) ) {
return( (HEXE)NULL );
}
if (FindFirstFile(szName, &wfd) != INVALID_HANDLE_VALUE)
{
// If the long and short names are identical, don't bother with
// this extra pass
if ( !_ftcsicmp ( wfd.cFileName, wfd.cAlternateFileName )) {
goto exit;
}
SHSplitPath( wfd.cFileName, NULL, NULL, szFile, szExt);
}
else
{
// can't just return NULL here (hexeMatch may be set)
goto exit;
}
// Reset the iteration mechanism to the first exe
hexe = SHGetNextExe ( (HEXE)NULL );
}
do {
// get the full exe name
// WARNING: this assumes pointers are the same as handles!!!
szOMFPath = SHGetExeName( hexe );
// get the extension
SHSplitPath ( szOMFPath, NULL, NULL, szOMFFile, szOMFExt );
// check for match
if ( !_ftcsicmp ( szOMFFile, szFile ) && !_ftcsicmp ( szOMFExt, szExt )) {
// if we haven't done _tfullpath yet, do it now
if (szName[0] == '\0') {
if ( !_tfullpath ( szName, ltszPath, sizeof ( szName ) ) ) {
return( (HEXE)NULL );
}
iNameEnd = _ftcslen(szName);
if( *_ftcsdec( szName, &szName[iNameEnd] ) == '.' ) {
szName[--iNameEnd] = '\0';
}
}
// check for exact match, need the full path, but we know
// exe names are stored as full paths so szOMFPath is a full path
// if no extension, put the current extension on
if ( !szExt[0] && szOMFExt[0] ) {
_ftcscpy(szName + iNameEnd, szOMFExt);
}
// see if these are the same
if ( !_ftcsicmp( szOMFPath, szName ) ) {
hexeMatch = hexe;
goto exit;
}
if ( !szExt[0] ) {
szName[iNameEnd] = '\0';
}
// save away the first potential match
if( !hexeMatch ) {
hexeMatch = hexe;
}
}
} while ( hexe = SHGetNextExe ( hexe ) );
}
exit:
// restore '|'
if (lptchEnd)
*lptchEnd = '|';
return(hexeMatch);
}
#endif