|
|
/* 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; }
|