C++(Qt)软件调试---gdb调试入门用法(12)

gdb调试—入门用法(1)

文章目录

  • gdb调试---入门用法(1)
    • 1、前言
      • 1.1 什么是GDB
      • 1.2 为什么要学习GDB
      • 1.3 主要内容
      • 1.4 GDB资料
    • 2、C/C++开发调试环境准备
    • 3、gdb启动调试
      • 1.1 启动调试并传入参数
      • 1.2 附加到进程
      • 1.3 过程执行
      • 1.4 退出调试
    • 4、gdb断点管理
      • 1.1 设置断点
      • 1.2 管理断点
    • 5、gdb的图形化界面功能
    • 6、gdb查看和修改变量
    • 7、gdb查看和修改内存的值
    • 8、查看修改寄存器
    • 9、gdb源代码查看、管理
    • 10、搜索源代码
    • 11、函数调用栈管理
    • 12、观察点
    • 13、gdb调试捕获点
    • 14、gdb生成core dump文件
    • 15、gdb调试core dump

更多精彩内容
👉个人内容分类汇总 👈
👉C++软件调试、异常定位 👈
👉GDB官方教程文档(英文) 👈
👉100个gdb小技巧 👈

1、前言

1.1 什么是GDB

GDB是GNU调试器的缩写,是一种用于调试程序的工具。

它可以帮助程序员在程序运行时检查程序的状态,查找程序中的错误和问题,并提供一些调试工具来帮助程序员更好地理解程序的行为。

GDB支持多种编程语言,包括C、C++、Go、Fortran和汇编语言等。

它可以在命令行界面或者图形界面下使用,并且可以在多种操作系统上运行,包括Linux、Unix、Windows等。

GDB的主要作用包括以下几个方面:

  1. 检查程序状态:GDB可以帮助程序员在程序运行时检查程序的状态,包括变量的值、函数的调用栈、程序的执行流程等。
  2. 查找程序错误和问题:GDB可以帮助程序员更快地找到程序中的错误和问题,提高程序的质量和稳定性。
  3. 设置断点:GDB可以设置断点,让程序在特定的位置停下来,以便程序员检查程序的状态。
  4. 提供调试工具:GDB还提供了一些调试工具,如单步执行、查看内存、查看寄存器等,帮助程序员更好地理解程序的行为。

总之,GDB是一种非常强大的调试工具,可以帮助程序员更快地找到程序中的错误和问题,提高程序的质量和稳定性。

1.2 为什么要学习GDB

学习GDB可以帮助程序员更好地调试程序,找到程序中的错误和问题,提高程序的质量和稳定性。

在开发大型软件时,程序中可能存在许多错误和问题,这些问题可能会导致程序崩溃或者出现不可预期的行为。

使用GDB可以帮助程序员更快地找到这些问题,并且提供一些调试工具来帮助程序员更好地理解程序的行为。

此外,学习GDB还可以提高程序员的调试能力,让他们更加熟练地使用调试工具,提高工作效率。

因此,学习GDB是非常有必要的。

1.3 主要内容

  1. linux C/C++开发调试环境准备;
  2. GDB调试基本功能介绍;
    • 调试执行;
    • 断点管理;
    • 线程管理;
    • 调用栈管理;
    • 查看修改变量;
    • 其它基本功能;
  3. 多线程死锁调试;
  4. 动态库调试;
  5. 内存检查
    • 内存泄漏;
    • 堆栈溢出;
    • 删除后继续使用;
  6. 远程调试;
  7. Core dump调试分析;
  8. 发行版调试。

1.4 GDB资料

GDB:GNU 工程调试器 (sourceware.org)

顶部(使用 GDB 调试) (sourceware.org)

2、C/C++开发调试环境准备

  • 在ubuntu中使用下 列命令安装C++开发调试环境

    sudo apt install g++ gcc make gdb
    

3、gdb启动调试

1.1 启动调试并传入参数

  • 测试代码

    #include<iostream>using namespace std;int func(int x)
    {int sum = 0;for(int i = 0; i < x; i++){sum += i;}return sum;
    }int main(int argc, char** argv)
    {for(int i = 1; i < argc; i++){cout << "传入参数:" << i <<" " << argv[i] << endl;}int a = 0;int x = 0;if(argc > 1){x = atoi(argv[1]);}a = func(x);cout << x << " " << a << endl;return 0;
    }
  • gdb --args <executable> <arguments>
    • 在启动 GDB 调试器时指定程序及其参数;
    • “gdb --args” 是 GNU Debugger (gdb) 命令的一部分,用于在调试程序时指定要调试的可执行文件和其参数
    • 使用此命令可以将可执行文件和参数作为一个整体传递给 gdb。
    • 其中,“” 是要调试的可执行文件的路径和名称,“” 是要传递给可执行文件的命令行参数,多个参数之间以空格分隔。
  • set args <args>
    • gdb --args类似,不过是在 GDB 内部执行的命令(gdb启动后),用于修改当前正在调试的程序的命令行参数。
    • 使用 gdb set args 可以多次修改参数,而使用 gdb --args 只能在启动时设置一次。
    • 如果要调试的程序中包含空格或其他特殊字符,则必须使用引号或转义字符来正确指定参数。
  • r <args>
    • r是run的缩写,run命令用于启动程序;
    • r 用于启动程序并传递命令行参数,类似于set args + run。

在这里插入图片描述

  • 命令中的-q是用于关闭启动时的提示信息。

1.2 附加到进程

  • 什么是附加到进程调试

    附加到进程调试是一种调试技术,它允许开发人员在程序运行时观察和分析程序的内部状态。

    通常,在调试过程中,开发人员会在代码中设置断点,以便在程序执行到特定位置时停止并检查其状态。但是,有时候问题可能只在程序运行的特定环境中出现,或者只在特定条件下才能复现。这时,附加到进程调试就非常有用了。

    附加到进程调试的过程通常包括以下几个步骤:

    1. 打开调试器:首先,开发人员需要打开一个调试器,例如Visual Studio、GDB或LLDB等。调试器是一个用于观察和控制程序执行的工具。
    2. 选择进程:开发人员需要选择要附加调试的进程。这可以是正在运行的本地程序,也可以是远程计算机上的程序。
    3. 设置断点:开发人员可以在代码中设置断点,以便在程序执行到特定位置时停止。断点可以设置在函数调用、条件语句、循环等位置。
    4. 开始调试:一旦选择了进程并设置了断点,开发人员就可以开始调试了。调试器会监视程序的执行,并在断点处停止程序。
    5. 观察和分析:当程序停止在断点处时,开发人员可以观察和分析程序的内部状态,例如变量的值、函数的调用堆栈等。这有助于理解程序的行为和找出问题所在。
    6. 继续执行:在观察和分析完程序的内部状态后,开发人员可以选择继续执行程序,直到下一个断点或程序结束。

    附加到进程调试是一种强大的调试技术,可以帮助开发人员快速定位和解决程序中的问题。它在软件开发和故障排除过程中非常常见和重要。

  • 下面三条命令的主要区别在于语法的不同,但它们的功能是相同的。你可以使用gdb的各种命令来控制调试过程,例如"break"设置断点,"run"开始执行程序,"next"单步执行等等。

  • 请注意,附加到正在运行的进程可能会对其产生一些影响,因此请谨慎使用。此外,附加到进程可能需要root权限或者对进程的所有者具有适当的权限。

  • 是想要附加的进程的进程ID。附加成功后,gdb将会连接到该进程,并允许你使用gdb的调试功能来检查进程的状态、设置断点、单步执行等操作。

    • gdb attach <PID>
    • gdb --pid=<PID>
    • gdb -p <PID>
  • 测试代码

    #include <iostream>int main() 
    {int num;std::cout << "请输入一个整数:";std::cin >> num;int a;a = num + 1;int b;b = num * 10;std::cout << a <<" " << b << std::endl;std::cout << "您输入的整数是:" << num << std::endl;return 0;
    }
  • 演示如下

    1. 使用命令g++ test2.cpp -g编译代码,加上-g生成包含调试详细的可执行程序;
    2. 运行可执行程序;
    3. 使用命令cat -n test2.cpp 查看源代码;
    4. 使用命令ps -aux | grep a.out查看名称为a.out的进程的pid号;
    5. 进程的pid号;
    6. 使用命令 sudo gdb -q -p 9834将gdb附加到pid号为9834的进程进行调试,需要使用超级用户权限;
    7. 使用命令b test2.cpp:8在test2.cpp文件的第8行打一个断点;
    8. 继续执行gdb,c命令是continue的缩写,用于继续执行程序直到下一个断点或程序结束;
    9. 单步执行gdb,n命令是next的缩写,用于执行下一行代码。当程序被暂停在某个断点处时,可以使用n命令来执行下一行代码,而不会进入函数调用。这个命令通常用于逐行执行程序,以便观察程序的执行流程。

    在这里插入图片描述

1.3 过程执行

  • 常用过程执行命令

    • start:启动程序并暂停main函数的第一行,让程序在调试器中开始执行,而不是直接运行。
    • next(简写为n):执行下一行代码,并将控制权移动到下一行,遇见函数调用会跳过,如果调用的函数中有断点则会进入。
      • n:简写形式,执行下一行代码。
      • next:执行下一行代码。
      • next n:执行下n行代码。
      • nexti:执行下一条机器指令。
      • nexti n:执行下n条机器指令。
    • step [count](简写为s):执行下一行代码,并将控制权移动到下一行。如果当前行是函数调用,会进入该函数并在第一行暂停。
      • 其中,count是一个可选参数,表示要执行的行数。如果不指定count,则默认为1,即执行一行。
    • finish:执行完当前函数的剩余代码,并将控制权返回到调用该函数的地方
    • continue(简写为c):继续执行程序,直到遇到下一个断点或程序结束
  • 测试代码

    #include<iostream>using namespace std;int sumFun(int size)
    {int sum = 0;for(int i = 0; i < size; i++){sum += i;}return sum;
    }int main()
    {int size = 10;int sum = 0;sum = sumFun(size);cout << "计算从0到" << size <<" 的和为:" << endl;cout << sum << endl;size = 100;sum = sumFun(size);cout << "计算从0到" << size <<" 的和为:" << endl;cout << sum << endl;return 0;
    }
    
  • 演示

    在这里插入图片描述

1.4 退出调试

  • 退出调试方式
    • quit:缩写q这是最常用的退出命令,它会立即终止gdb会话并退出到终端。
    • Ctrl + D:这是一个快捷键组合,按下Ctrl和D键后,gdb会话会立即终止并退出到终端。
    • detach:用于将gdb与正在调试的程序分离,使得程序可以在后台继续运行,而不受gdb的控制。这在某些情况下非常有用,比如当你想让程序在调试过程中继续执行一段时间,而不需要gdb的干预。

4、gdb断点管理

  • 测试代码

    #include <iostream>using namespace std;int fun1()
    {int a = 10;int b = 20;throw a;return b;
    }int fun2(int a)
    {int b = 0;b = a + 10;return b;
    }
    int main()
    {cout <<"调用函数2" << endl;int a = 10;cout << fun2(a) << endl;cout << "调用函数1" << endl;try{fun1();}catch(...){cout <<"出现异常" << endl;}return 0;
    }
    

1.1 设置断点

  • 设置断点命令

    1. break:设置断点,缩写为b
      • 行号断点:使用break命令加上源代码的行号可以在指定行上设置断点。例如,break 10会在第10行设置一个断点;
      • 函数断点:使用break命令加上函数名可以在指定函数入口处设置断点。例如,break myFunction会在myFunction函数的入口处设置一个断点,如果是类或者命名空间则需要加上作用域;
      • 条件断点:使用break命令加上条件可以在满足条件时设置断点。例如,break myFunction if i == 10会在myFunction函数的入口处设置一个断点,但只有当变量i的值等于10时才会触发断点;
      • 内存地址断点:使用break命令加上内存地址可以在指定内存地址处设置断点。例如,break *0x12345678会在内存地址0x12345678处设置一个断点,当调试汇编程序,或者没有调试信息的程序时,经常需要在程序地址上打断点,可以使用disassemble命令查看程序的反汇编后的地址;
      • 指令断点:使用break命令加上指令地址可以在指定指令处设置断点。例如,break *0x12345678会在指令地址0x12345678处设置一个断点;
    2. tbreak:命令用于设置临时断点,缩写为tb。与break命令不同,临时断点只会在程序执行到该断点时触发一次,然后自动被删除。您可以使用tbreak命令后跟函数或行号来设置临时断点。
    3. rbreak:设置正则表达式断点,缩写为rb
      • 语法rbreak [regexp],其中,regexp是一个正则表达式,用于匹配要设置断点的函数名。rbreak命令会在所有可执行文件中搜索匹配的函数名,并在每个匹配的函数入口处设置断点;
      • 设置所有函数名以"foo"开头的断点: rbreak ^foo
      • 设置所有函数名以"bar"结尾的断点: rbreak bar$
      • 设置所有函数名中包含"baz"的断点: rbreak baz
    4. catch:catch命令用于设置异常断点。
      • 异常断点会在程序抛出异常时触发。您可以使用catch命令后跟异常类型来设置异常断点;
      • 语法catch [exception] [command]
      • exception:是要捕获的异常类型,可以是以下几种:
        • throw:捕获由C++程序中的throw语句引发的异常。
        • catch:捕获由C++程序中的catch语句处理的异常。
        • exec:捕获由被调试程序中的exec调用引发的异常。
        • fork:捕获由被调试程序中的fork调用引发的异常。
        • vfork:捕获由被调试程序中的vfork调用引发的异常。
        • syscall:捕获由被调试程序中的系统调用引发的异常。
      • command:是在捕获到异常时要执行的命令。如果省略command,则gdb会在捕获到异常时停止程序的执行并显示相关信息。
    5. trace:用于设置跟踪点。
      • 跟踪点是一种特殊的断点,它可以在程序执行到指定的函数或行号时触发,并显示函数的参数和返回值。
      • 跟踪点可以帮助开发人员更详细地了解程序的执行过程,以便更好地调试和分析代码。
  • 演示

    在这里插入图片描述

1.2 管理断点

  • gdb断点管理常用命令

    1. delete:删除断点。会从断点列表中删除指定的断点,但不会清除程序中的断点位置。如果再次运行程序,断点仍然会被触发。

      • 缩写为d

      • 删除所有断点:使用delete命令后不加任何参数,即可删除所有已设置的断点。

      • 删除指定编号的断点:每个断点都有一个唯一的编号,可以使用delete命令后加上断点编号来删除指定的断点。例如delete 1

      • 删除所有在指定函数中设置的断点:可以使用delete命令后加上函数名来删除所有在该函数中设置的断点。例如 delete function_name

      • 删除所有在指定文件中设置的断点:可以使用delete命令后加上文件名来删除所有在该文件中设置的断点。例如:delete file_name

      • 删除所有在指定行号处设置的断点:可以使用delete命令后加上行号来删除所有在该行号处设置的断点。例如delete line_number

      • 需要注意的是,删除断点时需要确保当前正在调试的程序处于暂停状态,否则删除操作可能无效。可以使用info breakpoints命令来查看当前已设置的断点,并获取它们的编号以及其他相关信息。

    2. clear:清除断点。会从程序中清除指定的断点位置,这意味着即使再次运行程序,断点也不会被触发。

      • 清除所有断点:使用clear命令后不跟任何参数,可以清除所有已设置的断点。
      • 清除指定行号的断点:使用clear命令后跟上要清除断点的源文件名行号,可以清除指定行号的断点。例如,clear main.cpp:10可以清除main.cp文件中第10行的断点。
      • 清除指定函数的断点:使用clear命令后跟上要清除断点的函数名,可以清除指定函数的断点。例如clear my_function可以清除名为my_function的函数的断点。
      • 清除指定源文件的断点:使用clear命令后跟上要清除断点的源文件名,可以清除指定源文件的所有断点。例如,clear main.cpp可以清除main.cp文件中的所有断点。
    3. disable:禁用断点、观察点或线程。

      • 语法:disable [breakpoint|watchpoint|thread] <编号>

        • breakpoint表示断点;
        • watchpoint表示观察点;
        • thread表示线程;
        • <编号>是要禁用的断点、观察点或线程的编号。
      • 可以使用disable命令后跟断点号来禁用特定的断点,例如disable 1

    4. enable:用于启用断点。

      • 可以使用enable命令后跟断点号来启用特定的断点,例如enable 1
    5. info breakpoints:显示当前设置的所有断点。

      • 缩写为i b
      • 使用info breakpoints命令可以查看当前设置的所有断点的详细信息,包括断点号、断点类型、断点位置等。
  • 演示

    在这里插入图片描述

5、gdb的图形化界面功能

gdb中的tui是指Text User Interface,它是gdb的一个可选功能,用于在终端中以图形化的方式显示源代码、汇编代码和调试信息。

tui提供了一个类似于文本编辑器的界面,可以在调试过程中更方便地查看和操作代码。

使用tui可以在终端中同时显示源代码和调试信息,以及当前执行的代码行。

它可以帮助开发人员更直观地理解代码的执行流程,快速定位问题。

启动tui功能的方式:

  1. 启动gdb时使用命令gdb -tui 可执行程序
  2. 在gdb命令行中输入命令tui enable
  3. 在gdb命令行中使用快捷键Ctrl x a

关闭tui功能的方式:在gdb命令行中输入命令tui disable

启用tui后,可以使用以下命令来操作:

  • layout src:显示源代码窗口。
  • layout asm:显示汇编代码窗口。
  • layout regs:显示寄存器窗口。
  • layout split:将源代码窗口和汇编代码窗口分割显示。
  • layout next:切换到下一个布局。
  • layout prev:切换到上一个布局。
  • focus next:将焦点切换到下一个窗口。
  • focus prev:将焦点切换到上一个窗口。
  • 使用gdb图形化调试界面时,可以使用“winheight <win_name> [+ | -]count”命令调整窗口大小(winheight缩写为winwin_name可以是srccmdasmregs)。
    • 例如:win src -5

此外,还可以使用其他gdb命令来设置断点、单步执行代码等。

需要注意的是,gdb的tui功能在不同的终端和操作系统上可能会有一些差异,具体的使用方法和快捷键可能会有所不同。可以通过在gdb命令行中输入help tui来获取更详细的帮助信息。

  • 演示:使用命令打的断点在tui窗口中可以实时看见。

    在这里插入图片描述

6、gdb查看和修改变量

  • 测试代码

    #include<iostream>using namespace std;int g_a = 10;
    char g_b = 'a';int func(int x)
    {int sum = 0;for(int i = 0; i < x; i++){sum += i;}return sum;
    }struct Test{int a = 10;char b = 'c';double c = 123.321;
    };int main(int argc, char** argv)
    {for(int i = 1; i < argc; i++){cout << "传入参数:" << i <<" " << argv[i] << endl;}int a = 0;int x = 0;char str[] = "hello";if(argc > 1){x = atoi(argv[1]);}a = func(x);cout << x << " " << a << endl;Test t;cout << "结构体" << endl;return 0;
    }
  • 常用命令

    1. info locals:显示当前栈帧的局部变量的值。
    2. info args:gdb将会显示出当前函数的参数列表及其对应的值。这些参数包括函数的形参名称以及实际传递给函数的值。
    3. info variables:这个命令将显示当前作用域中所有变量的列表,包括全局变量。
    4. print variable_name:这个命令将显示指定变量的值。(缩写为p)
    5. set print null-stop:设置字符串的显示规则,显示字符串时遇见\0就停止输出;
    6. set print pretty:显示结构体,结构体换行输出;
    7. set print array on:显示数组;
    8. p 变量名=value:修改变量值为value;
    9. set var 变量名=value:修改变量值为value;
    10. set main::str = "hello":修改字符串的值,需要注意内存越界;
  • 演示

    在这里插入图片描述

7、gdb查看和修改内存的值

  • 测试代码

    #include <iostream>using namespace std;int main()
    {int a = 10;char c = 'a';return 0;
    }
  • 查看内存

  • x/[格式 长度] 地址

  • 格式字母有:

    • o(八进制)
    • x(十六进制)
    • d(十进制)
    • u(无符号十进制)
    • t(二进制)
    • f(浮点)
    • a(地址)
    • i(指令)
    • c(字符)
    • s(字符串)
    • z(十六进制,左边加零)。
  • 大小字母有

    • b:以字节为单位显示数据。
    • h:以半字(2字节)为单位显示数据。
    • w:以字(4字节)为单位显示数据。
    • g:以双字(8字节)为单位显示数据。
  • 设置内存

    • set {type}address=value
    • address:存储地址;
    • type:变量类型;
    • value:需要设置的值。
  • 演示

    在这里插入图片描述

8、查看修改寄存器

  • 测试代码

    #include <iostream>using namespace std;int fun(const char* name, int age)
    {cout << name <<" " << age << endl;return 0;
    }int main()
    {fun("hello", 123);return 0;
    }
  • 使用命令

    • info registers:用于显示当前正在被调试程序的寄存器状态。它会列出各个寄存器的名称和当前的值。
    • info r rdi:查看单个寄存器rdi;
  • 函数参数的寄存器

    寄存器函数参数
    rdi第一个参数
    rsi第二个参数
    rdx第三个参数
    rcx第四个参数
    r8第五个参数
    r9第六个参数
  • 演示:没有调试符号时可以通过查看寄存器来进行调试。

    在这里插入图片描述

  • 修改寄存器命令

  • set var $pc=value:修改pc寄存器,pc寄存器是一种用于存储即将被执行的指令地址的寄存器。它通常用于计算机的中央处理器(CPU)中,在执行程序时起到指示下一条要执行的指令的作用。

  • 演示

    • 使用b fun在fun函数打一个断点;
    • 使用r命令运行程序,停在断点处;
    • 使用info line 8命令查看第8行代码的地址;
    • 使用set var &pc=0x5555555551e3将pc寄存器执行的下一条指令修改为第8行代码;
    • 使用n命令单步执行,程序直接跳转到第8行,跳过了int a = 10这一行代码。

    在这里插入图片描述

9、gdb源代码查看、管理

  • 测试代码

    • main.cpp

      /********************************************************************************
      * 文件名:   main.cpp
      * 创建时间: 2023-07-26 20:14:04
      * 开发者:   MHF
      * 邮箱:     1603291350@qq.com
      * 功能:     
      *********************************************************************************/
      #include<iostream>
      #include "test.h"using namespace std;int main()
      {int a = 10;int b = 20;int sum = 0;test t;t.setValue(a, b);sum = t.getSum();cout << sum << endl;return 0;
      }
      
    • test.h

      #pragma oneclass test
      {
      private:int m_a = 0;int m_b = 0;public:test(/* args */);~test();void setValue(int a, int b);int getSum();
      };
    • test.cpp

      #include "test.h"test::test(/* args */)
      {
      }test::~test()
      {
      }void test::setValue(int a, int b)
      {m_a = a;m_b = b;
      }int test::getSum()
      {return m_a + m_b;
      }
      
  • 使用命令

    • list:缩写为l,它用于显示源代码,并帮助程序员在调试过程中理解代码的执行流程。
    • 语法:list [function] [start-line [end-line]]
      • function(可选):指定要显示源代码的函数名或方法名。如果不指定,则显示当前默认的函数或方法的源代码。
      • start-line(可选):指定要从哪一行开始显示源代码。如果不指定,则默认从当前上下文中的下一行开始显示。
      • end-line(可选):指定要到哪一行结束显示源代码。如果不指定,则默认显示从起始行开始的十行代码。
    • 使用示例
      • list:显示当前函数或方法的源代码,默认从下一行开始,显示十行代码。
      • list main:显示名为"main"的函数的源代码,默认从下一行开始,显示十行代码。
      • list main 10:显示名为"main"的函数的源代码,从第10行开始,显示十行代码。
      • list main.cpp:15:显示指定文件的指定行代码。
      • list file:fun:显示指定文件中的指定函数代码;
      • list class:fun:显示指定类的成员函数代码。
    • set listsize xx:设置每次显示的代码行数。
  • 演示

    在这里插入图片描述

10、搜索源代码

  • 使用命令
    • search str:在当前文件中查找包含str字符串的行;
    • forward-search str:向后查找;
    • reverse-search str:向前查找。

11、函数调用栈管理

  • 测试代码

    #include <iostream>using namespace std;void fun1()
    {int a = 10;int* b = nullptr;*b = a;
    }void fun2()
    {char c = 'a';cout << c << endl;fun1();
    }int main()
    {fun2();return 0;
    }
  • 使用命令

    1. backtrace命令:显示当前的函数调用栈。可以在程序崩溃或中止时使用,用来追踪函数调用链以确定程序执行到哪里。缩写为bt
    2. updown命令:在当前函数调用链中向上或向下切换。
      • up : 切换到调用当前函数的函数
      • down:切换回当前函数
      • up n :向上选择函数堆栈帧,其中n是层数
      • down n:切向下选择函数堆栈帧,其中n是层数
    3. frame命令:切换到指定的栈帧(Stack Frame)。
      • 先使用backtrace查看栈帧列表
      • 在使用frame 2 切换到第3个栈帧
    4. info frame命令:显示当前栈帧的详细信息,包括函数调用点、参数、局部变量等。
      • info frame :查看当前栈帧信息
      • info frame 3 :查看id为3的栈帧信息
  • 演示

    在这里插入图片描述

12、观察点

  • watch: watch 命令允许您监视一个变量或一个表达式的值,并在其值发生更改时暂停程序的执行。您可以使用 watch 命令来跟踪特定变量的变化,以便在发生错误或特定事件时检查它们的值。

    • watch a
    • watch a == 10:观察点可以带有条件。条件可以使观察点仅在满足特定条件时触发。例如,要在变量x的值为10时触发观察点;
    • watch a thread 1:指定只有线程1写变量a时触发;
  • rwatch:rwatch 命令也是用于监视变量或表达式的值,但它只在读取(而不是写入)该值时触发断点。这对于跟踪对某个变量的读取很有用,以确认某些代码段是否访问了它。

  • awatch: awatch 命令可用于监视变量或表达式的读取写入操作。当变量或表达式的值发生变化时,程序将在读取或写入操作上暂停执行。

  • info watch:查看观察点;

  • delete:删除观察点;

  • disable:禁用观察点;

  • enable:弃用观察点;

  • 测试代码

    #include <iostream>using namespace std;int main()
    {int a = 10;char c = 'a';return 0;
    }
  • 演示

    在这里插入图片描述

13、gdb调试捕获点

  • 捕获点是一个特殊的断点,命令语法为:catch event

  • 即捕获到event这个事件的时候,程序就会中断下类;

  • 支持的捕获事件有:(可以在gdb中使用help catch命令查看)

    事件说明
    catch assertCatch在引发时失败的Ada断言。
    catch catch当程序捕获异常时触发捕获点。可以用来跟踪异常的捕获过程。
    catch exceptionCatch Ada异常,当引发时。
    catch exec捕获对exec的调用。
    catch fork捕获对fork的调用。
    catch handlers处理时捕获Ada异常。
    catch load捕获共享库的负载。
    catch rethrow重新引发时捕获异常。
    catch signal通过信号的名称和/或编号捕捉信号。
    catch syscall通过系统调用的名称、组和/或号码捕获系统调用。
    catch throw抛出时捕获异常
    catch unload捕获共享库的卸载。
    catch vfork捕获对vfork的调用。
  • 测试代码

    #include<iostream>using namespace std;void fun()
    {int a = 1;cout << a << endl;throw a;
    }int main()
    {try{fun();}catch(int a){cout << "捕获:" << a << endl;}
    }
  • 演示

    在这里插入图片描述

14、gdb生成core dump文件

  • 测试代码

  • 使用命令

    • generate-core-file:gcore 类似,generate-core-file 命令也用于在 gdb 中生成核心转储文件,可以单独使用命令,也可以在generate-core-file后跟文件路径文件名称。
    • gcore:在正在运行的进程中,使用 gcore 命令可以生成一个称为核心转储文件(core dump)的文件。这个核心转储文件包含了进程在崩溃时的内存状态、寄存器信息等,有助于开发人员分析程序崩溃的原因。
  • 使用示例

    在这里插入图片描述

15、gdb调试core dump

  • 测试代码

  • 方法1:使用gdb 可执行程序 core文件命令加载调试core dump;

  • 方法2:使用gdb 可执行程序命令进入gdb后,使用core core文件名命令指定core文件,进行调试;

  • 演示

    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49609.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机竞赛 卷积神经网络手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

mysql------做主从复制,读写分离

1.为什么要做主从复制&#xff08;主从复制的作用&#xff09; 做数据的热备&#xff0c;作为后备数据库&#xff0c;主数据库服务器故障后&#xff0c;可切换到从数据库继续工作&#xff0c;避免数据丢失。 架构的扩展。业务量越来越大,I/O访问频率过高&#xff0c;单机无法满…

shell和Python 两种方法分别画 iostat的监控图

在服务器存储的测试中,经常需要看performance的性能曲线&#xff0c;这样最能直接观察HDD或者SSD的性能曲线。 如下这是一个针对HDD跑Fio读写的iostat监控log,下面介绍一下分别用shell 和Python3 写画iostat图的方法 1 shell脚本 环境:linux OS gnuplot工具 第一步 :解析iosta…

DETR-《End-to-End Object Detection with Transformers》论文精读笔记

DETR&#xff08;基于Transformer架构的目标检测方法开山之作&#xff09; End-to-End Object Detection with Transformers 参考&#xff1a;跟着李沐学AI-DETR 论文精读【论文精读】 摘要 在摘要部分作者&#xff0c;主要说明了如下几点&#xff1a; DETR是一个端到端&am…

测试工具coverage的高阶使用

在文章Python之单元测试使用的一点心得中&#xff0c;笔者介绍了自己在使用Python测试工具coverge的一点心得&#xff0c;包括&#xff1a; 使用coverage模块计算代码测试覆盖率使用coverage api计算代码测试覆盖率coverage配置文件的使用coverage badge的生成 本文在此基础上…

【Android】设置-显示-屏保-启用时机-去除插入基座相关(不支持该功能的话)

设置-显示-屏保-启用时机-去除插入基座相关&#xff08;不支持该功能的话&#xff09; 1-项目场景&#xff1a;2-问题描述3-解决方案&#xff1a;4-代码修改前后效果对比图&#xff1a;代码修改前&#xff1a;代码修改后&#xff1a; 1-项目场景&#xff1a; 展锐平台 2-问题描…

ctfshow-web12

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 国际惯例看一下返回包&#xff0c;是不是有注释 然后做一下测试&#xff0c;看是命令执行还是代码执行 通过phpinfo看到可以执行代码 然后尝试执行命令&#xff0c;无法&#xff0c;发现存在disable_function…

基于nginx禁用访问ip

一、背景 网络安全防护时&#xff0c;禁用部分访问ip,基于nginx可快速简单实现禁用。 二、操作 1、创建 conf.d文件夹 在nginx conf 目录下创建conf.d文件夹 Nginx 扩展配置文件一般在conf.d mkdir conf.d 2、新建blocksip.conf文件 在conf.d目录新建禁用ip的扩展配置文…

从头到尾说一次 Spring 事务管理(器) | 京东云技术团队

事务管理&#xff0c;一个被说烂的也被看烂的话题&#xff0c;还是八股文中的基础股之一。​ 本文会从设计角度&#xff0c;一步步的剖析 Spring 事务管理的设计思路&#xff08;都会设计事务管理器了&#xff0c;还能玩不转&#xff1f;&#xff09; 为什么需要事务管理&…

C++基础Ⅰ编译、链接

目录儿 1 C是如何工作的1.1 预处理语句1.2 include1.3 main()1.4 编译单独编译项目编译 1.5 链接 2 定义和调用函数3 编译器如何工作3.1 编译3.1.1 引入头文件系统头文件自定义头文件 3.1.2 自定义类型3.1.3 条件判断拓展: 汇编 3.2 链接3.2.1 起始函数3.2.2 被调用的函数 3.3 …

无人机精细化巡检方案制定:提高效率与准确性的关键

在当前技术日新月异的时代&#xff0c;无人机在多个领域的应用已成为行业标配。但如何制定出一套有效、细致的无人机巡检方案&#xff0c;确保其最大效能&#xff0c;成为许多组织与公司的核心议题。其中&#xff0c;复亚智能在此领域已展现出了卓越的实力与深入的见解。 1. 精…

把matlab的m文件打包成单独的可执行文件

安装Matlab Compiler Adds-on在app里找到Application Compiler 选择要打包的文件matlab单独的运行程序的话需要把依赖的库做成runtime. 这里有两个选项. 上面那个是需要对方在联网的情况下安装, 安装包较小.下面那个是直接把runtime打包成安装程序, 大概由你的程序依赖的库的多…

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型&#xff0c;以及景区的类目&#xff0c;从而可以吸引更多的人来体验。 1、市场调研&#xff1a;在决定建设VR游乐场项目之前&#xff0c;需要进行市场调研&#xff0c;了解当地…

DNQ算法原理(Deep Q Network)

1.强化学习概念 学习系统没有像很多其它形式的机器学习方法一样被告知应该做出什么行为 必须在尝试了之后才能发现哪些行为会导致奖励的最大化 当前的行为可能不仅仅会影响即时奖励&#xff0c;还会影响下一步的奖励以及后续的所有奖励 每一个动作(action)都能影响代理将来的…

linux 上安装es

首先 到官网 https://www.elastic.co/cn/downloads/elasticsearch 下载对应的安装包&#xff0c;我这里下载的是 https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.9.1-linux-x86_64.tar.gz 然后讲该压缩包上传到 linux 的/usr/local 目录下执行 tar -z…

Just KNIME it[S2C21] 图像识别

朋友们&#xff0c;Just KNIME it 还有在跟进吗? 本季已经到 21 期啦。 本期探讨的主题是图像识别问题&#xff0c;快随指北君一起看看吧。 挑战 21&#xff1a;帮助球童&#xff08;第 1 部分&#xff09; 级别&#xff1a;中 描述&#xff1a;球童汤姆是一位最受欢迎的高尔夫…

Ansible学习笔记(一)

1.什么是Ansible 官方网站&#xff1a;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html Ansible是一个配置管理和配置工具&#xff0c;类似于Chef&#xff0c;Puppet或Salt。这是一款很简单也很容易入门的部署工具&#xff0c;它使用SS…

Linux解决RocketMQ中NameServer启动问题

启动步骤可以查看官网&#xff0c;https://github.com/apache/rocketmq 一下说明遇到的问题。 1&#xff1a;ROCKETMQ_HOME问题 根据官网提示进入mq/bin目录下&#xff0c;可以使用./mqnamesrv进行NameServer启动&#xff0c;但是会遇到第一个问题&#xff0c;首次下载Rocket…

机器学习---常见的距离公式(欧氏距离、曼哈顿距离、标准化欧式距离、余弦距离、杰卡德距离、马氏距离、切比雪夫距离、闵可夫斯基距离、K-L散度)

1. 欧氏距离 欧几里得度量&#xff08;euclidean metric&#xff09;&#xff08;也称欧氏距离&#xff09;是一个通常采用的距离定义&#xff0c;指在m维空 间中两个点之间的真实距离&#xff0c;或者向量的自然长度&#xff08;即该点到原点的距离&#xff09;。在二维和三维…

一文读懂数据云的「对象体系」

确切地说&#xff0c;有6个域、32个对象 啥是「对象」&#xff1f; 在计算机科学的定义中 对象&#xff08;Object&#xff09;是面向对象编程的基本单位 是一种将数据和操作封装在一起的实体 它具有「属性」和「行为」 可以与其他对象进行交互和通信 对象最突出的特征 莫…