GDB调试----基本用法

第一章 gcc的编译过程

1。编译过程

  • gcc -E hello.c -o hello.i:1.预处理,生成预编译文件
  • gcc -S hello.i -o hello.s:2.编译,生成汇编文件
  • gcc -c hello.s -o hello.o:3.汇编生成对象文件,可以用objdump查看
    • as hello.s -o hello.o
  • gcc main.o hello.o4.链接

2。热身准备:

  • 1.复现之前的心得
    • 配置环境
      • 挂载、内核模块参数、选项
      • 网络通信对方的硬件(网卡)
      • 磁盘的硬件制造商
      • 配置文件的内容
    • 听取:有疑问或需要更多信息应总结之后一起问,此外,对方可能不会告诉你重要消息
    • 重新审视配置:确认网线、配置文件内容、命令确认
  • 2.复现之后的心得
    • 确认现象:有些现象很像但bug不是真的复现了
    • 确认复现率和时间
  • 3.分析时候的心得
    • 目视确认现象
      • 某种操作后重启的例子,应当确认,是执行特定操作后出现panic就重启,还是几十秒后有watchdog重启,重启前能否操作、ping是否畅通
      • 控制台消息无法显示到画面上,请执行 echo 7 > /proc/sys/kernel/printk
    • 尽量缩小范围,缩短复现时间、提高复现概率
    • 根据内核配置、内核启动参数划分问题
      • 内核bug,可修改启动参数、内核配置方法。启动参数加上nosmp,确认是否为SMP环境下发生bug,e1000驱动bug,禁用NAPI也许能做出判断
    • 根据版本划分问题:低版本时候发生
    • 其他途径
      • 如网络问题,不仅查ifconfig、还需考虑ip命令、route命令、/proc/net信息
    • 根据事实做出判断
  • 4.问题不明时心得
    • 怀疑硬件问题
    • 找找以前改正的同类错误:git或Bugzilla中关键字搜索
    • 无法复现、原因不明时:加调试信息
    • 为bug做准备:输出日志,定期获取内存、网络、IO、CPU使用率,sar、top、free、/proc/meminfo、/proc/slainfo等日志
    • 跟同事讨论
    • 咨询社区

二章 调试前的必会知识

4. 获取内核的进程转储

4.1 举例

  • ulimit -c:查看当前内核转储是否有效
  • ulimit -c unlimited:不限制内核转储文件大小
  • ulimit -c 1073741824:设置内核转储文件上限
  • 打开/etc/sysctl.conf设置core文件路径
    # %p-进程ID,%s-引发转储的信号编号,%t-转储时刻,%e-可执行文件名
    kernel.core_pattern=/mnt/f/core/core.%t-%e-%p
    kernel.core_uses_pid=0
    
  • sysctl -p
  • 新建测试文件
    #include 
    int main(void){
       int *a=NULL;
       *a=0x1;
       return 0;
    }
    
  • 编译:gcc 14_a.c -g#注意加上-g选项保存调试信息
  • ./a.out#运行,,正常应该报错
  • file *core:在当前目录下查看生成的内核转储文件
  • gdb -c core ./a.out:用GDB调试生成的内核转储文件,出现如下信息
    [New LWP 3096]
    Core was generated by `./a.out'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0x00000000004004e6 in main () at 14_a.c:4
    4	   *a=0x1;
    
    • 指示第7行在访问a地址的时候出现错误

4.2 启用整个系统的内核转储功能

  • 修改会添加 /etc/profie:
    ulimit -S -c unlimited > /dev/null 2>&1
    DAEMON_COREFILEFILE='unlimited'
  • 在文件/etc/sysctl.conf中添加:fs.suid_dumpable=1
  • 重启系统

4.3 利用内核转储掩码排除共享内存


5. 调试器(GDB)的基本使用方法(之一)

1.带着调试选项编译

  • gcc -wall -02 -werror -g 源文件
    • -g:保存调试信息
    • -werror:在警告发生时当做错误来处理
  • CFLAGS = -Wall -O2 -g
  • ./configure CFLAGS="-Wall -O2 -g"

2.启动调试器

  • 运行gdb
    • gdb a.out
    • ./a.out ;ls *core#运行并查看内核转储文件
    • gdb -c core ./a.out:用GDB调试生成的内核转储文件,出现如下信息
  • 设置断点
    • break 函数名/行号/文件名:行号/文件名:函数名/+偏移量/-偏移量/*地址
      • b main:在main函数出设置断点
      • b +3:现在暂停位置往后3行
    • info braek:查看断点
  • 运行
    • run -a:运行程序,不加参数会执行到设置了断点的位置
    • start:同上
  • 显示栈帧
    • backtrace full -N:在端点处显示最后的N个栈帧,简写bt
    • bt 3:显示前3个栈帧
    • bt full -3:从外向内显示3个栈帧及局部变量
  • 显示变量
    • print:显示局部变量
      • p *argv:打印argv指针指向的值
  • 显示寄存器
    • info reg/registers:显示寄存器值
    • p/c $eax:ASCII显示寄存器的值
      • u:无符号十进制
      • o:八进制
      • t:二进制
      • d:十进制
      • f/s/c/a/i:浮点/字符串/ASCII/地址/机器语言
  • 显示内存内容
    • x/NFU addr
      • n为重复次数,F为格式,U:
        • b字节,h半字,w字,g双字
        • x/10i $pc:显示地址从pc开始的10条汇编代码
  • 反汇编
    • disassemble:反汇编当前的整个函数
    • disassemble 程序计数器:反汇编程序计数器所在函数的整个函数
    • disassemble 开始地址 结束地址:反汇编从开始地址到结束地址之间的部分
      • disas $pc:反汇编程序计数器所在函数的整个函数
      • disas $pc $pc+50:从开始到结束地址之前的部分
  • 单步执行
    • next:执行下一步
    • step:执行到函数内部
    • nexti/stepi:逐条执行汇编指令
  • 继续运行
    • continue:继续执行,加数字如 c 5表遇到5次断点不停止
    • continue 5:忽略5次断点
  • 监视点
    • watch <表达式>:常量或变量发生变化时暂停运行
    • awatch <表达式>:被访问、改变时暂停访问
    • rwatch <表达式>:被访问时暂停运行
      • awatch short_output:short_output被访问时暂停运行
  • 删除断点或监视点
    • 先通过info b查看断点编号
    • delete 2:删除断点或监视点编号3
  • 改变变量的值
    • set variable <变量>=<表达式>:如set variable a=1,把a的值改为1
  • 生成内核转储文件
    • generate-core-file:生成内核转储文件
    • gcore 'pidof emacs':在命令行直接生成内核转储文件,无须停止程序

6. 调试器(GDB)的基本使用方法(之二)

  • attach到进程
    • attach pid:attach到进程ID为pid的进程上
    • detach:和进程分离
    • info proc:显示进程信息
  • 条件断点
    • break 断点 if 条件:条件断点
      • b iseq_compile if node==0
    • condition 断点编号 条件
      • 给指定断点添加或删除触发条件
  • 反复执行
    • ignore 断点编号 次数:反复执行
    • step/stepi/next/netxi/continue 次数:指定命令执行的次数
  • 删除断点和禁用断点
    • clear:清空已定义的断点
      • clear/clear 函数名/行号…
    • disable/enable:禁用/启用断点
      • disable display:禁用display命令定义的自动显示
      • disable men:禁用men命令定义的内存区域
      • enable [breakpoints] once 断点编号:启用一次断点编号
  • 断点命令:在断点中继后自动执行命令
    commands 断点编号
       命令
       ...
    end
    
    • 例:
      (gdb) command 2
      Type commands for when breakpoint 2 is hit,one per line.
      End whth a line saying just "end".
      >p *iseq
      >end
      
  • 其他命令
    • directory:dir,插入目录
    • down/up:在当前栈帧中选择要显示的栈帧
    • edit:编辑文件或函数
    • frame:选择要显示的栈帧
    • forward-search:向前搜索
    • list:l,显示函数或行
    • print-object:po,显示目标信息
    • sharedlibrary:share,加载共享库的符号
    • finish:执行完当前函数后暂停
    • until <地址>:执行完当前代码块后跳出循环,常用于跳出循环

_7. 调试器(GDB)的基本使用方法(之三)

  • p $:显示最后一次print输出的值
  • show walue:显示历史中print的最后十条值

你可能感兴趣的:(调试经验)