3995 lines
120 KiB
C++
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, <szPath[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(®Info,
|
|
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 (®Info,
|
|
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 (®Info,
|
|
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
|