GDB动态调试学习-1-【信息显示 函数】

文章目录

显示gdb版本信息

启动时不显示提示信息

gdb在启动时会显示如上类似的提示信息。

如果不想显示这个信息,则可以使用-q选项把提示信息关掉:

.bashrc

.bashrc是home目录下的一个shell文件,用于储存用户的个性化设置。在bash每次启动时都会加载.bashrc文件中的内容,并根据内容定制当前bash的配置和环境。

可以在~/.bashrc中,为gdb设置一个别名:

bash 复制代码
alias gdb="gdb -q"

关于~和/

~是主目录

/是根目录

此时运行gdb

列出函数的名字

参考链接

单步调试源码

n/s都是C语言级的断点定位。 s会进入C函数内部,但是不会进入没有调试信息的函数(比如没有加-g编译的代码,因为其没有C代码的行数标记,没办法定位,可以执行"set step-mode on"命令,这样gdb就不会跳过没有调试信息的函数,而是进入其汇编,接下来可以使用调试汇编程序的办法去调试函数。),n不会。

说白了就是要一行一行源码的执行

单步调试汇编

ni/si都是汇编级别的断点定位。si会进入汇编和C函数内部,ni不会。

说白了就是一行一行汇编代码的执行

si ni s n的归纳

归纳:当要进入没有调试信息的库函数调试的时候,用si是唯一的方法。

当进入有调试信息的函数,用si和s都可以,但是他们不同,si是定位到汇编级别的第一个语句,但是s是进入到C级别的第一个语句

退出正在调试的函数

参考链接

c 复制代码
#include <stdio.h>

int func(void)
{
    int i = 0;

    i += 2;
    i *= 10;

    return i;
}

int main(void)
{
    int a = 0;

    a = func();
    printf("%d\n", a);
    return 0;
}

当单步调试一个函数时,如果不想继续跟踪下去了,可以有两种方式退出。

第一种用"finish"命令,这样函数会继续执行完,然后达到返回地址的对应的指令位置

第二种用"return"命令,这样函数不会继续执行下面的语句,而是直接返回。也可以用"return expression"命令指定函数的返回值。仍以上面代码为例:

此时执行return,此时到返回地址的对应指令的寄存器信息和执行return时的一样

通常,所选的堆栈帧具有调试信息。当调试信息可用时,GDB将始终使用调试信息而不是隐式表达式类型。例如,如果你输入return -1,并且当前堆栈框架中的函数被声明为返回一个long long int, gdb会透明地将-1的隐式int值转换为一个long long int:
但是,如果选择的堆栈帧没有调试信息,例如,如果函数在没有调试信息的情况下编译,gdb必须找出要从用户返回的类型。错误地指定不同的类型可能会在不同的下级寄存器中设置值,而不是调用方代码所期望的值。例如,键入return -1和它的隐式类型int,对于调试信息较少的函数(在32位体系结构上),只会设置long long int结果的一部分。因此,用户需要通过适当的强制转换显式指定返回类型:

直接执行函数

call和print在执行函数上没有什么区别

c 复制代码
#include <stdio.h>

int global = 1;

int func(void) 
{
	return (++global);
}

int main(void)
{
	printf("%d\n", global);
	return 0;
}


打印函数堆栈帧信息

c 复制代码
#include <stdio.h>
int func(int a, int b)
{
	int c = a * b;
	printf("c is %d\n", c);
}

int main(void) 
{
	func(1, 2);
	return 0;
}

gdb 调试器为了方便用户在调试程序时查看某个栈帧中记录的信息,提供了 frame 和 backtrace 命令。

Linux下 gdb 调试中,常常会查看函数的堆栈帧信息。

bt(backtrace的缩写)命令:查看当前函数向上的堆栈的函数的堆栈信息。

i frame (info frame的缩写)命令:查看当前调试函数的堆栈帧信息。这种方式查看的堆栈信息比较详细。

输出了当前函数堆栈帧的地址,指令寄存器的值,局部变量地址及值等信息

打印尾调用堆栈帧信息

c 复制代码
#include<stdio.h>
void a(void)
{
        printf("Tail call frame\n");
}

void b(void)
{
        a();
}

void c(void)
{
        b();
}

int main(void)
{
        c();
        return 0;
}

当一个函数最后一条指令是调用另外一个函数时,开启优化选项的编译器常常以最后被调用的函数返回值作为调用者的返回值,这称之为"尾调用(Tail call)"。以上面程序为例,编译程序(使用'-O'):

可以看到main函数直接调用了函数a

可以设置"debug entry-values"选项为非0的值,这样除了输出正常的函数堆栈帧信息以外,还可以输出尾调用的相关信息:但会和与是否带-g参数编译有关

没有带-g编译

带-g编译

选择函数堆栈帧

c 复制代码
#include <stdio.h>

int func1(int a)
{
        return 2 * a;
}

int func2(int a)
{
        int c = 0;
        c = 2 * func1(a);
        return c;
}

int func3(int a)
{
        int c = 0;
        c = 2 * func2(a);
        return c;
}

int main(void)
{
        printf("%d\n", func3(10));
        return 0;
}

可以用"frame n"命令选择函数堆栈帧,其中n是层数。然后通过info frame会查看到选择的函数堆栈帧,或者直接frame也可以查看到当前选择的堆栈帧。显示信息格式不同而已

向上或向下切换函数堆栈帧

c 复制代码
#include <stdio.h>

int func1(int a)
{
        return 2 * a;
}

int func2(int a)
{
        int c = 0;
        c = 2 * func1(a);
        return c;
}

int func3(int a)
{
        int c = 0;
        c = 2 * func2(a);
        return c;
}

int main(void)
{
        printf("%d\n", func3(10));
        return 0;
}

可以用"up n"或"down n"命令向上或向下选择函数堆栈帧,其中n是层数。以上面程序为例:

up是将其编号+1,down是将编号-1

up-silently n"和"down-silently n"这两个命令,与"up n"和"down n"命令区别在于,切换堆栈帧后,不会打印信息,仍以上面程序为例:

相关推荐
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
sanguine__4 小时前
Web APIs学习 (操作DOM BOM)
学习
数据的世界017 小时前
.NET开发人员学习书籍推荐
学习·.net
四口鲸鱼爱吃盐7 小时前
CVPR2024 | 通过集成渐近正态分布学习实现强可迁移对抗攻击
学习
OopspoO9 小时前
qcow2镜像大小压缩
学习·性能优化
A懿轩A9 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
居居飒10 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
kkflash310 小时前
提升专业素养的实用指南
学习·职场和发展
1 9 J11 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
6.9412 小时前
Scala——身份证号码查询籍贯
学习·scala