/*++ 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 #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() strncpy(myfilename, filename, sizeof(myfilename)); myfilename[sizeof(myfilename)-1] = '\0'; if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) { //PRINTF("VDMDBG: Error reading file %s\n", filename); strncpy(myfilename, filename, sizeof(myfilename)-sizeof(".exe")); myfilename[sizeof(myfilename)-sizeof(".exe")-1] = '\0'; strcat(myfilename, ".exe"); if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) { //PRINTF("VDMDBG: Error reading file %s\n", myfilename); strncpy(myfilename, filename, sizeof(myfilename)-sizeof(".dll")); myfilename[sizeof(myfilename)-sizeof(".dll")-1] = '\0'; 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; strncpy(filename, fn,sizeof(filename)-sizeof(".sym")); filename[sizeof(filename)-sizeof(".sym")-1] = '\0'; 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; strncpy(filename, fn, sizeof(filename)-sizeof(".sym")); filename[sizeof(filename)-sizeof(".sym")-1] = '\0'; 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)); }