Bagaimana cara menghasilkan dump inti di Linux pada kesalahan segmentasi?

217

Saya memiliki proses di Linux yang mendapatkan kesalahan segmentasi. Bagaimana saya bisa mengatakannya untuk menghasilkan dump inti ketika gagal?

Nathan Fellman
sumber
1
Cara melihatnya aftewards: stackoverflow.com/questions/8305866/...
Ciro Santilli郝海东冠状病六四事件法轮功

Jawaban:

249

Ini tergantung pada shell apa yang Anda gunakan. Jika Anda menggunakan bash, maka perintah ulimit mengontrol beberapa pengaturan yang berkaitan dengan eksekusi program, seperti apakah Anda harus membuang inti. Jika Anda mengetik

ulimit -c unlimited

maka itu akan memberi tahu bash bahwa programnya dapat membuang inti dari berbagai ukuran. Anda dapat menentukan ukuran seperti 52M daripada yang tidak terbatas jika Anda mau, tetapi dalam praktiknya ini tidak perlu karena ukuran file inti mungkin tidak akan pernah menjadi masalah bagi Anda.

Di tcsh, Anda akan mengetik

limit coredumpsize unlimited
Eli Courtwright
sumber
21
@ lzprgmr: Untuk memperjelas: alasan mengapa core dump tidak dihasilkan secara default adalah bahwa batasnya tidak disetel dan / atau diatur ke 0, yang mencegah core untuk dibuang. Dengan menetapkan batas tidak terbatas, kami menjamin bahwa dump inti selalu dapat dihasilkan.
Eli Courtwright
6
Tautan ini masuk lebih dalam dan memberikan lebih banyak opsi untuk memungkinkan pembuatan dump inti di linux. Satu-satunya kelemahan adalah bahwa beberapa perintah / pengaturan dibiarkan tidak dijelaskan.
Salsa
6
Pada bash 4.1.2 (1) - batasan rilis seperti 52M tidak dapat ditentukan, menghasilkan pesan kesalahan nomor yang tidak valid. Halaman manual mengatakan bahwa "Nilai-nilai berada dalam peningkatan 1024 byte".
a1an
4
Yah saya punya proyek OpenGL "kecil", yang pernah melakukan hal aneh, dan menyebabkan crash X-server. Ketika saya login kembali, saya melihat file inti 17 GB kecil yang lucu (pada partisi 25 GB). Ini pasti ide yang baik untuk menjaga ukuran file inti terbatas :)
IceCool
1
@PolarisUser: Jika Anda ingin memastikan partisi Anda tidak dimakan, saya sarankan menetapkan batas sesuatu seperti 1 manggung. Itu harus cukup besar untuk menangani dump inti yang masuk akal, sementara tidak mengancam untuk menggunakan semua ruang hard drive yang tersisa.
Eli Courtwright
60

Seperti dijelaskan di atas, pertanyaan sebenarnya yang diajukan di sini adalah bagaimana mengaktifkan dump inti pada sistem di mana mereka tidak diaktifkan. Pertanyaan itu terjawab di sini.

Jika Anda datang ke sini berharap belajar cara menghasilkan dump inti untuk proses yang digantung, jawabannya adalah

gcore <pid>

jika gcore tidak tersedia di sistem Anda maka

kill -ABRT <pid>

Jangan gunakan kill -SEGV karena itu akan sering memanggil penangan sinyal sehingga lebih sulit untuk mendiagnosis proses macet

George Co
sumber
Saya pikir itu jauh lebih mungkin yang -ABRTakan memanggil penangan sinyal daripada -SEGV, karena pembatalan lebih mungkin dipulihkan daripada segfault. (Jika Anda menangani segfault, biasanya itu hanya akan memicu lagi begitu pawang Anda keluar.) Pilihan sinyal yang lebih baik untuk menghasilkan dump inti adalah -QUIT.
celticminstrel
32

Untuk memeriksa di mana core dump dihasilkan, jalankan:

sysctl kernel.core_pattern

atau:

cat /proc/sys/kernel/core_pattern

di mana %enama proses dan %twaktu sistem. Anda dapat mengubahnya /etc/sysctl.confdan memuat ulang oleh sysctl -p.

Jika file inti tidak dihasilkan (uji dengan: sleep 10 &dan killall -SIGSEGV sleep), periksa batas oleh: ulimit -a.

Jika ukuran file inti Anda terbatas, jalankan:

ulimit -c unlimited

untuk membuatnya tidak terbatas.

Kemudian uji lagi, jika core dumping berhasil, Anda akan melihat "(core dumped)" setelah indikasi kesalahan segmentasi seperti di bawah ini:

Kesalahan segmentasi: 11 (core dumped)

Lihat juga: core dumped - tetapi file inti tidak ada di direktori saat ini?


Ubuntu

Di Ubuntu, dump inti ditangani oleh Apport dan dapat ditemukan di /var/crash/. Namun, ini dinonaktifkan secara default di rilis stabil.

Untuk detail lebih lanjut, silakan periksa: Di mana saya menemukan dump inti di Ubuntu? .

macOS

Untuk macOS, lihat: Bagaimana cara menghasilkan core dumps di Mac OS X?

kenorb
sumber
3
Untuk Ubuntu, untuk dengan cepat kembali ke perilaku normal (membuang file inti di direktori saat ini), cukup hentikan layanan apport dengan "sudo service apport stop". Perhatikan juga bahwa jika Anda berjalan di dalam buruh pelabuhan, pengaturan itu dikontrol pada sistem host dan bukan di dalam wadah.
Digicrat
26

Apa yang saya lakukan pada akhirnya adalah melampirkan gdb ke proses sebelum crash, dan kemudian ketika mendapat segfault saya menjalankan generate-core-fileperintah. Itu memaksa generasi dump inti.

Nathan Fellman
sumber
Bagaimana Anda melampirkan gdb ke proses?
Chani
6
Untuk menjawab Ritwik G, untuk melampirkan proses ke gdb, cukup luncurkan gdb dan masukkan 'attach <pid>' di mana <pid> adalah nomor pid dari proses yang ingin Anda lampirkan.
Jean-Dominique Frattini
(disingkat ge)
user202729
Jika mereka memiliki pertanyaan baru, mereka harus mengajukan pertanyaan baru alih-alih bertanya dalam komentar.
user202729
Yang aneh adalah saya sudah mengatur ulimit -cuntuk unlimited, tetapi file inti masih tidak dibuat, generate-core-filefile dalam sesi gdb membuat file inti, terima kasih.
CodyChan
19

Mungkin Anda bisa melakukannya dengan cara ini, program ini adalah demonstrasi cara menjebak kesalahan segmentasi dan shell ke debugger (ini adalah kode asli yang digunakan di bawah AIX) dan mencetak jejak stack hingga ke titik kesalahan segmentasi. Anda perlu mengubah sprintfvariabel yang akan digunakan gdbdalam kasus Linux.

#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 */
}

Anda mungkin harus menambahkan parameter untuk mendapatkan gdb untuk membuang inti seperti yang ditunjukkan di sini di blog ini di sini .

t0mm13b
sumber
16

Ada banyak hal yang dapat memengaruhi pembentukan dump inti. Saya menemukan ini:

  • direktori untuk dump harus dapat ditulis. Secara default ini adalah direktori proses saat ini, tetapi itu dapat diubah dengan pengaturan /proc/sys/kernel/core_pattern.
  • dalam beberapa kondisi, nilai kernel di /proc/sys/fs/suid_dumpabledapat mencegah core dihasilkan.

Ada lebih banyak situasi yang dapat mencegah generasi yang dijelaskan di halaman manual - coba man core.

mlutescu
sumber
9

Untuk mengaktifkan core dump, lakukan hal berikut:

  1. Dalam /etc/profileberkomentar, baris:

    # ulimit -S -c 0 > /dev/null 2>&1
  2. Dalam /etc/security/limits.confkomentar di luar garis:

    *               soft    core            0
  3. jalankan cmd limit coredumpsize unlimiteddan periksa dengan cmd 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
    #
  4. untuk memeriksa apakah corefile ditulis, Anda dapat mematikan proses yang berkaitan dengan cmd kill -s SEGV <PID>(tidak diperlukan, kalau-kalau tidak ada file inti yang ditulis, ini dapat digunakan sebagai cek):

    # kill -s SEGV <PID>

Setelah corefile telah ditulis pastikan untuk menonaktifkan pengaturan coredump lagi di file terkait (1./2./3.)!

Edgar Jordi
sumber
9

Untuk Ubuntu 14.04

  1. Periksa dump inti diaktifkan:

    ulimit -a
  2. Salah satu garis harus:

    core file size          (blocks, -c) unlimited
  3. Jika tidak :

    gedit ~/.bashrcdan tambahkan ulimit -c unlimitedke akhir file dan simpan, jalankan kembali terminal.

  4. Bangun aplikasi Anda dengan informasi debug:

    Di Makefile -O0 -g

  5. Jalankan aplikasi yang membuat dump inti (file dump inti dengan nama 'core' harus dibuat di dekat file application_name):

    ./application_name
  6. Jalankan di bawah gdb:

    gdb application_name core
mrgloom
sumber
Pada Langkah 3, Bagaimana cara 'menjalankan kembali' terminal? Maksud Anda reboot?
Naveen
@Naveen tidak, cukup tutup terminal dan buka yang baru, juga sepertinya Anda bisa memasukkan ulimit -c unlimitedterminal untuk solusi sementara, karena hanya mengedit yang ~/.bashrcmemerlukan terminal restart untuk perubahan membuat efek.
mrgloom
4

Secara default Anda akan mendapatkan file inti. Periksa untuk melihat bahwa direktori saat ini dari proses dapat ditulisi, atau tidak ada file inti yang akan dibuat.

Mark Harrison
sumber
4
Dengan "direktori proses saat ini", maksud Anda $ cwd pada saat proses dijalankan? ~ / abc> / usr / bin / cat def jika cat crash, apakah direktori saat ini dipertanyakan ~ / abc atau / usr / bin?
Nathan Fellman
5
~ / abc. Hmm, komentar harus sepanjang 15 karakter!
Mark Harrison
5
Ini akan menjadi direktori saat ini pada saat SEGV. Juga, proses yang berjalan dengan pengguna dan / atau grup efektif berbeda dari pengguna / grup sebenarnya tidak akan menulis file inti.
Darron
2

Lebih baik menyalakan core dump secara terprogram menggunakan system call setrlimit.

contoh:

#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));
}
kgbook
sumber
mengapa itu lebih baik?
Nathan Fellman
file inti yang dihasilkan setelah crash, tidak perlu ulimit -c unlimiteddi lingkungan baris perintah, dan kemudian jalankan kembali aplikasi.
kgbook
Saya tidak ingin dump inti setiap kali crash, hanya ketika pengguna menghubungi saya sebagai pengembang untuk melihatnya. Jika crash 100 kali, saya tidak perlu 100 core dump untuk melihatnya.
Nathan Fellman
Dalam hal ini, lebih baik digunakan ulimit -c unlimited. Anda juga dapat mengkompilasi dengan definisi marco, aplikasi tidak akan menyertakan enable_core_dumpsimbol jika tidak mendefinisikan makro saat rilis, dan Anda akan mendapatkan penggantian dump inti dengan versi debug.
kgbook
bahkan jika itu dikualifikasi oleh makro, itu masih mengharuskan saya untuk mengkompilasi ulang jika saya ingin menghasilkan dump inti, daripada hanya menjalankan perintah di shell sebelum menjalankan kembali.
Nathan Fellman
1

Perlu disebutkan bahwa jika Anda memiliki set sistemd , maka hal-hal sedikit berbeda. Pengaturan biasanya akan memiliki file inti yang akan disalurkan, melalui core_patternnilai sysctl, melalui systemd-coredump(8). Ukuran file inti rlimit biasanya akan dikonfigurasikan sebagai "tidak terbatas".

Maka dimungkinkan untuk mengambil dump inti dengan menggunakan coredumpctl(1).

Penyimpanan dump inti, dll. Dikonfigurasi oleh coredump.conf(5). Ada beberapa contoh cara mendapatkan file inti di halaman manual coredumpctl, tetapi singkatnya, akan terlihat seperti ini:

Temukan file inti:

[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

Dapatkan file inti:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Pawel Veselov
sumber
0

Ubuntu 19.04

Semua jawaban lain sendiri tidak membantu saya. Tapi jumlah berikut berhasil

Buat ~/.config/apport/settingsdengan konten berikut:

[main]
unpackaged=true

(Ini memberitahu apport juga untuk menulis dump inti untuk aplikasi khusus)

periksa: ulimit -c. Jika output 0, perbaiki dengan

ulimit -c unlimited

Hanya untuk dalam kasus restart apport:

sudo systemctl restart apport

File kerusakan sekarang ditulis dalam bahasa /var/crash/. Tetapi Anda tidak dapat menggunakannya dengan gdb. Untuk menggunakannya dengan gdb, gunakan

apport-unpack <location_of_report> <target_directory>

Informasi lebih lanjut:

  • Beberapa jawaban menyarankan perubahan core_pattern. Ketahuilah, bahwa file itu mungkin akan ditimpa oleh layanan yang sesuai saat memulai ulang.
  • Menghentikan permintaan tidak melakukan pekerjaan
  • The ulimit -cnilai mungkin akan berubah secara otomatis saat Anda sedang mencoba jawaban lain dari web. Pastikan untuk memeriksanya secara teratur selama pengaturan pembuatan inti sampah Anda.

Referensi:

DarkTrick
sumber