gdb调试详解

一、gdb调试简介及常用命令

  gdb是linux下非常好用的一个调试工具,虽然它是命令行模式的调试工具,但是它的功能强大到你无法想象,这里简单介绍下gdb下常用的命令。

1、编译代码并启动gdb

gcc -g test.cpp -o test 
//-g选项告诉gcc在编译程序时加入调试信息
//没有这个选项就会报错:No symbol table is loaded. Use the "file" command
gdb -q test //启动gdb,加上-q选项屏蔽掉版本等无用信息

2、调试选项

(1)查看源码(l)

list 5,10   //显示第5行到第10行的代码;

list func   //显示func函数周围的代码,显示范围和list参数有关;

list test.c:5,10  //显示源文件test.c第5行到第10行的代码,一般用于调试含多个源文件的程序。

(2)设置断点(b)

break 14     // 在当前文件的第 14 行设置断点

break shell_sort.cpp:12 // 在其它文件指定行设置断点

b print   // 在函数 print() 处设置断点

info break  // 查看断点信息

break 7 if n==6 // 条件断点

(3)运行程序(r)

 run     // 开始执行程序

(4)执行下一句代码(n)

next    // 继续执行下一条语句,只执行一条。

(5)执行多句代码(c)

continue  // 让程序继续运行,直到下个断点或者结束

(6)打印变量的值(p)

print i   // 用print命令打印出i的值

(7)自动打印变量的值(display)

display i // 自动打印i的值

(8)退出gdb(q)

quit     // 退出gdb调试

二、gdb调试core dump文件

1、core dump是什么

  其实就是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。最常见的就是段错误,然后程序直接挂掉

2、常见 core dump 错误

  • 无效指针:对空指针进行了操作;对未初始化的指针进行了操作;使用一个已经释放内存过的指针再次delete 重复释放,(所以说释放后要置空,置空就不会报错);多线程访问全局变量,导致内存值异常而程序核心转存。

  • 指针越界:检查赋值语句,检查定位到错误上下变量的值,可以结合注释来定位;内存变量值异常,检查定位行,代码走读排查函数调用是使用否有问题。

  • 操作系统特殊性:字节对齐方式引起的程序核心转储;引用模块与自身模块所定义的结构体的字节对齐方式不同。

3、gdb调试过程

(1)查看系统是否有对 core 文件的限制(ulimit -a)

  如果有大小限制,则修改为无限制(ulimit -c unlimited):
在这里插入图片描述
在这里插入图片描述

(2)编译生成core文件(g++ -g -o main main.cpp)

在这里插入图片描述
在这里插入图片描述

(3)调试core文件(gdb main core)

在这里插入图片描述
在这里插入图片描述

三、gdb调试多线程

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

void* pthread_run1(void* arg)
{
    (void)arg;

    while(1)
    {
        printf("I am thread1,ID: %d\n",pthread_self());
        sleep(1);
    }
}

void* pthread_run2(void* arg)
{
    (void)arg;

    while(1)
    {
        printf("I am thread2,ID: %d\n",pthread_self());
        sleep(1);
    }
}


int main()
{

    pthread_t tid1;
    pthread_t tid2;

    pthread_create(&tid1,NULL,pthread_run1,NULL);
    pthread_create(&tid2,NULL,pthread_run2,NULL);

    printf("I am main thread\n");

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    return 0;
}

1、查看进程和线程信息

//查看当前运行的进程
ps aux|grep a.out
//查看当前运行的轻量级进程
ps -aL|grep a.out
//查看主线程和新线程的关系
pstree -p 主线程id

在这里插入图片描述

2、线程栈结构的查看(pstack)

在这里插入图片描述

3、利用gdb查看线程信息

(1)将进程附加到gdb调试器当中,查看是否创建了新线程(gdb attach 主线程ID)

在这里插入图片描述

ptrace 不允许操作解决方法:

sudo gedit /etc/sysctl.d/10-ptrace.conf

kernel.yama.ptrace_scope = 0

reboot

(2)查看线程的一些信息

//1.查看进程:info inferiors
//2.查看线程:info threads
//3.查看线程栈结构:bt
//4.切换线程:thread n(n代表第几个线程)

在这里插入图片描述

4、利用gdb调试多线程

(1)设置断点

设置断点:break 行号/函数名
查看断点:info b

在这里插入图片描述

(2)执行线程2的函数,指行完毕继续运行到断点处

继续使某一线程运行:thread apply 1-n(第几个线程) n
重新启动程序运行到断点处:r

在这里插入图片描述

(3)只运行当前线程

设置:set scheduler-locking on
运行:n

在这里插入图片描述

(4)所有线程并发执行

设置:set scheduler-locking off
运行:n

在这里插入图片描述

5、总结调试多线程的命令

在这里插入图片描述

参考:https://blog.csdn.net/a1414345/article/details/74311741
https://blog.csdn.net/zhangye3017/article/details/80382496

猜你喜欢

转载自blog.csdn.net/daaikuaichuan/article/details/89791255