gdb中使用python脚本

news2024/12/28 23:42:31

1、入门案例

首先有1个a.cpp,代码如下:

#include <map>
#include <set>
#include <iostream>
#include <string>

using namespace std;

struct MyStruct {
    std::string mName;
    std::map<int, std::string> mField1;
    std::set<std::string> mField2;
    int mI;
    int mJ;
};

int main() {
    std::map<int,string> lm;
    std::set<std::string> ls;
    MyStruct s = {std::string("student"), lm, ls, 3, 4};
    return 0;
}

上面的C代码中有一个结构体MyStruct,如果想要打印结构体的内容。在GDB 9.X版本中打印出来是这样

$1 = {mName = "student", mField1 = std::map with 0 elements, mField2 = std::set with 0 elements, mI = 3, mJ = 4}

如果使用的是GDB 7.X,打印出来就是这样

$1 = {mName = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffffffe380 "student"},
    _M_string_length = 7, {_M_local_buf = "student\000\000\000\000\000\000\000\000", _M_allocated_capacity = 32772479054607475}}, mField1 = {_M_t = {
      _M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<No data fields>}, <No data fields>}, <std::_Rb_tree_key_compare<std::less<int> >> = {
          _M_key_compare = {<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>}}, <std::_Rb_tree_header> = {_M_header = {_M_color = std::_S_red, _M_parent = 0x0, _M_left = 0x7fffffffe398,
            _M_right = 0x7fffffffe398}, _M_node_count = 0}, <No data fields>}}}, mField2 = {_M_t = {
      _M_impl = {<std::allocator<std::_Rb_tree_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>}, <std::_Rb_tree_key_compare<std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
          _M_key_compare = {<std::binary_function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool>> = {<No data fields>}, <No data fields>}}, <std::_Rb_tree_header> = {_M_header = {_M_color = std::_S_red, _M_parent = 0x0, _M_left = 0x7fffffffe3c8, _M_right = 0x7fffffffe3c8}, _M_node_count = 0}, <No data fields>}}},
  mI = 3, mJ = 4}

可以看到在GDB 9.X中打印出来的要美观很多,主要是由于GDB 9.x自带了一系列标准库的Python Pretty Printer(美观打印器)。如果想要查看原始的数据,可以使用 p /r s命令。

当然我们也可以实现字节的美观打印器。主要需要完成下面几个功能:

(1)自定义打印类,提供to_string()方法,该方法返回希望打印出来的字符串。

(2)创建判断函数,判断一个值是否需要使用自定义的打印类来打印。

(3)将判断函数注册到GDB美观打印函数中。

下面直接看完整的代码,t.py

class MyPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        return "name: {} integer: {}".format(self.val['mName'], self.val['mI'])

def lookup_pretty_printer(val):
    if val.type.code == gdb.TYPE_CODE_PTR:
        return None
    if 'MyStruct' == val.type.tag:
        return MyPrinter(val)
    return None
gdb.printing.register_pretty_printer(gdb.current_objfile(),lookup_pretty_printer,replace=True)

简单解释下上面的python代码。

1、定义了一个名为 MyPrinter 的类,它有一个构造函数,接收一个 val 参数。参数就是p s中的s, to_string 方法定义了如何将 MyStruct 对象转换为字符串,例子中包含 mNamemI 字段的值。

2、lookup_pretty_printer 这个函数用来决定是否使用 MyPrinter 来打印某个值。如果传入的 val 是指针类型,则直接返回 None,表明不需要特别处理。如果 val 的类型标签是 MyStruct,则返回一个新的 MyPrinter 实例,否则也返回 None

3、最后一行,gdb.printing 是 GDB 的一个 Python 接口模块,它提供了一系列与 pretty printing 相关的功能。Pretty printing 是一种用于美化或格式化输出的技术,尤其是在处理复杂数据结构时,能够使输出更加清晰易读。gdb.printing 模块提供了以下功能:

  • 注册 pretty printers

  • 管理 pretty printer 集合

  • 提供查找 pretty printer 的方法

    gdb.printing.register_pretty_printergdb.printing 模块中的一个函数,用于注册一个 pretty printer。当 GDB 在打印某个变量或表达式时,它会调用已注册的 pretty printer 来美化输出。这个函数允许用户为特定类型的数据结构定制输出格式,使得输出更加直观和有用。

    三个参数分别表示:

    • objfile: gdb.ObjfileNone,表示要为其注册 pretty printer 的目标文件。如果是 None,则表示注册的 pretty printer 对所有目标文件有效。
    • pretty_printer: 函数,接受一个 gdb.Value 对象并返回一个 pretty printer 对象或 None。这个函数负责决定是否使用自定义的 pretty printer。
    • replace: 布尔值,默认为 False,表示是否替换现有的 pretty printer。如果为 True,则新注册的 pretty printer 会覆盖先前为相同类型注册的所有 pretty printer。

使用步骤:

  • 使用g++ -g a.cpp -o a将代码编译成可调试的可执行程序。

  • 将上面的t.py和上面编译出来的a放到同一目录。

  • 使用gdb a使用调试状态执行a

  • 在gdb命令行加载t.py,使用source t.py

  • 添加断点b 22,在a.cpp第22行添加断点。

  • 使用r命令运行程序,会在代码22行的位置停下来;使用p s打印变量s的值,就能看到打印格式就是我们t.pyMyPrinter.to_string指定的输出格式。

    在这里插入图片描述

2、在GDB窗口定义python脚本

除了可以上面的在外部定义python脚本,也可以直接在gdb调试窗口中定义函数。

步骤如下:

  • 在gdb 窗口输入python进入python脚本编辑模式

  • 输入python脚本内容,完成后输入end退回到gdb模式下

  • 使用python前缀调用python脚本中的内容

    (gdb) python
    >def my_function(arg):
    >    print(f"Argument received: {arg}")
    >end
    (gdb) python my_function(100)
    Argument received: 100
    
    

3、使用python控制gdb流程。

比如我们需要监控某个函数中某个变量的值,比如循环中执行多次,如果我们每次在gdb中手动输入命令,那就太繁琐了,我们可以使用python来做到这些。

比如有个c程序b.c

#include <stdio.h>

int sum=0;
void print_message(const int i) {
    sum+=i;
}

int main() {
    for(int i=0; i<100; i++){
        print_message(i);
    }
    printf("sum = %d\n", sum);
    return 0;
}

想要打印每次print_message函数执行时,变量i的值,也可以通过python脚本来实现。

下面是python脚本的内容c1.py

import gdb

class PrintVariable(gdb.Breakpoint):
    def __init__(self, function, variable):
        super(PrintVariable, self).__init__(function, gdb.BP_BREAKPOINT)
        self.variable = variable

    def stop(self):
        frame = gdb.selected_frame()
        if frame:
            try:
                value = frame.read_var(self.variable)
                print(f"Variable '{self.variable}' has value: {value}")
            except gdb.error as e:
                print(f"Error reading variable '{self.variable}': {e}")

# 禁用分页
gdb.execute("set pagination off")

# 要执行的程序   file 是关键字,后文件路径
gdb.execute("file /root/c_debug/b")


# 替换这里的'function_name'和'variable_name'为你的函数名(或者代码行号)和变量名
function_name = "5"
variable_name = "i"

# 创建一个断点在函数f的开始处
bp = PrintVariable(function_name, variable_name)


# 设置断点命令
bp.commands = "print " + variable_name


# 运行程序
gdb.execute("run")

脚本的内容都有注释,也就不再说什么了 。

下面看看怎么执行:

  • 将上面的b.c编译成可调试的可执行程序。

gcc -g b.c -o b,我本地是放在/root/c_debug/b,也是上面脚本中的路径

  • 使用gdb命令进入gdb窗口,执行source c1.py,由于我们是在代码第5行设置断点,就可以看到就会自动执行上面我们编译的b,同时每次打印变量i的值。
root@wbo112:~/c_debug# gdb
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.2) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) source c1.py
Breakpoint 1 at 0x1154: file b.c, line 5.
Variable 'i' has value: 0
Variable 'i' has value: 1
Variable 'i' has value: 2
Variable 'i' has value: 3
Variable 'i' has value: 4
Variable 'i' has value: 5
Variable 'i' has value: 6
Variable 'i' has value: 7
Variable 'i' has value: 8
Variable 'i' has value: 9
Variable 'i' has value: 10
Variable 'i' has value: 11
Variable 'i' has value: 12
Variable 'i' has value: 13
Variable 'i' has value: 14
Variable 'i' has value: 15
Variable 'i' has value: 16
Variable 'i' has value: 17
Variable 'i' has value: 18
Variable 'i' has value: 19
Variable 'i' has value: 20
Variable 'i' has value: 21
Variable 'i' has value: 22
Variable 'i' has value: 23
Variable 'i' has value: 24
Variable 'i' has value: 25
Variable 'i' has value: 26
Variable 'i' has value: 27
Variable 'i' has value: 28
Variable 'i' has value: 29
Variable 'i' has value: 30
Variable 'i' has value: 31
Variable 'i' has value: 32
Variable 'i' has value: 33
Variable 'i' has value: 34
Variable 'i' has value: 35
Variable 'i' has value: 36
Variable 'i' has value: 37
Variable 'i' has value: 38
Variable 'i' has value: 39
Variable 'i' has value: 40
Variable 'i' has value: 41
Variable 'i' has value: 42
Variable 'i' has value: 43
Variable 'i' has value: 44
Variable 'i' has value: 45
Variable 'i' has value: 46
Variable 'i' has value: 47
Variable 'i' has value: 48
Variable 'i' has value: 49
Variable 'i' has value: 50
Variable 'i' has value: 51
Variable 'i' has value: 52
Variable 'i' has value: 53
Variable 'i' has value: 54
Variable 'i' has value: 55
Variable 'i' has value: 56
Variable 'i' has value: 57
Variable 'i' has value: 58
Variable 'i' has value: 59
Variable 'i' has value: 60
Variable 'i' has value: 61
Variable 'i' has value: 62
Variable 'i' has value: 63
Variable 'i' has value: 64
Variable 'i' has value: 65
Variable 'i' has value: 66
Variable 'i' has value: 67
Variable 'i' has value: 68
Variable 'i' has value: 69
Variable 'i' has value: 70
Variable 'i' has value: 71
Variable 'i' has value: 72
Variable 'i' has value: 73
Variable 'i' has value: 74
Variable 'i' has value: 75
Variable 'i' has value: 76
Variable 'i' has value: 77
Variable 'i' has value: 78
Variable 'i' has value: 79
Variable 'i' has value: 80
Variable 'i' has value: 81
Variable 'i' has value: 82
Variable 'i' has value: 83
Variable 'i' has value: 84
Variable 'i' has value: 85
Variable 'i' has value: 86
Variable 'i' has value: 87
Variable 'i' has value: 88
Variable 'i' has value: 89
Variable 'i' has value: 90
Variable 'i' has value: 91
Variable 'i' has value: 92
Variable 'i' has value: 93
Variable 'i' has value: 94
Variable 'i' has value: 95
Variable 'i' has value: 96
Variable 'i' has value: 97
Variable 'i' has value: 98
Variable 'i' has value: 99
sum = 4950
[Inferior 1 (process 78220) exited normally]
(gdb) q

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

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

相关文章

SpringBoot3 简单集成 Mybatis plus

SpringBoot3 集成 Mybatis plus 1、引入Mybatisplus的starter <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency>2、引入数据…

JVM3-双亲委派机制

目录 概述 作用 如何指定加载类的类加载器&#xff1f; 面试题 打破双亲委派机制 自定义类加载器 线程上下文类加载器 Osgi框架的类加载器 概述 由于Java虚拟机中有多个类加载器&#xff0c;双亲委派机制的核心是解决一个类到底由谁加载的问题 双亲委派机制&#xff…

Qt中window frame的影响

window frame 在创建图形化界面的时候&#xff0c;会创建窗口主体&#xff0c;上面会多出一条&#xff0c;周围多次一圈细边&#xff0c;这就叫window frame窗口框架&#xff0c;这是操作系统自带的。 这个对geometry的一些属性有一定影响&#xff0c;主要体现在Qt坐标系体系…

安装Seata-Service,Seata服务中心安装,并完成Nacos注册

一、下载服务器软件包 从 Releases apache/incubator-seata GitHub ,下载服务器软件包&#xff0c;将其解压缩。 版本选择&#xff1a; 1可以从官网查询版本对照。 2.可以在项目中&#xff0c;倒入seata版依赖 <!-- seata--><dependency><groupId&…

嘉立创中秋福利来啦!

单笔订单商品实付慢2万送良品铺子月饼 多品牌折扣 快来立创商城一探究竟吧~ 立创商城_一站式电子元器件采购自营商城_嘉立创电子商城 (szlcsc.com)

深度学习中常见的权重参数初始化方法

在深度学习中&#xff0c;权重参数的初始化对模型的训练过程和性能有着非常重要的影响。一个好的权重初始化方法能够帮助模型更快收敛、避免梯度爆炸或梯度消失等问题。以下是几种常见的权重初始化方法及其背后的原理。 1. 零初始化&#xff08;Zero Initialization&#xff0…

每天学习一个字符串类函数之memmove函数

目录 前言&#xff1a; 一、头文件 二、memmove函数的作用 三、理解memmove函数的定义 1、返回类型 2、参数 四、使用memmove函数 案例1&#xff1a; 案例2&#xff1a; 五、解决数据拷贝之前被覆盖的方法 六、模拟实现memmove函数 前言&#xff1a; 上一篇博客&#xff0c;我…

【C++】STL容器详解【上】

目录 一、STL基本概念 二、STL的六大组件 三、string容器常用操作 3.1 string 容器的基本概念 3.2 string 容器常用操作 3.2.1 string 构造函数 3.2.2 string基本赋值操作 3.2.3 string存取字符操作 3.2.4 string拼接字符操作 3.2.5 string查找和替换 3.2.6 string比…

Unity Shader实现简单的各向异性渲染(采用各向异性形式的GGX分布)

目录 准备工作 BRDF部分 Unity部分 代码 实现的效果 参考 最近刚结束GAMES202的学习&#xff0c;准备慢慢过渡到GAMES103。GAMES103的作业框架为Unity&#xff0c;并没有接触过&#xff0c;因此准备先学一点Unity的使用。刚好101和202都是渲染相关的&#xff0c;因此先学习…

如何查看Mac的处理器架构‌‌是ARM还是x86

‌通过命令行查看Mac的处理器架构‌‌ 打开终端&#xff08;Terminal&#xff09;。输入命令 uname -m 并回车。如果输出结果是 arm64&#xff0c;则表示你的Mac使用的是ARM架构&#xff1b;如果输出结果是 x86_64&#xff0c;则表示你的Mac使用的是x86架构。 如图&#xff1…

牛客JZ36 二叉搜索树与双向链表 C++

牛客JZ36 二叉搜索树与双向链表 C 思路&#x1f9d0;&#xff1a; 由图所示&#xff0c;我们看出该链表走的是中序&#xff0c;所以我们可以使用中序遍历的方式来解决这个问题&#xff0c;在遍历过程中&#xff0c;我们创建一个前驱和一个后继结点&#xff0c;来进行链接。 并且…

基于stm32f407的跟随行驶系统项目报告(利用openmv+超声波模块)

2023年全国大学生电子设计竞赛&#xff08;TI杯&#xff09; 2024年05月29日 摘要 本项目的硬件结构&#xff1a;基于STM32F407芯片为主控芯片&#xff0c;由TB6612电机驱动&#xff0c;控制左右轮电机的转动控制小车提供前进前进的速度&#xff0c;通过控制两轮的差数达到稳定…

Hive中的分区表与分桶表详解

目录 分区表和分桶表 分区表 分区表基本语法 1. 创建分区表 2. 分区表读写数据 1&#xff09;写数据 &#xff08;1&#xff09;LOAD &#xff08;2&#xff09;INSERT 2&#xff09;读数据 3. 分区表基本操作 1&#xff09;查看所有分区信息 2&#xff09;增加分区 …

数据库MySQL零基础-下【详细】

目录 六、事务/视图/触发器/存储过程 1、事务的理解 &#xff08;1&#xff09;事务的理解 &#xff08;2&#xff09;事务的特性 2、事务的应用 &#xff08;1&#xff09;事务的开启与提交 # 语法 # 示例 &#xff08;2&#xff09;开启autocommit&#xff08;临时生…

MybatisPlus静态工具 通用枚举

静态工具 有的时候Service之间也会相互调用&#xff0c;为了避免出现循环依赖问题&#xff0c;MybatisPlus提供一个静态工具类&#xff1a;Db&#xff0c;其中的一些静态方法与IService中方法签名基本一致&#xff0c;就在方法例多给出一个参数&#xff0c;操作的实体类类型。…

P3285 [SCOI2014] 方伯伯的OJ

*原题链接* 本题与NOIP2017列队有很多共通之处&#xff0c;都是一开始给我们一个排好编号的队列&#xff0c;然后进行一些操作。 如果n的范围不大&#xff0c;我们会如何做呢&#xff1f;很容易想到权值线段树&#xff0c;以编号为下标建立权值线段树&#xff0c;维护每个下标…

WEB攻防-ASP安全MDB下载植入IIS短文件名写权限解析

知识点&#xff1a; 1、ASP环境搭建组合&#xff1b; 2、ASP-数据库下载&植入&#xff1b; 3、IIS-短文件&解析&写权限&#xff1b; WEB安全攻防 1、web源码&#xff1b; 2、开发语言&#xff1b; 3、中间件平台&#xff1b; 4、数据库类型&#xff1b; 5、…

百度快照劫持之JS劫持诊断与恢复一例

劫持现象&#xff1a; 百度搜索结果中&#xff0c;被劫持网站出现在搜索结果中&#xff0c; 点击进入网站&#xff0c;网站显示正常&#xff0c;数秒后网站自动跳转到彩票网站f51688.com/ff6/。但是第二次点击搜索结果&#xff0c;正常进入网站缺不会跳转到彩票网站。 初步认…

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理&#xff0c;打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名…

GO语言快速入门(比较乱)

一、环境安装 1、安装Go环境 1、官网下载 2、cmd-->go version 3、环境变量 GOROOT&#xff1a;go安装路径 GOPATH&#xff1a;go存放代码的路径 4、GOWorks新建三个文件 5、go env查看配置 2、安装编辑器 GoLand或者VSCode 3、HelloWorld package main //一个程序只有一个…