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

sda*_*aau 26 c debugging automation gdb

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

这是一个例子,基于这个带有a main和a函数的简单文件,每个都有两个断点:

$ 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.
Run Code Online (Sandbox Code Playgroud)

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

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

Breakpoint 1, main () at test.c:14
14    count = 1;
(gdb) 
Run Code Online (Sandbox Code Playgroud)

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

(gdb) c
Continuing.

Breakpoint 2, doFunction () at test.c:7
7     count += 2;
(gdb)
Run Code Online (Sandbox Code Playgroud)

另一方面,不是继续 - 我可以逐行,通过使用step(s)或next(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) 
Run Code Online (Sandbox Code Playgroud)

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

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

sda*_*aau 21

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

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

  • 我首先发现了Convenience Variables,并且考虑到 - 如果有程序计数器等可用,必须有一些GDB便利变量给出"断点"状态,并且可以直接在GDB脚本中使用.然而,在浏览了GDB参考索引一段时间后,我根本找不到任何这样的变量(我的尝试是在nub.gdb中)
  • 缺少这样的"断点状态"内部变量 - 唯一要做的就是将GDB的('stdout')命令行输出(作为对命令的响应)捕获为字符串,并解析它(寻找"断点")
  • 然后,我发现了关于GDB的Python API,以及gdb.execute("CMDSTR", toString=True)命令 - 这似乎是捕获输出所需要的:" 默认情况下,命令生成的任何输出都会发送到gdb的标准输出.如果to_string参数为True,然后输出将被gdb.execute收集并返回为字符串[ 1 ] "!

最后,有效的方法是:暂时将GDB输出从a重定向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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

 

基本上,pygdb-logg.gdb加载pygdb-logg.pypython脚本,设置别名nubnextUntilBreakpoint,并初始化会话-其他的都是由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)
Run Code Online (Sandbox Code Playgroud)

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

 

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

 

这里有一些参考:


gue*_*stn 5

如何使用命令文件在gdb中这样做呢?更改文件参数,并根据需要循环计数。

gdb -x run.gdb
Run Code Online (Sandbox Code Playgroud)

run.gdb:

set pagination off
set logging file gdb.log
set logging on
set $i = 0
file main
break main
break WriteData
# sadly, commands not getting executed on reaching breakpoint 2
commands 2
  set $i=1000
  print "commands 2 : %d",$i
end
run
while ( $i < 1000 )
  step
  # next
  # continue
  set $i = $i + 1
end
Run Code Online (Sandbox Code Playgroud)