当前位置: 首页 > news >正文

调试——GDB、日志

调试——GDB、日志

    • 1. gdb常用指令
    • 2. 如何生成core文件并调试?
    • 3. 如何调试正在运行的程序
    • 4. 调试多进程程序
    • 5. 调试多线程程序
    • 6. log日志

  • gcc编译器可以帮我们发现语法错误,但是对业务逻辑错误却无能为力。当我们想找出逻辑错误时,就需要调试,也就是要用gdb调试
  • GDB(gdb)全称“GNU symbolic debugger”,是 Linux 下常用的程序调试器。 为了能够使用 gdb 调试,需要在代码编译的时候加上-g,如
g++ -g -o test test.cpp

1. gdb常用指令

b(break) 10	:在第10行打上断点
r(run) :开始运行程序,直到遇到断点,并在断点这一行停下来(第一个运行的命令)
c(continue) :继续运行,一般先停下来,再用continue继续运行,直到遇到下一个断点
n(next) :执行当前这一行(彻底执行完,如果当前这一行是函数调用,则执行完这个函数)
p(print) name :显示变量name的值
p name++ :后面可以写一行代码,也就是一个表达式(什么都行,包括改变变量、输出都行)
set var name="仲书颉" :set var可以设置变量的值,这里设置name的值为仲书颉
set args 参数1 参数2:set args可以设置main(args,argv[])函数的参数,参数1就是argv[1]的值,参数2就是argv[2]的值-注意,当参数1内有空格时,要这样表示:set args "参数1" 参数2
s(step) :执行当前这一行-这一行不是函数时,和n(next)一样-这一行是函数时,s会进入函数的内部,执行函数内部的第一行(想进入函数里面,必须要用step)-注意,s并不能进入库函数或第三方函数,只能进入我们自己定义的函数(有函数源码)
l(list) :显示10行代码(基本不用,因为我们会另开一个窗口看源代码,一般不用list来看)
bt :查看执行到目前这一行为止,函数的调用栈
info b :显示断点的信息(有几个,哪几个)
info threads :显示已创建的线程的信息,带*号的就是当前被调试的线程
thread 2 :切换到id为2的线程来调试

2. 如何生成core文件并调试?

当程序出现段错误(core dump)时,用gdb调试core文件,可以立即定位到段错误所在行****,非常方便但是core文件默认是不生成的如何生成core文件呢?

在程序出现段错误后,我们需要在Linux中输入:
ulimit -a

会显示这样的结果:

我们只需要关注第一行,上面显示core文件大小为0

将core文件大小改为unlimited
ulimit -c unlimited

再出入ulimit -a后,显示:

gdb打开core文件

设置完core文件大小后,我们重新运行源程序,就会生成core文件。我们可以通过 **ls **来查看。

然后就用gdb调试即可:

gdb 可执行文件 core文件
#如:gdb book core19356

会显示:

可见,直接显示在第7行出现段错误

注:什么是段错误

**访问未分配或权限不足的内存 所产生的错误,就是段错误。有以下几种情况:

**

3. 如何调试正在运行的程序

如果我们使用gdb调试一个这个在运行的程序,那么这个程序就会立即停止运行。此时为了查看程序运行到说明地方,我们需要用 bt 命令,来查看函数的调用栈——最上面的就是正在运行的函数。

我们可用使用其他调试命令,如n、s等,可以让原本停下的程序继续运行一行。通过组合使用 n、s 和 bt 命令,可以调试正在运行的程序

4. 调试多进程程序

注:被调试的进程会停止运行,将在调试命令下一步一步执行。

调试父进程(默认)

默认就是调试父进程,或者也可以显示指定:

set follow-fork-mode parent

此时子进程将自动执行;而父进程会阻塞(因为先前设置了断点),等待我们的调试

调试子进程

需要显示指定:

set follow-fork-mode child

此时父进程将自动执行;而子进程会阻塞(因为先前设置了断点),等待我们的调试

调试模式

在确定调试子进程还是父进程后,就可以设置调试模式了,一共有两种调试模式:

调试当前进程时,其他进程继续运行

这是默认的情况,也可以显示指定:

set detach-on-fork on 
调试当前进程时,其他进程被gdb挂起,不能运行

需要显示指定:

set detach-on-fork off

如果我们是在调试父进程时采用了第二种调试模式,那么在调试父进程时,子进程不会自动运行。即使父进程调试执行完,子进程也不会运行。

查看和切换被调试的进程

设置第二种调试模式之后(即 set detach-on-fork off),我们才能查看和切换被调试的进程。

查看被调试的进程
info inferiors

序号1的前面有*号,表示我们正在调试的进程是 序号为1的进程

**切换要调试的进程**
inferior 进程id
#如 inferior 2,表示改为调试进程2,不再调试进程1

5. 调试多线程程序

注:如果使用的是POSIX线程库的话,在编译时还要加上 -l pthread

查看进程、线程以及线程之间的关系
//shell命令(非gdb命令):
ps aux | grep 过滤条件  #查看当前运行的进程ps -aL | grep 过滤条件  #查看当前运行的线程pstree -p 主线程id  #查看主线程和子线程之间的关系

线程调试的基础命令
info threads #显示已创建的线程的信息,带*号的就是当前被调试的线程thread 3 #切换到id为3的线程来调试

设置线程调试模式
**调试当前线程时,其他线程继续运行**

默认的情况,也可以显示指定:

set scheduler-locking off
**调试当前线程时,其他线程全部阻塞**

需要显示指定:

set scheduler-locking on
让指定线程执行指定命令
thread apply 线程id 命令
#如:thread apply 2 n,表示让线程3往下执行一次(即使当前调试的不是线程2,也可以执行该语句)

另,也可以让所有线程执行同一个语句:

thread apply all 命令

6. log日志

设置断点和单步调试 会严重影响线程之间的竞争状态。因为当一个线程在断点处停住了,而让另一个线程跑,就会导致并发被破坏,此时我们看到的只是一个和谐的假象。而log日志,就可以避免断点和单步的副作用。我们可以输出log日志,让程序每一步运行的时间都可以在日志文件中查到。

开源日志框架——freecplus

项目里需要同时包含_cmpublic.h、_freecplus.h、_freecplus.cpp这三个文件。第一个里全是程序用到的头文件;第二个文件包含了第一个文件,它定义了函数和类的声明;第三个文件包含了第二个文件,它是对函数和类的具体实现。_cmpublic.h_freecplus.cpp_freecplus.h

具体使用过程:

  1. 包含#include<_freecplus.h>(第一个文件就不用写了,因为已经包含了)
  2. 定义日志文件类(全局):
CLogFile logfile;
  1. 创建日志文件
logfile.Open("/tmp/gdbfork.log","w+");
/* 
/tmp/gdbfork.log是日志文件名,可以自己定义; w+是打开文件的方式,直接写上就好
*/
  1. 将所有的输出语句(printf、cout等)改为输出到日志文件
logfile.Write("Hello World");
  1. 编译并运行项目
g++ gdbfork.cpp _freecplus.cpp -o gdbfork
./gdbfork  #此时日志已经把所有的内容 输出的日志文件里面了
  1. 最后打开日志文件来查看即可
vi /tmp/gdbfork.log

我们也可以一边让程序运行,一边打开事先创建的日志文件,这样就可以观测** 程序运行的实时状态**。

http://www.xdnf.cn/news/284347.html

相关文章:

  • 使用直觉理解不等式
  • 架构思维:构建高并发读服务_热点数据查询的架构设计与性能调优
  • JVM 内存结构全解析
  • AI预测的艺术品走势靠谱吗?
  • 矩阵快速幂 快速求解递推公式
  • 数据集-目标检测系列- 蜥蜴 检测数据集 lizard >> DataBall
  • kotlin中枚举带参数和不带参数的区别
  • Debezium MySqlValueConverters详解
  • 抖音生活服务“五一”数据:小城游火爆,“食住”消费增速显著
  • 【Game】Powerful——Transformation Card(10)
  • linux系统基本操作命令
  • 探索神经符号系统:医疗AI的范式化进程分析
  • # 从零构建一个简单的卷积神经网络:手写数字识别
  • HTML 元素
  • adb无线调试步骤
  • MySQL C API高效编程:C语言实现数据库操作的深入解析
  • Git 第一讲---基础篇 git基础概念与操作
  • 《MATLAB实战训练营:从入门到工业级应用》高阶挑战篇-《用无人机仿真玩转PID控制:MATLAB四旋翼仿真建模全攻略》
  • MATLAB人工大猩猩部队GTO优化CNN-LSTM多变量时间序列预测
  • CDN一般在什么情况下会出现402报错呢?
  • 详解RabbitMQ工作模式之路由模式
  • Java后端开发day41--IO流(一)--FileOutputStreamFileInputStream
  • React-router v7 第八章(边界处理)
  • tensorflow 调试
  • Python从入门到高手8.2节-元组的常用操作符
  • 【Leetcode 每日一题 - 补卡】838. 推多米诺
  • LeetCode 热题 100 78. 子集
  • HTML5好看的水果蔬菜在线商城网站源码系列模板9
  • Nginx正反向代理与正则表达式
  • jupyter notebook运行简单程序