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. hiveSQL常见专题

    SQL强化 SQL执行顺序 --举例: select a.sex, b.city, count(1) as cnt, sum(salary) as sum1 from table1 a join ta ...

  2. Spark Streaming快速入门

    Spark Streaming快速入门 一.简介 Spark Streaming 是构建在 Spark Core 基础之上的流处理框架(但实际上是微批次处理框架),是 Spark 非常重要的组成部分. ...

  3. Draco使用笔记(1)——图形解压缩

    目录 1. 概述 2. 详论 2.1. 工具 2.2. 代码 1. 概述 Draco是Google开发的图形压缩库,用于压缩和解压缩3D几何网格(geometric mesh)和点云(point cl ...

  4. 空间数据库基础理论 GIS空间数据处理分析涉及的基本概念

    <空间数据库>课程整理汇总,106篇课程,内容太长,学习中,把一些关键点,汇总记下笔记 地理空间 GIS中的地理空间(Geo-spatial)是指经过投影变换后,在笛卡尔坐标系中的地球表层 ...

  5. 【终极教程】Cocos2dx服务端重构(优化cocos2dx服务端)

    [终极教程]Cocos2dx服务端重构(优化cocos2dx服务端) 文章目录 概述 问题概述1. 代码混淆代码加密具体步骤测试和配置阶段IPA 重签名操作步骤2. 缺乏文档3. 缺乏推荐的最佳实践4 ...

  6. 智能学习灯赛道竞争日趋激烈 火山引擎 VeDI 用数据技术助力打造新优势

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,并进入官方交流群 智能学习灯的赛道正变得越来越拥挤. 2021 年 3 月 2 日,腾讯教育联合暗物智能科技联合发布"AILA 智 ...

  7. PPT 毕业答辩:学术风格的PPT

    PPT 毕业答辩:学术风格的PPT 合适字体 便于阅读, 封面.标题 楷体.华康俪金黑.粗宋体.思源宋体.中山行书 正文 宋体.仿宋.微软雅黑.思源黑体 主题色 学术红.严谨紫.科学蓝 跟着LOGO ...

  8. 用 three.js 绘制三维带箭头线 (线内箭头)

    在LineMaterial.js基础上修改的ArrowLineMaterial.js代码: /** * @author WestLangley / http://github.com/WestLang ...

  9. 揭秘 vivo 如何打造千万级 DAU 活动中台 - 启航篇

    本文首发于 vivo互联网技术 微信公众号 链接:  https://mp.weixin.qq.com/s/Ka1pjJKuFwuVL8B-t7CwuA作者:悟空中台研发团队 vivo大厦(南京) 一 ...

  10. Serverless 应用托管助力企业加速创新

    作者: 熊峰 | 阿里云技术专家 云原生时代的 Serverless 应用托管架构 回顾过去十年,数字化转型将科技创新与商业元素不断融合.重构,重新定义了新业态下的增长极.商业正在从大工业时代的固化范 ...