home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / SOURCE.ZIP / EXEUTIL.AWK < prev    next >
Encoding:
Text File  |  1992-06-09  |  14.4 KB  |  526 lines

  1. # EXEUTIL.AWK
  2. # Andrew Schulman (CIS 76320,302)
  3. #
  4. # Copyright (c) 1992 Andrew Schulman.  All rights reserved.
  5. #
  6. # Contact:  Andrew Schulman (CompuServe 76320,302)
  7. #
  8. # Performs various operations on new executable (NE) files:
  9. #       DIFF: display entry-point differences between two NE files
  10. #       DUPES: display multiple entry points to same code
  11. #       IMPORTS: display all imports
  12. #       UNDOC: display all imports of undocumented functions
  13. #       FINDUNDOC: display all undocumented exports
  14. #
  15. # Requires Thompson AWK compiler (Thompson Automation; 503-224-1639) features:
  16. #       Produce standalone executable (awkc -xe exeutil.awk)
  17. #       Automatic sorting of arrays
  18. #       Multidimensional arrays
  19. #       Hex numbers
  20. #
  21. # Requires the following other components:
  22. #       EXEDUMP.EXE
  23. #       UNDOCWIN.DAT
  24. #       WINFUNC.DAT
  25. #
  26. # from the book "Undocumented Windows" by Schulman, Maxey, and Pietrek
  27. # (Addison-Wesley 1992)
  28. #
  29.  
  30. ######################################################################
  31. # general-purpose routines
  32.  
  33. function hex(s)     { return ("0x" s) + 0; }
  34.  
  35. function help()
  36. {
  37.     print "To display entry-point differences between two versions of file:";
  38.     print "         EXEUTIL -DIFF exe_file1 exe_file2";
  39.     print "example: exeutil -diff \\win31\\system\\user.exe \\win30\\system\\user.exe";
  40.     print "";
  41.     print "To display multiple entry points to same code:";
  42.     print "         EXEUTIL -DUPES exe_file";
  43.     print "example: exeutil -dupes \\windows\\system\\krnl386.exe";
  44.     print "";
  45.     print "To display all imports:";
  46.     print "         EXEUTIL -IMPORTS exe_file";
  47.     print "example: exeutil -imports \\windows\\progman.exe";
  48.     print "";
  49.     print "To display all imports of undocumented functions:";
  50.     print "         EXEUTIL -UNDOC exe_file";
  51.     print "example: exeutil -undoc \\windows\\progman.exe";
  52.     print "";
  53.     print "To find any undocumented exports:";
  54.     print "         EXEUTIL -FINDUNDOC exe_file header_file";
  55.     print "example: exeutil -findundoc \\win31\\system\\user.exe \\windev\\windows.h";
  56.     exit;
  57. }
  58.  
  59. function fail(s) { print "exeutil error: " s > stderr; exit; }
  60.  
  61. function getpathname(filename)
  62. {
  63.     local path, dir, tmp, x;
  64.     if ((pathname = findfirst(filename)) != "")
  65.         return pathname;
  66.     else if ((pathname = findfirst("\\sourcer\\" filename)) != "")
  67.         return pathname;
  68.     else
  69.     {
  70.         # later - also look in ARGV[0] if supplied by AWK
  71.         path = ENV["PATH"];
  72.         split(path, dir, ";");
  73.         for (x in dir)
  74.             if ((pathname = findfirst(dir[x] "\\" filename)) != "")
  75.                 return pathname;
  76.     }
  77.     return "";
  78. }
  79.  
  80. function run(filename, cmdline)
  81. {
  82.     if ((pathname = getpathname(filename)) == "")
  83.         fail("EXEUTIL requires " filename " on PATH");
  84.     if ((ret = system(pathname " " cmdline)) != 0)
  85.         fail("Cannot execute " filename " " cmdline);
  86. }
  87.  
  88. function check_magic(f) \
  89. {
  90.     if (filesize(f) == -1)
  91.         fail("Can't find " f);
  92.     run("exedump.exe", " -magic " f " > _tmp.tmp");
  93.     getline s < "_tmp.tmp";
  94.     close("_tmp.tmp");
  95.     split(s, arr);
  96.     if (arr[1] != "NE")
  97.         fail(f " is an " arr[1] ", not an NE (new executable) file");
  98. }
  99.  
  100. #######################################################################
  101. # EXEUTIL -DIFF
  102.  
  103. function diffhdr() \
  104. {
  105.     FS = " ";
  106.     tempfile = "_tmp.tmp";
  107.     run("exedump.exe", " -nobanner -noreloc " files[2] " > " tempfile);
  108.  
  109.     printf("Entry point differences:               \n");
  110.  
  111.     while (getline < tempfile)
  112.     {
  113.         if ($0 == "begin entry")
  114.             in_entry = 1;
  115.         else if (in_entry)
  116.         {
  117.             if (NF == 0)
  118.                 break;
  119.             else if ((NF == 3) || (NF == 4))
  120.                 entrytab2[++line] = $0;
  121.         }
  122.         odometer();
  123.     }
  124.  
  125.     for (x in entrytab)
  126.     {
  127.         split(entrytab[x], arr);
  128.         if (arr[4])
  129.             func1[arr[3]] = arr[4];     # ord = func
  130.         else
  131.             func1[arr[3]] = "(unnamed @" arr[3] ")" ;
  132.     }
  133.     for (x in entrytab2)
  134.     {
  135.         split(entrytab2[x], arr);
  136.         if (arr[4])
  137.             func2[arr[3]] = arr[4];     # ord = func
  138.         else
  139.             func2[arr[3]] = "(unnamed @" arr[3] ")" ;
  140.     }
  141.  
  142.     # list functions in ne1 that are different or missing in ne2
  143.     printf("\t%30s\t%s\n", files[1], files[2]);
  144.     for (i in func1)
  145.         if (func1[i] != func2[i])   ## difference between versions
  146.         {
  147.             printf("%u\t%-30s\t%s\n", i, func1[i], func2[i]);
  148.             delete func2[i];  ## said something once, why said it again
  149.         }
  150.  
  151.     # list functions in ne2 that are different or missing in ne1
  152.     printf("\n\t%30s\t%s\n", files[2], files[1]);
  153.     for (i in func2)
  154.         if (func2[i] != func1[i])
  155.             printf("%u\t%-30s\t%s\n", i, func2[i], func1[i]);
  156.  
  157.     delete func1;
  158.     delete func2;
  159.     delete entrytab2;
  160. }
  161.  
  162. #######################################################################
  163. # EXEUTIL -DUPES
  164.  
  165. function dupes() \
  166. {
  167.     FS = " ";
  168.     printf("Multiple entry points for same segment:offset:      \n");
  169.  
  170.     for (x in entrytab)
  171.     {
  172.         split(entrytab[x], arr);
  173.         s = arr[1];
  174.         o = arr[2];
  175.         if ((s in so) && (o in so[s]))
  176.             duplicate[s][o][entrytab[x]] = 1;
  177.         else
  178.             so[s][o] = entrytab[x];
  179.     }
  180.     
  181.     for (s in duplicate)
  182.         for (o in duplicate[s])
  183.         {
  184.             print so[s][o];
  185.             for (f in duplicate[s][o])
  186.                 print f;
  187.             print "";
  188.         }
  189.  
  190.     delete arr;
  191.     delete duplicate;
  192.     delete so;
  193. }
  194.  
  195. #######################################################################
  196. # EXEUTIL -IMPORTS
  197.  
  198. function load_winfunc() \
  199. {
  200.     if (winfunc)
  201.         return;     # already loaded
  202.  
  203.     if ((winfunc_dat2 = getpathname(winfunc_dat)) != "")
  204.     {
  205.         while (getline < winfunc_dat2)
  206.             if ($0 !~ /;/)  # discard comments
  207.                 winfunc[$1 "_" $3] = $4;
  208.         close(winfunc_dat2);
  209.     }
  210.     else
  211.         fail("can't find .DAT file -- " winfunc_dat);
  212. }
  213.  
  214. function imports() \
  215. {
  216.     FS = " ";
  217.     load_winfunc();
  218.  
  219.     printf("%s imported references:              \n", toupper(files[1]));
  220.  
  221.     for (mod in reloc)
  222.     {
  223.         if (mod == modname)
  224.         {
  225.             # internal references really, probably unnamed!
  226.             for (ordnum in reloc[modname])
  227.             {
  228.                 internal_reloc[ordnum]++;
  229.                 if ((s = winfunc[modname "_" ordnum]))
  230.                     internal_reloc_name[ordnum] = s;
  231.                 else
  232.                     internal_reloc_name[ordnum] = "?";
  233.             }
  234.         }
  235.         else
  236.         {
  237.             for (ordnum in reloc[mod])
  238.             {
  239.                 if (winfunc[mod "_" ordnum])
  240.                     printf("\t%s (%s.%s)", 
  241.                         winfunc[mod "_" ordnum], mod, ordnum);
  242.                 else
  243.                     printf("\t%s.%s", mod, ordnum);
  244.                 if (reloc[mod][ordnum] > 10)
  245.                     printf(" -- %u references\n", reloc[mod][ordnum]);
  246.                 else
  247.                     print "";
  248.             }
  249.         }
  250.     }
  251.  
  252.     if (internal_reloc)
  253.     {
  254.         print "";
  255.         printf("%s internal references:      \n", toupper(files[1]));
  256.         for (f in internal_reloc)
  257.         {
  258.             printf("\t%s (%s.%s)", internal_reloc_name[f], modname, f);
  259.             if (internal_reloc[f] > 10)
  260.                 printf(" -- %u references\n", internal_reloc[f]);
  261.             else
  262.                 print "";
  263.         }
  264.     }
  265. }
  266.  
  267. #######################################################################
  268. # EXEUTIL -UNDOC (imports)
  269.  
  270. function load_undocwin() \
  271. {
  272.     if (undocwin)
  273.         return;     # already loaded
  274.  
  275.     if ((uwin_dat2 = getpathname(uwin_dat)) != "")
  276.     {
  277.         while (getline < uwin_dat2)
  278.             if ($0 !~ /;/)  # discard comments
  279.                 undocwin[$1 "_" $3] = $4;
  280.         close(uwin_dat2);
  281.     }
  282.     else
  283.         fail("can't find .DAT file -- " uwin_dat);
  284. }
  285.  
  286. function getundoc() \
  287. {
  288.     FS = " ";
  289.     load_undocwin();
  290.  
  291.     printf("%s undocumented imports:          \n", toupper(files[1]));
  292.  
  293.     for (mod in reloc)
  294.         for (ordnum in reloc[mod])
  295.             if (undocwin[mod "_" ordnum])
  296.             {
  297.                 printf("\t%s (%s.%s)", 
  298.                     undocwin[mod "_" ordnum], mod, ordnum);
  299.                 if (reloc[mod][ordnum] > 10)
  300.                     printf(" -- %u references\n", reloc[mod][ordnum]);
  301.                 else
  302.                     print "";
  303.             }
  304.  
  305.     if (reloc["KERNEL"][50])    # GetProcAddress
  306.         print "\tuses run-time dynamic linking (GetProcAddress)" ;
  307.  
  308.     if (internal_reloc)
  309.         for (f in internal_reloc)
  310.             if (undocwin[modname "_" f] == internal_reloc_name[f])
  311.             {
  312.                 printf("\t%s (%s.%s) -- INTERNAL",
  313.                     internal_reloc_name[f], modname, f);
  314.                 if (internal_reloc[f] > 10)
  315.                     printf(" -- %u references\n", internal_reloc[f]);
  316.                 else
  317.                     print "";
  318.             }
  319. }
  320.  
  321. #######################################################################
  322. # EXEUTIL -FINDUNDOC (exports)
  323.  
  324. (not_first_file == 0) && (FILENAME != ARGV[2]) \
  325.     not_first_file = 1;
  326.     FS = "[^A-Za-z0-9_]+";
  327. }
  328.  
  329. # print status report every 100 lines
  330. function odometer()
  331. {
  332.     if ((NR % 100) == 0)
  333.         printf("%u %s\t\t\t\r", 
  334.             NR, 
  335.             (FILENAME=="_tmp.tmp" ? files[1] : FILENAME)) > stderr;
  336. }
  337.  
  338. {
  339.     odometer();
  340. }
  341.  
  342. # for every file other than the first one specified
  343. not_first_file == 1 \
  344. {
  345.     for (i=1; i<=NF; i++)           # for each field in record
  346.         if ($i ~ /^[A-Za-z_]/)      # if valid identifier
  347.             doc[toupper($i)]++;     # put in dictionary
  348. }
  349.  
  350. # maybe use if (FILENAME ~ "*.H")???
  351. # /^.*[ \t]+FAR[ \t]+.*(PASCAL)|(cdecl)|(WINAPI)|(API)[ \t]+.*\(.*\)?;?$/ &&
  352. # $1 != "typedef" {
  353. #   sub(/\(.*;?/, "", $0) ;
  354. #   # resplit and print last field
  355. #   nf = split($0, f) ;
  356. #   doc[toupper(f[nf])]++;
  357. #   }
  358.  
  359. function findundoc()
  360. {
  361.     FS = " ";       # restore, since changed it
  362.     print ";" ;
  363.     print "; Functions in " files[1] " but not in " files[2] ":" ;
  364.     if (description)
  365.         print "; " description ;
  366.     print ";" ;
  367.     # for every entry in the entry table
  368.     for (x in entrytab)
  369.     {
  370.         split(entrytab[x], arr);                # split line into fields
  371.         if (arr[4])
  372.         {
  373.             if (! (arr[4] in doc))              # if name not in doc array
  374.                 printf("%s . %d\t%s\n",         # display it
  375.                     modname, arr[3], arr[4]);   # modname . ord \t funcname
  376.         }
  377.     }
  378. }
  379.  
  380. #######################################################################
  381. #
  382. # Take output from EXEDUMP and put into arrays
  383. #
  384.  
  385. # EXEDUMP output for entry table looks like this:
  386. # begin entry
  387. #   1   007b    1   TASKMANDLGPROC
  388. #   1   1234    2
  389. # AWK assigns the first field to $1, the second to $2, and the number
  390. # of fields to NF; NR is the record number.  Thus, segment is $1,
  391. # offset is $2, ordinal is $3, and name (optional) is $4.                 
  392.  
  393. # for every line in entry table
  394. $0 == "begin entry", NF == 0 \
  395. {
  396.     if (NF == 3 || NF == 4)     # if three or four fields...
  397.         entrytab[NR] = $0;      # put entire line into array
  398. }
  399.  
  400. # EXEDUMP output for relocation table looks like this:
  401. # begin reloc
  402. #   1   031e    [m] USER 135    PTR
  403. #   1   0302    [m] KERNEL 158  PTR
  404. #   1   311d    [n] WMHANDLER_WNDPROC /* callfunc 1 */  OFF
  405. # The type (such as [m] or [n]) is $3. For [m], the module is $4 and
  406. # the ordinal is $5; for [n], the ordinal is $7, and the name is $4.
  407.  
  408. # for every line in relocation table
  409. $0 == "begin reloc", NF == 0 \
  410. {
  411.     if (do_reloc)
  412.     {
  413.         if ($3 == "[m]")      # mod.ord reference
  414.         {
  415.             reloc[$4][$5]++;  # increment refcount for reloc[module][ordinal]
  416.         }
  417.         else if ($3 == "[n]") # internal reference
  418.         {
  419.             internal_reloc[$7]++;   # increment refcount for ordinal#
  420.             internal_reloc_name[$7] = $4;   # save name for ordinal#
  421.         }
  422.     }
  423. }
  424.  
  425. $1 == "description" \
  426. {
  427.     split($0, arr, "\""); 
  428.     if (arr[2])
  429.         description = arr[2];
  430. }
  431.  
  432. $1 == "modname" \
  433. {
  434.     modname = $2;
  435. }
  436.  
  437. # main
  438. BEGIN \
  439. {
  440.     print "Windows New-Executable (NE) Header Utilities version 1.0" > stderr;
  441.     print "from \"Undocumented Windows\" by Schulman et al. " \
  442.           "(Addison-Wesley, 1992)" > stderr;
  443.     print "Copyright (c) 1992 Andrew Schulman. All rights reserved." > stderr;
  444.     print "";
  445.  
  446.     winfunc_dat = "WINFUNC.DAT" ;       # default
  447.     uwin_dat = "UNDOCWIN.DAT" ;
  448.  
  449.     do_reloc = 0;
  450.     do_options = 0;
  451.     DO_DIFF = 1;
  452.     DO_DUPES = 2;
  453.     DO_FINDUNDOC = 4;
  454.     DO_IMPORTS = 8;
  455.     DO_UNDOC = 16;
  456.  
  457.     if ((ARGC < 2) || (ARGV[1] == "/?"))
  458.         help();
  459.  
  460.     arg = toupper(ARGV[1]);
  461.     if (arg == "-FINDUNDOC")
  462.         do_options = DO_FINDUNDOC;
  463.     else if (arg == "-DIFF")
  464.         do_options = DO_DIFF;
  465.     else if (arg == "-DUPES")
  466.         do_options = DO_DUPES;
  467.     else if (arg == "-IMPORTS")
  468.     {
  469.         do_reloc++;
  470.         do_options = DO_IMPORTS;
  471.     }
  472.     else if (arg == "-UNDOC")
  473.     {
  474.         do_reloc++;
  475.         do_options = DO_UNDOC;
  476.     }
  477.  
  478.     for (i=2; i<ARGC; i++)
  479.         files[++num_files] = ARGV[i];
  480.  
  481.     if (do_options == 0)
  482.         help();
  483.     if (num_files < 1)
  484.         help();
  485.  
  486.     check_magic(files[1]);
  487.  
  488.     if (and(do_options, DO_DIFF))
  489.     {
  490.         if (num_files != 2)
  491.             fail("-DIFF requires two NE files");
  492.         check_magic(files[2]);
  493.     }
  494.     
  495.     if (and(do_options, DO_FINDUNDOC))
  496.     {
  497.         if (num_files != 2)
  498.             fail("-FINDUNDOC requires an NE file and a header");
  499.     }
  500.  
  501.     if (do_reloc)
  502.         run("exedump.exe", " -nobanner " files[1] " > _tmp.tmp");
  503.     else
  504.         run("exedump.exe", " -nobanner -noreloc " files[1] " > _tmp.tmp");
  505.     ARGV[1] = "";
  506.     ARGV[2] = "_tmp.tmp";
  507.     okay = 1;
  508. }
  509.  
  510. END \
  511. {
  512.     if (! okay)
  513.         exit;
  514.  
  515.     if (and(do_options, DO_DIFF))       diffhdr();
  516.     if (and(do_options, DO_DUPES))      dupes();
  517.     if (and(do_options, DO_FINDUNDOC))  findundoc();
  518.     if (and(do_options, DO_IMPORTS))    imports();
  519.     if (and(do_options, DO_UNDOC))      getundoc();
  520.  
  521.     system("del _tmp.tmp");
  522. }
  523.  
  524.  
  525.