GDB用法(一)

预备

测试代码

main.cpp
c++ 复制代码
#include <iostream>
#include <vector>
#include "student.h"

using namespace std;

int add(int a, int b)
{
    return a + b;
}

int main()
{
    vector<int> v = {1, 3};
    
    Student* s1 = new Student("zz", 20);
    Student* s2 = new Student("aa", 23);
    Student* s3 = new Student("bb", 26);

    int sum = add(s1->GetAge(), s2->GetAge());
    
    // 显示Student信息
    cout << s1->ToString() << endl;
    cout << s2->ToString() << endl;
    cout << s3->ToString() << endl;

    delete s1;
    delete s2;
    delete s3;

    return 0;
}
Functions/student.h
c++ 复制代码
#ifndef _STUDENT_H_
#define _STUDENT_H_

#include <vector>
#include <string>

class Student
{
private:
    std::string m_name;
    int m_age;
    
public:
    Student(std::string name, int age);
    
    int GetAge() const;
    std::string GetName() const;
    std::string ToString() const;
};

#endif
Functions/student.cpp
c++ 复制代码
#include "student.h"

Student::Student(std::string name, int age): m_name(name), m_age(age)
{

}

int Student::GetAge() const
{
    return m_age;
}

std::string Student::GetName() const
{
    return m_name;
}

std::string Student::ToString() const
{
    return "学生姓名: " + m_name + "学生年纪: " + std::to_string(m_age);
}
CMakeLists.txt
cmake 复制代码
cmake_minimum_required(VERSION 3.10)

project(main)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall")

INCLUDE_DIRECTORIES(./)
INCLUDE_DIRECTORIES(./Functions)

AUX_SOURCE_DIRECTORY(./ MAIN)
AUX_SOURCE_DIRECTORY(./Functions FUNCTION)

add_executable(main ${MAIN} ${FUNCTION})

(gdb) 启动

gdb 可执行文件

后面带可执行文件, gdb会把可执行文件的符号表加载到gdb中

(break/b) 设置断点

break 函数名

break 行号

断点是源程序中行号, 注意编译选项不要优化代码, 不然行号和优化后的代码对应不上

break 文件名: 行号

break 文件名:函数名

break + 偏移量

break - 偏移量

在运行时, 进入断点后, 使用偏移量, 对断点行号加/减多少行

break *地址

(info break/i b) 展示所有设置的断点

(run/r) 运行

run 参数

run后面可以带参数, 也就是给运行程序加参

修改main.cpp

c++ 复制代码
#include <iostream>
#include <vector>
#include "student.h"

using namespace std;

int add(int a, int b)
{
    return a + b;
}

int main(int argc,char *argv[])
{
    cout << "参数个数:" << argc << endl;
    for(int i = 0; i < argc; i++)
    {
        cout << "参数[" << i << "]:" << argv[i] << endl;
    }
    
    vector<int> v = {1, 3};
    
    Student* s1 = new Student("zz", 20);
    Student* s2 = new Student("aa", 23);
    Student* s3 = new Student("bb", 26);

    int sum = add(s1->GetAge(), s2->GetAge());
    
    // 显示Student信息
    cout << s1->ToString() << endl;
    cout << s2->ToString() << endl;
    cout << s3->ToString() << endl;

    delete s1;
    delete s2;
    delete s3;

    return 0;
}

(backtrace/bt) 显示栈帧

bt // 显示所有栈帧

bt N //显示开头N个栈帧

bt -N // 显示最后N个栈帧
bt full // 不仅显示栈帧, 还显示局部变量

bt full N

bt full -N

(print/p) 显示变量

p /格式 变量

格式 说明
x 显示为十六进制数
d 显示为十进制数
u 显示为无符号十进制数
o 显示为八进制数
t 显示为二进制数, t的由来是two
a 地址
c 显示为字符(ASCII)
f 浮点小数
s 显示为字符串
i 显示为机器语言(仅在显示内存的x命令中可用)

(info registers/info reg) 显示寄存器

寄存器名前面加$, 可现实各个寄存器的内容

(x) 显示内存的内容

x/NFU ADDR

// ADDR为希望显示的地址

// N为重复次数

// F为前面显示变量中的格式(x, d, u, o, t, a, c, f, s, i)

// U为单位

U代表单位 说明
b 字节
h 半字(2字节)
w 字(4字节/默认值)
g 双字(8字节)

x/i 为显示汇编指令

从rip所指地址开始的10条指令(i)

(dissassemble/disas) 反汇编

dissassemble [FUNCTION] // 反汇编当前函数

dissassemble 开始地址 结束地址 // 反汇编从开始地址到结束地址之前的部分

(next/n) 单步执行, 不会进入函数内部执行

n 行数

(nexti/ni) 汇编指令的单步执行

需要设置set disassemble-next-line on, 让gdb打印出下一条要执行的汇编代码

(step/s) 单步执行, 会进入函数内部执行

s 行数

(stepi/si) 汇编指令的单步执行

(continue/c) 继续执行

c 次数

后面加次数是指定次数忽略断点, c 5则5次遇到断点不停止, 第6次遇到断点时才暂停执行

跳过了参数0, 参数1,参数2, 3次断点, 第4次断点时暂停执行

(watch) 监视点

// 软件观察点

watch [options] <表达式> // 表达式发生变化时暂停运行

// 这里的表达式是指常量或变量

选项(options) 表达式
-l/-location 指定只在被监视表达式的特定位置暂停程序的执行,能够避免多线程环境下的停顿问题
-r/-read 可以指定只在被监视表达式被读取时停止程序的执行
-w/-write 只在被监视表达式被修改时停止程序的执行
-c 在被监视变量被修改的时候,停止后继续执行的次数。如果指定了count,则每次监视到变量修改时计数器减1,当计数器为0时,程序会停止执行
-s 可以指定watch只在指定变量或表达式的值满足某个条件时停止程序的执行

// 硬件观察点

awatch <表达式> // 表达式被访问, 改变时暂停运行

rwatch <表达式> // 表达式被访问时暂停运行

设置监视点会降低速度

(delete/d) 删除断点和监视点

delete 编号

(set variable) 改变变量的值

set variable <变量> = <表达式>

可以在运行时随意修改变量的值

(generate-core-file) 生成内核转储文件

generate-core-file

生成在当前目录下

(gcore) linux工具生成内核转储文件

gcore -o 保存路径 pid

修改main.cpp

c++ 复制代码
#include <iostream>
#include <vector>
#include "student.h"

using namespace std;

int add(int a, int b)
{
    return a + b;
}

int main(int argc,char *argv[])
{
    std::cout << "程序开始" << std::endl;
    while(true)
    {
        // cout << "参数个数:" << argc << endl;
        // for(int i = 0; i < argc; i++)
        // {
        //     cout << "参数[" << i << "]:" << argv[i] << endl;
        // }
        
        vector<int> v = {1, 3};
        
        Student* s1 = new Student("zz", 20);
        Student* s2 = new Student("aa", 23);
        Student* s3 = new Student("bb", 26);

        int sum = add(s1->GetAge(), s2->GetAge());
        
        // 显示Student信息
        // cout << s1->ToString() << endl;
        // cout << s2->ToString() << endl;
        // cout << s3->ToString() << endl;

        delete s1;
        delete s2;
        delete s3;
    }
  

    return 0;
}

从命令行直接生成内核转储文件

这里的路径需要是存在的

也可以 脚本每个多久生成一次core文件

相关推荐
怀澈1221 小时前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
chnming19871 小时前
STL关联式容器之set
开发语言·c++
威桑1 小时前
MinGW 与 MSVC 的区别与联系及相关特性分析
c++·mingw·msvc
熬夜学编程的小王2 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins2 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
Mr.132 小时前
什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
开发语言·c++
阿史大杯茶2 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
C++忠实粉丝2 小时前
计算机网络socket编程(3)_UDP网络编程实现简单聊天室
linux·网络·c++·网络协议·计算机网络·udp
我们的五年2 小时前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
程序猿阿伟3 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链