https://www.jianshu.com/p/9bdaa0644dba

整理一下在linux下C/C++用gdb工具debug一些提高效率的操作。基本的gdb操作就不在这里赘述了。

  • 打印各种变量
    x 命令
    在gdb中可以使用x命令,来打印内存中的值。具体的格式是x/nfu addr。 含义为以f格式打印从addr开始的n个长度单元为u的内存值。
    1. n表示打印的n个u的长度
    2. f 表示打印格式,u,d表示10进制的无符号和有符号数; x表示16进制;t表示二进制
    3. u表示单元长度,b表示一个byte,w表示4个byte
    int main()
    {
    int val = 0xa; char buff[1024];
    memset(buff, 0, sizeof(1024)); char name[]="hello world";
    strcpy(buff, name); int arr[10] = {0};
    arr[0] = 0xa;
    arr[1] = 10;
    arr[2] = 20; return 0;
    } (gdb) x/16db &arr
    0x7fffffffe010: 10 0 0 0 10 0 0 0
    0x7fffffffe018: 20 0 0 0 0 0 0 0 (gdb) x/16sb &buff
    0x7fffffffe050: "hello world"
    0x7fffffffe05c: "\177"
    0x7fffffffe05f: ""
    0x7fffffffe060: "<纵?\177"
    0x7fffffffe067: ""
    0x7fffffffe068: "X\227\177"
    0x7fffffffe06f: ""
    0x7fffffffe070: "\020暂?\177"
    0x7fffffffe077: ""
    0x7fffffffe078: ""
    0x7fffffffe079: ""
    0x7fffffffe07a: ""
    0x7fffffffe07b: ""
    0x7fffffffe07c: "\001"
    0x7fffffffe07e: ""
    0x7fffffffe07f: ""

  • 日志打印到某个文件

    set pagination off
    set logging file a.log
    set logging overwrite
    set logging on

  • -tui 图形界面选项
    gdb a.out -tui # gdb tui 启动
    gdb attach pid -tui # gdb tui attach

     

  • gdb定义函数
    在开发中有时会遇到需要看一个很大的数组,里面有没有被写坏的元素。如果数组中还有嵌套其他结构体,每个依次打印出来非常麻烦。这里可以使用gdbinit,定义一个函数,依次遍历数组,打印超过某个值的元素。比如:

    const int MAX_LEN = 1024;
    
    struct DEBUG_DETAIL_INFO{
    int id;
    int extra_info;
    }; struct DEBUG_ARR{
    int num;
    DEBUG_DETAIL_INFO info_arr[MAX_LEN];
    }; int main()
    {
    DEBUG_ARR arr;
    init_arr(100, arr); // todo
    return 0;
    }

gdb调用函数有两种方式:

  1. gdb启动时,会在当前目录下查找 .gdbinit 文件
  2. gdb在运行时,在命令行输入 source xx.gdb文件 来加载

gdb启动的时候,会在当前目录或home目录自动加载gdbinit脚本。在脚本中定义gdb函数。(或者gdb attach上去。)

define print_if_my_arr
printf "argc %d, arg %d \n", $argc, $arg0 set $num = arr.num
printf "print_func num %d \n", $num set $idx = 0
while $idx < $num
if arr.info_arr[$idx].id >= $arg0
printf "idx %d id %d \n", $idx, arr.info_arr[$idx].id
end
set $idx = $idx + 1
end
end document print_if_my_arr
example : print_if_my_arr 10
desc : print DEBUG_ARR ele if val >= 10
end

gdb实测一把

 

gdbinit文件同理也可以插入其他命令,比如各种让输出比较直观的命令等:

set print pretty on
set print object on

gdb定义的常用函数可以放到一个文件里面,需要的时候通过source命令加载。

define mybt
set logging file output_bt.log
set logging on
bt
set logging off
end

使用的时候

gdb attach xxxx
source xxx/path/xxx.gdb
mybt

  • gdb 条件断点

    # 文件名 + 行号的条件断点
    b xxx.cpp:20 if value == 100 #xx.cpp 行号20 如果value == 100 触发断点 # 包含一些简单计算的断点
    (gdb) p 100
    $2 = 100
    (gdb) b test1.cpp:8 if i + $2 == 130

  • ignore 命令
    断点触发被忽略xx次
    ignore <break_list> count

     

  • command命令
    command <break_list>

    触发断点后自动执行command里面定义的命令

     

command的命令另一个妙用

 

  • gdb return
    进入某个函数执行,不想执行里面的逻辑,直接gdb return 出去。里面的逻辑就不会执行了。
 

  • gdb gcore
    gcore命令可以从当前环境导出成为一个core文件,供日后分析。

     

  • handle SIGPIPE nostop
    为了gdb不被信号断开,可以屏蔽掉各种pipe信号。

  • gdb -ex 参数
    生产环境操作的时候可以使用

    gdb -ex "bt" -batch -p pid

    跳出死循环

     
     

  • display 命令

    对于debug需要关注的变量名,可以使用display打印出来。每次gdb操作的时候,都会显示出来。示意图如下:

     

  • info命令

    info sharedlibrary  #显示共享库
    (gdb) info sharedlibrary
    From To Syms Read Shared Object Library
    0x00007ffff7dd5050 0x00007ffff7df4854 Yes (*) /lib64/ld-linux-x86-64.so.2
    0x00007ffff7aceb60 0x00007ffff7b84bb2 Yes (*) /lib64/libstdc++.so.6
    0x00007ffff76c9510 0x00007ffff77687ca Yes (*) /lib64/libm.so.6
    0x00007ffff74a7dc0 0x00007ffff74b8a25 Yes (*) /lib64/libgcc_s.so.1
    0x00007ffff7104900 0x00007ffff724ef0f Yes (*) /lib64/libc.so.6

  • gdb调用函数

    void func() {  xxx; }
    
    b func
    call func() // gdb 直接调用这个函数

    gdb调用class的成员函数

    // todo

  • strip命令 (这个和gdb关系不大)
    strip命令可以极大的降低可执行文件的体积,其实就是去掉符号表和调试信息等。当gdb的时候,拷贝strip下来的.debug文件到需要gdb的机器上,然后进行gdb attach。这里gdb上来以后,会自动找到对应的.debug文件。

     cd xxxx_app_bin_path
    objcopy --only-keep-debug xxxx_app ./.debug/xxxx.debug
    strip --strip-debug --strip-unneeded xxxx_app
    objcopy --add-gnu-debuglink=./.debug/xxxx_app.debug xxxx_app

GDB的基本原理

gdb有两种跟踪进程的方法,第一种是gdb + a.out的方式启动进程,第二种的方式是gdb去attach一个已经启动了的进程。这种方式都是利用ptrace系统调用去跟踪被调试的进程。

ptrace共有四个参数:
long ptrace(enum __ptrace_request request,pid_t pid,void *addr,void *data); // 两种gdb的区别在于参数不同
PTRACE_TRACEME 和 PTRACE_ATTACH

ptrace系统函数是Linux内核提供的一个用于进程跟踪的系统调用,通过它,一个进程(gdb)可以读写另外一个进程(test)的指令空间、数据空间、堆栈和寄存器的值。而且gdb进程接管了test进程的所有信号,也就是说系统向test进程发送的所有信号,都被gdb进程接收到,这样一来,test进程的执行就被gdb控制了,从而达到调试的目的。

也就是说,如果没有gdb调试,操作系统与目标进程之间是直接交互的;如果使用gdb来调试程序,那么操作系统发送给目标进程的信号就会被gdb截获,gdb根据信号的属性来决定:在继续运行目标程序时是否把当前截获的信号转交给目标程序,如此一来,目标程序就在gdb发来的信号指挥下进行相应的动作。

第一种方式是通过gdb去fork一个子进程,子进程去执行被调试的进程。然后建立父子关系。如下图所示:

 

第二种方式是gdb去attach被调试的子进程。如果想对一个已经执行的进程B进行调试,那么就要在gdb这个父进程中调用ptrace(PTRACE_ATTACH,[其他参数]),此时,gdb进程会attach(绑定)到已经执行的进程B,gdb把进程B收养成为自己的子进程,而子进程B的行为等同于它进行了一次 PTRACE_TRACEME操作。此时gdb进程会发送SIGSTO信号给子进程B,子进程B接收到SIGSTOP信号后,就会暂停执行进入TASK_STOPED状态,表示自己准备好被调试了。

 

[转帖]gdb进阶调试技巧的更多相关文章

  1. gdb命令调试技巧

    gdb命令调试技巧 一.信息显示1.显示gdb版本 (gdb) show version2.显示gdb版权 (gdb) show version or show warranty3.启动时不显示提示信 ...

  2. 第09课:GDB 实用调试技巧(下)

    本节课的核心内容: 多线程下禁止线程切换 条件断点 使用 GDB 调试多进程程序 多线程下禁止线程切换 假设现在有 5 个线程,除了主线程,工作线程都是下面这样的一个函数: void thread_p ...

  3. 第08课:GDB 实用调试技巧( 上)

    本节课的核心内容: 将 print 打印结果显示完整 让被 GDB 调试的程序接收信号 函数明明存在,添加断点时却无效 将 print 打印结果显示完整 当使用 print 命令打印一个字符串或者字符 ...

  4. 【转贴】gdb中的信号(signal)相关调试技巧

    一篇不错的帖子,讲的是gdb中的信号(signal)相关调试技巧 转自Magic C++论坛  http://www.magicunix.com/index_ch.html  http://www.m ...

  5. GDB调试技巧:总结篇

    目录 一 写在开头 1.1 本文内容 二 学习资料 三 常用命令 四 调试技巧 注:原创不易,转载请务必注明原作者和出处,感谢支持! 一 写在开头 1.1 本文内容 总结GDB调试的一些常用命令和调试 ...

  6. gdb各种调试命令和技巧

    陈皓:用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台 ...

  7. pwn 题GDB调试技巧和exp模板

    GDB分析ELF文件常用的调试技巧 gdb常用命令 首先是gbd+文件名 静态调试 ,gdb attach +文件名 动态调试 为了方便查看堆栈和寄存器 最好是安装peda插件 安装 可以通过pip直 ...

  8. XCode的一些调试技巧

    XCode 内置GDB,我们可以在命令行中使用 GDB 命令来调试我们的程序.下面将介绍一些常用的命令以及调试技巧. po 命令:为 print object 的缩写,显示对象的文本描述(显示从对象的 ...

  9. GDB 多进程调试

    启动: $gdb <file>  || $gdb 然后(gdb)file <file> 运行: (gdb)run <该程序本身的命令行参数> 查看代码: (gdb) ...

  10. Linux c c++ 开发调试技巧

    看到一篇介绍 linux c/c++ 开发调试技巧的文章,感觉挺使用,哪来和大家分享. 通向 UNIX 天堂的 10 个阶梯Author: Arpan Sen, 高级技术人员, Systems Doc ...

随机推荐

  1. 实时入库不用愁,HStore帮分忧

    本文分享自华为云社区<直播回顾 | 实时入库不用愁,HStore帮分忧>,作者:汀丶. 海量数据时代,如何实现数据实时入库与实时查询?GaussDB(DWS) HStore表为数据高效存储 ...

  2. 基于Serverless的端边云一体化媒体网络

    摘要:视频在边缘的创新方向在哪?下一代视频云平台什么样? 本文分享自华为云社区<探讨视频云与边缘云平台的竞争力--基于Serverless的端边云一体化媒体网络>,作者/卢志航,整理 / ...

  3. Windows Service 服务中,不能访问挂载目录(网络映射盘)

    SpringBoot Windows 自启动 - 通过 Windows Service 服务实现 Windows Service 服务中,不能访问挂载目录(网络映射盘) 在Windows操作系统中,系 ...

  4. Nginx--用户认证&&访问控制&&限速&&状态访问

    一 用户认证 某些网页只希望给特定的用户访问,可以设置用户认证,使用户访问时需要进行身份认证,只有认证通过才可访问网页 location / { root html; index index.html ...

  5. Springcloud和Dubbo的区别。Eureka和Ribbon和Hystrix和zuul

    netty 是什么? "netty 是一个基于nio的客户.服务器端编程框架,netty提供异步的,事件驱动的网络应用程序框架和工具,可以快速开发高可用的客户端和服务器.netty是基于ni ...

  6. element的table组件在flex布局下宽度不能自适应

    问题描述 用了flex布局,左侧固定宽度,右侧flex:1:(表格在右侧区域),且中间容器都有width:100%,当将屏幕变大,表格随着变宽,当屏幕变小时,表格不会随着屏幕变小,宽度无法自适应. 解 ...

  7. 【Qt】开源一键代码开光神器,一行代码给你的项目施加祝福,减少Bug

    年底啦,没什么项目,想摸鱼划水没见到什么好玩的东西,看到有人分享这个,直接做个库来玩下,之后说不定会嵌到公司的项目里面去.... 效果如下,佛光普照! 输入也只需要一行命令 magic_spells: ...

  8. python常见面试题讲解(六)取近似值

    题目描述 写出一个程序,接受一个正浮点数值,输出该数值的近似整数值.如果小数点后数值大于等于5,向上取整:小于5,则向下取整. 输入描述: 输入一个正浮点数值 输出描述: 输出该数值的近似整数值 示例 ...

  9. ACP 知识点总结

    记录下学习ACP过程不断遇到的且需要记录的知识点: 在阿里云专有网络VPC创建之后,路由器也是随着VPC一起自动创建,所以不需要手动创建,这个时候需要继续创建交换机才能在交换机种创建其他云产品. 7层 ...

  10. 【lvgl-micropython】官方源码之ports/unix 编译报错

    lv_micropython/ports/unix make 报错 编译环境如下 这是缺少SDL2库导致的 sudo apt-get install libsdl2-2.0 sudo apt-get ...