home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / emxtutor.zip / emxsrcd1.zip / emx / src / emxexp / emxexp.c < prev    next >
C/C++ Source or Header  |  1998-12-19  |  16KB  |  624 lines

  1. /* emxexp.c -- Create export definitions from .o and .obj files
  2.    Copyright (c) 1993-1998 Eberhard Mattes
  3.  
  4. This file is part of emxexp.
  5.  
  6. emxexp is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emxexp is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emxexp; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <getopt.h>
  27. #include <errno.h>
  28. #include <ar.h>
  29. #include "defs.h"
  30. #include <sys/omflib.h>
  31. #include "demangle.h"
  32.  
  33. #define VERSION "0.9d"
  34.  
  35. struct bss_list
  36. {
  37.   char *name;
  38.   struct bss_list *next;
  39. };
  40.  
  41. static int ordinal = 0;
  42. static int noname_flag = FALSE;
  43. static int bss_flag = FALSE;
  44.  
  45. static FILE *out_file;
  46. static const char *inp_fname;
  47. static const char *mod_name;
  48. static int new_mod = FALSE;
  49. static int last_dem = FALSE;
  50. static struct bss_list *bss_list = NULL;
  51.  
  52. static void error (const char *fmt, ...) NORETURN2;
  53. static void usage (void) NORETURN2;
  54. static void bad_omf (void) NORETURN2;
  55.  
  56.  
  57. static void error (const char *fmt, ...)
  58. {
  59.   va_list arg_ptr;
  60.  
  61.   va_start (arg_ptr, fmt);
  62.   fprintf (stderr, "emxexp: ");
  63.   vfprintf (stderr, fmt, arg_ptr);
  64.   fputc ('\n', stderr);
  65.   exit (2);
  66. }
  67.  
  68.  
  69. /* Allocate N bytes of memory.  Quit on failure.  This function is
  70.    used like malloc(), but we don't have to check the return value. */
  71.  
  72. void *xmalloc (size_t n)
  73. {
  74.   void *p;
  75.   
  76.   p = malloc (n);
  77.   if (p == NULL)
  78.     error ("Out of memory");
  79.   return p;
  80. }
  81.  
  82.  
  83. /* Change the allocation of PTR to N bytes.  Quit on failure.  This
  84.    function is used like realloc(), but we don't have to check the
  85.    return value. */
  86.  
  87. void *xrealloc (void *ptr, size_t n)
  88. {
  89.   void *p;
  90.   
  91.   p = realloc (ptr, n);
  92.   if (p == NULL)
  93.     error ("Out of memory");
  94.   return p;
  95. }
  96.  
  97.  
  98. /* How to call this program. */
  99.  
  100. static void usage (void)
  101. {
  102.   fputs ("emxexp " VERSION " -- Copyright (c) 1993-1995 by Eberhard Mattes\n\n"
  103.          "Usage: emxexp [-n] [-u] [-o[<ordinal>] <input_file>...\n\n"
  104.          "Options:\n"
  105.          "  -n          Output NONAME keyword for each exported symbol\n"
  106.          "  -o          Output ordinal numbers, starting at 1\n"
  107.          "  -o<ordinal> Output ordinal numbers, starting at <ordinal>\n"
  108.          "  -u          Also export uninitialized variables\n",
  109.          stderr);
  110.   exit (1);
  111. }
  112.  
  113.  
  114. static void export (const char *name)
  115. {
  116.   char *dem;
  117.  
  118.   if (new_mod)
  119.     {
  120.       fprintf (out_file, "\n; From %s", inp_fname);
  121.       if (mod_name != NULL)
  122.         fprintf (out_file, "(%s)", mod_name);
  123.       fputc ('\n', out_file);
  124.       new_mod = FALSE;
  125.     }
  126.   dem = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
  127.   if (dem != NULL)
  128.     {
  129.       fprintf (out_file, "\n  ; %s\n", dem);
  130.       free (dem);
  131.       last_dem = TRUE;
  132.     }
  133.   else if (last_dem)
  134.     {
  135.       fputc ('\n', out_file);
  136.       last_dem = FALSE;
  137.     }
  138.   fprintf (out_file, "  \"%s\"", name);
  139.   if (ordinal != 0)
  140.     fprintf (out_file, " @%d", ordinal++);
  141.   if (noname_flag)
  142.     fprintf (out_file, " NONAME");
  143.   fputc ('\n', out_file);
  144. }
  145.  
  146.  
  147. static void export_bss (const char *name)
  148. {
  149.   struct bss_list *p;
  150.  
  151.   if (bss_flag)
  152.     {
  153.       for (p = bss_list; p != NULL; p = p->next)
  154.         if (strcmp (p->name, name) == 0)
  155.           return;
  156.       p = xmalloc (sizeof (*p));
  157.       p->name = xmalloc (strlen (name) + 1);
  158.       strcpy (p->name, name);
  159.       p->next = bss_list;
  160.       bss_list = p;
  161.       export (name);
  162.     }
  163. }
  164.  
  165.  
  166. static void process_aout (FILE *inp_file, long size)
  167. {
  168.   byte *inp_buf;
  169.   const struct a_out_header *a_out_h;
  170.   const byte *sym;
  171.   const struct nlist *sym_ptr;
  172.   const byte *str_ptr;
  173.   long str_size;
  174.   int sym_count, i;
  175.   const char *name;
  176.  
  177.   new_mod = TRUE;
  178.  
  179.   inp_buf = xmalloc (size);
  180.   size = fread (inp_buf, 1, size, inp_file);
  181.  
  182.   a_out_h = (struct a_out_header *)inp_buf;
  183.   if (size < sizeof (struct a_out_header) || a_out_h->magic != 0407)
  184.     error ("Malformed input file `%s'", inp_fname);
  185.   sym = (inp_buf + sizeof (struct a_out_header) + a_out_h->text_size
  186.          + a_out_h->data_size + a_out_h->trsize + a_out_h->drsize);
  187.   str_ptr = sym + a_out_h->sym_size;
  188.   if (str_ptr + 4 - inp_buf > size)
  189.     error ("Malformed input file `%s'", inp_fname);
  190.   str_size = *(long *)str_ptr;
  191.   sym_ptr = (const struct nlist *)sym;
  192.   sym_count = a_out_h->sym_size / sizeof (struct nlist);
  193.   if (str_ptr + str_size - inp_buf > size)
  194.     error ("Malformed input file `%s'", inp_fname);
  195.  
  196.   for (i = 0; i < sym_count; ++i)
  197.     if (sym_ptr[i].type == (N_TEXT|N_EXT) || sym_ptr[i].type == (N_DATA|N_EXT))
  198.       {
  199.         name = str_ptr + sym_ptr[i].string;
  200.         if (*name == '_')
  201.           ++name;
  202.         export (name);
  203.       }
  204.     else if (sym_ptr[i].type == N_EXT && sym_ptr[i].value != 0)
  205.       {
  206.         name = str_ptr + sym_ptr[i].string;
  207.         if (*name == '_')
  208.           ++name;
  209.         export_bss (name);
  210.       }
  211.  
  212.   free (inp_buf);
  213. }
  214.  
  215.  
  216. static byte rec_buf[MAX_REC_SIZE+8];
  217. static int rec_type;
  218. static int rec_len;
  219. static int rec_idx;
  220.  
  221.  
  222. static void bad_omf (void)
  223. {
  224.   error ("Malformed OMF file `%s'", inp_fname);
  225. }
  226.  
  227.  
  228. static void get_mem (void *dst, int len)
  229. {
  230.   if (rec_idx + len > rec_len)
  231.     bad_omf ();
  232.   memcpy (dst, rec_buf + rec_idx, len);
  233.   rec_idx += len;
  234. }
  235.  
  236.  
  237. static int get_byte (void)
  238. {
  239.   if (rec_idx >= rec_len)
  240.     bad_omf ();
  241.   return rec_buf[rec_idx++];
  242. }
  243.  
  244.  
  245. static void get_string (byte *dst)
  246. {
  247.   int len;
  248.  
  249.   len = get_byte ();
  250.   get_mem (dst, len);
  251.   dst[len] = 0;
  252. }
  253.  
  254.  
  255. static int get_index (void)
  256. {
  257.   int result;
  258.  
  259.   result = get_byte ();
  260.   if (result & 0x80)
  261.     {
  262.       if (rec_idx >= rec_len)
  263.         bad_omf ();
  264.       result = ((result & 0x7f) << 8) | rec_buf[rec_idx++];
  265.     }
  266.   return result;
  267. }
  268.  
  269.  
  270. static word get_dword (void)
  271. {
  272.   dword result;
  273.  
  274.   if (rec_idx + 4 > rec_len)
  275.     bad_omf ();
  276.   result = rec_buf[rec_idx++];
  277.   result |= rec_buf[rec_idx++] << 8;
  278.   result |= rec_buf[rec_idx++] << 16;
  279.   result |= rec_buf[rec_idx++] << 24;
  280.   return result;
  281. }
  282.  
  283.  
  284. static word get_word (void)
  285. {
  286.   word result;
  287.  
  288.   if (rec_idx + 2 > rec_len)
  289.     bad_omf ();
  290.   result = rec_buf[rec_idx++];
  291.   result |= rec_buf[rec_idx++] << 8;
  292.   return result;
  293. }
  294.  
  295.  
  296. static dword get_word_or_dword (void)
  297. {
  298.   return rec_type & REC32 ? get_dword () : get_word ();
  299. }
  300.  
  301.  
  302. static dword get_commlen (void)
  303. {
  304.   dword result;
  305.  
  306.   result = get_byte ();
  307.   if (result <= 0x80)
  308.     return result;
  309.   switch (result)
  310.     {
  311.     case 0x81:
  312.       return get_word ();
  313.     case 0x84:
  314.       result = get_byte ();
  315.       result |= get_byte () << 8;
  316.       result |= get_byte () << 16;
  317.       return result;
  318.     case 0x88:
  319.       return get_dword ();
  320.     default:
  321.       bad_omf ();
  322.     }
  323. }
  324.  
  325.  
  326. static void omf_pubdef (void)
  327. {
  328.   int type, group, seg;
  329.   word frame;
  330.   dword offset;
  331.   byte name[256];
  332.  
  333.   group = get_index ();
  334.   seg = get_index ();
  335.   if (seg == 0)
  336.     frame = get_word ();
  337.  
  338.   while (rec_idx < rec_len)
  339.     {
  340.       get_string (name);
  341.       offset = get_word_or_dword ();
  342.       type = get_index ();
  343.       export (name);
  344.     }
  345. }
  346.  
  347.  
  348. static void omf_comdef (void)
  349. {
  350.   int type_index, data_type;
  351.   byte name[256];
  352.  
  353.   while (rec_idx < rec_len)
  354.     {
  355.       get_string (name);
  356.       type_index = get_index ();
  357.       data_type = get_byte ();
  358.       switch (data_type)
  359.         {
  360.         case 0x61:
  361.           get_commlen ();
  362.           get_commlen ();
  363.           break;
  364.         case 0x62:
  365.           get_commlen ();
  366.           break;
  367.         default:
  368.           bad_omf ();
  369.         }
  370.       export_bss (name);
  371.     }
  372. }
  373.  
  374.  
  375. static void process_omf (FILE *inp_file)
  376. {
  377.   struct omf_rec rec;
  378.  
  379.   new_mod = TRUE;
  380.   do
  381.     {
  382.       if (fread (&rec, sizeof (rec), 1, inp_file) != 1)
  383.         error ("Unexpected end of file on input file `%s'", inp_fname);
  384.       rec_type = rec.rec_type;
  385.       rec_len = rec.rec_len;
  386.       rec_idx = 0;
  387.       if (rec_len > sizeof (rec_buf))
  388.         error ("OMF record too long in `%s'", inp_fname);
  389.       if (fread (rec_buf, rec_len, 1, inp_file) != 1)
  390.         error ("Unexpected end of file on input file `%s'", inp_fname);
  391.       --rec_len;                /* Remove checksum */
  392.       switch (rec_type)
  393.         {
  394.         case PUBDEF:
  395.         case PUBDEF|REC32:
  396.           omf_pubdef ();
  397.           break;
  398.         case COMDEF:
  399.           if (bss_flag)
  400.             omf_comdef ();
  401.           break;
  402.         }
  403.     } while (rec.rec_type != MODEND && rec_type != (MODEND|REC32));
  404. }
  405.  
  406.  
  407. /* Process one input file. */
  408.  
  409. static void process (void)
  410. {
  411.   static char ar_magic[SARMAG+1] = ARMAG;
  412.   char ar_test[SARMAG], *p, *end;
  413.   struct ar_hdr ar;
  414.   long size, ar_pos, index;
  415.   int i, n;
  416.   FILE *inp_file;
  417.   char *long_names = NULL;
  418.   size_t long_names_size = 0;
  419.  
  420.   mod_name = NULL;
  421.   inp_file = fopen (inp_fname, "rb");
  422.   if (inp_file == NULL)
  423.     error ("Cannot open input file `%s'", inp_fname);
  424.  
  425.   /* Read some bytes from the start of the file to find out whether
  426.      this is an archive (.a) file or not. */
  427.  
  428.   if (fread (ar_test, sizeof (ar_test), 1, inp_file) != 1)
  429.     error ("Cannot read input file `%s'", inp_fname);
  430.  
  431.   if (memcmp (ar_test, ar_magic, SARMAG) == 0)
  432.     {
  433.  
  434.       /* The input file is an archive. Loop over all the members of
  435.          the archive. */
  436.  
  437.       ar_pos = SARMAG;
  438.       for (;;)
  439.         {
  440.  
  441.           /* Read the header of the member. */
  442.  
  443.           fseek (inp_file, ar_pos, SEEK_SET);
  444.           size = fread  (&ar, 1, sizeof (ar), inp_file);
  445.           if (size == 0)
  446.             break;
  447.           else if (size != sizeof (ar))
  448.             error ("Malformed archive `%s'", inp_fname);
  449.  
  450.           /* Decode the header. */
  451.  
  452.           errno = 0;
  453.           size = strtol (ar.ar_size, &p, 10);
  454.           if (p == ar.ar_size || errno != 0 || size <= 0 || *p != ' ')
  455.             error ("Malformed archive header in `%s'", inp_fname);
  456.           ar_pos += (sizeof (ar) + size + 1) & -2;
  457.  
  458.           /* Remove trailing blanks from the member name. */
  459.  
  460.           i = sizeof (ar.ar_name) - 1;
  461.           while (i > 0 && ar.ar_name[i-1] == ' ')
  462.             --i;
  463.           ar.ar_name[i] = 0;
  464.  
  465.           if (strcmp (ar.ar_name, "ARFILENAMES/") == 0)
  466.             {
  467.               size_t i;
  468.  
  469.               /* The "ARFILENAMES/" member contains the long file
  470.                  names, each one is terminated with a newline
  471.                  character.  Member names starting with a space are
  472.                  also considered long file names because a leading
  473.                  space is used for names pointing into the
  474.                  "ARFILENAMES/" table.  Read the "ARFILENAMES/" member
  475.                  to LONG_NAMES. */
  476.  
  477.               if (size != 0)
  478.                 {
  479.                   long_names_size = (size_t)size;
  480.                   long_names = xmalloc (long_names_size);
  481.                   size = fread (long_names, 1, long_names_size, inp_file);
  482.                   if (ferror (inp_file))
  483.                     error ("Cannot read `%s'", inp_fname);
  484.                   if (size != long_names_size)
  485.                     error ("%s: ARFILENAMES/ member is truncated", inp_fname);
  486.  
  487.                   /* Replace the newlines with nulls to make
  488.                      processing a bit more convenient. */
  489.  
  490.                   for (i = 0; i < long_names_size; ++i)
  491.                     if (long_names[i] == '\n')
  492.                       long_names[i] = 0;
  493.                   if (long_names[long_names_size-1] != 0)
  494.                     error ("%s: ARFILENAMES/ member corrupt", inp_fname);
  495.                 }
  496.             }
  497.  
  498.           /* Ignore the __.SYMDEF and __.IMPORT members. */
  499.  
  500.           else if (strcmp (ar.ar_name, "__.SYMDEF") != 0
  501.               && strcmp (ar.ar_name, "__.IMPORT") != 0)
  502.             {
  503.               /* Process the current member.  First, fetch the name of
  504.                  the member.  If the ar_name starts with a space, the
  505.                  decimal number following that space is an offset into
  506.                  the "ARFILENAMES/" member.  The number may be
  507.                  followed by a space and a substring of the long file
  508.                  name. */
  509.  
  510.               mod_name = ar.ar_name;
  511.               if (mod_name[0] == ' ' && long_names != NULL
  512.                   && (index = strtol (mod_name + 1, &end, 10)) >= 0
  513.                   && index < long_names_size - 1
  514.                   && (*end == 0 || *end == ' ')
  515.                   && (index == 0 || long_names[index-1] == 0))
  516.                 mod_name = long_names + index;
  517.  
  518.               process_aout (inp_file, size);
  519.             }
  520.         }
  521.     }
  522.   else
  523.     {
  524.       if (*(word *)ar_test == 0407)
  525.         {
  526.           if (fseek (inp_file, 0L, SEEK_END) != 0)
  527.             error ("Input file `%s' is not seekable", inp_fname);
  528.           size = ftell (inp_file);
  529.           fseek (inp_file, 0L, SEEK_SET);
  530.           process_aout (inp_file, size);
  531.         }
  532.       else if (*(byte *)ar_test == LIBHDR)
  533.         {
  534.           struct omflib *lib;
  535.           char errmsg[512], name[257];
  536.           int page;
  537.  
  538.           lib = omflib_open (inp_fname, errmsg);
  539.           if (lib == NULL)
  540.             error ("%s: %s", inp_fname, errmsg);
  541.  
  542.           n = omflib_module_count (lib, errmsg);
  543.           if (n == -1)
  544.             error ("%s: %s", inp_fname, errmsg);
  545.           for (i = 0; i < n; ++i)
  546.             {
  547.               if (omflib_module_info (lib, i, name, &page, errmsg) != 0)
  548.                 error ("%s: %s", inp_fname, errmsg);
  549.               else
  550.                 {
  551.                   fseek (inp_file, omflib_page_pos (lib, page), SEEK_SET);
  552.                   mod_name = name;
  553.                   process_omf (inp_file);
  554.                 }
  555.             }
  556.           if (omflib_close (lib, errmsg) != 0)
  557.             error ("%s: %s", inp_fname, errmsg);
  558.         }
  559.       else
  560.         {
  561.           fseek (inp_file, 0L, SEEK_SET);
  562.           process_omf (inp_file);
  563.         }
  564.     }
  565.   fclose (inp_file);
  566. }
  567.  
  568.  
  569. /* Main line. */
  570.  
  571. int main (int argc, char **argv)
  572. {
  573.   int c, i;
  574.   char *p;
  575.  
  576.   _response (&argc, &argv);
  577.   _wildcard (&argc, &argv);
  578.   opterr = 0;
  579.   optswchar = "-";
  580.   optind = 0;
  581.   while ((c = getopt (argc, argv, "no::u")) != EOF)
  582.     {
  583.       switch (c)
  584.         {
  585.         case 'n':
  586.           noname_flag = TRUE;
  587.           break;
  588.         case 'o':
  589.           if (optarg == NULL)
  590.             ordinal = 1;
  591.           else
  592.             {
  593.               errno = 0;
  594.               ordinal = (int)strtol (optarg, &p, 0);
  595.               if (p == optarg || errno != 0 || *p != 0
  596.                   || ordinal < 1 || ordinal > 65535)
  597.                 usage ();
  598.             }
  599.           break;
  600.         case 'u':
  601.           bss_flag = TRUE;
  602.           break;
  603.         default:
  604.           error ("Invalid option");
  605.         }
  606.     }
  607.  
  608.   out_file = stdout;
  609.  
  610.   if (optind >= argc)
  611.     usage ();
  612.  
  613.   for (i = optind; i < argc; ++i)
  614.     {
  615.       inp_fname = argv[i];
  616.       process ();
  617.     }
  618.  
  619.   if (fflush (out_file) != 0 || (out_file != stdout && fclose (out_file) != 0))
  620.     error ("Write error");
  621.  
  622.   return 0;
  623. }
  624.