IE盒子

搜索
查看: 180|回复: 1

【C-32】C语言调试工具gdb

[复制链接]

4

主题

5

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2022-9-22 20:02:03 | 显示全部楼层 |阅读模式
1、GDB简介

GDB(GNU Debugger)是GCC的调试工具。主要帮你完成下面四个方面的功能:

  • 启动程序, 可以按照你的自定义的要求随心所欲的运行程序。
  • 可让被调试的程序在你所指定的断点处停住。(断点可以是条件表达式)
  • 当程序被停住时, 可以检查此时你的程序中所发生的事。
  • 动态的改变你程序的执行环境。
2、gdb调试

gdb是在程序运行的结果与预期不符合的时候, 可以使用gdb进行调试。特别注意的是: 使用gdb调试需要在编译的时候加-g参数.  如果没有-g, 你将看不见程序的函数名、变量名, 所代替的全是运行时的内存地址。
gcc -g -c hello.c
gcc -o hello hello.o3、基本操作

1 启动gdb

这里测试还是使用【C-30】C语言gcc编译器和静动态库 的四个简单函数为实例。并作稍微修改如下:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "head.h"

int main(int argc, char *argv[])
{
    printf("this is main!\n");
        int i = 0;
        for(i=0; i<argc; i++)
        {
                printf("[%d]:[%s]\n", i, argv);
        }

    fun1();
    fun2();

        printf("sum(10)==[%d]\n", sum(10));

    return 0;
}sum.c
#include <stdio.h>

int sum(int len)
{
        int i = 0;
        int sum = 0;
        for(i=0; i<len; i++)
        {
                sum += i;
        }
        return sum;
}修改之前的Makefile如下($(CC) -g -c $< $(CPPFLAGS))
src=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./

$(target):$(object)
        $(CC) -o $@ $^

%.o:%.c
        $(CC) -g -c $< $(CPPFLAGS)

.PHONY:clean
clean:
        #rm -f $(target) $(object)
        rm -f $(object)
启动gdb:gdb program
program 也就是你的执行文件, 一般在当前目录下。
设置运行参数

  • set args 可指定运行时参数。(如:set args 10 20 30 40 50 )
  • show args 命令可以查看设置好的运行参数。
启动程序

  • run:程序开始执行, 如果有断点, 停在第一个断点处
  • start:程序向下执行一行。(在第一条语句处停止)
gdb ./main
(gdb) set args hello yifan,I am here
(gdb) show args
Argument list to give program being debugged when it is started is "hello yifan,I am here".
(gdb) run
Starting program: /u02/wangbao/test_c/main hello yifan,I am here
this is main!
this is fun
this is fun2
this is fun2
[Inferior 1 (process 24566) exited normally]
(gdb) start
Temporary breakpoint 1 at 0x40051d: file main.c, line 6.
Starting program: /u02/wangbao/test_c/main hello yifan,I am here

Temporary breakpoint 1, main (argc=5, argv=0x7fffffffea88) at main.c:6
6                printf("this is main!\n");退出gdb,使用quit
2 显示源代码       

GDB 可以打印出所调试程序的源代码,当然在程序编译时一定要加上-g的参数,把源程序信息编译到执行文件中。不然就看不到源程序了。当程序停下来以后, GDB会报告程序停在了那个文件的第几行上。你可以用list命令来打印程序的源代码, 默认打印10行, list命令的用法如下所示:
list linenum:打印第linenum行的上下文内容.
list function:显示函数名为function的函数的源程序。
list: 显示当前行后面的源程序。
list -:显示当前文件开始处的源程序。
list file:linenum: 显示file文件下第n行
list file:function: 显示file文件的函数名为function的函数的源程序 一般是打印当前行的上5行和下5行,默认是10行, 当然, 你也可以定制显示的范围, 使用下面命令可以设置一次显示源程序的行数。

  • set listsize count:设置一次显示源代码的行数。
  • show listsize:   查看当前listsize的设置。
(gdb) list fun1.c:1
1        #include<stdio.h>
2        void fun1()
3        {
4                printf("this is fun\n");
5        }
(gdb)
Line number 6 out of range; fun1.c has 5 lines.
(gdb) list fun1.c:fun1
1        #include<stdio.h>
2        void fun1()
3        {
4                printf("this is fun\n");
5        }

(gdb) list main
1        #include<stdio.h>
2        #include<stdlib.h>
3        #include"head.h"
4        int main(int argc, char *argv[])
5        {
6                printf("this is main!\n");
7                fun1();
8                fun2();
9                return 0;
10        }
(gdb) set listsize 4
(gdb) list main
3        #include"head.h"
4        int main(int argc, char *argv[])
5        {
6                printf("this is main!\n");
(gdb)list 可以简写为l
3 断点操作

1 简单断点—当前文件
break 设置断点, 可以简写为b

  • b 10 设置断点, 在源程序第10行
  • b func 设置断点, 在func函数入口处
2 多文件设置断点---其他文件
在进入指定函数时停住:

  • b filename:linenum --在源文件filename的linenum行处停住
  • b filename:function --在源文件filename的function函数的入口处停住
3 查询所有断点

  • info b == info break == i break == i b
4 条件断点

一般来说, 为断点设置一个条件, 我们使用if关键词, 后面跟其断点条件。设置一个条件断点:

  • b test.c:8 if intValue == 5
  • b linenum
  • b func
  • b file:linenum
  • b file:func
5 维护断点

delete [range...] 删除指定的断点, 其简写命令为d。如果不指定断点号, 则表示删除所有的断点。range表示断点号的范围(如:3-7)。

  • 删除某个断点: delete num
  • 删除多个断点: delete num1 num2  ...
  • 删除连续的多个断点: delete m-n
  • 删除所有断点: delete
比删除更好的一种方法是disable停止点, disable了的停止点, GDB不会删除, 当你还需要时, enable即可, 就好像回收站一样。

  • disable [range...] 使指定断点无效, 简写命令是dis。
  • enable [range...] 使无效断点生效, 简写命令是ena。
6 调试代码


  • run 运行程序, 可简写为r
  • next 单步跟踪, 函数调用当作一条简单语句执行, 可简写为n
  • step 单步跟踪, 函数调进入被调用函数体内, 可简写为s
  • finish 退出进入的函数, 如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
  • until 在一个循环体内单步跟踪时, 这个命令可以运行程序直到退出循环体,可简写为u,如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
  • continue 继续运行程序, 可简写为c(若有断点则跳到下一个断点处)
2: sum = 3
(gdb) n
7                for(i=0; i<len; i++)
2: sum = 6
(gdb) until
11                return sum;
2: sum = 45
7 查看变量的值

查看运行时变量的值

  • print 打印变量、字符串、表达式等的值, 可简写为p
自动显示变量的值
你可以设置一些自动显示的变量, 当程序停住时, 或是在你单步跟踪时, 这些变量会自动显示。相关的GDB命令是display。

  • display 变量名
  • info display -- 查看display设置的自动显示的信息。
  • undisplay num(info display时显示的编号)
  • delete display dnums… -- 删除自动显示, dnums意为所设置好了的自动显式的编号。如果要同时删除几个, 编号可以用空格分隔, 如果要删除一个范围内的编号, 可以用减号表示(如:2-5)

    • 删除某个自动显示: undisplay num 或者delete display num
    • 删除多个: delete display num1 num2
    • 删除一个范围: delete display m-n

  • disable display dnums…   显示无效
  • enable display dnums…   显示有效
  • disable和enalbe          不删除自动显示的设置, 而只是让其失效和恢复。
(gdb) print sum
$7 = 3
(gdb) print i
$8 = 2
---------------------以上是手动print,可以设置成自动显示----------------------------
(gdb) display i
1: i = 2
(gdb) next
9                        sum += i;
1: i = 3
(gdb) display sum
2: sum = 3
(gdb) n
7                for(i=0; i<len; i++)
1: i = 3
2: sum = 6
   
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  i
2:   y  sum
(gdb) disable display 1
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   n  i
2:   y  sum查看修改变量的值

  • ptype width --查看变量width的类型
  • p width --打印变量width 的值
你可以使用set var命令来告诉GDB, width不是你GDB的参数, 而是程序的变量名, 如:set var width=47  // 将变量var值设置为47在你改变程序变量取值时, 最好都使用set var格式的GDB命令。
(gdb) r
Starting program: /u02/test_c/main
Breakpoint 5, __libc_start_main (main=0x400593 <main>, argc=1, argv=0x7fffffffeac8,
    init=0x400630 <__libc_csu_init>, fini=0x4006a0 <__libc_csu_fini>,
    rtld_fini=0x7ffff7de3b40 <_dl_fini>, stack_end=0x7fffffffeab8) at ../csu/libc-start.c:137
137        ../csu/libc-start.c: No such file or directory.
(gdb) ptype argc
type = int
(gdb) ptype argv
type = char **
(gdb) print argv
$10 = (char **) 0x7fffffffeac8
(gdb) print argc
$11 = 1
(gdb) print argv[0]
$12 = 0x7fffffffed04 "/u02/test_c/main"main函数的第一个参数就是主程序,后面才是自己的参数。
8 设置参数并显示

举例:set args yifan nihao
(gdb) set args yifan nihao
(gdb) print argc
No symbol "argc" in current context.
(gdb) i b
No breakpoints or watchpoints.
(gdb) b 10
Breakpoint 1 at 0x4005a2: file main.c, line 10.
(gdb) run
Starting program: /u02/wangbao/test_c/main yifan nihao

Breakpoint 1, main (argc=3, argv=0x7fffffffeaa8) at main.c:10
10            printf("this is main!\n");
(gdb) print argc
$1 = 3
(gdb) print argv
$2 = (char **) 0x7fffffffeaa8
(gdb) print argv[0]
$3 = 0x7fffffffecf8 "/u02/wangbao/test_c/main"
(gdb) print argv[1]
$4 = 0x7fffffffed11 "yifan"
(gdb) print argv[2]
$5 = 0x7fffffffed17 "nihao"
(gdb) print argv[3]
$6 = 0x04、debug实例

一个项目中地址切词部分需要debug,这里正好演示操作。因为是公司项目,代码部分就不粘贴了。
1 编译部分加  -g

sudo g++ -O3 -lpthread -std=c++11 -g  wb_word_cut.cpp -I/u03/wb/addr_i1_cpp/addr_20/dict/include -o /u03/wang/addr_i1_cpp/addr_20/run_wb/wb_word_cut_gdb
2 开启gdb

开启gdb,并输入参数:
]$gdb wb_word_cut

(gdb) set args "上海上海市松江区上海上海市松江区泗泾镇泗凤公路1500弄7号楼804"3 设置断点

使用list查找要打断点的位置


设置断点


4 测试

(gdb) run
Starting program: /u03/wangbao/addr_i1_cpp/addr_20210927_15/run_wb/wb_word_cut_gdb "上海上海市松江区上海上海市松江区泗泾镇泗凤公路1500弄7号楼804"
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 3, RepairAddrWords (words=std::vector of length 11, capacity 13 = {...}) at fun_const.h:1039
1039                for (int j = 0; j < 5; j++) {
(gdb) i display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  res (cannot be evaluated in the current context)
(gdb) display words
2: words = std::vector of length 11, capacity 13 = {"上海市", "上海市", "松江区", "上海", "上海市", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb) i display
Auto-display expressions now in effect:
Num Enb Expression
2:   y  words
1:   y  res (cannot be evaluated in the current context)
(gdb) n
查看效果情况:
#补全功能,上海  补全成上海市
1040                        if (words[j] == u8"北京" || words[j] == u8"天津" || words[j] == u8"重庆" || words[j] == u8"上海") {
2: words = std::vector of length 11, capacity 13 = {"上海市", "上海市", "松江区", "上海", "上海市", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb) n
1041                                words[j] = words[j] + u8"市";
2: words = std::vector of length 11, capacity 13 = {"上海市", "上海市", "松江区", "上海", "上海市", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb) n
1045                        if (words[j] == u8"广东" || words[j] == u8"浙江" || words[j] == u8"河北" || words[j] == u8"辽宁" || words[j] == u8"吉林" || words[j] == u8"黑龙江" || words[j] == u8"江苏" ||
2: words = std::vector of length 11, capacity 13 = {"上海市", "上海市", "松江区", "上海市", "上海市", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}


#去重功能:松江区重复的去掉:
2: words = std::vector of length 8, capacity 13 = {"上海市", "松江区", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb)
1068                                        if (words[j] == words ||
2: words = std::vector of length 8, capacity 13 = {"上海市", "松江区", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb)
1072                                                words.erase(words.begin() + i, words.begin() + i + 1);
2: words = std::vector of length 8, capacity 13 = {"上海市", "松江区", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
(gdb)
1067                                for (int i = iEnd; i > j; i--) {
2: words = std::vector of length 7, capacity 13 = {"上海市", "松江区", "泗泾镇", "泗凤公路", "1500弄", "7号楼", "804"}
回复

使用道具 举报

3

主题

10

帖子

17

积分

新手上路

Rank: 1

积分
17
发表于 18 小时前 | 显示全部楼层
围观 围观 沙发在哪里!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表