掌握GDB调试工具,轻松排除bug(上)

简介: 掌握GDB调试工具,轻松排除bug

一、什么是GDB

gdb是GNU debugger的缩写,是编程调试工具。

  • GDB官网:https://www.gnu.org/software/gdb/(https://www.gnu.org/software/gdb/)
  • GDB适用的编程语言: Ada / C / C++ / objective-c / Pascal 等。
  • GDB的工作方式: 本地调试和远程调试。

目前release的最新版本为8.0,GDB可以运行在Linux 和Windows 操作系统上。

1.1安装与启动GDB

  1. gdb -v 检查是否安装成功,未安装成功则安装(必须确保编译器已经安装,如 gcc) 。
  2. 启动 gdb
  1. gdb test_file.exe 来启动 gdb 调试, 即直接指定需要调试的可执行文件名
  2. 直接输入 gdb 启动,进入 gdb 之后采用命令 file test_file.exe 来指定文件名
  3. 如果目标执行文件要求出入参数(如 argv[] 接收参数),则可以通过三种方式指定参数:
  1. 在启动 gdb 时,gdb --args text_file.exe
  2. 在进入gdb 之后,运行 set args param_1
  3. 在 进入 gdb 调试以后,run param_1 或者 start para_1

1.2gdb的功能

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

1.3gdb的使用

运行程序

run(r)运行程序,如果要加参数,则是run arg1 arg2 ...

查看源代码

list(l):查看最近十行源码
list fun:查看fun函数源代码
list file:fun:查看flie文件中的fun函数源代码

设置断点与观察断点

break 行号/fun设置断点。
break file:行号/fun设置断点。
break if<condition>:条件成立时程序停住。
info break(缩写:i b):查看断点。
watch expr:一旦expr值发生改变,程序停住。
delete n:删除断点。

单步调试

continue(c):运行至下一个断点。
step(s):单步跟踪,进入函数,类似于VC中的step in。
next(n):单步跟踪,不进入函数,类似于VC中的step out。
finish:运行程序,知道当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
until:当厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序知道退出循环体。

查看运行时数据

print(p):查看运行时的变量以及表达式。
ptype:查看类型。
print array:打印数组所有元素。
print *array@len:查看动态内存。len是查看数组array的元素个数。
print x=5:改变运行时数据。

1.4程序错误

  • 编译错:编写程序的时候没有符合语言规范导致编译错误。比如:语法错误。
  • 运行时错误:编译器检查不出这种错误,但在运行时候可能会导致程序崩溃。比如:内存地址非法访问。
  • 逻辑错误:编译和运行都很顺利,但是程序没有干我们期望干的事情。

1.5gdb调试段错误

什么是段错误?段错误是由于访问非法地址而产生的错误。

  • 访问系统数据区,尤其是往系统保护的内存地址写数据。比如:访问地址为0的地址。
  • 内存越界(数组越界,变量类型不一致等)访问到不属于当前程序的内存区域。

gdb调试段错误,可以直接运行程序,当程序运行崩溃后,gdb会打印运行的信息,比如:收到了SIGSEGV信号,然后可以使用bt命令,打印栈回溯信息,然后根据程序发生错误的代码,修改程序。

1.6.core文件调试

6.1 core文件

在程序崩溃时,一般会生成一个文件叫core文件。core文件记录的是程序崩溃时的内存映像,并加入调试信息,core文件生成过程叫做core dump(核心已转储)。系统默认不会生成该文件。

6.2 设置生成core文件

  • ulimit -c:查看core-dump状态。
  • ulimit -c xxxx:设置core文件的大小。
  • ulimit -c unlimited:core文件无限制大小。

6.3 gdb调试core文件

当设置完ulimit -c xxxx后,再次运行程序发生段错误,此时就会生成一个core文件,使用gdb core调试core文件,使用bt命令打印栈回溯信息。

-------------------------------感谢大家的支持------------------------------------

【文章福利】小编推荐自己的Linux内核技术交流群:【 865977150】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值 699的内核资料包(含视频教程、电子书、实战项目及代码)

[内核资料领取,](https://docs.qq.com/doc/DTmFTc29xUGdNSnZ2)   [Linux内核源码学习地址。](https://ke.qq.com/course/4032547?flowToken=1044435)

二、GDB常用命令

  • 以下以 test_file.c 作为源程序例子的名字,test_file.exe 作为可执行文件例子的名字, 以param_1 作为参数的例子的名字。
  • (gdb) 表示是在 gdb 调试模式下运行
  • 一般常用的方法有两种,即打断点调试单步调试
  • list(l): 列出源代码
  • quit(q): 退出 gdb 调试模式
  • 进入 gdb 之后,输入 help 可以查看所有命令的使用说明

2.1查看源码

list [函数名][行数]

2.2打断点调试

(1)设置断点:

  • a、break + [源代码行号][源代码函数名][内存地址]
  • b、break ... if condition ...可以是上述任一参数,condition是条件。例如在循环体中可以设置break ... if i = 100 来设置循环次数

删除断点

(gdb) clear location:参数 location 通常为某一行代码的行号或者某个具体的函数名。当 location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。

(gdb) delete [breakpoints] [num]:breakpoints 参数可有可无,num 参数为指定断点的编号,其可以是 delete 删除某一个断点,而非全部。

禁用断点

disable [breakpoints] [num...]:breakpoints 参数可有可无;num... 表示可以有多个参数,每个参数都为要禁用断点的编号。如果指定 num...,disable 命令会禁用指定编号的断点;反之若不设定 num...,则 disable 会禁用当前程序中所有的断点。

激活断点

  1. enable [breakpoints] [num...]激活用 num... 参数指定的多个断点,如果不设定 num...,表示激活所有禁用的断点
  2. enable [breakpoints] once num… 临时激活以 num... 为编号的多个断点,但断点只能使用 1 次,之后会自动回到禁用状态
  3. enable [breakpoints] count num... 临时激活以 num... 为编号的多个断点,断点可以使用 count 次,之后进入禁用状态
  4. enable [breakpoints] delete num… 激活 num.. 为编号的多个断点,但断点只能使用 1 次,之后会被永久删除。

break(b): 打的是普通断点,打断点有两种形式

(gdb) break location // b location,location 代表打断点的位置

(gdb) break ... if cond // b .. if cond,代表如果 cond 条件为true,则在 “...” 处打断点

通过借助 condition 命令为不同类型断点设置条件表达式,只有当条件表达式成立(值为 True)时,相应的断点才会触发从而使程序暂停运行。

tbreak: tbreak 命令可以看到是 break 命令的另一个版本,tbreak 和 break 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

rbreak: 和 break 和 tbreak 命令不同,rbreak 命令的作用对象是 C、C++ 程序中的函数,它会在指定函数的开头位置打断点。

  • (gdb) tbreak regex
  • regex 代表一个正则表达式,会在匹配到的函数的内部的开头位置打断点
  • tbreak 命令打的断点和 break 命令打断点的效果是一样的,会一直存在,不会自动消失。

watch: 此命令打的是观察断点,可以监控某个变量或者表达式的值。只有当被监控变量(表达式)的值发生改变,程序才会停止运行。

  • (gdb) watch cond
  • cond 代表的就是要监控的变量或者表达式

rwatch 命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;

awatch 命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。

catch: 捕捉断点的作用是,监控程序中某一事件的发生,例如程序发生某种异常时、某一动态库被加载时等等,一旦目标时间发生,则程序停止执行。

(2)观察断点:

  • a、watch + [变量][表达式] 当变量或表达式值改变时即停住程序。
  • b、rwatch + [变量][表达式] 当变量或表达式被读时,停住程序。
  • c、awatch + [变量][表达式] 当变量或表达式被读或被写时,停住程序。

(3)设置捕捉点:

catch + event 当event发生时,停住程序。

event可以是下面的内容:

  • a、throw 一个C++抛出的异常。(throw为关键字)
  • b、catch 一个C++捕捉到的异常。(catch为关键字)
  • c、exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)
  • d、fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)
  • e、vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)
  • f、load 或 load 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
  • g、unload 或 unload 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)

(4)捕获信号:

handle + [argu] + signals

signals:是Linux/Unix定义的信号,SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号; SIGKILL表示终止程序运行的信号,等等。

argu:

  • nostop 当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。
  • stop 当被调试的程序收到信号时,GDB会停住你的程序。
  • print 当被调试的程序收到信号时,GDB会显示出一条信息。
  • noprint 当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。
  • pass or noignore 当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。
  • nopass or ignore 当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。

(5)线程中断:

break [linespec] thread [threadno] [if ...]

linespec 断点设置所在的源代码的行号。如: test.c:12表示文件为test.c中的第12行设置一个断点。

threadno 线程的ID。是GDB分配的,通过输入info threads来查看正在运行中程序的线程信息。

if ... 设置中断条件。

查看信息:

(1)查看数据:

print variable 查看变量

print *array@len 查看数组(array是数组指针,len是需要数据长度)

可以通过添加参数来设置输出格式:

/ 按十六进制格式显示变量。
/d 按十进制格式显示变量。
/u 按十六进制格式显示无符号整型。
/o 按八进制格式显示变量。
/t 按二进制格式显示变量。 
/a 按十六进制格式显示变量。
/c 按字符格式显示变量。
/f 按浮点数格式显示变量。

(2)查看内存

examine /n f u + 内存地址(指针变量)

  • n 表示显示内存长度
  • f 表示输出格式(见上)
  • u 表示字节数制定(b 单字节;h 双字节;w 四字节;g 八字节;默认为四字节)
如:x /10cw pFilePath  (pFilePath为一个字符串指针,指针占4字节)
     x 为examine命令的简写。

(3)查看栈信息

backtrace [-n][n]

  • n 表示只打印栈顶上n层的栈信息。
  • -n 表示只打印栈底上n层的栈信息。
  • 不加参数,表示打印所有栈信息。

2.3单步调试

run(r)

continue(c)

next(n)

  • 命令格式: (gdb) next count:count 表示单步执行多少行代码,默认为 1 行
  • 其最大的特点是当遇到包含调用函数的语句时,无论函数内部包含多少行代码,next 指令都会一步执行完。也就是说,对于调用的函数来说,next 命令只会将其视作一行代码

step(s)

  • (gdb) step count:参数 count 表示一次执行的行数,默认为 1 行。
  • 通常情况下,step 命令和 next 命令的功能相同,都是单步执行程序。不同之处在于,当 step 命令所执行的代码行中包含函数时,会进入该函数内部,并在函数第一行代码处停止执行。

until(u)

  • (gdb) until:不带参数的 until 命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。注意,until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用;反之,until 命令和 next 命令的功能一样,只是单步执行程序

(gdb) until location:参数 location 为某一行代码的行号

查看变量的值

print(p)

  • p num_1:参数 num_1 用来代指要查看或者修改的目标变量或者表达式
  • 它的功能就是在 GDB 调试程序的过程中,输出或者修改指定变量或者表达式的值

isplay

  • (gdb) display expr
  • (gdb) display/fmt expr
  • expr 表示要查看的目标变量或表达式;参数 fmt 用于指定输出变量或表达式的格式

  • (gdb) undisplay num...
  • (gdb) delete display num...
  • 参数 num... 表示目标变量或表达式的编号,编号的个数可以是多个
  • (gdb) disable display num...
  • 禁用自动显示列表中处于激活状态下的变量或表达式
  • (gdb) enable display num...
  • 也可以激活当前处于禁用状态的变量或表达式
  • 和 print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值
  • 它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会

GDB handle 命令: 信号处理

→(gdb) handle signal mode其中,signal 参数表示要设定的目标信号,它通常为某个信号的全名(SIGINT)或者简称(去除‘SIG’后的部分,如 INT);如果要指定所有信号,可以用 all 表示。


mode 参数用于明确 GDB 处理该目标信息的方式,其值可以是如下几个:

  • ostop:当信号发生时,GDB 不会暂停程序,其可以继续执行,但会打印出一条提示信息,告诉我们信号已经发生;
  • stop:当信号发生时,GDB 会暂停程序执行。
  • noprint:当信号发生时,GDB 不会打印出任何提示信息;
  • print:当信号发生时,GDB 会打印出必要的提示信息;
  • nopass(或者 ignore):GDB 捕获目标信号的同时,不允许程序自行处理该信号;
  • pass(或者 noignore):GDB 调试在捕获目标信号的同时,也允许程序自动处理该信号。

可以在 gdb 模式下,通过 info signals 或者 info signals <signal_name> (例如 info signals SIGINT) 查看不同 signal 的信息。

GDB frame和backtrace命令:查看栈信息

(gdb) frame spec 该命令可以将 spec 参数指定的栈帧选定为当前栈帧。spec 参数的值,常用的指定方法有 3 种:

  1. 通过栈帧的编号指定。0 为当前被调用函数对应的栈帧号,最大编号的栈帧对应的函数通常就是 main() 主函数;
  2. 借助栈帧的地址指定。栈帧地址可以通过 info frame 命令(后续会讲)打印出的信息中看到;
  3. 通过函数的函数名指定。注意,如果是类似递归函数,其对应多个栈帧的话,通过此方法指定的是编号最小的那个栈帧。

(gdb) info frame 我们可以查看当前栈帧中存储的信息

该命令会依次打印出当前栈帧的如下信息:

  • 当前栈帧的编号,以及栈帧的地址;
  • 当前栈帧对应函数的存储地址,以及该函数被调用时的代码存储的地址
  • 当前函数的调用者,对应的栈帧的地址;
  • 编写此栈帧所用的编程语言;
  • 函数参数的存储地址以及值;
  • 函数中局部变量的存储地址;
  • 栈帧中存储的寄存器变量,例如指令寄存器(64位环境中用 rip 表示,32为环境中用 eip 表示)、堆栈基指针寄存器(64位环境用 rbp 表示,32位环境用 ebp 表示)等。

除此之外,还可以使用 info args 命令查看当前函数各个参数的值;使用 info locals 命令查看当前函数中各局部变量的值。

(gdb) backtrace [-full] [n] 用于打印当前调试环境中所有栈帧的信息

其中,用 [ ] 括起来的参数为可选项,它们的含义分别为:

  • n:一个整数值,当为正整数时,表示打印最里层的 n 个栈帧的信息;n 为负整数时,那么表示打印最外层 n 个栈帧的信息;
  • -full:打印栈帧信息的同时,打印出局部变量的值。

GDB编辑和搜索源码

GDB edit命令:编辑文件

  • (gdb) edit [location]
  • (gdb) edit [filename] : [location]
  • location 表示程序中的位置。这个命令表示激活文件的指定位置,然后进行编辑。
  • 如果遇到报错 "bash: /bin/ex: 没有那个文件或目录", 因为 GDB 的默认编辑器是 ex , 则需要指定编辑器,如 export EDITOR=/usr/bin/vim or export EDITOR=/usr/bin/vi

GDB search命令:搜索文件

  • search <regexp>
  • reverse-search <regexp>
  • 第一项命令格式表示从当前行的开始向前搜索,后一项表示从当前行开始向后搜索。其中 regexp 就是正则表达式,正则表达式描述了一种字符串匹配的模式,可以用来检查一个串中是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串。很多的编程语言都支持使用正则表达式。

三、GDB调试程序用法

一般来说,GDB主要帮忙你完成下面四个方面的功能:

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。

2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)

3、当程序被停住时,可以检查此时你的程序中所发生的事。

4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。

一个调试示例:

源程序:tst.c
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
21 }
22
23 printf("result[1-100] = %d /n", result );
24 printf("result[1-250] = %d /n", func(250) );
25 }

编译生成执行文件:(Linux下)

hchen/test> cc -g tst.c -o tst

使用GDB调试:

hchen/test> gdb tst <---------- 启动GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-SUSE-linux"...
(gdb) l <-------------------- l命令相当于list,从第一行开始例出原码。
1 #include <stdio.h>
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i<n; i++)
7 {
8 sum+=i;
9 }
10 return sum;
(gdb) <-------------------- 直接回车表示,重复上一次命令
11 }
12
13
14 main()
15 {
16 int i;
17 long result = 0;
18 for(i=1; i<=100; i++)
19 {
20 result += i;
(gdb) break 16 <-------------------- 设置断点,在源程序第16行处。
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func <-------------------- 设置断点,在函数func()入口处。
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break <-------------------- 查看断点信息。
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048496 in main at tst.c:16
2 breakpoint keep y 0x08048456 in func at tst.c:5
(gdb) r <--------------------- 运行程序,run命令简写
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17 <---------- 在断点处停住。
17 long result = 0;
(gdb) n <--------------------- 单条语句执行,next命令简写。
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) n
18 for(i=1; i<=100; i++)
(gdb) n
20 result += i;
(gdb) c <--------------------- 继续运行程序,continue命令简写。
Continuing.
result[1-100] = 5050 <----------程序输出。
Breakpoint 2, func (n=250) at tst.c:5
5 int sum=0,i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p i <--------------------- 打印变量i的值,print命令简写。
$1 = 134513808
(gdb) n
8 sum+=i;
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8 sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6 for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt <--------------------- 查看函数堆栈。
#0 func (n=250) at tst.c:5
#1 0x080484e4 in main () at tst.c:24
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish <--------------------- 退出函数。
Run till exit from #0 func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24 printf("result[1-250] = %d /n", func(250) );
Value returned is $6 = 31375
(gdb) c <--------------------- 继续运行。
Continuing.
result[1-250] = 31375 <----------程序输出。
Program exited with code 027. <--------程序退出,调试结束。
(gdb) q <--------------------- 退出gdb。
hchen/test>

好了,有了以上的感性认识,还是让我们来系统地认识一下gdb吧。

基本gdb命令:

GDB常用命令 格式  含义  简写
list  List [开始,结束]  列出文件的代码清单 l
prit  Print 变量名 打印变量内容  p
break Break [行号或函数名]  设置断点  b
continue  Continue [开始,结束]  继续运行  c
info  Info 变量名  列出信息  i
next  Next  下一行 n
step  Step  进入函数(步入)  S
display Display 变量名 显示参数   
file  File 文件名(可以是绝对路径和相对路径)  加载文件   
run Run args  运行程序  r
相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
2月前
|
NoSQL 编译器 Linux
gdb调试工具的使用方法
gdb调试工具的使用方法
33 1
|
2月前
|
NoSQL Linux 编译器
Linux:vim调试工具gdb | 常见命令集
Linux:vim调试工具gdb | 常见命令集
124 0
|
2月前
|
NoSQL openCL Linux
Linux调试工具—gdb
Linux调试工具—gdb
|
2月前
|
NoSQL Linux 开发工具
【linux】git和gdb调试工具
【linux】git和gdb调试工具
64 5
|
2月前
|
NoSQL Shell 程序员
【C/C++ 调试 GDB指南 】GDB调试工具介绍:从基础到高级
【C/C++ 调试 GDB指南 】GDB调试工具介绍:从基础到高级
127 0
|
2月前
|
NoSQL Linux
Linux下的系统编程——gdb调试工具(三)
Linux下的系统编程——gdb调试工具(三)
51 0
Linux下的系统编程——gdb调试工具(三)
|
2月前
|
机器学习/深度学习 存储 NoSQL
【Linux系统编程】代码调试工具gdb--2
【Linux系统编程】代码调试工具gdb--2
|
2月前
|
机器学习/深度学习 NoSQL Linux
【Linux系统编程】代码调试工具gdb--1
【Linux系统编程】代码调试工具gdb--1
|
7月前
|
NoSQL Linux 开发工具
LINUX入门篇【7】--git提交指令以及代码调试工具gdb
LINUX入门篇【7】--git提交指令以及代码调试工具gdb
73 1
|
2月前
|
存储 NoSQL Linux
Linux调试工具GDB(2)
Linux调试工具GDB(2)
41 0