如何在到达给定断点之前自动打印 GDB 中的每个执行行? [英] How to print every executed line in GDB automatically until a given breakpoint is reached?

查看:27
本文介绍了如何在到达给定断点之前自动打印 GDB 中的每个执行行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够在 GDB 中设置一个断点,并让它运行到那个点 - 在这个过程中,打印出它逐步通过"的行.

I would like to be able to set a breakpoint in GDB, and have it run to that point - and in the process, print out lines it has "stepped through".

这是一个示例,基于这个简单的文件,其中包含一个 main 和一个函数,每个文件都有两个断点:

Here is an example, based on this simple file with a main and a function, and two breakpoints for each:

$ cat > test.c <<EOF
#include "stdio.h"

int count=0;

void doFunction(void) {
  // two steps forward
  count += 2;
  // one step back
  count--;
}

int main(void) {
  // some pointless init commands;
  count = 1;
  count += 2;
  count = 0;
  //main loop
  while(1) {
    doFunction();
    printf("%d
", count);
  }
}
EOF

$ gcc -g -Wall test.c -o test.exe
$ chmod +x test.exe
$ gdb -se test.exe
...
Reading symbols from /path/to/test.exe...done.
(gdb) b main
Breakpoint 1 at 0x80483ec: file test.c, line 14.
(gdb) b doFunction
Breakpoint 2 at 0x80483c7: file test.c, line 7.

要开始会话,我需要运行 (r) 程序,然后程序会在第一个断点 (main) 处停止:

To start the session, I need to run (r) the program, which will then stop at first breakpoint (main):

(gdb) r
Starting program: /path/to/test.exe 

Breakpoint 1, main () at test.c:14
14    count = 1;
(gdb) 

此时 - 例如,我可以点击 continue (c);并且该过程将运行,不输出任何内容,并在请求的行处中断:

At this point - I can, for instance, hit continue (c); and the process will run through, not outputing anything, and break at the requested line:

(gdb) c
Continuing.

Breakpoint 2, doFunction () at test.c:7
7     count += 2;
(gdb)

另一方面,我可以使用 step (s) 或 next (n) 来逐行执行,而不是 continue;例如:

On the other hand, instead of continue - I can go line by line, either by using step (s) or next (n); for instance:

14    count = 1;
(gdb) n
15    count += 2;
(gdb) s
16    count = 0;
(gdb) s
19      doFunction();
(gdb) s

Breakpoint 2, doFunction () at test.c:7
7     count += 2;
(gdb) s
9     count--;
(gdb) s
10  }
(gdb) s
main () at test.c:20
20      printf("%d
", count);
(gdb) s
...
(gdb) s
_IO_vfprintf_internal (s=Cannot access memory at address 0xe5853361
) at vfprintf.c:210
210 vfprintf.c: No such file or directory.
    in vfprintf.c
(gdb) s
245 in vfprintf.c
(gdb) s
210 in vfprintf.c
(gdb) n
245 in vfprintf.c
...
(gdb) n
2006    in vfprintf.c
(gdb) n
__printf (format=0x80484f0 "%d
") at printf.c:39
39  printf.c: No such file or directory.
    in printf.c
(gdb) n
main () at test.c:21
21    }
(gdb) n
19      doFunction();
(gdb) n

Breakpoint 2, doFunction () at test.c:7
7     count += 2;
(gdb) 

无论如何,我知道我可以按住 Enter,最后输入的命令(步骤或下一步)将重复(在第二种情况下留下更长的会话,以显示'next' 保持在同一级别,'step' 步入被调用的函数).但是,可以看出,根据是 step 还是 next 运行,可能需要一段时间才能达到结果 - 所以,我不想坐 10 分钟,我的手卡在 Enter 按钮上 :)

Anyways, I am aware that I can keep Enter pressed, and the last entered command (step or next) will repeat (left a bit longer session in the second case, to show that 'next' remains on same level, 'step' steps inside the functions being called). However, as it can be seen, depending on whether step or next runs, it may take a while until a result is reached - and so, I don't want to sit for 10 minutes with my hand stuck on the Enter button :)

所以,我的问题是——我能否以某种方式指示 gdb 在没有用户进一步干预的情况下运行到断点 2"——同时打印出它经过的行,就好像步骤(或下一步)是按下了吗?

So, my question is - can I somehow instruct gdb to run to 'breakpoint 2' without further user intervention - while printing out the lines it goes through, as if step (or next) was pressed?

推荐答案

嗯,这并不容易 - 但我想我有点明白了 :) 我经历了一堆失败的尝试(发布 这里);相关代码如下.

Well, this wasn't easy - but I think I somewhat got it :) I went through a bunch of failed attempts (posted here); relevant code is below.

基本上,直到断点的下一步/步骤"中的问题是,如果调试器停止(在某个步骤),如何确定您是否打开"断点.另请注意,我使用 GDB 7.2-1ubuntu11(当前适用于 Ubuntu 11.04).所以,它是这样的:

Basically, the problem in a "next/step until breakpoint" is how to determine whether you're "on" a breakpoint or not, if the debugger is stopped (at a step). Note also I use GDB 7.2-1ubuntu11 (current for Ubuntu 11.04). So, it went like this:

  • 我首先发现了 便利变量,并认为 - 在那里是程序计数器等可用的,必须有一些 GDB 便利变量给出断点"状态,并且可以直接在 GDB 脚本中使用.但是,在浏览了 GDB 参考索引 之后,我根本找不到任何这样的变量(我的尝试在 nub.gdb)
  • 在缺少这种断点状态"内部变量的情况下,唯一要做的就是将 GDB 的 ('stdout') 命令行输出(响应命令)捕获为字符串,并解析它(寻找断点")
  • 然后,我发现了 Python API 到 GDB,以及 gdb.execute("CMDSTR", toString=True) 命令 - 这似乎正是捕获输出所需要的:默认情况下,任何输出都会产生by command被发送到gdb的标准输出.如果to_string参数为True,那么输出将被gdb.execute收集并作为字符串返回[1]"!
    • 所以,首先我尝试制作一个脚本(pygdb-nub.py,gdbwrap) 将利用 gdb.execute 以推荐的方式;在这里失败 - 因为这个:
      • I first found about Convenience Variables, and thought - given there are program counters and such available, there must be some GDB convenience variable that gives the "breakpoint" status, and can be used directly in a GDB script. After looking through GDB reference Index for a while, however, I simply cannot find any such variables (my attempts are in nub.gdb)
      • In lack of such a "breakpoint status" internal variable - the only thing left to do, is to capture the ('stdout') command line output of GDB (in response to commands) as a string, and parse it (looking for "Breakpoint")
      • Then, I found out about Python API to GDB, and the gdb.execute("CMDSTR", toString=True) command - which is seemingly exactly what is needed to capture the output: "By default, any output produced by command is sent to gdb's standard output. If the to_string parameter is True, then output will be collected by gdb.execute and returned as a string[1]"!
        • So, first I tried to make a script (pygdb-nub.py,gdbwrap) that would utilize gdb.execute in the recommended manner; failed here - because of this:
          • Bug 627506 – python: gdb.execute([...], to_string=True) partly prints to stdout/stderr
          • Bug 10808 – Allow GDB/Python API to capture and store GDB output

          最后,可行的方法是:临时将 GDB 输出从 gdb.execute 重定向到 RAM 中的日志文件(Linux:/dev/shm);然后读回它,解析它并从 python 打印它——python 还处理一个简单的 while 循环,该循环会一直执行,直到到达断点.

          And finally, the approach that worked is: temporarily redirecting the GDB output from a gdb.execute to a logfile in RAM (Linux: /dev/shm); and then reading it back, parsing it and printing it from python - python also handles a simple while loop that steps until a breakpoint is reached.

          具有讽刺意味的是 - 大多数通过重定向日志文件导致此解决方案的错误实际上最近在 SVN 中得到修复;这意味着这些将在不久的将来传播到发行版,并且可以直接使用 gdb.execute("CMDSTR", toString=True) :/然而,因为我不能冒险构建 GDB现在的来源(并且可能会遇到可能的新不兼容性),这对我来说也足够了:)

          The irony is - most of these bugs, that caused this solution via redirecting the logfile, are actually recently fixed in SVN; meaning those will propagate to the distros in the near future, and one will be able to use gdb.execute("CMDSTR", toString=True) directly :/ Yet, as I cannot risk building GDB from source right now (and possibly bumping into possible new incompatibilites), this is good enough for me also :)

           

          这里是相关文件(部分也在 pygdb-fork.gdb,pygdb-fork.py):

          Here are the relevant files (partially also in pygdb-fork.gdb,pygdb-fork.py):

          pygdb-logg.gdb 是:

          # gdb script: pygdb-logg.gdb
          # easier interface for pygdb-logg.py stuff
          # from within gdb: (gdb) source -v pygdb-logg.gdb
          # from cdmline: gdb -x pygdb-logg.gdb -se test.exe
          
          # first, "include" the python file:
          source -v pygdb-logg.py
          
          # define shorthand for nextUntilBreakpoint():
          define nub
            python nextUntilBreakpoint()
          end
          
          # set up breakpoints for test.exe:
          b main
          b doFunction
          
          # go to main breakpoint
          run
          

          pygdb-logg.py 是:

          # gdb will 'recognize' this as python
          #  upon 'source pygdb-logg.py'
          # however, from gdb functions still have
          #  to be called like:
          #  (gdb) python print logExecCapture("bt")
          
          import sys
          import gdb
          import os
          
          def logExecCapture(instr):
            # /dev/shm - save file in RAM
            ltxname="/dev/shm/c.log"
          
            gdb.execute("set logging file "+ltxname) # lpfname
            gdb.execute("set logging redirect on")
            gdb.execute("set logging overwrite on")
            gdb.execute("set logging on")
            gdb.execute(instr)
            gdb.execute("set logging off")
          
            replyContents = open(ltxname, 'r').read() # read entire file
            return replyContents
          
          # next until breakpoint
          def nextUntilBreakpoint():
            isInBreakpoint = -1;
            # as long as we don't find "Breakpoint" in report:
            while isInBreakpoint == -1:
              REP=logExecCapture("n")
              isInBreakpoint = REP.find("Breakpoint")
              print "LOOP:: ", isInBreakpoint, "
          ", REP
          

           

          基本上,pygdb-logg.gdb加载pygdb-logg.py python脚本,为设置别名nubnextUntilBreakpoint,并初始化会话 - 其他一切都由 python 脚本处理.这是一个示例会话 - 关于 OP 中的测试源:

          Basically, pygdb-logg.gdb loads the pygdb-logg.py python script, sets up the alias nub for nextUntilBreakpoint, and initializes the session - everything else is handled by the python script. And here is a sample session - in respect to the test source in OP:

          $ gdb -x pygdb-logg.gdb -se test.exe
          ...
          Reading symbols from /path/to/test.exe...done.
          Breakpoint 1 at 0x80483ec: file test.c, line 14.
          Breakpoint 2 at 0x80483c7: file test.c, line 7.
          
          Breakpoint 1, main () at test.c:14
          14    count = 1;
          (gdb) nub
          LOOP::  -1
          15    count += 2;
          
          LOOP::  -1
          16    count = 0;
          
          LOOP::  -1
          19      doFunction();
          
          LOOP::  1
          
          Breakpoint 2, doFunction () at test.c:7
          7     count += 2;
          
          (gdb) nub
          LOOP::  -1
          9     count--;
          
          LOOP::  -1
          10  }
          
          LOOP::  -1
          main () at test.c:20
          20      printf("%d
          ", count);
          
          1
          LOOP::  -1
          21    }
          
          LOOP::  -1
          19      doFunction();
          
          LOOP::  1
          
          Breakpoint 2, doFunction () at test.c:7
          7     count += 2;
          
          (gdb)
          

          ...就像我想要的那样:P 只是不知道它有多可靠(以及是否可以在 avr-gdb 中使用,这就是我需要这个:) Ubuntu 11.04 中的 avr-gdb 版本目前是 6.4,它无法识别 python 命令:()

          ... just as I wanted it :P Just don't know how reliable it is (and whether it will be possible to use in avr-gdb, which is what I need this for :) version of avr-gdb in Ubuntu 11.04 is currently 6.4, which doesn't recognize the python command :()

           

          嗯,希望这对某人有所帮助,
          干杯!

          Well, hope this helps someone,
          Cheers!

           

          这里有一些参考:

          • GDB: error detected on stdin
          • GDB has problems with getting commands piped to STDIN
          • Re: [Gdb] How do i use GDB other input?
          • gdb doesn't accept input on stdin
          • Using gdb in an IDE - comp.os.linux.development.apps | Google Groups
          • rmathew: Terminal Sickness
          • [TUTORIAL] Calling an external program in C (Linux) - GIDForums
          • shell - how to use multiple arguments with a shebang (i.e. #!)? - Stack Overflow
          • Redirecting/storing output of shell into GDB variable? - Stack Overflow
          • Corey Goldberg: Python - Redirect or Turn Off STDOUT and STDERR
          • The Cliffs of Inanity › 9. Scripting gdb
          • gdb python scripting: where has parse_and_eval gone? - Stack Overflow
          • shell - Invoke gdb to automatically pass arguments to the program being debugged - Stack Overflow
          • Storing Files/Directories In Memory With tmpfs | HowtoForge - Linux Howtos and Tutorials
          • simple way to touch a file if it does not exist | Python | Python
          • os.fork() different in cgi-script? - Python
          • java - Writing tests that use GDB - how to capture output? - Stack Overflow
          • Debugging with GDB: How to create GDB Commands in Python - Wiki
          • GDB reference card

          这篇关于如何在到达给定断点之前自动打印 GDB 中的每个执行行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆