Ustaw punkt przerwania w kodzie C lub C ++ programowo dla GDB w systemie Linux

105

Jak programowo ustawić punkt przerwania w kodzie C lub C ++, który będzie działał dla GDB w systemie Linux?

To znaczy:

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
źródło
8
Bardzo na marginesie (przepraszam za czubek), ale jeśli martwisz się o przenośność, prawdopodobnie martwisz się także o poprawność - dlatego int mainraczej niż void main.
Stuart Golodetz
@Stuart - Naprawiono. Powinienem to zrobić jakiś czas temu.
J. Polfer,
4
@ J.Polfer: Nie return 0jest to jednak konieczne i to tylko hałas!
Wyścigi lekkości na orbicie

Odpowiedzi:

107

Jednym ze sposobów jest zasygnalizowanie przerwania:

#include <csignal>

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

W C:

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

AKTUALIZACJA : MSDN stwierdza, że system Windows tak naprawdę nie obsługuje SIGINT, więc jeśli problemem jest przenośność, prawdopodobnie lepiej będzie używać SIGABRT.

Håvard S
źródło
Tak, powinno to działać w różnych systemach operacyjnych / kompilatorach / debuggerach.
Håvard S,
1
Nie znam innych debuggerów, ale gdb jest dość elastyczny, jeśli chodzi o obsługę sygnałów .
Cascabel
4
Znaleźliśmy SIGTRAP lepiej na niektórych Unices
JBRWilkinson,
1
w Windows, MSVC możesz użyć __debug_break, DebugBreak lub _asm {int 3}.
Fernando Gonzalez Sanchez
2
@FernandoGonzalezSanchez: w rzeczywistości nazwa funkcji to __debugbreak()i NIE __debug_break() , jak widać tutaj
Morix Dev
27

W projekcie, nad którym pracuję, robimy to:

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

(W naszym przypadku chcieliśmy mocno się zawiesić, gdyby wydarzyło się to poza debugerem, generując raport o awarii, jeśli to możliwe. To jeden z powodów, dla których użyliśmy SIGABRT. Wykonanie tego przenośnie w systemach Windows, Mac i Linux wymagało kilku prób. Skończyło się na kilku #ifdefs, pomocnie skomentowane tutaj: http://hg.mozilla.org/mozilla-central/file/98fa9c0cff7a/js/src/jsutil.cpp#l66 .)

Jason Orendorff
źródło
2
Jak zwykle okna nie wyglądają jak inne :)
mathk
Czy można wydać „sygnał 0”, aby kontynuować program w stanie wstrzymania? Byłoby miło móc od tego momentu używać „n” lub „s” bez wydawania „c”.
Jason Doucette
2
@JasonDoucette Jeśli naprawdę chcesz, aby program się zatrzymał, możesz dodać breakpoint()funkcję do swojego programu (może być pusta lub po prostu zawierać instrukcję print) i dodać break breakpointdo swojego ~/.gdbinit.
Jason Orendorff
26

Patrząc tutaj , znalazłem następujący sposób:

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

Wydaje mi się to trochę hakerskie. Myślę, że działa to tylko w architekturze x86.

J. Polfer
źródło
3
I tylko z kompilatorami obsługującymi składnię asemblera AT&T. W szczególności kompilator Microsoftu ( cl.exe) nie obsługuje tej składni, ale używa innej składni.
Håvard S
pytanie dotyczyło Linuksa, więc myślę, że możemy założyć, że składnia gcc będzie działać na x86.
js.
BTW - wypróbowałem powyższe na mojej maszynie x86 i zadziałało. Byłem ciekawy, czy istnieje lepszy sposób na zrobienie tego. Wygląda na to, że jest.
J. Polfer,
2
Używam mingw w systemie Windows, więc inne sugestie nie mogą mi pomóc. Podniesienie sygnału SIGINT po prostu kończy działanie aplikacji, SIGTRAP nie jest zdefiniowany w nagłówkach mingw ... Używanie instrukcji int faktycznie wysyła SIGTRAP, a gdb ładnie przerywa w odpowiedniej linii.
Machta
W Linuksie int 3podnosi SIGTRAP.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
12

__asm__("int $3"); powinno działać:

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
źródło
1
Podoba mi się #defineto, żebym nie musiał pamiętać składni. Mam to rozsypane po całym kodzie, czasami zamiast assert(), ponieważ zatrzymanie debiugera pozwala mi zbadać wszystkie zmienne i stos. I oczywiście, tak jak assert, nie muszę go usuwać w celu uzyskania kodu produkcyjnego
Mawg mówi, że przywróć Monikę
Ciekawe, że ma to 10 głosów pozytywnych, gdy ograniczenia pytania „Linux” i „GDB” dają wiele opcji poza uciekaniem się do asemblacji, co zawsze powinno być ostatecznością ze względu na przenośność, jeśli nic innego. Zobacz inne odpowiedzi.
Benjamin Crawford Ctrl-Alt-Tut
5

Rozczarowujące jest widzieć tak wiele odpowiedzi, które nie używają dedykowanego sygnału dla programowych punktów przerwania SIGTRAP:

#include <signal.h>

raise(SIGTRAP); // At the location of the BP.
Benjamin Crawford Ctrl-Alt-Tut
źródło
1

Na OS X możesz po prostu zadzwonić std::abort()(może być tak samo w systemie Linux)

dacap
źródło
Która biblioteka?
Alex
Jest to część standardowej biblioteki C ++ i jest wieloplatformowa, na której istnieją kompilatory zgodne z C ++ 11. To jednak podnosi SIGABRT, co nie jest odpowiednim sygnałem do podniesienia w tym przypadku.
Benjamin Crawford Ctrl-Alt-Tut