Linux'ta bir yığın izlemesi yazdırıyorsa herhangi bir program alabilir misiniz?


20

Kabuktan bir program çalıştırırsam ve segfaults:

$ buggy_program
Segmentation fault

Ancak bana, belki de böyle bir şey çalıştırarak programların geri iz yazdırmasını sağlamanın bir yolu olduğunu söyleyecektir:

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

Ayrıca, bu tür bilgiler için strace veya ltrace kullanmamayı tercih ederim, çünkü her iki şekilde de basacaklar ...

Yanıtlar:


25

Daha iyi bir yol olabilir, ancak bu tür bir otomatiğe sahiptir.

Aşağıdakileri yerleştirin ~/backtrace:

backtrace
quit

Bunu, yolunuzdaki seg_wrapper.shbir dizinde çağrılan bir komut dosyasına yerleştirin :

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

ulimitÇekirdek boşaltılır, böylece bir komut yapar. "$@"betiğe verilen argümanlardır, bu yüzden programınız ve argümanları olacaktır. $?çıkış durumunu tutar, 139 bir segfault için makinem için varsayılan çıkış durumu gibi görünüyor.

Çünkü gdb, -qsessiz (giriş mesajı yok) anlamına gelir ve -xkendisine gdbverilen dosyada komutları çalıştırmayı söyler .

kullanım

Yani kullanmak için sadece:

seg_wrapper.sh ./mycommand and its arguments 

Güncelleme

Bunu yapan bir sinyal işleyici de yazabilirsiniz, bu bağlantıya bakın .


2
Sinyal işleyici çözümüne bağlantınız öldü - bu yüzden cevaplar diğer kaynaklara bağlanmamalıdır ...
josch

1
Muhtemelen "-x gdb'nin çalıştırılmasını söyler" yerine "-x gdb'ye çıkmasını söyler"
josch

19

2 yıl sonra buraya geldiğim için üzgünüm ... başka bir şey ararken tökezledi. Bunu bütünlük için ekliyoruz.

1) Kabul edilen cevabın harika olduğunu düşünüyorum, ancak gdb gerektiriyor. Bildiğim yöntem libSegFault.so kullanır.

Uygulamanızı şu şekilde çalıştırırsanız:

LD_PRELOAD = ... yol ... / libSegFault.so myapp

Geri izleme, yüklü kütüphaneler, vb. İçeren bir rapor alırsınız

2) Adresleri dosya adı + satır numarasına çevirmek catchsegviçin kullanmaya çalışan bir sarıcı komut dosyası da mevcuttur addr2line.

Bunlar çekirdek dosyalardan veya gdb'den çok daha hafif çözümler (örneğin gömülü sistemler için iyi)


Aslında, LD_PRELOAD=libSegFault.sodl yolunda ise iyidir.
Fernando Silveira

1
@FernandoSilveira tamam. Cevabı bu şekilde yazmak okuyucuya bu yolun ne olduğunu kontrol etmeleri gerektiğini ima eder.
nhed

6

Herkesin arkadaşı GDB'ye ihtiyacınız var

gdb <program> [core file]

Corefile'ınızı yükledikten sonra, 'backtrace' (bt olarak kısaltılabilir) komutu size mevcut çağrı yığınını verecektir. Programınızı gdb içinden çalıştırırsanız, rastgele kesme noktaları ayarlayabilir ve bellek içeriğini vb. İnceleyebilirsiniz.


Sadece geri izini yazdırıp çıkmanın bir yolu var mı?
Neil

5

catchsegv

Başka bir cevapta bahsedildi (ancak hiçbir şekilde odaklanmadı). Glibc projesi ile birlikte gelen kullanışlı bir araçtır. Yalnızca bir program gerçekten de segfault yaparsa bir geri izleme (ve diğer yararlı hata ayıklama bilgileri) sağlar .

İyi bir yazma yukarı var burada .

Uygun gördüğünüz gibi kendi komut dosyalarınıza ekleyebilirsiniz.


3

Ubuntu (bir proje olarak) bunu yapmak için Apport'u kullanır. Nasıl yaptıklarına bakabilirsiniz.

https://wiki.ubuntu.com/Apport


2
+1: Apport, aşina olmadığım bazı yararlı mekanizmalardan bahsediyor, örneğin/proc/sys/kernel/core_pattern
RobM

2

Kyle Brandt'ın senaryosunun biraz değiştirilmiş bir çeşidi. Aşağıdaki şekillerde geliştirilir:

  • yığın izi uzunsa manuel etkileşim gerektirmez
  • bazı coredumps ad desen çekirdeği ile kaydedilir, bu ayara uyun
  • gdb için uçan açık bir komut dosyası gerektirmez (geçici bir komut dosyası oluşturur)
  • arka plan işlerini bekle

Senaryo:

#!/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

1
Böyle basit komutların bir zinciri için, sadece -exbunun yerine kullanırım. gdb ... -ex 'set pagination off' -ex backtrace -ex quit
Josh Stone
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.