如何自动打印GDB中的所有执行行,直到达到给定的断点?

我想在GDB中设置一个断点,并将其运行到这一点 – 在此过程中,打印出它已经“穿过”的行。

这是一个例子,基于这个简单的文件与一个主要和一个功能,每个断点:

$ 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\n", 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)停止:

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

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

在这一点上 – 我可以,例如,继续(c);并且进程将通过,不输出任何内容,并在请求的行中断:

(gdb) c
Continuing.

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

另一方面,而不是继续 – 我可以一行一行地,通过使用步骤或下一个(n);例如:

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\n", 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\n") 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键,最后输入的命令(步骤或下一步)将重复(在第二种情况下留下更长的会话,以显示“下一个”保持在同一级别,“步骤”步骤在被调用的函数内)。但是,可以看出,取决于步骤还是下一步运行,可能需要一段时间才能达到结果 – 所以我不想坐在10分钟,我的手卡在输入按钮上:)

所以,我的问题是 – 我可以以某种方式指示gdb运行到’断点2’,而不需要进一步的用户干预 – 同时打印出它所经过的行,就像步骤(或下一步)被按下一样?

最佳答案
那么这不容易 – 但我认为我有点了:)我经历了一系列失败的尝试(发布here);相关代码如下。

基本上,如果调试器停止(一步),“下一步/直到断点的步骤”中的问题是如何确定是否处于断点。注意我也使用GDB 7.2-1ubuntu11(当前为Ubuntu 11.04)。所以,它是这样的:

>我首先发现了大约Convenience Variables,并且认为 – 由于有程序计数器和可用性,必须有一些GDB便利变量给出“断点”状态,并且可以直接在GDB脚本中使用。然而,在查看GDB reference Index一段时间后,我根本无法找到任何这样的变量(我的尝试是在nub.gdb)
>缺少这样一个“断点状态”的内部变量 – 唯一要做的就是将GDB的命令行输出(作为响应命令)作为一个字符串来捕获(并且解析它)(寻找“断点”)
>然后,我发现大约Python API到GDB,gdb.execute(“CMDSTR”,toString = True)命令 – 这似乎是捕获输出所需要的:“默认情况下,任何由命令产生的输出都被发送到gdb的标准输出,如果to_string参数为True,则输出将由gdb.execute收集并返回为字符串[1]“!

>所以,首先我试图制作一个脚本(pygdb-nub.py,gdbwrap),以推荐的方式使用gdb.execute;在这里失败 – 因为这样:

> 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

>然后,我以为我会使用一个python脚本来进行子进程。打开GDB程序,同时替换它的stdin和stdout;然后从那里继续控制GDB(pygdb-sub.py) – 失败了…(显然,因为我没有重定向stdin / out)
>然后,我想我会使用python脚本从GDB(通过源)调用,这将在gdb.execute被调用时内部分叉到一个pty,以便捕获其输出(pygdb-fork.gdb,pygdb-fork.py)…这个几乎工作 – 因为有字符串返回;但是GDB注意到一些不正确的事情:“[tcsetpgrp failed in terminal_inferior:Operation allowed allowed]”,后续的返回字符串似乎没有改变。

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

讽刺的是 – 大多数这些错误,通过重定向日志文件导致了这个解决方案,实际上最近固定在SVN中;这意味着在不久的将来会传播给发行版,并且可以直接使用gdb.execute(“CMDSTR”,toString = True)/ /然而,因为我现在无法从源代码构建GDB(并且可能会碰撞)进入可能的新不相容),这对我来说还不错:)

以下是相关文件(部分也在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, "\n", REP

基本上,pygdb-logg.gdb加载pygdb-logg.py python脚本,设置nextUntilBreakpoint的别名nub,并初始化会话 – 其他所有内容都由python脚本处理。这里是一个示例会话 – 在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\n", 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中使用,这是我需要的:) EDIT:avr-gdb的版本Ubuntu 11.04目前是6.4,它不能识别python命令:()

那么希望这有助于某人,
干杯!

这里有一些参考:

> 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中的所有执行行,直到达到给定的断点? - 代码日志