Cách lập trình gây ra kết xuất lõi trong C / C ++


93

Tôi muốn buộc kết xuất lõi tại một vị trí cụ thể trong ứng dụng C ++ của mình.

Tôi biết tôi có thể làm điều đó bằng cách làm một số việc như:

int * crash = NULL;
*crash = 1;

Nhưng tôi muốn biết có cách nào sạch hơn không?

Nhân tiện, tôi đang sử dụng Linux.


18
Một cách "sạch" hơn để kết xuất lõi? .... hay lắm;)
OJ.

5
Cái này thật dễ thương. Hơn thế nữa sử dụng một boolean ... if ((enum trong c?) Sụp đổ = true) {/ OH SHI ... * /}
Ape-inago

3
BTW, phương pháp đó không hoạt động trong tất cả các UNIX. HPUX, đối với một, cho phép bạn đọc và ghi NULL mà không bị trừng phạt (rất may, điều này có thể định cấu hình).
paxdiablo

1
Tôi vừa học được 3 hoặc 4 điều mới tuyệt vời. Cảm ơn.
Trevor Boyd Smith

@pax thats nhiều hơn một lý do để tìm một cách chung chung;) Cảm ơn
hhafez

Câu trả lời:


76

Tăng tín hiệu số 6 ( SIGABRTtrong Linux) là một cách để thực hiện điều đó (mặc dù hãy nhớ rằng SIGABRT không bắt buộc phải là 6 trong tất cả các triển khai POSIX, vì vậy bạn có thể muốn sử dụng SIGABRTchính giá trị này nếu đây là bất kỳ điều gì khác ngoài quick'n 'mã gỡ lỗi bẩn).

#include <signal.h>
: : :
raise (SIGABRT);

Việc gọi abort()cũng sẽ gây ra kết xuất cốt lõi và bạn thậm chí có thể thực hiện điều này mà không cần chấm dứt quy trình của mình bằng cách gọi fork()sau đó chỉ abort()trong phần con - hãy xem câu trả lời này để biết chi tiết.


7
SIGABRT không bắt buộc phải là tín hiệu số 6 (mặc dù nó thường là - và cụ thể là trên Linux).
Jonathan Leffler

4
Không, bạn nói đúng, không phải vậy nhưng tôi có xu hướng không lo lắng quá nhiều về tính đúng đắn của mã gỡ lỗi. Nếu đó thoát vào môi trường tự nhiên, sự sạch sẽ của mã của tôi là đơn giản nhất của những lo lắng của tôi :-)
paxdiablo

2
Gọi abort () có thể vô dụng trên một số kiến ​​trúc với một số trình biên dịch và một số thư viện C (như gcc và glibc hoặc uClibc trên ARM) bởi vì hàm abort () được khai báo với thuộc tính noreturn và trình biên dịch hoàn toàn tối ưu hóa tất cả thông tin trả về, làm cho tệp lõi không sử dụng được. Bạn không thể theo dõi nó qua lệnh gọi raise () hoặc hủy bỏ (). Vì vậy, tốt hơn nhiều là gọi trực tiếp raise (SIGABRT) hoặc kill (getpid (), SIGABRT), hầu như giống nhau.
Alexander Amelkin

3
Rất tiếc, trên ARM, điều tương tự cũng xảy ra ngay cả khi tăng (SIGABRT). Vì vậy, cách duy nhất để tạo ra một tập tin lõi theo dõi là kill (getpid (), SIGABRT)
Alexander Amelkin

Gợi ý ulimit -c unlimitedtừ câu trả lời của Suvesh Pratapa, đã giúp tôi rất nhiều cho câu trả lời này.
Boris Däppen

74

Một vài năm trước, Google đã phát hành thư viện coredumper .

Tổng quat

Thư viện coredumper có thể được biên dịch thành các ứng dụng để tạo ra các kết xuất cốt lõi của chương trình đang chạy - mà không cần kết thúc. Nó hỗ trợ cả kết xuất lõi đơn và đa luồng, ngay cả khi hạt nhân không hỗ trợ các tệp lõi đa luồng.

Coredumper được phân phối theo các điều khoản của Giấy phép BSD.

Thí dụ

Đây không phải là một ví dụ hoàn chỉnh; nó chỉ đơn giản là mang lại cho bạn cảm giác về giao diện của API coredumper.

#include <google/coredumper.h>
...
WriteCoreDump('core.myprogram');
/* Keep going, we generated a core file,
 * but we didn't crash.
 */

Nó không phải là những gì bạn đang yêu cầu, nhưng có lẽ nó thậm chí còn tốt hơn :)


3
Ban đầu tôi khá hào hứng khi xem câu trả lời này. Nhưng core dumper ngày nay trông khá cũ kỹ và hư hỏng. Có dấu hiệu cho thấy thậm chí là nó không hoạt động nữa trên Linux hiện đại Kernels: stackoverflow.com/questions/38314020/...
jefe2000

37

Như được liệt kê trong trang chủ tín hiệu , bất kỳ tín hiệu nào có hành động được liệt kê là 'lõi' sẽ buộc kết xuất lõi. Một số ví dụ:

SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGSEGV      11       Core    Invalid memory reference

Đảm bảo rằng bạn bật kết xuất lõi:

ulimit -c unlimited

Cảm ơn, nhận xét của bạn về việc kích hoạt bãi chứa lõi với sự ulimit -c unlimitedtrợ giúp.

Bạn sẽ đặt ulimit từ trong mã như thế nào? @ ks1322
Karan Joisher

@KaranJoisher Đó có thể là một câu hỏi đáng giá cho chính nó, nhưng tóm lại, bạn có thể sử dụng setrlimit(RLIMIT_CORE, &core_limits);có sẵn qua #include <sys/resource.h>. Bạn tạo một loại cấu trúc rlimitvà sau đó đặt rlim_currlim_maxcác thành viên.
Brent viết mã

31
#include <stdlib.h>   // C
//#include <cstdlib>  // C++

void core_dump(void)
{
    abort();
}

3
Tại sao không chỉ gọi abort()trực tiếp?
Trầm


6

Một cách khác để tạo kết xuất lõi:

$ bash
$ kill -s SIGSEGV $$

Chỉ cần tạo một phiên bản mới của bash và giết nó bằng tín hiệu được chỉ định. Đây $$là PID của shell. Nếu không, bạn đang giết bash hiện tại của mình và sẽ bị đăng xuất, đóng hoặc ngắt kết nối.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$

Rất đơn giản và hữu ích!
firo

1
Tôi cũng muốn có một cái như vậy. Nó thậm chí có thể được đơn giản hóa thành bash -c 'kill -SIGSEGV $$'.
Christian Krause

4

Bạn có thể sử dụng kill (2) để gửi tín hiệu.

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

Vì thế,

kill(getpid(), SIGSEGV);

Đúng vậy. Đã thêm điều đó vào câu trả lời.
Eugene Yokota

2

Đôi khi có thể thích hợp để làm điều gì đó như sau:

int st = 0;
pid_t p = fork();

if (!p) {
    signal(SIGABRT, SIG_DFL);
    abort(); // having the coredump of the exact copy of the calling thread
} else {
    waitpid(p, &st, 0); // rip the zombie
}

// here the original process continues to live

Một vấn đề với cách tiếp cận đơn giản này là chỉ một luồng sẽ được coredumped.


1
 #include <stdio.h>
 #include <stdlib.h>
 int main()
 {
   printf("\n");
   printf("Process is aborting\n");
   abort();
   printf("Control not reaching here\n");
   return 0;
 }

sử dụng cách tiếp cận này bất cứ nơi nào bạn muốn :)


0
#include <assert.h>
.
.
.
     assert(!"this should not happen");

Có thể cần kết hợp với NDEBUG để xác nhận cụ thể này hoạt động ngay cả khi các xác nhận khác không hoạt động.
Rhys Ulerich
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.