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.
The difference between gdbserver and remote gdb
gdbserver is smaller than GDB and has fewer dependencies, so it can be run on a system which is resource constrained such that GDB itself can't be run. Or maybe GDB just can't be run for some other reason, e.g. the target platform doesn't have Python, and you want to use some of the Python features of GDB.
Next, but kind of related, the target platform might not be the same architecture as the host platform (on which GDB runs), maybe compiling GDB, Python, syntax-highlighting libraries, etc for a small target isn't what you want to do with your time, instead you can just compile gdbserver, and then run GDB on your local machine.
Finally, though gdbserver is useful in itself, it also serves as a useful mechanism to test GDB's remote serial protocol support. This protocol is documented in the GDB manual and allows software other than gdbserver to interact with GDB, for example OpenOCD, and QEMU, both support GDB's remote protocol, this allows GDB to debug baremetal targets on which neither GDB, nor gdbserver could ever run.
You are correct to observe that this basically means that GDB has two methods of debug, its native target support, and its remote target support. If we wanted to be ideologically pure then we could (in theory) remove the native target support from GDB, and just make use of the gdbserver in all cases, i.e. when you try to debug a program on the local machine, GDB would automatically start gdbserver, connect to it, and debug through that interface. I don't expect to see that change any time soon though.
Related Topics
Dlopen Failed: Cannot Open Shared Object File: No Such File or Directory
How to Show Read Prompt with a New Line
How to Measure the Stack Size of a Process
How to Narrow Down Perf.Data to a Time Sub Interval
How to Set a Dynamic Variable in Haproxy
Lazarus: How to List All the Available Network Connection on a System
How to Make the Watch Command Interpret Vt100 Sequences
How to Prevent Matlab Printing False Space and Use Wrong Fonts
How to Store Linux Command Output into a Variable in Puppet
How to Import Environment Settings into My Perl Program
Running Multiple Compass-Sass Watch Operations Automatically