To help gdb reload symbol files from /proc/<pid>/maps, making it possible to load debug info for ELF and PE modules for Wine processes.
When sourced (from ~/.gdbinit for instance), this adds a new "load-symbol-files" command (with an "lsf" alias), which automatically calls add-symbol-file on every mapped file that can be read as ELF or PE, with the correct section offset.
The command has to be run manually, for instance after executing for a while, to load new modules that may have been loaded, as there's no way for gdb to be notified of such changes automatically.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This is some script I've been using for a while, and more or less broken versions are also used by other people, so I figured maybe it would be better to have a proper working version officially distributed with Wine source instead, as it's pretty useful for debugging Wine under gdb.
It's still a bit manual to use, as gdb cannot easily be notified of dynamic library loading [1], but I think it's much better than having nothing.
[1] in theory there's ways to do it using systemtap probes, but it's going to be hard to make it work, especially for PE modules.
tools/gdbinit.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 tools/gdbinit.py
diff --git a/tools/gdbinit.py b/tools/gdbinit.py new file mode 100644 index 00000000000..265d97722b7 --- /dev/null +++ b/tools/gdbinit.py @@ -0,0 +1,108 @@ +#!/bin/env python3 + +# Copyright 2021 Rémi Bernon for CodeWeavers +# +# 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 +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +from __future__ import print_function + +import gdb +import re +import subprocess +import sys + +class LoadSymbolFiles(gdb.Command): + 'Command to load symbol files directly from /proc/<pid>/maps.' + + def __init__(self): + sup = super(LoadSymbolFiles, self) + sup.__init__('load-symbol-files', gdb.COMMAND_FILES, gdb.COMPLETE_NONE, + False) + + self.libs = {} + gdb.execute('alias -a lsf = load-symbol-files', True) + + def invoke(self, arg, from_tty): + pid = gdb.selected_inferior().pid + if not pid in self.libs: self.libs[pid] = {} + + def command(cmd, confirm=from_tty): + to_string = not from_tty + gdb.execute(cmd, from_tty=confirm, to_string=to_string) + + def execute(cmd): + return subprocess.check_output(cmd, stderr=subprocess.STDOUT) \ + .decode('utf-8') + + # load mappings addresses + libs = {} + with open('/proc/{}/maps'.format(pid), 'r') as maps: + for line in maps: + addr, _, _, _, node, path = re.split(r'\s+', line, 5) + path = path.strip() + if node == '0': continue + if path in libs: continue + libs[path] = int(addr.split('-')[0], 16) + + # unload symbol file if address changed + for k in set(libs) & set(self.libs[pid]): + if libs[k] != self.libs[pid][k]: + command('remove-symbol-file "{}"'.format(k), confirm=False) + del self.libs[k] + + # load symbol file for new mappings + for k in set(libs) - set(self.libs[pid]): + if arg is not None and re.search(arg, k) is None: continue + addr = self.libs[pid][k] = libs[k] + offs = None + + try: + out = execute(['file', k]) + except: + continue + + # try loading mapping as ELF + try: + out = execute(['readelf', '-l', k]) + for line in out.split('\n'): + if not 'LOAD' in line: continue + base = int(line.split()[2], 16) + break + + out = execute(['objdump', '-h', k]) + for line in out.split('\n'): + if not '.text' in line: continue + offs = int(line.split()[3], 16) - base + break + if offs is None: continue + + # try again, assuming mapping is PE + except: + try: + out = execute(['objdump', '-h', k]) + for line in out.split('\n'): + if not '.text' in line: continue + offs = int(line.split()[5], 16) + break + if offs is None: continue + + except: + continue + + command('add-symbol-file "{}" 0x{:x}'.format(k, addr + offs), + confirm=False) + + +LoadSymbolFiles()
On 6/21/21 2:33 PM, Rémi Bernon wrote:
To help gdb reload symbol files from /proc/<pid>/maps, making it possible to load debug info for ELF and PE modules for Wine processes.
When sourced (from ~/.gdbinit for instance), this adds a new "load-symbol-files" command (with an "lsf" alias), which automatically calls add-symbol-file on every mapped file that can be read as ELF or PE, with the correct section offset.
The command has to be run manually, for instance after executing for a while, to load new modules that may have been loaded, as there's no way for gdb to be notified of such changes automatically.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
This is some script I've been using for a while, and more or less broken versions are also used by other people, so I figured maybe it would be better to have a proper working version officially distributed with Wine source instead, as it's pretty useful for debugging Wine under gdb.
It's still a bit manual to use, as gdb cannot easily be notified of dynamic library loading [1], but I think it's much better than having nothing.
[1] in theory there's ways to do it using systemtap probes, but it's going to be hard to make it work, especially for PE modules.
I'm probably missing something, but why can't we just do it in response to LOAD_DLL_DEBUG_EVENT?
On 6/22/21 7:00 PM, Zebediah Figura (she/her) wrote:
On 6/21/21 2:33 PM, Rémi Bernon wrote:
To help gdb reload symbol files from /proc/<pid>/maps, making it possible to load debug info for ELF and PE modules for Wine processes.
When sourced (from ~/.gdbinit for instance), this adds a new "load-symbol-files" command (with an "lsf" alias), which automatically calls add-symbol-file on every mapped file that can be read as ELF or PE, with the correct section offset.
The command has to be run manually, for instance after executing for a while, to load new modules that may have been loaded, as there's no way for gdb to be notified of such changes automatically.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
This is some script I've been using for a while, and more or less broken versions are also used by other people, so I figured maybe it would be better to have a proper working version officially distributed with Wine source instead, as it's pretty useful for debugging Wine under gdb.
It's still a bit manual to use, as gdb cannot easily be notified of dynamic library loading [1], but I think it's much better than having nothing.
[1] in theory there's ways to do it using systemtap probes, but it's going to be hard to make it work, especially for PE modules.
I'm probably missing something, but why can't we just do it in response to LOAD_DLL_DEBUG_EVENT?
It's not for winedbg but when using gdb directly.
Hello Rémi, I was trying to do similar with rr-debugger [1] to load symbols iterating over mapped files, but it never got into a really got state.
But with a little modification (patch attached), your script does the same and is way less complicated.
I noted just one issue while testing a little with notepad.exe, with plain gdb and rr:
Sections other than .text of ELF libraries get mapped to address 0x0. (Could you see this too in 'info target'?) This combined with a kind of huge .data section of shell32.dll.so overlaps then with .text of notepad.exe, therefore gdb shows then in a backtrace not the right symbols. The other attached patch tries to also map the data section to resolve this. But I am not sure if other sections should also be mapped.
Thanks for sharing.
Kind regards, Bernhard
On 6/24/21 10:50 PM, Bernhard Übelacker wrote:
Hello Rémi, I was trying to do similar with rr-debugger [1] to load symbols iterating over mapped files, but it never got into a really got state.
But with a little modification (patch attached), your script does the same and is way less complicated.
I noted just one issue while testing a little with notepad.exe, with plain gdb and rr:
Sections other than .text of ELF libraries get mapped to address 0x0. (Could you see this too in 'info target'?) This combined with a kind of huge .data section of shell32.dll.so overlaps then with .text of notepad.exe, therefore gdb shows then in a backtrace not the right symbols. The other attached patch tries to also map the data section to resolve this. But I am not sure if other sections should also be mapped.
Thanks for sharing.
Kind regards, Bernhard
Hi Bernhard,
Thanks for the feedback, I've also tried rr in the past, without much success so far, but I'd love to be able to use it with Wine. On Intel, gdb supports branch trace record, which has been very, very, convenient to debug Wine issues but I'm now on AMD and I'm missing it a bit.
I haven't looked into the issue you mentioned, and I think I've seen a few cases where the debug symbols were off, but in general it's been working well enough. I'll try to have a better look.
Cheers,
Am 28.06.21 um 13:27 schrieb Rémi Bernon:
On 6/24/21 10:50 PM, Bernhard Übelacker wrote:
Hello Rémi, I was trying to do similar with rr-debugger [1] to load symbols iterating over mapped files, but it never got into a really got state.
But with a little modification (patch attached), your script does the same and is way less complicated.
I noted just one issue while testing a little with notepad.exe, with plain gdb and rr:
Sections other than .text of ELF libraries get mapped to address 0x0. (Could you see this too in 'info target'?) This combined with a kind of huge .data section of shell32.dll.so overlaps then with .text of notepad.exe, therefore gdb shows then in a backtrace not the right symbols. The other attached patch tries to also map the data section to resolve this. But I am not sure if other sections should also be mapped.
Thanks for sharing.
Kind regards, Bernhard
Hi Bernhard,
Thanks for the feedback, I've also tried rr in the past, without much success so far, but I'd love to be able to use it with Wine. On Intel, gdb supports branch trace record, which has been very, very, convenient to debug Wine issues but I'm now on AMD and I'm missing it a bit.
I haven't looked into the issue you mentioned, and I think I've seen a few cases where the debug symbols were off, but in general it's been working well enough. I'll try to have a better look.
Cheers,
Hello Rémi, recording wine worked for me just when all wine processes are inside the recording. Otherwise some modifications through e.g. mapped memory does not get recorded (e.g. user_shared_data) which may lead when replaying to wrong register values, as these modifications are missing. Unfortunately this makes it kind of slow. (Maybe at least wineserver and the desired process have to be in the recording ... if modifications are just one way from wineserver to other processes ... but that makes preparing the session ugly.)
And I am using it with AMD, but so called "SBB mitigation" is required. I am using the kernel module: https://github.com/rr-debugger/rr/wiki/Zen
Kind regards, Bernhard
Am 28.06.21 um 23:22 schrieb Bernhard Übelacker:
Am 28.06.21 um 13:27 schrieb Rémi Bernon:
On 6/24/21 10:50 PM, Bernhard Übelacker wrote:
Hello Rémi, I was trying to do similar with rr-debugger [1] to load symbols iterating over mapped files, but it never got into a really got state.
But with a little modification (patch attached), your script does the same and is way less complicated.
I noted just one issue while testing a little with notepad.exe, with plain gdb and rr:
Sections other than .text of ELF libraries get mapped to address 0x0. (Could you see this too in 'info target'?) This combined with a kind of huge .data section of shell32.dll.so overlaps then with .text of notepad.exe, therefore gdb shows then in a backtrace not the right symbols. The other attached patch tries to also map the data section to resolve this. But I am not sure if other sections should also be mapped.
Thanks for sharing.
Kind regards, Bernhard
Hi Bernhard,
Thanks for the feedback, I've also tried rr in the past, without much success so far, but I'd love to be able to use it with Wine. On Intel, gdb supports branch trace record, which has been very, very, convenient to debug Wine issues but I'm now on AMD and I'm missing it a bit.
I haven't looked into the issue you mentioned, and I think I've seen a few cases where the debug symbols were off, but in general it's been working well enough. I'll try to have a better look.
Cheers,
Hello Rémi, recording wine worked for me just when all wine processes are inside the recording. Otherwise some modifications through e.g. mapped memory does not get recorded (e.g. user_shared_data) which may lead when replaying to wrong register values, as these modifications are missing. Unfortunately this makes it kind of slow. (Maybe at least wineserver and the desired process have to be in the recording ... if modifications are just one way from wineserver to other processes ... but that makes preparing the session ugly.)
And I am using it with AMD, but so called "SBB mitigation" is required. I am using the kernel module: https://github.com/rr-debugger/rr/wiki/Zen
Kind regards, Bernhard
Hello Rémi, just a small update, sorry for the late reply.
I sometimes got an issue with some sections placed automatically by gdb to some location where they did not belong. Therefore, as far as I remember, I changed it to trying to map all sections of a file, which worked in these cases better for me.
There is also another maybe interesting thing related to this area. Keno Fischer created a prototype of gdb being able to iterate the list of dlls itself with just a few modifications, which can be used standalone or with rr also. (Currently just 64-bit.)
https://github.com/JuliaComputing/gdb-solib-wine
Kind regards, Bernhard
Hi Bernhard,
On 1/23/22 23:18, Bernhard Übelacker wrote:
Am 28.06.21 um 23:22 schrieb Bernhard Übelacker:
Hello Rémi, just a small update, sorry for the late reply.
I sometimes got an issue with some sections placed automatically by gdb to some location where they did not belong. Therefore, as far as I remember, I changed it to trying to map all sections of a file, which worked in these cases better for me.
Thanks for the update, I also have made some updates to my script too to do things like that and it's working much better now as far as I could see.
There is also another maybe interesting thing related to this area. Keno Fischer created a prototype of gdb being able to iterate the list of dlls itself with just a few modifications, which can be used standalone or with rr also. (Currently just 64-bit.)
Wow, that's quite nice to see! I guess it could then also hook the loader functions to refresh the list on DLL load / unload, in the same way gdb hooks dlopen.
(FWIW I am still unable to use rr with Wine, although I only tried again a few months ago and I'm not putting a lot of effort in it, but I would really like to succeed, it sounds useful)
Cheers,