Bạn có thể lấy bất kỳ chương trình nào trong Linux để in dấu vết ngăn xếp nếu nó bị lỗi không?


20

Nếu tôi chạy một chương trình từ shell và nó sẽ phân tách:

$ buggy_program
Segmentation fault

Tuy nhiên, nó sẽ cho tôi biết có cách nào để các chương trình in một backtrace, có lẽ bằng cách chạy một cái gì đó như thế này:

$ print_backtrace_if_segfault buggy_program
Segfault in main.c:35
(rest of the backtrace)

Tôi cũng không nên sử dụng strace hoặc ltrace cho loại thông tin đó, vì họ sẽ in theo bất kỳ cách nào ...

Câu trả lời:


25

Có thể có một cách tốt hơn, nhưng loại tự động hóa nó.

Đặt những thứ sau vào ~/backtrace:

backtrace
quit

Đặt điều này trong một tập lệnh được gọi seg_wrapper.shtrong một thư mục trong đường dẫn của bạn:

#!/bin/bash
ulimit -c unlimited
"$@"
if [[ $? -eq 139 ]]; then
    gdb -q $1 core -x ~/backtrace
fi

Các ulimitlệnh làm cho nó nên cốt lõi được đổ. "$@"là các đối số được đưa ra cho tập lệnh, vì vậy nó sẽ là chương trình của bạn và các đối số của nó. $?giữ trạng thái thoát, 139 dường như là trạng thái thoát mặc định cho máy của tôi cho một segfault.

For gdb, -qcó nghĩa là yên tĩnh (không có thông báo giới thiệu) và -xyêu gdbcầu thực thi các lệnh trong tệp được cung cấp cho nó.

Sử dụng

Vì vậy, để sử dụng nó, bạn sẽ chỉ:

seg_wrapper.sh ./mycommand and its arguments 

Cập nhật

Bạn cũng có thể viết một trình xử lý tín hiệu thực hiện điều này, xem liên kết này .


2
Liên kết của bạn đến giải pháp xử lý tín hiệu đã chết - đây là lý do tại sao câu trả lời không nên liên kết với các tài nguyên khác ...
josch

1
bạn có thể có nghĩa là "-x bảo gdb thực thi" thay vì "-x bảo gdb thoát"
josch

19

Xin lỗi để đến đây 2 năm sau ... vấp ngã trong khi tìm kiếm một cái gì đó khác. Thêm điều này cho đầy đủ.

1) Trong khi tôi nghĩ rằng câu trả lời được chấp nhận là tuyệt vời, nó đòi hỏi gdb. Phương pháp tôi quen thuộc với việc sử dụng libSegFault.so.

Nếu bạn chạy ứng dụng của mình với

LD_PRELOAD = ... đường dẫn đến ... / libSegFault.so myapp

Bạn sẽ nhận được một báo cáo với backtrace, libs được tải, v.v.

2) Một tập lệnh bao bọc catchsegvcũng có sẵn mà sẽ cố gắng sử dụng addr2lineđể dịch địa chỉ sang tên tệp + số dòng.

Đây là những giải pháp nhẹ hơn nhiều so với các tệp lõi hoặc gdb (ví dụ tốt cho các hệ thống nhúng)


Trên thực tế, LD_PRELOAD=libSegFault.sonó là tốt nếu nó là trong con đường dl.
Fernando Silveira

1
@FernandoSilveira ok. Viết câu trả lời theo cách này gợi ý cho người đọc rằng họ nên kiểm tra xem con đường đó là gì.
nhed

6

Bạn cần bạn bè của mọi người GDB

gdb <program> [core file]

Khi bạn đã tải corefile của mình, lệnh 'backtrace' (có thể viết tắt là bt) sẽ cung cấp cho bạn ngăn xếp cuộc gọi hiện tại. Nếu bạn chạy chương trình của mình từ bên trong gdb, bạn có thể đặt các điểm dừng tùy ý và kiểm tra nội dung bộ nhớ, v.v.


Có cách nào để có được nó chỉ để in backtrace và thoát?
Neil

5

Catchsegv

Nó đã được đề cập trong một câu trả lời khác (nhưng không có cách nào tập trung vào). Đây là một công cụ tiện dụng đi kèm với dự án glibc. Nó sẽ cung cấp một backtrace (và thông tin gỡ lỗi hữu ích khác) chỉ khi một chương trình thực sự segfault.

Một văn bản tốt lên tồn tại ở đây .

Bạn có thể đưa nó vào tập lệnh của riêng bạn khi bạn thấy phù hợp.


3

Ubuntu (như một dự án) sử dụng Apport để làm điều này. Bạn có thể nhìn cách họ đã làm điều đó.

https://wiki.ubfox.com/Apport


2
+1: Apport đề cập đến một số cơ chế hữu ích mà tôi không quen thuộc, như/proc/sys/kernel/core_pattern
RobM

2

Đây là một biến thể sửa đổi một chút của kịch bản từ Kyle Brandt. Nó được cải thiện theo những cách sau:

  • không yêu cầu tương tác thủ công nếu dấu vết ngăn xếp dài
  • một số coredumps được lưu với lõi mẫu tên., hãy tôn trọng cài đặt này
  • không yêu cầu tệp lệnh rõ ràng bay xung quanh cho gdb (nó sẽ tạo một tệp tạm thời)
  • chờ công việc nền

Kịch bản:

#!/bin/bash
gdbcommandfile=$(tempfile)
usepid=$(cat /proc/sys/kernel/core_uses_pid)
printf "set pagination off\nbacktrace\nquit\n" > $gdbcommandfile
ulimit -c unlimited
"$@"&
pid=$!
wait $!
if [[ $? -eq 139 ]]; then
    if [[ $usepid == 1 ]]; then 
        gdb -q $1 core.$pid -x $gdbcommandfile
    else
        gdb -q $1 core -x $gdbcommandfile
    fi
fi
rm $gdbcommandfile

1
Đối với một chuỗi các lệnh đơn giản như vậy, tôi sẽ chỉ sử dụng -exthay thế. gdb ... -ex 'set pagination off' -ex backtrace -ex quit
Josh Stone
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.