gdb for Windows doesn't understand debugging symbol of Wine
Qian Hong <[email protected]>
| Newsgroups | gmane.comp.gdb.devel |
|---|---|
| Message-ID | <CALd+sZSkE5005jvS+ZP-PL8RfKdBLQHZio9bw2eBu3XEqTJVAQ@mail.gmail.com> |
Dear list, We are working on improving Wine support of win32 version of GNU toolchains, including gcc / gdb / binutils / etc. With Wine (staging) plus a few local hacks, I've successfully built 300+ MSYS2 packages [1] using GNU toolchain provided by MSYS2. During this process, a lot of Wine bugs are detected and fixed, while we also hit some partner project (from those 300 packages) bugs by accident, which was a lot of fun. However, when debugging Win32 version of GNU toolchains on Wine, one painful thing is lack of debugging symbol info. On one side, the Wine builtin debugger (winedbg) has dwarf2 support but doesn't understand dwarf3/dwarf4, so their is no symbol for those recent MSYS2 exes. (OT: nobody working on that yet, volunteers welcome, feel free to contact me if anyone has interesting to start). On the other side, the Win32 version of gdb also doesn't understand the memory layout and symbol of Wine modules good enough, which is what I'm asking for help here. Wine's builtin dll system includes two kinds of module: one we call fake dlls, which has a fake PE32 header and an extension name of .dll; the other one is the real library, which is in the ELF32 format and has an extension name of .dll.so. Assume we installed Wine on Linux, one can look at /usr/lib/wine/fakedlls/ntdll.dll.fake as an example of fake dll, and look at /usr/lib/wine/ntdll.dll.so as an example of the real library. Once a user initialize Wine by running winecfg or any wine/win32 executable, those fake dlls in /usr/lib/wine/fakedlls/ will be copied to ~/.wine/drive_c/windows/system32 and the extension name will be renamed to .dll. When Wine load a win32 process, the memory layout is like below, generated by Wine's builtin debugger: info share Module Address Debug info Name (29 modules) PE 400000- 42e000 Dwarf curl PE 61000000-61500000 Dwarf msys-2.0 PE 618c0000-619a9000 Dwarf msys-iconv-2 PE 62000000-6200f000 Dwarf msys-intl-8 PE 62c00000-62def000 --none-- msys-crypto-1.0.0 PE 63900000-63970000 Dwarf msys-curl-4 PE 644c0000-644da000 Dwarf msys-z PE 69b40000-69b6c000 Dwarf msys-expat-1 PE 6ac00000-6ac20000 Dwarf msys-gcc_s-1 PE 6ad40000-6ad52000 Dwarf msys-metalink-3 PE 6bac0000-6bb35000 --none-- msys-ssl-1.0.0 PE 6d840000-6d86c000 Dwarf msys-ssh2-1 PE 70980000-709b7000 Dwarf msys-idn-11 ELF 7b800000-7ba71000 Dwarf kernel32<elf> \-PE 7b810000-7ba71000 \ kernel32 ELF 7bc00000-7bd09000 Dwarf ntdll<elf> \-PE 7bc10000-7bd09000 \ ntdll ELF 7bf00000-7bf04000 Dwarf <wine-loader> ELF 7e567000-7e574000 Dwarf libnss_files.so.2 ELF 7e574000-7e580000 Dwarf libnss_nis.so.2 ELF 7e580000-7e599000 Dwarf libnsl.so.1 ELF 7ef9a000-7efe0000 Dwarf libm.so.6 ELF b7341000-b7346000 Dwarf libdl.so.2 ELF b7346000-b74f3000 Dwarf libc.so.6 ELF b74f4000-b7511000 Dwarf libpthread.so.0 ELF b7517000-b7520000 Dwarf libnss_compat.so.2 ELF b7531000-b76f9000 Dwarf libwine.so.1 ELF b76fb000-b771d000 Dwarf ld-linux.so.2 ELF b771d000-b771e000 Dwarf [vdso].so In the above table, some modules start has a type of "PE", like curl and msys-2.0, they are real win32 PE binaries, Win32 gdb can understand their debugging symbol; Some modules start from ELF and then connected by a line of "\-PE", like ntdll<elf> and ntdll, they are Wine's builltin modules, Win32 gdb can't understand their debugging info. The main reason that Win32 gdb doesn't understand Wine module debugging info is, those fake PE dll doesn't contain any debugging info at all. Below is a proof of concept to help Win32 gdb read Wine's debugging symbol. The proof of concept is for ntdll.dll only: Firstly, use tool like objcopy to adjust the .text section of Wine's fake PE module ntdll.dll: $ pwd /home/<user>/.wine/drive_c/windows/system32 $ objcopy --change-section-address .text+0xf000 ntdll.dll (I'm lying, the real process is more complicate and painful, but I simplify the description here) Second, use objcopy to extract debugging symbol from debugging build of ntdll.dll.so: $ objcopy --only--keep-debug ntdll.dll.so ntdll.dbg Finally, link the fake PE module with the newly created debugging info file: $ objcopy --add-gnu-debuglink=ntdll.dbg ntdll.dll After that, restart a Win32 gdb on Wine, and it will understand Wine's debugging info from ntdll.dll now. Wine's builtin debugger use a different way to understand Wine's module debugging info. Basically, Wine's debugger use the public Win32 api SymLoadModuleExW() to load module and public Win32 api SymFromAddr() to translate address to symbols. In Wine's implementation, SymFromAddr() calls module_get_debug(), which handle different kinds of modules. module_get_debug() calls module_get_container() to try to find if there is a "container" of a module. For example, Wine's builtin fake ntdll.dll is in the address range of 7bc10000-7bd09000, while Wine's builtin ntdll.dll.so is in the address range of 7bc00000-7bd09000, the latter covers the former, so we call the latter is a container of the former. Once Wine found a container, it will try to load the debugging symbol of the container, that is why Wine's builtin debugger work with Wine's builtin fake dll while those fake dlls even have no symbols. It would be great if we can make Win32 gdb works with Wine's module, I personally prefer Win32 gdb much more than Wine's builtin debugger since it is more complete and more powerful (for example, thread handle is missing in Wine's builtin debugger, but it works well with Wine + Win32 gdb). One possible idea come to my mind is implementing a "fallback" mode in Win32 gdb: firstly trying to load module using current gdb way, and if it doesn't find debugging symbols, try the Win32 api SymLoadModuleExW(), and if symbol is found this time, use SymFromAddr() to in the future for that module. In this way, gdb might be able to work better both on Windows and Wine: on Windows, it can use SymFromAddr() to understand MS VC++'s debugging symbols; on Wine, it can use Wine's SymFromAddr() to understand Wine's mixed PE+ELF modules. Would that be possible, and would that be a valid feature request to gdb? If someone could write a draft patch I'm more than glad to test, otherwise if anyone could point out the start point to hack or even mentor on this topic, I'm happy to give myself a try as well. It might be also possible to implement Wine support without any Win32 api if preferable, if anyone support any other idea I would be glad to test / try as well. Any comment is great appreciated and thanks for the cool job! (I'm CCing two Wine developers who is willing to be CCed, please CC Sebastian and Michael in your reply, thank you!) [1] https://github.com/Alexpux/MSYS2-packages [2] https://github.com/wine-compholio/wine-patched/blob/master/dlls/dbghelp/module.c#L333 -- Regards, Qian Hong - http://www.winehq.org