从本地sysroot和远程gdbserver获得GDB加载库的一种方法

时间:2019-11-18 20:36:28

标签: debugging gdb gdbserver

使用gdbserver进行远程调试时,我想让gdb从本地sysroot加载正在调试的程序的某些共享库,但也允许从gdbserver下载功能来加载sysroot中不存在的其他功能。

gdb似乎只能使用一种方法来查找库,本地文件或远程下载,而不能同时使用这两种方法。

例如,如果我将sysroot设置为target:/以使用远程文件,则将下载所有内容:

(gdb) set sysroot target:/
(gdb) run
Starting program:  
Reading /root/a.out from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /root/a.out from remote target...
Reading symbols from target:/root/a.out...
Reading /lib/ld-linux-armhf.so.3 from remote target...

不幸的是,远程系统上的系统库没有调试符号。这是具有有限闪存空间的嵌入式系统。调试符号会大大增加文件系统的总大小,根本不合适。

但是,我有一个所有系统库的本地sysroot树,它确实包含调试符号。但是,如果我将sysroot设置为该树,则gdb将不再考虑远程下载。

(gdb) set sysroot /bsp/sysroot
(gdb) run
Starting program:  
Reading symbols from /bsp/sysroot/root/a.out...
warning: Could not load shared library symbols for /lib/libm.so.6.

在此示例中,sysroot中不存在libm.so.6,但可以从目标中下载它。但是现在似乎存在将target:/添加到搜索路径的方法。将其放在solib-search-path中无效。

这种情况是由于嵌入式系统开发中使用了板级支持包(BSP)引起的。 BSP包含许多库,这些库在目标上已剥离,否则它们将无法容纳,但具有主机的未压缩副本。 BSP的用户可以构建自己的软件,但是该软件不是BSP的一部分,也不存在于BSP的sysroot中。但是它在目标系统上。

似乎没有办法告诉gdb首先尝试在本地查找库,但是如果找不到它们,便退回远程下载。

1 个答案:

答案 0 :(得分:1)

GDB不支持多个sysroot,但是有一些解决方法。

  • 解决此问题的一种方法是修补GDB以实际支持多个sysroot。 solib_find_1link to source code)中的函数gdb/solib.c处理库查找。当前,它检查sysroot(如果以target:开头,则使用目标中的库)。否则,它将使用基本名称(即,从给定的绝对路径中获取文件名)并在solib-search-path中查找库。
    为了获得所需的行为,solib_find_1函数应改回其他目录,例如此补丁:https://gitlab.com/gbenson/binutils-gdb/commit/0ebe17076406a85a35eb0c4f362850ed9efb843e
  • 一种不修补GDB的简单方法:将目标库复制到主机。变体包括:
    • 直接在本地sysroot内部。这是快速而简单的。
    • 通过本地sysroot内部的符号链接指向目标库的位置。
    • 使用合并多个位置的文件系统,例如OverlayFS
    • 使用bind mount通过sysroot挂载目录或文件。
  • 如果您不想复制文件,请执行以下操作:从目标建立自动的本地库镜像(例如,使用sshfs),并在需要时使用上一点的方法回退到目标。
  • 如果您无权更改文件系统,则可以在GDB客户端和GDB服务器之间放置一个代理:
    1. 使用set sysroot target:
    2. GDB's File-I/O Remote Protocol创建一个代理,并使其透明转发所有消息,但对目标文件的请求除外。如果感兴趣的文件在本地可用,请回复。否则,按原样转发消息。
    3. 使用target remote :[your_proxy_port]而不是target remote :[actual_gdbserver_port]连接调试器,以使您的代理代表您连接到gdbserver。

我发现“复制目标库到主机”变体的组合是最有效的,因为它具有最低的要求(我只需要一种从目标复制/接收文件一次的方法):

  • 我将系统库从目标复制到了本地目录。我实际上复制了所有这些文件,因此不必找出我真正需要的文件。
  • 我在应用程序的目标上重新创建了目录结构,并向我的项目的生成输出目录添加了符号链接。使用symlinks可以使设置正常运行而无需重复维护。

sysroot的内容实际上不必与目标的远程文件相同:目标已剥离了没有调试符号的库,而我在sysroot中使用了非剥离的库。