↑ 点击蓝字 关注视学算法

作者丨薛定谔的喵@知乎

来源丨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>.pyimport gdbclass 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 registerrbp = gdb.parse_and_eval('$rbp')rsp = gdb.parse_and_eval('$rsp')ptr = rspppwc = 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:passptr += 8# This registers our class to the gdb runtime at "source" time.
StackWalk()

Note: wc_print是我写的另外一个简单Python命令,用于打印给定地址的宽字符串,具体实现留作习题~

更快地调试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 gdbclass 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 contextthread.switch()# Get the thread IDS(tpid, lwpid, tid) = thread.ptidgtid = 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 comparisonbacktrace = []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_mapsif 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 themfor 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 recordedprint("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

https://undo.io/resources/gdb-watchpoint/python-gdb/

https://codeyarns.com/2014/07/17/how-to-enable-pretty-printing-for-stl-in-gdb/

觉得有用麻烦给个在看啦~  

你还在用GDB调试程序吗?相关推荐

  1. 【linux】Valgrind工具集详解(六):使用Valgrind gdbserver和GDB调试程序

    一.概述 在Valgrind下运行的程序不是由CPU直接执行的.相反,它运行在Valgrind提供的合成CPU上.这就是调试器在Valgrind上运行时无法调试程序的原因. 二.快速入门 在使用Mem ...

  2. 用GDB调试程序(转)

    用GDB调试程序 GDB概述 ---- GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做 ...

  3. 转:用GDB调试程序

    从CSDN的网站上找到的GDB使用说明. 原文标题:用GDB调试程序     作者:haoel (QQ是:753640,MSN是: haoel@hotmail.com)     关键字:gdb 调试  ...

  4. GDB调试程序-Ubuntu

    导读: 用GDB调试程序 出自Ubuntu中文 目录 [隐藏] 1 GDB概述 2 一个调试示例 3 使用GDB 4 GDB的命令概貌 5 GDB中运行UNIX的shell程序 6 在GDB中运行程序 ...

  5. GDB调试程序系列 (3)

    GDB调试程序系列 (3)  用GDB调试程序 来源:www.trucy.org (2005-03-23 16:48:14) GDB是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形成 ...

  6. GDB 调试程序 详解 使用实例

    用GDB调试程序 GDB概述 ---- GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做 ...

  7. 使用gdb调试程序完全教程

    程序的调试过程主要有:单步执行,跳入函数,跳出函数,设置断点,设置观察点,查看变量. 本文将主要介绍linux下的强大调试工具是怎么完成这些工作的. 之所以要调试程序,是因为程序的运行结果和预期结果不 ...

  8. linux使用gdb调试程序完全教程

    转自 http://blog.csdn.net/gatieme 程序的调试过程主要有:单步执行,跳入函数,跳出函数,设置断点,设置观察点,查看变量.  本文将主要介绍linux下的强大调试工具是怎么完 ...

  9. 用GDB调试程序(一)

    用GDB调试程序 GDB概述 ---- GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做 ...

最新文章

  1. UVA816 Abbott的复仇 Abbott's Revenge(final的BFS)(真•答案)
  2. java 实验4 异常
  3. Oracle 左外连接的一些測试
  4. Linux下百度网盘一直进入不了登陆界面的解决方案
  5. 为什么WEB-INF外的jsp无法根据cookie享受国际化
  6. Qtum量子链研究院:Plasma扩容方案详解(上)
  7. 关于UIImageView的显示问题——居中显示或者截取图片的中间部分显示
  8. java解析json_JAVA解析JSON数据
  9. c语言表达式5 gt 3 gt 1,C语言题目谁会做?
  10. JS高级——手写call()、apply()、bind()
  11. DevPartner Studio Professional Edition 11 内存泄露检测使用
  12. Spring Cloud Eureka(一)搭建一个注册中心
  13. oracle关键字作为字段名使用方法
  14. windows10(专业版和家庭版)---禁止自动更新系统
  15. CTF-实验吧-安全杂项-社交网络
  16. html 让360浏览器兼容模式,360浏览器兼容模式怎么设置?360浏览器兼容模式设置方法介绍...
  17. 小葵花妈妈课堂之nginx必须要了解的优化九部曲!
  18. windows安装exe为系统服务
  19. IO_CELL里的slew rate control
  20. Android利用SpannableStringBuilder设置TextView中部分文字的颜色...

热门文章

  1. 刻意练习:LeetCode实战 -- Task21. 二叉树的最大深度
  2. 测试一下,你能小学毕业吗?
  3. 【MATLAB】交互式绘图(ginput,gtext,zoom)
  4. 数字化探索:建立学习型组织,HR 也能驱动业务营收?
  5. 5 亿微博数据疑泄露,Python 爬虫如何避免踩天坑?
  6. 如果三十年前有这些AI技术,可可西里的悲剧不会发生
  7. 加速AI应用落地,英特尔AI 2.0的进阶之道
  8. 杨超越的声音+高晓松的脸~如此酸爽的技术,你值得拥有!
  9. 想体验无人商店?去京东他们家直接刷脸!
  10. 2018机器阅读理解技术竞赛,奇点机智获第一名