zoukankan      html  css  js  c++  java
  • 【转载】【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实现同样的效果。具体步骤如下:

    1. 下载pretty printer: svn co svn://
    2. 在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

    这样你就可以放心使用了~

    详细请看:

    将重复的工作变成一个命令

    比如在调试的时候,你知道当前栈指向一个字符串,但是你不知道具体在哪里,你想遍历这个栈将它找出来,那么你可以借助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

    2

  • 相关阅读:
    记忆力:记忆分类
    范例-项目-.NET-PetShop-4.0-数据库设计:MSPetShop4Service
    范例-项目-.NET-PetShop-4.0-数据库设计:MSPetShop4Profile
    范例-项目-.NET-PetShop-4.0-数据库设计:MSPetShop4Order
    范例-项目-.NET-PetShop-4.0-数据库设计:MSPetShop4
    范例-项目-.NET-PetShop-4.0-架构设计:PetShop 4.0架构与技术分析(2)
    范例-项目-.NET-PetShop-4.0-架构设计与技术分析:PetShop 4.0架构与技术分析(1)
    Error-Javascript:Uncaught Error: Malformed UTF-8 data at Object.stringify (crypto-js.js:478) at WordArray.init.toString (crypto-js.js:215)
    System.Diagnostics.Stopwatch.cs
    开发软件-服务器:Apache Tomcat
  • 原文地址:https://www.cnblogs.com/gaoshaonian/p/13253877.html
Copyright © 2011-2022 走看看