windows-nt/Source/XPSP1/NT/base/mvdm/vdmdbg/sym.c
2020-09-26 16:20:57 +08:00

706 lines
18 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
sym.c
Abstract:
This function contains the 16-bit symbol support for VDMDBG
Author:
Bob Day (bobday) 29-Feb-1992 Grabbed standard header
Revision History:
Neil Sandlin (NeilSa) 15-Jan-1996 Merged with vdmexts
Neil Sandlin (NeilSa) 01-Mar-1997 Moved it to VDMDBG,
Rewrote it
--*/
#include <precomp.h>
#pragma hdrstop
#define PRINTF(x) TRUE
#define MYOF_FLAGS (OF_READ | OF_SHARE_DENY_NONE)
#define MAX_MODULE_LIST 200
char ModuleList[MAX_MODULE_LIST][9];
int ModuleListCount = 0;
typedef struct _SYM_MAP {
WORD map_ptr;
WORD map_lsa;
WORD pgm_ent;
WORD abs_cnt;
WORD abs_ptr;
WORD seg_cnt;
WORD seg_ptr;
BYTE sym_nam_max;
BYTE map_nam_len;
char map_name[20];
} SYM_MAP;
typedef struct _SYM_SEG {
WORD nxt_seg;
WORD sym_cnt;
WORD sym_ptr;
WORD seg_lsa;
WORD seg_in[4];
WORD seg_lin;
BYTE seg_ldd;
char seg_cin;
BYTE seg_nam_len;
char seg_name[20];
} SYM_SEG;
typedef struct _SYM_ITEM {
WORD sym_val;
BYTE sym_nam_len;
char sym_name[256];
} SYM_ITEM;
BOOL
FindExport(
LPSTR filename,
WORD segment,
WORD offset,
LPSTR sym_text,
BOOL next,
LONG *dist
)
{
int iFile;
OFSTRUCT ofs;
int rc;
IMAGE_DOS_HEADER doshdr;
IMAGE_OS2_HEADER winhdr;
BYTE Table[65536];
BYTE bBundles;
BYTE bFlags;
BYTE *ptr;
WORD wIndex = 1;
int i;
int this_dist;
int wIndexBest = -1;
char myfilename[256];
#pragma pack(1)
typedef struct
{
BYTE bFlags;
UNALIGNED WORD wSegOffset;
} FENTRY, *PFENTRY;
typedef struct
{
BYTE bFlags;
UNALIGNED WORD wINT3F;
BYTE bSegNumber;
UNALIGNED WORD wSegOffset;
} MENTRY, *PMENTRY;
#pragma pack()
strcpy(myfilename, filename);
if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
//PRINTF("VDMDBG: Error reading file %s\n", filename);
strcpy(myfilename, filename);
strcat(myfilename, ".exe");
if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
//PRINTF("VDMDBG: Error reading file %s\n", myfilename);
strcpy(myfilename, filename);
strcat(myfilename, ".dll");
if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
//PRINTF("VDMDBG: Error reading file %s\n", myfilename);
PRINTF("VDMDBG: Error reading file\n");
return FALSE;
}
}
}
rc = _lread(iFile, &doshdr, sizeof(doshdr));
if (rc != sizeof(doshdr)) {
PRINTF("VDMDBG: Error reading DOS header\n");
goto Error;
}
if (doshdr.e_magic != IMAGE_DOS_SIGNATURE) {
PRINTF("VDMDBG: Error - no DOS EXE signature");
goto Error;
}
rc = _llseek(iFile, doshdr.e_lfanew, FILE_BEGIN);
if (rc == -1) {
PRINTF("VDMDBG: Error - could not seek - probably not Win3.1 exe\n");
goto Error;
}
rc = _lread(iFile, &winhdr, sizeof(winhdr));
if (rc != sizeof(winhdr)) {
PRINTF("VDMDBG: Error - could not read WIN header - probably not Win3.1 exe\n");
goto Error;
}
if (winhdr.ne_magic != IMAGE_OS2_SIGNATURE) {
PRINTF("VDMDBG: Error - not WIN EXE signature\n");
goto Error;
}
rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_enttab, FILE_BEGIN);
if (rc == -1) {
PRINTF("VDMDBG: Error - could not seek to entry table\n");
goto Error;
}
rc = _lread(iFile, Table, winhdr.ne_cbenttab);
if (rc != winhdr.ne_cbenttab) {
PRINTF("VDMDBG: Error - could not read entry table\n");
goto Error;
}
ptr = Table;
while (TRUE) {
bBundles = *ptr++;
if (bBundles == 0)
break;
bFlags = *ptr++;
switch (bFlags) {
case 0: // Placeholders
wIndex += bBundles;
break;
case 0xff: // movable segments
for (i=0; i<(int)bBundles; ++i) {
PMENTRY pe = (PMENTRY )ptr;
if (pe->bSegNumber == segment) {
this_dist = (!next) ? offset - pe->wSegOffset
: pe->wSegOffset - offset;
if ( this_dist >= 0 && (this_dist < *dist || *dist == -1) ) {
// mark this as the best match so far
*dist = this_dist;
wIndexBest = wIndex;
}
}
ptr += sizeof(MENTRY);
wIndex++;
}
break;
default: // fixed segments
if ((int)bFlags != segment) {
ptr += (int)bBundles * sizeof(FENTRY);
wIndex += (int)bBundles;
} else {
for (i=0; i<(int)bBundles; ++i) {
PFENTRY pe = (PFENTRY)ptr;
this_dist = (!next) ? offset - pe->wSegOffset
: pe->wSegOffset - offset;
if ( this_dist >= 0 && (this_dist < *dist || *dist == -1) ) {
// mark this as the best match so far
*dist = this_dist;
wIndexBest = wIndex;
}
ptr += sizeof(FENTRY);
wIndex++;
}
}
break;
}
}
if (wIndexBest == -1) {
// no match found - error out
Error:
_lclose(iFile);
return FALSE;
}
// Success: match found
// wIndexBest = ordinal of the function
// segment:offset = address to look up
// *dist = distance from segment:offset to the symbol
// filename = name of .exe/.dll
// Look for the ordinal in the resident name table
rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_restab, FILE_BEGIN);
if (rc == -1) {
PRINTF("VDMDBG: Error - unable to seek to residentname table\n");
goto Error;
}
rc = _lread(iFile, Table, winhdr.ne_modtab-winhdr.ne_restab);
if (rc != winhdr.ne_modtab-winhdr.ne_restab) {
PRINTF("VDMDBG: Error - unable to read entire resident name table\n");
goto Error;
}
ptr = Table;
while (*ptr) {
if ( *(UNALIGNED USHORT *)(ptr+1+*ptr) == (USHORT)wIndexBest) {
// found the matching name
*(ptr+1+*ptr) = '\0'; // null-terminate the function name
strcpy(sym_text, ptr+1);
goto Finished;
}
ptr += *ptr + 3;
}
// Look for the ordinal in the non-resident name table
rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_nrestab, FILE_BEGIN);
if (rc == -1) {
PRINTF("VDMDBG: Error - unable to seek to non-residentname table\n");
goto Error;
}
rc = _lread(iFile, Table, winhdr.ne_cbnrestab);
if (rc != winhdr.ne_cbnrestab) {
PRINTF("VDMDBG: Error - unable to read entire non-resident name table\n");
goto Error;
}
ptr = Table;
while (*ptr) {
if ( *(UNALIGNED USHORT *)(ptr+1+*ptr) == (USHORT)wIndexBest) {
// found the matching name
*(ptr+1+*ptr) = '\0'; // null-terminate the function name
strcpy(sym_text, ptr+1);
goto Finished;
}
ptr += *ptr + 3;
}
// fall into error path - no match found
goto Error;
Finished:
_lclose(iFile);
return TRUE;
}
BOOL
ExtractSymbol(
int iFile,
DWORD ulSegPos,
DWORD ulSymPos,
WORD csym,
WORD seglsa,
WORD segment,
DWORD offset,
BOOL next,
LPSTR sym_text,
PLONG pdist
)
{
WORD uLastSymdefPos=0;
/* ulWrap allows for wrapping around with more than 64K of symbols */
DWORD ulWrap=0;
LONG SymOffset;
LONG this_dist;
BOOL fResult = FALSE;
char name_text[256];
for (; csym--; ulSymPos+=sizeof(WORD))
{
WORD uSymdefPos;
SYM_ITEM sym;
if (_llseek(iFile, ulSymPos, FILE_BEGIN) == -1)
return FALSE;
if (_lread(iFile, (LPSTR)&uSymdefPos, sizeof(uSymdefPos)) != sizeof(uSymdefPos))
return FALSE;
if (uSymdefPos < uLastSymdefPos)
ulWrap += 0x10000L;
_llseek(iFile, ulSegPos + uSymdefPos + ulWrap, FILE_BEGIN);
_lread(iFile, (LPSTR)&sym, sizeof(sym));
if (segment == 0) {
SymOffset = (LONG)seglsa*16 + sym.sym_val;
} else {
SymOffset = (LONG)sym.sym_val;
}
// Depending on whether the caller wants the closest symbol
// from below or above, compute the distance from the current
// symbol to the target offset.
switch( next ) {
case FALSE:
this_dist = offset - SymOffset;
break;
case TRUE:
this_dist = SymOffset - offset;
break;
}
//
// Since we don't really know if the current symbol is actually
// the nearest symbol, just remember it if it qualifies. Keep
// the best distance so far in 'dist'.
//
if ((this_dist >= 0) && ((this_dist < *pdist) || (*pdist == -1))) {
*pdist = this_dist;
strncpy(name_text, sym.sym_name, sym.sym_nam_len);
name_text[sym.sym_nam_len] = 0;
fResult = TRUE;
}
uLastSymdefPos = uSymdefPos;
}
if (fResult) {
//
// The scan of the symbols in this segment produced a winner.
// Copy the name and displacement back up to the caller.
//
strcpy(sym_text, name_text);
}
return fResult;
}
BOOL
WalkSegmentsForSymbol(
int iFile,
SYM_MAP *pMap,
ULONG ulMapPos,
WORD segment,
DWORD offset,
BOOL next,
LPSTR sym_text,
PDWORD pDisplacement
)
{
DWORD ulSegPos;
LONG dist = -1;
BOOL fResult = FALSE;
WORD this_seg;
#if 0
/* first, walk absolute segment */
if (fAbsolute && map.abs_cnt != 0) {
/* the thing with seg_ptr below is to allow for an absolute
* segment with more than 64K of symbols: if the segment
* pointer of the next symbol is more than 64K away, then
* add 64K to the beginning of the table of symbol pointers.
*/
if (ExtractSymbol(iFile,
ulMapPos,
ulMapPos + pMap->abs_ptr + (pMap->seg_ptr&0xF000)*0x10L,
pMap->abs_cnt,
0,
segment,
offset,
next,
sym_text,
pDisplacement)) {
return TRUE;
}
}
#endif
/* now walk other segments */
ulSegPos = (DWORD)pMap->seg_ptr * 16;
for (this_seg = 0; this_seg < pMap->seg_cnt; this_seg++) {
SYM_SEG seg;
if (_llseek(iFile, ulSegPos, FILE_BEGIN) == -1)
return FALSE;
if (_lread(iFile, (LPSTR)&seg, sizeof(seg)) != sizeof(seg))
return FALSE;
if ((segment == 0) || (segment == this_seg+1)) {
if (ExtractSymbol(iFile,
ulSegPos,
ulSegPos + seg.sym_ptr,
seg.sym_cnt,
seg.seg_lsa,
segment,
offset,
next,
sym_text,
&dist)) {
fResult = TRUE;
if (segment != 0) {
// only looking in one segment
break;
}
}
}
ulSegPos = (DWORD)seg.nxt_seg * 16;
}
if (fResult) {
*pDisplacement = dist;
}
return fResult;
}
BOOL
WINAPI
VDMGetSymbol(
LPSTR fn,
WORD segment,
DWORD offset,
BOOL bProtectMode,
BOOL next,
LPSTR sym_text,
PDWORD pDisplacement
)
{
int iFile;
char filename[256];
OFSTRUCT ofs;
SYM_MAP map;
SYM_SEG seg;
SYM_ITEM item;
ULONG ulMapPos = 0;
strcpy(filename, fn);
strcat(filename,".sym");
iFile = OpenFile( filename, &ofs, MYOF_FLAGS );
if ( iFile == -1 ) {
// Open the .EXE/.DLL file and see if the address corresponds
// to an exported function.
return(FindExport(fn,segment,(WORD)offset,sym_text,next,pDisplacement));
}
do {
if (_llseek( iFile, ulMapPos, FILE_BEGIN) == -1) {
PRINTF("VDMDBG: GetSymbol failed to seek to map\n");
break;
}
if (_lread( iFile, (LPSTR)&map, sizeof(map)) != sizeof(map)) {
PRINTF("VDMDBG: GetSymbol failed to read map\n");
break;
}
if (WalkSegmentsForSymbol(iFile, &map, ulMapPos,
segment, offset, next,
sym_text, pDisplacement)) {
_lclose( iFile );
return TRUE;
}
} while(ulMapPos);
_lclose( iFile );
return FALSE;
}
BOOL
ExtractValue(
int iFile,
DWORD ulSegPos,
DWORD ulSymPos,
WORD csym,
LPSTR szSymbol,
PWORD pValue
)
{
WORD uLastSymdefPos=0;
/* ulWrap allows for wrapping around with more than 64K of symbols */
DWORD ulWrap=0;
LONG SymOffset;
char name_text[256];
for (; csym--; ulSymPos+=sizeof(WORD))
{
WORD uSymdefPos;
SYM_ITEM sym;
if (_llseek(iFile, ulSymPos, FILE_BEGIN) == -1)
return FALSE;
if (_lread(iFile, (LPSTR)&uSymdefPos, sizeof(uSymdefPos)) != sizeof(uSymdefPos))
return FALSE;
if (uSymdefPos < uLastSymdefPos)
ulWrap += 0x10000L;
_llseek(iFile, ulSegPos + uSymdefPos + ulWrap, FILE_BEGIN);
_lread(iFile, (LPSTR)&sym, sizeof(sym));
strncpy(name_text, sym.sym_name, sym.sym_nam_len);
name_text[sym.sym_nam_len] = 0;
if (_stricmp(szSymbol, name_text) == 0) {
*pValue = sym.sym_val;
return TRUE;
}
uLastSymdefPos = uSymdefPos;
}
return FALSE;
}
BOOL
WalkSegmentsForValue(
int iFile,
SYM_MAP *pMap,
ULONG ulMapPos,
LPSTR szSymbol,
PWORD pSegmentBase,
PWORD pSegmentNumber,
PWORD pValue
)
{
DWORD ulSegPos;
WORD this_seg;
#if 0
/* first, walk absolute segment */
if (fAbsolute && pMap->abs_cnt != 0) {
/* the thing with seg_ptr below is to allow for an absolute
* segment with more than 64K of symbols: if the segment
* pointer of the next symbol is more than 64K away, then
* add 64K to the beginning of the table of symbol pointers.
*/
if (ExtractValue(iFile,
ulMapPos,
ulMapPos + pMap->abs_ptr + (pMap->seg_ptr&0xF000)*0x10L,
pMap->abs_cnt,
szSymbol,
pValue)) {
return TRUE;
}
}
#endif
/* now walk other segments */
ulSegPos = (DWORD)pMap->seg_ptr * 16;
for (this_seg = 0; this_seg < pMap->seg_cnt; this_seg++) {
SYM_SEG seg;
if (_llseek(iFile, ulSegPos, FILE_BEGIN) == -1)
return FALSE;
if (_lread(iFile, (LPSTR)&seg, sizeof(seg)) != sizeof(seg))
return FALSE;
if (ExtractValue(iFile,
ulSegPos,
ulSegPos + seg.sym_ptr,
seg.sym_cnt,
szSymbol,
pValue)) {
*pSegmentBase = seg.seg_lsa;
*pSegmentNumber = this_seg+1;
return TRUE;
}
ulSegPos = (DWORD)seg.nxt_seg * 16;
}
return FALSE;
}
BOOL
WalkMapForValue(
LPSTR fn,
LPSTR szSymbol,
PWORD pSelector,
PDWORD pOffset,
PWORD pType
)
{
int iFile;
char filename[256];
OFSTRUCT ofs;
SYM_MAP map;
SYM_SEG seg;
SYM_ITEM item;
ULONG ulMapPos = 0;
WORD SegmentNumber;
WORD SegmentBase;
WORD Value;
strcpy(filename, fn);
strcat(filename,".sym");
iFile = OpenFile( filename, &ofs, MYOF_FLAGS );
if ( iFile == -1 ) {
return FALSE;
}
do {
if (_llseek( iFile, ulMapPos, FILE_BEGIN) == -1) {
PRINTF("VDMDBG: failed to seek to map\n");
break;
}
if (_lread( iFile, (LPSTR)&map, sizeof(map)) != sizeof(map)) {
PRINTF("VDMDBG: failed to read map\n");
break;
}
if (WalkSegmentsForValue(iFile, &map, ulMapPos,
szSymbol, &SegmentBase, &SegmentNumber, &Value)) {
VDM_SEGINFO si;
if (GetInfoBySegmentNumber(fn, SegmentNumber, &si)) {
*pSelector = si.Selector;
if (!si.Type) {
*pType = VDMADDR_V86;
if (!si.SegNumber) {
// This is a "combined" map of all the segments,
// so we need to calculate the offset
*pOffset = (DWORD)SegmentBase*16 + Value;
} else {
// This is a "split" v86 map
*pOffset = (DWORD) Value;
}
} else {
*pType = VDMADDR_PM16;
*pOffset = (DWORD)Value;
}
_lclose( iFile );
return TRUE;
}
}
} while(ulMapPos);
_lclose( iFile );
return FALSE;
}
BOOL
WINAPI
VDMGetAddrExpression(
LPSTR szModule,
LPSTR szSymbol,
PWORD pSelector,
PDWORD pOffset,
PWORD pType
)
{
int iFile;
char filename[256];
OFSTRUCT ofs;
SYM_MAP map;
SYM_SEG seg;
SYM_ITEM item;
ULONG ulMapPos = 0;
if (szModule) {
return(WalkMapForValue(szModule, szSymbol, pSelector, pOffset, pType));
}
return (EnumerateModulesForValue(VDMGetAddrExpression,
szSymbol,
pSelector,
pOffset,
pType));
}