当前位置:   article > 正文

C/C++程序调试_c++调试

c++调试

一、源码debug

C语言的debug有两种形式,一种是源码debug,一种是可执行代码debug

源码形式的debug,可以使用printf()打印出程序中间过程的一些关键信息,比如某些变量

可执行文件的debug,需要使用调试器(gdb)来进行追踪

源代码的debug类似于下面的形式,在程序中添加printf打印关键变量,通过打印信息,来定位bug出现的位置,然后再修改源码

#include <stdio.h>
void f() {;}
int main()
{
#ifdef _DEBUG
	printf("start main functoin!\n")
#endif
    void f();
#ifdef _DEBUG
    printf("leave main function!\n");
#endif
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

除了添加打印信息之外,还可以使用开发工具自带的调试进行单步调试,这个根据实际使用的开发工具自行google

二、二进制debug

1、gdb调试过程

linux平台使用gdb进行程序调试,用一个列子来演示一下如何使用gdb调试二进制代码

xu@xu:~$ cat test.c 
#include <stdio.h>
void FunTest()
{
    int *p = NULL;
    *p = 1;
}
int main()
{
    FunTest();
    return 0;
}
xu@xu:~$ gcc -g test.c -o test			# 编译,并加-g参数打开gdb调试
xu@xu:~$ ./test 
段错误 (核心已转储)
xu@xu:~$
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面这个程序能生成二进制,代表已经通过了编译阶段,可是为什么最后编译之后生成的二进制还是不能跑呢?只提示了个段错误。这就要使用gdb进行调试了,看一下问题究竟出现在哪里

下面进行gdb调试,首先需要用ulimit命令查看一下core文件允许生成的最大值,然后使用ulimit -c更改一下如下,改完后,再次运行二进制,发现已经可以生成core文件

xu@xu:~$ ulimit -a
core file size          (blocks, -c) 0					# 默认这个数值是0,也就是不生成core文件
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 60650
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 60650
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

xu@xu:~$ ulimit -c 10240	# 可以把这个数值设置大些,10240代表10240k,如果实际情况超过了这个限制就不能生成了
# core文件大小即为程序运行时占用的内存大小,可能发生堆栈溢出的时候,会占用更大的内存
xu@xu:~$ echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern		# 更改一下生成的默认路径和core文件名格式
xu@xu:~$ ulimit -a
core file size          (blocks, -c) 10240
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

上面这些操作做好之后,就能再次运行test二进制了,可以在/tmp目录下看到有core文件生成

xu@xu:~/test$ gcc -g test.c -o test
xu@xu:~/test$ ./test 
段错误 (核心已转储)
xu@xu:~/test$ ls /tmp | grep core
core.1640590166
  • 1
  • 2
  • 3
  • 4
  • 5

程序中FunTest函数对NULL进行了引用,这会导致程序崩溃,下面使用gdb调试看一下,看一下是不是能找到程序出问题的位置

xu@xu:/tmp$ file core.1640590166 
core.1640590166: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './test', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './test', platform: 'x86_64'
# 可以看到该core文件来自test这个二进制
xu@xu:/tmp$ gdb ~/test/test core.1640590166 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/xu/test/test...
[New LWP 27051]
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000564c0b94c13d in FunTest () at test.c:5
5	    *p = 1;					# 显示除了错误所在行数,并且改行代码内容也进行了显示
(gdb) 

# 然后按q退出调试
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
2、gdb基本命令

启动程序:run
设置断点:b 行号|函数名
删除断点:delete 断点编号
禁用断点:disable 断点编号
启用断点:enable 断点编号
单步跟踪:next (简写 n)
单步跟踪:step (简写 s)
打印变量:print 变量名字 (简写p)
设置变量:set var=value
查看变量类型:ptype var
顺序执行到结束:cont
顺序执行到某一行: util lineno
打印堆栈信息:bt

三、补充core文件的配置

查看core文件默认保存路径cat /proc/sys/kernel/core_pattern/sbin/sysctl kernel.core_pattern

使用/sbin/sysctl命令查看的内容实际上还是/proc/sys/kernel/下的core_pattern这个文件内容,修改core文件核心转储文件目录和命名规则也是改这个文件

可以用这个方式改echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern,产生的core文件名为core-命令名-pid-时间戳,且存放于/tmp下

一下是相关的参数解释

%p - insert pid into filename 添加 pid

%u - insert current uid into filename 添加当前 uid

%g - insert current gid into filename 添加当前 gid

%s - insert signal that caused the coredump into the filename 添加导致产生 core 的信号

%t - insert UNIX time that the coredump occurred into filename 添加 core 文件生成时的 unix 时间

%h - insert hostname where the coredump happened into filename 添加主机名

%e - insert coredumping executable name into filename 添加命令名

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/620897
推荐阅读
相关标签
  

闽ICP备14008679号