Bisakah Anda mendapatkan program di Linux untuk mencetak jejak stack jika itu segfaults?

20

Jika saya menjalankan program dari shell, dan itu segfaults:

$ buggy_program
Segmentation fault

Ini akan memberi tahu saya, bagaimanapun, apakah ada cara untuk mendapatkan program untuk mencetak backtrace, mungkin dengan menjalankan sesuatu seperti ini:

$ print_backtrace_if_segfault buggy_program
Segfault in main.c:35
(rest of the backtrace)

Saya juga lebih suka tidak menggunakan strace atau ltrace untuk informasi semacam itu, karena mereka akan mencetak baik ...

Neil
sumber

Jawaban:

25

Mungkin ada cara yang lebih baik, tetapi ini mengotomatiskannya.

Masukkan yang berikut ini ~/backtrace:

backtrace
quit

Masukkan ini dalam skrip yang disebut seg_wrapper.shdalam direktori di jalur Anda:

#!/bin/bash
ulimit -c unlimited
"$@"
if [[ $? -eq 139 ]]; then
    gdb -q $1 core -x ~/backtrace
fi

The ulimitperintah membuatnya begitu inti dibuang. "$@"adalah argumen yang diberikan ke skrip, jadi itu akan menjadi program Anda dan argumennya. $?memegang status keluar, 139 tampaknya menjadi status keluar default untuk mesin saya untuk segfault.

Sebab gdb, -qberarti sunyi (tidak ada pesan intro), dan -xmemberitahu gdbuntuk menjalankan perintah dalam file yang diberikan padanya.

Pemakaian

Jadi untuk menggunakannya, Anda cukup:

seg_wrapper.sh ./mycommand and its arguments 

Memperbarui

Anda juga dapat menulis penangan sinyal yang melakukan ini, lihat tautan ini .

Kyle Brandt
sumber
2
Tautan Anda ke solusi penangan sinyal sudah mati - inilah mengapa jawaban tidak boleh ditautkan ke sumber daya lain ...
josch
1
Anda mungkin bermaksud "-x memberitahu gdb untuk mengeksekusi" bukan "-x memberitahu gdb untuk keluar"
josch
19

Maaf datang ke sini 2 tahun kemudian ... menemukan sambil mencari sesuatu yang lain. Menambahkan ini untuk kelengkapan.

1) Sementara saya pikir jawaban yang diterima bagus, itu membutuhkan gdb. Metode yang saya kenal menggunakan libSegFault.so.

Jika Anda menjalankan aplikasi dengan

LD_PRELOAD = ... path-to ... / libSegFault.so myapp

Anda akan mendapatkan laporan dengan lacak balik, lib yang dimuat, dll

2) Sebuah skrip wrapper catchsegvjuga tersedia yang akan berusaha digunakan addr2lineuntuk menerjemahkan alamat ke nama file + nomor baris.

Ini adalah solusi yang jauh lebih ringan daripada file inti atau gdb (bagus untuk sistem embedded misalnya)

nhed
sumber
Sebenarnya, LD_PRELOAD=libSegFault.sotidak masalah jika ada di jalur dl.
Fernando Silveira
1
@FernandoSilveira ok. Menulis jawaban dengan cara ini mengisyaratkan kepada pembaca bahwa mereka harus memeriksa apa jalan itu.
nhed
6

Anda membutuhkan GDB teman semua orang

gdb <program> [core file]

Setelah Anda memuat corefile Anda, perintah 'backtrace' (dapat disingkat menjadi bt) akan memberi Anda tumpukan panggilan saat ini. Jika Anda menjalankan program dari dalam gdb, Anda dapat mengatur breakpoint sembarang dan memeriksa konten memori, dll.

Tel Janin
sumber
Apakah ada cara untuk mendapatkannya hanya dengan mencetak backtrace dan keluar?
Neil
5

catchsegv

Itu disebutkan dalam jawaban lain (tetapi sama sekali tidak fokus pada). Ini adalah alat praktis yang dibundel dengan proyek glibc. Ini akan memberikan backtrace (dan informasi debug berguna lainnya) hanya jika suatu program memang melakukan segfault.

Tulisan yang bagus ada di sini .

Anda dapat memasukkannya ke dalam skrip Anda sendiri sesuai keinginan Anda.

wulfgarpro
sumber
3

Ubuntu (sebagai proyek) menggunakan Apport untuk melakukan ini. Anda dapat melihat bagaimana mereka melakukannya.

https://wiki.ubuntu.com/Apport

sendmoreinfo
sumber
2
+1: Apport menyebutkan beberapa mekanisme berguna yang tidak saya kenal, seperti/proc/sys/kernel/core_pattern
RobM
2

Ini adalah varian naskah yang sedikit dimodifikasi dari Kyle Brandt. Ini ditingkatkan dengan cara-cara berikut:

  • tidak memerlukan interaksi manual jika stack stack panjang
  • beberapa coredump disimpan dengan inti pola nama., hormati pengaturan ini
  • tidak memerlukan file perintah eksplisit yang terbang di sekitar untuk gdb (itu akan membuat yang sementara)
  • menunggu pekerjaan latar belakang

Naskah:

#!/bin/bash
gdbcommandfile=$(tempfile)
usepid=$(cat /proc/sys/kernel/core_uses_pid)
printf "set pagination off\nbacktrace\nquit\n" > $gdbcommandfile
ulimit -c unlimited
"$@"&
pid=$!
wait $!
if [[ $? -eq 139 ]]; then
    if [[ $usepid == 1 ]]; then 
        gdb -q $1 core.$pid -x $gdbcommandfile
    else
        gdb -q $1 core -x $gdbcommandfile
    fi
fi
rm $gdbcommandfile
Sampai Schäfer
sumber
1
Untuk rantai perintah sederhana seperti itu, saya hanya akan menggunakan -exsebagai gantinya. gdb ... -ex 'set pagination off' -ex backtrace -ex quit
Josh Stone