home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / SHOWEXE.ZIP / SHOWEXE.C next >
Text File  |  1988-12-07  |  18KB  |  576 lines

  1. /*
  2.  * SHOWEXE displays information about the EXE file named on the
  3.  * command line.  It can handle both the DOS and the OS/2 formats.  
  4.  * If output is not redirected, it pauses after each section.
  5.  * Written by David A. Schmitt.
  6.  */ 
  7. #include <stdio.h>
  8. extern far pascal VioScrollUp();
  9. extern far pascal VioWrtCharStr();
  10. extern far pascal VioWrtNAttr();
  11. extern char *malloc();
  12.  
  13. extern void pause();
  14. extern void cls();
  15. /**
  16. *
  17. * Old executable header, used by DOS
  18. *
  19. */
  20. struct EXE_DOS
  21.    {
  22.    unsigned short e_magic;    /* magic number 0x5A4D     */
  23.    unsigned short e_cblp;     /* bytes in last page      */
  24.    unsigned short e_cp;    /* 512-byte pages in file  */
  25.    unsigned short e_crlc;     /* number of relocations   */
  26.    unsigned short e_cparhdr;  /* paragraphs in header    */
  27.    unsigned short e_minalloc; /* minimum extra paragraphs   */
  28.    unsigned short e_maxalloc; /* maximum extra paragraphs   */
  29.    unsigned short e_ss;    /* initial SS value     */
  30.    unsigned short e_sp;    /* initial SP value     */
  31.    unsigned short e_csum;     /* checksum          */
  32.    unsigned short e_ip;    /* initial IP value     */
  33.    unsigned short e_cs;    /* initial CS value     */ 
  34.    unsigned short e_lfarlc;   /* file address of reloc table   */
  35.    unsigned short e_ovno;     /* overlay number       */
  36.    unsigned short e_res1[4];  /* reserved          */
  37.    unsigned short e_oemid;    /* OEM identifier       */
  38.    unsigned short e_oeminfo;  /* OEM information      */
  39.    unsigned short e_res2[10]; /* reserved          */
  40.    unsigned long  e_lfanew;   /* file address of new header    */
  41.    };
  42. /**
  43. *
  44. * Structure of DOS relocation items
  45. *
  46. */
  47. struct REL
  48.    {
  49.    unsigned short offset;
  50.    unsigned short segment;
  51.    };
  52. /**/
  53. /**
  54. *
  55. * New executable header, used by OS/2 
  56. *
  57. */
  58. struct EXE_OS2
  59.    {
  60.    unsigned short ne_magic;   /* magic number 0x454E  */
  61.    unsigned char ne_ver;      /* version number    */
  62.    unsigned char ne_rev;      /* revision number      */
  63.    unsigned short ne_enttab;  /* offset of entry table*/
  64.    unsigned short ne_cbenttab;   /* # of bytes in entry table*/
  65.    long ne_crc;            /* checksum          */
  66.    unsigned short ne_flags;   /* miscellaneous flags     */
  67.    unsigned short ne_autodata;   /* auto data segment number   */
  68.    unsigned short ne_heap;    /* initial heap allocation */
  69.    unsigned short ne_stack;   /* initial stack allocation   */
  70.    unsigned short ne_ip;      /* initial IP offset    */
  71.    unsigned short ne_cs;      /* initial CS segment number*/
  72.    unsigned short ne_sp;      /* initial SP offset    */
  73.    unsigned short ne_ss;      /* initial SS segment number*/
  74.    unsigned short ne_cseg;    /* number of segments      */
  75.    unsigned short ne_cmod;    /* number of module references   */
  76.    unsigned short ne_cbnrestab;  /* size of non-resident names*/
  77.    unsigned short ne_segtab;  /* segment table offset    */
  78.    unsigned short ne_rsrctab; /* resource table offset   */
  79.    unsigned short ne_restab;  /* resident name table offset */
  80.    unsigned short ne_modtab;  /* module reference table offset*/
  81.    unsigned short ne_imptab;  /* import name table offset   */
  82.    unsigned long ne_nrestab;  /* non-resident name tab offset  */
  83.    unsigned short ne_cmovent; /* number of movable entries  */
  84.    unsigned short ne_align;   /* segment alignment shift count*/
  85.    unsigned short ne_cres;    /* number of resource entries */
  86.    char resv[10];          /* reserved       */
  87.    };
  88. /**
  89.  *
  90.  * Definition of bits in ne_flags
  91.  *
  92.  */
  93. #define NENOTP 0x8000      /* not a process        */
  94. #define NEIERR 0x2000      /* errors in image         */
  95. #define NEFLTP 0x0080      /* floating point instructions */
  96. #define NEI386 0x0040      /* 80386 instructions      */
  97. #define NEI286 0x0020      /* 80286 instructions      */
  98. #define NEI086 0x0010      /* 8086 instructions       */
  99. #define NEPROT 0x0008      /* protected mode only     */
  100. #define NEPPLI 0x0004      /* per-process library initialization*/
  101. #define NEINST 0x0002      /* per-instance data       */
  102. #define NESOLO 0x0001      /* solo data            */
  103. /**
  104.  *
  105.  * Structure of segment table entries
  106.  *
  107.  */
  108. struct SEG
  109.    {
  110.    unsigned short ns_sector;  /* starting sector      */
  111.    unsigned short ns_cbseg;   /* segment size (in file)*/
  112.    unsigned short ns_flags;   /* segment flags     */
  113.    unsigned short ns_minalloc;   /* minimum size in bytes*/
  114.    };
  115. /**
  116. *
  117. * Definition of bits in ns_flags
  118. *
  119. */
  120. #define NSTYPE 0x0007      /* segment type mask, types are...  */
  121. #define NSCODE 0        /*    0 for code segment   */
  122. #define NSDATA 1        /*    1 for data segment   */
  123. #define NSITER 0x0008      /* iterated segment        */
  124. #define NSMOVE 0x0010      /* movable segment         */
  125. #define NSPURE 0x0020      /* pure segment            */
  126. #define NSPRELOAD 0x0040   /* preloaded segment    */
  127. #define NSEXRD 0x0080      /* code segment: execute only*/
  128.                      /* data segment: read only */
  129. #define NSRELOC 0x0100     /* relocation information present   */
  130. #define NSCONFORM 0x0200   /* conforming segment      */
  131. #define NSDPL 0x0c00    /* 80286 DPL bits       */
  132. #define SHIFTDPL 10        /* shift factor for NSDPL  */
  133. #define NSDISCARD 0x1000   /* discardable segment     */
  134. #define NS32BIT 0x2000     /* 32-bit segment       */
  135. #define NSHUGE 0x4000      /* huge memory segment     */
  136. /**/
  137. /**
  138. *
  139. * name      main -- main program
  140. *
  141. * synopsis  main(argc,argv)
  142. *     int argc;      number of arguments
  143. *     char *argv[];     argument pointer array
  144. *
  145. * description:
  146. * This is the main program that displays EXE file information.
  147. *     Upon entry, argc should be 2, and argv[1] should point to
  148. *     the EXE file name, which must include the .EXE extension.
  149. *
  150. *     The program sends its output to stdout, which can be
  151. *     redirected to somewhere other than the system console.
  152. *     Error output is sent to stderr, and when an error occurs
  153. *     the program exits with a completion code of 1.
  154. **/
  155. main(argc,argv)
  156. int argc;
  157. char *argv[];
  158. {
  159. FILE *fp;
  160. unsigned char *p;
  161. int i,j,k;
  162. union 
  163.    {
  164.    short w;
  165.    char b[2];
  166.    } word;
  167. struct EXE_DOS oldexe;
  168. struct REL rel;
  169. struct EXE_OS2 newexe;
  170. struct SEG seg;
  171. char b[256];
  172. /*
  173. *
  174. * Check file argument, open file, and read old EXE header
  175. *
  176. */
  177. if(argc < 2)
  178.    {
  179.    fprintf(stderr,"No EXE file specified\n");
  180.    exit(1);
  181.    }
  182. fp = fopen(argv[1],"rb");
  183. if(fp == NULL)
  184.    {
  185.    fprintf(stderr,"Can't open \"%s\"\n",argv[1]);
  186.    exit(1);
  187.    }
  188. if(fread((char *)(&oldexe),sizeof(struct EXE_DOS),1,fp) != 1)
  189.    {
  190.    fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  191.    exit(1);
  192.    }
  193. if(oldexe.e_magic != 0x5a4d)
  194.    {
  195.    fprintf(stderr,"\"%s\" is not an EXE file\n",argv[1]);
  196.    exit(1);
  197.    }
  198. /*
  199. *
  200. * Print DOS header information
  201. *
  202. */
  203. cls();
  204. printf("DOS EXE header information for \"%s\"...\n\n",argv[1]);
  205. printf("%40s: %u\n","Number of bytes in header",oldexe.e_cparhdr*16);
  206. printf("%40s: %u\n","Number of 512-byte pages",oldexe.e_cp);
  207. printf("%40s: %u\n","Number of bytes in last page",oldexe.e_cblp);
  208. printf("%40s: %04XH\n","Checksum",oldexe.e_csum);
  209. printf("%40s: %04XH\n","Minimum number of extra paragraphs",
  210.         oldexe.e_minalloc);
  211. printf("%40s: %04XH\n","Maximum number of extra paragraphs",
  212.         oldexe.e_maxalloc);
  213. printf("%40s: %04X:%04X\n","Starting address",oldexe.e_cs,
  214.         oldexe.e_ip);
  215. printf("%40s: %04X:%04X\n","Stack address",oldexe.e_ss,
  216.         oldexe.e_sp);
  217. printf("%40s: %u\n","Overlay number",oldexe.e_ovno);
  218. printf("%40s: %04XH\n","OEM identifier",oldexe.e_oemid);
  219. printf("%40s: %04XH\n","OEM information",oldexe.e_oeminfo);
  220. printf("%40s: %u\n","Number of relocations",oldexe.e_crlc);
  221. /*
  222. *
  223. * Print DOS relocation table
  224. *
  225. */
  226. if(oldexe.e_crlc)
  227.    {
  228.    pause(fp);
  229.    printf("\n\nRelocation table at file offset %04XH...\n",
  230.       oldexe.e_lfarlc);
  231.    if(fseek(fp,(long)oldexe.e_lfarlc,0))
  232.       {
  233.       fprintf(stderr,"Can't seek to %04XH in \"%s\"\n",
  234.          oldexe.e_lfarlc,argv[1]);
  235.       exit(1);
  236.       }
  237.    for(i = 1; i <= oldexe.e_crlc; i++)
  238.       {
  239.       if(fread((char *)(&rel),sizeof(struct REL),1,fp) != 1)
  240.          {
  241.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  242.          exit(1);
  243.          }
  244.       printf("%04X:%04X  ",rel.segment,rel.offset);
  245.       if((i % 6) == 0) printf("\n");
  246.       }
  247.    }
  248. /*
  249.  *
  250.  * Check if OS/2 executable, and terminate if not.  
  251.  * Otherwise, read in the OS/2 header.
  252.  *
  253.  */
  254. if(oldexe.e_lfanew == 0) exit(0);
  255. pause();
  256. printf("\n\nOS/2 EXE header information at %04XH...\n\n",
  257.         oldexe.e_lfanew);
  258. if(fseek(fp,(long)oldexe.e_lfanew,0))
  259.    {
  260.    fprintf(stderr,"Can't seek to %04XH in \"%s\"\n",
  261.       oldexe.e_lfanew,argv[1]);
  262.    exit(1);
  263.    }
  264. if(fread((char *)(&newexe),sizeof(struct EXE_OS2),1,fp) != 1)
  265.    {
  266.    fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  267.    exit(1);
  268.    }
  269. if(newexe.ne_magic != 0x454e)
  270.    {
  271.    fprintf(stderr,"\"%s\" is not an OS/2 EXE file\n",argv[1]);
  272.    exit(1);
  273.    }
  274. /*
  275. *
  276. * Print basic information from new EXE header
  277. *
  278. */
  279. printf("%40s: %08lXH\n","Checksum",newexe.ne_crc);
  280. printf("%40s: %u\n","Version number",newexe.ne_ver);
  281. printf("%40s: %u\n","Revision number",newexe.ne_rev);
  282. printf("%40s: %u\n","Number of segments",newexe.ne_cseg);
  283. printf("%40s: %04X:%04X\n","Starting address",
  284.         newexe.ne_cs,newexe.ne_ip);
  285. printf("%40s: %04X:%04X\n","Stack address",newexe.ne_ss,newexe.ne_sp);
  286. printf("%40s: %u\n","Automatic data segment number",
  287.         newexe.ne_autodata);
  288. printf("%40s: %04XH\n","Initial heap allocation in auto data",
  289.         newexe.ne_heap);
  290. printf("%40s: %04XH\n","Initial stack allocation in auto data",
  291.         newexe.ne_stack);
  292. printf("%40s: %04XH\n","Flags",newexe.ne_flags);
  293. printf("%40s? %s\n","Program or library",
  294.    (newexe.ne_flags & NENOTP) ? "LIBRARY" : "PROGRAM");
  295. printf("%40s? %s\n","Errors in image",
  296.    (newexe.ne_flags & NEIERR) ? "YES" : "NO");
  297. printf("%40s? %s\n","Floating point instructions", 
  298.    (newexe.ne_flags & NEFLTP) ? "YES" : "NO");
  299. printf("%40s? %s\n","80386 instructions",
  300.    (newexe.ne_flags & NEI386) ? "YES" : "NO");
  301. printf("%40s? %s\n","80286 instructions",
  302.    (newexe.ne_flags & NEI286) ? "YES" : "NO");
  303. printf("%40s? %s\n","8086 instructions",
  304.    (newexe.ne_flags & NEI086) ? "YES" : "NO");
  305. printf("%40s? %s\n","Protected mode only",
  306.    (newexe.ne_flags & NEPROT) ? "YES" : "NO");
  307. printf("%40s? %s\n","Per-process initialization",
  308.    (newexe.ne_flags & NEPPLI) ? "YES" : "NO");
  309. printf("%40s? %s\n","Per-instance data",
  310.    (newexe.ne_flags & NEINST) ? "YES" : "NO");
  311. printf("%40s? %s\n","Solo data",
  312.    (newexe.ne_flags & NESOLO) ? "YES" : "NO");
  313. pause();
  314. /*
  315. *
  316. * Print segment table
  317. *
  318. */
  319. printf("\n\nSegment table at %08lXH (%08lXH + %04XH)...\n\n",
  320.       (long)(oldexe.e_lfanew+newexe.ne_segtab),
  321.       oldexe.e_lfanew,newexe.ne_segtab);
  322. printf("     FILE  FILE         MEMORY\n");
  323. printf("SEG  ADDR  SIZE  FLAGS   SIZE\n\n");
  324. if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_segtab),0))
  325.    {
  326.    fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  327.       (long)(oldexe.e_lfanew+newexe.ne_segtab),argv[1]);
  328.    exit(1);
  329.    }
  330. for(i = 1; i <= newexe.ne_cseg; i++)
  331.    {
  332.    if(fread((char *)(&seg),sizeof(struct SEG),1,fp) != 1)
  333.       {
  334.       fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  335.       exit(1);
  336.       }
  337.    printf("%3d  %04X  %04X  %04X    %04X  %s\n",i,
  338.       seg.ns_sector,seg.ns_cbseg,seg.ns_flags,seg.ns_minalloc,
  339.       (seg.ns_flags & NSTYPE) ? "Data" : "Code");
  340.    }
  341. pause();
  342. /*
  343. *
  344. * Print imported name table
  345. *
  346. */
  347. if(newexe.ne_imptab)
  348.    {
  349.    printf("\n\n");
  350.    printf("Imported Name Table at %08lXH (%08lXH + %04XH)...\n\n",
  351.           (long)(oldexe.e_lfanew+newexe.ne_imptab),
  352.           oldexe.e_lfanew,newexe.ne_imptab);
  353.    if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_imptab + 1),0))
  354.       {
  355.       fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  356.          (long)(oldexe.e_lfanew+newexe.ne_imptab + 1),argv[1]);
  357.       exit(1);
  358.       }
  359.    printf("INDEX  NAME\n");
  360.    printf("-----  ----\n");
  361.    for(i = newexe.ne_imptab+1; i < newexe.ne_enttab; i += j+1)
  362.       {
  363.       j = fgetc(fp);
  364.       if(j == EOF)
  365.          {
  366.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  367.          exit(1);
  368.          }
  369.       if(j == 0) break;
  370.       if(fread(b,j,1,fp) != 1)
  371.          {
  372.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  373.          exit(1);
  374.          }
  375.       b[j] = '\0';
  376.       printf(" %04x  %s\n",(i-newexe.ne_imptab),b);
  377.       }
  378.    pause();
  379.    }
  380. /*
  381. *
  382. * Print Module Reference Table
  383. *
  384. */
  385. if(newexe.ne_cmod)
  386.    {
  387.    printf("\n\n");
  388.    printf("Module Reference Table at %08lXH (%08lXH + %04XH)...\n\n",
  389.          (long)(oldexe.e_lfanew+newexe.ne_modtab),
  390.          oldexe.e_lfanew,newexe.ne_modtab);
  391.    if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_modtab),0))
  392.       {
  393.       fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  394.          (long)(oldexe.e_lfanew+newexe.ne_modtab),argv[1]);
  395.       exit(1);
  396.       }
  397.    printf("MODULE  INDEX\n");
  398.    printf("------  -----\n");
  399.    for(i = 1; i <= newexe.ne_cmod; i++)
  400.       {
  401.       if(fread((char *)(&j),2,1,fp) != 1)
  402.          {
  403.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  404.          exit(1);
  405.          }
  406.       printf(" %04X    %04X\n",i,j);
  407.       }
  408.    pause();
  409.    }  
  410. /*
  411. *
  412. * Print Resident Name Table
  413. *
  414. */
  415. if(newexe.ne_restab)
  416.    {
  417.    printf("\n\n");
  418.    printf("Resident Name Table at %08lXH (%08lXH + %04XH)...\n\n",
  419.           (long)(oldexe.e_lfanew+newexe.ne_restab),
  420.           oldexe.e_lfanew,newexe.ne_restab);
  421.    if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_restab),0))
  422.       {
  423.       fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  424.          (long)(oldexe.e_lfanew+newexe.ne_restab),argv[1]);
  425.       exit(1);
  426.       }
  427.    printf("ORDINAL  NAME\n");
  428.    printf("-------  ----\n");
  429.    while(i = fgetc(fp))
  430.       {
  431.       if((i == EOF) || (fread(b,i,1,fp) != 1))
  432.          {
  433.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  434.          exit(1);
  435.          }
  436.       b[i] = '\0';
  437.       if(fread((char *)(&j),2,1,fp) != 1)
  438.          {
  439.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  440.          exit(1);
  441.          }
  442.       printf("   %04X  %s\n",j,b);
  443.       }
  444.    pause();
  445.    }
  446. /*
  447. *
  448. * Print Non-resident Name Table
  449. *
  450. */
  451. if(newexe.ne_nrestab)
  452.    {
  453.    printf("\n\nNon-resident Name Table at %08lXH...\n\n",
  454.       newexe.ne_nrestab);
  455.    if(fseek(fp,newexe.ne_nrestab,0))
  456.       {
  457.       fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  458.          newexe.ne_nrestab,argv[1]);
  459.       exit(1);
  460.       }
  461.    printf("ORDINAL  NAME\n");
  462.    printf("-------  ----\n");
  463.    while(i = fgetc(fp))
  464.       {
  465.       if((i == EOF) || (fread(b,i,1,fp) != 1))
  466.          {
  467.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  468.          exit(1);
  469.          }
  470.       b[i] = '\0';
  471.       if(fread((char *)(&j),2,1,fp) != 1)
  472.          {
  473.          fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  474.          exit(1);
  475.          }
  476.       printf("   %04X  %s\n",j,b);
  477.       }
  478.    pause();
  479.    }
  480. /*
  481. *
  482. * Print entry table
  483. *
  484. */
  485. if(newexe.ne_cbenttab)
  486.    {
  487.    printf("\n\nEntry table at %08lXH (%08lXH + %04XH)...\n\n",
  488.          (long)(oldexe.e_lfanew+newexe.ne_enttab),
  489.          oldexe.e_lfanew,newexe.ne_enttab);
  490.    if(fseek(fp,(long)(oldexe.e_lfanew + newexe.ne_enttab),0))
  491.       {
  492.       fprintf(stderr,"Can't seek to %08lXH in \"%s\"\n",
  493.              (long)(oldexe.e_lfanew+newexe.ne_enttab),argv[1]);
  494.       exit(1);
  495.       }
  496.    p = malloc(newexe.ne_cbenttab);
  497.    if(p == NULL)
  498.       {
  499.       fprintf(stderr,"Out of memory\n");
  500.       exit(1);
  501.       }
  502.    if(fread(p,newexe.ne_cbenttab,1,fp) != 1)
  503.       {
  504.       fprintf(stderr,"Can't read \"%s\"\n",argv[1]);
  505.       exit(1);
  506.       }
  507.    printf("SEG  OFFSET  FLAGS\n");
  508.    printf("---  ------  -----\n");
  509.    for(i = 0; i < newexe.ne_cbenttab; )
  510.       {
  511.       j = p[i++];
  512.       k = p[i++];
  513.       if(k) while(j-- > 0)
  514.          {
  515.          if(k != 255)
  516.             {
  517.             word.b[0] = p[i+1];
  518.             word.b[1] = p[i+2];
  519.             printf("%3d  %04X    %02X\n",k,word.w,p[i]);
  520.             i += 3;
  521.             }
  522.          else
  523.             {
  524.             word.b[0] = p[i+4];
  525.             word.b[1] = p[i+5];
  526.             printf("%3d  %04X    %02X\n",p[i+3],word.w,p[i]);
  527.             i += 6;
  528.             }
  529.          }
  530.       }
  531.    }
  532. }
  533. /**/
  534. /**
  535. * name      pause
  536. *
  537. * synopsis  pause();
  538. *
  539. * description  This function checks if the standard output file 
  540. *     is the system console.  If so, it displays a pause message
  541. *     and then waits until the user presses a key.
  542. *
  543. **/
  544. void pause()
  545. {
  546. char reverse = 0x70;
  547. static char prompt[] = "Press any key to continue";
  548.  
  549. if(isatty(fileno(stdout)))
  550.    {
  551.    VioWrtNAttr((char far *)(&reverse),80,24,0,0);
  552.    VioWrtCharStr((char far *)prompt,sizeof(prompt)-1,24,0,0);
  553.    getch();
  554.    cls();
  555.    }
  556. }
  557. /**
  558. *
  559. * name      cls -- clear the screen
  560. *
  561. * synopsis  cls();
  562. *
  563. * description  This function clears the screen by calling the
  564. *     VioScrollUp function in a special way.  However,
  565. *     it has not be generalized to work with display
  566. *     modes using more than 25 lines of 80 characters each.
  567. *
  568. **/
  569. void cls()
  570. {
  571. short fill = 0x0720;
  572.  
  573. VioScrollUp(0,0,24,79,-1,(short far *)(&fill),0);
  574. }
  575.