Подтвердить что ты не робот

Есть ли способ установить точку останова в gdb, которая является условной для стека вызовов?

Я отлаживаю С++ в gdb 7.1 на Linux.

У меня есть функция a(), которая вызывается во многих местах кода. Я хочу установить в нем точку останова, но только если она была вызвана из b(). Есть ли способ сделать это?

Есть ли способ сделать это, только если b() был вызван из c() и т.д. ad infinitum?

4b9b3361

Ответ 1

Обновление: теперь есть лучший ответ на этот вопрос: используйте удобную функцию GDB _is_caller.

Необходимость, которую вы описываете, возникает довольно часто, обычно в контексте того, что some_utility_fn часто, но вас интересует только вызов, some_other_fn от some_other_fn.

Вероятно, вы могли бы написать сценарий всего этого взаимодействия, используя новую встроенную поддержку Python в GDB из ствола CVS.

Без 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

Вуаля: мы остановились на a() вызванном из b(), игнорируя предыдущие 100 вызовов a().

Ответ 2

Я тестировал это на 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

Ответ 3

Более простое решение, чем сценарии Python, использует временную точку останова.

Это выглядит так:

b ParentFunction
command 1
  tb FunctionImInterestedIn
  c
end

Каждый раз, когда вы нарушаете ParentFunction, вы устанавливаете одноразовую ParentFunction останова для функции, которая вам действительно интересна, а затем продолжаете работу (предположительно, пока не достигнете этой точки останова).

Поскольку FunctionImInterestedIn будет ParentFunction ровно один раз, это не сработает, если FunctionImInterestedIn вызывается несколько раз в контексте ParentFunction и вы хотите выполнить разрыв при каждом вызове.

Ответ 4

не уверен, как это сделать с помощью gdb.
Но вы можете объявить глобальную переменную, например:

bool call_a = false;

и когда b вызывает

call_a = true;   
a();

и установите для call_a значение false, когда другая функция вызывает a() или после точки останова

затем используйте условие break

break [line-number] if call_a == true

Ответ 5

GDB может справиться с этим прямо сейчас без необходимости Python. Просто сделай это:

b a if $_caller_is("b")

Ответ 6

Легкий для руки:

Задайте точку останова в интересующей вас функции.

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(), команда временно выдает один стек стека, тем самым обновляя регистр ссылок. Затем значение регистра номера вызывающих абонентов может быть использовано, если вызывающий абонент не является исполнением путь, который вам нужен.

Enjoy.