gdb
简述
- gdb是gcc的调试工具,它主要由c和c++编写的应用程序
- 功能十分强大
- 启动程序,可按用户自定义要求随心所欲运行程序
- 可以让被调试的程序在指定端点停住
- 当程序被停住时,可以检查此时程序中运行状态
- 动态的改变程序的运行环境
- 要调试C/C++程序,需要在编译时将调试信息加入到可执行文件中,使用编译器的-g参数可完成
- 启动gdb的方法
- gdb program
- program是执行文件,一般在当前目录下
- gdb program core
- 用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件
- gdb program 1234
- 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID,gdb会自动进行attach操作,并调试这个程序
- gdb program
常见用法
- 示例代码
//test.cpp
#include<iostream>
using namespace std;
int fun(int n)
{
int res = 0;
for(int i=1;i<=n;i++)
res+=i;
return res;
}
int main()
{
int arr[10];
arr[0]=0;
arr[1]=1;
for(int i=2;i<10;i++)
{
arr[i]=arr[i-1]+arr[i-2];
}
cout<<"arr[9]"<<arr[9]<<endl;
cout<<"fun(9)"<<fun(9)<<endl;
return 0;
}
- 使用如下命令进行编译程序
g++ -g -o test test.cpp
- 使用gdb调试程序
gdb test
- 参数使用帮助
- l,列出函数代码及其行数
- b 16,在代码16处设置断点
- b fun,在函数fun处设置断点
- info break,查看断点信息
- r,运行程序
- n,单条执行语句
- p i,打印i变量的值
- bt,查看函数的堆栈
- finish,退出函数
- q,结束调试
-
使用gdb分析coredump文件
- core又称为coredump文件,是Unix/Linux操作系统的一种机制,对于线上服务来说,出core的过程意味着服务暂时不能响应,需要恢复,并且随着Core进程的内存空间越大,此过程可能持续很长一段时间
- 凡事皆有两面性,操作系统在coredump时,虽然会终止当前进程,但是也会保留下第一手的现场数据,操作系统仿佛是一架按下快门的相机,照片就是生成的coredump
- coredump文件包含当进程被终止时内存、CPU寄存器和各种函数调用堆栈信息等,以供后序开发人员调试
- coredump存储路径
- 执行命令可以看到core文件存在位置
- coredump产生条件
- coredump产生原因
-
gdb定位coredump文件
- 示例代码
- 使用命令编译代码并执行
strace
strace是一种调试工具,可以用来跟踪程序系统调用,在Ubuntu下可以通过命令apt install strace安装
- 也可以用来跟踪信号调用,且可统计系统调用。
示例
实例程序:
#include<iostream>
using namespace std;
int main()
{
cout<<"Hello World!"<<endl;
return 0;
}
使用如下命令追踪系统调用
g++ test.cpp -o teststrace ./test
运行结果图
结果分析
- 每一行都是一次系统调用,等号左边是系统调用的函数名和参数,右边是该调用的返回值
- 从上面结果图,系统首先调用execve,创建一个新的进程,接着是一些环境初始化,然后在最后倒数第4行,调用write函数将字符串输出到屏幕,最后调用exit_group退出进程
使用strace做信号追踪
- strace在运行程序时,如果程序被传递了任何信号是可以监视到的
- 统计系统调用
- 通过使用 -c 参数,可以将进程的所有系统调用做一个统计分析并显示
- 通过使用 -c 参数,可以将进程的所有系统调用做一个统计分析并显示
SystemTap
SystemTap基于kprobe的实现,可监控内核和用户程序。
示例:
监控运行中程序指定函数的调用参数值。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void print(char *p){
printf("%s.\n", p);
}
void* test_fn(void* arg){
while(1){
print("hello");
sleep(5);
}
return ((void *)0);
}
int main(int argc, char **argv){
pthread+t id;
int ret;
ret = pthread_create(&id, NULL, test_fn, NULL);
if(ret != 0){
printf("create! \n");
exit(1);
}
printf("int main process.\n");
pthread_join(id, NULL);
return 0;
}
以上程序没5秒会调用一次print,我想知道print的输入参数是什么,那么编写SystemTap脚本:
function myprint: string (val)
%{
char *str = (char *) STAP_ARG_val;
snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%s", str);
%}
probe process(3266).function("print") {printf("%s\n", myprint($p));}
stap -g test.stp
这样就可以获得监控的结果了,因为用到了内嵌C来获取字符串的值,所以就需要加上-g参数。
DTrace
Dtrace可以监控用户态的程序。