Setzen Sie den Haltepunkt in C- oder C ++ - Code programmgesteuert für gdb unter Linux


103

Wie kann ich programmgesteuert einen Haltepunkt in C- oder C ++ - Code festlegen, der für gdb unter Linux funktioniert?

Dh:

int main(int argc, char** argv)
{
    /* set breakpoint here! */
    int a = 3;
    a++;  /*  In gdb> print a;  expect result to be 3 */
    return 0;
}

8
Sehr viel eine Randnotiz (sorry zu nitpick), aber wenn Sie sich Sorgen um die Portabilität machen, dann sind Sie wahrscheinlich auch besorgt über die Korrektheit - daher int maineher als void main.
Stuart Golodetz

@Stuart - Behoben. Hätte das schon vor einiger Zeit tun sollen.
J. Polfer

4
@ J.Polfer: Das return 0ist aber nicht nötig und ist nur Lärm!
Leichtigkeitsrennen im Orbit

Antworten:


105

Eine Möglichkeit besteht darin, einen Interrupt zu signalisieren:

#include <csignal>

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

In C:

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

UPDATE : MSDN gibt an, dass Windows nicht wirklich unterstützt SIGINT. Wenn also Portabilität ein Problem darstellt, sollten Sie es wahrscheinlich besser verwenden SIGABRT.


Ja, dies sollte für alle Betriebssysteme / Compiler / Debugger funktionieren.
Håvard S

1
Ich kenne keine anderen Debugger, aber gdb ist ziemlich flexibel in Bezug auf die Signalverarbeitung .
Cascabel

4
Wir fanden SIGTRAP auf einigen Unices besser
JBRWilkinson

1
In Windows, MSVC können Sie __debug_break, DebugBreak oder _asm {int 3} verwenden.
Fernando Gonzalez Sanchez

2
@ FernandoGonzalezSanchez: Eigentlich ist der Funktionsname __debugbreak()und NICHT __debug_break() , wie Sie hier sehen können
Morix Dev

27

In einem Projekt, an dem ich arbeite, machen wir Folgendes:

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

(In unserem Fall wollten wir hart abstürzen, wenn dies außerhalb des Debuggers geschah, und wenn möglich einen Absturzbericht generieren. Dies ist ein Grund, warum wir SIGABRT verwendet haben. Dies portabel für Windows, Mac und Linux zu tun, erforderte mehrere Versuche. Am Ende hatten wir einige #ifdefs, hier hilfreich kommentiert: http://hg.mozilla.org/mozilla-central/file/98fa9c0cff7a/js/src/jsutil.cpp#l66 .)


2
Wie immer sieht Windows nicht aus wie die anderen :)
Mathk

Ist es möglich, "Signal 0" auszugeben, um das Programm in einem angehaltenen Zustand fortzusetzen? Es wäre schön, ab diesem Punkt 'n' oder 's' verwenden zu können, ohne dass ein 'c' ausgegeben wird.
Jason Doucette

2
@JasonDoucette Wenn Sie wirklich nur möchten, dass das Programm angehalten wird, möchten Sie möglicherweise eine breakpoint()Funktion in Ihr Programm einfügen (sie kann leer sein oder nur eine print-Anweisung enthalten) und break breakpointzu Ihrer hinzufügen ~/.gdbinit.
Jason Orendorff

26

Als ich hier nachgesehen habe , habe ich folgenden Weg gefunden:

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

Das scheint mir ein bisschen hackisch zu sein. Und ich denke, das funktioniert nur auf x86-Architektur.


3
Und nur mit Compilern, die die AT & T-Assemblysyntax unterstützen. Insbesondere der Compiler ( cl.exe) von Microsoft unterstützt diese Syntax nicht, verwendet jedoch eine andere Syntax.
Håvard S

Die Frage war über Linux, also können wir davon ausgehen, dass die gcc-Syntax für x86 funktioniert.
js.

Übrigens - ich habe das oben genannte auf meinem x86-Computer ausprobiert und es hat funktioniert. Ich war neugierig, ob es einen besseren Weg gibt. Sieht so aus.
J. Polfer

2
Ich verwende Mingw unter Windows, daher können mir die anderen Vorschläge nicht helfen. Das Auslösen des SIGINT-Signals beendet nur die Anwendung, SIGTRAP ist nicht in MingW-Headern definiert ... Wenn Sie den int-Befehl verwenden, werden SIGTRAP und gdb-Unterbrechungen in der entsprechenden Zeile gesendet.
Machta

int 3Löst unter Linux ein SIGTRAP aus.
Ciro Santilli 郝海东 冠状 病 六四 六四 法轮功

11

__asm__("int $3"); sollte arbeiten:

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;
}

1
Ich mag #definedas, damit ich mich nicht an die Syntax erinnern muss. Ich habe es in meinem Code verteilt, manchmal anstelle von assert(), da ich beim Stoppen des Debiuggers alle Variablen und den Stapel untersuchen möchte. Und natürlich muss ich es, wie behauptet, nicht für den Produktionscode entfernen
Mawg sagt, Monica

Interessant, dass dies 10 positive Stimmen hat, wenn die Frageeinschränkungen von "Linux" und "GDB" viele Optionen bieten, die nicht auf Assembler zurückgreifen, was aus Gründen der Portabilität immer der letzte Ausweg sein sollte, wenn nichts anderes. Bitte sehen Sie einige der anderen Antworten.
Benjamin Crawford Ctrl-Alt-Tut

5

Enttäuschend, so viele Antworten zu sehen, bei denen das dedizierte Signal nicht für Software-Haltepunkte verwendet wird SIGTRAP:

#include <signal.h>

raise(SIGTRAP); // At the location of the BP.

1

Unter OS X können Sie einfach anrufen std::abort()(unter Linux ist es möglicherweise dasselbe).


Welche Bibliothek?
Alex

Dies ist Teil der Standard-C ++ - Bibliothek und plattformübergreifend, wenn C ++ 11-kompatible Compiler vorhanden sind. Dies löst jedoch SIGABRT aus, was in diesem Fall kein wirklich geeignetes Signal zum Erhöhen ist.
Benjamin Crawford Ctrl-Alt-Tut
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.