你还在用GDB调试程序吗?

2020 年 9 月 21 日 极市平台
↑ 点击 蓝字  关注极市平台

作者丨薛定谔的喵@知乎
来源丨https://zhuanlan.zhihu.com/p/152274203
编辑丨极市平台

极市导读

 

借助Python scripting功能,使用者能够提高自己的GDB调试技能,轻松解决繁复的工作。>>加入极市CV技术交流群,走在计算机视觉的最前沿

你还在用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里面输入(将路径改成你下载的路径):

pythonimport syssys.path.insert(0, '/home/maude/gdb_printers/python')from libstdcxx.v6.printers import register_libstdcxx_printersregister_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()

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 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
https://undo.io/resources/gdb-watchpoint/python-gdb/
https://codeyarns.com/2014/07/17/how-to-enable-pretty-printing-for-stl-in-gdb/


推荐阅读



添加极市小助手微信(ID : cvmart2),备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳),即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群:月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~

△长按添加极市小助手

△长按关注极市平台,获取 最新CV干货

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


登录查看更多
0

相关内容

Beginner's All-purpose Symbolic Instruction Code(初学者通用的符号指令代码),刚开始被作者写做 BASIC,后来被微软广泛地叫做 Basic 。
【2020新书】操作反模式: DevOps解决方案, 322页pdf
专知会员服务
34+阅读 · 2020年11月8日
【2020新书】使用R和Python的高级BI分析,425页pdf
专知会员服务
35+阅读 · 2020年10月14日
【干货书】Python 编程,480页pdf
专知会员服务
241+阅读 · 2020年8月14日
【经典书】C++编程:从问题分析到程序设计,1491页pdf
专知会员服务
65+阅读 · 2020年8月11日
【2020新书】高级Python编程,620页pdf
专知会员服务
238+阅读 · 2020年7月31日
【新书】Python编程基础,669页pdf
专知会员服务
195+阅读 · 2019年10月10日
【SIGGRAPH2019】TensorFlow 2.0深度学习计算机图形学应用
专知会员服务
41+阅读 · 2019年10月9日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
你真的会正确地调试 TensorFlow 代码吗?
数据库开发
7+阅读 · 2019年3月18日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
开发、调试计算机视觉代码有哪些技巧?
AI研习社
3+阅读 · 2018年7月9日
已删除
将门创投
7+阅读 · 2018年4月18日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
用Python调用百度OCR接口实例
数据挖掘入门与实战
16+阅读 · 2018年1月29日
教你用Python来玩跳一跳
七月在线实验室
6+阅读 · 2018年1月2日
Arxiv
0+阅读 · 2020年12月1日
Question Generation by Transformers
Arxiv
5+阅读 · 2019年9月14日
Arxiv
3+阅读 · 2019年3月1日
Rapid Customization for Event Extraction
Arxiv
7+阅读 · 2018年9月20日
Arxiv
6+阅读 · 2017年12月2日
VIP会员
相关VIP内容
【2020新书】操作反模式: DevOps解决方案, 322页pdf
专知会员服务
34+阅读 · 2020年11月8日
【2020新书】使用R和Python的高级BI分析,425页pdf
专知会员服务
35+阅读 · 2020年10月14日
【干货书】Python 编程,480页pdf
专知会员服务
241+阅读 · 2020年8月14日
【经典书】C++编程:从问题分析到程序设计,1491页pdf
专知会员服务
65+阅读 · 2020年8月11日
【2020新书】高级Python编程,620页pdf
专知会员服务
238+阅读 · 2020年7月31日
【新书】Python编程基础,669页pdf
专知会员服务
195+阅读 · 2019年10月10日
【SIGGRAPH2019】TensorFlow 2.0深度学习计算机图形学应用
专知会员服务
41+阅读 · 2019年10月9日
相关资讯
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
你真的会正确地调试 TensorFlow 代码吗?
数据库开发
7+阅读 · 2019年3月18日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
开发、调试计算机视觉代码有哪些技巧?
AI研习社
3+阅读 · 2018年7月9日
已删除
将门创投
7+阅读 · 2018年4月18日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
用Python调用百度OCR接口实例
数据挖掘入门与实战
16+阅读 · 2018年1月29日
教你用Python来玩跳一跳
七月在线实验室
6+阅读 · 2018年1月2日
相关论文
Arxiv
0+阅读 · 2020年12月1日
Question Generation by Transformers
Arxiv
5+阅读 · 2019年9月14日
Arxiv
3+阅读 · 2019年3月1日
Rapid Customization for Event Extraction
Arxiv
7+阅读 · 2018年9月20日
Arxiv
6+阅读 · 2017年12月2日
Top
微信扫码咨询专知VIP会员