超级详细的gdb的入门手册

1. gdb使用

文章目录

1.1. Linux Core 文件生成及设置

1.1.1. 永久设置

  • 编辑/root/.bash_profile文件,在其中加入 ulimit -c unlimited,如果没有这个文件,则创建
  • 重启系统或者执行:source /root/.bash_profile

1.1.2. 临时设置

1.1.3. core文件的设置

  • /proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展名,生成的core文件格式为core.xxxx;为0则表示生成的core文件统一命名为core,例如:

    echo "1" > /proc/sys/kernel/core_uses_pid
    
  • proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式,可通过以下命令修改此文件,例如:

    echo "/corefile/core-%e-%p-%t-s" >/proc/sys/kernel/core_pattern
    

1.1.4. 参数说明

  • 可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳,需要提前创建/corefile文件夹,以下是参数列表:

    1. %p - insert pid into filename #添加pid
    2. %u - insert current uid into filename #添加当前uid
    3. %g - insert current gid into filename #添加当前gid
    4. %s - insert signal that caused the coredump into the filename #添加导致产生core的信号
    5. %t - insert UNIX time that the coredump occurred into filename #添加core文件生成时的unix时间
    6. %h - insert hostname where the coredump happened into filename  #添加主机名
    7. %e - insert coredumping executable name into filename   #添加产生coredump的可执行文件名
    

1.2. GDB调试时的信息显示

1.2.1. 显示版本信息

show version

1.2.2. 显示GDB版权相关信

show copying
show warranty

1.2.3. 启动时不显示提示信息

gdb -q                # 可以在~/.bashrc中,为gdb设置一个别名

1.2.4. gdb退出时不显示提示信息

set confirm off       # 可以把这个命令加到.gdbinit文件里面

1.2.5. 输出信息多时不会暂停输出

  • 有时当gdb输出信息较多时,gdb会暂停输出,并会打印“—Type to continue, or q to quit—”这样的提示信息,解决方法所示
set pagination off  或者  set height 0

1.3. 函数

1.3.1. info functions

  • 支持正则
info functions        # 列出函数原型以及不带调试信息的函数
info functions Msg*   # gdb只会列出名字里包含“Msg”的函数

使用gdb调试遇到函数时,使用step命令(缩写为s)可以进入函数(函数必须有调试信息),使用next命令(缩写为n)不进入函数,gdb会等函数执行完,再显示下一行要执行的程序代码

1.3.2. 进入不带调试信息的函数

set step-mode on          # 设置该命令,gdb就不会跳过没有调试信息的函数

1.3.3. 退出正在调试的函数

  • 当单步调试一个函数时,如果不想继续跟踪下去了,可以有两种方式退出
1.finish  当不想再继续跟踪函数时,执行完“finish”命令,gdb会打印函数输出结果,然后停在返回的地方。
2.return  这样函数不会继续执行下面的语句,而是直接返回。也可以用“return expression”命令指定函数的返回值

1.3.4. 直接执行函数

  • call 函数名 或者print 函数名
call  func()
print func()

1.3.5. 打印函数堆栈帧信息

info frame

1.3.6. 选择函数堆栈帧

frame addr addr是堆栈地址

1.3.7. 向下或向上切换函数堆栈帧

up 层级     #  up 2 往外层的堆栈帧移动两层
down 层级   # down 2 往里层的堆栈帧移动两层
或者
"up-silently n"
"down-silently n""up n""down n"命令区别在于,切换堆栈帧后,不会打印信息

1.4. 断点

1.4.1. 在匿名空间设置断点

namespace Foo
{
  void foo()
  {
  }
}

namespace
{
  void bar()
  {
  }
}
    在gdb中,如果要对namespace Foo中的foo函数设置断点,可以使用如下命令:
        (gdb) b Foo::foo
    如果要对匿名空间中的bar函数设置断点,可以使用如下命令:
        (gdb) b (anonymous namespace)::bar
在程序地址上打断点:

0000000000400522 <main>:
  400522:       55                      push   %rbp
  400523:       48 89 e5                mov    %rsp,%rbp
  400526:       8b 05 00 1b 00 00       mov    0x1b00(%rip),%eax        # 40202c <he+0xc>
  40052c:       85 c0                   test   %eax,%eax
  40052e:       75 07                   jne    400537 <main+0x15>
  400530:       b8 7c 06 40 00          mov    $0x40067c,%eax
  400535:       eb 05                   jmp    40053c <main+0x1a>
当调试汇编程序,或者没有调试信息的程序时,经常需要在程序地址上打断点,方法为b *address。
例如:
    (gdb) b *0x400522

1.4.2. 在程序入口打断点

  • 获取程序入口
1.strip a.out  
2.readelf -h a.out            # 找到Entry point address 就是 程序入口
3.进入gdb,执行info files       # 找到Entry point address 就是 程序入口
  • 打断点
b *address(这个地方是上个步骤获取到的程序入口地址)

1.4.3. 在文件行号上打断点

b file:linenum

1.4.4. 查看断点信息

info breakpoints

1.4.5. 保存已经设置的断点

  • 在gdb中,可以使用如下命令将设置的断点保存下来
(gdb) save breakpoints file-name-to-save
  • 下此调试时,可以使用如下命令批量设置保存的断点
(gdb) source file-name-to-save

1.4.6. 设置临时断点

tbreak     # 简写为tb

1.4.7. 设置条件断点

  • break … if cond
break 46 if testsize==100
break main if argc > 1
break 180 if string == NULLL && i < 0
break test.c:34 if(s & y) == 1
break myfunc if i % (j + 3) != 0
break if strlen(mystring) == 0

1.4.8. 忽略断点

  • ignore bunm count
    • 意思是接下来count次编号为bnum的断点触发都不会让程序中断,只有第count + 1次断点触发才会让程序中断

1.4.9. conditon

  • 与break…if类似,只是condition只能用在已存在的断点上
  • 用法:condition <break_list> (condition)
  • 示例:
cond 3 i==5 将会在断点3上附加条件(i==3)

1.4.10. 为断点设置命令列表

  • 使用commands命令
  • 用法:commands break_list
  • 示例:
(gdb)commands 1
Type commands for when breakpoint 1 is hit,one per line.
End with a line saying just "end"
>silent
>printf "n = %d\n",n
>continue
>end

1.4.11. 向一个程序的所有函数设置断点

rbreak .

1.4.12. 清除第n行的断点

clear 行号

1.4.13. 忽略断点

  • ignore <break_list> count
ignore 1 100 #表示忽略断点1的前100次停止

1.5. 观察点

1.5.1. 设置观察点

1.watch a    # 当a的值发生变化的时候,程序都会停下来
2.watch *(data_type *)address
  • 如果系统支持硬件观测的话,当设置观测点会打印信息
Hardware watchpoint num:expr
  • 如果不想用硬件观测点的话可设置为
set can-use-hw-watchpoints

1.5.2. 查看观察点

info watchpoints
  • watch 设置的观察点也可以用控制断点的命令来控制:disable,enable,delete

1.5.3. 设置观察点只对指定线程有效

watch expr thread thradnum  # 只有编号为threadnum的线程改变了变量expr的值,程序才会停下来
  • 这种针对特定线程设置观察点方式只对硬件观察点有效

1.5.4. 设置读观察点

rwatch  # 当发生读取变量行为时,程序就会暂停
  • rwatch只对硬件观察点才生效

1.6. catchpoint(捕捉点)

1.6.1. 让catchpoint只触发一次

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    pid_t pid;
    int i = 0;

    for (i = 0; i < 2; i++)
    {
        pid = fork();
        if (pid < 0)
        {
            exit(1);
        }
        else if (pid == 0)
        {
            exit(0);
        }
    }
    printf("hello world\n");
    return 0;
}
  • tcatch fork ------ tcatch 命令设置catchpoint只触发一次,程序就暂停
  • catch fork ------ 用catch fork命令为fork调用设置catchpoint

1.6.2. 为系统调用设置catchpoint

  • catch syscall [name | number]
catch syscall mmap
catch syscall 9  # 使用系统调用的编号设置catchpoint
  • 系统调用和编号的映射文件路径:
    • /usr/share/gdb/syscalls/amd64-linux.xml
    • /usr/local/share/gdb/syscalls/amd64-linux.xml

1.6.3. 通过为ptrace调用设置catchpoint破解anti-debugging的程序

1.7. 打印

1.7.1. 打印ASCII和宽字符字符串

#include <stdio.h>
#include <wchar.h>

int main(void)
{
        char str1[] = "abcd";
        wchar_t str2[] = L"abcd";

        return 0;
}
* x/s  str1           # 打印字符串str1的值
* x/ws str2           # 打印字符串str2的值

1.7.2. 打印STL容器中的内容

#include <iostream>
#include <vector>

using namespace std;

int main ()
{
    vector<int> vec(10); // 10 zero-initialized elements

    for (int i = 0; i < vec.size(); i++)
    vec[i] = i;

    cout << "vec contains:";
    for (int i = 0; i < vec.size(); i++)
    cout << ' ' << vec[i];
    cout << '\n';

    return 0;
}
  • p vec ----- 缺省的显示结果可读性差
  • gcc 7.0之后,可以使用python脚本,改善打印结果,设置方法,将dbinit_stl_views 下载下来,将dbinit_stl_views-1.0.3.txt,执行 cat dbinit_stl_views-1.0.3.txt >> ~/.gdbinit.

1.7.3. 打印大数组中的内容

  • 在GDb中,如果要打印大数组的内容,缺省最多会显示200个元素,
  • 修改打印的元素个数上限:set print elements number-of-elements
set print elements 0
或  
set print elements unlimited   # 修改打印的元素个数上限为无限制

1.7.4. 打印数组中任意连续元素值

p array[index]@num   # array:数组名称,index:数组索引,num:连续打印的元素个数
p *array@10          # 打印从数组开头连续元素的值

1.7.5. 打印数组的索引下标

set print array-indexs on

1.7.6. 打印函数局部变量的值

  • 当程序在某个断点停住时
bt full          # 显示各个函数的局部变量值
bt full n        # 从内向外显示n个栈帧
info locals      # 打印当前函数局部变量的值

1.7.7. 打印进程内存信息

info proc mappings
info files
info target

1.7.8. 打印静态变量的值

print filename::static_varname  # filename::static_varname ---->文件名::静态变量名

1.7.9. 打印变量类型和所在文件

whatis xxxx             # 查看变量类型
ptype xxx               # 查看变量详细类型
info variables xxx      # 查看xxx变量所在的文件

1.7.10. 打印内存的值

1.7.11. 打印源代码行

list main         # 指定函数打印
list - , list +   # 向前,向后打印
list 1,10         # 指定打印范围

1.7.12. 使用"$_“和”$__"变量

  • x"命令会把最后检查的内存地址值存在" " 这 个 " c o n v e n i e n c e v a r i a b l e " 中 , 并 且 会 把 这 个 地 址 中 的 内 容 放 在 " _"这个"convenience variable"中,并且会把这个地址中的内容放在" ""conveniencevariable""__“这个"convenience variable”
  • 参考https://github.com/hellogcc/100-gdb-tips/blob/master/src/use- − _- __-variables.md

1.7.13. 打印程序动态分配内存的信息

1.7.14. 打印调用栈帧中变量的值

1.7.15. 设置打印长度

set print elements 0  # 设置打印 elements 的长度不受限制,默认是打印200个元素
show print elements

1.7.16. 查看局部变量

info local

1.7.17. 打印宏信息

  • 需要在编译程序的时候加上-g3或者-ggdb3,在gdb内打印宏信息
p xxx
或者
info macro xxx

1.8. core dump 文件

1.8.1. 为调试进程产生core dump文件

  • gcore 或者 generate-core-file,让被调试的进程产生core dump文件,记录现在进程的状

1.9. 图形化界面

1.9.1. 进入图形化界面

  1. gdb -tui
  2. gdbtui
  3. 进入gdb之后使用"Crtl + A + X"组合键
  4. 退出界面,也是使用"Crtl + A + X"

1.9.2. 显示汇编代码

layout asm

1.9.3. 既显示汇编又显示源代码

layout split

1.9.4. 显示寄存器窗口

layout regs

1.9.5. 显示浮点寄存器

tui reg float

1.9.6. 显示系统寄存器

tui reg system

1.9.7. 显示通用寄存器

tui reg general

1.9.8. 调整窗口大小

  • winheight <win_name> [+ | -]count
  • win_name 可以是src,cmd,asm,regs
  • 例如:
winheight src -5

1.10. 显示各项链接库信息

1.10.1. info sharelibrary regex

  • 显示程序加载的共享链接库信息,其中regex可以是正则表达式,意为显示名字符合regex的共享链接库。如果没有regex,则列出所有的库

1.11. 信号

  • info signals 或者 info handle 查看gdb如何处理进程收到的信号
Signal        Stop      Print   Pass to program Description
第一项(Signal):标示每个信号。
第二项(Stop):表示被调试的程序有对应的信号发生时,gdb是否会暂停程序。
第三项(Print):表示被调试的程序有对应的信号发生时,gdb是否会打印相关信息。
第四项(Pass to program):gdb是否会把这个信号发给被调试的程序。
第五项(Description):信号的描述信息。

1.12. 启动

  • gdb -command=command_file exec_file
  • 表示要在可执行文件 exec_file 上运行GDB,首先要从文件command_file中读取命令

1.13. 线程

1.13.1. 查看当前应用程序中所有的线程

info threads

1.13.2. 指定线程

thread <thread number>

1.13.3. 锁定调度器来避开gdb根据优先权来改变当前线程

set scheduler-locking on/off

1.13.4. 确定当前模式

show scheduler -locking

1.13.5. 想所有线程应用一个命令

thread apply all <command(比如backtrace)>

1.14. 其他

1.14.1. 设置变量的值

  • print
(gdb)print x=4          # x=4这个表达式是C/C++的语法,意为把变量x的值修改为4
(gdb)set var print=4

1.14.2. 查看结构体的定义

ptype struct 类型名

1.14.3. gdb输出到文件

1.
    set args > output.log
2.
    通过tee在启动时重定向
    gdb |tee -a file
3.
    set logging file <文件名>
    set logging on
        输入这个命令后,此后的调试信息将输出到指定文件
4.
    set logging overwrite [on|off]
        By default, gdb will append to the logfile. Set overwrite if you want set logging on to overwrite the logfile instead. 
5.
    set logging redirect [on|off]
        By default, gdb output will go to both the terminal and the logfile. Set redirect if you want output to go only to the log file.
6.
    show logging
        Show the current values of the logging settings
7.
    set logging off
        Disable logging.

1.14.4. finish

  • 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息

1.14.5. info program

  • 查看当前进程运行状态

1.14.6. until

  • 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体

1.14.7. call

  • 调用“函数”,并传递“参数”,如:call gdb_test(55)

1.14.8. jump

  • jump 行号,行号可以是:1.数字;2.(+/-)偏移;3.文件名:行号
j 136
  • jump 位置,位置可以是:1.函数名;2.文件名:函数名;3.*内存地址

1.15. gdb调试报错

1.15.1. Cannot get thread event message: debugger service failed

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q375923078

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值