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

569 lines
22 KiB
C++

// SHsymlb0.c - general library routines to find an omff symbol by name or address.
// Copyright <C> 1988-94, Microsoft Corporation
// Purpose: To supply a concise interface to the debug omf for symbols
// 10-Nov-94 BryanT
// Merge in NT changes.
// SHIsAddrInMod -> IsAddrInMod
// Delete SHszDir/SHszDrive/SHszDebuggeeDrive/SHszDebuggeeDir. Not used
// Make SHSetDebuggeeDir a shell since there is no usage for the dir.
// Delete special case Mac targeting S_CEXMODEL32 handling.
// Remove ems code from SHpSymlplLabLoc.
// Add support for S_THUNK16/S_THUNK32 in SHpSymlplLabLoc.
// Replace local statics with a Cache entry.
// Remove SHModelFromCxt (no callers and not exposed).
#include "shinc.hpp"
#pragma hdrstop
// fundamental source line lookup routines
VOID SHSetDebuggeeDir (LSZ lszDir)
{
// Functionality not used any longer.
}
// SHpSymlplLabLoc
// Purpose: To completely fill in a plpl pkt. The hmod and addr must already
// be valid. The locals and labels are searched based on paddr. The
// whole module is search for now. Better decisions may be made in the future.
// Input:
// plpl - lpl packet with a valid module and address in it.
// Output:
// plpl - Is updated with Proc, Local, and Label.
// Notes: This includes locals and lables
VOID SHpSymlplLabLoc (LPLBS lplbs)
{
SYMPTR lpSym = NULL;
SYMPTR lpSymEnd;
LPMDS lpmds;
ULONG cbMod = 0;
CV_uoff32_t obModelMin = 0;
CV_uoff32_t obModelMax = CV_MAXOFFSET;
CV_uoff32_t obTarget;
CV_uoff32_t doffNew;
CV_uoff32_t doffOld;
// for now we are doing the whole module
lplbs->tagLoc = NULL;
lplbs->tagLab = NULL;
lplbs->tagProc = NULL;
lplbs->tagThunk = NULL;
lplbs->tagModelMin = NULL;
lplbs->tagModelMax = NULL;
if (!lplbs->tagMod) {
return;
}
// because segments of locals don't have to match the segment of the
// searched module, check segment here is wrong. However we can set
// a flag up for proc and labels
lpmds = (LPMDS) lplbs->tagMod;
obTarget = (CV_uoff32_t)GetAddrOff (lplbs->addr);
// add/subtract the size of the hash table ptr
lpSym = (SYMPTR) ((LPB) GetSymbols (lpmds) + sizeof(long));
cbMod = lpmds->cbSymbols;
lpSymEnd = (SYMPTR) ((BYTE *) lpSym + cbMod - sizeof (long));
while(lpSym < lpSymEnd) {
switch(lpSym->rectyp) {
case S_CEXMODEL16:
if (((WORD)(((CEXMPTR16)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr))) {
CV_uoff32_t obTemp = (CV_uoff32_t)(((CEXMPTR16)lpSym)->off);
if (obTemp <= obModelMax) {
if (obTemp > obTarget) {
lplbs->tagModelMax = (CEXMPTR16)lpSym;
obModelMax = obTemp;
}
else if (obTemp >= obModelMin) {
lplbs->tagModelMin = (CEXMPTR16)lpSym;
obModelMin = obTemp;
}
}
}
break;
case S_LPROC16:
case S_GPROC16:
if (((WORD)(((PROCPTR16)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((PROCPTR16)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((PROCPTR16)lpSym)->off) + (CV_uoff32_t)(((PROCPTR16)lpSym)->len)))) {
lplbs->tagProc = (SYMPTR)lpSym;
}
break;
case S_LABEL16:
if (((WORD)(((LABELPTR16)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) && (((CV_uoff32_t)((LABELPTR16)lpSym)->off) <= obTarget)) {
doffNew = obTarget - (CV_uoff32_t)(((LABELPTR16)lpSym)->off);
// calculate what the old offset was, this requires no
// use of static variables
doffOld = obTarget;
if (lplbs->tagLab) {
doffOld -= (CV_uoff32_t)(((LABELPTR16)lplbs->tagLab)->off);
}
if (doffNew <= doffOld) {
lplbs->tagLab = (SYMPTR)lpSym;
}
}
break;
case S_LDATA16:
case S_GDATA16:
if (((WORD)(((DATAPTR16)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) && ((CV_uoff32_t)(((DATAPTR16)lpSym)->off) <= obTarget)) {
doffNew = obTarget - (CV_uoff32_t)(((DATAPTR16)lpSym)->off);
// calculate what the old offset was.
doffOld = obTarget;
if (lplbs->tagLoc) {
doffOld -= (CV_uoff32_t)(((DATAPTR16)lplbs->tagLoc)->off);
}
if (doffNew <= doffOld) {
lplbs->tagLoc = (SYMPTR) lpSym;
}
}
break;
case S_THUNK16:
if (((WORD)(((THUNKPTR16)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((THUNKPTR16)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((THUNKPTR16)lpSym)->off) + (CV_uoff32_t)(((THUNKPTR16)lpSym)->len)))) {
lplbs->tagThunk = (SYMPTR)lpSym;
}
break;
case S_CEXMODEL32:
if (((WORD)(((CEXMPTR32)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr))) {
CV_uoff32_t obTemp = (CV_uoff32_t)(((CEXMPTR32)lpSym)->off);
if (obTemp <= obModelMax) {
if (obTemp > obTarget) {
lplbs->tagModelMax = (CEXMPTR16)(CEXMPTR32)lpSym;
obModelMax = obTemp;
}
else if (obTemp >= obModelMin) {
lplbs->tagModelMin = (CEXMPTR16)(CEXMPTR32)lpSym;
obModelMin = obTemp;
}
}
}
break;
case S_LPROC32:
case S_GPROC32:
if (((WORD)(((PROCPTR32)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((PROCPTR32)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((PROCPTR32)lpSym)->off) + (CV_uoff32_t)(((PROCPTR32)lpSym)->len)))) {
lplbs->tagProc = (SYMPTR)lpSym;
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
if (((WORD)(((PROCPTRMIPS)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((PROCPTRMIPS)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((PROCPTRMIPS)lpSym)->off) + (CV_uoff32_t)(((PROCPTRMIPS)lpSym)->len)))) {
lplbs->tagProc = (SYMPTR)lpSym;
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
if (((WORD)(((PROCPTRIA64)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((PROCPTRIA64)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((PROCPTRIA64)lpSym)->off) + (CV_uoff32_t)(((PROCPTRIA64)lpSym)->len)))) {
lplbs->tagProc = (SYMPTR)lpSym;
}
break;
case S_LABEL32:
if (((WORD)(((LABELPTR32)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
(((CV_uoff32_t)((LABELPTR32)lpSym)->off) <= obTarget)) {
doffNew = obTarget - (CV_uoff32_t)(((LABELPTR32)lpSym)->off);
// calculate what the old offset was, this requires no
// use of static variables
doffOld = obTarget;
if (lplbs->tagLab) {
doffOld -= (CV_uoff32_t)(((LABELPTR32)lplbs->tagLab)->off);
}
if (doffNew <= doffOld) {
lplbs->tagLab = (SYMPTR)lpSym;
}
}
break;
case S_LDATA32:
case S_GDATA32:
case S_LTHREAD32:
case S_GTHREAD32:
if (((WORD)(((DATAPTR32)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) && ((CV_uoff32_t)(((DATAPTR32)lpSym)->off) <= obTarget)) {
doffNew = obTarget - (CV_uoff32_t)(((DATAPTR32)lpSym)->off);
// calculate what the old offset was.
doffOld = obTarget;
if (lplbs->tagLoc) {
doffOld -= (CV_uoff32_t)(((DATAPTR32)lplbs->tagLoc)->off);
}
if (doffNew <= doffOld) {
lplbs->tagLoc = (SYMPTR) lpSym;
}
}
break;
case S_THUNK32:
if (((WORD)(((THUNKPTR32)lpSym)->seg) == (WORD)GetAddrSeg (lplbs->addr)) &&
((CV_uoff32_t)(((THUNKPTR32)lpSym)->off) <= obTarget) &&
(obTarget < ((CV_uoff32_t)(((THUNKPTR32)lpSym)->off) + (CV_uoff32_t)(((THUNKPTR32)lpSym)->len)))) {
lplbs->tagThunk = (SYMPTR)lpSym;
}
break;
}
lpSym = NEXTSYM (SYMPTR, lpSym);
}
}
// SHdNearestSymbol
// 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:
// ptxt - a pointer to the context, address and mdi must
// be filled in.
// sop - Determine what type of symbols to look for
// Notes: If CV_MAXOFFSET is returned in the lpodr, there is no closest
// symbol Also all symbols in the module are searched so only the
// cxt.addr and cxt.mdi have meaning.
VOID SHdNearestSymbol (PCXT pcxt, SOP sop, LPODR lpodr)
{
HSYM hSym;
SYMPTR pSym;
LBS lbs;
ULONG doff = CV_MAXOFFSET;
ULONG doffNew = CV_MAXOFFSET;
LPCH lpch = lpodr->lszName;
lpodr->fst = fstNone;
lpodr->fcd = fcdUnknown;
lpodr->fpt = fptUnknown;
lpodr->cbProlog = 0;
lpodr->dwDeltaOff = 0;
*lpch = '\0';
if (SHHMODFrompCXT (pcxt)) {
BOOL bAddrInProc = FALSE;
// 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 = SHHMODFrompCXT (pcxt);
lbs.addr = *SHpADDRFrompCXT (pcxt);
SHpSymlplLabLoc (&lbs);
// check for closest data local, if requested
if ((sop & sopData) && lbs.tagLoc) {
pSym = (SYMPTR) lbs.tagLoc;
switch (pSym->rectyp) {
case S_LDATA16:
case S_GDATA16:
doff = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((DATAPTR16)pSym)->off));
_tcsncpy (lpch, (char *)&((DATAPTR16)pSym)->name[1], (BYTE)(*((DATAPTR16)pSym)->name));
lpch[(BYTE)(*((DATAPTR16)pSym)->name)] = '\0';
break;
case S_LDATA32:
case S_GDATA32:
case S_LTHREAD32:
case S_GTHREAD32:
doff = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((DATAPTR32)pSym)->off));
_tcsncpy (lpch, (char *)&((DATAPTR32)pSym)->name[1], (BYTE)(*((DATAPTR32)pSym)->name));
lpch[(BYTE)(*((DATAPTR32)pSym)->name)] = '\0';
break;
}
}
// check for closest label
if (!(sop & sopFcn) && lbs.tagLab) {
pSym = (SYMPTR) lbs.tagLab;
switch (pSym->rectyp) {
case S_LABEL16:
doff = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((LABELPTR16)pSym)->off) );
_tcsncpy (lpch, (char *)&((LABELPTR16)pSym)->name[1], (BYTE)(*((LABELPTR16)pSym)->name));
lpch[(BYTE)(*((LABELPTR16)pSym)->name)] = '\0';
break;
case S_LABEL32:
doff = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((LABELPTR32)pSym)->off) );
_tcsncpy (lpch, (char *)&((LABELPTR32)pSym)->name[1], (BYTE)(*((LABELPTR32)pSym)->name));
lpch[(BYTE)(*((LABELPTR32)pSym)->name)] = '\0';
break;
}
}
// if the proc name is closer
if (lbs.tagProc) {
pSym = (SYMPTR) lbs.tagProc;
switch (pSym->rectyp) {
case S_LPROC16:
case S_GPROC16:
doffNew = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((PROCPTR16)pSym)->off));
if (doffNew <= doff) {
doff = doffNew;
_tcsncpy (lpch, (char *)&((PROCPTR16)pSym)->name[1], (BYTE)(*((PROCPTR16)pSym)->name));
lpch[(BYTE)(*((PROCPTR16)pSym)->name)] = '\0';
lpodr->cbProlog = ((PROCPTR16)pSym)->DbgStart - 1;
lpodr->fcd = (((PROCPTR16)pSym)->flags.CV_PFLAG_FAR) ? fcdFar : fcdNear;
lpodr->fst = fstSymbol;
if ( doff < (CV_uoff32_t)((PROCPTR16)pSym)->len ) {
bAddrInProc = TRUE;
}
}
break;
case S_LPROC32:
case S_GPROC32:
doffNew = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((PROCPTR32)pSym)->off));
if (doffNew <= doff) {
doff = doffNew;
_tcsncpy (lpch, (char *)&((PROCPTR32)pSym)->name[1], (BYTE)(*((PROCPTR32)pSym)->name));
lpch[(BYTE)(*((PROCPTR32)pSym)->name)] = '\0';
// cbProlog is a WORD, so until we change that, we'll
// have to make sure the prolog is <64K (a safe bet)
assert (((PROCPTR32)pSym)->DbgStart <= 65535);
lpodr->cbProlog = (WORD)(((PROCPTR32)pSym)->DbgStart);
lpodr->fcd = (((PROCPTR32)pSym)->flags.CV_PFLAG_FAR) ? fcdFar : fcdNear;
lpodr->fst = fstSymbol;
if (((PROCPTR32)pSym)->flags.CV_PFLAG_NOFPO ) {
lpodr->fpt = fptPresent;
}
if ( doff < (CV_uoff32_t)((PROCPTR32)pSym)->len ) {
bAddrInProc = TRUE;
}
}
break;
case S_LPROCMIPS:
case S_GPROCMIPS:
doffNew = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((PROCPTRMIPS)pSym)->off));
if (doffNew <= doff) {
doff = doffNew;
_tcsncpy (lpch, (char *)&((PROCPTRMIPS)pSym)->name[1], (BYTE)(*((PROCPTRMIPS)pSym)->name));
lpch[(BYTE)(*((PROCPTRMIPS)pSym)->name)] = '\0';
// cbProlog is a WORD, so until we change that, we'll
// have to make sure the prolog is <64K (a safe bet)
if (((PROCPTRMIPS)pSym)->DbgStart == 0) {
lpodr->cbProlog = 0;
} else {
// TEMPORARY HACK !!!!!!! - sanjays
assert (((PROCPTRMIPS)pSym)->DbgStart - 1 <= 65535);
lpodr->cbProlog = (WORD)(((PROCPTRMIPS)pSym)->DbgStart - 1);
}
lpodr->fcd = fcdNear;
lpodr->fst = fstSymbol;
if ( doff < (CV_uoff32_t)((PROCPTRMIPS)pSym)->len ) {
bAddrInProc = TRUE;
}
}
break;
case S_LPROCIA64:
case S_GPROCIA64:
doffNew = (ULONG)(GetAddrOff (lbs.addr) - (CV_uoff32_t)(((PROCPTRIA64)pSym)->off));
if (doffNew <= doff) {
doff = doffNew;
_tcsncpy (lpch, (char *)&((PROCPTRIA64)pSym)->name[1], (BYTE)(*((PROCPTRIA64)pSym)->name));
lpch[(BYTE)(*((PROCPTRIA64)pSym)->name)] = '\0';
// cbProlog is a WORD, so until we change that, we'll
// have to make sure the prolog is <64K (a safe bet)
assert (((PROCPTRIA64)pSym)->DbgStart <= 65535);
lpodr->cbProlog = (WORD)(((PROCPTRIA64)pSym)->DbgStart);
lpodr->fcd = (((PROCPTRIA64)pSym)->flags.CV_PFLAG_FAR) ? fcdFar : fcdNear;
lpodr->fst = fstSymbol;
if (((PROCPTRIA64)pSym)->flags.CV_PFLAG_NOFPO ) {
lpodr->fpt = fptPresent;
}
if ( doff < (CV_uoff32_t)((PROCPTRIA64)pSym)->len ) {
bAddrInProc = TRUE;
}
}
break;
}
}
if (!doff) {
lpodr->dwDeltaOff = 0; // Exact Match
return;
}
// Avoid searching the publics if the address we were searching for
// is in the range of the proc we found.
if ( bAddrInProc && !(sop & sopData))
{
lpodr->dwDeltaOff = doff;
return;
}
}
// now check the publics
doffNew = PHGetNearestHsym (SHpADDRFrompCXT (pcxt), (HEXE) SHpADDRFrompCXT(pcxt)->emi, &hSym);
if (doffNew < doff) {
doff = doffNew;
pSym = (SYMPTR) hSym;
switch (pSym->rectyp) {
case S_GDATA16:
case S_PUB16:
_tcsncpy (lpch, (char *)&((DATAPTR16)pSym)->name[1], (BYTE)(*((DATAPTR16)pSym)->name));
lpch[(BYTE)(*((DATAPTR16)pSym)->name)] = '\0';
lpodr->fst = fstPublic;
break;
case S_GDATA32:
case S_PUB32:
_tcsncpy (lpch, (char *)&((DATAPTR32)pSym)->name[1], (BYTE)(*((DATAPTR32)pSym)->name));
lpch[(BYTE)(*((DATAPTR32)pSym)->name)] = '\0';
lpodr->fst = fstPublic;
break;
}
}
lpodr->dwDeltaOff = doff;
}
// the next function is provided to osdebug via callbacks and should not be called within the CV kernel
// SHModelFromAddr
// Purpose: To fill the supplied buffer with the relevant Change Execution Model record from the symbols section.
// Input:
// pcxt - a pointer to an addr,
// Output:
// pch - The Change Execution Model record is copied here.
// Returns
// True if there is symbol information for the module.
// Notes: If there is no symbol information for the module, the supplied buffer is not changed and the function returns FALSE.
// UNDONE: The statics in this function s/b moved to a CACHE struct. Better yet, it, simply test for mac targetting and return native if not.
int SHModelFromAddr (LPADDR paddr, LPW lpwModel, LPB lpbModel, UOFFSET *pobMax)
{
static CEXMPTR16 tagOld;
static CV_uoff32_t obMax = 0;
static CV_uoff32_t obMin = 0;
static HEMI emiOld = 0;
static WORD segOld = 0;
SYMPTR *lppModel = (SYMPTR *) lpbModel;
LBS lbs;
ADDR addr;
LPMDS lpmds;
HMOD hmod;
CXT cxt = {0};
CB cbSecContrib;
BOOL fTmp;
// if physical, unfix it up
if (!ADDR_IS_LI (*paddr)) {
SYUnFixupAddr (paddr);
}
cxt.addr = *paddr;
cxt.hMod = 0;
if ((segOld != (WORD) GetAddrSeg (*SHpADDRFrompCXT(&cxt))) ||
(emiOld != emiAddr (*SHpADDRFrompCXT(&cxt))) ||
(GetAddrOff (*SHpADDRFrompCXT(&cxt)) >= obMax) ||
(GetAddrOff (*SHpADDRFrompCXT(&cxt)) < obMin))
{
if (!SHHMODFrompCXT (&cxt)) {
addr = *SHpADDRFrompCXT (&cxt);
memset(&cxt, 0, sizeof(CXT));
if (!SHSetCxtMod(&addr, &cxt)) {
return FALSE;
}
}
hmod = (HMOD)SHHGRPFrompCXT(&cxt);
if (!hmod) {
return FALSE;
}
lpmds = (LPMDS) hmod;
emiOld = emiAddr (*SHpADDRFrompCXT(&cxt));
fTmp = IsAddrInMod (lpmds, &cxt.addr, &segOld, (OFF *)&obMin, &cbSecContrib);
assert(fTmp);
obMax = obMin + cbSecContrib + 1;
tagOld = NULL;
// 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 Relevant change model records
if (GetSymbols ((LPMDS) (lbs.tagMod = SHHMODFrompCXT (&cxt)))) {
lbs.addr = *SHpADDRFrompCXT(&cxt);
SHpSymlplLabLoc (&lbs);
if (tagOld = lbs.tagModelMin) {
if (((SYMPTR)(lbs.tagModelMin))->rectyp == S_CEXMODEL32) {
obMin = ((CEXMPTR32)(lbs.tagModelMin))->off;
} else {
obMin = (lbs.tagModelMin)->off;
}
}
if (lbs.tagModelMax) {
if (((SYMPTR)(lbs.tagModelMax))->rectyp == S_CEXMODEL32) {
obMax = ((CEXMPTR32)(lbs.tagModelMax))->off;
} else {
obMax = (lbs.tagModelMax)->off;
}
}
}
}
if (tagOld != NULL) {
// pass on ptr to the SYM
*lppModel = (SYMPTR) tagOld;
if (((SYMPTR)tagOld)->rectyp == S_CEXMODEL32) {
*lpwModel = ((CEXMPTR32) *lppModel) -> model;
} else {
*lpwModel = ((CEXMPTR16) *lppModel) -> model;
}
if (*lpwModel != CEXM_MDL_cobol
&& *lpwModel != CEXM_MDL_pcode32Mac
&& *lpwModel != CEXM_MDL_pcode32MacNep
) {
*lpwModel &= 0xfff0;
}
} else {
// no model record, must be native
*lppModel = NULL;
*lpwModel = CEXM_MDL_native;
}
*pobMax = obMax;
return TRUE;
}