#查看所有断点 (gdb) info break# 或 info b Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000004d93a in main at server.c:6147 2 breakpoint keep y 0x0000000000041593 in dictSdsKeyCaseCompare at server.c:1269 3 breakpoint keep y 0x0000000000043589 in beforeSleep at server.c:2364 #可见示例中一共存在3个断点,分别在6147、1269、2364行 #如果想禁用某个断点,使用 disable 断点编号 就可以禁用这个断点;同理,被禁用的断点也可以使用 enable 断点编号 重新开启 (gdb) disable 2 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep n 0x000000000004d93a in main at server.c:6147 2 breakpoint keep y 0x0000000000041593 in dictSdsKeyCaseCompare at server.c:1269 3 breakpoint keep y 0x0000000000043589 in beforeSleep at server.c:2364 #可见,禁用断点2后,Enb下方的标志由y变为n. 同理,使用enable 2命令重启后,该标志又会回到y #enable、disable命令后不加断点编号,即表示开启、禁用所有断点 #delete 断点编号,即表示删除某断点。同理,不加断点编号,即表示删除所有断点
#打印server.port变量的值 (gdb) print variable (gdb) p server.port $1 = 6379 #打印server.port变量的类型 (gdb) ptype server.port type = int #列出当前对象的各个成员变量值 (gdb) p *this #打印三个变量的和 (gdb) p a+b+c #打印函数执行结果 (gdb) p function() #某个时刻,某个系统函数执行失败了,通过系统变量 errno 得到一个错误码,可以使用 (gdb) p strerror(errno) #将这个错误码对应的文字信息打印出来,这样就不用去 man 手册上查找这个错误码对应的错误含义 #修改变量的值 (gdb) p server.port=6400 $4 = 6400 #打印变量时可以指定输出格式 (gdb) print /format variable (gdb) p /x server.port $6 = 0x1900 #format常见取值 o octal 八进制显示 x hex 十六进制显示 d decimal 十进制显示 u unsigned decimal 无符号十进制显示 t binary 二进制显示 f float 浮点值显示 a address 内存地址格式显示(与十六进制相似) i instruction 指令格式显示 s string 字符串形式显示 z hex, zero padded on the left 十六进制左侧补0显示
(gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff79d57c0 (LWP 230901) "redis-server" 0x00007ffff7c9046e in epoll_wait ( epfd=5, events=0x5555557a1db0, maxevents=10128, timeout=100) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30 2 Thread 0x7ffff6ba6700 (LWP 230905) "bio_close_file" futex_wait_cancelable ( private=<optimized out>, expected=0, futex_word=0x5555557073e8 <bio_newjob_cond+40>) at ../sysdeps/nptl/futex-internal.h:183 3 Thread 0x7ffff63a5700 (LWP 230906) "bio_aof_fsync" futex_wait_cancelable ( private=<optimized out>, expected=0, futex_word=0x555555707418 <bio_newjob_cond+88>) at ../sysdeps/nptl/futex-internal.h:183 4 Thread 0x7ffff5ba4700 (LWP 230907) "bio_lazy_free" futex_wait_cancelable ( private=<optimized out>, expected=0, futex_word=0x555555707448 <bio_newjob_cond+136>) at ../sysdeps/nptl/futex-internal.h:183 #一共有4个线程,当前gdb附加在1号线程(带星号)。 #【所有的线程ID在第三栏(LWP number)中。在早期的 Linux 系统的内核里面,不存在真正的线程实现 # 当时所有的线程都是用进程来实现,称之为LWP,即Light Weight Process(轻量级进程)】
#切换到其他线程,使用thread 线程编号 (gdb) thread 3 [Switching to thread 3 (Thread 0x7ffff63a5700 (LWP 231546))] #0 futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x555555707418 <bio_newjob_cond+88>) at ../sysdeps/nptl/futex-internal.h:183 183 ../sysdeps/nptl/futex-internal.h: No such file or directory. (gdb) info threads Id Target Id Frame 1 Thread 0x7ffff79d57c0 (LWP 231538) "redis-server" 0x00007ffff7c9046e in epoll_wait (epfd=5, events=0x5555557a1db0, maxevents=10128, timeout=100) at ../sysdeps/unix/sysv/linux/epoll_wait.c:30 2 Thread 0x7ffff6ba6700 (LWP 231545) "bio_close_file" futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x5555557073e8 <bio_newjob_cond+40>) at ../sysdeps/nptl/futex-internal.h:183 * 3 Thread 0x7ffff63a5700 (LWP 231546) "bio_aof_fsync" futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x555555707418 <bio_newjob_cond+88>) at ../sysdeps/nptl/futex-internal.h:183 4 Thread 0x7ffff5ba4700 (LWP 231547) "bio_lazy_free" futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x555555707448 <bio_newjob_cond+136>) at ../sysdeps/nptl/futex-internal.h:183
如何找到main函数所在的主线程,并切换过去?
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#_start 是C程序的入口函数,可以设置断点在入口函数内,然后运行程序,查看当前线程: (gdb) break _start Breakpoint 1 at 0x55555558bb80 (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/changhe/gdb/redis-6.2.4/src/redis-server [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, 0x000055555558bb80 in _start () (gdb) info threads Id Target Id Frame * 1 Thread 0x7ffff79d57c0 (LWP 231538) "redis-server" 0x000055555558bb80 in _start ()
info 命令还可以用来查看当前堆栈处函数的参数值:info args
1 2 3 4 5 6 7 8 9 10 11 12 13 14
(gdb) bt #0 0x00007ffff71e2603 in epoll_wait () from /usr/lib64/libc.so.6 #1 0x0000000000428a9e in aeApiPoll (eventLoop=0x5e5770, tvp=0x7fffffffe140) at ae_epoll.c:112 #2 0x00000000004297e2 in aeProcessEvents (eventLoop=0x5e5770, flags=27) at ae.c:447 #3 0x0000000000429ab6 in aeMain (eventLoop=0x5e5770) at ae.c:539 #4 0x00000000004372bb in main (argc=1, argv=0x7fffffffe308) at server.c:5175 (gdb) f 2 #切换到堆栈 #2,堆栈 #2 调用处的函数是 aeProcessEvents(),一共有两个参数 #2 0x00000000004297e2 in aeProcessEvents (eventLoop=0x5e5770, flags=27) at ae.c:447 447 numevents = aeApiPoll(eventLoop, tvp); (gdb) info args #使用该命令输出当前函数的两个参数值,指针类型的参数,gdb 默认会输出该变量的指针地址值 eventLoop = 0x5e5770 flags = 27 (gdb) p *eventLoop #要想输出指针指向的对象的值,可以使用print命令, #如果还要查看其成员值,继续使用 变量名->字段名 即可(如 p eventLoop->maxfd )
(gdb) b initServer Breakpoint 2 at 0x555555599666: file server.c, line 3137. (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/changhe/gdb/redis-6.2.4/src/redis-server [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 235674:C 12 Oct 2023 16:00:36.542 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 235674:C 12 Oct 2023 16:00:36.542 # Redis version=6.2.4, bits=64, commit=00000000, modified=0, pid=235674, just started 235674:C 12 Oct 2023 16:00:36.542 # Warning: no config file specified, using the default config. In order to specify a config file use /home/changhe/gdb/redis-6.2.4/src/redis-server /path/to/redis.conf