Est-il possible de définir un point d'arrêt dans gdb, qui est subordonné à la pile d'appel?

je suis en train de déboguer C++ dans la gdb 7.1 sur Linux.

j'ai une fonction a() qui est appelée à de nombreux endroits dans le code. Je veux mettre un point d'arrêt, mais seulement si elle a été appelée à partir de b(). Est-il possible de le faire?

Est-il possible de le faire uniquement si b() a été appelé de c(), et ainsi de suite ad infinitum?

25
demandé sur phuclv 2011-03-17 11:04:12

6 réponses

le besoin que vous décrivez apparaît assez souvent, habituellement dans le contexte de some_utility_fn être appelé beaucoup, mais vous êtes seulement intéressé par l'appel qui vient de some_other_fn.

vous pourriez probablement script toute cette interaction en utilisant le nouveau support Python intégré dans GDB à partir du tronc CVS.

Sans Python, vous êtes limité dans ce que vous pouvez faire, mais la technique habituelle est d'avoir un désactivé point d'arrêt sur a(), et de l'activer à partir d'une commande, attaché à un point d'arrêt sur b().

Voici un exemple:

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: nous avons arrêté sur a() appelé b(), ignorant 100 précédents appels à a().

21
répondu Employed Russian 2011-03-21 00:44:47

j'ai testé cela sur gdb 7.6 qui est déjà disponible, mais il ne fonctionne pas sur gdb 7.2 et probablement sur gdb 7.1:

Donc c'est le principal.rpc:

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 principal.rpc

C'est 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")

Et voilà comment cela fonctionne:

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
7
répondu Sergei Kurenkov 2013-11-26 06:22:35

une solution plus simple que Python scripting est d'utiliser un point de rupture temporaire.

Il ressemble à ceci:

b ParentFunction
command 1
  tb FunctionImInterestedIn
  c
end

Chaque fois que vous cassez dans ParentFunction, vous allez définir un point de rupture unique sur la fonction qui vous intéresse réellement, puis continuer à courir (probablement jusqu'à ce que vous atteigniez ce point de rupture).

puisque vous casserez exactement une fois sur FunctionImInterestedIn, cela ne fonctionnera pas si FunctionImInterestedIn est appelé plusieurs fois dans le contexte de ParentFunction et vous voulez pour rompre sur chaque invocation.

4
répondu rix0rrr 2016-05-02 18:10:24

Je ne sais pas comment le faire par gdb.

Mais vous pouvez déclarer une variable globale comme:

bool call_a = false;

et lorsque b de l'appel d'une

call_a = true;   
a();

et définissez call_a à false quand une autre fonction appelle a () ou après votre point de rupture

alors utilisez le point de rupture de condition

break [line-number] if call_a == true
4
répondu owenwater 2016-12-30 14:08:33

facile pour les bras:

Définir le point d'arrêt dans la fonction qui vous intéresse.

break a

attachez une commande gdb à ce point de rupture.

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 

lorsque vous arrivez dans la fonction a (), la commande affiche temporairement un cadre de pile, mettant ainsi à jour le registre de liens. Les appelants lien enregistrer la valeur peut ensuite être utilisé continuer lorsque l'appelant n'est pas l'exécution chemin d'accès dont vous avez besoin.

Profiter.

0
répondu AppSpec 2015-04-15 01:46:48

gdb peut gérer cela directement maintenant, sans besoin de Python. Faites simplement ceci:

b a if $_caller_is("b")
0
répondu Jeff Trull 2018-03-01 19:10:23