क्या आप लिनक्स में कोई प्रोग्राम प्राप्त कर सकते हैं, अगर यह segfaults का स्टैक ट्रेस प्रिंट करता है?


20

यदि मैं शेल से एक प्रोग्राम चलाता हूं, और यह segfaults:

$ buggy_program
Segmentation fault

हालांकि, यह मुझे बताएगा कि क्या बैकट्रेस प्रिंट करने के लिए प्रोग्राम प्राप्त करने का एक तरीका है, शायद इस तरह से कुछ चलाकर:

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

मैं भी इस तरह की जानकारी के लिए स्ट्रेस या लेट्रेस का उपयोग नहीं करूंगा, क्योंकि वे किसी भी तरह से प्रिंट करेंगे ...

जवाबों:


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

आपको बैकट्रेस, लोडेड लिबास आदि के साथ एक रिपोर्ट मिलेगी

2) एक आवरण स्क्रिप्ट catchsegvभी उपलब्ध है जो addr2lineपते को अनुवाद करने के लिए फ़ाइल नाम + लाइन नंबर का उपयोग करने का प्रयास करेगी ।

ये कोर फ़ाइलों या gdb की तुलना में बहुत हल्के समाधान हैं (उदाहरण के लिए एम्बेडेड सिस्टम के लिए अच्छा)


वास्तव में, LD_PRELOAD=libSegFault.soयदि यह dl पथ में है तो ठीक है।
फर्नांडो सिल्वेरा

1
@FernandoSilveira ठीक है। इस तरह से उत्तर लिखने से पाठक को संकेत मिलता है कि उन्हें जांचना चाहिए कि वह रास्ता क्या है।
ned

6

आपको हर किसी के मित्र GDB की आवश्यकता है

gdb <program> [core file]

एक बार जब आप अपना कोरफ़िल लोड कर लेते हैं, तो कमांड 'बैकट्रेस' (जिसे बीटी के लिए संक्षिप्त किया जा सकता है) आपको वर्तमान कॉल स्टैक देगा। यदि आप अपने प्रोग्राम को जीडीबी के अंदर से चलाते हैं, तो आप मनमाने ब्रेकपॉइंट सेट कर सकते हैं और मेमोरी कंटेंट आदि की जांच कर सकते हैं।


क्या बैकट्रेस प्रिंट करने और बाहर निकलने के लिए इसे प्राप्त करने का कोई तरीका है?
नील

5

catchsegv

यह एक और जवाब में उल्लेख किया गया था (लेकिन किसी भी तरह से ध्यान केंद्रित नहीं किया गया)। यह glibc प्रोजेक्ट के साथ बंडल किया गया एक आसान टूल है। यह एक बैकट्रेस (और अन्य उपयोगी डिबग जानकारी) प्रदान करेगा केवल अगर कोई प्रोग्राम वास्तव में सेगफॉल्ट करता है।

एक अच्छा लेखन यहाँ मौजूद है

आप इसे अपनी स्क्रिप्ट में शामिल कर सकते हैं जैसा कि आप फिट देखते हैं।


3

Ubuntu (एक परियोजना के रूप में) ऐसा करने के लिए Apport का उपयोग करता है। आप देख सकते हैं कि उन्होंने यह कैसे किया।

https://wiki.ubuntu.com/Apport


2
+1: Apport में कुछ उपयोगी तंत्रों का उल्लेख है /proc/sys/kernel/core_pattern
जिनसे

2

यहां काइल ब्रांट से स्क्रिप्ट का थोड़ा संशोधित संस्करण है। यह निम्नलिखित तरीकों से सुधरा है:

  • यदि स्टैक ट्रेस लंबा है, तो मैन्युअल इंटरैक्शन की आवश्यकता नहीं है
  • कुछ कोरपंप नाम पैटर्न कोर के साथ सहेजे जाते हैं। इस सेटिंग का सम्मान करें
  • 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
जोश स्टोन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.