pdb_pdborcl - CSDN
精华内容
参与话题
  • Python3 : pdb调试

    千次阅读 2018-07-11 20:00:49
    原文链接:https://www.ibm.com/developerworks/cn/linux/l-cn-pythondebugger/pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源...pdb 提供了一些常用的调试命令,详情见表 1。表 1. pdb 常用命令命...

    原文链接:https://www.ibm.com/developerworks/cn/linux/l-cn-pythondebugger/

    pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些常用的调试命令,详情见表 1。

    表 1. pdb 常用命令

    下面结合具体的实例讲述如何使用 pdb 进行调试。

    清单 1. 测试代码示例
    1
    2
    3
    4
    5
    6
    7
    import pdb
     a = "aaa"
     pdb.set_trace()
     b = "bbb"
     c = "ccc"
     final = a + b + c
     print final

    开始调试:直接运行脚本,会停留在 pdb.set_trace() 处,选择 n+enter 可以执行当前的 statement。在第一次按下了 n+enter 之后可以直接按 enter 表示重复执行上一条 debug 命令。

    清单 2. 利用 pdb 调试
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py
     > /root/epdb1.py(4)?()
     -> b = "bbb"
     (Pdb) n
     > /root/epdb1.py(5)?()
     -> c = "ccc"
     (Pdb)
     > /root/epdb1.py(6)?()
     -> final = a + b + c
     (Pdb) list
      1     import pdb
      2     a = "aaa"
      3     pdb.set_trace()
      4     b = "bbb"
      5     c = "ccc"
      6  -> final = a + b + c
      7     print final
     [EOF]
     (Pdb)
     [EOF]
     (Pdb) n
     > /root/epdb1.py(7)?()
     -> print final
     (Pdb)

    退出 debug:使用 quit 或者 q 可以退出当前的 debug,但是 quit 会以一种非常粗鲁的方式退出程序,其结果是直接 crash。

    清单 3. 退出 debug
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py
     > /root/epdb1.py(4)?()
     -> b = "bbb"
     (Pdb) n
     > /root/epdb1.py(5)?()
     -> c = "ccc"
     (Pdb) q
     Traceback (most recent call last):
      File "epdb1.py", line 5, in ?
        c = "ccc"
      File "epdb1.py", line 5, in ?
        c = "ccc"
      File "/usr/lib64/python2.4/bdb.py", line 48, in trace_dispatch
        return self.dispatch_line(frame)
      File "/usr/lib64/python2.4/bdb.py", line 67, in dispatch_line
        if self.quitting: raise BdbQuit
     bdb.BdbQuit

    打印变量的值:如果需要在调试过程中打印变量的值,可以直接使用 p 加上变量名,但是需要注意的是打印仅仅在当前的 statement 已经被执行了之后才能看到具体的值,否则会报 NameError: < exceptions.NameError … ....> 错误。

    清单 4. debug 过程中打印变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py
     > /root/epdb1.py(4)?()
     -> b = "bbb"
     (Pdb) n
     > /root/epdb1.py(5)?()
     -> c = "ccc"
     (Pdb) p b
    'bbb'
     (Pdb)
    'bbb'
     (Pdb) n
     > /root/epdb1.py(6)?()
     -> final = a + b + c
     (Pdb) p c
    'ccc'
     (Pdb) p final
     *** NameError: <exceptions.NameError instance at 0x1551b710 >
     (Pdb) n
     > /root/epdb1.py(7)?()
     -> print final
     (Pdb) p final
    'aaabbbccc'
     (Pdb)

    使用 c 可以停止当前的 debug 使程序继续执行。如果在下面的程序中继续有 set_statement() 的申明,则又会重新进入到 debug 的状态,读者可以在代码 print final 之前再加上 set_trace() 验证。

    清单 5. 停止 debug 继续执行程序
    1
    2
    3
    4
    5
    6
    7
    8
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py
     > /root/epdb1.py(4)?()
     -> b = "bbb"
     (Pdb) n
     > /root/epdb1.py(5)?()
     -> c = "ccc"
     (Pdb) c
     aaabbbccc

    显示代码:在 debug 的时候不一定能记住当前的代码块,如要要查看具体的代码块,则可以通过使用 list 或者 l 命令显示。list 会用箭头 -> 指向当前 debug 的语句。

    清单 6. debug 过程中显示代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py
     > /root/epdb1.py(4)?()
     -> b = "bbb"
     (Pdb) list
      1     import pdb
      2     a = "aaa"
      3     pdb.set_trace()
      4  -> b = "bbb"
      5     c = "ccc"
      6     final = a + b + c
      7     pdb.set_trace()
      8     print final
     [EOF]
     (Pdb) c
     > /root/epdb1.py(8)?()
     -> print final
     (Pdb) list
      3     pdb.set_trace()
      4     b = "bbb"
      5     c = "ccc"
      6     final = a + b + c
      7     pdb.set_trace()
      8  -> print final
     [EOF]
     (Pdb)

    在使用函数的情况下进行 debug

    清单 7. 使用函数的例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import pdb
     def combine(s1,s2):      # define subroutine combine, which...
        s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ...
        s3 = '"' + s3 +'"'   # encloses it in double quotes,...
        return s3            # and returns it.
     a = "aaa"
     pdb.set_trace()
     b = "bbb"
     c = "ccc"
     final = combine(a,b)
     print final

    如果直接使用 n 进行 debug 则到 final=combine(a,b) 这句的时候会将其当做普通的赋值语句处理,进入到 print final。如果想要对函数进行 debug 如何处理呢 ? 可以直接使用 s 进入函数块。函数里面的单步调试与上面的介绍类似。如果不想在函数里单步调试可以在断点处直接按 r 退出到调用的地方。

    清单 8. 对函数进行 debug
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    [root@rcc-pok-idg-2255 ~]# python epdb2.py
     > /root/epdb2.py(10)?()
     -> b = "bbb"
     (Pdb) n
     > /root/epdb2.py(11)?()
     -> c = "ccc"
     (Pdb) n
     > /root/epdb2.py(12)?()
     -> final = combine(a,b)
     (Pdb) s
     --Call--
     > /root/epdb2.py(3)combine()
     -> def combine(s1,s2):      # define subroutine combine, which...
     (Pdb) n
     > /root/epdb2.py(4)combine()
     -> s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ...
     (Pdb) list
      1     import pdb
      2
      3     def combine(s1,s2):      # define subroutine combine, which...
      4  ->     s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ...
      5         s3 = '"' + s3 +'"'   # encloses it in double quotes,...
      6         return s3            # and returns it.
      7
      8     a = "aaa"
      9     pdb.set_trace()
     10     b = "bbb"
     11     c = "ccc"
     (Pdb) n
     > /root/epdb2.py(5)combine()
     -> s3 = '"' + s3 +'"'   # encloses it in double quotes,...
     (Pdb) n
     > /root/epdb2.py(6)combine()
     -> return s3            # and returns it.
     (Pdb) n
     --Return--
     > /root/epdb2.py(6)combine()->'"aaabbbaaa"'
     -> return s3            # and returns it.
     (Pdb) n
     > /root/epdb2.py(13)?()
     -> print final
     (Pdb)

    在调试的时候动态改变值 。在调试的时候可以动态改变变量的值,具体如下实例。需要注意的是下面有个错误,原因是 b 已经被赋值了,如果想重新改变 b 的赋值,则应该使用! B。

    清单 9. 在调试的时候动态改变值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@rcc-pok-idg-2255 ~]# python epdb2.py
     > /root/epdb2.py(10)?()
     -> b = "bbb"
     (Pdb) var = "1234"
     (Pdb) b = "avfe"
     *** The specified object '= "avfe"' is not a function
     or was not found along sys.path.
     (Pdb) !b="afdfd"
     (Pdb)

    pdb 调试有个明显的缺陷就是对于多线程,远程调试等支持得不够好,同时没有较为直观的界面显示,不太适合大型的 python 项目。而在较大的 python 项目中,这些调试需求比较常见,因此需要使用更为高级的调试工具。接下来将介绍 PyCharm IDE 的调试方法 .

    使用 PyCharm 进行调试

    PyCharm 是由 JetBrains 打造的一款 Python IDE,具有语法高亮、Project 管理、代码跳转、智能提示、自动完成、单元测试、版本控制等功能,同时提供了对 Django 开发以及 Google App Engine 的支持。分为个人独立版和商业版,需要 license 支持,也可以获取免费的 30 天试用。试用版本的 Pycharm 可以在官网上下载,下载地址为:http://www.jetbrains.com/pycharm/download/index.html。 PyCharm 同时提供了较为完善的调试功能,支持多线程,远程调试等,可以支持断点设置,单步模式,表达式求值,变量查看等一系列功能。PyCharm IDE 的调试窗口布局如图 1 所示。

    图 1. PyCharm IDE 窗口布局
    图片示例

    下面结合实例讲述如何利用 PyCharm 进行多线程调试。具体调试所用的代码实例见清单 10。

    清单 10. PyCharm 调试代码实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    __author__ = 'zhangying'
     #!/usr/bin/python
     import thread
     import time
     # Define a function for the thread
     def print_time( threadName, delay):
        count = 0
        while count <  5:
            count += 1
            print "%s: %s" % ( threadName, time.ctime(time.time()) )
     def check_sum(threadName,valueA,valueB):
        print "to calculate the sum of two number her"
        result=sum(valueA,valueB)
        print "the result is" ,result;
     def sum(valueA,valueB):
        if valueA >0 and valueB>0:
            return valueA+valueB
     def readFile(threadName, filename):
        file = open(filename)
        for line in file.xreadlines():
            print line
     try:
        thread.start_new_thread( print_time, ("Thread-1", 2, ) )
        thread.start_new_thread( check_sum, ("Thread-2", 4,5, ) )
        thread.start_new_thread( readFile, ("Thread-3","test.txt",))
     except:
        print "Error: unable to start thread"
     while 1:
     #   print "end"
        pass

    在调试之前通常需要设置断点,断点可以设置在循环或者条件判断的表达式处或者程序的关键点。设置断点的方法非常简单:在代码编辑框中将光标移动到需要设置断点的行,然后直接按 Ctrl+F8 或者选择菜单"Run"->"Toggle Line Break Point",更为直接的方法是双击代码编辑处左侧边缘,可以看到出现红色的小圆点(如图 2)。当调试开始的时候,当前正在执行的代码会直接显示为蓝色。下图中设置了三个断点,蓝色高亮显示的为正在执行的代码。

    图 2. 断点设置
    图片示例 2

    表达式求值:在调试过程中有的时候需要追踪一些表达式的值来发现程序中的问题,Pycharm 支持表达式求值,可以通过选中该表达式,然后选择“Run”->”Evaluate Expression”,在出现的窗口中直接选择 Evaluate 便可以查看。

    Pychar 同时提供了 Variables 和 Watches 窗口,其中调试步骤中所涉及的具体变量的值可以直接在 variable 一栏中查看。

    图 3. 变量查看
    图片示例 3

    如果要动态的监测某个变量可以直接选中该变量并选择菜单”Run”->”Add Watch”添加到 watches 栏中。当调试进行到该变量所在的语句时,在该窗口中可以直接看到该变量的具体值。

    图 4. 监测变量
    图片示例 4

    对于多线程程序来说,通常会有多个线程,当需要 debug 的断点分别设置在不同线程对应的线程体中的时候,通常需要 IDE 有良好的多线程调试功能的支持。 Pycharm 中在主线程启动子线程的时候会自动产生一个 Dummy 开头的名字的虚拟线程,每一个 frame 对应各自的调试帧。如图 5,本实例中一共有四个线程,其中主线程生成了三个线程,分别为 Dummy-4,Dummy-5,Dummy-6. 其中 Dummy-4 对应线程 1,其余分别对应线程 2 和线程 3。

    图 5. 多线程窗口
    图片示例 5

    当调试进入到各个线程的子程序时,Frame 会自动切换到其所对应的 frame,相应的变量栏中也会显示与该过程对应的相关变量,如图 6,直接控制调试按钮,如 setp in,step over 便可以方便的进行调试。

    图 6. 子线程调试
    图片示例 6

    查看大图

    使用 PyDev 进行调试

    PyDev 是一个开源的的 plugin,它可以方便的和 Eclipse 集成,提供方便强大的调试功能。同时作为一个优秀的 Python IDE 还提供语法错误提示、源代码编辑助手、Quick Outline、Globals Browser、Hierarchy View、运行等强大功能。下面讲述如何将 PyDev 和 Eclipse 集成。在安装 PyDev 之前,需要先安装 Java 1.4 或更高版本、Eclipse 以及 Python。 第一步:启动 Eclipse,在 Eclipse 菜单栏中找到 Help 栏,选择 Help > Install New Software,并选择 Add button,添加 Ptdev 的下载站点 http://pydev.org/updates。选择 PyDev 之后完成余下的步骤便可以安装 PyDev。

    图 7. 安装 PyDev
    图片示例 7

    安装完成之后需要配置 Python 解释器,在 Eclipse 菜单栏中,选择 Window > Preferences > Pydev > Interpreter – Python。Python 安装在 C:\Python27 路径下。单击 New,选择 Python 解释器 python.exe,打开后显示出一个包含很多复选框的窗口,选择需要加入系统 PYTHONPATH 的路径,单击 OK。

    图 8. 配置 PyDev
    图片示例 8

    在配置完 Pydev 之后,可以通过在 Eclipse 菜单栏中,选择 File > New > Project > Pydev >Pydev Project,单击 Next 创建 Python 项目,下面的内容假设 python 项目已经创建,并且有个需要调试的脚本 remote.py(具体内容如下),它是一个登陆到远程机器上去执行一些命令的脚本,在运行的时候需要传入一些参数,下面将详细讲述如何在调试过程中传入参数 .

    清单 11. Pydev 调试示例代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #!/usr/bin/env python
    import os  
    def telnetdo(HOST=None, USER=None, PASS=None, COMMAND=None): #define a function
        import telnetlib, sys
        if not HOST:
            try:
                HOST = sys.argv[1]
                USER = sys.argv[2]
                PASS = sys.argv[3]
                COMMAND = sys.argv[4]
            except:
                print "Usage: remote.py host user pass command"
                return
        tn = telnetlib.Telnet() #
        try:
            tn.open(HOST)
        except:
            print "Cannot open host"
            return
        tn.read_until("login:")
        tn.write(USER + '\n')
        if PASS:
            tn.read_until("Password:")
            tn.write(PASS + '\n')
            tn.write(COMMAND + '\n')
            tn.write("exit\n")
            tmp = tn.read_all()
            tn.close()
            del tn
            return tmp
            
    if __name__ == '__main__':
        print telnetdo()

    在调试的时候有些情况需要传入一些参数,在调试之前需要进行相应的配置以便接收所需要的参数,选择需要调试的程序(本例 remote.py),该脚本在 debug 的过程中需要输入四个参数:host,user,password 以及命令。在 eclipse 的工程目录下选择需要 debug 的程序,单击右键,选择“Debug As”->“Debug Configurations”,在 Arguments Tab 页中选择“Variables”。如下 图 9 所示 .

    图 9. 配置变量
    图片示例 9

    在窗口”Select Variable”之后选择“Edit Varuables” ,出现如下窗口,在下图中选择”New” 并在弹出的窗口中输入对应的变量名和值。特别需要注意的是在值的后面一定要有空格,不然所有的参数都会被当做第一个参数读入。

    图 10. 添加具体变量
    图片示例 10

    按照以上方式依次配置完所有参数,然后在”select variable“窗口中安装参数所需要的顺序依次选择对应的变量。配置完成之后状态如下图 11 所示。

    图 11. 完成配置
    图片示例 11

    选择 Debug 便可以开始程序的调试,调试方法与 eclipse 内置的调试功能的使用相似,并且支持多线程的 debug,这方面的文章已经有很多,读者可以自行搜索阅读,或者参考”使用 Eclipse 平台进行调试“一文。

    使用日志功能达到调试的目的

    日志信息是软件开发过程中进行调试的一种非常有用的方式,特别是在大型软件开发过程需要很多相关人员进行协作的情况下。开发人员通过在代码中加入一些特定的能够记录软件运行过程中的各种事件信息能够有利于甄别代码中存在的问题。这些信息可能包括时间,描述信息以及错误或者异常发生时候的特定上下文信息。 最原始的 debug 方法是通过在代码中嵌入 print 语句,通过输出一些相关的信息来定位程序的问题。但这种方法有一定的缺陷,正常的程序输出和 debug 信息混合在一起,给分析带来一定困难,当程序调试结束不再需要 debug 输出的时候,通常没有很简单的方法将 print 的信息屏蔽掉或者定位到文件。python 中自带的 logging 模块可以比较方便的解决这些问题,它提供日志功能,将 logger 的 level 分为五个级别,可以通过 Logger.setLevel(lvl) 来设置。默认的级别为 warning。

    表 2. 日志的级别

    logging lib 包含 4 个主要对象

    • logger:logger 是程序信息输出的接口。它分散在不同的代码中使得程序可以在运行的时候记录相应的信息,并根据设置的日志级别或 filter 来决定哪些信息需要输出并将这些信息分发到其关联的 handler。常用的方法有 Logger.setLevel(),Logger.addHandler() ,Logger.removeHandler() ,Logger.addFilter() ,Logger.debug(), Logger.info(), Logger.warning(), Logger.error(),getLogger() 等。logger 支持层次继承关系,子 logger 的名称通常是父 logger.name 的方式。如果不创建 logger 的实例,则使用默认的 root logger,通过 logging.getLogger() 或者 logging.getLogger("") 得到 root logger 实例。
    • Handler:Handler 用来处理信息的输出,可以将信息输出到控制台,文件或者网络。可以通过 Logger.addHandler() 来给 logger 对象添加 handler,常用的 handler 有 StreamHandler 和 FileHandler 类。StreamHandler 发送错误信息到流,而 FileHandler 类用于向文件输出日志信息,这两个 handler 定义在 logging 的核心模块中。其他的 hander 定义在 logging.handles 模块中,如 HTTPHandler,SocketHandler。
    • Formatter:Formatter 则决定了 log 信息的格式 , 格式使用类似于 %(< dictionary key >)s 的形式来定义,如'%(asctime)s - %(levelname)s - %(message)s',支持的 key 可以在 python 自带的文档 LogRecord attributes 中查看。
    • Filter:Filter 用来决定哪些信息需要输出。可以被 handler 和 logger 使用,支持层次关系,比如如果设置了 filter 为名称为 A.B 的 logger,则该 logger 和其子 logger 的信息会被输出,如 A.B,A.B.C.
    清单 12. 日志使用示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import logging
     LOG1=logging.getLogger('b.c')
     LOG2=logging.getLogger('d.e')
     filehandler = logging.FileHandler('test.log','a')
     formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)s %(message)s')
     filehandler.setFormatter(formatter)
     filter=logging.Filter('b')
     filehandler.addFilter(filter)
     LOG1.addHandler(filehandler)
     LOG2.addHandler(filehandler)
     LOG1.setLevel(logging.INFO)
     LOG2.setLevel(logging.DEBUG)
     LOG1.debug('it is a debug info for log1')
     LOG1.info('normal infor for log1')
     LOG1.warning('warning info for log1:b.c')
     LOG1.error('error info for log1:abcd')
     LOG1.critical('critical info for log1:not worked')
     LOG2.debug('debug info for log2')
     LOG2.info('normal info for log2')
     LOG2.warning('warning info for log2')
     LOG2.error('error:b.c')
     LOG2.critical('critical')

    上例设置了 filter b,则 b.c 为 b 的子 logger,因此满足过滤条件该 logger 相关的日志信息会 被输出,而其他不满足条件的 logger(这里是 d.e)会被过滤掉。

    清单 13. 输出结果
    1
    2
    3
    4
    b.c 2011-11-25 11:07:29,733 INFO normal infor for log1
     b.c 2011-11-25 11:07:29,733 WARNING warning info for log1:b.c
     b.c 2011-11-25 11:07:29,733 ERROR error info for log1:abcd
     b.c 2011-11-25 11:07:29,733 CRITICAL critical info for log1:not worked

    logging 的使用非常简单,同时它是线程安全的,下面结合多线程的例子讲述如何使用 logging 进行 debug。

    清单 14. 多线程使用 logging
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    logging.conf
     [loggers]
     keys=root,simpleExample
     
     [handlers]
     keys=consoleHandler
     
     [formatters]
     keys=simpleFormatter
     
     [logger_root]
     level=DEBUG
     handlers=consoleHandler
     
     [logger_simpleExample]
     level=DEBUG
     handlers=consoleHandler
     qualname=simpleExample
     propagate=0
     
     [handler_consoleHandler]
     class=StreamHandler
     level=DEBUG
     formatter=simpleFormatter
     args=(sys.stdout,)
     
     [formatter_simpleFormatter]
     format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
     datefmt=
     
     code example:
     #!/usr/bin/python
     import thread
     import time
     import logging
     import logging.config
     logging.config.fileConfig('logging.conf')
     # create logger
     logger = logging.getLogger('simpleExample')
     # Define a function for the thread
     def print_time( threadName, delay):
         logger.debug('thread 1 call print_time function body')
         count = 0
         logger.debug('count:%s',count)

    总结

    全文介绍了 python 中 debug 的几种不同的方式,包括 pdb 模块、利用 PyDev 和 Eclipse 集成进行调试、PyCharm 以及 Debug 日志进行调试,希望能给相关 python 使用者一点参考。更多关于 python debugger 的资料可以参见参考资料。


    展开全文
  • PDB文件:每个开发人员都必须知道的

    原文地址:http://www.cnblogs.com/itech/archive/2011/08/15/2136522.html

    PDB Files: What Every Developer Must Know
    http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx
     
    PDB文件:每个开发人员都必须知道的
     

    一 、什么是PDB文件

    大部分的开发人员应该都知道PDB文件是用来帮助软件的调试的。但是他究竟是如何工作的呢,我们可能并不熟悉。本文描述了PDB文件的存储和内容。同时还描 述了debugger如何找到binay相应的PDB文件,以及debugger如何找到与binay对应的源代码文件。本文适用于所有的Native和 Managed的开发人员。

    在开始前,我们先定义2个术语:private build, 用来表示在开发人员自己机器上生成的build;public build,表示在公用的build机器上生成的build。private build相对来说比较简单,因为PDB和binay在相同的地方,通常地我们遇到的问题都是关于public build。 
     
    所有的的开发人员需要知道的最重要的事情是”PDB文件跟源代码同样的重要“, 没有PDB文件,你甚至不能debugging。对于public build,需要symbol server存储所有的PDB,然后当用户报告错误的时候,debugger才可以自动地找到binay相应的PDB文件, visual studio 和 windbg都知道如何访问symbol server。在将PDB和binay存储到symbol server前,还需要对PDB运行进行source indexing, source indexing的作用是将PDB和source关联起来。 
     
    接下来的部分假设有已经设置好了symbol server和source server indexing。TFS2010中可以很简单地完成对一个新的build的source indexing 和 symbol server copying。
     

    二 、PDB文件的内容

    正式开始PDB的内容,PDB不是公开的文件格式,但是Microsoft提供了API来帮助从PDB中获取数据。
     
    Native C++ PDB包含了如下的信息:
     * public,private 和static函数地址;
     * 全局变量的名字和地址;
     * 参数和局部变量的名字和在堆栈的偏移量;
     * class,structure 和数据的类型定义;
     * Frame Pointer Omission 数据,用来在x86上的native堆栈的遍历;
     * 源代码文件的名字和行数;
     
    .NET PDB只包含了2部分信息:
     * 源代码文件名字和行数;
     * 和局部变量的名字;
     * 所有的其他的数据都已经包含在了.NET Metadata中了; 
     

    三、 PDB如何工作

    当你加载一个模块到进程的地址空间的时候,debugger用2中信息来找到相应的PDB文件。第一个毫无疑问就是文件的名字,如果加载 zzz.dll,debugger则查找zzz.pdb文件。在文件名字相同的情况下debugger还通过嵌入到PDB和binay的GUID来确保 PDB和binay的真正的匹配。 所以即使没有任何的代码修改,昨天的binay和今天的PDB是不能匹配的。可以使用dempbin.exe来查看binary的GUID。
     
    在VisualStudio中的modules窗口的symbol file列可以查看PDB的load顺序。第一个搜索的路径是binary所在的路径,如果不在binary所在的路径,则查找binary中hardcode记录的build目录,例如obj\debug\*.pdb, 如果以上两个路径都没有找到PDB,则根据symbol server的设置,在本地的symbol server的cache中查找,如果在本地的symbol server的cache中没有对应的PDB,则最后才到远程的symbol server中查找。通过上面的查找顺序我们可以看出为什么public build和private build的PDB查找不会冲突。
     
    对于private build有时我们需要在别人的机器上debug的情况,需要将相应的PDB与binary一起拷贝,对于加入GAC的.NET的binary,需要将PDB文件拷贝到C:\Windows\assembly\GAC_MSIL\Example\1.0.0.0__682bc775ff82796a类似的binary所在的目录。另一个变通的方法是定义环境变量DEVPATH,从而代替使用命令GACUTIL将binary放入GAC中。在定义DEVPATH后,只需要将binary和PDB放到DEVPATH的路径,在DEVPATH下的binary相当于在GAC下。使用DEVPATH,首先需要创建目录且对当前build用户有写权限,然后创建环境变量DEVPATH且值为刚才创建的目录,然后在web.config,app.config或machine.config中开启development模式,启动对DEVPATH的使用

    <configuration>
       <runtime>
          <developmentMode developerInstallation="true"/>
       </runtime>
    </configuration> 
    在你打开了development模式后,如果DEVPATH没有定义或路径不存在的话会导致程序启动时异常"Invalid value for registry"。而且如果在machine.config中开启DEVPATH的使用会影响其他的所有的程序,所以要慎重使用machine.config。
     
    最后开发人员需要知道的是源代码信息是如何存储在PDB文件中的。对于public builds,在运行source indexing tool后,版本控制工具将代码存储到你设置的代码cache中。对于private builds,只是存储了PDB文件的全路径,例如在c:\foo下的源文件mycode.cpp,在pdb文件中存储的路径为c:\foo\mycode.cpp。对于private builds可以使用虚拟盘来增加PDB对绝对路径的依赖,例如可以使用subst.exe将源代码路径挂载为V:,在别人的机器上debug的时候也挂载V:。

     

    完!


    作者:iTech
    出处:http://itech.cnblogs.com/
    持续集成总群172758282持续集成和发布-总群
    持续集成2群567940397持续集成和发布-2
    持续集成招聘群567931165持续集成和发布-招聘
    linux讨论总群426095548www.linux6.com-总群
    linux讨论2群483205747www.linux6.com-2

    展开全文
  • PB反译工具对PDB进行反编译,非常好用PB反译工具对PDB进行反编译,非常好用
  • PDB文件详解

    万次阅读 2020-06-11 15:34:40
    PDB文件的介绍 PDB(Program Data Base),意即程序的基本数据,是VS编译链接时生成的文件。DPB文件主要存储了VS调试程序时所需要的基本信息,主要包括源文件名、变量名、函数名、FPO(帧指针)、对应的行号等等。因为...
    1. PDB文件的介绍

    PDB(Program Data Base),意即程序的基本数据,是VS编译链接时生成的文件。DPB文件主要存储了VS调试程序时所需要的基本信息,主要包括源文件名、变量名、函数名、FPO(帧指针)、对应的行号等等。因为存储的是调试信息,所以一般情况下PDB文件是在Debug模式下才会生成。

    1. PDB文件的调用过程

    模块(Module),EXE和DLL都可以称之为模块,因为它们都有自已独立的Stack,所以我们在调试程序时,可以在Call Stack窗口查看到所有调用的Module Name。并且可以右键查看相应模块的ybmol Load Information,即该模块调用的PDB文件路径的过程。

    每个模块被载入的时候,其相同名字的PDB文件同时被载入。所以Debug模式下,不仅因为代码没有优化,同时因为要载入PDB文件,所以Debug模式下的程序执行速度非常慢。

    每个模块只会生成一个相同名字的PDB文件,并且模块生成的同时,会校验PDB文件生成GUID记录在模块内。这是因为调试时,调试器强制要求每个模块必须和PDB文件保持一致。实验过程中,用之前生成的PDB文件替换当前生成的PDB文件时,Debug窗口会显示No symbols loaded. MSDN也做了相应的说明:The debugger will load only a PDB for a binary that exactly matches the PDB that was created when the binary was built.

    PDB文件中记录了源文件路径的相关信息,所以在载入PDB文件的时候,就可以将相关调试信息与源码对应。这样可以可视化的实时查看调试时的函数调用、变量值等相关信息。模块当中记录的PDB文件是绝对路径。所以只要模块在当前电脑上载入,调试器自然地会根据模块当中的路径信息找到相应PDB文件并载入。同样PDB文件中记录的源文件路径也是绝对路径,所以PDB文件只要在当前电脑上载入,调试进入相应模块时,都能够匹配到记录的源文件,然后可视化地查看相应信息。

    如果源文件找不到,那么依然能够查看调试信息,只是这个时候只能查看汇编代码,不能通过源文件可视化查看信息。一般情况下,绝大多数C++程序员不具备阅读汇编代码的能力。所以完全通过PDB文件调试,意义与作用均没有多大。如果要让其他人能够调试自已的代码,PDB文件和源码都应该提供,只提供PDB文件的意义不大。如果确实有类似的需求,可以保留相应生成的PDB文件。微软的很多库默认是不提供PDB文件的,但是近来微软逐渐开放了一些库的PDB文件。

    1. VS搜索PDB文件的路径顺序

    MSDN中详细的讲述:

    1. The Visual Studio debugger uses the path to the PDB in the EXE or DLL file to find the project.PDB file.

    2. If the debugger cannot find the PDB file at that location or if the path is invalid (for example, if the project was moved to another computer), the debugger searches the path containing the EXE.

    3. the symbol paths specified in the Options dialog box (Debugging folder, Symbols node).

    1是默认当前路径,2是编译链接时记录在模块当中的路径。现在重点说3,即设置符号文件路径。

    通过Options->Debuggin->Symbols或在Call Stack窗口右键找到Symbol Settings打开下面的窗口。

    我将PDF的生成路径调整到D:\,调试时将PFB文件剪切到D:\Other目录。

     

    然后调试进入dll模块时,右键在Call Stack对应的Module上选择查看Symbol Load Information.

     

    通过上图即可以看到VS加载PDB文件的顺序,这与MSDN中介绍的是一样的。

    Symbol Settings窗口里,还可以从服务器上缓存符号文件,可是我试了很多方式,均没有成功。

    为什么讲这个设置符号文件呢?因为有时候,有些项目非常庞大,并且代码是共享的,所以代码会放到服务器上。很多很大PDB调试文件,如果拷贝到本地电脑上比较麻烦。这个时候,就可以指定网络路径,直接通过网络路径调试。

    1. 静态库的PDB文件

    静态库也有自已的PDB文件,只不过其名字是VC80.PDB/VC100.PDB这样的名字。静态库的PDB文件会在链接时合并到EXE/DLL的PDB文件中去。如果生成的静态库lib里有记录相应的PDB文件,却又没有相应的PDB文件,那么静态库链接成EXE/DLL时就会报警告找不到静态库对应的PDB文件。所以如果静态库作第三方库发布时,可以不用生成PDB文件,这样调用者链接时就不会报警告。

    通过PDB文件可以获取函数名及对应的代码行号,更多信息可以参考微软给的示例。

    更多详细资料见:https://msdn.microsoft.com/zh-cn/library/2008hf0e

    展开全文
  • Pdb & Pycharm

    2015-11-25 21:52:17
    pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些

    http://www.ibm.com/developerworks/cn/linux/l-cn-pythondebugger/index.html


    使用 pdb 进行调试

    pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些常用的调试命令,详情见表 1。

    表 1. pdb 常用命令
    命令 解释
    break 或 b 设置断点 设置断点
    continue 或 c 继续执行程序
    list 或 l 查看当前行的代码段
    step 或 s  进入函数
    return 或 r 执行代码直到从当前函数返回
    exit 或 q 中止并退出
    next 或 n  执行下一行
    pp  打印变量的值
    help 帮助

    下面结合具体的实例讲述如何使用 pdb 进行调试。

    清单 1. 测试代码示例
    import pdb 
     a = "aaa"
     pdb.set_trace() 
     b = "bbb"
     c = "ccc"
     final = a + b + c 
     print final

    开始调试:直接运行脚本,会停留在 pdb.set_trace() 处,选择 n+enter 可以执行当前的 statement。在第一次按下了 n+enter 之后可以直接按 enter 表示重复执行上一条 debug 命令。

    清单 2. 利用 pdb 调试
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py 
     > /root/epdb1.py(4)?() 
     -> b = "bbb"
     (Pdb) n 
     > /root/epdb1.py(5)?() 
     -> c = "ccc"
     (Pdb) 
     > /root/epdb1.py(6)?() 
     -> final = a + b + c 
     (Pdb) list 
      1     import pdb 
      2     a = "aaa"
      3     pdb.set_trace() 
      4     b = "bbb"
      5     c = "ccc"
      6  -> final = a + b + c 
      7     print final 
     [EOF] 
     (Pdb) 
     [EOF] 
     (Pdb) n 
     > /root/epdb1.py(7)?() 
     -> print final 
     (Pdb)

    退出 debug:使用 quit 或者 q 可以退出当前的 debug,但是 quit 会以一种非常粗鲁的方式退出程序,其结果是直接 crash。

    清单 3. 退出 debug
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py 
     > /root/epdb1.py(4)?() 
     -> b = "bbb"
     (Pdb) n 
     > /root/epdb1.py(5)?() 
     -> c = "ccc"
     (Pdb) q 
     Traceback (most recent call last): 
      File "epdb1.py", line 5, in ? 
        c = "ccc"
      File "epdb1.py", line 5, in ? 
        c = "ccc"
      File "/usr/lib64/python2.4/bdb.py", line 48, in trace_dispatch 
        return self.dispatch_line(frame) 
      File "/usr/lib64/python2.4/bdb.py", line 67, in dispatch_line 
        if self.quitting: raise BdbQuit 
     bdb.BdbQuit

    打印变量的值:如果需要在调试过程中打印变量的值,可以直接使用 p 加上变量名,但是需要注意的是打印仅仅在当前的 statement 已经被执行了之后才能看到具体的值,否则会报 NameError: < exceptions.NameError … ....> 错误。

    清单 4. debug 过程中打印变量
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py 
     > /root/epdb1.py(4)?() 
     -> b = "bbb"
     (Pdb) n 
     > /root/epdb1.py(5)?() 
     -> c = "ccc"
     (Pdb) p b 
    'bbb'
     (Pdb) 
    'bbb'
     (Pdb) n 
     > /root/epdb1.py(6)?() 
     -> final = a + b + c 
     (Pdb) p c 
    'ccc'
     (Pdb) p final 
     *** NameError: <exceptions.NameError instance at 0x1551b710 > 
     (Pdb) n 
     > /root/epdb1.py(7)?() 
     -> print final 
     (Pdb) p final 
    'aaabbbccc'
     (Pdb)

    使用 c 可以停止当前的 debug 使程序继续执行。如果在下面的程序中继续有 set_statement() 的申明,则又会重新进入到 debug 的状态,读者可以在代码 print final 之前再加上 set_trace() 验证。

    清单 5. 停止 debug 继续执行程序
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py 
     > /root/epdb1.py(4)?() 
     -> b = "bbb"
     (Pdb) n 
     > /root/epdb1.py(5)?() 
     -> c = "ccc"
     (Pdb) c 
     aaabbbccc

    显示代码:在 debug 的时候不一定能记住当前的代码块,如要要查看具体的代码块,则可以通过使用 list 或者 l 命令显示。list 会用箭头 -> 指向当前 debug 的语句。

    清单 6. debug 过程中显示代码
    [root@rcc-pok-idg-2255 ~]#  python epdb1.py 
     > /root/epdb1.py(4)?() 
     -> b = "bbb"
     (Pdb) list 
      1     import pdb 
      2     a = "aaa"
      3     pdb.set_trace() 
      4  -> b = "bbb"
      5     c = "ccc"
      6     final = a + b + c 
      7     pdb.set_trace() 
      8     print final 
     [EOF] 
     (Pdb) c 
     > /root/epdb1.py(8)?() 
     -> print final 
     (Pdb) list 
      3     pdb.set_trace() 
      4     b = "bbb"
      5     c = "ccc"
      6     final = a + b + c 
      7     pdb.set_trace() 
      8  -> print final 
     [EOF] 
     (Pdb)

    在使用函数的情况下进行 debug

    清单 7. 使用函数的例子
    import pdb 
     def combine(s1,s2):      # define subroutine combine, which... 
        s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ... 
        s3 = '"' + s3 +'"'   # encloses it in double quotes,... 
        return s3            # and returns it. 
     a = "aaa"
     pdb.set_trace() 
     b = "bbb"
     c = "ccc"
     final = combine(a,b) 
     print final

    如果直接使用 n 进行 debug 则到 final=combine(a,b) 这句的时候会将其当做普通的赋值语句处理,进入到 print final。如果想要对函数进行 debug 如何处理呢 ? 可以直接使用 s 进入函数块。函数里面的单步调试与上面的介绍类似。如果不想在函数里单步调试可以在断点处直接按 r 退出到调用的地方。

    清单 8. 对函数进行 debug
    [root@rcc-pok-idg-2255 ~]# python epdb2.py 
     > /root/epdb2.py(10)?() 
     -> b = "bbb"
     (Pdb) n 
     > /root/epdb2.py(11)?() 
     -> c = "ccc"
     (Pdb) n 
     > /root/epdb2.py(12)?() 
     -> final = combine(a,b) 
     (Pdb) s 
     --Call-- 
     > /root/epdb2.py(3)combine() 
     -> def combine(s1,s2):      # define subroutine combine, which... 
     (Pdb) n 
     > /root/epdb2.py(4)combine() 
     -> s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ... 
     (Pdb) list 
      1     import pdb 
      2 
      3     def combine(s1,s2):      # define subroutine combine, which... 
      4  ->     s3 = s1 + s2 + s1    # sandwiches s2 between copies of s1, ... 
      5         s3 = '"' + s3 +'"'   # encloses it in double quotes,... 
      6         return s3            # and returns it. 
      7 
      8     a = "aaa"
      9     pdb.set_trace() 
     10     b = "bbb"
     11     c = "ccc"
     (Pdb) n 
     > /root/epdb2.py(5)combine() 
     -> s3 = '"' + s3 +'"'   # encloses it in double quotes,... 
     (Pdb) n 
     > /root/epdb2.py(6)combine() 
     -> return s3            # and returns it. 
     (Pdb) n 
     --Return-- 
     > /root/epdb2.py(6)combine()->'"aaabbbaaa"'
     -> return s3            # and returns it. 
     (Pdb) n 
     > /root/epdb2.py(13)?() 
     -> print final 
     (Pdb)

    在调试的时候动态改变值 。在调试的时候可以动态改变变量的值,具体如下实例。需要注意的是下面有个错误,原因是 b 已经被赋值了,如果想重新改变 b 的赋值,则应该使用! B。

    清单 9. 在调试的时候动态改变值
    [root@rcc-pok-idg-2255 ~]# python epdb2.py 
     > /root/epdb2.py(10)?() 
     -> b = "bbb"
     (Pdb) var = "1234"
     (Pdb) b = "avfe"
     *** The specified object '= "avfe"' is not a function 
     or was not found along sys.path. 
     (Pdb) !b="afdfd"
     (Pdb)

    pdb 调试有个明显的缺陷就是对于多线程,远程调试等支持得不够好,同时没有较为直观的界面显示,不太适合大型的 python 项目。而在较大的 python 项目中,这些调试需求比较常见,因此需要使用更为高级的调试工具。接下来将介绍 PyCharm IDE 的调试方法 .

    使用 PyCharm 进行调试

    PyCharm 是由 JetBrains 打造的一款 Python IDE,具有语法高亮、Project 管理、代码跳转、智能提示、自动完成、单元测试、版本控制等功能,同时提供了对 Django 开发以及 Google App Engine 的支持。分为个人独立版和商业版,需要 license 支持,也可以获取免费的 30 天试用。试用版本的 Pycharm 可以在官网上下载,下载地址为:http://www.jetbrains.com/pycharm/download/index.html。 PyCharm 同时提供了较为完善的调试功能,支持多线程,远程调试等,可以支持断点设置,单步模式,表达式求值,变量查看等一系列功能。PyCharm IDE 的调试窗口布局如图 1 所示。

    图 1. PyCharm IDE 窗口布局
    图片示例

    下面结合实例讲述如何利用 PyCharm 进行多线程调试。具体调试所用的代码实例见清单 10。

    清单 10. PyCharm 调试代码实例
    __author__ = 'zhangying'
     #!/usr/bin/python 
     import thread 
     import time 
     # Define a function for the thread 
     def print_time( threadName, delay): 
        count = 0 
        while count <  5: 
            count += 1 
            print "%s: %s" % ( threadName, time.ctime(time.time()) ) 
     def check_sum(threadName,valueA,valueB): 
        print "to calculate the sum of two number her"
        result=sum(valueA,valueB) 
        print "the result is" ,result; 
     def sum(valueA,valueB): 
        if valueA >0 and valueB>0: 
            return valueA+valueB 
     def readFile(threadName, filename): 
        file = open(filename) 
        for line in file.xreadlines(): 
            print line 
     try: 
        thread.start_new_thread( print_time, ("Thread-1", 2, ) ) 
        thread.start_new_thread( check_sum, ("Thread-2", 4,5, ) ) 
        thread.start_new_thread( readFile, ("Thread-3","test.txt",)) 
     except: 
        print "Error: unable to start thread"
     while 1: 
     # 	 print "end"
        pass

    在调试之前通常需要设置断点,断点可以设置在循环或者条件判断的表达式处或者程序的关键点。设置断点的方法非常简单:在代码编辑框中将光标移动到需要设置断点的行,然后直接按 Ctrl+F8 或者选择菜单"Run"->"Toggle Line Break Point",更为直接的方法是双击代码编辑处左侧边缘,可以看到出现红色的小圆点(如图 2)。当调试开始的时候,当前正在执行的代码会直接显示为蓝色。下图中设置了三个断点,蓝色高亮显示的为正在执行的代码。

    图 2. 断点设置
    图片示例 2

    表达式求值:在调试过程中有的时候需要追踪一些表达式的值来发现程序中的问题,Pycharm 支持表达式求值,可以通过选中该表达式,然后选择“Run”->”Evaluate Expression”,在出现的窗口中直接选择 Evaluate 便可以查看。

    Pychar 同时提供了 Variables 和 Watches 窗口,其中调试步骤中所涉及的具体变量的值可以直接在 variable 一栏中查看。

    图 3. 变量查看
    图片示例 3

    如果要动态的监测某个变量可以直接选中该变量并选择菜单”Run”->”Add Watch”添加到 watches 栏中。当调试进行到该变量所在的语句时,在该窗口中可以直接看到该变量的具体值。

    图 4. 监测变量
    图片示例 4

    对于多线程程序来说,通常会有多个线程,当需要 debug 的断点分别设置在不同线程对应的线程体中的时候,通常需要 IDE 有良好的多线程调试功能的支持。 Pycharm 中在主线程启动子线程的时候会自动产生一个 Dummy 开头的名字的虚拟线程,每一个 frame 对应各自的调试帧。如图 5,本实例中一共有四个线程,其中主线程生成了三个线程,分别为 Dummy-4,Dummy-5,Dummy-6. 其中 Dummy-4 对应线程 1,其余分别对应线程 2 和线程 3。

    图 5. 多线程窗口
    图片示例 5

    当调试进入到各个线程的子程序时,Frame 会自动切换到其所对应的 frame,相应的变量栏中也会显示与该过程对应的相关变量,如图 6,直接控制调试按钮,如 setp in,step over 便可以方便的进行调试。

    图 6. 子线程调试
    图片示例 6

    查看大图

    使用 PyDev 进行调试

    PyDev 是一个开源的的 plugin,它可以方便的和 Eclipse 集成,提供方便强大的调试功能。同时作为一个优秀的 Python IDE 还提供语法错误提示、源代码编辑助手、Quick Outline、Globals Browser、Hierarchy View、运行等强大功能。下面讲述如何将 PyDev 和 Eclipse 集成。在安装 PyDev 之前,需要先安装 Java 1.4 或更高版本、Eclipse 以及 Python。 第一步:启动 Eclipse,在 Eclipse 菜单栏中找到 Help 栏,选择 Help > Install New Software,并选择 Add button,添加 Ptdev 的下载站点 http://pydev.org/updates。选择 PyDev 之后完成余下的步骤便可以安装 PyDev。

    图 7. 安装 PyDev
    图片示例 7

    安装完成之后需要配置 Python 解释器,在 Eclipse 菜单栏中,选择 Window > Preferences > Pydev > Interpreter – Python。Python 安装在 C:\Python27 路径下。单击 New,选择 Python 解释器 python.exe,打开后显示出一个包含很多复选框的窗口,选择需要加入系统 PYTHONPATH 的路径,单击 OK。

    图 8. 配置 PyDev
    图片示例 8

    在配置完 Pydev 之后,可以通过在 Eclipse 菜单栏中,选择 File > New > Project > Pydev >Pydev Project,单击 Next 创建 Python 项目,下面的内容假设 python 项目已经创建,并且有个需要调试的脚本 remote.py(具体内容如下),它是一个登陆到远程机器上去执行一些命令的脚本,在运行的时候需要传入一些参数,下面将详细讲述如何在调试过程中传入参数 .

    清单 11. Pydev 调试示例代码
     #!/usr/bin/env python 
     import os 	 
     def telnetdo(HOST=None, USER=None, PASS=None, COMMAND=None): #define a function 
    	 import telnetlib, sys 
    	 if not HOST: 
    		 try: 
    			 HOST = sys.argv[1] 
    			 USER = sys.argv[2] 
    			 PASS = sys.argv[3] 
    			 COMMAND = sys.argv[4] 
    		 except: 
    			 print "Usage: remote.py host user pass command"
    			 return 
    	 tn = telnetlib.Telnet() # 
    	 try: 
    		 tn.open(HOST) 
    	 except: 
    		 print "Cannot open host"
    		 return 
    	 tn.read_until("login:") 
    	 tn.write(USER + '\n') 
    	 if PASS: 
    		 tn.read_until("Password:") 
    		 tn.write(PASS + '\n') 
    		 tn.write(COMMAND + '\n') 
    		 tn.write("exit\n") 
    		 tmp = tn.read_all() 
    		 tn.close() 
    		 del tn 
    		 return tmp 
    		
     if __name__ == '__main__': 
    	 print telnetdo()

    在调试的时候有些情况需要传入一些参数,在调试之前需要进行相应的配置以便接收所需要的参数,选择需要调试的程序(本例 remote.py),该脚本在 debug 的过程中需要输入四个参数:host,user,password 以及命令。在 eclipse 的工程目录下选择需要 debug 的程序,单击右键,选择“Debug As”->“Debug Configurations”,在 Arguments Tab 页中选择“Variables”。如下 图 9 所示 .

    图 9. 配置变量
    图片示例 9

    在窗口”Select Variable”之后选择“Edit Varuables” ,出现如下窗口,在下图中选择”New” 并在弹出的窗口中输入对应的变量名和值。特别需要注意的是在值的后面一定要有空格,不然所有的参数都会被当做第一个参数读入。

    图 10. 添加具体变量
    图片示例 10

    按照以上方式依次配置完所有参数,然后在”select variable“窗口中安装参数所需要的顺序依次选择对应的变量。配置完成之后状态如下图 11 所示。

    图 11. 完成配置
    图片示例 11

    选择 Debug 便可以开始程序的调试,调试方法与 eclipse 内置的调试功能的使用相似,并且支持多线程的 debug,这方面的文章已经有很多,读者可以自行搜索阅读,或者参考”使用 Eclipse 平台进行调试“一文。

    使用日志功能达到调试的目的

    日志信息是软件开发过程中进行调试的一种非常有用的方式,特别是在大型软件开发过程需要很多相关人员进行协作的情况下。开发人员通过在代码中加入一些特定的能够记录软件运行过程中的各种事件信息能够有利于甄别代码中存在的问题。这些信息可能包括时间,描述信息以及错误或者异常发生时候的特定上下文信息。 最原始的 debug 方法是通过在代码中嵌入 print 语句,通过输出一些相关的信息来定位程序的问题。但这种方法有一定的缺陷,正常的程序输出和 debug 信息混合在一起,给分析带来一定困难,当程序调试结束不再需要 debug 输出的时候,通常没有很简单的方法将 print 的信息屏蔽掉或者定位到文件。python 中自带的 logging 模块可以比较方便的解决这些问题,它提供日志功能,将 logger 的 level 分为五个级别,可以通过 Logger.setLevel(lvl) 来设置。默认的级别为 warning。

    表 2. 日志的级别
    Level 使用情形
    DEBUG 详细的信息,在追踪问题的时候使用
    INFO 正常的信息
    WARNING 一些不可预见的问题发生,或者将要发生,如磁盘空间低等,但不影响程序的运行
    ERROR 由于某些严重的问题,程序中的一些功能受到影响
    CRITICAL 严重的错误,或者程序本身不能够继续运行

    logging lib 包含 4 个主要对象

    • logger:logger 是程序信息输出的接口。它分散在不同的代码中使得程序可以在运行的时候记录相应的信息,并根据设置的日志级别或 filter 来决定哪些信息需要输出并将这些信息分发到其关联的 handler。常用的方法有 Logger.setLevel(),Logger.addHandler() ,Logger.removeHandler() ,Logger.addFilter() ,Logger.debug(), Logger.info(), Logger.warning(), Logger.error(),getLogger() 等。logger 支持层次继承关系,子 logger 的名称通常是父 logger.name 的方式。如果不创建 logger 的实例,则使用默认的 root logger,通过 logging.getLogger() 或者 logging.getLogger("") 得到 root logger 实例。
    • Handler:Handler 用来处理信息的输出,可以将信息输出到控制台,文件或者网络。可以通过 Logger.addHandler() 来给 logger 对象添加 handler,常用的 handler 有 StreamHandler 和 FileHandler 类。StreamHandler 发送错误信息到流,而 FileHandler 类用于向文件输出日志信息,这两个 handler 定义在 logging 的核心模块中。其他的 hander 定义在 logging.handles 模块中,如 HTTPHandler,SocketHandler。
    • Formatter:Formatter 则决定了 log 信息的格式 , 格式使用类似于 %(< dictionary key >)s 的形式来定义,如'%(asctime)s - %(levelname)s - %(message)s',支持的 key 可以在 python 自带的文档 LogRecord attributes 中查看。
    • Filter:Filter 用来决定哪些信息需要输出。可以被 handler 和 logger 使用,支持层次关系,比如如果设置了 filter 为名称为 A.B 的 logger,则该 logger 和其子 logger 的信息会被输出,如 A.B,A.B.C.
    清单 12. 日志使用示例
    import logging 
     LOG1=logging.getLogger('b.c') 
     LOG2=logging.getLogger('d.e') 
     filehandler = logging.FileHandler('test.log','a') 
     formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)s %(message)s') 
     filehandler.setFormatter(formatter) 
     filter=logging.Filter('b') 
     filehandler.addFilter(filter) 
     LOG1.addHandler(filehandler) 
     LOG2.addHandler(filehandler) 
     LOG1.setLevel(logging.INFO) 
     LOG2.setLevel(logging.DEBUG) 
     LOG1.debug('it is a debug info for log1') 
     LOG1.info('normal infor for log1') 
     LOG1.warning('warning info for log1:b.c') 
     LOG1.error('error info for log1:abcd') 
     LOG1.critical('critical info for log1:not worked') 
     LOG2.debug('debug info for log2') 
     LOG2.info('normal info for log2') 
     LOG2.warning('warning info for log2') 
     LOG2.error('error:b.c') 
     LOG2.critical('critical')

    上例设置了 filter b,则 b.c 为 b 的子 logger,因此满足过滤条件该 logger 相关的日志信息会 被输出,而其他不满足条件的 logger(这里是 d.e)会被过滤掉。

    清单 13. 输出结果
    b.c 2011-11-25 11:07:29,733 INFO normal infor for log1 
     b.c 2011-11-25 11:07:29,733 WARNING warning info for log1:b.c 
     b.c 2011-11-25 11:07:29,733 ERROR error info for log1:abcd 
     b.c 2011-11-25 11:07:29,733 CRITICAL critical info for log1:not worked

    logging 的使用非常简单,同时它是线程安全的,下面结合多线程的例子讲述如何使用 logging 进行 debug。

    清单 14. 多线程使用 logging
    logging.conf 
     [loggers] 
     keys=root,simpleExample 
    
     [handlers] 
     keys=consoleHandler 
    
     [formatters] 
     keys=simpleFormatter 
    
     [logger_root] 
     level=DEBUG 
     handlers=consoleHandler 
    
     [logger_simpleExample] 
     level=DEBUG 
     handlers=consoleHandler 
     qualname=simpleExample 
     propagate=0 
    
     [handler_consoleHandler] 
     class=StreamHandler 
     level=DEBUG 
     formatter=simpleFormatter 
     args=(sys.stdout,) 
    
     [formatter_simpleFormatter] 
     format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 
     datefmt= 
    
     code example: 
     #!/usr/bin/python 
     import thread 
     import time 
     import logging 
     import logging.config 
     logging.config.fileConfig('logging.conf') 
     # create logger 
     logger = logging.getLogger('simpleExample') 
     # Define a function for the thread 
     def print_time( threadName, delay): 
    	 logger.debug('thread 1 call print_time function body') 
    	 count = 0 
    	 logger.debug('count:%s',count)

    总结

    全文介绍了 python 中 debug 的几种不同的方式,包括 pdb 模块、利用 PyDev 和 Eclipse 集成进行调试、PyCharm 以及 Debug 日志进行调试,希望能给相关 python 使用者一点参考。更多关于 python debugger 的资料可以参见参考资料。

    展开全文
  • Python+Pycharm使用opencv

    万次阅读 2017-12-03 13:55:16
    在这个配置过程中,遇到了不少的问题,于是就写了这篇博文,希望可以帮到遇到相同问题的人。 主要步骤:  1.Anaconda2的下载:传送门  2.opencv320库下载:传送门  3.pycharm中配置解析器  ...
  • Pycharm调试高效,还是pdb调试高效? (在服务端) python 3.9k次浏览 问题对人有帮助,内容完整,我也想知道答案0问题没有实际价值,缺少关键内容,没有改进余地 [问题描述]以前均是使用Pycharm调试...
  • 在python调用opencv库,使用pycharm环境

    万次阅读 2019-03-26 13:36:04
    我这只学术的小小只白,竟然也开始写博客了。因为配置opencv的库用了很长的时间,三天,遇到很多问题,一个个解决后,才决定分享出来,想要用pythont调用opencv库的少走些弯路。 首先安装python,有2.X和3.X,两个...
  • pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些常用的调试命令,
  • PDB 文件

    千次阅读 2018-10-07 23:35:06
    PDB 文件 什么是 PDB 文件 PDB (Program Data Base) 即程序的基本数据,是 VS 编译链接时生成的文件,每个程序集(EXE 或 DLL)都有一个与之对应的 PDB 文件。DPB 文件主要存储了 VS 调试程序时所需要的基本信息...
  • Python 必备 debug 神器:pdb

    千次阅读 2019-06-07 22:05:43
    首先,介绍一下 pdb 调试,pdb 是 python 的一个内置模块,用于命令行来调试 Python 代码。或许你会说,现在用 Pycharm 等编辑器来调试代码很方便,为啥要用命令行呢?这个问题,我曾经也这么想,直到有一次,代码...
  • 使用 pdb 进行调试

    万次阅读 2016-08-26 09:50:14
    pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。pdb 提供了一些常用的调试命令,详
  • PDB文件:每个开发人员都必须知道的   一 什么是PDB文件 大部分的开发人员应该都知道PDB文件是用来帮助软件的调试的。但是他究竟是如何工作的呢,我们可能并不熟悉。本文描述了PDB文件的存储和内容。同时还...
  • pdb和pdm文件有什么区别?

    万次阅读 2015-05-27 17:12:19
    早期的PowerBuilder编译生成的动态链接库的后缀名是PDB,  但后来PowerDesigner出来后,它的物理模型图(数据表结构)文件后缀名是PDM,但同时它会生成这个文件的备份文件,就是后缀名为PDB的文件。附文件名意思:...
  • 京麦的pdb文件都在一个目录下面,比如workStation中的pdb文件都在如下目录下:
  • warning LNK4099: 未找到 PDB“vc120.pdb

    万次阅读 2015-11-26 21:46:30
    warning LNK4099: 未找到 PDB“vc120.pdb”的解决方法
  • 前几天发布项目,有时候就发布那几个dll,但是一个dll同时还有一个pdb文件,而且pdb文件貌似还挺大。全选的话,要复制多一份pdb文件到服务器,上传时间长。不全选,就要按住ctrl,再点选每个dll,每次都麻烦得很呀,...
  • VS2013让Release程序生成pdb文件

    万次阅读 2016-05-16 22:19:14
    vc2012报错了: 1>c:\program files (x86)\microsoft visual studio11.0\vc\include\xutility(2176): error C4996: 'std::_Copy_impl': Function callwith p
  • vs2017无法查找或打开 pdb 文件

    万次阅读 热门讨论 2017-08-27 13:20:41
    解决方法 步骤1.勾选 工具->选项->调试->常规->启动源服务器支持; 启动源服务器支持下面的三栏不用勾选; ...确定后弹出对话框选 是;...步骤2....工具->选项->调试->符号->Microsoft符号服务器;...步骤3....
  • 【C++学习之路】解决:无法查找或打开 PDB 文件

    万次阅读 多人点赞 2016-07-28 15:51:56
    无法查找或打开 PDB 文件。 已加载“C:\Windows\SysWOW64\kernel32.dll”。已加载符号。 已加载“C:\Windows\SysWOW64\KernelBase.dll”。无法查找或打开 PDB 文件。 已加载“C:\Windows\SysWOW64\msvcr120d.dll”...
1 2 3 4 5 ... 20
收藏数 39,101
精华内容 15,640
关键字:

pdb