758 lines
18 KiB
C
758 lines
18 KiB
C
/* Chris Peters
|
||
* CHANGED: Fritz Knabe, 7/28/87
|
||
* mikedr, 8/8/88 - read offset bytes after 0xff seg no on swap
|
||
* allow specification of data file location
|
||
* c-chrisc [Christine Comaford], 10/31/89 - added "-i" flag to
|
||
* allow symbol file path spec on command line, added "-m"
|
||
* flag to precede module spec, rewrote module parser,
|
||
* added usage display, misc other enhancements.
|
||
*
|
||
* Copyright Microsoft Corporation, 1985-1990
|
||
*/
|
||
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <assert.h>
|
||
#include <memory.h>
|
||
#include <malloc.h>
|
||
#include <stdlib.h>
|
||
|
||
/* standard stuff */
|
||
typedef unsigned char BYTE;
|
||
typedef unsigned short WORD;
|
||
typedef unsigned long DWORD;
|
||
typedef int BOOL;
|
||
#define TRUE 1
|
||
#define FALSE 0
|
||
|
||
BOOL FModuleMatch(BYTE *, BYTE);
|
||
int GetSymbolString(BYTE *, BYTE *, WORD, WORD);
|
||
int GetSegNum(char *, char *);
|
||
BYTE *htoa(BYTE *, WORD);
|
||
char *ProcessArguments(int, char **);
|
||
|
||
/* Debug Symbol Table Structures
|
||
-----------------------------
|
||
For each symbol table (map): (MAPDEF)
|
||
-------------------------------------------------------------------------------------------------
|
||
| map_ptr | lsa | pgm_ent | abs_cnt | abs_ptr | seg_cnt | seg_ptr | nam_max | nam_len | name... |
|
||
------------------------------------------------------------------------------------------------- */
|
||
struct mapdef
|
||
{
|
||
unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */
|
||
unsigned lsa ; /* 16 bit Load Segment address */
|
||
unsigned pgm_ent; /* 16 bit entry point segment value */
|
||
int abs_cnt; /* 16 bit count of constants in map */
|
||
unsigned abs_ptr; /* 16 bit ptr to constant chain */
|
||
int seg_cnt; /* 16 bit count of segments in map */
|
||
unsigned seg_ptr; /* 16 bit ptr to segment chain */
|
||
char nam_max; /* 8 bit Maximum Symbol name length */
|
||
char nam_len; /* 8 bit Symbol table name length */
|
||
};
|
||
|
||
struct mapend
|
||
{
|
||
unsigned chnend; /* end of map chain (0) */
|
||
char rel; /* release */
|
||
char ver; /* version */
|
||
};
|
||
|
||
/* For each segment/group within a symbol table: (SEGDEF)
|
||
--------------------------------------------------------------
|
||
| nxt_seg | sym_cnt | sym_ptr | seg_lsa | name_len | name... |
|
||
-------------------------------------------------------------- */
|
||
struct segdef
|
||
{
|
||
unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */
|
||
int sym_cnt; /* 16 bit count of symbols in sym list */
|
||
unsigned sym_ptr; /* 16 bit ptr to symbol list */
|
||
unsigned seg_lsa; /* 16 bit Load Segment address */
|
||
unsigned seg_in0; /* 16 bit instance 0 physical address */
|
||
unsigned seg_in1; /* 16 bit instance 1 physical address */
|
||
unsigned seg_in2; /* 16 bit instance 2 physical address */
|
||
unsigned seg_in3; /* 16 bit instance 3 physical address */
|
||
unsigned seg_lin; /* 16 bit ptr to line number record */
|
||
char seg_ldd; /* 8 bit boolean 0 if seg not loaded */
|
||
char seg_cin; /* 8 bit current instance */
|
||
char nam_len; /* 8 bit Segment name length */
|
||
};
|
||
|
||
/* Followed by a list of SYMDEF's..
|
||
for each symbol within a segment/group: (SYMDEF)
|
||
-------------------------------
|
||
| sym_val | nam_len | name... |
|
||
------------------------------- */
|
||
struct symdef
|
||
{
|
||
unsigned sym_val; /* 16 bit symbol addr or const */
|
||
char nam_len; /* 8 bit symbol name length */
|
||
};
|
||
|
||
typedef struct tagMODSEG /* Structure for saving information */
|
||
{ /* about cmd line arguments */
|
||
int segno; /* Special values:
|
||
-1 information about all segments in the module
|
||
is supplied
|
||
-2 an invalid segment name was supplied, i.e.
|
||
nothing matches this record/argument
|
||
>=0 valid segment number
|
||
*/
|
||
char szModule[32]; /* Name of module */
|
||
} MODSEG, *PMODSEG;
|
||
|
||
|
||
/*----------------------------------------------------------------------------
|
||
| Global Variables
|
||
|
|
||
----------------------------------------------------------------------------*/
|
||
|
||
#define MAX_ARGS 34 /* arbitrary (but reasonable) values */
|
||
#define MAX_PATHS 16
|
||
|
||
char curpath_buffer[65]; /* buffer holding current sym file path */
|
||
char path_buffer[132]; /* buffer holding cmd line sym path string */
|
||
char *path_table[MAX_PATHS]; /* table of sym file buffers */
|
||
|
||
int num_paths = 0; /* index into path_table[] */
|
||
int nNumArgs; /* Number of command line arguments */
|
||
|
||
char *ModSegTab[MAX_ARGS]; /* Table of MODSEG records */
|
||
|
||
BOOL bModule = FALSE; /* is module specified on command line? */
|
||
BOOL bSymPath = FALSE; /* is symbol file path specified on command line? */
|
||
|
||
int num_mods = 0; /* index into module table */
|
||
|
||
|
||
char usage[] = "\nUSAGE: SWAP [-Ipath1;path2;...] [-Fswapfile] [-Mmod1[:seg];mod2[:seg];...]\n\n"
|
||
" -Ipath1;path2;... -- Path list for .SYM files.\n\n"
|
||
" -Fswapfile -- Name and path of swap file,\n"
|
||
" default: swappro.dat.\n\n"
|
||
" -Mmod1[:seg];mod2[:seg];... -- Name of module or module:segment\n"
|
||
" pairs to return swap data for.\n";
|
||
|
||
|
||
/*----------------------------------------------------------------------------
|
||
| Main Program
|
||
|
|
||
|
|
||
----------------------------------------------------------------------------*/
|
||
|
||
/* Structure of swappro.dat records:
|
||
BYTE type; 0 = Call, 1 = Swap, 2 = Discard, 3 = Return
|
||
WORD time;
|
||
BYTE nam_len; Length of following name (not null terminated)
|
||
BYTE name[];
|
||
BYTE segno; This is the end of the record for DISCARD records
|
||
or resources (segno == 0xFF)
|
||
WORD offset; This is the end of the record for types 2 and 3
|
||
BYTE nam2_len; If 0, the next field missing, and the name is the
|
||
same as the previous one
|
||
BYTE name2[];
|
||
BYTE segno2;
|
||
BYTE offset2;
|
||
*/
|
||
|
||
|
||
main(argc, argv)
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
register FILE *pfIn;
|
||
BYTE rgch1[256];
|
||
BYTE rgch2[256];
|
||
register BYTE stModule[32], stModule2[32];
|
||
BYTE rt;
|
||
BYTE cch;
|
||
WORD t;
|
||
WORD segno = 0, segno2 = 0;
|
||
WORD offset, offset2;
|
||
BOOL fFirst = TRUE;
|
||
long time, timePrev, timeBase;
|
||
char *filepath;
|
||
|
||
|
||
/* sign on */
|
||
|
||
printf("Microsoft (R) Swap File Analyzer Version 3.00\n");
|
||
printf("Copyright (C) Microsoft Corp 1990. All rights reserved.\n\n");
|
||
|
||
filepath = ProcessArguments(argc, argv);
|
||
if (filepath == NULL)
|
||
filepath = "swappro.dat";
|
||
|
||
pfIn = fopen(filepath,"rb");
|
||
if (pfIn == NULL)
|
||
{
|
||
printf("\nFile %s not found.\n",filepath);
|
||
exit(2);
|
||
}
|
||
|
||
printf("\nType\tTime\tSegment\tOffset\tSegment\tOffset");
|
||
printf("\n----\t----\t-------\t------\t-------\t------");
|
||
|
||
while(!feof(pfIn))
|
||
{
|
||
fread(&rt, 1, 1, pfIn); /* Get the record type */
|
||
|
||
timePrev = time;
|
||
fread(&t, 2, 1, pfIn); /* Get the time */
|
||
time = t;
|
||
if (fFirst)
|
||
{
|
||
timePrev = 0;
|
||
timeBase = time;
|
||
fFirst = FALSE;
|
||
}
|
||
time -= timeBase;
|
||
if (time < timePrev)
|
||
{
|
||
time += 65536;
|
||
timeBase -= 65536;
|
||
}
|
||
|
||
switch (rt)
|
||
{
|
||
default:
|
||
printf("\n **** Invalid swap record ****");
|
||
break;
|
||
|
||
case 0: /* Call */
|
||
case 1: /* Swap */
|
||
fread(stModule, 1, 1, pfIn);
|
||
fread(stModule+1, 1, stModule[0], pfIn);
|
||
fread(&segno, 1, 1, pfIn);
|
||
if (segno != 0xFF)
|
||
fread(&offset, 2, 1, pfIn);
|
||
|
||
else /* We have a RESOURCE, so we don't fread */
|
||
offset = 0xFFFF;
|
||
|
||
fread(stModule2, 1, 1, pfIn);
|
||
/* Check if this module name is the same as
|
||
stModule */
|
||
if (stModule2[0])
|
||
fread(stModule2+1, 1, stModule2[0], pfIn);
|
||
else
|
||
memcpy(stModule2, stModule, 1 + stModule[0]);
|
||
|
||
/* read segment and offset */
|
||
fread(&segno2, 1, 1, pfIn);
|
||
fread(&offset2, 2, 1, pfIn);
|
||
if (segno2 == 0xFF)
|
||
offset2 = 0xFFFF;
|
||
|
||
if (bModule)
|
||
{
|
||
|
||
if (!FModuleMatch(stModule, segno) &&
|
||
!FModuleMatch(stModule2, segno2))
|
||
break;
|
||
}
|
||
|
||
GetSymbolString(rgch1, stModule, segno, offset);
|
||
GetSymbolString(rgch2, stModule2, segno2, offset2);
|
||
|
||
if (rt == 1)
|
||
printf("\nSwap");
|
||
else
|
||
printf("\nCall");
|
||
printf("\t%ld\t%s\t%s",time, rgch1, rgch2);
|
||
break;
|
||
|
||
case 2: /* Discard */
|
||
case 3: /* Return */
|
||
fread(stModule, 1, 1, pfIn);
|
||
fread(stModule+1, 1, stModule[0], pfIn);
|
||
fread(&segno, 1, 1, pfIn);
|
||
if (rt == 2 || segno == 0xFF)
|
||
offset = 0xFFFF;
|
||
else
|
||
/* Only read offset if not a DISCARD
|
||
record or a resource */
|
||
fread(&offset, 2, 1, pfIn);
|
||
|
||
|
||
if (bModule)
|
||
{
|
||
|
||
if (!FModuleMatch(stModule, segno))
|
||
break;
|
||
|
||
}
|
||
|
||
GetSymbolString(rgch1, stModule, segno, offset);
|
||
if (rt == 2)
|
||
printf("\nDiscard");
|
||
else
|
||
printf("\nReturn");
|
||
printf("\t%ld\t%s",time,rgch1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* returns pointer to swap data file name, NULL if none given */
|
||
char *ProcessArguments(argc, argv)
|
||
int argc;
|
||
char *argv[];
|
||
{
|
||
PMODSEG pms;
|
||
int i,j;
|
||
int nArgSep = 0;
|
||
int n = 0;
|
||
char *filepath = NULL;
|
||
char *curpath;
|
||
char ch;
|
||
char *opt;
|
||
char module_buffer[132];
|
||
char *curmodule;
|
||
|
||
#define MAX_MODULES 20
|
||
char *module_table[MAX_MODULES];
|
||
|
||
|
||
nNumArgs = (int) min(argc,MAX_ARGS);
|
||
|
||
if (nNumArgs < 2) /* No arguments */
|
||
return(filepath);
|
||
|
||
for (i = 1; i < argc; i++)
|
||
{
|
||
if ((*argv[i] == '-' || *argv[i] == '/'))
|
||
{
|
||
ch = tolower(argv[i][1]);
|
||
|
||
switch (ch) {
|
||
|
||
case 'f':
|
||
/* create swap data file spec */
|
||
filepath = &argv[i][2]; /* first char past flag */
|
||
if (!*filepath) /* skip white space */
|
||
{
|
||
i++; /* adjust command line variables */
|
||
nNumArgs--;
|
||
filepath = argv[i]; /* get file name from next arg */
|
||
}
|
||
|
||
nNumArgs--;
|
||
break;
|
||
|
||
case 'i':
|
||
bSymPath = TRUE;
|
||
|
||
/* place the current directory at the head of the symbol
|
||
table path */
|
||
getcwd(curpath_buffer, 132);
|
||
path_table[num_paths++] = curpath_buffer;
|
||
|
||
/* create symbol file spec */
|
||
strcpy(path_buffer, &argv[i][2]);
|
||
|
||
if (!*path_buffer)
|
||
{
|
||
/* space after flag, so increment index */
|
||
i++;
|
||
|
||
/* adjust command line arg count */
|
||
nNumArgs--;
|
||
|
||
/* get all symbol file path names from next arg */
|
||
strcpy (path_buffer, argv[i]);
|
||
}
|
||
|
||
strcat(path_buffer, ";");
|
||
|
||
curpath = strtok(path_buffer, ";");
|
||
|
||
do {
|
||
path_table[num_paths++] = curpath;
|
||
} while (curpath = strtok(NULL, ";"));
|
||
|
||
break;
|
||
|
||
|
||
case 'm':
|
||
|
||
/* create module and/or module:_segment file spec */
|
||
|
||
bModule = TRUE;
|
||
|
||
strcpy(module_buffer, &argv[i][2]);
|
||
|
||
if (!*module_buffer)
|
||
{
|
||
i++;
|
||
nNumArgs--;
|
||
strcpy(module_buffer, argv[i]);
|
||
|
||
}
|
||
|
||
strcat(module_buffer, ";");
|
||
|
||
/* fill module table with mod names */
|
||
curmodule = strtok(module_buffer, ";");
|
||
|
||
do {
|
||
module_table[num_mods++] = curmodule;
|
||
} while (curmodule = strtok(NULL, ";"));
|
||
|
||
|
||
/* for each module, assign segno if applicable */
|
||
for (j = 0; j < num_mods; j++)
|
||
{
|
||
if (!(pms = (PMODSEG) malloc(sizeof(MODSEG))))
|
||
{
|
||
printf ("MEMORY ALLOCATION FAILED!!!!");
|
||
exit (1);
|
||
}
|
||
|
||
/* determine whether a segment has been specified
|
||
(i.e., GDI:_FONTRES), look for a ':' */
|
||
|
||
nArgSep = strcspn(module_table[j], ":");
|
||
strncpy(pms->szModule, module_table[j], nArgSep);
|
||
|
||
pms->szModule[nArgSep] = '\0';
|
||
|
||
/* Get segment number */
|
||
|
||
/* First case: no segment specified; e.g. format of
|
||
arg would be "user" */
|
||
if (nArgSep == strlen(module_table[j]) ||
|
||
module_table[j][nArgSep+1] == '\0')
|
||
pms->segno = -1;
|
||
|
||
/* Second case: decimal segment number supplied; e.g.
|
||
"user:10" */
|
||
else if (isdigit(module_table[j][nArgSep+1]))
|
||
pms->segno = atoi(module_table[j]+nArgSep+1);
|
||
|
||
/* Third case: the segment name is "resource" */
|
||
else if (strcmpi(module_table[j]+nArgSep+1, "RESOURCE") == 0)
|
||
pms->segno = 0xFF;
|
||
|
||
/* Fourth case: a segment name is supplied; get
|
||
it's number */
|
||
else
|
||
{
|
||
pms->segno = GetSegNum(pms->szModule,
|
||
module_table[j]+nArgSep+1);
|
||
|
||
}
|
||
|
||
ModSegTab[n++] = (char *) pms;
|
||
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
/* Display cmd line args and quit */
|
||
fprintf(stderr, usage);
|
||
exit(1);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return(filepath);
|
||
}
|
||
|
||
|
||
|
||
/* Determines whether module specified on command line is equal to
|
||
current module read in. No called if no mod, mod/seg is specified on
|
||
command line. If false is returned, record won't be displayed. */
|
||
|
||
BOOL FModuleMatch(stModule, segno)
|
||
register BYTE stModule[];
|
||
BYTE segno;
|
||
{
|
||
register int i;
|
||
PMODSEG pms;
|
||
|
||
|
||
if (nNumArgs < 2)
|
||
return TRUE;
|
||
|
||
stModule[stModule[0]+1] = '\0';
|
||
|
||
for (i = 0; i < num_mods; i++)
|
||
{
|
||
pms = (PMODSEG) ModSegTab[i];
|
||
|
||
if (strcmpi(stModule+1, pms->szModule) == 0 &&
|
||
(pms->segno == -1 || pms->segno == segno))
|
||
return(TRUE);
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
int GetSegNum(szModule, szSegment)
|
||
char *szModule;
|
||
char *szSegment;
|
||
{
|
||
/* Gets the number of the named segment in the named module, if it exists.
|
||
This is a "stripped" version of GetSymbolString. */
|
||
|
||
char buf[50];
|
||
FILE *pfSym;
|
||
struct mapdef MAPDEF;
|
||
struct mapend MAPEND;
|
||
struct segdef SEGDEF;
|
||
WORD seg_ptr, fstseg_ptr;
|
||
int i;
|
||
register int pathcnt;
|
||
char symfile[65];
|
||
|
||
|
||
strcpy(symfile, szModule);
|
||
strcat(symfile, ".SYM");
|
||
|
||
|
||
if (bSymPath)
|
||
{
|
||
/* Loop through all symbol file paths until file is found */
|
||
|
||
for (pathcnt=0; pathcnt <num_paths; pathcnt++)
|
||
{
|
||
strcpy(buf, path_table[pathcnt]);
|
||
strcat(buf, "\\");
|
||
strcat(buf, symfile);
|
||
|
||
if (pfSym = fopen(buf, "rb"))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
pfSym = fopen(symfile, "rb");
|
||
|
||
if (!pfSym)
|
||
return -1;
|
||
|
||
fread(&MAPDEF, 1, sizeof(MAPDEF), pfSym);
|
||
fstseg_ptr = seg_ptr = (WORD)MAPDEF.seg_ptr;
|
||
fseek(pfSym, (long)-sizeof(MAPEND), 2);
|
||
fread(&MAPEND, 1, sizeof(MAPEND), pfSym);
|
||
if (MAPEND.ver != 3)
|
||
{
|
||
fclose(pfSym);
|
||
return -1;
|
||
}
|
||
i = 0;
|
||
do
|
||
{
|
||
if (MAPEND.rel >= 10)
|
||
fseek(pfSym, (long)(seg_ptr * 16), 0);
|
||
else
|
||
fseek(pfSym, (long)seg_ptr, 0);
|
||
fread(&SEGDEF, 1, sizeof(SEGDEF), pfSym);
|
||
seg_ptr = (WORD)SEGDEF.nxt_seg;
|
||
fread(buf, 1, SEGDEF.nam_len, pfSym);
|
||
buf[SEGDEF.nam_len] = '\0';
|
||
if (strcmpi(buf, szSegment) == 0)
|
||
{
|
||
fclose(pfSym);
|
||
return i;
|
||
}
|
||
i++;
|
||
}
|
||
while (seg_ptr && seg_ptr != fstseg_ptr);
|
||
fclose(pfSym);
|
||
return -2;
|
||
}
|
||
|
||
|
||
int GetSymbolString(pchOut, stModule, segno, offset)
|
||
BYTE *pchOut; /* output buffer */
|
||
BYTE stModule[]; /* module name */
|
||
WORD segno; /* segment number */
|
||
WORD offset; /* offset into segment */
|
||
{
|
||
int cch;
|
||
register int i;
|
||
register BYTE *pch;
|
||
FILE *pfSym;
|
||
WORD seg_ptr;
|
||
long symPos1, symPos2;
|
||
struct mapdef MAPDEF;
|
||
struct mapend MAPEND;
|
||
struct segdef SEGDEF;
|
||
struct symdef SYMDEF;
|
||
BYTE *htoa();
|
||
register int pathcnt;
|
||
char symfile[65];
|
||
int len;
|
||
|
||
|
||
pch = stModule;
|
||
|
||
cch = *pch++;
|
||
pch = (BYTE *) memcpy(pchOut, pch, cch) + cch;
|
||
|
||
if((len = strlen(pchOut)) < 2)
|
||
return (-1);
|
||
|
||
|
||
pch[0] = '.';
|
||
pch[1] = 'S';
|
||
pch[2] = 'Y';
|
||
pch[3] = 'M';
|
||
pch[4] = 0;
|
||
|
||
if (bSymPath)
|
||
{
|
||
for (pathcnt=0; pathcnt <num_paths; pathcnt++)
|
||
{
|
||
strcpy(symfile, path_table[pathcnt]);
|
||
strcat(symfile, "\\");
|
||
strcat(symfile, pchOut);
|
||
|
||
if (pfSym = fopen(symfile, "rb"))
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
pfSym = fopen(pchOut, "rb");
|
||
|
||
|
||
/* If symbol file not found, insert/append () around name */
|
||
if (pfSym == NULL)
|
||
{
|
||
pch = stModule;
|
||
cch = *pch++;
|
||
pch = (BYTE *) memcpy(pchOut+1, pch, cch) + cch;
|
||
*pchOut = '(';
|
||
*pch++ = ')';
|
||
if (offset != 0xFFFF)
|
||
*pch++ = '\t';
|
||
*pch = 0;
|
||
return(-1);
|
||
}
|
||
|
||
fread(&MAPDEF, 1, sizeof(MAPDEF), pfSym);
|
||
|
||
*pch++ = '!';
|
||
if (segno == 0xFF)
|
||
{
|
||
*pch++ = 'R';
|
||
*pch++ = 'E';
|
||
*pch++ = 'S';
|
||
*pch++ = 'O';
|
||
*pch++ = 'U';
|
||
*pch++ = 'R';
|
||
*pch++ = 'C';
|
||
*pch++ = 'E';
|
||
*pch = 0;
|
||
fclose(pfSym);
|
||
return(1);
|
||
}
|
||
|
||
if (segno >= MAPDEF.seg_cnt)
|
||
goto lbNoSeg;
|
||
|
||
seg_ptr = (WORD)MAPDEF.seg_ptr;
|
||
fseek(pfSym, (long)-sizeof(MAPEND), 2);
|
||
fread(&MAPEND, 1, sizeof(MAPEND), pfSym);
|
||
if (MAPEND.ver != 3)
|
||
{
|
||
|
||
lbNoSeg:
|
||
pch = htoa(pch, segno);
|
||
*pch = 0;
|
||
if (offset != 0xFFFF)
|
||
{
|
||
*pch++ = '\t';
|
||
pch = htoa(pch, offset);
|
||
*pch = 0;
|
||
}
|
||
fclose(pfSym);
|
||
return(-2);
|
||
}
|
||
i = segno+1;
|
||
while (i--)
|
||
{
|
||
if (MAPEND.rel >= 10)
|
||
fseek(pfSym, (long)(seg_ptr * 16), 0);
|
||
else
|
||
fseek(pfSym, (long)seg_ptr, 0);
|
||
fread(&SEGDEF, 1, sizeof(SEGDEF), pfSym);
|
||
seg_ptr = (WORD)SEGDEF.nxt_seg;
|
||
}
|
||
fread(pch, 1, (int)((BYTE)SEGDEF.nam_len), pfSym);
|
||
|
||
pch += SEGDEF.nam_len;
|
||
*pch = 0;
|
||
if (offset == 0xFFFF)
|
||
{
|
||
fclose(pfSym);
|
||
return(1);
|
||
}
|
||
*pch++ = '\t';
|
||
|
||
i = (WORD)SEGDEF.sym_cnt;
|
||
if (i == 0)
|
||
goto lbNoSym;
|
||
symPos1 = 0;
|
||
while (i--)
|
||
{
|
||
symPos2 = symPos1;
|
||
symPos1 = ftell(pfSym);
|
||
fread(&SYMDEF, 1, sizeof(SYMDEF), pfSym);
|
||
if (i == 0 || (WORD)SYMDEF.sym_val > offset)
|
||
{
|
||
if ((WORD)SYMDEF.sym_val > offset)
|
||
{
|
||
if (symPos2 == 0)
|
||
goto lbNoSym;
|
||
fseek(pfSym, (long)symPos2, 0);
|
||
fread(&SYMDEF, 1, sizeof(SYMDEF), pfSym);
|
||
}
|
||
fread(pch, 1, (int)((BYTE)SYMDEF.nam_len), pfSym);
|
||
pch += SYMDEF.nam_len;
|
||
if ((WORD)SYMDEF.sym_val < offset)
|
||
{
|
||
*pch++ = '+';
|
||
pch = htoa(pch, offset - SYMDEF.sym_val);
|
||
}
|
||
*pch = 0;
|
||
fclose(pfSym);
|
||
return(1);
|
||
}
|
||
fseek(pfSym, (long)((BYTE)SYMDEF.nam_len), 1);
|
||
}
|
||
lbNoSym:
|
||
pch = htoa(pch, offset);
|
||
*pch = 0;
|
||
fclose(pfSym);
|
||
return(0);
|
||
}
|
||
|
||
BYTE *htoa( s, w ) /* Hexadecimal to ASCII */
|
||
register BYTE *s;
|
||
WORD w;
|
||
{
|
||
register int i;
|
||
char c;
|
||
|
||
i = 4;
|
||
s += i;
|
||
while (i--)
|
||
{
|
||
c = (char)(w & (WORD)0xF);
|
||
w >>= 4;
|
||
if (c > 9)
|
||
c += 'A' - 10;
|
||
else
|
||
c += '0';
|
||
*--s = c;
|
||
}
|
||
|
||
return s+4;
|
||
}
|
||
|