include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / tools / winedump / main.c
blob99b1221fdacce00ffb347fc534a07bab96090de0
1 /*
2 * Option processing and main()
4 * Copyright 2000 Jon Griffiths
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include "winedump.h"
25 _globals globals; /* All global variables */
28 static void do_include (const char *arg)
30 if (!globals.directory)
31 globals.directory = xstrdup(arg);
32 else
33 globals.directory = strmake( "%s %s", globals.directory, arg );
34 globals.do_code = TRUE;
38 static inline const char* strip_ext (const char *str)
40 int len = strlen(str);
41 if (len>4 && strcmp(str+len-4,".dll") == 0)
42 return str_substring (str, str+len-4);
43 else
44 return xstrdup (str);
48 static void do_name (const char *arg)
50 globals.dll_name = strip_ext (arg);
54 static void do_spec (const char *arg)
56 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
57 globals.mode = SPEC;
61 static void do_demangle (const char *arg)
63 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
64 globals.mode = DMGL;
65 globals.do_code = TRUE;
66 globals.do_demangle = TRUE;
70 static void do_dump (const char *arg)
72 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
73 globals.mode = DUMP;
74 globals.do_code = TRUE;
78 static void do_code (const char *arg)
80 globals.do_code = TRUE;
84 static void do_trace (const char *arg)
86 globals.do_trace = TRUE;
87 globals.do_code = TRUE;
91 static void do_forward (const char *arg)
93 globals.forward_dll = arg;
94 globals.do_trace = TRUE;
95 globals.do_code = TRUE;
98 static void do_document (const char *arg)
100 globals.do_documentation = TRUE;
103 static void do_cdecl (const char *arg)
105 globals.do_cdecl = TRUE;
109 static void do_quiet (const char *arg)
111 globals.do_quiet = TRUE;
115 static void do_start (const char *arg)
117 globals.start_ordinal = atoi (arg);
118 if (!globals.start_ordinal)
119 fatal ("Invalid -s option (must be numeric)");
123 static void do_end (const char *arg)
125 globals.end_ordinal = atoi (arg);
126 if (!globals.end_ordinal)
127 fatal ("Invalid -e option (must be numeric)");
131 static void do_symfile (const char *arg)
133 FILE *f;
134 char symstring[256]; /* keep count with "%<width>s" below */
135 search_symbol *symbolp,**symbolptail = &globals.search_symbol;
137 if (!(f = fopen(arg, "rt")))
138 fatal ("Cannot open <symfile>");
139 while (1 == fscanf(f, "%255s", symstring)) /* keep count with [<width>] above */
141 symstring[sizeof(symstring)-1] = '\0';
142 symbolp = xmalloc(sizeof(*symbolp) + strlen(symstring));
143 strcpy(symbolp->symbolname, symstring);
144 symbolp->found = FALSE;
145 symbolp->next = NULL;
146 *symbolptail = symbolp;
147 symbolptail = &symbolp->next;
149 if (fclose(f))
150 fatal ("Cannot close <symfile>");
154 static void do_verbose (const char *arg)
156 globals.do_verbose = TRUE;
160 static void do_symdmngl (const char *arg)
162 globals.do_demangle = TRUE;
165 static void do_dumphead (const char *arg)
167 globals.do_dumpheader = TRUE;
170 static void do_dumpsect (const char* arg)
172 unsigned count = 2;
173 char* p;
174 const char** out;
176 for (p = (char*)arg; (p = strchr(p, ',')) != NULL; p++, count++);
177 out = malloc(count * sizeof(char*));
178 globals.dumpsect = out;
179 count = 0;
180 p = strdup(arg);
181 for (;;)
183 out[count++] = p;
184 p = strchr(p, ',');
185 if (!p) break;
186 *p++ = '\0';
188 out[count] = NULL;
191 static void do_rawdebug (const char *arg)
193 globals.do_debug = TRUE;
196 static void do_dumpall(const char *arg)
198 globals.do_dumpheader = TRUE;
199 globals.do_dump_rawdata = TRUE;
200 globals.do_symbol_table = TRUE;
201 do_dumpsect ("ALL");
204 static void do_symtable(const char* arg)
206 globals.do_symbol_table = TRUE;
209 struct my_option
211 const char *name;
212 Mode mode;
213 int has_arg;
214 void (*func)(const char *arg);
215 const char *usage;
218 static const struct my_option option_table[] = {
219 {"--help",NONE, 0, do_usage, "--help Display this help message"},
220 {"-h", NONE, 0, do_usage, "-h Synonym for --help"},
221 {"-?", NONE, 0, do_usage, "-? Synonym for --help"},
222 {"dump", DUMP, 0, do_dump, "dump <file> Dump the contents of 'file' (dll, exe, lib...)"},
223 {"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"},
224 {"-f", DUMP, 0, do_dumphead, "-f Dump file header information"},
225 {"-G", DUMP, 0, do_rawdebug, "-G Dump raw debug information"},
226 {"-j", DUMP, 1, do_dumpsect, "-j <sect_name> Dump the content of section 'sect_name'\n"
227 " (use '-j sect_name,sect_name2' to dump several sections)\n"
228 " for NE: export, resource\n"
229 " for PE: import, export, debug, resource, tls, loadcfg, clr, reloc, dynreloc, except, apiset\n"
230 " for PDB: PDB, TPI, DBI, IPI, public, image\n"
231 " and suboptions: hash (PDB, TPI, TPI, DBI, public) and line (DBI)\n"
232 " for minidump: exception, handle, info, memory, module, system, thread, token\n"
233 " and suboptions: content (memory, module, thread, token)\n"},
234 {"-t", DUMP, 0, do_symtable, "-t Dump symbol table"},
235 {"-x", DUMP, 0, do_dumpall, "-x Dump everything"},
236 {"sym", DMGL, 0, do_demangle, "sym <sym> Demangle C++ symbol <sym> and exit"},
237 {"spec", SPEC, 0, do_spec, "spec <dll> Use 'dll' for input file and generate implementation code"},
238 {"-I", SPEC, 1, do_include, "-I <dir> Look for prototypes in 'dir' (implies -c)"},
239 {"-c", SPEC, 0, do_code, "-c Generate skeleton code (requires -I)"},
240 {"-t", SPEC, 0, do_trace, "-t TRACE arguments (implies -c)"},
241 {"-f", SPEC, 1, do_forward, "-f <dll> Forward calls to 'dll' (implies -t)"},
242 {"-D", SPEC, 0, do_document, "-D Generate documentation"},
243 {"-o", SPEC, 1, do_name, "-o <name> Set the output dll name (default: dll). Note: strips .dll extensions"},
244 {"-C", SPEC, 0, do_cdecl, "-C Assume __cdecl calls (default: __stdcall)"},
245 {"-s", SPEC, 1, do_start, "-s <num> Start prototype search after symbol 'num'"},
246 {"-e", SPEC, 1, do_end, "-e <num> End prototype search after symbol 'num'"},
247 {"-S", SPEC, 1, do_symfile, "-S <symfile> Search only prototype names found in 'symfile'"},
248 {"-q", SPEC, 0, do_quiet, "-q Don't show progress (quiet)."},
249 {"-v", SPEC, 0, do_verbose, "-v Show lots of detail while working (verbose)."},
250 {NULL, NONE, 0, NULL, NULL}
253 void do_usage (const char *arg)
255 const struct my_option *opt;
256 printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\n");
257 printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
258 printf (" When used in --help mode\n");
259 for (opt = option_table; opt->name; opt++)
260 if (opt->mode == NONE)
261 printf (" %s\n", opt->usage);
262 printf (" When used in sym mode\n");
263 for (opt = option_table; opt->name; opt++)
264 if (opt->mode == DMGL)
265 printf (" %s\n", opt->usage);
266 printf (" When used in spec mode\n");
267 for (opt = option_table; opt->name; opt++)
268 if (opt->mode == SPEC)
269 printf (" %s\n", opt->usage);
270 printf (" When used in dump mode\n");
271 for (opt = option_table; opt->name; opt++)
272 if (opt->mode == DUMP)
273 printf (" %s\n", opt->usage);
275 puts ("");
276 exit (1);
280 /*******************************************************************
281 * parse_cmdline
283 * Parse options from the argv array
285 static void parse_cmdline (char *argv[])
287 const struct my_option *opt;
288 char *const *ptr;
289 const char *arg = NULL;
291 ptr = argv + 1;
293 while (*ptr != NULL)
295 for (opt = option_table; opt->name; opt++)
297 if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
298 continue;
299 if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
300 ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
302 arg = *ptr + strlen (opt->name);
303 if (*arg == '\0') arg = *++ptr;
304 break;
306 if (!strcmp (*ptr, opt->name))
308 arg = NULL;
309 break;
313 if (!opt->name)
315 if ((*ptr)[0] == '-')
316 fatal ("Unrecognized option");
317 if (globals.input_name != NULL)
318 fatal ("Only one file can be treated at once");
319 globals.input_name = *ptr;
321 else if (opt->has_arg && arg != NULL)
322 opt->func (arg);
323 else
324 opt->func ("");
326 ptr++;
329 if (globals.mode == SPEC && globals.do_code && !globals.directory)
330 fatal ("-I must be used if generating code");
332 if (VERBOSE && QUIET)
333 fatal ("Options -v and -q are mutually exclusive");
335 if (globals.mode == NONE)
336 do_dump("");
339 static void set_module_name(BOOL setUC)
341 /* FIXME: we shouldn't assume all module extensions are .dll in winedump
342 * in some cases, we could have some .drv for example
344 globals.input_module = replace_extension( get_basename( globals.input_name ), ".dll", "" );
345 OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( xstrdup (OUTPUT_DLL_NAME)) : "";
348 /* Marks the symbol as 'found'! */
349 /* return: perform-search */
350 static BOOL symbol_searched(int count, const char *symbolname)
352 search_symbol *search_symbol;
354 if (!(count >= globals.start_ordinal
355 && (!globals.end_ordinal || count <= globals.end_ordinal)))
356 return FALSE;
357 if (!globals.search_symbol)
358 return TRUE;
359 for (search_symbol = globals.search_symbol;
360 search_symbol;
361 search_symbol = search_symbol->next)
363 if (!strcmp(symbolname, search_symbol->symbolname))
365 search_symbol->found = TRUE;
366 return TRUE;
369 return FALSE;
372 /* return: some symbols weren't found */
373 static BOOL symbol_finish(void)
375 const search_symbol *search_symbol;
376 BOOL started = FALSE;
378 for (search_symbol = globals.search_symbol;
379 search_symbol;
380 search_symbol = search_symbol->next)
382 if (search_symbol->found)
383 continue;
384 if (!started)
386 /* stderr? not a practice here */
387 puts("These requested <symfile> symbols weren't found:");
388 started = TRUE;
390 printf("\t%s\n",search_symbol->symbolname);
392 return started;
395 BOOL globals_dump_sect(const char* s)
397 const char** sect;
399 if (!s || !globals.dumpsect) return FALSE;
400 for (sect = globals.dumpsect; *sect; sect++)
401 if (!strcmp(*sect, s) || !strcmp(*sect, "ALL")) return TRUE;
402 return FALSE;
405 /*******************************************************************
406 * main
408 #ifdef __GNUC__
409 int main (int argc __attribute__((unused)), char *argv[])
410 #else
411 int main (int argc, char *argv[])
412 #endif
414 parsed_symbol symbol;
415 int count = 0;
417 globals.mode = NONE;
418 globals.forward_dll = NULL;
419 globals.input_name = NULL;
420 globals.dumpsect = NULL;
422 parse_cmdline (argv);
424 memset (&symbol, 0, sizeof (parsed_symbol));
426 switch (globals.mode)
428 case DMGL:
429 VERBOSE = TRUE;
431 if (globals.input_name == NULL)
432 fatal("No symbol name has been given\n");
433 printf("%s\n", get_symbol_str(globals.input_name));
434 break;
436 case SPEC:
437 if (globals.input_name == NULL)
438 fatal("No file name has been given\n");
439 set_module_name(TRUE);
440 if (!dll_open (globals.input_name))
441 break;
443 output_spec_preamble ();
444 output_header_preamble ();
445 output_c_preamble ();
447 while (dll_next_symbol (&symbol))
449 count++;
451 if (NORMAL)
452 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
453 VERBOSE ? '\n' : ' ');
455 if (globals.do_code && symbol_searched(count, symbol.symbol))
457 /* Attempt to get information about the symbol */
458 BOOL result = symbol_search(&symbol);
460 if (result && symbol.function_name)
461 /* Clean up the prototype */
462 symbol_clean_string (symbol.function_name);
464 if (NORMAL)
465 puts (result ? "[OK]" : "[Not Found]");
467 else if (NORMAL)
468 puts ("[Ignoring]");
470 output_spec_symbol (&symbol);
471 output_header_symbol (&symbol);
472 output_c_symbol (&symbol);
474 symbol_clear (&symbol);
477 output_makefile ();
479 if (VERBOSE)
480 puts ("Finished, Cleaning up...");
481 if (symbol_finish())
482 return 1;
483 break;
484 case NONE:
485 do_usage(0);
486 break;
487 case DUMP:
488 if (globals.input_name == NULL)
489 fatal("No file name has been given\n");
490 set_module_name(FALSE);
491 dump_file(globals.input_name);
492 break;
495 return 0;