高效的调试离不开调试符号。下载调试符号的最好方式是从符号服务器按需下载。
近几年引入的debuginfod机制和微软的符号服务器很类似。
为了给NDB增加debuginfod支持,去年暑假,我曾安排两位实习生做这个努力。一位做了一些调查,写了点试验代码,另一位推进的远一些,在ndw模块中实现了初步的代码,但是没有完成。
今年暑假,继续安排一位实习生完成debuginfod的支持。
走了几次弯路后,终于碰到了核心问题,拼接出来的url不对,服务器返回404.
为了扫清这个障碍,我使用gdb调试gdb,很快找到了正确的url格式。
以下是gdb命令。
gdb --args gdb /bin/ls
先对write设置一个断点:
b write
命中后,再对curl_easy_setopt设置断点:
Thread 1 "gdb" hit Breakpoint 1.1, __GI___libc_write (fd=1, buf=buf@entry=0x55564916d0, nbytes=nbytes@entry=74)
at ../sysdeps/unix/sysv/linux/write.c:25
warning: 25 ../sysdeps/unix/sysv/linux/write.c: No such file or directory
(gdb) b curl_easy_setopt
Breakpoint 2 at 0x7ff698daac
断点命中后,bt观察,可以看到正是libdebuginfod在调用。
Thread 1 "gdb" hit Breakpoint 2, 0x0000007ff698daac in curl_easy_setopt () from /lib/aarch64-linux-gnu/libcurl-gnutls.so.4
(gdb) bt
#0 0x0000007ff698daac in curl_easy_setopt () from /lib/aarch64-linux-gnu/libcurl-gnutls.so.4
#1 0x0000007ff71242cc in ?? () from /lib/aarch64-linux-gnu/libdebuginfod.so.1
#2 0x00000055557d71dc in ?? ()
#3 0x00000055557ed15c in ?? ()
#4 0x000000555582a374 in ?? ()
#5 0x0000005555850b10 in ?? ()
#6 0x0000005555a7c7b8 in ?? ()
#7 0x0000005555a7bf7c in ?? ()
#8 0x0000005555a7d824 in ?? ()
#9 0x0000005555a7db18 in ?? ()
#10 0x000000555592273c in ?? ()
#11 0x0000005555925280 in ?? ()
#12 0x0000005555925640 in ?? ()
#13 0x00000055556604cc in ?? ()
#14 0x0000007ff6c184c4 in __libc_start_call_main (main=main@entry=0x5555660480, argc=argc@entry=2,
argv=argv@entry=0x7ffffff368) at ../sysdeps/nptl/libc_start_call_main.h:58
#15 0x0000007ff6c18598 in __libc_start_main_impl (main=0x5555660480, argc=2, argv=0x7ffffff368, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=<optimized out>) at ../csu/libc-start.c:360
#16 0x000000555566d530 in ?? ()
curl_easy_setopt有三个参数。
curl_easy_setopt(handle, CURLOPT_URL, myurl);
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 1000000);
因为不想等待gdb下载符号,所以直接观察寄存器看参数。
(gdb) info registers
x0 0x55564d1490 366520112272
x1 0x2712 10002
x2 0x55564d0354 366520107860
x3 0x0 0
x4 0x45 69
x5 0x7ff69c6930 549598292272
x6 0x7ff69c6a60 549598292576
x7 0x7ff7125977 549606021495
x8 0x101010101010101 72340172838076673
x9 0x7fffffb5c0 549755794880
x10 0x0 0
x11 0x0 0
x12 0x7ff7fbb030 549621313584
x13 0x2a 42
x14 0x3a06df4 60845556
x15 0x8 8
x16 0x7ff7140240 549606130240
x17 0x7ff698daa0 549598059168
x18 0x33 51
x19 0x55564d0350 366520107856
前三个参数为:
(gdb) info registers
x0 0x55564d1490 366520112272
x1 0x2712 10002
x2 0x55564d0354 366520107860
观察第三个参数:
(gdb) p (char*)$x2
$1 = 0x55564d0354 "https://debuginfod.ubuntu.com/buildid/18937e81921b5ccd6be14802088d079b9481bfd9/debuginfo"
上面便是与debuginfod通信的url,可以认为是rest形式的接口,其基本格式为:
https://debuginfod.ubuntu.com/buildid/<build-id>/debuginfo
其中的build-id就是elf文件中.note节中的构建ID,可以通过readelf -n命令获取。
geduer@gdk8:~/gelabs/llaolao$ readelf -n /bin/ls
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: fec30f5745c2582aaf143e7079d3bb46ca7a010f
Downloading separate debug info for /usr/bin/ls
Reading symbols from /home/geduer/.cache/debuginfod_client/fec30f5745c2582aaf143e7079d3bb46ca7a010f/debuginfo...
多年前写作《软件调试》时,经常使用WinDBG来调试WinDBG,近年偶尔用gdb调试gdb。时过境迁,很多东西变了,但是基本的思想没有变,威力依旧。
(写文章很辛苦,恳请各位读者点击“在看”,也欢迎转发)
*************************************************
正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生
扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物
也欢迎关注格友公众号