Làm cách nào để tạo kết xuất lõi trong Linux do lỗi phân đoạn?


Câu trả lời:


249

Điều này phụ thuộc vào loại vỏ bạn đang sử dụng. Nếu bạn đang sử dụng bash, thì lệnh ulimit sẽ kiểm soát một số cài đặt liên quan đến thực thi chương trình, chẳng hạn như liệu bạn có nên kết xuất lõi hay không. Nếu bạn gõ

ulimit -c unlimited

sau đó sẽ cho bash biết rằng các chương trình của nó có thể kết xuất các lõi có kích thước bất kỳ. Bạn có thể chỉ định kích thước như 52M thay vì không giới hạn nếu bạn muốn, nhưng trong thực tế, điều này không cần thiết vì kích thước của các tệp lõi có thể sẽ không bao giờ là vấn đề đối với bạn.

Trong tcsh, bạn gõ

limit coredumpsize unlimited

21
@lzprgmr: Để làm rõ: lý do tại sao các kết xuất lõi không được tạo theo mặc định là giới hạn không được đặt và / hoặc được đặt thành 0, điều này ngăn lõi bị đổ. Bằng cách đặt giới hạn không giới hạn, chúng tôi đảm bảo rằng các bãi chứa lõi luôn có thể được tạo.
Eli Courtwright

6
Liên kết này đi sâu hơn và cung cấp thêm một số tùy chọn để cho phép tạo ra các kết xuất lõi trong linux. Hạn chế duy nhất là một số lệnh / cài đặt không được giải thích.
Salsa

6
Trên bash 4.1.2 (1) - các giới hạn giải phóng như 52M không thể được chỉ định, dẫn đến thông báo lỗi số không hợp lệ. Trang man nói rằng "Các giá trị nằm trong khoảng tăng 1024 byte".
a1an

4
Chà, tôi đã có một dự án OpenGL "nhỏ", đã từng làm một số điều kỳ lạ và gây ra sự cố máy chủ X. Khi tôi đăng nhập lại, tôi thấy một tệp lõi 17 GB nhỏ dễ thương (trên phân vùng 25 GB). Đó chắc chắn là một ý tưởng tốt để giữ cho kích thước của tệp lõi bị giới hạn :)
IceCool

1
@PolarisUser: Nếu bạn muốn đảm bảo phân vùng của mình không bị ăn, tôi khuyên bạn nên đặt giới hạn khoảng 1 gig. Điều đó phải đủ lớn để xử lý bất kỳ kết xuất lõi hợp lý nào, trong khi không đe dọa sử dụng hết dung lượng ổ cứng còn lại của bạn.
Eli Courtwright

60

Như đã giải thích ở trên, câu hỏi thực sự được hỏi ở đây là làm thế nào để kích hoạt các bãi rác cốt lõi trên một hệ thống mà chúng không được kích hoạt. Câu hỏi đó được trả lời ở đây.

Nếu bạn đến đây với hy vọng tìm hiểu cách tạo kết xuất lõi cho quy trình treo, câu trả lời là

gcore <pid>

nếu gcore không có sẵn trên hệ thống của bạn thì

kill -ABRT <pid>

Đừng sử dụng kill -SEGV vì điều đó thường sẽ gọi trình xử lý tín hiệu khiến cho việc chẩn đoán quá trình bị kẹt trở nên khó khăn hơn


Tôi nghĩ rằng nhiều khả năng nó -ABRTsẽ gọi trình xử lý tín hiệu hơn -SEGV, vì việc hủy bỏ có nhiều khả năng có thể phục hồi hơn so với một segfault. (Nếu bạn xử lý một segfault, thông thường nó sẽ chỉ kích hoạt lại ngay sau khi trình xử lý của bạn thoát.) Một lựa chọn tốt hơn về tín hiệu để tạo kết xuất lõi là -QUIT.
celticminstrel

32

Để kiểm tra nơi các lõi được tạo ra, hãy chạy:

sysctl kernel.core_pattern

hoặc là:

cat /proc/sys/kernel/core_pattern

nơi %elà tên quy trình và %tthời gian hệ thống. Bạn có thể thay đổi nó trong /etc/sysctl.confvà tải lại bằng cáchsysctl -p .

Nếu các tệp lõi không được tạo (kiểm tra nó bằng cách: sleep 10 &killall -SIGSEGV sleep), hãy kiểm tra các giới hạn bằng cách:ulimit -a .

Nếu kích thước tệp lõi của bạn bị giới hạn, hãy chạy:

ulimit -c unlimited

để làm cho nó không giới hạn.

Sau đó kiểm tra lại, nếu việc bán phá giá lõi thành công, bạn sẽ thấy Rơ (lõi bị đổ) sau dấu hiệu lỗi phân đoạn như sau:

Lỗi phân đoạn: 11 (đổ lõi)

Xem thêm: lõi bị đổ - nhưng tệp lõi không có trong thư mục hiện tại?


Ubuntu

Trong Ubuntu, các bãi chứa lõi được xử lý bởi Apport và có thể được đặt trong /var/crash/. Tuy nhiên, nó bị tắt theo mặc định trong các bản phát hành ổn định.

Để biết thêm chi tiết, vui lòng kiểm tra: Tôi tìm thấy bãi chứa lõi trong Ubuntu ở đâu? .

hệ điều hành Mac

Đối với macOS, hãy xem: Làm cách nào để tạo các kết xuất lõi trong Mac OS X?


3
Đối với Ubuntu, để nhanh chóng trở lại hành vi bình thường (bỏ tập tin lõi trong thư mục hiện tại), chỉ cần dừng dịch vụ apport với "dừng dịch vụ sudo dịch vụ". Cũng lưu ý rằng nếu bạn đang chạy trong docker, cài đặt đó được kiểm soát trên hệ thống máy chủ chứ không phải trong container.
Digicrat

26

Những gì tôi đã làm ở cuối là gắn gdb vào quá trình trước khi nó bị hỏng, và sau đó khi nó nhận được segfault, tôi đã thực thi generate-core-filelệnh. Đó là thế hệ bắt buộc của một bãi chứa lõi.


Làm thế nào bạn đính kèm gdb vào quá trình?
Chani

6
Để trả lời Ritwik G, để đính kèm một quy trình vào gdb, chỉ cần khởi chạy gdb và nhập 'Đính kèm <pid>' trong đó <pid> là số pid của quy trình bạn muốn đính kèm.
Jean-Dominique Frattini

(viết tắt là ge)
user202729

Nếu họ có một câu hỏi mới, họ nên hỏi một câu hỏi mới thay vì hỏi trong một bình luận.
dùng202729

Điều kỳ lạ là tôi đã được thiết lập ulimit -cđể unlimited, nhưng các tập tin cốt lõi là làm yên không tạo ra, generate-core-filetập tin trong phiên gdb không tạo ra các tập tin cốt lõi, cảm ơn.
CodyChan

19

Có lẽ bạn có thể làm theo cách này, chương trình này là một minh họa về cách bẫy lỗi phân đoạn và trình bày với trình gỡ lỗi (đây là mã gốc được sử dụng bên dưới AIX) và in dấu vết ngăn xếp lên đến điểm của lỗi phân đoạn. Bạn sẽ cần thay đổi sprintfbiến để sử dụng gdbtrong trường hợp 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 */
}

Bạn có thể phải thêm một tham số để có được gdb để kết xuất lõi như được hiển thị ở đây trong blog này ở đây .


16

Có nhiều thứ có thể ảnh hưởng đến việc tạo ra một bãi chứa lõi. Tôi đã gặp những điều này:

  • thư mục cho bãi chứa phải được ghi. Theo mặc định, đây là thư mục hiện tại của quy trình, nhưng có thể thay đổi bằng cách đặt/proc/sys/kernel/core_pattern .
  • trong một số điều kiện, giá trị kernel trong /proc/sys/fs/suid_dumpablecó thể ngăn lõi được tạo.

Có nhiều tình huống có thể ngăn chặn thế hệ được mô tả trong trang con người - hãy thử man core.


9

Để kích hoạt kết xuất lõi, hãy làm như sau:

  1. Trong /etc/profilebình luận dòng:

    # ulimit -S -c 0 > /dev/null 2>&1
  2. Trong /etc/security/limits.confbình luận ra dòng:

    *               soft    core            0
  3. thực hiện cmd limit coredumpsize unlimitedvà kiểm tra nó với 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. để kiểm tra xem corefile có được viết hay không, bạn có thể hủy tiến trình liên quan bằng cmd kill -s SEGV <PID>(không cần thiết, chỉ trong trường hợp không có tệp lõi nào được ghi, điều này có thể được sử dụng như một kiểm tra):

    # kill -s SEGV <PID>

Khi corefile đã được viết, hãy đảm bảo hủy kích hoạt lại cài đặt coredump trong các tệp liên quan (1./2./3.)!


9

Dành cho Ubuntu 14.04

  1. Kiểm tra kết xuất lõi được kích hoạt:

    ulimit -a
  2. Một trong những dòng nên là:

    core file size          (blocks, -c) unlimited
  3. Nếu không :

    gedit ~/.bashrcvà thêm ulimit -c unlimitedvào cuối tập tin và lưu, chạy lại thiết bị đầu cuối.

  4. Xây dựng ứng dụng của bạn với thông tin gỡ lỗi:

    Trong Makefile -O0 -g

  5. Chạy ứng dụng tạo kết xuất lõi (tệp kết xuất lõi có tên 'lõi' nên được tạo gần tệp application_name):

    ./application_name
  6. Chạy theo gdb:

    gdb application_name core

Ở Bước 3, Làm thế nào để 'chạy lại' thiết bị đầu cuối? Bạn có nghĩa là khởi động lại?
Naveen

@Naveen không, chỉ cần đóng thiết bị đầu cuối và mở cái mới, dường như bạn chỉ có thể đặt ulimit -c unlimitedthiết bị đầu cuối cho giải pháp tạm thời, bởi vì chỉ chỉnh sửa ~/.bashrcyêu cầu thiết bị đầu cuối khởi động lại để thay đổi có hiệu lực.
mrgloom

4

Theo mặc định, bạn sẽ nhận được một tập tin cốt lõi. Kiểm tra xem thư mục hiện tại của quy trình có thể ghi được không, hoặc không có tệp lõi nào được tạo.


4
Theo "thư mục hiện tại của quy trình", ý bạn là $ cwd tại thời điểm quy trình được chạy? ~ / abc> / usr / bin / cat def nếu mèo gặp sự cố, thư mục hiện tại trong câu hỏi ~ / abc hay / usr / bin?
Nathan Fellman

5
~ / abc. Hmm, bình luận phải dài 15 ký tự!
Đánh dấu Harrison

5
Đây sẽ là thư mục hiện tại tại thời điểm SEGV. Ngoài ra, các quy trình đang chạy với một người dùng và / hoặc nhóm hiệu quả khác với người dùng / nhóm thực sự sẽ không ghi các tệp cốt lõi.
Darron

2

Tốt hơn là bật kết xuất lõi bằng lập trình bằng cách sử dụng lệnh gọi hệ thống setrlimit .

thí dụ:

#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));
}

tại sao điều đó tốt hơn
Nathan Fellman

tập tin lõi được tạo sau sự cố, không cần ulimit -c unlimitedtrong môi trường dòng lệnh và sau đó chạy lại ứng dụng.
kgbook

Tôi không muốn kết xuất lõi mỗi khi nó gặp sự cố, chỉ khi người dùng liên hệ với tôi với tư cách là nhà phát triển để xem xét nó. Nếu nó gặp sự cố 100 lần, tôi không cần phải xem 100 bãi lõi.
Nathan Fellman

Trong trường hợp tha, tốt hơn để sử dụng ulimit -c unlimited. Ngoài ra, bạn có thể biên dịch với định nghĩa marco, ứng dụng sẽ không bao gồm enable_core_dumpký hiệu nếu không xác định macro đó khi phát hành và bạn sẽ nhận được kết xuất lõi thay thế bằng phiên bản gỡ lỗi.
kgbook

ngay cả khi nó đủ điều kiện bởi một macro, điều đó vẫn yêu cầu tôi biên dịch lại nếu tôi muốn tạo một kết xuất lõi, thay vì chỉ thực hiện một lệnh trong trình bao trước khi chạy lại.
Nathan Fellman

1

Điều đáng nói là nếu bạn có một hệ thống được thiết lập, thì mọi thứ sẽ khác đi một chút. Việc thiết lập thường sẽ có các tệp cốt lõi được xử lý core_pattern, thông qua giá trị sysctl, thông qua systemd-coredump(8). Thông thường kích thước tệp lõi rlimit thường được cấu hình là "không giới hạn".

Sau đó có thể lấy các bãi chứa lõi bằng cách sử dụng coredumpctl(1).

Việc lưu trữ các bãi chứa lõi, vv được cấu hình bởi coredump.conf(5). Có các ví dụ về cách lấy các tệp cốt lõi trong trang man coredumpctl, nhưng tóm lại, nó sẽ trông như thế này:

Tìm tập tin cốt lõi:

[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

Lấy tập tin cốt lõi:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163

0

Ubuntu 19.04

Tất cả các câu trả lời khác không giúp tôi. Nhưng tổng hợp sau đây đã làm công việc

Tạo ~/.config/apport/settingsvới nội dung sau:

[main]
unpackaged=true

(Điều này cho biết apport cũng viết các kết xuất cốt lõi cho các ứng dụng tùy chỉnh)

kiểm tra : ulimit -c. Nếu nó xuất ra 0, hãy sửa nó bằng

ulimit -c unlimited

Chỉ dành cho trường hợp khởi động lại apport:

sudo systemctl restart apport

Tập tin sự cố bây giờ được viết bằng /var/crash/. Nhưng bạn không thể sử dụng chúng với gdb. Để sử dụng chúng với gdb, hãy sử dụng

apport-unpack <location_of_report> <target_directory>

Thêm thông tin:

  • Một số câu trả lời đề nghị thay đổi core_pattern. Xin lưu ý rằng tệp đó có thể bị ghi đè bởi dịch vụ apport khi khởi động lại.
  • Đơn giản chỉ cần dừng apport đã không làm công việc
  • Các ulimit -cgiá trị có thể bị thay đổi tự động trong khi bạn đang cố gắng câu trả lời khác của trang web. Hãy chắc chắn kiểm tra nó thường xuyên trong khi thiết lập tạo kết xuất lõi của bạn.

Người giới thiệu:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.