有没有办法在gdb中设置一个以调用堆栈为条件的断点?

问题描述 投票:26回答:6

我正在Linux上的gdb 7.1中调试C ++。

我有一个函数a()在代码中的许多地方调用。我想在其中设置一个断点,但前提是它是从b()调用的。有什么办法吗?

有没有办法做到这一点只有b()c()调用,等等无限无疑?

c++ gdb breakpoints callstack
6个回答
23
投票

更新:这个问题现在有一个better answer:使用GDB _is_caller便利功能。

你需要描述的需要经常出现,通常是在some_utility_fn被大量调用的情况下,但你只对来自some_other_fn的调用感兴趣。

您可以使用CVS trunk中的GDB中的新嵌入式Python支持来编写整个交互的脚本。

如果没有Python,你可以做的事情是有限的,但通常的技术是在a()上有一个禁用的断点,并从一个命令启用它,附加到b()上的断点。

这是一个例子:

int a(int x)
{
  return x + 1;
}

int b()
{
  return a(1);
}

int call_a_lots()
{
  int i, sum = 0;
  for (i = 0; i < 100; i++)
    sum += a(i);
}

int main()
{
  call_a_lots();
  return b();
}

gcc -g t.c
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) break a
Breakpoint 1 at 0x4004cb: file t.c, line 3.
(gdb) disable 1
(gdb) break b
Breakpoint 2 at 0x4004d7: file t.c, line 8.
(gdb) command 2
>silent
>enable 1
>continue
>end
(gdb) run

Breakpoint 1, a (x=1) at t.c:3
3     return x + 1;
(gdb) bt
#0  a (x=1) at t.c:3
#1  0x00000000004004e1 in b () at t.c:8
#2  0x000000000040052c in main () at t.c:21
(gdb) q

Voila:我们已经停止了从a()打来的b(),忽略了之前100次对a()的召唤。


8
投票

我已经在已经可用的gdb 7.6上测试了这个,但是它不适用于gdb 7.2并且可能在gdb 7.1上:

所以这是main.cpp:

int a()
{
  int p = 0;
  p = p +1;
  return  p;
}

int b()
{
  return a();
}

int c()
{
  return a();
}

int main()
{
  c();
  b();
  a();
  return 0;
}

然后g ++ -g main.cpp

这是my_check.py:

class MyBreakpoint (gdb.Breakpoint):
    def stop (self):
        if gdb.selected_frame().older().name()=="b":
          gdb.execute("bt")
          return True
        else:
          return False

MyBreakpoint("a")

这就是它的工作原理:

4>gdb -q -x my_check.py ./a.out
Reading symbols from /home/a.out...done.
Breakpoint 1 at 0x400540: file main.cpp, line 3.
(gdb) r
Starting program: /home/a.out
#0  a () at main.cpp:3
#1  0x0000000000400559 in b () at main.cpp:10
#2  0x0000000000400574 in main () at main.cpp:21

Breakpoint 1, a () at main.cpp:3
3         int p = 0;
(gdb) c
Continuing.
[Inferior 1 (process 16739) exited normally]
(gdb) quit

5
投票

比Python脚本更简单的解决方案是使用temporary breakpoint

它看起来像这样:

b ParentFunction
command 1
  tb FunctionImInterestedIn
  c
end

每当你在ParentFunction中断时,你将在你真正感兴趣的函数上设置一次性断点,然后继续运行(大概直到你达到那个断点)。

因为你在FunctionImInterestedIn上只打破一次,如果在FunctionImInterestedIn的上下文中多次调用ParentFunction并且你想在每次调用时中断,这将不起作用。


3
投票

不确定如何通过gdb做到这一点。 但你可以声明全局变量,如:

bool call_a = false;

当b打电话给

call_a = true;   
a();

当其他函数调用a()或断点之后,将call_a设置为false

然后使用条件断点

break [line-number] if call_a == true

2
投票

gdb现在可以直接处理这个,而不需要Python。这样做:

b a if $_caller_is("b")

0
投票

一个简单的手臂是:

在您感兴趣的函数中设置断点。

break a

将gdb命令附加到该断点。

command 1
 up 1
 if $lr == 0x12345678
  echo match \n
  down 1
 else
  echo no match \n
  echo $lr \n
  down 1
  cont 
 end 
end 

当你到达函数a()时,命令暂时弹出一个堆栈帧,从而更新链接寄存器。当调用者不是您需要的执行路径时,可以继续使用调用者链接寄存器值。

请享用。

© www.soinside.com 2019 - 2024. All rights reserved.