| Winedump - A Wine DLL tool |
| -------------------------- |
| |
| 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 |
| won't be doing either of the above, then you won't need winedump. |
| |
| Creating a .spec file is a labour intensive task during which it is easy |
| to make a mistake. The idea of winedump is to automate this task and create |
| the majority of the support code needed for your DLL. In addition you can |
| have winedump create code to help you reimplement a DLL, by providing |
| tracing of calls to the DLL, and (in some cases) automatically determining |
| the parameters, calling conventions, and return values of the DLLs functions. |
| |
| You can think of winedump as somewhat similar to the IMPLIB tool when |
| only its basic functionality is used. |
| |
| |
| Usage |
| ----- |
| |
| Winedump is a command line tool. Running it with no arguments or passing |
| it '-h' on the command line lists the available options: |
| |
| 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 |
| |
| Basic options |
| ------------- |
| |
| OPTION: -o name Set the output dll name (default: dll) |
| |
| By default, if winedump is run on DLL 'foo', it creates files called |
| '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). |
| |
| There are 3 levels of output while winedump is running. The default level, |
| 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 |
| lot of information is dumped while winedump works: this is intended to help |
| debug any problems. Giving -q means nothing will be printed unless a fatal |
| error occurs, and could be used when calling winedump from a script. |
| |
| |
| 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 |
| winedump determines the calling convention for and which does not match |
| 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, |
| change to it, and run winedump as follows: |
| |
| winedump spec zipextra (Note: this assumes winedump is in your path) |
| |
| The output will look something like the following: |
| |
| 22 named symbols in DLL, 22 in total ... |
| Export 1 - '_OpenZipFile' ... [Ignoring] |
| Export 2 - '_UnZipFile' ... [Ignoring] |
| ... |
| |
| "[Ignoring]" Just tells you that winedump isn't trying to determine the |
| 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 |
| ---------------- |
| |
| This section discusses features of winedump that are useful to Wine Hackers |
| 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) |
| |
| For all advanced functionality, you must give winedump a directoryor file that |
| 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. |
| |
| If you have no prototypes, specify /dev/null for 'dir'. Winedump may still |
| 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. |
| |
| Winedump searches for prototypes using 'grep', and then retrieves each |
| 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 |
| winedump take an excessively long time to locate a prototype, you can check |
| 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' |
| |
| By passing the -s or -e options you can have winedump try to generate code |
| 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 |
| |
| By default, winedump generates a standard comment at the header of each |
| function it generates. Passing this option makes winedump output a full |
| header template for standard Wine documentation, listing the parameters |
| and return value of the function. |
| |
| |
| OPTION: -c Generate skeleton code (requires -I) |
| |
| This option tells winedump that you want to create function stubs for |
| each function in the DLL. This is the most basic level of code generation. |
| As winedump reads each exported symbol from the source DLL, it first tries |
| to demangle the name. If the name is a C++ symbol, the arguments, class and |
| return value are all encoded into the symbol name. Winedump converts this |
| 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. |
| |
| If winedump does not find a prototype, it emits code like the following: |
| |
| 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\n"); |
| return 0; |
| } |
| |
| Note that if the prototype does not contain argument names, winedump will |
| 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\n", 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: |
| |
| winedump spec zipextra -f zipextra -o myzipextra -I "~/zipextra/include/*h" |
| |
| 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 |
| their address in memory. A future version of winedump may generate this |
| 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 |
| if a new version of winedump brings increased functionality, then you |
| 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. |
| |
| To save some typing in case you don't have headers for your DLL type, winedump |
| 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 |
| file for use in compiling your DLL. For example, if winedump encounters the |
| (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: |
| |
| winedump -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h |
| |
| By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be |
| greatly reduced. |
| |
| If winedump encounters a type it doesnt know that is passed by value (as in |
| 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: |
| |
| winedump spec msvcrt -C -f ms_msvcrt -I "inc/*.h" |
| |
| 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 |
| winebuild will resolve our forward calls to it (for the cases where winedump |
| couldn't generate code and has placed an '@forward' line in the .spec file): |
| |
| winedump spec msvcrt -C -o ms_msvcrt |
| |
| Install this DLL into the wine tree (since its a stub DLL, no changes are |
| needed to the code). |
| |
| Now uncomment the line that winedump inserted into msvcrt.spec: |
| |
| #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 |
| prototype for it, please send me the symbol as reported by winedump and the |
| 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. |
| |
| |
| 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. |