demangle_datatype: delete superflous free().
[wine] / tools / winedump / main.c
1 /*
2  *  Option processing and main()
3  *
4  *  Copyright 2000 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "winedump.h"
24
25 _globals globals; /* All global variables */
26
27
28 static void do_include (const char *arg)
29 {
30   globals.directory = arg;
31   globals.do_code = 1;
32 }
33
34
35 static inline const char* strip_ext (const char *str)
36 {
37   char *ext = strstr(str, ".dll");
38   if (ext)
39     return str_substring (str, ext);
40   else
41     return strdup (str);
42 }
43
44
45 static void do_name (const char *arg)
46 {
47   globals.dll_name = strip_ext (arg);
48 }
49
50
51 static void do_spec (const char *arg)
52 {
53     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
54     globals.mode = SPEC;
55 }
56
57
58 static void do_demangle (const char *arg)
59 {
60     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
61     globals.mode = DMGL;
62     globals.do_code = 1;
63 }
64
65
66 static void do_dump (const char *arg)
67 {
68     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
69     globals.mode = DUMP;
70     globals.do_code = 1;
71 }
72
73
74 static void do_code (void)
75 {
76   globals.do_code = 1;
77 }
78
79
80 static void do_trace (void)
81 {
82   globals.do_trace = 1;
83   globals.do_code = 1;
84 }
85
86
87 static void do_forward (const char *arg)
88 {
89   globals.forward_dll = arg;
90   globals.do_trace = 1;
91   globals.do_code = 1;
92 }
93
94 static void do_document (void)
95 {
96   globals.do_documentation = 1;
97 }
98
99 static void do_cdecl (void)
100 {
101   globals.do_cdecl = 1;
102 }
103
104
105 static void do_quiet (void)
106 {
107   globals.do_quiet = 1;
108 }
109
110
111 static void do_start (const char *arg)
112 {
113   globals.start_ordinal = atoi (arg);
114   if (!globals.start_ordinal)
115     fatal ("Invalid -s option (must be numeric)");
116 }
117
118
119 static void do_end (const char *arg)
120 {
121   globals.end_ordinal = atoi (arg);
122   if (!globals.end_ordinal)
123     fatal ("Invalid -e option (must be numeric)");
124 }
125
126
127 static void do_symfile (const char *arg)
128 {
129   FILE *f;
130   char symstring[256];    /* keep count with "%<width>s" below */
131   search_symbol *symbolp,**symbolptail = &globals.search_symbol;
132
133   if (!(f = fopen(arg, "rt")))
134     fatal ("Cannot open <symfile>");
135   while (1 == fscanf(f, "%255s", symstring))    /* keep count with [<width>] above */
136   {
137     symstring[sizeof(symstring)-1] = '\0';
138     if (!(symbolp = malloc(sizeof(*symbolp) + strlen(symstring))))
139       fatal ("Out of memory");
140     strcpy(symbolp->symbolname, symstring);
141     symbolp->found = 0;
142     symbolp->next = NULL;
143     *symbolptail = symbolp;
144     symbolptail = &symbolp->next;
145   }
146   if (fclose(f))
147     fatal ("Cannot close <symfile>");
148 }
149
150
151 static void do_verbose (void)
152 {
153   globals.do_verbose = 1;
154 }
155
156
157 static void do_symdmngl (void)
158 {
159     globals.do_demangle = 1;
160 }
161
162 static void do_dumphead (void)
163 {
164     globals.do_dumpheader = 1;
165 }
166
167 static void do_dumpsect (const char* arg)
168 {
169     globals.dumpsect = arg;
170 }
171
172 static void do_dumpall(void)
173 {
174     globals.do_dumpheader = 1;
175     globals.dumpsect = "ALL";
176 }
177
178 struct option
179 {
180   const char *name;
181   Mode mode;
182   int   has_arg;
183   void  (*func) ();
184   const char *usage;
185 };
186
187 static const struct option option_table[] = {
188   {"-h",    NONE, 0, do_usage,    "-h           Display this help message"},
189   {"sym",   DMGL, 0, do_demangle, "sym <sym>    Demangle C++ symbol <sym> and exit"},
190   {"spec",  SPEC, 0, do_spec,     "spec <dll>   Use dll for input file and generate implementation code"},
191   {"-I",    SPEC, 1, do_include,  "-I dir       Look for prototypes in 'dir' (implies -c)"},
192   {"-c",    SPEC, 0, do_code,     "-c           Generate skeleton code (requires -I)"},
193   {"-t",    SPEC, 0, do_trace,    "-t           TRACE arguments (implies -c)"},
194   {"-f",    SPEC, 1, do_forward,  "-f dll       Forward calls to 'dll' (implies -t)"},
195   {"-D",    SPEC, 0, do_document, "-D           Generate documentation"},
196   {"-o",    SPEC, 1, do_name,     "-o name      Set the output dll name (default: dll)"},
197   {"-C",    SPEC, 0, do_cdecl,    "-C           Assume __cdecl calls (default: __stdcall)"},
198   {"-s",    SPEC, 1, do_start,    "-s num       Start prototype search after symbol 'num'"},
199   {"-e",    SPEC, 1, do_end,      "-e num       End prototype search after symbol 'num'"},
200   {"-S",    SPEC, 1, do_symfile,  "-S symfile   Search only prototype names found in 'symfile'"},
201   {"-q",    SPEC, 0, do_quiet,    "-q           Don't show progress (quiet)."},
202   {"-v",    SPEC, 0, do_verbose,  "-v           Show lots of detail while working (verbose)."},
203   {"dump",  DUMP, 0, do_dump,     "dump <mod>   Dumps the content of the module (dll, exe...) named <mod>"},
204   {"-C",    DUMP, 0, do_symdmngl, "-C           Turns on symbol demangling"},
205   {"-f",    DUMP, 0, do_dumphead, "-f           Dumps file header information"},
206   {"-j",    DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug)"},
207   {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
208   {NULL,    NONE, 0, NULL,        NULL}
209 };
210
211 void do_usage (void)
212 {
213     const struct option *opt;
214     printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll>]\n");
215     printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
216     printf ("\tWhen used in -h mode\n");
217     for (opt = option_table; opt->name; opt++)
218         if (opt->mode == NONE)
219             printf ("\t   %s\n", opt->usage);
220     printf ("\tWhen used in sym mode\n");
221     for (opt = option_table; opt->name; opt++)
222         if (opt->mode == DMGL)
223             printf ("\t   %s\n", opt->usage);
224     printf ("\tWhen used in spec mode\n");
225     for (opt = option_table; opt->name; opt++)
226         if (opt->mode == SPEC)
227             printf ("\t   %s\n", opt->usage);
228     printf ("\tWhen used in dump mode\n");
229     for (opt = option_table; opt->name; opt++)
230         if (opt->mode == DUMP)
231             printf ("\t   %s\n", opt->usage);
232
233     puts ("\n");
234     exit (1);
235 }
236
237
238 /*******************************************************************
239  *          parse_options
240  *
241  * Parse options from the argv array
242  */
243 static void parse_options (char *argv[])
244 {
245   const struct option *opt;
246   char *const *ptr;
247   const char *arg = NULL;
248
249   ptr = argv + 1;
250
251   while (*ptr != NULL)
252   {
253     for (opt = option_table; opt->name; opt++)
254     {
255      if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
256        continue;
257      if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
258          ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
259       {
260         arg = *ptr + strlen (opt->name);
261         if (*arg == '\0') arg = *++ptr;
262         break;
263       }
264       if (!strcmp (*ptr, opt->name))
265       {
266         arg = NULL;
267         break;
268       }
269     }
270
271     if (!opt->name)
272     {
273         if ((*ptr)[0] == '-')
274             fatal ("Unrecognized option");
275         if (globals.input_name != NULL)
276             fatal ("Only one file can be treated at once");
277         globals.input_name = *ptr;
278     }
279     else if (opt->has_arg && arg != NULL)
280         opt->func (arg);
281     else
282         opt->func ("");
283
284     ptr++;
285   }
286
287   if (globals.mode == SPEC && globals.do_code && !globals.directory)
288     fatal ("-I must be used if generating code");
289
290   if (VERBOSE && QUIET)
291     fatal ("Options -v and -q are mutually exclusive");
292 }
293
294 static void set_module_name(unsigned setUC)
295 {
296     const char* ptr;
297     char*       buf;
298     int         len;
299
300     /* FIXME: we shouldn't assume all module extensions are .dll in winedump
301      * in some cases, we could have some .drv for example
302      */
303     /* get module name from name */
304     if ((ptr = strrchr (globals.input_name, '/')))
305         ptr++;
306     else
307         ptr = globals.input_name;
308     len = strlen(ptr);
309     if (len > 4 && strcmp(ptr + len - 4, ".dll") == 0)
310         len -= 4;
311     buf = malloc(len + 1);
312     memcpy(buf, (void*)ptr, len);
313     buf[len] = 0;
314     globals.input_module = buf;
315     OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( strdup (OUTPUT_DLL_NAME)) : "";
316 }
317
318 /* Marks the symbol as 'found'! */
319 /* return: perform-search */
320 static int symbol_searched(int count, const char *symbolname)
321 {
322     search_symbol *search_symbol;
323
324     if (!(count >= globals.start_ordinal
325           && (!globals.end_ordinal || count <= globals.end_ordinal)))
326         return 0;
327     if (!globals.search_symbol)
328         return 1;
329     for (search_symbol = globals.search_symbol;
330          search_symbol;
331          search_symbol = search_symbol->next)
332     {
333         if (!strcmp(symbolname, search_symbol->symbolname))
334         {
335             search_symbol->found = 1;
336             return 1;
337         }
338     }
339     return 0;
340 }
341
342 /* return: some symbols weren't found */
343 static int symbol_finish(void)
344 {
345     const search_symbol *search_symbol;
346     int started = 0;
347
348     for (search_symbol = globals.search_symbol;
349          search_symbol;
350          search_symbol = search_symbol->next)
351     {
352         if (search_symbol->found)
353             continue;
354         if (!started)
355         {
356             /* stderr? not a practice here */
357             puts("These requested <symfile> symbols weren't found:");
358             started = 1;
359         }
360         printf("\t%s\n",search_symbol->symbolname);
361     }
362     return started;
363 }
364
365 /*******************************************************************
366  *         main
367  */
368 #ifdef __GNUC__
369 int   main (int argc __attribute__((unused)), char *argv[])
370 #else
371 int   main (int argc, char *argv[])
372 #endif
373 {
374     parsed_symbol symbol;
375     int count = 0;
376
377     globals.mode = NONE;
378     globals.forward_dll = NULL;
379     globals.input_name = NULL;
380
381     parse_options (argv);
382
383     memset (&symbol, 0, sizeof (parsed_symbol));
384
385     switch (globals.mode)
386     {
387     case DMGL:
388         globals.uc_dll_name = "";
389         VERBOSE = 1;
390
391         symbol_init (&symbol, globals.input_name);
392         globals.input_module = "";
393         if (symbol_demangle (&symbol) == -1)
394             fatal( "Symbol hasn't got a mangled name\n");
395         if (symbol.flags & SYM_DATA)
396             printf (symbol.arg_text[0]);
397         else
398             output_prototype (stdout, &symbol);
399         fputc ('\n', stdout);
400         symbol_clear(&symbol);
401         break;
402
403     case SPEC:
404         if (globals.input_name == NULL)
405             fatal("No file name has been given\n");
406         set_module_name(1);
407         dll_open (globals.input_name);
408
409         output_spec_preamble ();
410         output_header_preamble ();
411         output_c_preamble ();
412
413         while (!dll_next_symbol (&symbol))
414         {
415             count++;
416
417             if (NORMAL)
418                 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
419                         VERBOSE ? '\n' : ' ');
420
421             if (globals.do_code && symbol_searched(count, symbol.symbol))
422             {
423                 /* Attempt to get information about the symbol */
424                 int result = symbol_demangle (&symbol);
425
426                 if (result)
427                     result = symbol_search (&symbol);
428
429                 if (!result && symbol.function_name)
430                     /* Clean up the prototype */
431                     symbol_clean_string (symbol.function_name);
432
433                 if (NORMAL)
434                     puts (result ? "[Not Found]" : "[OK]");
435             }
436             else if (NORMAL)
437                 puts ("[Ignoring]");
438
439             output_spec_symbol (&symbol);
440             output_header_symbol (&symbol);
441             output_c_symbol (&symbol);
442
443             symbol_clear (&symbol);
444         }
445
446         output_makefile ();
447         output_install_script ();
448
449         if (VERBOSE)
450             puts ("Finished, Cleaning up...");
451         if (symbol_finish())
452             return 1;
453         break;
454     case NONE:
455         do_usage();
456         break;
457     case DUMP:
458         if (globals.input_name == NULL)
459             fatal("No file name has been given\n");
460         set_module_name(0);
461         dump_file(globals.input_name);
462         break;
463     }
464
465     return 0;
466 }