Tôi có một quy trình trong Linux đó là lỗi phân đoạn. Làm thế nào tôi có thể bảo nó tạo ra một bãi chứa lõi khi nó thất bại?
Tôi có một quy trình trong Linux đó là lỗi phân đoạn. Làm thế nào tôi có thể bảo nó tạo ra một bãi chứa lõi khi nó thất bại?
Câu trả lời:
Đ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
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
-ABRT
sẽ 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
.
Để 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 %e
là tên quy trình và %t
thời gian hệ thống. Bạn có thể thay đổi nó trong /etc/sysctl.conf
và 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 &
và 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?
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? .
Đố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?
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-file
lệnh. Đó là thế hệ bắt buộc của một bãi chứa lõi.
ge
)
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-file
tập tin trong phiên gdb không tạo ra các tập tin cốt lõi, cảm ơn.
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 sprintf
biến để sử dụng gdb
trong 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 .
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:
/proc/sys/kernel/core_pattern
. /proc/sys/fs/suid_dumpable
có 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
.
Để kích hoạt kết xuất lõi, hãy làm như sau:
Trong /etc/profile
bình luận dòng:
# ulimit -S -c 0 > /dev/null 2>&1
Trong /etc/security/limits.conf
bình luận ra dòng:
* soft core 0
thực hiện cmd limit coredumpsize unlimited
và 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
#
để 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.)!
Dành cho Ubuntu 14.04
Kiểm tra kết xuất lõi được kích hoạt:
ulimit -a
Một trong những dòng nên là:
core file size (blocks, -c) unlimited
Nếu không :
gedit ~/.bashrc
và thêm ulimit -c unlimited
vào cuối tập tin và lưu, chạy lại thiết bị đầu cuối.
Xây dựng ứng dụng của bạn với thông tin gỡ lỗi:
Trong Makefile -O0 -g
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
Chạy theo gdb:
gdb application_name core
ulimit -c unlimited
thiết bị đầu cuối cho giải pháp tạm thời, bởi vì chỉ chỉnh sửa ~/.bashrc
yêu cầu thiết bị đầu cuối khởi động lại để thay đổi có hiệu lực.
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.
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));
}
ulimit -c unlimited
trong môi trường dòng lệnh và sau đó chạy lại ứng 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_dump
ký 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.
Đ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
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/settings
vớ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:
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.ulimit -c
giá 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: