home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
prgramer
/
showexe
/
showexe.c
next >
Wrap
Text File
|
1988-12-07
|
18KB
|
576 lines
/*
* SHOWEXE displays information about the EXE file named on the
* command line. It can handle both the DOS and the OS/2 formats.
* If output is not redirected, it pauses after each section.
* Written by David A. Schmitt.
*/
#include <stdio.h>
extern far pascal VioScrollUp();
extern far pascal VioWrtCharStr();
extern far pascal VioWrtNAttr();
extern char *malloc();
extern void pause();
extern void cls();
/**
*
* Old executable header, used by DOS
*
*/
struct EXE_DOS
{
unsigned short e_magic; /* magic number 0x5A4D */
unsigned short e_cblp; /* bytes in last page */
unsigned short e_cp; /* 512-byte pages in file */
unsigned short e_crlc; /* number of relocations */
unsigned short e_cparhdr; /* paragraphs in header */
unsigned short e_minalloc; /* minimum extra paragraphs */
unsigned short e_maxalloc; /* maximum extra paragraphs */
unsigned short e_ss; /* initial SS value */
unsigned short e_sp; /* initial SP value */
unsigned short e_csum; /* checksum */
unsigned short e_ip; /* initial IP value */
unsigned short e_cs; /* initial CS value */
unsigned short e_lfarlc; /* file address of reloc table */
unsigned short e_ovno; /* overlay number */
unsigned short e_res1[4]; /* reserved */
unsigned short e_oemid; /* OEM identifier */
unsigned short e_oeminfo; /* OEM information */
unsigned short e_res2[10]; /* reserved */
unsigned long e_lfanew; /* file address of new header */
};
/**
*
* Structure of DOS relocation items
*
*/
struct REL
{
unsigned short offset;
unsigned short segment;
};
/**/
/**
*
* New executable header, used by OS/2
*
*/
struct EXE_OS2
{
unsigned short ne_magic; /* magic number 0x454E */
unsigned char ne_ver; /* version number */
unsigned char ne_rev; /* revision number */
unsigned short ne_enttab; /* offset of entry table*/
unsigned short ne_cbenttab; /* # of bytes in entry table*/
long ne_crc; /* checksum */
unsigned short ne_flags; /* miscellaneous flags */
unsigned short ne_autodata; /* auto data segment number */
unsigned short ne_heap; /* initial heap allocation */
unsigned short ne_stack; /* initial stack allocation */
unsigned short ne_ip; /* initial IP offset */
unsigned short ne_cs; /* initial CS segment number*/
unsigned short ne_sp; /* initial SP offset */
unsigned short ne_ss; /* initial SS segment number*/
unsigned short ne_cseg; /* number of segments */
unsigned short ne_cmod; /* number of module references */
unsigned short ne_cbnrestab; /* size of non-resident names*/
unsigned short ne_segtab; /* segment table offset */
unsigned short ne_rsrctab; /* resource table offset */
unsigned short ne_restab; /* resident name table offset */
unsigned short ne_modtab; /* module reference table offset*/
unsigned short ne_imptab; /* import name table offset */
unsigned long ne_nrestab; /* non-resident name tab offset */
unsigned short ne_cmovent; /* number of movable entries */
unsigned short ne_align; /* segment alignment shift count*/
unsigned short ne_cres; /* number of resource entries */
char resv[10]; /* reserved */
};
/**
*
* Definition of bits in ne_flags
*
*/
#define NENOTP 0x8000 /* not a process */
#define NEIERR 0x2000 /* errors in image */
#define NEFLTP 0x0080 /* floating point instructions */
#define NEI386 0x0040 /* 80386 instructions */
#define NEI286 0x0020 /* 80286 instructions */
#define NEI086 0x0010 /* 8086 instructions */
#define NEPROT 0x0008 /* protected mode only */
#define NEPPLI 0x0004 /* per-process library initialization*/
#define NEINST 0x0002 /* per-instance data */
#define NESOLO 0x0001 /* solo data */
/**
*
* Structure of segment table entries
*
*/
struct SEG
{
unsigned short ns_sector; /* starting sector */
unsigned short ns_cbseg; /* segment size (in file)*/
unsigned short ns_flags; /* segment flags */
unsigned short ns_minalloc; /* minimum size in bytes*/
};
/**
*
* Definition of bits in ns_flags
*
*/
#define NSTYPE 0x0007 /* segment type mask, types are... */
#define NSCODE 0 /* 0 for code segment */
#define NSDATA 1 /* 1 for data segment */
#define NSITER 0x0008 /* iterated segment */
#define NSMOVE 0x0010 /* movable segment */
#define NSPURE 0x0020 /* pure segment */
#define NSPRELOAD 0x0040 /* preloaded segment */
#define NSEXRD 0x0080 /* code segment: execute only*/
/* data segment: read only */
#define NSRELOC 0x0100 /* relocation information present */
#define NSCONFORM 0x0200 /* conforming segment */
#define NSDPL 0x0c00 /* 80286 DPL bits */
#define SHIFTDPL 10 /* shift factor for NSDPL */
#define NSDISCARD 0x1000 /* discardable segment */
#define NS32BIT 0x2000 /* 32-bit segment */
#define NSHUGE 0x4000 /* huge memory segment */
/**/
/**
*
* name main -- main program
*
* synopsis main(argc,argv)
* int argc; number of arguments
* char *argv[]; argument pointer array
*
* description:
* This is the main program that displays EXE file information.
* Upon entry, argc should be 2, and argv[1] should point to
* the EXE file name, which must include the .EXE extension.
*
* The program sends its output to stdout, which can be
* redirected to somewhere other than the system console.
* Error output is sent to stderr, and when an error occurs
* the program exits with a completion code of 1.
**/
main(argc,argv)
int argc;
char *argv[];
{
FILE *fp;
unsigned char *p;
int i,j,k;
union
{
short w;
char b[2];
} word;
struct EXE_DOS oldexe;
struct REL rel;
struct EXE_OS2 newexe;
struct SEG seg;
char b[256];
/*
*
* Check file argument, open file, and read old EXE header
*
*/
if(argc < 2)
{
fprintf(stderr,"No EXE file specified\n");
exit(1);
}
fp = fopen(argv[1],"rb");
if(fp == NULL)
{
fprintf(stderr,"Can't open \"%s\"\n",argv[1]);
exit(1);
}
if(fread((char *)(&oldexe),sizeof(struct EXE_DOS),1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
if(oldexe.e_magic != 0x5a4d)
{
fprintf(stderr,"\"%s\" is not an EXE file\n",argv[1]);
exit(1);
}
/*
*
* Print DOS header information
*
*/
cls();
printf("DOS EXE header information for \"%s\"...\n\n",argv[1]);
printf("%40s: %u\n","Number of bytes in header",oldexe.e_cparhdr*16);
printf("%40s: %u\n","Number of 512-byte pages",oldexe.e_cp);
printf("%40s: %u\n","Number of bytes in last page",oldexe.e_cblp);
printf("%40s: %04XH\n","Checksum",oldexe.e_csum);
printf("%40s: %04XH\n","Minimum number of extra paragraphs",
oldexe.e_minalloc);
printf("%40s: %04XH\n","Maximum number of extra paragraphs",
oldexe.e_maxalloc);
printf("%40s: %04X:%04X\n","Starting address",oldexe.e_cs,
oldexe.e_ip);
printf("%40s: %04X:%04X\n","Stack address",oldexe.e_ss,
oldexe.e_sp);
printf("%40s: %u\n","Overlay number",oldexe.e_ovno);
printf("%40s: %04XH\n","OEM identifier",oldexe.e_oemid);
printf("%40s: %04XH\n","OEM information",oldexe.e_oeminfo);
printf("%40s: %u\n","Number of relocations",oldexe.e_crlc);
/*
*
* Print DOS relocation table
*
*/
if(oldexe.e_crlc)
{
pause(fp);
printf("\n\nRelocation table at file offset %04XH...\n",
oldexe.e_lfarlc);
if(fseek(fp,(long)oldexe.e_lfarlc,0))
{
fprintf(stderr,"Can't seek to %04XH in \"%s\"\n",
oldexe.e_lfarlc,argv[1]);
exit(1);
}
for(i = 1; i <= oldexe.e_crlc; i++)
{
if(fread((char *)(&rel),sizeof(struct REL),1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf("%04X:%04X ",rel.segment,rel.offset);
if((i % 6) == 0) printf("\n");
}
}
/*
*
* Check if OS/2 executable, and terminate if not.
* Otherwise, read in the OS/2 header.
*
*/
if(oldexe.e_lfanew == 0) exit(0);
pause();
printf("\n\nOS/2 EXE header information at %04XH...\n\n",
oldexe.e_lfanew);
if(fseek(fp,(long)oldexe.e_lfanew,0))
{
fprintf(stderr,"Can't seek to %04XH in \"%s\"\n",
oldexe.e_lfanew,argv[1]);
exit(1);
}
if(fread((char *)(&newexe),sizeof(struct EXE_OS2),1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
if(newexe.ne_magic != 0x454e)
{
fprintf(stderr,"\"%s\" is not an OS/2 EXE file\n",argv[1]);
exit(1);
}
/*
*
* Print basic information from new EXE header
*
*/
printf("%40s: %08lXH\n","Checksum",newexe.ne_crc);
printf("%40s: %u\n","Version number",newexe.ne_ver);
printf("%40s: %u\n","Revision number",newexe.ne_rev);
printf("%40s: %u\n","Number of segments",newexe.ne_cseg);
printf("%40s: %04X:%04X\n","Starting address",
newexe.ne_cs,newexe.ne_ip);
printf("%40s: %04X:%04X\n","Stack address",newexe.ne_ss,newexe.ne_sp);
printf("%40s: %u\n","Automatic data segment number",
newexe.ne_autodata);
printf("%40s: %04XH\n","Initial heap allocation in auto data",
newexe.ne_heap);
printf("%40s: %04XH\n","Initial stack allocation in auto data",
newexe.ne_stack);
printf("%40s: %04XH\n","Flags",newexe.ne_flags);
printf("%40s? %s\n","Program or library",
(newexe.ne_flags & NENOTP) ? "LIBRARY" : "PROGRAM");
printf("%40s? %s\n","Errors in image",
(newexe.ne_flags & NEIERR) ? "YES" : "NO");
printf("%40s? %s\n","Floating point instructions",
(newexe.ne_flags & NEFLTP) ? "YES" : "NO");
printf("%40s? %s\n","80386 instructions",
(newexe.ne_flags & NEI386) ? "YES" : "NO");
printf("%40s? %s\n","80286 instructions",
(newexe.ne_flags & NEI286) ? "YES" : "NO");
printf("%40s? %s\n","8086 instructions",
(newexe.ne_flags & NEI086) ? "YES" : "NO");
printf("%40s? %s\n","Protected mode only",
(newexe.ne_flags & NEPROT) ? "YES" : "NO");
printf("%40s? %s\n","Per-process initialization",
(newexe.ne_flags & NEPPLI) ? "YES" : "NO");
printf("%40s? %s\n","Per-instance data",
(newexe.ne_flags & NEINST) ? "YES" : "NO");
printf("%40s? %s\n","Solo data",
(newexe.ne_flags & NESOLO) ? "YES" : "NO");
pause();
/*
*
* Print segment table
*
*/
printf("\n\nSegment table at %08lXH (%08lXH + %04XH)...\n\n",
(long)(oldexe.e_lfanew+newexe.ne_segtab),
oldexe.e_lfanew,newexe.ne_segtab);
printf(" FILE FILE MEMORY\n");
printf("SEG ADDR SIZE FLAGS SIZE\n\n");
if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_segtab),0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
(long)(oldexe.e_lfanew+newexe.ne_segtab),argv[1]);
exit(1);
}
for(i = 1; i <= newexe.ne_cseg; i++)
{
if(fread((char *)(&seg),sizeof(struct SEG),1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf("%3d %04X %04X %04X %04X %s\n",i,
seg.ns_sector,seg.ns_cbseg,seg.ns_flags,seg.ns_minalloc,
(seg.ns_flags & NSTYPE) ? "Data" : "Code");
}
pause();
/*
*
* Print imported name table
*
*/
if(newexe.ne_imptab)
{
printf("\n\n");
printf("Imported Name Table at %08lXH (%08lXH + %04XH)...\n\n",
(long)(oldexe.e_lfanew+newexe.ne_imptab),
oldexe.e_lfanew,newexe.ne_imptab);
if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_imptab + 1),0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
(long)(oldexe.e_lfanew+newexe.ne_imptab + 1),argv[1]);
exit(1);
}
printf("INDEX NAME\n");
printf("----- ----\n");
for(i = newexe.ne_imptab+1; i < newexe.ne_enttab; i += j+1)
{
j = fgetc(fp);
if(j == EOF)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
if(j == 0) break;
if(fread(b,j,1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
b[j] = '\0';
printf(" %04x %s\n",(i-newexe.ne_imptab),b);
}
pause();
}
/*
*
* Print Module Reference Table
*
*/
if(newexe.ne_cmod)
{
printf("\n\n");
printf("Module Reference Table at %08lXH (%08lXH + %04XH)...\n\n",
(long)(oldexe.e_lfanew+newexe.ne_modtab),
oldexe.e_lfanew,newexe.ne_modtab);
if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_modtab),0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
(long)(oldexe.e_lfanew+newexe.ne_modtab),argv[1]);
exit(1);
}
printf("MODULE INDEX\n");
printf("------ -----\n");
for(i = 1; i <= newexe.ne_cmod; i++)
{
if(fread((char *)(&j),2,1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf(" %04X %04X\n",i,j);
}
pause();
}
/*
*
* Print Resident Name Table
*
*/
if(newexe.ne_restab)
{
printf("\n\n");
printf("Resident Name Table at %08lXH (%08lXH + %04XH)...\n\n",
(long)(oldexe.e_lfanew+newexe.ne_restab),
oldexe.e_lfanew,newexe.ne_restab);
if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_restab),0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
(long)(oldexe.e_lfanew+newexe.ne_restab),argv[1]);
exit(1);
}
printf("ORDINAL NAME\n");
printf("------- ----\n");
while(i = fgetc(fp))
{
if((i == EOF) || (fread(b,i,1,fp) != 1))
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
b[i] = '\0';
if(fread((char *)(&j),2,1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf(" %04X %s\n",j,b);
}
pause();
}
/*
*
* Print Non-resident Name Table
*
*/
if(newexe.ne_nrestab)
{
printf("\n\nNon-resident Name Table at %08lXH...\n\n",
newexe.ne_nrestab);
if(fseek(fp,newexe.ne_nrestab,0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
newexe.ne_nrestab,argv[1]);
exit(1);
}
printf("ORDINAL NAME\n");
printf("------- ----\n");
while(i = fgetc(fp))
{
if((i == EOF) || (fread(b,i,1,fp) != 1))
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
b[i] = '\0';
if(fread((char *)(&j),2,1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf(" %04X %s\n",j,b);
}
pause();
}
/*
*
* Print entry table
*
*/
if(newexe.ne_cbenttab)
{
printf("\n\nEntry table at %08lXH (%08lXH + %04XH)...\n\n",
(long)(oldexe.e_lfanew+newexe.ne_enttab),
oldexe.e_lfanew,newexe.ne_enttab);
if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_enttab),0))
{
fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
(long)(oldexe.e_lfanew+newexe.ne_enttab),argv[1]);
exit(1);
}
p = malloc(newexe.ne_cbenttab);
if(p == NULL)
{
fprintf(stderr,"Out of memory\n");
exit(1);
}
if(fread(p,newexe.ne_cbenttab,1,fp) != 1)
{
fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
exit(1);
}
printf("SEG OFFSET FLAGS\n");
printf("--- ------ -----\n");
for(i = 0; i < newexe.ne_cbenttab; )
{
j = p[i++];
k = p[i++];
if(k) while(j-- > 0)
{
if(k != 255)
{
word.b[0] = p[i+1];
word.b[1] = p[i+2];
printf("%3d %04X %02X\n",k,word.w,p[i]);
i += 3;
}
else
{
word.b[0] = p[i+4];
word.b[1] = p[i+5];
printf("%3d %04X %02X\n",p[i+3],word.w,p[i]);
i += 6;
}
}
}
}
}
/**/
/**
*
* name pause
*
* synopsis pause();
*
* description This function checks if the standard output file
* is the system console. If so, it displays a pause message
* and then waits until the user presses a key.
*
**/
void pause()
{
char reverse = 0x70;
static char prompt[] = "Press any key to continue";
if(isatty(fileno(stdout)))
{
VioWrtNAttr((char far *)(&reverse),80,24,0,0);
VioWrtCharStr((char far *)prompt,sizeof(prompt)-1,24,0,0);
getch();
cls();
}
}
/**
*
* name cls -- clear the screen
*
* synopsis cls();
*
* description This function clears the screen by calling the
* VioScrollUp function in a special way. However,
* it has not be generalized to work with display
* modes using more than 25 lines of 80 characters each.
*
**/
void cls()
{
short fill = 0x0720;
VioScrollUp(0,0,24,79,-1,(short far *)(&fill),0);
}