Defina o ponto de interrupção no código C ou C ++ programaticamente para gdb no Linux

105

Como posso definir um ponto de interrupção no código C ou C ++ programaticamente que funcionará para gdb no Linux?

Ie:

int main(int argc, char** argv)
{
    /* set breakpoint here! */
    int a = 3;
    a++;  /*  In gdb> print a;  expect result to be 3 */
    return 0;
}
J. Polfer
fonte
8
Uma observação lateral (desculpe a picuinha), mas se você está preocupado com a portabilidade, então provavelmente também está preocupado com a correção - portanto, em int mainvez de void main.
Stuart Golodetz
@Stuart - Corrigido. Deveria ter feito isso há um tempo.
J. Polfer
4
@ J.Polfer: Mas return 0não é necessário e é apenas ruído!
Lightness Races in Orbit

Respostas:

107

Uma maneira é sinalizar uma interrupção:

#include <csignal>

// Generate an interrupt
std::raise(SIGINT);

Em C:

#include <signal.h>
raise(SIGINT);

ATUALIZAÇÃO : o MSDN afirma que o Windows não oferece suporte SIGINT, portanto, se a portabilidade for uma preocupação, é melhor você usá-lo SIGABRT.

Håvard S
fonte
Sim, isso deve funcionar em sistemas operacionais / compiladores / depuradores.
Håvard S
1
Não conheço outros depuradores, mas o gdb é bastante flexível quanto ao tratamento de sinais .
Cascabel
4
Encontramos SIGTRAP melhor em alguns Unices
JBRWilkinson
1
no Windows, MSVC você pode usar __debug_break, DebugBreak ou _asm {int 3}.
Fernando Gonzalez Sanchez
2
@FernandoGonzalezSanchez: na verdade o nome da função é __debugbreak()e NÃO __debug_break() , como você pode ver aqui
Morix Dev
27

Em um projeto em que trabalho, fazemos o seguinte:

raise(SIGABRT);  /* To continue from here in GDB: "signal 0". */

(No nosso caso, queríamos travar fortemente se isso acontecesse fora do depurador, gerando um relatório de falha, se possível. Esse é um dos motivos pelos quais usamos o SIGABRT. Fazer isso portável no Windows, Mac e Linux exigiu várias tentativas. Acabamos com algumas #ifdefs, útil comentado aqui: http://hg.mozilla.org/mozilla-central/file/98fa9c0cff7a/js/src/jsutil.cpp#l66 .)

Jason Orendorff
fonte
2
Como de costume, as janelas não se parecem com as outras :)
mathk
É possível emitir "sinal 0" para continuar a programar o programa em um estado de pausa? Seria bom poder usar 'n' ou 's' a partir deste ponto, sem um 'c' sendo emitido.
Jason Doucette de
2
@JasonDoucette Se você realmente deseja que o programa pause, você pode adicionar uma breakpoint()função em seu programa (pode estar vazia ou conter apenas uma instrução de impressão) e adicionar break breakpointao seu ~/.gdbinit.
Jason Orendorff
26

Olhando aqui , descobri a seguinte maneira:

void main(int argc, char** argv)
{
    asm("int $3");
    int a = 3;
    a++;  //  In gdb> print a;  expect result to be 3
}

Isso me parece meio hackeado. E acho que isso só funciona na arquitetura x86.

J. Polfer
fonte
3
E apenas com compiladores que suportam a sintaxe de montagem AT&T. Em particular, o compilador da Microsoft ( cl.exe) não oferece suporte a essa sintaxe, mas usa uma sintaxe diferente.
Håvard S
a questão era sobre o linux, então acho que podemos assumir que a sintaxe gcc funcionará para x86.
js.
BTW - eu tentei o acima na minha máquina x86 e funcionou. Eu estava curioso para saber se havia uma maneira melhor de fazer isso. Parece que sim.
J. Polfer
2
Estou usando o mingw no Windows, então as outras sugestões não podem me ajudar. Aumentar o sinal SIGINT apenas finaliza a aplicação, SIGTRAP não é definido nos cabeçalhos mingw ... Usar a instrução int na verdade envia SIGTRAP e gdb quebra perfeitamente na linha apropriada.
Machta
No Linux, int 3gera um SIGTRAP.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
12

__asm__("int $3"); Deveria trabalhar:

int main(int argc, char** argv)
{
    /* set breakpoint here! */
    int a = 3;
    __asm__("int $3");
    a++;  /*  In gdb> print a;  expect result to be 3 */
    return 0;
}
hek2mgl
fonte
1
Gosto #definedisso, para não ter que lembrar a sintaxe. Eu tenho isso espalhado em todo o meu código, às vezes no lugar de assert(), uma vez que parar o depurador me permite examinar todas as variáveis ​​e a pilha. E, claro, como afirmar, não preciso removê-lo para o código de produção
Mawg diz para restabelecer Monica em
Interessante que isso tenha 10 votos positivos quando as restrições de questão de "Linux" e "GDB" oferecem muitas opções fora de recorrer ao assembly, que deve ser sempre um último recurso para o bem da portabilidade, senão outra coisa. Por favor, veja algumas das outras respostas.
Benjamin Crawford Ctrl-Alt-Tut
5

Decepcionante ver tantas respostas sem usar o sinal dedicado para pontos de interrupção de software SIGTRAP:

#include <signal.h>

raise(SIGTRAP); // At the location of the BP.
Benjamin Crawford Ctrl-Alt-Tut
fonte
1

No OS X você pode simplesmente ligar std::abort()(pode ser o mesmo no Linux)

dacap
fonte
Qual biblioteca?
Alex
Isso faz parte da biblioteca C ++ padrão e é uma plataforma cruzada onde existem compiladores compatíveis com C ++ 11. Isso, entretanto, aumenta SIGABRT, que não é realmente um sinal apropriado para aumentar neste caso.
Benjamin Crawford Ctrl-Alt-Tut