main.c 13 KB

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