Linux'ta bir segmentasyon hatası alan bir işlemim var. Başarısız olduğunda bir çekirdek dökümü oluşturmasını nasıl söyleyebilirim?
Linux'ta bir segmentasyon hatası alan bir işlemim var. Başarısız olduğunda bir çekirdek dökümü oluşturmasını nasıl söyleyebilirim?
Yanıtlar:
Bu hangi kabuğu kullandığınıza bağlıdır. Bash kullanıyorsanız, ulimit komutu, program yürütmeyle ilgili olarak çekirdeği boşaltmanız gerekip gerekmediği gibi çeşitli ayarları denetler. Yazarsanız
ulimit -c unlimited
o zaman bash, programlarının herhangi bir boyuttaki çekirdeği dökebileceğini söyleyecektir. İsterseniz sınırsız yerine 52M gibi bir boyut belirtebilirsiniz, ancak uygulamada bu gerekli olmamalıdır çünkü çekirdek dosyaların boyutu muhtemelen sizin için bir sorun olmayacaktır.
Tcsh'de şunu yazarsınız:
limit coredumpsize unlimited
Yukarıda açıklandığı gibi, burada sorulan gerçek soru, etkinleştirilmedikleri bir sistemde çekirdek dökümlerinin nasıl etkinleştirileceği. Bu soru burada cevaplanıyor.
Buraya, asılı bir işlem için çekirdek dökümü oluşturmayı öğrenmek için geldiyseniz, cevap
gcore <pid>
sisteminizde gcore yoksa o zaman
kill -ABRT <pid>
Kill -SEGV işlevini kullanmayın, çünkü bu genellikle sıkışmış işlemi teşhis etmeyi zorlaştıran bir sinyal işleyiciyi harekete geçirir
-ABRT
olduğundan -SEGV
, bir sinyal işleyicisi çağırmak çok daha muhtemel olduğunu düşünüyorum . (Bir segfault ile uğraşırsanız, normalde işleyiciniz çıkar çıkmaz tekrar tetiklenir.) Bir çekirdek dökümü oluşturmak için daha iyi bir sinyal seçimi -QUIT
.
Çekirdek dökümlerin nerede oluşturulduğunu kontrol etmek için şunu çalıştırın:
sysctl kernel.core_pattern
veya:
cat /proc/sys/kernel/core_pattern
%e
işlem adı ve %t
sistem saati nerede . İçinde değiştirebilirsiniz/etc/sysctl.conf
ve yenidensysctl -p
.
Çekirdek dosyalar oluşturulmazsa (tarafından test edin: sleep 10 &
vekillall -SIGSEGV sleep
) ile sınırlarını kontrol: ulimit -a
.
Temel dosya boyutunuz sınırlıysa, çalıştırın:
ulimit -c unlimited
sınırsız yapmak.
Sonra tekrar test edin, çekirdek boşaltma başarılı olursa, segmentasyon hatası göstergesinden sonra aşağıdaki gibi “(çekirdek boşaltma)” görürsünüz:
Segmentasyon hatası: 11 (çekirdek boşaltıldı)
Ayrıca bkz: çekirdek dökümü - ancak çekirdek dosya geçerli dizinde değil mi?
Ubuntu'da çekirdek dökümler Apport tarafından işlenir ve içinde bulunabilir /var/crash/
. Ancak, kararlı sürümlerde varsayılan olarak devre dışıdır.
Daha fazla ayrıntı için lütfen kontrol edin: Ubuntu'daki çekirdek dökümü nerede bulabilirim? .
MacOS için, bkz . Mac OS X'te çekirdek dökümleri nasıl oluşturulur?
Sonunda yaptığım, çökmeden önce işleme gdb eklemek oldu ve sonra segfault aldığında generate-core-file
komutu yürüttüm . Çekirdek bir dökümün zorla üretilmesi.
ge
)
ulimit -c
için unlimited
, ancak çekirdek dosyası hiçbir yaratılmış kabiliyetini kaybetmemiş olan, generate-core-file
gdb oturumda dosya sayesinde çekirdek dosyası oluşturmak yapar.
Belki bu şekilde yapabilirsiniz, bu program bir segmentasyon hatası tuzak ve bir hata ayıklayıcı için kabukları (bu altında kullanılan orijinal kodudur AIX
) ve yığın izlemesi bir segmentasyon hatası noktasına kadar yazdırır. Linux sprintf
için kullanılacak değişkeni değiştirmeniz gerekecektir gdb
.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
Bu blogda burada gösterildiği gibi ek çekirdek dökümü olsun gdb bir parametre eklemek gerekebilir burada .
Bir çekirdek dökümü oluşumunu etkileyebilecek daha fazla şey var. Bunlarla karşılaştım:
/proc/sys/kernel/core_pattern
. /proc/sys/fs/suid_dumpable
çekirdeğin üretilmesini engelleyebilir.Man sayfasında açıklanan nesli engelleyebilecek daha fazla durum vardır - deneyin man core
.
Çekirdek dökümü etkinleştirmek için aşağıdakileri yapın:
Yorumda /etc/profile
satır:
# ulimit -S -c 0 > /dev/null 2>&1
Gelen /etc/security/limits.conf
hat üzerinden comment:
* soft core 0
cmd'yi çalıştırın ve cmd limit coredumpsize unlimited
ile kontrol edin limit
:
# limit coredumpsize unlimited
# limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 10240 kbytes
coredumpsize unlimited
memoryuse unlimited
vmemoryuse unlimited
descriptors 1024
memorylocked 32 kbytes
maxproc 528383
#
corefile yazılıp yazılmadığını kontrol etmek için ilgili işlemi cmd ile öldürebilirsiniz kill -s SEGV <PID>
(gerekli olmamalıdır, sadece çekirdek dosyanın yazılmaması durumunda bu bir kontrol olarak kullanılabilir):
# kill -s SEGV <PID>
Core dosyası yazıldıktan sonra ilgili dosyalarda (1./2./3.) Coredump ayarlarını tekrar devre dışı bıraktığınızdan emin olun!
Ubuntu 14.04 için
Çekirdek boşaltma etkin olup olmadığını kontrol edin:
ulimit -a
Çizgilerden biri şöyle olmalıdır:
core file size (blocks, -c) unlimited
Değilse:
gedit ~/.bashrc
ve ulimit -c unlimited
dosyanın sonuna ekleyin ve kaydedin, terminali yeniden çalıştırın.
Hata ayıklama bilgileriyle uygulamanızı oluşturun:
Makefile bölgesinde -O0 -g
Çekirdek dökümü oluşturan uygulamayı çalıştırın ('core' adıyla çekirdek dökümü dosyası application_name dosyasının yakınında oluşturulmalıdır):
./application_name
GDB altında çalıştırın:
gdb application_name core
ulimit -c unlimited
geçici çözüm için sadece terminali koyabileceğiniz gibi görünüyor , çünkü sadece düzenleme ~/.bashrc
, değişikliklerin etkili olması için terminal kısıtlayıcısı gerektiriyor.
Varsayılan olarak bir çekirdek dosyası alırsınız. İşlemin geçerli dizininin yazılabilir olduğunu veya herhangi bir çekirdek dosya oluşturulmayacağını kontrol edin.
Sistem aramasını kullanarak çekirdek dökümü programlı olarak açmak daha iyidir setrlimit
.
misal:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
ulimit -c unlimited
komut satırı ortamında ve sonra uygulamayı yeniden çalıştırın.
ulimit -c unlimited
. Ayrıca marco tanımı ile derleyebilirsiniz, uygulama enable_core_dump
serbest bırakıldığında bu makroyu tanımlamazsa sembol içermez ve hata ayıklama sürümü ile bir çekirdek dökümü alırsınız.
Eğer bir varsa söz It değerinde systemd setini, işler biraz farklı. Kurulum tipik olarak temel dosyaların core_pattern
sysctl değeri aracılığıyla iletilmesini sağlar systemd-coredump(8)
. Çekirdek dosya boyutu sınırı genellikle "sınırsız" olarak yapılandırılır.
Daha sonra kullanarak çekirdek döküntülerini almak mümkündür coredumpctl(1)
.
Çekirdek dökümlerin depolanması vb. İle yapılandırılır coredump.conf(5)
. Coredumpctl man sayfasındaki temel dosyaların nasıl alınacağına dair örnekler var, ancak kısaca şöyle görünecektir:
Çekirdek dosyayı bulun:
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Çekirdek dosyayı edinin:
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Ubuntu 19.04
Diğer tüm cevaplar bana yardımcı olmadı. Ancak aşağıdaki özet, işi yaptı
Oluşturmak ~/.config/apport/settings
şu içeriğe sahip:
[main]
unpackaged=true
(Bu, apport'a ayrıca özel uygulamalar için temel dökümler yazmasını söyler)
kontrol edin ulimit -c
. 0 çıktısı verirse,
ulimit -c unlimited
Sadece yeniden başlatma uygulamasında:
sudo systemctl restart apport
Kilitlenme dosyaları şimdi yazıldı /var/crash/
. Ama olamaz gdb ile kullanabilirsiniz. Gdb ile kullanmak için
apport-unpack <location_of_report> <target_directory>
Daha fazla bilgi:
core_pattern
. Bu dosyanın yeniden başlatma sırasında apport hizmeti tarafından üzerine yazılabileceğini unutmayın.ulimit -c
Web'de diğer cevaplar çalışırlarken değer otomatik olarak değişmiş olabilir olsun. Çekirdek döküm oluşturma işleminizi ayarlarken düzenli olarak kontrol ettiğinizden emin olun.Referanslar: