Linux下gdb调试用法命令

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/keith_bb/article/details/55216039

一直在Fedora平台下写opencv的程序,需要对程序进行调试,主要用的调试工具是gdb. gdb提供了如下功能:

  • 1.在程序中设置断点,Debug时遇到断点处暂停
  • 2.可以监视某个变量,并利用print函数将该变量的值打印出来
  • 3.程序可step-by-step执行
  • 4.运行时修改变量的值
  • 5.跟踪路径
  • 6.线程切换等
    下面结合OpenCV针对C\C++程序使用gdb调试进行介绍。

1.gdb安装

首先检查一下电脑中是否已经安装gdb

gdb --version

如果已经存在gdb,则会得到如下结果:
这里写图片描述
如果没有给出gdb的版本号则需要手动下载

sudo apt-get install gdb #针对Ubuntu系统
sudo dnf install gdb #针对Fedora系统

2.gcc\g++编译基础

在前面我们文章《opencv之在Linux下编译opencv程序的两种方式g++、cmake》介绍过gcc\g++编译的基础内容,当需要使用gdb调试代码时,需要在gcc\g++编译选项中添加-g选项,如下所示:

g++ -g `pkg-config opencv --cflags` opencv.cpp  -o opencv `pkg-config opencv --libs`  

这样生成的opencv可执行文件可以直接使用gdb进行调试
可以直接在命令行输入gdb+程序名进入调试,在这里使用《opencv学习(三十一)之图像边缘像素填充估计copyMakeBorder()》中的程序进行演示,其代码如下所示:

/*程序说明
 *当按下按键‘c’代表使用BORDER_CONSTANT
 *RNG生成的随机数作为像素值进行填充
 *当按下按键‘r’代表使用BORDER_REPLICATE
 *图像扩充的边框由原图像边缘像素的值进行填充
 */

#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

using namespace std;
using namespace cv;

//声明全局变量
Mat srcImage, dstImage;
int g_top, g_bottom, g_left, g_right;
int borderType;
Scalar value;
String windowName = "copyMakeBorder Demo";
RNG rng(12345);

int main()
{
    int c;

    srcImage = imread("dog.jpg");

    //判断图像是否加载成功
    if(srcImage.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像记载成功" << endl << endl;
    imshow("原图像", srcImage);

    //程序使用说明
    printf("\n \t copyMakeBorder Demo: \n");
    printf("\t --------------------\n");
    printf("**Press 'c' to set the border to a random constant value \n");
    printf("**Press 'r' to set the border to be replicated \n");
    printf("**Press 'ESC' to exit the program \n");

    //创建窗口
    namedWindow(windowName, WINDOW_AUTOSIZE);

    //初始化边框参数
    g_top = (int)(0.05*srcImage.rows);
    g_bottom = (int)(0.05*srcImage.rows);
    g_left = (int)(0.05*srcImage.cols);
    g_right = (int)(0.05*srcImage.cols);

    //显示初始图像
    dstImage = srcImage;    
    imshow(windowName, dstImage);

    while(true)
    {
        c = waitKey(500);

        if((char)c == 27)   //c为ESC程序退出
        {break;}
        else if((char)c == 'c')
        {borderType = BORDER_CONSTANT;}
        else if((char)c == 'r')
        {borderType = BORDER_REPLICATE;}

        value = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        copyMakeBorder(srcImage, dstImage, g_top, g_bottom, g_left, g_right, borderType, value);

        imshow(windowName, dstImage);
    }

    return 0;
}

使用g++对该程序进行编译,如下

g++ -g `pkg-config opencv --cflags` copyMakeBorder.cpp -o copyMakeBorder `pkg-config opencv --libs` 

在程序文件夹中生成名字为copyMakeBorder的可执行文件,下面进入gdb调试状态,直接输入gdb+程序名即:

gdb copyMakeBorder

这里写图片描述

3.gdb调试基本命令

进入gdb后可直接在(gdb)后输入相应命令进行调试操作。

3.1 list命令

list命令可以所写为l,可以列出所调试程序的代码,其居具体用法包括:

  • list+lineNumber(中间有空格)
    可以打印出行第lineNumber行周围的源程序,如:
(gdb)list 45

其打印结果如下:
这里写图片描述

  • list 打印函数名称为Function的函数上下文的源程序,如下
(gdb) list main

结果如下:
这里写图片描述

  • list 输出当前行后面的代码,如
(gdb) list

这里写图片描述

  • list -显示当前行前面的代码
(gdb) list -

这里写图片描述

针对前面介绍的四种情况,在执行完一个命令后不输入任何命令,gdb会默认执行上一个命令

3.2 run命令

在gdb中运行程序使用run命令,在程序运行前可以设置程序的工作远景如:

  • 程序运行参数

    可以通过set args执行运行时的参数,针对的是main函数有如下书写格式时的程序

int main(int argc, char** argv)
{
    ...
}

对于这种格式的程序可以参考《程序命令行argc\argv》

- 程序运行环境
path < dir >可设定程序的运行路径;how paths可查看程序的运行路径;set environment varname [=value]用于设置环境变量;show environment [varname]用于查看环境变量。
![这里写图片描述](https://img-blog.csdn.net/20170215204054254?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2VpdGhfYmI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
  • 工作目录
    cd < dir >相当于在终端中输入的cd命令;pwd命令用于显示当前所在目录
    这里写图片描述
  • 输入输出
    info terminal用于显示程序用到的终端模式;gdb中也可以使用重定向控制程序输出如:run>outfile; tty命令可以指定输入输出设备终端,如:tty /dev/ttyS1.

3.3 break命令

在使用gdb调试时使用break命令来设置断点,有如下几种方法:

  • break < function >
    在进入指定的函数function时既停止运行,C++中可以使用class::function或function(type, type)格式来指定函数名称
  • break < lineNumber>
    在指定的代码行打断点
  • break +offset/break -offset
    在当前行的前面或后面的offset行打断点,offset为自然数
  • break filename:lineNumber
    在名称为filename的文件中的第lineNumber行打断点
  • break filename:function
    在名称为filename的文件中的function函数入口处打断点
  • break *address
    在程序运行的内存地址处打断点
  • break
    在下一条命令处停止运行
  • break … if < condition>
    在处理某些循环体中可使用此方法进行调试,其中…可以是上述的break lineNumber、break +offset/break -offset中的参数,其中condition表示条件,在条件成立时程序即停止运行,如设置break if i=100表示当i为100时程序停止运行。
    查看断点时,也可以使用info命令如info breakpoints [n]、info break [n]其中n 表示断点号来查看断点信息。
    如下:
    这里写图片描述

可以通过delete命令删除所有的断点,如下:
这里写图片描述

3.4 逐步调试

使用gdb工具调试可以使用next命令单步执行程序代码,next的单步不会进入函数的内部,与next对应的step命令则在单步执行一个函数时进入函数内部,类似于VC++中的step into.其用法如下

  • next < count>
    单步跟踪,如果有函数调用不会进入函数,如果后面不加count表示一条一条的执行,加count表示执行后面的count条指令,
(gdb) next 5

这里写图片描述
- step < count>
单步跟踪,如果有函数调用则进入该函数(进入该函数前提是此函数编译有Debug信息),与next类似,其不加count表示一条一条执行,加上count表示自当前行开始执行count条代码指令
- set step-mode
set step-mode on用于打开step-mode模式,这样在进行单步跟踪时,程序不会因为没有debug信息而不停止运行,这很有利于查看机器码,可以通过set step-mode off关闭step-mode模式
- finish
运行程序直到当前函数完成并打印函数返回时的堆栈地址和返回值及参数值等信息。
- until
运行程序直到退出循环体
- stepi(缩写si)和nexti(缩写ni)
stepi和nexti用于单步跟踪一条及其指令,一条程序代码有可能由数条机器指令完成,stepi和nexi可以单步执行机器指令。

3.5 continue命令

当程序遇到断点停止运行后可以使用continue命令恢复程序的运行到下一个断点或直到程序结束,其具体用法如下:

  • continue [ignore-count]
    continue也可缩写为c,fg命令与continue命令相同,故上述continue可以使用c或fg代替,如下:
    这里写图片描述

3.6 print命令

print可以缩写为p,可以通过print命令查看参数或程序运行数据

(gdb) break 53
Breakpoint 1 at 0x80490a7: file copyMakeBorder.cpp, line 53.
(gdb) break 54
Breakpoint 2 at 0x80490f3: file copyMakeBorder.cpp, line 54.
(gdb) break 55
Breakpoint 3 at 0x8049129: file copyMakeBorder.cpp, line 55.
(gdb) break 56
Breakpoint 4 at 0x804915f: file copyMakeBorder.cpp, line 56.
(gdb) r
Starting program: /home/keith/program/opencv/opencv学习(三十一)之图像边框/copyMakeBorder 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
[New Thread 0xb543fb40 (LWP 11484)]
图像记载成功

[New Thread 0xb470db40 (LWP 11485)]
[New Thread 0xb3dffb40 (LWP 11486)]

     copyMakeBorder Demo: 
     --------------------
**Press 'c' to set the border to a random constant value 
**Press 'r' to set the border to be replicated 
**Press 'ESC' to exit the program 

Thread 1 "copyMakeBorder" hit Breakpoint 1, main () at copyMakeBorder.cpp:53
53      g_top = (int)(0.05*srcImage.rows);
(gdb) continue
Continuing.

Thread 1 "copyMakeBorder" hit Breakpoint 2, main () at copyMakeBorder.cpp:54
54      g_bottom = (int)(0.05*srcImage.rows);
(gdb) p g_top
$1 = 20
(gdb) p g_bottom
$2 = 0
(gdb) continue 
Continuing.

Thread 1 "copyMakeBorder" hit Breakpoint 3, main () at copyMakeBorder.cpp:55
55      g_left = (int)(0.05*srcImage.cols);
(gdb) p g_bottom 
$3 = 20
(gdb) 

部分截图如下:
这里写图片描述
值得注意的是print输出可以指定输出格式

  • x按16进制格式显示变量
  • d按十进制显示变量
  • u按十六进制格式显示无符号整形
  • o按八进制格式显示变量
  • t按二进制格式显示变量
  • c按字符格式显示变量
  • f按浮点数格式显示变量
    可以使用display命令设置一些自动显示的变量,当程序暂停运行或单步跟踪时,这些变量会自动显示
    这里写图片描述
    如果要修改变量的值也可以使用print命令如
print g_top = 24

使用print查看程序运行时的数据时,每一个print都会被gdb记录下来并且以 (美元符号)1、(美元符号)2…这样的方式为每一个print命令编号,我们可以使用这个编号来访问以前的表达式如:
这里写图片描述

3.7 watch命令

watch命令一般来观察某个表达式(变量也可视为一种表达式)的值是否发生了变化,如果由变化则程序立即停止运行,其具体用法如下:

  • watch < expr>
    为表达式(变量)expr设置一个观察点一旦其数值由变化,程序立即停止运行
  • rwatch < expr>
    当表达式expr被读时,程序立即停止运行
  • awatch < expr>
    当表达式expr的值被读或被写时程序立即停止运行
  • info watchpoints
    列出当前所设置的所有观察点

3.8 return命令

如果在函数中设置了调试断点,在断点后还有语句没有执行完,这个时候我们可以使用return命令强制函数忽略还没有执行的语句并返回。可以直接使用return命令用于取消当前函数的执行并立即返回函数值,也可以指定表达式如 return < expression>那么该表达式的值会被作为函数的返回值。

3.9 info命令

info命令可以用来在调试时查看寄存器、断点、观察点和信号等信息。其用法如下:

  • info registers:查看除了浮点寄存器以外的寄存器
  • info all-registers: 查看所有的寄存器包括浮点寄存器
  • info registers < registersName>:查看指定寄存器
  • info break: 查看所有断点信息
  • info watchpoints: 查看当前设置的所有观察点
  • info signals info handle: 查看有哪些信号正在被gdb检测
  • info line: 查看源代码在内存中的地址
  • info threads: 可以查看多线程

3.10 run和quit命令

run(缩写r)和quit(缩写q)分别可以开始运行程序和退出gdb调试

3.11 其他命令

  • whatis或ptype显示变量的类型
  • bt显示函数调用路径

这篇参考了很多篇博客,gdb的这些命令不断应用才能熟练运用,当然这些命令没有完全列出gdb命令,可以通过help命令查看gdb所有命令帮助。
参考博客:
http://blog.csdn.net/21cnbao/article/details/7385161
http://blog.csdn.net/yeyuangen/article/details/6825542
http://www.cnblogs.com/kunhu/p/3603268.html

猜你喜欢

转载自blog.csdn.net/keith_bb/article/details/55216039