Setel breakpoint dalam kode C atau C ++ secara terprogram untuk gdb di Linux

105

Bagaimana cara menetapkan breakpoint dalam kode C atau C ++ secara terprogram yang akan berfungsi untuk gdb di Linux?

Yaitu:

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
sumber
8
Sangat banyak catatan tambahan (maaf untuk nitpick), tetapi jika Anda khawatir tentang portabilitas maka Anda mungkin juga khawatir tentang kebenaran - karenanya int maindaripada void main.
Stuart Golodetz
@Stuart - Tetap. Seharusnya sudah melakukan itu beberapa waktu lalu.
J. Polfer
4
@ J.Polfer: Ini return 0tidak perlu, dan hanya kebisingan!
Balapan Ringan di Orbit

Jawaban:

107

Salah satu caranya adalah dengan memberi sinyal interupsi:

#include <csignal>

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

Di C:

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

UPDATE : MSDN menyatakan bahwa Windows tidak benar-benar mendukung SIGINT, jadi jika portabilitas menjadi perhatian, Anda mungkin lebih baik menggunakannya SIGABRT.

Håvard S
sumber
Ya, ini harus bekerja di seluruh sistem operasi / kompiler / debugger.
Håvard S
1
Saya tidak tahu debugger lain, tetapi gdb cukup fleksibel tentang penanganan sinyal .
Kaskabel
4
Kami menemukan SIGTRAP lebih baik di beberapa Unix
JBRWilkinson
1
di Windows, MSVC Anda dapat menggunakan __debug_break, DebugBreak atau _asm {int 3}.
Fernando Gonzalez Sanchez
2
@FernandoGonzalezSanchez: sebenarnya nama fungsinya __debugbreak()dan BUKAN __debug_break() , seperti yang Anda lihat di sini
Morix Dev
27

Dalam proyek yang saya kerjakan, kami melakukan ini:

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

(Dalam kasus kami, kami ingin crash keras jika ini terjadi di luar debugger, menghasilkan laporan kerusakan jika memungkinkan. Itulah salah satu alasan kami menggunakan SIGABRT. Melakukan ini secara portabel di Windows, Mac, dan Linux membutuhkan beberapa upaya. Kami berakhir dengan beberapa #ifdefs, dengan senang hati berkomentar di sini: http://hg.mozilla.org/mozilla-central/file/98fa9c0cff7a/js/src/jsutil.cpp#l66 .)

Jason Orendorff
sumber
2
Seperti biasa, jendela tidak terlihat seperti yang lain :)
mathk
Apakah mungkin mengeluarkan "sinyal 0" untuk melanjutkan program dalam keadaan jeda? Alangkah baiknya bisa menggunakan 'n' atau 's' mulai saat ini, tanpa mengeluarkan 'c'.
Jason Doucette
2
@JasonDoucette Jika Anda benar-benar hanya ingin program untuk jeda, Anda mungkin ingin menambahkan breakpoint()fungsi dalam program Anda (bisa kosong atau hanya berisi pernyataan print) dan menambahkan break breakpointke Anda ~/.gdbinit.
Jason Orendorff
26

Dengan melihat di sini , saya menemukan cara berikut:

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

Ini sepertinya sentuhan hackish bagi saya. Dan menurut saya ini hanya berfungsi pada arsitektur x86.

J. Polfer
sumber
3
Dan hanya dengan kompiler yang mendukung sintaks perakitan AT&T. Secara khusus, compiler Microsoft ( cl.exe) tidak mendukung sintaks ini, tetapi menggunakan sintaks yang berbeda.
Håvard S
pertanyaannya adalah tentang linux, jadi saya kira kita dapat berasumsi bahwa sintaks gcc akan berfungsi untuk x86.
js.
BTW - Saya mencoba yang di atas pada mesin x86 saya dan berhasil. Saya ingin tahu apakah ada cara yang lebih baik untuk melakukannya. Sepertinya ada.
J. Polfer
2
Saya menggunakan mingw di windows sehingga saran lain tidak dapat membantu saya. Menaikkan sinyal SIGINT hanya menghentikan aplikasi, SIGTRAP tidak didefinisikan di header mingw ... Menggunakan instruksi int sebenarnya mengirim SIGTRAP dan gdb putus dengan baik pada baris yang sesuai.
Machta
Di Linux, int 3memunculkan SIGTRAP.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
12

__asm__("int $3"); harus bekerja:

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
sumber
1
Saya suka #defineini, jadi saya tidak perlu terlalu mengingat sintaksnya. Saya memilikinya ditaburkan di seluruh kode saya, kadang-kadang di tempat assert(), sejak menghentikan debiugger, mari saya periksa semua variabel & tumpukan. Dan, tentu saja, seperti menegaskan, saya tidak perlu menghapusnya untuk kode produksi
Mawg mengatakan memulihkan Monica
Menarik bahwa ini memiliki 10 suara positif ketika batasan pertanyaan "Linux" dan "GDB" memberikan banyak pilihan di luar beralih ke perakitan, yang harus selalu menjadi pilihan terakhir demi portabilitas jika tidak ada yang lain. Silakan lihat beberapa jawaban lainnya.
Benjamin Crawford Ctrl-Alt-Tut
5

Mengecewakan untuk melihat begitu banyak jawaban tidak menggunakan sinyal khusus untuk breakpoints software, SIGTRAP:

#include <signal.h>

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

Di OS X Anda bisa menelepon std::abort()(mungkin sama di Linux)

dacap
sumber
Perpustakaan yang mana?
Alex
Ini adalah bagian dari pustaka C ++ standar dan merupakan lintas platform tempat terdapat kompiler yang sesuai dengan C ++ 11. Namun ini, meningkatkan SIGABRT, yang sebenarnya bukan merupakan sinyal yang tepat untuk dinaikkan dalam hal ini.
Benjamin Crawford Ctrl-Alt-Tut