【转载】【GDB】GDB with Python
作者:薛定谔的喵
链接:https://zhuanlan.zhihu.com/p/152274203
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
你还在用GDB调试程序吗?
如果是,那么我们是同道中人。但是你知道GDB有一个很强大的功能,Python scripting嘛?
如果是的,那么恭喜你,你是一个大牛。
本文主要讲述如何使用Python来提高你的gdb调试技能, 让你从繁重的重复的工作里面挣脱出来呼吸新鲜空气。
首先,第一件事,使用gdb7.x以上的版本,最好9.x的。因为Python的支持是从gdb7.0(2009年?)开始的。
进入正题
gdb本来就支持自定义脚本辅助调试,为什么还要用Python脚本呢?因为自定义脚本的语法比较老,不如写Python欢快。如果你喜欢用原来的自定义脚本方法,那也是可以的。
借助Python,你可以将难看的数据变得好看,
借助Python,你可以将重复的工作变成一个命令,
借助Python,你可以更快的调试bug,
借助Python,你可以装逼,哈哈哈
……
将难看的数据变得好看
以下面的代码为例
#include <map>
#include <iostream>
#include <string>
using namespace std; int main() {
std::map<string, string> lm;
lm["good"] = "heart";
// 查看map 里面内容
std::cout<<lm["good"];
}
当代码运行到std<<cout时, 你想查看map里面的内容,如果没有python和自定义的脚本,print lm看到的是
$2 = {_M_t = {
_M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > 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<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 = 0x55555556eeb0,
_M_left = 0x55555556eeb0, _M_right = 0x55555556eeb0},
_M_node_count = 1}, <No data fields>}}}
但是当你在gdb9.2里面输入print lm的时候,你看到的将是
(gdb) p lm
$3 = std::map with 1 element = {["good"] = "heart"}
map里面有什么一清二楚。这是因为gdb9.x自带了一系列标准库的Python pretty priniter。 如果你使用的是gdb7.x,那么你可以手动的导入这些pretty printer实现同样的效果。具体步骤如下:
- 下载pretty printer: svn co svn://http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
- 在gdb里面输入(将路径改成你下载的路径):
python
import sys
sys.path.insert(0, '/home/maude/gdb_printers/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
这样你就可以放心使用了~
详细请看:
https://sourceware.org/gdb/wiki/STLSupport
https://codeyarns.com/2014/07/17/how-to-enable-pretty-printing-for-stl-in-gdb/
将重复的工作变成一个命令
比如在调试的时候,你知道当前栈指向一个字符串,但是你不知道具体在哪里,你想遍历这个栈将它找出来,那么你可以借助Python自定义一个命令"stackwalk",这个命令可以直接Python代码遍历栈,将字符串找出来。
#####################################################
# Usage: to load this to gdb run:
# (gdb) source ..../path/to/<script_file>.py import gdb class StackWalk(gdb.Command):
def __init__(self):
# This registers our class as "StackWalk"
super(StackWalk, self).__init__("stackwalk", gdb.COMMAND_DATA) def invoke(self, arg, from_tty):
# When we call "StackWalk" from gdb, this is the method
# that will be called.
print("Hello from StackWalk!")
# get the register
rbp = gdb.parse_and_eval('$rbp')
rsp = gdb.parse_and_eval('$rsp')
ptr = rsp
ppwc = gdb.lookup_type('wchar_t').pointer().pointer()
while ptr < rbp:
try:
print('pointer is {}'.format(ptr))
print(gdb.execute('wc_print {}'.format(ptr.cast(ppwc).dereference())))
print('===')
except:
pass
ptr += 8 # This registers our class to the gdb runtime at "source" time.
StackWalk() 更快的调试bug
当你调试多线程的时候,你发现callstack 一堆,而且好多都是重复的,如果它们可以自动去重或者折叠多好,这样你只需要关注一小部分。好消息!Python可以让你用一个命令就可以轻松搞定。而且已经有人写好了相应的代码,你只需要导入即可。详细介绍请看https://fy.blackhats.net.au/blog/html/2017/08/04/so_you_want_to_script_gdb_with_python.html # From https://fy.blackhats.net.au/blog/html/2017/08/04/so_you_want_to_script_gdb_with_python.html
#####################################################
#
# Usage: to load this to gdb run:
# (gdb) source ..../path/to/debug_naughty.py
#
# To have this automatically load, you need to put the script
# in a path related to your binary. If you make /usr/sbin/foo,
# You can ship this script as:
# /usr/share/gdb/auto-load/ <PATH TO BINARY>
# /usr/share/gdb/auto-load/usr/sbin/foo
#
# This will trigger gdb to autoload the script when you start
# to acces a core or the live binary from this location.
# import gdb class StackFold(gdb.Command):
def __init__(self):
super(StackFold, self).__init__("stackfold", gdb.COMMAND_DATA) def invoke(self, arg, from_tty):
# An inferior is the 'currently running applications'. In this case we only
# have one.
stack_maps = {}
# This creates a dict where each element is keyed by backtrace.
# Then each backtrace contains an array of "frames"
#
inferiors = gdb.inferiors()
for inferior in inferiors:
for thread in inferior.threads():
try:
# Change to our threads context
thread.switch()
# Get the thread IDS
(tpid, lwpid, tid) = thread.ptid
gtid = thread.num
# Take a human readable copy of the backtrace, we'll need this for display later.
o = gdb.execute('bt', to_string=True)
# Build the backtrace for comparison
backtrace = []
gdb.newest_frame()
cur_frame = gdb.selected_frame()
while cur_frame is not None:
if cur_frame.name() is not None:
backtrace.append(cur_frame.name()) cur_frame = cur_frame.older()
# Now we have a backtrace like ['pthread_cond_wait@@GLIBC_2.3.2', 'lazy_thread', 'start_thread', 'clone']
# dicts can't use lists as keys because they are non-hashable, so we turn this into a string.
# Remember, C functions can't have spaces in them ...
s_backtrace = ' '.join(backtrace)
# Let's see if it exists in the stack_maps
if s_backtrace not in stack_maps:
stack_maps[s_backtrace] = []
# Now lets add this thread to the map.
stack_maps[s_backtrace].append({'gtid': gtid, 'tpid' : tpid, 'bt': o} )
except Exception as e:
print(e)
# Now at this point we have a dict of traces, and each trace has a "list" of pids that match. Let's display them
for smap in stack_maps:
# Get our human readable form out.
o = stack_maps[smap][0]['bt']
for t in stack_maps[smap]:
# For each thread we recorded
print("Thread %s (LWP %s))" % (t['gtid'], t['tpid']))
print(o) # This registers our class to the gdb runtime at "source" time.
StackFold()
等等!还有好多,毕竟Python图灵完备,只要GDB提供相应的API,你想要啥都能实现。
会了这些,你就可以向新手装逼去了
References:
1 https://undo.io/resources/gdb-watchpoint/python-gdb/
2 https://codeyarns.com/2014/07/17/how-to-enable-pretty-printing-for-stl-in-gdb/
【转载】【GDB】GDB with Python的更多相关文章
- gdb可以调试python的pdb么
1.如题: gdb可以调试python的pdb么? 答案:可以,实验如下. 2.实验: 生成一个a.py代码文件,代码如下: import pdb a = 1 print "111" ...
- 【转载】gdb基本命令总结
本文介绍使用gdb调试程序的常用命令. 主要内容: [简介] [举例] [其他] [简介] ============= GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.如果你是在 U ...
- [skill][gdb] gdb 多线程调试
中文快速入门: http://coolshell.cn/articles/3643.html (关于多线程的部署说的并不太对) 进阶: 多进程相关概念: inferiors 是什么? http://m ...
- How to Find Processlist Thread id in gdb !!!!!GDB 使用
https://mysqlentomologist.blogspot.jp/2017/07/ Saturday, July 29, 2017 How to Find Process ...
- 【转载】GDB反向调试(Reverse Debugging)
记得刚开始学C语言的时候,用vc的F10来调试程序,经常就是一阵狂按,然后一不小心按过了.结果又得从头再来,那时候我就问我的老师,能不能倒退回去几步.我的老师很遗憾地和我说,不行,开弓没有回头箭.这句 ...
- GDB gdb 调试
除了用grmon看汇编调试外,还可以用gdb. 编译的时候加-g gdb app即可进入gdb调试 设置断点:b main.c:10 然后运行程序:run 断点处可以查看变量:display a 其它 ...
- 转载八个最佳Python IDE
八个最佳Python IDE 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Python是一种功能强大.语言简洁的编程语言.本文向大家推荐8个适合Pyt ...
- 转载 为什么print在Python 3中变成了函数?
转载自编程派http://codingpy.com/article/why-print-became-a-function-in-python-3/ 原作者:Brett Cannon 原文链接:htt ...
- [转载]windows下安装Python虚拟环境virtualenvwrapper-win
1 前言 由于Python的版本众多,还有Python2和Python3的争论,因此有些软件包或第三方库就容易出现版本不兼容的问题. 通过 virtualenv 这个工具,就可以构建一系列 虚拟的Py ...
- [转载]windows下安装Python虚拟环境virtualenv,virtualenvwrapper-win
1 前言 由于Python的版本众多,还有Python2和Python3的争论,因此有些软件包或第三方库就容易出现版本不兼容的问题. 通过 virtualenv 这个工具,就可以构建一系列 虚拟的Py ...
随机推荐
- 认识ollydbg
四个区域:汇编区:虚拟地址,机器码,汇编指令,注释: 寄存器区:寄存器,数据: 数据区, 栈. 这是上面按钮的作用 热键: Ctrl+F2 - 重启程序. Alt+F2 - 关闭被调试程序. F3 - ...
- Java连接MySQL数据库——含详细步骤和代码
工具:eclipse.MySQL.MySQL连接驱动:mysql-connector-java-5.1.45.jar 首先要下载Connector/J地址:http://www.mysql.com/d ...
- 阿里巴巴java开发手册-泰山版 下载
最近,阿里的<Java开发手册>又更新了,这个版本历经一年的修炼,取名:<Java开发手册(泰山版)>正式出道.正所谓无规矩不成方圆,在程序员的世界里,也存在很多规范,阿里出版 ...
- 虚拟机的安装and虚拟机中安装Linux操作系统
安装虚拟机并安装Linux系统,我们首先需要下载: (1)VMware安装包 (2)Linux 镜像iso 文件 下载VM安装包后准备安装虚拟机: 直接点击下一步 接受条款下一步 这里默认是c盘,建议 ...
- Inno Step软件安装包制作教程
Inno setup制作软件安装包教程 1,Inno Setup介绍 Inno Setup 是一个免费的安装制作软件,小巧.简便.精美是其最大特点,支持pascal脚本,能快速制作出标准Windows ...
- 这些JS技巧,看看你是否都会用?
问题1:以下代码在浏览器控制台上会打印什么? var a = 10; function foo() { console.log(a); // ?? var a = 20; } foo(); 问题2:如 ...
- 第三章 存储器的扩展(二)——> 重要
3.2 主存储器 四.只读存储器(ROM)---->了解(考试也可能会考) 掩膜ROM(MROM) 行列选择线交叉处有 MOS 管为"1" 行列选择线交叉处无 MOS 管为& ...
- 一言不合就开始搞JDK源码
Java是一门面向对象的编程语言,那什么是面向对象呢,下面将是历史上最通俗易懂的解释了,请看下图: 哈哈,解释的够清楚的了吧.闪. 从源码学编程的好处 学Java编程时,最好同时看一些Java的源码 ...
- 哎,这让人抠脑壳的 LFU。
这是why哥的第 83 篇原创文章 让人抠脑壳的 LFU 前几天在某APP看到了这样的一个讨论: 看到一个有点意思的评论: LFU 是真的难,脑壳都给我抠疼了. 如果说 LRU 是 Easy 模式的话 ...
- Flutter 基础组件:输入框和表单
前言 Material组件库中提供了输入框组件TextField和表单组件Form. 输入框TextField 接口描述 const TextField({ Key key, // 编辑框的控制器,通 ...