main.c 12.6 KB
Newer Older
1 2 3 4
/*
 *  Option processing and main()
 *
 *  Copyright 2000 Jon Griffiths
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
 */

21
#include "config.h"
22
#include "wine/port.h"
23 24

#include "winedump.h"
25 26 27 28 29 30

_globals globals; /* All global variables */


static void do_include (const char *arg)
{
31 32 33 34 35 36 37 38 39
  char *newIncludes;

  if (!globals.directory)
    globals.directory = strdup(arg);
  else {
    newIncludes = str_create (3,globals.directory," ",arg);
    free(globals.directory);
    globals.directory = newIncludes;
  }
40
  globals.do_code = TRUE;
41 42 43 44 45
}


static inline const char* strip_ext (const char *str)
{
46 47 48
  int len = strlen(str);
  if (len>4 && strcmp(str+len-4,".dll") == 0)
    return str_substring (str, str+len-4);
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  else
    return strdup (str);
}


static void do_name (const char *arg)
{
  globals.dll_name = strip_ext (arg);
}


static void do_spec (const char *arg)
{
    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
    globals.mode = SPEC;
}


static void do_demangle (const char *arg)
{
    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
    globals.mode = DMGL;
71 72
    globals.do_code = TRUE;
    globals.do_demangle = TRUE;
73 74 75 76 77 78
}


static void do_dump (const char *arg)
{
    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
79
    globals.mode = DUMP;
80
    globals.do_code = TRUE;
81 82 83
}


84
static void do_code (const char *arg)
85
{
86
  globals.do_code = TRUE;
87 88 89
}


90
static void do_trace (const char *arg)
91
{
92 93
  globals.do_trace = TRUE;
  globals.do_code = TRUE;
94 95 96 97 98 99
}


static void do_forward (const char *arg)
{
  globals.forward_dll = arg;
100 101
  globals.do_trace = TRUE;
  globals.do_code = TRUE;
102 103
}

104
static void do_document (const char *arg)
105
{
106
  globals.do_documentation = TRUE;
107 108
}

109
static void do_cdecl (const char *arg)
110
{
111
  globals.do_cdecl = TRUE;
112 113 114
}


115
static void do_quiet (const char *arg)
116
{
117
  globals.do_quiet = TRUE;
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
}


static void do_start (const char *arg)
{
  globals.start_ordinal = atoi (arg);
  if (!globals.start_ordinal)
    fatal ("Invalid -s option (must be numeric)");
}


static void do_end (const char *arg)
{
  globals.end_ordinal = atoi (arg);
  if (!globals.end_ordinal)
    fatal ("Invalid -e option (must be numeric)");
}


137 138 139 140 141 142 143 144 145 146 147 148 149 150
static void do_symfile (const char *arg)
{
  FILE *f;
  char symstring[256];    /* keep count with "%<width>s" below */
  search_symbol *symbolp,**symbolptail = &globals.search_symbol;

  if (!(f = fopen(arg, "rt")))
    fatal ("Cannot open <symfile>");
  while (1 == fscanf(f, "%255s", symstring))    /* keep count with [<width>] above */
  {
    symstring[sizeof(symstring)-1] = '\0';
    if (!(symbolp = malloc(sizeof(*symbolp) + strlen(symstring))))
      fatal ("Out of memory");
    strcpy(symbolp->symbolname, symstring);
151
    symbolp->found = FALSE;
152 153 154 155 156 157 158 159 160
    symbolp->next = NULL;
    *symbolptail = symbolp;
    symbolptail = &symbolp->next;
  }
  if (fclose(f))
    fatal ("Cannot close <symfile>");
}


161
static void do_verbose (const char *arg)
162
{
163
  globals.do_verbose = TRUE;
164 165 166
}


167
static void do_symdmngl (const char *arg)
168
{
169
    globals.do_demangle = TRUE;
170 171
}

172
static void do_dumphead (const char *arg)
173
{
174
    globals.do_dumpheader = TRUE;
175 176 177 178 179 180 181
}

static void do_dumpsect (const char* arg)
{
    globals.dumpsect = arg;
}

182
static void do_rawdebug (const char *arg)
183
{
184
    globals.do_debug = TRUE;
185 186
}

187
static void do_dumpall(const char *arg)
188
{
189 190 191
    globals.do_dumpheader = TRUE;
    globals.do_dump_rawdata = TRUE;
    globals.do_symbol_table = TRUE;
192 193 194
    globals.dumpsect = "ALL";
}

195 196
static void do_symtable(const char* arg)
{
197
    globals.do_symbol_table = TRUE;
198 199
}

200
struct my_option
201 202 203 204
{
  const char *name;
  Mode mode;
  int   has_arg;
205
  void  (*func)(const char *arg);
206 207 208
  const char *usage;
};

209
static const struct my_option option_table[] = {
210 211 212
  {"--help",NONE, 0, do_usage,    "--help          Display this help message"},
  {"-h",    NONE, 0, do_usage,    "-h              Synonym for --help"},
  {"-?",    NONE, 0, do_usage,    "-?              Synonym for --help"},
213 214 215 216 217 218 219
  {"dump",  DUMP, 0, do_dump,     "dump <file>     Dump the contents of 'file' (dll, exe, lib...)"},
  {"-C",    DUMP, 0, do_symdmngl, "-C              Turn on symbol demangling"},
  {"-f",    DUMP, 0, do_dumphead, "-f              Dump file header information"},
  {"-G",    DUMP, 0, do_rawdebug, "-G              Dump raw debug information"},
  {"-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)"},
  {"-t",    DUMP, 0, do_symtable, "-t              Dump symbol table"},
  {"-x",    DUMP, 0, do_dumpall,  "-x              Dump everything"},
220 221 222 223 224 225 226 227 228 229 230 231 232 233
  {"sym",   DMGL, 0, do_demangle, "sym <sym>       Demangle C++ symbol <sym> and exit"},
  {"spec",  SPEC, 0, do_spec,     "spec <dll>      Use 'dll' for input file and generate implementation code"},
  {"-I",    SPEC, 1, do_include,  "-I <dir>        Look for prototypes in 'dir' (implies -c)"},
  {"-c",    SPEC, 0, do_code,     "-c              Generate skeleton code (requires -I)"},
  {"-t",    SPEC, 0, do_trace,    "-t              TRACE arguments (implies -c)"},
  {"-f",    SPEC, 1, do_forward,  "-f <dll>        Forward calls to 'dll' (implies -t)"},
  {"-D",    SPEC, 0, do_document, "-D              Generate documentation"},
  {"-o",    SPEC, 1, do_name,     "-o <name>       Set the output dll name (default: dll). Note: strips .dll extensions"},
  {"-C",    SPEC, 0, do_cdecl,    "-C              Assume __cdecl calls (default: __stdcall)"},
  {"-s",    SPEC, 1, do_start,    "-s <num>        Start prototype search after symbol 'num'"},
  {"-e",    SPEC, 1, do_end,      "-e <num>        End prototype search after symbol 'num'"},
  {"-S",    SPEC, 1, do_symfile,  "-S <symfile>    Search only prototype names found in 'symfile'"},
  {"-q",    SPEC, 0, do_quiet,    "-q              Don't show progress (quiet)."},
  {"-v",    SPEC, 0, do_verbose,  "-v              Show lots of detail while working (verbose)."},
234 235 236
  {NULL,    NONE, 0, NULL,        NULL}
};

237
void do_usage (const char *arg)
238
{
239
    const struct my_option *opt;
240
    printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\n");
241
    printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
242
    printf ("\tWhen used in --help mode\n");
243 244
    for (opt = option_table; opt->name; opt++)
	if (opt->mode == NONE)
245 246
	    printf ("\t   %s\n", opt->usage);
    printf ("\tWhen used in sym mode\n");
247 248
    for (opt = option_table; opt->name; opt++)
	if (opt->mode == DMGL)
249 250
	    printf ("\t   %s\n", opt->usage);
    printf ("\tWhen used in spec mode\n");
251 252
    for (opt = option_table; opt->name; opt++)
	if (opt->mode == SPEC)
253 254
	    printf ("\t   %s\n", opt->usage);
    printf ("\tWhen used in dump mode\n");
255 256
    for (opt = option_table; opt->name; opt++)
	if (opt->mode == DUMP)
257
	    printf ("\t   %s\n", opt->usage);
258

259
    puts ("");
260 261 262 263 264 265 266 267 268 269 270
    exit (1);
}


/*******************************************************************
 *          parse_options
 *
 * Parse options from the argv array
 */
static void parse_options (char *argv[])
{
271
  const struct my_option *opt;
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
  char *const *ptr;
  const char *arg = NULL;

  ptr = argv + 1;

  while (*ptr != NULL)
  {
    for (opt = option_table; opt->name; opt++)
    {
     if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
       continue;
     if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
	 ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
      {
        arg = *ptr + strlen (opt->name);
        if (*arg == '\0') arg = *++ptr;
        break;
      }
      if (!strcmp (*ptr, opt->name))
      {
        arg = NULL;
        break;
      }
    }

    if (!opt->name)
298 299 300 301 302 303 304 305
    {
        if ((*ptr)[0] == '-')
            fatal ("Unrecognized option");
        if (globals.input_name != NULL)
            fatal ("Only one file can be treated at once");
        globals.input_name = *ptr;
    }
    else if (opt->has_arg && arg != NULL)
306 307 308
	opt->func (arg);
    else
	opt->func ("");
309

310 311 312 313 314 315 316 317
    ptr++;
  }

  if (globals.mode == SPEC && globals.do_code && !globals.directory)
    fatal ("-I must be used if generating code");

  if (VERBOSE && QUIET)
    fatal ("Options -v and -q are mutually exclusive");
318 319 320

  if (globals.mode == NONE)
      do_dump("");
321 322
}

323
static void set_module_name(BOOL setUC)
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
{
    const char*	ptr;
    char*	buf;
    int		len;

    /* FIXME: we shouldn't assume all module extensions are .dll in winedump
     * in some cases, we could have some .drv for example
     */
    /* get module name from name */
    if ((ptr = strrchr (globals.input_name, '/')))
	ptr++;
    else
	ptr = globals.input_name;
    len = strlen(ptr);
    if (len > 4 && strcmp(ptr + len - 4, ".dll") == 0)
	len -= 4;
    buf = malloc(len + 1);
341
    memcpy(buf, (const void*)ptr, len);
342 343 344 345
    buf[len] = 0;
    globals.input_module = buf;
    OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( strdup (OUTPUT_DLL_NAME)) : "";
}
346

347 348
/* Marks the symbol as 'found'! */
/* return: perform-search */
349
static BOOL symbol_searched(int count, const char *symbolname)
350 351 352 353 354
{
    search_symbol *search_symbol;

    if (!(count >= globals.start_ordinal
          && (!globals.end_ordinal || count <= globals.end_ordinal)))
355
        return FALSE;
356
    if (!globals.search_symbol)
357
        return TRUE;
358 359 360 361 362 363
    for (search_symbol = globals.search_symbol;
         search_symbol;
         search_symbol = search_symbol->next)
    {
        if (!strcmp(symbolname, search_symbol->symbolname))
        {
364
            search_symbol->found = TRUE;
365
            return TRUE;
366 367
        }
    }
368
    return FALSE;
369 370 371
}

/* return: some symbols weren't found */
372
static BOOL symbol_finish(void)
373 374
{
    const search_symbol *search_symbol;
375
    BOOL started = FALSE;
376 377 378 379 380 381 382 383 384 385 386

    for (search_symbol = globals.search_symbol;
         search_symbol;
         search_symbol = search_symbol->next)
    {
        if (search_symbol->found)
            continue;
        if (!started)
        {
            /* stderr? not a practice here */
            puts("These requested <symfile> symbols weren't found:");
387
            started = TRUE;
388 389 390 391 392 393
        }
        printf("\t%s\n",search_symbol->symbolname);
    }
    return started;
}

394 395 396 397 398 399 400 401 402 403 404 405 406
/*******************************************************************
 *         main
 */
#ifdef __GNUC__
int   main (int argc __attribute__((unused)), char *argv[])
#else
int   main (int argc, char *argv[])
#endif
{
    parsed_symbol symbol;
    int count = 0;

    globals.mode = NONE;
407
    globals.forward_dll = NULL;
408
    globals.input_name = NULL;
409
    globals.dumpsect = NULL;
410 411 412 413 414 415 416 417

    parse_options (argv);

    memset (&symbol, 0, sizeof (parsed_symbol));

    switch (globals.mode)
    {
    case DMGL:
418
        VERBOSE = TRUE;
419

420 421 422
        if (globals.input_name == NULL)
            fatal("No symbol name has been given\n");
        printf("%s\n", get_symbol_str(globals.input_name));
423
	break;
424

425
    case SPEC:
426 427
        if (globals.input_name == NULL)
            fatal("No file name has been given\n");
428
        set_module_name(TRUE);
429 430
	if (!dll_open (globals.input_name))
            break;
431 432 433 434 435

	output_spec_preamble ();
	output_header_preamble ();
	output_c_preamble ();

436
        while (dll_next_symbol (&symbol))
437 438 439 440 441 442 443
	{
	    count++;

	    if (NORMAL)
		printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
			VERBOSE ? '\n' : ' ');

444
	    if (globals.do_code && symbol_searched(count, symbol.symbol))
445 446
	    {
		/* Attempt to get information about the symbol */
447
                BOOL result = symbol_demangle (&symbol) || symbol_search(&symbol);
448

449
                if (result && symbol.function_name)
450 451 452 453
		    /* Clean up the prototype */
		    symbol_clean_string (symbol.function_name);

		if (NORMAL)
454
                    puts (result ? "[OK]" : "[Not Found]");
455 456 457 458 459 460 461
	    }
	    else if (NORMAL)
		puts ("[Ignoring]");

	    output_spec_symbol (&symbol);
	    output_header_symbol (&symbol);
	    output_c_symbol (&symbol);
462

463 464 465 466 467 468 469
	    symbol_clear (&symbol);
	}

	output_makefile ();

	if (VERBOSE)
	    puts ("Finished, Cleaning up...");
470 471
        if (symbol_finish())
            return 1;
472 473
	break;
    case NONE:
474
	do_usage(0);
475 476
	break;
    case DUMP:
477 478
        if (globals.input_name == NULL)
            fatal("No file name has been given\n");
479
        set_module_name(FALSE);
480 481 482 483 484 485
	dump_file(globals.input_name);
	break;
    }

    return 0;
}