一、GDB
GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划(同时诞生的还有 GCC、Emacs 等),是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 经常用来调试 C 和 C++ 程序。
基本调试命令:
[参考:](GDB使用详解 - 知乎 (zhihu.com))
语法
gdb(选项)(参数)
选项
-cd:设置工作目录;
-q:安静模式,不打印介绍信息和版本信息;
-d:添加文件查找路径;
-x:从指定文件中执行GDB指令;
-s:设置读取的符号表文件。
常用命令
命令名称 |
命令缩写 |
命令说明 |
run |
r |
运行一个待调试的程序 |
continue |
c |
让暂停的程序继续运行 |
next |
n |
运行到下一行 |
step |
s |
单步执行,遇到函数会进入 |
until |
u |
运行到指定行停下来 |
finish |
fi |
结束当前调用函数,回到上一层调用函数处 |
return |
return |
结束当前调用函数并返回指定值,到上一层函数调用处 |
jump |
j |
将当前程序执行流跳转到指定行或地址 |
print |
p |
打印变量或寄存器值 |
backtrace |
bt |
查看当前线程的调用堆栈 |
frame |
f |
切换到当前调用线程的指定堆栈 |
thread |
thread |
切换到指定线程 |
break |
b |
添加断点 |
tbreak |
tb |
添加临时断点 |
delete |
d |
删除断点 |
enable |
enable |
启用某个断点 |
disable |
disable |
禁用某个断点 |
watch |
watch |
监视某一个变量或内存地址的值是否发生变化 |
list |
l |
显示源码 |
info |
i |
查看断点 / 线程等信息 |
ptype |
ptype |
查看变量类型 |
disassemble |
dis |
查看汇编代码 |
set args |
set args |
设置程序启动命令行参数 |
show args |
show args |
查看设置的命令行参数 |
为什么没有产生core 文件?
解决方法 :
1.打开core开关
ulimit -c unlimited
ulimit -a
core file size (blocks, -c) 0 ##core文件的最大值
data seg size (kbytes, -d) unlimited ##进程的数据段大小
scheduling priority (-e) 0 ##限制进程优先级
file size (blocks, -f) unlimited ##文件大小
pending signals (-i) 31638 ##最多有多少个待处理的信号
max locked memory (kbytes, -l) 64 ##一个任务锁住的物理内存的最大值为多少
max memory size (kbytes, -m) unlimited##个任务锁住的物理内存的最大值
open files (-n) 1024 ##一个任务最多可以同时打开多少个文件
pipe size (512 bytes, -p) 8 ##管道的最大空间为多少字节
POSIX message queues (bytes, -q) 819200##POSIX的消息队列的最大值
real-time priority (-r) 0 ##限制程序实时优先级的范围
stack size (kbytes, -s) 8192 ##进程的栈的最大值
cpu time (seconds, -t) unlimited ##进程使用的CPU时间
max user processes (-u) 31638 ##当前用户同时打开的进程(包括线程)的最大个数
virtual memory (kbytes, -v) unlimited ##限制进程的最大地址空间
file locks (-x) unlimited ##所能锁住的文件的最大个数
2.core文件的生成位置和名字
echo "./core-%e-%p-%t" > /proc/sys/kernel/core_pattern
3.编译选项
编译程序的时候还需要为gcc/g++添加-g选项,如果使用-g3选项可以进行宏的调试
参考:https://blog.csdn.net/jiemashizhen/article/details/125016646
一、GDB
1.test
2.常用命令
gdb常用命令:
run: 运行程序
break: 打断点
bt: 查看调用堆栈
print: 打印信息
next: 单步调试
list: 打印代码
step: 进入函数
continue:继续运行到下一断点
quit: 退出
set logging file gdb_test.txt
set logging on
把gdb的日志保存下来
info locals: 打印局部变量
info arg: 打印传入的参数
info break : 打印所有断点
shell (命令): 执行shell命令
3.使用core:
gdb (二进制文件)(core文件)
gdb xxx core
二、代码检查
代码检查可以有效的提高代码质量,更进一步的说代码检查可以更好的提高代码质量
未使用的变量,类型不一致,使用未定义变量,无法执行的代码,忽略返回值,执行路径未返回,无限循环等错误
1.splint
安装splint:
sudo apt install splint
2.valgrind
常见错误
1.访问不应该访问的内存,如使用超过 malloc分配的内存空间、溢出堆栈顶部、以及使用已经释放的内存(Accessing memory you shouldn’t)。
2.使用未初始化的内存 (Use of uninitialisedmemory)。
3.堆内存释放不正确,如重复 free、申请和释放内存函数malloc/free/new/delete 不匹配(Incorrect freeing of heap memory)。
4.内存泄漏 (Memory leaks – where pointers tomalloc’d blocks are lost forever)。
5.将可疑(可能为负)值传递给内存分配函数的大小参数(Passing afishy (presumably negative) value to the size parameter of a memory allocationfunction)。
6.src 和 dst 的重叠(Overlapping src and dstpointers in memcpy() and related functions)。
安装valgrind:
sudo apt install valgrind
命令格式
valgrind[valgrind-options] [your-program] [your-program-options]
valgrind-options:
Memcheck 是重量级内存检测工具。
Cachegrind 检查程序中缓存使用出现的问题。
Callgrind 检查程序中函数调用过程中出现的问题。
Helgrind 检测多线程中的数据竞争问题。
DRD也用于分析多线程。与Helgrind类似,但是用不同的分析技术,所以可以检测不同的问题。
Massif,检查程序中堆栈使用中出现的问题。
DHAT 是一种不同类型的堆分析器。它可以帮助您了解块生命周期、块利用率和布局效率低下的问题。BBV
是一个实验性的 SimPoint 基本块向量生成器。 它对从事计算机体系结构研究和开发的人很有用
test1
编译可执行文件时 需要加上-g选项
gcc -g check.c -o check
valgrind --tool=memcheck--leak-check=full ./check
“definitelylost”:确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
“indirectlylost”:间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与"definitelylost"一起出现,只要修复"definitely lost"即可。例子可参考我的例程。
“possiblylost”:可能丢失。大多数情况下应视为与"definitelylost"一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址),然后通过运算得到这块内存起始地址,再释放它。例子可参考我的例程。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存的起始地址,但可以访问其中的某一部分数据,则会报这个错误。
“stillreachable”:可以访问,未丢失但也未释放。如果程序是正常结束的,那么它可能不会造成程序崩溃,但长时间运行有可能耗尽系统资源,因此笔者建议修复它。如果程序是崩溃(如访问非法的地址而崩溃)而非正常结束的,则应当暂时忽略它,先修复导致程序崩溃的错误,然后重新检测。
“suppressed”:已被解决。出现了内存泄露但系统自动处理了。可以无视这类错误。这类错误我没能用例程触发,看官方的解释也不太清楚是操作系统处理的还是valgrind,也没有遇到过。所以无视他吧~
test2 编译一个多种内存使用错误的小程序,用动态代码检查工具输出详细日志
参考:
https://blog.csdn.net/Sxy_wspsby/article/details/127042016
https://blog.csdn.net/erlang_hell/article/details/51360149
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// 1.对空指针进行解引用操作
int *p = NULL;
*p=5;
// 2.对动态开辟内存空间进行了越界访问
p = (int *)malloc(10);
*(p+11)=10;
// 3.对非动态开辟内存使用free释放
int a = 10;
int *p1 = &a;
free(p1);
// 4.使用free释放动态开辟内存的一部分
p1 = p;
p1++;
free(p);
// 5.对同一块动态开辟内存进行多次释放
free(p);
free(p);
// 6.动态开辟的内存空间忘记释放(内存泄漏)
return 0;
}
makefile
all:
gcc -g -o test test.c
valgrind --log-file=./valgrind_report.log --leak-check=full --show-leak-kinds=all --show-reachable=no --track-origins=yes ./test