首页 > 其他分享 >性能分析之调试工具——GDB之二

性能分析之调试工具——GDB之二

时间:2023-04-03 14:34:19浏览次数:41  
标签:redis gdb 之二 symbols GDB lib64 root 调试

由于上一个GDB的写的水份比较足,所以应看官们的要求,来写些具体的东西。

其实网上有很多GDB的教程。我也搜索过。但是总是有那么一两个点缺少的。

所以决定自己还是把工作中的记录一些下来。至少是具体工作中的实践操作。

前几天因为遇到个redis的问题,所以编译了一下reids,并且做一些监控。这里把一部分的操作实践记录下来,后面如果有需要,我再把GDB的一些命令使用整理一下。


首先,GDB的环境会有一些要求,debug包一定要全,比如说,我的主机上装的有如下debug包。

[root@7dgroup redis]# rpm -qa|grep debug
gcc-base-debuginfo-4.8.5-4.el7.x86_64
glibc-debuginfo-common-2.17-157.el7_3.1.x86_64
nss-softokn-debuginfo-3.28.3-8.el7_4.x86_64
ncurses-debuginfo-5.9-13.20130511.el7.x86_64
yum-plugin-auto-update-debug-info-1.1.31-50.el7.noarch
procps-ng-debuginfo-3.3.10-5.el7_2.x86_64
kernel-debuginfo-3.10.0-327.28.2.el7.x86_64
net-snmp-debuginfo-5.7.2-33.el7_5.2.x86_64
gcc-debuginfo-4.8.5-4.el7.x86_64
zlib-debuginfo-1.2.7-15.el7.x86_64
pcre-debuginfo-8.32-15.el7_2.1.x86_64
systemd-debuginfo-219-19.el7_2.12.x86_64
glibc-debuginfo-2.17-157.el7_3.1.x86_64
kernel-debuginfo-common-x86_64-3.10.0-327.28.2.el7.x86_64
[root@7dgroup redis]#

推荐大家都最好不要自己安装各种包依赖,比如说像这样安装:

[root@7dgroup ]# yum install gdb
[root@7dgroup ]# debuginfo-install libgcc-4.8.5-4.el7.x86_64
[root@7dgroup ]# debuginfo-install nss-softokn-freebl-3.28.3-8.el7_4.x86_64 pcre-8.32-15.el7_2.1.x86_64 zlib-1.2.7-15.el7.x86_64

所有的依赖都会给你加上。

下面开始看gdb连redis的过程,我尽量写细。

下载redis源码并解压

[root@7dgroup GDB]# wget wget http://download.redis.io/releases/redis-5.0.5.tar.gz
--2019-08-04 10:15:14--  http://wget/
正在解析主机 wget (wget)... 失败:未知的名称或服务。
wget: 无法解析主机地址 “wget”
--2019-08-04 10:15:14--  http://download.redis.io/releases/redis-5.0.5.tar.gz
正在解析主机 download.redis.io (download.redis.io)... 109.74.203.151
正在连接 download.redis.io (download.redis.io)|109.74.203.151|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:1975750 (1.9M) [application/x-gzip]
正在保存至: “redis-5.0.5.tar.gz”

100%[=======================================================================================================================================================>] 1,975,750   20.2KB/s 用时 1m 47s

2019-08-04 10:17:02 (18.0 KB/s) - 已保存 “redis-5.0.5.tar.gz” [1975750/1975750])

FINISHED --2019-08-04 10:17:02--
Total wall clock time: 1m 48s
Downloaded: 1 files, 1.9M in 1m 47s (18.0 KB/s)
[root@7dgroup GDB]# tar zxvf redis-5.0.5.tar.gz
[root@7dgroup GDB]# cd redis-5.0.5
[root@7dgroup redis-5.0.5]# tree -h
.
├── [104K]  00-RELEASENOTES
├── [  53]  BUGS
......
......
......
    ├── [3.7K]  speed-regression.tcl
    └── [ 693]  whatisdoing.sh

68 directories, 725 files
[root@7dgroup redis-5.0.5]#

确认编译选项


[root@7dgroup redis-5.0.5]# grep DEBUG src/Makefile
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
DEBUG=-g -ggdb
	DEBUG=-g
	DEBUG_FLAGS=-g
	export CFLAGS LDFLAGS DEBUG DEBUG_FLAGS
[root@7dgroup redis-5.0.5]#

可以看到默认redis源码中就已经把debug选项配置好了,真是贴心。

[root@7dgroup redis-5.0.5]# make PREFIX=/root/GDB/redis-5.0.5/redis install
cd src && make install
make[1]: 进入目录“/root/GDB/redis-5.0.5/src”
    CC Makefile.dep
make[1]: 离开目录“/root/GDB/redis-5.0.5/src”
make[1]: 进入目录“/root/GDB/redis-5.0.5/src”
rm -rf redis-server redis-sentinel redis-cli redis-benchmark redis-check-rdb redis-check-aof *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark
(cd ../deps && make distclean)
make[2]: 进入目录“/root/GDB/redis-5.0.5/deps”
......
......
......
(cd hiredis && make clean) > /dev/null || true

Hint: It's a good idea to run 'make test' ;)

    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
    INSTALL install
make[1]: 离开目录“/root/GDB/redis-5.0.5/src”

请注意,redis默认使用了-O2 的编译优化选项。可以去掉,这个在官方的文档中有说明。所以这里的编译最好用如下命令:

make noopt PREFIX=/root/GDB/redis-5.0.5/redis install

另外,这里我也指定了安装目录。

检查下编译的对不对

[root@7dgroup redis-5.0.5]# make test
cd src && make test
make[1]: 进入目录“/root/GDB/redis-5.0.5/src”
    CC Makefile.dep
make[1]: 离开目录“/root/GDB/redis-5.0.5/src”
make[1]: 进入目录“/root/GDB/redis-5.0.5/src”
Cleanup: may take some time... OK
Starting test server at port 11111
[ready]: 28175
Testing unit/printver
[ready]: 28177
Testing unit/dump
[ready]: 28180
Testing unit/auth
......
......
......
  o/ All tests passed without errors!

Cleanup: may take some time... OK
make[1]: 离开目录“/root/GDB/redis-5.0.5/src”
[root@7dgroup redis-5.0.5]#

全部通过没有错误。

以上为什么把redis的编译列这么清楚呢。主要是如果有些人在过程中遇到的杂七杂八的问题,可以有个参照。

GDB调用redis-server

方法一

直接通过gdb启动。


[root@7dgroup redis]# gdb bin/redis-server
.......
.......
.......
Reading symbols from /root/GDB/redis-5.0.5/redis/bin/redis-server...done.
(gdb)

方法二

  1. 先启动redis-server。


[root@7dgroup redis]# ./bin/redis-server &
[1] 4001
[root@7dgroup redis]# 4001:C 04 Aug 2019 11:01:39.195 # oO0OoO0Oo bit
.......-`` .-```.  ```\/    _.,_ ''-._(    '      ,       .-`  | `,    )     Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
|    `-._   `._    /     _.-'    |     PID: 4001
  `-._    `-._  `-./  _.-'    _.-'
|`-._`-._    `-.__.-'    _.-'_.-'|
|    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
......4001:M 04 Aug 2019 11:01:39.196 * Ready to accept connections
  1. 查redis的pid


[root@7dgroup redis]# ps -ef|grep redis
root      4001   742  0 11:01 pts/3    00:00:00 ./bin/redis-server *:6379
root      4014   742  0 11:01 pts/3    00:00:00 grep --color=auto redis
[root@7dgroup redis]#
  1. 连上gdb


[root@7dgroup redis]# gdb attach 4001
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7
......Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/librt.so.1...Reading symbols from /usr/lib/debug/usr/lib64/librt-2.17.so.debug...done.
done.
Loaded symbols for /lib64/librt.so.1
Reading symbols from /lib64/libpthread.so.0...Reading symbols from /usr/lib/debug/usr/lib64/libpthread-2.17.so.debug...done.
done.
[New LWP 4004]
[New LWP 4003]
[New LWP 4002]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/usr/lib64/libc-2.17.so.debug...done.
done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/usr/lib64/ld-2.17.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007f8a60ce5d13 in epoll_wait () at ../sysdeps/unix/syscall-template.S:81
81	T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb)

或者这样:


[root@7dgroup redis]# gdb ./bin/redis-server 4001
......
Reading symbols from /root/GDB/redis-5.0.5/redis/bin/redis-server...done.
Attaching to program: /root/GDB/redis-5.0.5/redis/./bin/redis-server, process 4001
Reading symbols from /lib64/libm.so.6...Reading symbols from /usr/lib/debug/usr/lib64/libm-2.17.so.debug...done.
done.
Loaded symbols for /lib64/libm.so.6
Reading symbols from /lib64/libdl.so.2...Reading symbols from /usr/lib/debug/usr/lib64/libdl-2.17.so.debug...done.
done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/librt.so.1...Reading symbols from /usr/lib/debug/usr/lib64/librt-2.17.so.debug...done.
done.
Loaded symbols for /lib64/librt.so.1
Reading symbols from /lib64/libpthread.so.0...Reading symbols from /usr/lib/debug/usr/lib64/libpthread-2.17.so.debug...done.
done.
[New LWP 4004]
[New LWP 4003]
[New LWP 4002]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Loaded symbols for /lib64/libpthread.so.0
Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/usr/lib64/libc-2.17.so.debug...done.
done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/usr/lib64/ld-2.17.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007f8a60ce5d13 in epoll_wait () at ../sysdeps/unix/syscall-template.S:81
81	T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb)


请大家注意,symbols的加载最好不要出现任务警告或错误,不然调试过程中遇到搞不清楚的问题。

这些symbols也是因为有了前面的debug编译选项才产生的。并且官方说不影响性能。


下面就可以调试了。

示例


DEMO给人直观的感觉。在上面的demo中,我用了-tui参数,在调试时,把代码窗口也显示出来,这样就知道当前执行到了哪行代码。

如果你在使用时没有显示出源码,则需要用directory命令把源码加载进来。

命令如下:

(gdb) directory	/root/GDB/redis-5.0.5/src
Source directories searched: /root/GDB/redis-5.0.5/src:$cdir:$cwd
(gdb)

GDB调试过程

  1. 设置断点


(gdb) b setCommand
Breakpoint 1 at 0x452c80: file t_string.c, line 96.
(gdb)
  1. 继续执行


(gdb) c
Continuing.

Breakpoint 1, setCommand (c=0x7f8a6070da40) at t_string.c:96
96	void setCommand(client *c) {
  1. 断点命中后查看线程


(gdb) info threads
  Id   Target Id         Frame
4    Thread 0x7f8a59cd6700 (LWP 4002) "redis-server" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
3    Thread 0x7f8a594d5700 (LWP 4003) "redis-server" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
2    Thread 0x7f8a58cd4700 (LWP 4004) "redis-server" pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
* 1    Thread 0x7f8a61ae3f80 (LWP 4001) "redis-server" setCommand (c=0x7f8a6070da40)
    at t_string.c:96
(gdb)

线程号前面的*代表是当前正在执行的线程。
3. 切换到线程中去


(gdb) thread 1
[Switching to thread 1 (Thread 0x7f8a61ae3f80 (LWP 4001))]
#0  setCommand (c=0x7f8a6070da40) at t_string.c:96
96	void setCommand(client *c) {
(gdb)

切换到thread 1。
4. 查看断点
查看断点:


(gdb) bt
#0  setCommand (c=0x7f8a6070da40) at t_string.c:96
#1  0x0000000000430ac7 in call (c=c@entry=0x7f8a6070da40, flags=flags@entry=15)
    at server.c:2439
#2  0x0000000000431d5f in processCommand (c=0x7f8a6070da40) at server.c:2733
#3  0x0000000000440a55 in processInputBuffer (c=0x7f8a6070da40) at networking.c:1470
#4  0x000000000042af80 in aeProcessEvents (eventLoop=eventLoop@entry=0x7f8a6062b0a0,
    flags=flags@entry=11) at ae.c:443
#5  0x000000000042b24b in aeMain (eventLoop=0x7f8a6062b0a0) at ae.c:501
#6  0x00000000004280ff in main (argc=<optimized out>, argv=0x7ffe1bf60ac8) at server.c:4200
(gdb)
  1. 单步跟踪 next


(gdb) n
102	    for (j = 3; j < c->argc; j++) {
  1. 进入到函数内部 step


(gdb) s
100	    int flags = OBJ_SET_NO_FLAGS;
(gdb)
  1. 打印变量值


(gdb) p j
$3 = 3
(gdb) p *a
$6 = 58989
(gdb)
(gdb) p 't_string.c'::a
$7 = {58989, 57068, 5}
(gdb) i locals
j = 3
expire = 0x0
unit = 0
flags = 0
(gdb)

指定查看全局变量的值,通过::操作符。
file::variable
function::variable
因为当全局变量与局部变量冲突时,全局变量会被隐藏。
8. 查看当前stack frame局部变量

(gdb) i locals
j = 3
expire = 0x0
unit = 0
flags = 0
(gdb)
  1. 查看当前stack frame参数


(gdb) info args
c = 0x7f8a6070da40
(gdb)
  1. 修改变量的值


(gdb) i	locals
j = 0
expire = 0x5d46a88f
unit = 0
flags =	4392628
(gdb) set var j	= 1
(gdb) i	locals
j = 1
expire = 0x5d46a88f
unit = 0
flags =	4392628
(gdb)


上面这些操作让大家有一个直观的认识,看到了完整的调试过程。但是并不是GDB所有的指令集。

至少有了一个感觉就是我们在调试时对程序是想干吗干吗。


我看到有挺多的GDB的指令集的教程,有兴趣的可以一一试下指令。

本来我也是整理了指令集的,但是感觉和其他人整理的也没有什么区别,所以就不想发出来了。

后面有的GDB调试的具体场景,再看GDB在具体场景中的使用。


并且后面有空的时候也会写动态调试器相关的文章,欢迎多提意见。


最近也在玩k8s+istio最新的版本,后面也会一一整理,有兴趣的可以加我微信和QQ群一起讨论技术。

标签:redis,gdb,之二,symbols,GDB,lib64,root,调试
From: https://blog.51cto.com/u_15181572/6166347

相关文章

  • 【环境搭建】vscode调试php
    待解决问题使用vscode和phpstudy实现PHP的本地调试解决办法1.打开xdebug找到网站使用的PHP版本,在设置中将Xdebug调试组件打开,并确认端口是9000找到php扩展目录下的php_xdebug.dll,例如我电脑上的路径是"D:\software\phpstudy_pro\Extensions\php\php7.3.4nts\ext\php_xde......
  • oracle存储过程调试无法进入,oracle存储过程无法调试
    问题:使用pl/sqldeveloper调试oracle 存储过程。在存储过程上点右键,选调试(test),然后按f9(debug)。这是正常的话,那些run、stepinto等按钮就可以点了,或者点run到断点,或者点stepinto做单步跟踪。但是在一个oraclerac双机环境中调试一个存储过程,点f9后有时能继续run或者stepint......
  • ubuntu安装ch34x驱动,并安装串口调试助手
    1、查看系统自带的ch34x驱动kangxubo@kangxubo-HKNS:/lib/modules/5.19.0-38-generic/kernel/drivers/usb/serial$lsaircable.koftdi_sio.kokobil_sct.kopl2303.kousb_debug.koark3116.kogarmin_gps.komct_u232.koqcaux.ko......
  • OpenGL Mac开发-如何使用imgui(1.89.4)插件进行调试
    为了调试我们的OpenGLDemo,可以尝试使用一个成熟的开源GUI插件imgui。1,首先进入imgui在github上的地址。在Release中下载最近的版本,可以得到一个Zip压缩包。现在是2023年的4月1日,我下载到的版本是1.89.4,与Cherno的OpenGL教程中的代码略微有些区别。如果你看的是Cherno的教程,也......
  • 【转载】 解决VSCode运行或调试python文件无反应的问题
    ————————————————版权声明:本文为CSDN博主「姜行者」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/kraisi/article/details/127287966  ====================================================  ......
  • 调试freeradius时遇到的 线程池以及udp相关问题
    调试线程池过程中遇到了一个return和pthread_exit的问题;google一下发现右如下概念首先,return语句和pthread_exit()函数的含义不同,return的含义是返回,它不仅可以用于线程执行的函数,普通函数也可以使用;pthread_exit()函数的含义是线程退出,它专门用于结束某个线程的执行。在主......
  • Ubuntu GDB调试程序
    GDB命令//gdb命令$gdb-p87746//打印所有的线程信息(gdb)infothread//切换到第2个线程(gdb)thread2//bt可以打印函数堆栈,却无法看到函数参数,跟pstack命令一样(gdb)bt//打印第三帧信息,每次函数调用都会有压栈的过程,而frame则记录栈中的帧信息(gd......
  • 数据结构之二叉树
    树是一种非线性数据结构,是由n(n>=0)个有限节点组成的一个具有层次关系的集合。树的逻辑结构看起来像一棵倒挂的树,根朝上,叶子朝下。树一般是递归定义的,每一棵树都可以认为是由根和其子树构成,且各个子树不相交。树树的相关概念节点的度:一个节点含有的子树的个数称为该节点的度;叶节......
  • ubuntu GDB安装
    gdb是用来调试CC++程序的工具1、首先确保系统上面没有安装gdb相关的工具  可用gdb--version查看2、进入/opt目录里面进行下载   cd/opt  /opt/$wgethttps://ftp.gnu.org/gnu/gdb/gdb-10.1.tar.gz  或者直接sudoapt-getinstallgdb3下载完成后......
  • 台达plc采集IO调试备忘(冲压)和住友成型(成型)
    图片已经过处理。仅供参考字体颜色,只是提醒,对红色敏感的网易见谅。二娃制作www.erwa.cn1、台达PLC调试       plc型号:DVP-12SE11T      2、住友成型机住友厂商也提供数据采集的软件,可以找供应商咨询价格和功能。网口和串口用的协议都是一样,只......