คุณสามารถรับโปรแกรมใด ๆ ใน Linux เพื่อพิมพ์การติดตามสแต็กถ้าเป็น segfaults หรือไม่


20

ถ้าฉันเรียกใช้โปรแกรมจากเชลล์และมันคือ segfaults:

$ buggy_program
Segmentation fault

มันจะบอกฉันว่ามีวิธีให้โปรแกรมพิมพ์ backtrace หรือไม่โดยใช้บางสิ่งเช่นนี้

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

ฉันไม่ควรใช้ strace หรือ ltrace สำหรับข้อมูลประเภทนั้นเพราะพวกเขาจะพิมพ์ด้วยวิธีใดวิธีหนึ่ง ...

คำตอบ:


25

อาจมีวิธีที่ดีกว่า แต่ระบบอัตโนมัติแบบนี้

ใส่ต่อไปนี้ใน~/backtrace:

backtrace
quit

ใส่สิ่งนี้ในสคริปต์ที่เรียกว่าseg_wrapper.shในไดเรกทอรีในเส้นทางของคุณ:

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

ulimitคำสั่งที่ทำให้แกนทิ้ง "$@"เป็นอาร์กิวเมนต์ที่กำหนดให้กับสคริปต์ดังนั้นจึงเป็นโปรแกรมและข้อโต้แย้งของคุณ $?เก็บสถานะการออก 139 ดูเหมือนว่าจะเป็นสถานะการออกเริ่มต้นสำหรับเครื่องของฉันสำหรับ segfault

สำหรับgdb, -qหมายถึงเงียบ (ไม่มีข้อความแนะนำ), และ-xบอกgdbให้รันคำสั่งในไฟล์ที่ให้ไว้

การใช้

เพื่อที่จะใช้มันคุณแค่:

seg_wrapper.sh ./mycommand and its arguments 

ปรับปรุง

คุณสามารถเขียนตัวจัดการสัญญาณที่ทำสิ่งนี้ดูลิงค์นี้


2
ลิงก์ของคุณไปยังโซลูชันตัวจัดการสัญญาณนั้นตายแล้ว - นี่คือสาเหตุที่คำตอบไม่ควรเชื่อมโยงไปยังแหล่งข้อมูลอื่น ๆ ...
josch

1
คุณอาจหมายถึง "-x บอกให้ gdb เรียกใช้งาน" แทนที่จะเป็น "-x บอกให้ gdb ออก"
josch

19

ขออภัยที่จะมาที่นี่อีก 2 ปีต่อมา ... สะดุดในขณะที่มองหาอย่างอื่น การเพิ่มสิ่งนี้เพื่อความสมบูรณ์

1) ในขณะที่ฉันคิดว่าคำตอบที่ยอมรับนั้นยอดเยี่ยม แต่ต้องใช้ gdb วิธีที่ฉันคุ้นเคยกับการใช้ libSegFault.so

หากคุณเปิดแอพด้วย

LD_PRELOAD = ... เส้นทางไปยัง ... / libSegFault.so myapp

คุณจะได้รับรายงานที่มี backtrace, libs ที่โหลดเป็นต้น

2) สคริปต์ตัวตัดคำcatchsegvมีอยู่ซึ่งจะพยายามใช้addr2lineเพื่อแปลที่อยู่เป็นชื่อไฟล์ + หมายเลขบรรทัด

เหล่านี้เป็นโซลูชั่นที่เบากว่าไฟล์หลักหรือ gdb (ดีสำหรับระบบฝังตัวเช่น)


ที่จริงแล้วLD_PRELOAD=libSegFault.soก็ดีถ้าอยู่ในเส้นทาง dl
เฟอร์นันโดซิลวีรา

1
@FernandoSilveira ตกลง การเขียนคำตอบด้วยวิธีนี้จะบอกผู้อ่านว่าพวกเขาควรตรวจสอบว่าเส้นทางนั้นคืออะไร
พฤศจิกายน

6

คุณต้องการเพื่อนของ GDB

gdb <program> [core file]

เมื่อคุณโหลด corefile แล้วคำสั่ง 'backtrace' (สามารถย่อให้เป็น bt) จะให้ call stack ปัจจุบัน หากคุณรันโปรแกรมจากภายใน gdb คุณสามารถตั้งค่าเบรกพอยต์ตามอำเภอใจและตรวจสอบเนื้อหาหน่วยความจำ ฯลฯ


มีวิธีที่จะได้รับเพียงพิมพ์ backtrace และออก?
Neil

5

catchsegv

มันถูกกล่าวถึงในคำตอบอื่น (แต่ไม่ได้มุ่งเน้นไปที่) มันเป็นเครื่องมือที่มีประโยชน์รวมกับโครงการ glibc มันจะให้ backtrace (และข้อมูลการแก้ปัญหาที่มีประโยชน์อื่น ๆ ) เฉพาะในกรณีที่โปรแกรม segfault แน่นอน

ดีเขียนขึ้นมาอยู่ที่นี่

คุณสามารถรวมไว้ในสคริปต์ของคุณเองตามที่เห็นสมควร


3

Ubuntu (เป็นโครงการ) ใช้ Apport เพื่อทำสิ่งนี้ คุณสามารถดูว่าพวกเขาทำมันได้อย่างไร

https://wiki.ubuntu.com/Apport


2
+1: Apport กล่าวถึงกลไกที่มีประโยชน์บางอย่างที่ฉันไม่คุ้นเคยเช่น/proc/sys/kernel/core_pattern
RobM

2

นี่คือตัวแปรที่แตกต่างกันเล็กน้อยของสคริปต์จาก Kyle Brandt ได้รับการปรับปรุงในวิธีต่อไปนี้:

  • ไม่ต้องการการโต้ตอบแบบแมนนวลหากการติดตามสแต็กยาว
  • coredumps บางตัวจะถูกบันทึกด้วย core pattern pattern., เคารพการตั้งค่านี้
  • ไม่ต้องใช้ไฟล์คำสั่งที่ชัดเจนสำหรับ gdb (มันจะสร้างไฟล์ชั่วคราว)
  • รองานพื้นหลัง

สคริปต์:

#!/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
สำหรับโซ่ของคำสั่งง่ายๆเช่นนี้ฉันจะใช้-exแทน gdb ... -ex 'set pagination off' -ex backtrace -ex quit
Josh Stone
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.