This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gdb for Windows doesn't understand debugging symbol of Wine


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]