Debugging shared libraries remotely with gdb/gdbserver
Wild guess: you loaded the shared library into host GDB
at incorrect address.
Instead of explicitly loading it into GDB, use "set stop-on-solib-event on"
, wait for the library to get loaded (info shared
will tell you current list of loaded libraries), and then set the breakpoints.
A way to have GDB load libraries from local sysroot and remote gdbserver
GDB does not support multiple sysroots, but there are some work-arounds.
- One way to fix the issue is by patching GDB to actually support multiple sysroots. Function
solib_find_1
ingdb/solib.c
(link to source code) handles the library lookup. Currently, it checks thesysroot
(and if that starts withtarget:
, uses the libraries from the target). Otherwise it takes the basename (i.e. takes the file name from the given absolute path) and looks up the libraries insolib-search-path
.
To get the desired behavior, thesolib_find_1
function should instead fall back to a different directory, e.g. this patch: https://gitlab.com/gbenson/binutils-gdb/commit/0ebe17076406a85a35eb0c4f362850ed9efb843e - A simpler approach without patching GDB: Copy the target libraries to the host. Variants include:
- Directly inside the local sysroot. This is quick and simple.
- With symlinks inside the local sysroot to the location of the target libraries.
- Use a filesystem that merges multiple locations, such as OverlayFS.
- Use a bind mount to mount the directories or files over the sysroot.
- If you don't want to copy files: Establish an automatic local mirror of libraries from the target (e.g. with
sshfs
), and use the approaches from the previous point to fall back to the target when needed. - If you don't have the ability to alter the filesystem, then you can put a proxy between your GDB client and the GDB server:
- Use
set sysroot target:
- Create a proxy for GDB's File-I/O Remote Protocol, and let it transparently forward every message, except for requests for target files. If the files of interest are available locally, reply with that. Otherwise forward the message as-is.
- Attach the debugger using
target remote :[your_proxy_port]
instead oftarget remote :[actual_gdbserver_port]
, to let your proxy connect to the gdbserver on your behalf.
- Use
I found that a combination of the "Copy the target libraries to the host" variants was the most effective, as it has minimal requirements (I only need a way to copy/receive files from the target once):
- I copied the system libraries from the target to a local directory. I actually copied all of them so I didn't have to find out which one I really needed.
- I recreated the directory structure on the target of the application and added a symlink to the build output directory of my project. The use of symlinks efforts to get the setup working without recurring maintenance.
The content of the sysroot didn't actually have to be identical to the target's remote files: The target had stripped libraries without debugging symbols, while I used the non-stripped libraries in the sysroot.
GDB remote debugging: influences on execution on remote target
How does the usage of a wrong ld.so binary on the debugging host influence the execution of the application within gdbserver on the target?
Good question.
One possible explanation: in order to properly keep track of e.g. loaded shared libraries on the target, GDB sets a number of internal breakpoints (these are visible in maintenance info breakpoints
output -- they have negative breakpoint number).
When you don't supply a local file at all, GDB has no idea where to set these breakpoints, and so it doesn't (you can't e.g. debug library initializers without them).
When you supply an incorrect local file, GDB does set the breakpoint ... in the wrong place (by overwriting what GDB thinks is an instruction, but what in reality is a PLT relocation). When the loader then encounters this overwritten relocation, it complains.
GDB: Error while remotely loading shared libraries
Finally i found a solution for my problem.
The problem was in step 2 shown above. Somehow gdb was not loading all the symbols and PATH to shared libraries. Although PATH shown with ldd
command was accurate. But still it was not working for me if I simply run the gdb ./MY_Application
So I executed one more command after this i.e.
file MY_Application
and also copied library file from /srv/chroot/loc/usr/local/davis/lib/
to /usr/local/davis/lib/
after this I connect it to remote server and now it is working fine.
gdb: how to learn which shared library loaded a shared library in question
Is there any way to learn it in gdb or in some other way?
There are a few ways.
You can run the program with env LD_DEBUG=files /path/to/exe
.
This will produce output similar to:
LD_DEBUG=files /bin/date
76042:
76042: file=libc.so.6 [0]; needed by /bin/date [0]
It is the needed by part that you most care about.
You could also use GDB and use set set stop-on-solib-events 1
. This will produce output similar to:
Stopped due to shared library event:
Inferior loaded /lib/x86_64-linux-gnu/libc.so.6
At that point, you could execute where
command and observe which dlopen()
call caused the new library to be loaded.
You could also set a breakpoint on dlopen()
and do the same.
The stop-on-solib-events
may be better if your executable repeatedly dlopen()
s the same library -- the library set will not change when you dlopen()
the same library again, and you'll stop when you don't care to stop. Setting stop-on-solib-events
avoids such unnecessary stops.
Related Topics
Linux Keyboard Event Capturing /Dev/Inputx
Branch-Specific Configuration File Maintenance with Git
Getting Current Path in Variable and Using It
How to Mmap the Stack for the Clone() System Call on Linux
Is It Necessary to Deregister a Socket from Epoll Before Closing It
How to Return Spawned Process Exit Code in Expect Script
Change .Eclipse Folder in Linux
Logcat Show Invisible Messages in Eclipse Mars
How Is the Init Process Started in the Linux Kernel
Have 5 Scripts Running at Any Given Time
X86 Linux Assembler Get Program Parameters from _Start
/Usr/Bin/Perl: Bad Interpreter: Text File Busy
Parsing Shell Script Arguments
How to Install Influxdb in Windows
Gdb Break When Program Opens Specific File
How to Print a String to the Terminal in X86-64 Assembly (Nasm) Without Syscall