README 23.3 KB
Newer Older
1 2
Winedump - A Wine DLL tool
--------------------------
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

Background
----------

Most of the functions available in Windows, and in Windows applications, are
made available to applications from DLL's. Wine implements the Win32 API by
providing replacement's for the essential Windows DLLs in the form of Unix
shared library (.so) files, and provides a tool, winebuild, to allow Winelib
applications to link to functions exported from shared libraries/DLLs.

The first thing to note is that there are many DLLs that aren't yet
implemented in Wine. Mostly this doesn't present a problem because the native
Win32 versions of lots of DLLs can be used without problems, at least on
x86 platforms. However, one of Wine's goals is the eventual replacement of
every essential O/S DLL so that the whole API is implemented. This not only
means that a copy of the real O/S is not needed, but also that non-x86
platforms can run most Win32 programs after recompiling.

The second thing to note is that applications commonly use their own or 3rd
party DLLs to provide functionality. In order to call these functions with
a Winelib program, some 'glue' is needed. This 'glue' comes in the form of
a .spec file. The .spec file, along with some dummy code, is used to create
a Wine .so corresponding to the Windows DLL. The winebuild program can then
resolve calls made to DLL functions to call your dummy DLL. You then tell
Wine to only use the native Win32 version of the DLL, and at runtime your
calls will be made to the Win32 DLL. If you want to reimplement the dll,
you simply add the code for the DLL calls to your stub .so, and then tell
Wine to use the .so version instead [1].

These two factors mean that if you are:

A: Reimplementing a Win32 DLL for use within Wine, or
B: Compiling a Win32 application with Winelib that uses x86 DLLs

Then you will need to create a .spec file (amongst other things). If you
38
won't be doing either of the above, then you won't need winedump.
39 40

Creating a .spec file is a labour intensive task during which it is easy
41
to make a mistake. The idea of winedump is to automate this task and create
42
the majority of the support code needed for your DLL. In addition you can
43
have winedump create code to help you reimplement a DLL, by providing
44 45 46
tracing of calls to the DLL, and (in some cases) automatically determining
the parameters, calling conventions, and return values of the DLLs functions.

47
You can think of winedump as somewhat similar to the IMPLIB tool when
48 49 50 51 52 53
only its basic functionality is used.


Usage
-----

54
Winedump is a command line tool. Running it with no arguments or passing
55 56
it '-h' on the command line lists the available options:

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
Winedump can be used for different usages:
- generating default source files (.spec, .c...) for using a native DLL in Wine
- demangling MSVC C++ symbol names
- dumping the 'PE' files contents

Usage: winedump [-h sym <sym> spec <dll> dump <dll>] [mode options]
When used in -h mode
   -h           Display this help message
When used in sym mode
   sym <sym>    Demangle C++ symbol <sym>' and exit
When used in spec mode
   spec <dll>   Use dll for input file and generate implementation code
   -I dir       Look for prototypes in 'dir' (implies -c)
   -c           Generate skeleton code (requires -I)
   -t           TRACE arguments (implies -c)
   -f dll       Forward calls to 'dll' (implies -t)
   -D           Generate documentation
   -o name      Set the output dll name (default: dll)
   -C           Assume __cdecl calls (default: __stdcall)
   -s num       Start prototype search after symbol 'num'
   -e num       End prototype search after symbol 'num'
   -q           Don't show progress (quiet).
   -v           Show lots of detail while working (verbose).
When used in dump mode
   dump <dll>   Dumps the content of the dll named <dll>
   -C           Turns on symbol demangling
   -f           Dumps file header information
   -j sect_name Dumps only the content of section sect_name (import, export, debug)
   -x           Dumps everything
86 87 88 89 90 91

Basic options
-------------

OPTION: -o name  Set the output dll name (default: dll)

92
By default, if winedump is run on DLL 'foo', it creates files called
93 94 95 96 97 98 99 100 101 102
'foo.spec', 'foo_main.c' etc, and prefixes any functions generated
with 'FOO_'. If '-o bar' is given, these will become 'bar.spec',
'bar_main.c' and 'BAR_' respectively.

This option is mostly useful when generating a forwarding DLL. See below
for more information.

OPTION: -q       Don't show progress (quiet).
        -v       Show lots of detail while working (verbose).

103
There are 3 levels of output while winedump is running. The default level,
104 105 106
when neither -q or -v are given, prints the number of exported functions
found in the dll, followed by the name of each function as it is processed,
and a status indication of whether it was processed OK. With -v given, a
107
lot of information is dumped while winedump works: this is intended to help
108
debug any problems. Giving -q means nothing will be printed unless a fatal
109
error occurs, and could be used when calling winedump from a script.
110 111 112 113 114 115 116 117 118


OPTION: -C       Assume __cdecl calls (default: __stdcall)

This option determines the default calling convention used by the functions
in the DLL. If specbuild cannot determine the convention, __stdcall is
used by default, unless this option has been given.

Unless -q is given, a warning will be printed for every function that
119
winedump determines the calling convention for and which does not match
120 121 122 123 124 125 126 127 128 129 130 131
the assumed calling convention.


Generating stub DLLS
--------------------

If all you want to do is generate a stub DLL to allow you to link your
Winelib application to an x86 DLL, the above options are all you need.

As an example, lets assume the application you are porting uses functions
from a 3rd party dll called 'zipextra.dll', and the functions in the DLL
use the __stdcall calling convention. Copy zipextra.dll to an empty directory,
132
change to it, and run winedump as follows:
133

134
winedump spec zipextra  (Note: this assumes winedump is in your path)
135 136 137

The output will look something like the following:

138
22 named symbols in DLL, 22 in total ...
139 140 141 142
Export    1 - '_OpenZipFile' ... [Ignoring]
Export    2 - '_UnZipFile' ... [Ignoring]
...

143
"[Ignoring]" Just tells you that winedump isn't trying to determine the
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
parameters or return types of the functions, its just creating stubs.

The following files are created:

zipextra.spec
This is the .spec file. Each exported function is listed as a stub:

@ stub _OpenZipFile
@ stub _UnZipFile
...

This means that winebuild will generate dummy code for this function. That
doesn't concern us, because all we want is for winebuild to allow the
symbols to be resolved. At run-time, the functions in the native DLL will
be called; this just allows us to link.

zipextra_dll.h zipextra_main.c
These are source code files containing the minimum set of code to build
a stub DLL. The C file contains one function, ZIPEXTRA_Init, which does
nothing.

Makefile.in
This is a template for 'configure' to produce a makefile. It is designed
for a DLL that will be inserted into the Wine source tree. If your DLL
will not be part of Wine, or you don't wish to build it this way,
you should look at the Wine tool 'winemaker' to generate a DLL project.

FIXME: winemaker could run this tool automatically when generating projects
that use extra DLL's (*.lib in the "ADD LINK32" line in .dsp) ....

zipextra_install
A shell script for adding zipextra to the Wine source tree (see below).


Inserting a stub DLL into the Wine tree
---------------------------------------

To build your stub DLL as part of Wine, do the following:

 chmod a+x ./zipextra_install
 ./zipextra_install <wine-path>
 cd <wine-path>
 autoconf
 ./configure
 make depend && make
 make install

Your application can now link with the DLL.

NOTE: **DO NOT** submit patches to Wine for 3rd party DLLs! Building DLLs
      into your copy of the tree is just a simple way for you to link. When
      you release your application you won't be distributing the Unix .so
      anyway, just the Win32 DLL. As you update your version of Wine
      you can simply re-run the procedure above (Since no patches are
      involved, it should be pretty resiliant to changes).


Advanced Options
----------------

204
This section discusses features of winedump that are useful to Wine Hackers
205 206 207 208 209 210 211
or developers looking to reimplement a Win32 DLL for Unix. Using these
features means you will need to be able to resolve compilation problems and
have a general understanding of Wine programming.


OPTION: -I dir   Look for prototypes in 'dir' (implies -c)

212
For all advanced functionality, you must give winedump a directoryor file that
213 214 215 216 217 218 219 220 221
contains prototypes for the DLL. In the case of Windows DLLs, this could be
either the standard include directory from your compiler, or an SDK include
directory. If you have a text document with prototypes (such as documentation)
that can be used also, however you may need to delete some non-code lines to
ensure that prototypes are parsed correctly.

The 'dir' argument can also be a file specification (e.g. "include/*"). If
it contains wildcards you must quote it to prevent the shell from expanding it.

222
If you have no prototypes, specify /dev/null for 'dir'. Winedump may still
223 224 225 226 227 228 229 230
be able to generate some working stub code for you.

Once you have created your DLL, if you generated code (see below), you can
backup the DLL header file created and use it for rebuilding the DLL (you
should remove the DLLNAME_ prefix from the prototypes to make this work). This
allows you to add names to the function arguments, for example, so that the
comments and prototype in the regenerated DLL will be clearer.

231
Winedump searches for prototypes using 'grep', and then retrieves each
232 233 234
prototype by calling 'function_grep.pl', a Perl script. When you pass the -v
option on the command line, the calls to both of these programs are logged.
This allows you to see where each function definition has come from. Should
235
winedump take an excessively long time to locate a prototype, you can check
236 237 238 239 240 241 242 243 244 245
that it is searching the right files; you may want to limit the number of files
searched if locating the prototype takes too long.

You can compile function_grep.pl for a slight increase in performance; see
'man perlcc' for details.


OPTION: -s num   Start prototype search after symbol 'num'
        -e num   End prototype search after symbol 'num'

246
By passing the -s or -e options you can have winedump try to generate code
247 248 249 250 251 252 253 254
for only some functions in your DLL. This may be used to generate a single
function, for example, if you wanted to add functionality to an existing DLL.

They is also useful for debugging problems, in conjunction with -v.


OPTION: -D       Generate documentation

255 256
By default, winedump generates a standard comment at the header of each
function it generates. Passing this option makes winedump output a full
257 258 259 260 261 262
header template for standard Wine documentation, listing the parameters
and return value of the function.


OPTION: -c       Generate skeleton code (requires -I)

263
This option tells winedump that you want to create function stubs for
264
each function in the DLL. This is the most basic level of code generation.
265
As winedump reads each exported symbol from the source DLL, it first tries
266
to demangle the name. If the name is a C++ symbol, the arguments, class and
267
return value are all encoded into the symbol name. Winedump converts this
268 269 270 271 272 273 274 275
information into a C function prototype. If this fails, the file(s) specified
in the -I argument are scanned for a function prototype. If one is found it
is used for the next step of the process, code generation.

Note: C++ name demangling is currently under development. Since the algorithm
used is not documented, it must be decoded. Many simple prototypes are already
working however.

276
If winedump does not find a prototype, it emits code like the following:
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

In the .spec file:

@stub _OpenZipFile

in the header file:

/* __cdecl ZIPEXTRA__OpenZipFile() */

in the C source file:

/*********************************************************************
 *      _OpenZipFile     (ZIPEXTRA.@)
 *
 */
#if 0
__stdcall ZIPEXTRA__OpenZipFile()
{
    /* '@Stubbed'ed in .spec */
}
#endif

If a prototype is found, or correctly demangled, the following is emitted:

.spec:
@ stdcall _OpenZipFile ZIPEXTRA__OpenZipFile

.h:
BOOL __stdcall ZIPEXTRA__OpenZipFile(LPCSTR pszFileName);

.c:
BOOL __stdcall ZIPEXTRA__OpenZipFile(LPCSTR pszFileName)
{
  TRACE("stub");
  return 0;
}

314
Note that if the prototype does not contain argument names, winedump will
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
add them following the convention arg0, arg1 ... argN. If the function is
demangled C++, the first argument will be called '_this' if an implicit this
pointer is passed (i.e. the function is a non-static class member function).


OPTION: -t       TRACE arguments (implies -c)

This option produces the same code as -c, except that arguments are printed
out when the function is called, so the FIXME in the above example becomes:

  FIXME("(%s) stub", pszFileName);

Structs that are passed by value are printed as "struct", and functions
that take variable argument lists print "...".


OPTION: -f dll   Forward calls to 'dll' (implies -t)

This is the most complicated level of code generation. The same code is
generated as -t, however support is added for forwarding calls to another
DLL. The DLL to forward to is given as 'dll'. Lets suppose we built the
examples above using "-f real_zipextra". The code generated will look like
the following:

.spec
As for -c, except if a function prototype was not found:

@ forward _OpenZipFile real_zipextra._OpenZipFile

In this case the function is forwarded to the destination DLL rather
than stubbed.

.h
As for -c.

.c

A variable "hDLL" is added to hold a pointer to the DLL to forward to, and
the initialisation code in ZIPEXTRA_Init is changed to load and free the
forward DLL automatically:

HMODULE hDLL = 0; /* DLL to call through to */

BOOL WINAPI ZIPEXTRA_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    TRACE("(0x%08x, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);

    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        hDLL = LoadLibraryA( "real_zipextra" );
        TRACE ("Forwarding DLL (real_zipextra) loaded\n" );
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        FreeLibrary( hDLL );
        TRACE ("Forwarding DLL (real_zipextra) freed\n" );
    }

    return TRUE;
}

The stub function is changed to call the forwarding DLL and return that value.

BOOL __stdcall ZIPEXTRA__OpenZipFile(LPCSTR pszFileName)
{
  BOOL (__stdcall *pFunc)(LPCSTR) = (void*)GetProcAddress(hDLL,"_OpenZipFile");
  BOOL retVal;
  TRACE("((LPCSTR)%s) stub", pszFileName);
  retVal = pFunc(pszFileName);
  TRACE("returned (%ld)\n",(LONG)retVal));
  return retVal;
}

This allows you to investigate the workings of a DLL without interfering in
its operation in any way (unless you want to).

In the example I have been using, we probably should have used the -o option
to change the ouput name of our DLL to something else, and used the -f
option to forward to the real zipextra DLL:

395
winedump spec zipextra -f zipextra -o myzipextra -I "~/zipextra/include/*h"
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

Then in the .spec file for our Winelib application, we add the line:

import myzipextra

When we build our application, winebuild resolves the calls to our Unix .so.
As our application runs we can see the values of all parameters passed to
the DLL, and any values returned, without having to write code to dump
them ourselves (see below for a better way to wrap a DLL for forwarding).

This isn't a very realistic example of the usefulness of this feature,
however, since we could print out the results anyway, because it is our
application making the calls to the DLL. Where DLL forwarding is most useful
is where an application or DLL we didn't write calls functions in the DLL.
In this case we can capture the sequence of calls made, and the values passed
around. This is an aid in reimplementing the DLL, since we can add code for a
function, print the results, and then call the real DLL and compare. Only
when our code is the same do we need to remove the function pointer and the
call to the real DLL. A similar feature in wine is +relay debugging. Using a
fowarding DLL allows more granular reporting of arguments, because you can
write code to dump out the contents of types/structures rather than just
417
their address in memory. A future version of winedump may generate this
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
code automatically for common Win32 types.

See below for more information on setting up a forwarding DLL.


Problems compiling a DLL containing generated code
--------------------------------------------------

Unless you are very lucky, you will need to do a small amount of work to
get a DLL generated with -c, -t or -f to compile. The reason for this is
that most DLLs will use custom types such as structs whose definition
is not known to the code in the DLL.

Heres an example prototype from crtdll:

double __cdecl _cabs(struct _complex arg0)

The definition for the _complex struct needs to be given. Since it is passed
by value, its size also needs to be correct in order to forward the call
correctly to a native DLL. In this case the structure is 8 bytes in size, which
means that the gcc compile flag -freg-struct-return must be given when
compiling the function in order to be compatable with the native DLL. (In 
general this is not an issue, but you need to be aware of such issues if you
encounter problems with your forwarding DLL).

For third party (non C++) DLL's, the header(s) supplied with the DLL  can
normally be added as an include to the generated DLL header. For other DLLs
I suggest creating a seperate header in the DLL directory and adding any
needed types to that. This allows you to rebuild the DLL at whim, for example
447
if a new version of winedump brings increased functionality, then you
448 449 450 451 452 453 454 455 456 457
only have to overwrite the generated files and re-include the header to take
advantage of it.

Usually there isn't much work to do to get the DLL to compile if you have
headers. As an example, building a forwarded crtdll, which contains 520
functions, required 20 types to be defined before it compiled. Of these,
about half were structures, so about 35 lines of code were needed. The only
change to the generated code was one line in the header to include the type
definitions.

458
To save some typing in case you don't have headers for your DLL type, winedump
459 460
will dump dummy declarations for unknown classes and types it encounters,
if you use the -v option. These can be piped directly into a fix-up header
461
file for use in compiling your DLL. For example, if winedump encounters the
462 463 464 465 466 467 468 469 470 471 472 473 474
(C++ ) symbol:

??0foobar@@QAE@ABV0@@Z   (Which is a constructor for a foobar object)

It will emit the following with -v set:

struct foobar { int _FIXME; };

(Classes are mapped to C structs when generating code).

The output should be piped through 'sort' and 'uniq' to remove multiple
declarations, e.g:

475
winedump -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h
476 477 478 479

By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be
greatly reduced.

480
If winedump encounters a type it doesnt know that is passed by value (as in
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
the _cabs example above), it also prints a FIXME message like:

/* FIXME: By value type: Assumed 'int' */ typedef int ldiv_t;
 
If the type is not an int, you will need to change the code and possibly
the .spec entry in order to forward correctly. Otherwise, include the typedef
in your fixup header to avoid compile errors.


Using a forwarding DLL
----------------------

To create and use a forwarding DLL to trace DLL calls, you need to first
create a DLL using the -f option as outlined above, and get it to compile.
In order to forward calls the following procedure can be used (for this
example we are going to build a forwarding msvcrt.dll for the purpose
of reimplementing it).

First we create the forwarding DLL. We will rename the real msvcrt.dll on our
system to ms_msvcrt.dll, and our msvcrt implementation will call it:

502
winedump spec msvcrt -C -f ms_msvcrt -I "inc/*.h"
503 504 505

We then install this DLL into the Wine tree and add the types we need to
make it compile. Once the DLL compiles, we create a dummy ms_msvcrt DLL so
506
winebuild will resolve our forward calls to it (for the cases where winedump
507 508
couldn't generate code and has placed an '@forward' line in the .spec file):

509
winedump spec msvcrt -C -o ms_msvcrt
510 511 512 513

Install this DLL into the wine tree (since its a stub DLL, no changes are
needed to the code).

514
Now uncomment the line that winedump inserted into msvcrt.spec:
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545

#inport ms_msvcrt.dll

And recompile Wine.

Finally, we must tell Wine to only use the builtin msvcrt.dll and to only use
the native (Win32) ms_msvcrt.dll. Add the following two lines to ~/.wine/config
under the [DllOverrides] section:

;Use our implmentation of msvcrt
"msvcrt" = "builtin, so"
;Use only the Win32 ms_msvcrt
"ms_msvcrt" = "native"

At this point, when any call is made to msvcrt.dll, Our libmsvcrt.so recieves
the call. It then forwards or calls ms_msvcrt.dll, which is the native dll. We
recieve a return value and pass it back to our caller, having TRACEd the
arguments on the way.

At this point you are ready to start reimplementing the calls.


Final comments
--------------

If you have any suggestions for improving this tool, please let me know.
If anyone can help answer the FIXME questions in msmangle.c or can fill me in
on any aspect of the C++ mangling scheme, I would appreciate it. In particular
I want to know what _E and _G represent.

If you encounter a C++ symbol that doesn't demangle **AND** you have the
546
prototype for it, please send me the symbol as reported by winedump and the
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
prototype. The more examples I have the easier it is to decypher the scheme,
and generating them myself is very slow.

Finally, although it is easy to generate a DLL, I _very strongly_ suggest that
you dont submit a generated DLL for inclusion into Wine unless you have
actually implemented a fairly reasonable portion of it. Even then, you should
only send the portions of the DLL you have implemented. Thousands of lines of
stub code don't help the project at all.

Please send questions and bug reports to jon_p_griffiths@yahoo.com.


References
----------

[1] See the Wine and Wine.conf man pages for details on how to tell Wine
    whether to use native (Win32) or internal DLLs.

565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

Demangling
----------

If you need to demangle a single C++ symbol, you can use the demangling mode
of winedump. This is useful for testing the demangler or implementing
C++ functions in partially implemented wine DLLS. As an example:

winedump sym "??3@YAXPAX@Z"

Gives:

void __cdecl _global_operator_delete_1(void * arg0)

Which is enough information to begin implementing the function.


Dumping
-------

Another tool might be helpful digging into a 32bit DLL (and any PE image file):
pedump.

Usage:
   -h           Display this help message
   -d <dll>     Use dll for input file and generate implementation code
   -C           Turns on symbol demangling
   -f           Dumps file header information
   -j dir_name  Dumps only the content of directory dir_name (import, export, debug)
   -x           Dumps everything

The basic usage, to look everything in a file is:
winedump dump -d mydll.dll -x

It'll print any available information on the file. This information can be splitted
into sub-categories:
- file hedaers (request by -f or -x) are made of the standard PE header structures, 
  plus the COFF sections
- directories: you can print them one after the other using the -j switch. Currently, 
  only the import, export and debug directories are implemented.
- -x displays the file headers and any available directory.