2008-09-19 15 views
68

मुझे पता है कि ऐसा करने के लिए कोई मानक सी फ़ंक्शन नहीं है। मैं सोच रहा था कि विंडोज़ और * निक्स पर इसकी क्या तकनीकें हैं? (विंडोज एक्सपी अभी यह करने के लिए मेरा सबसे महत्वपूर्ण ओएस है।)सी में एक स्टैक ट्रेस कैसे पकड़ सकता है?

+1

कर्नेल के लिए: http://stackoverflow.com/questions/21143924/how-to-print-the-current-thread-stack-trace-in-c, सी/सी ++ संस्करण: http: // stackoverflow। कॉम/प्रश्न/38 99870/प्रिंट-कॉल-स्टैक-इन-सी-या-सी –

उत्तर

20

हम अपने परियोजनाओं के लिए इस का उपयोग किया है:

https://www.codeproject.com/kb/threads/stackwalker.aspx

कोड एक बालक गंदा IMHO है, लेकिन यह अच्छी तरह से काम करता है। केवल विंडोज़

+2

लिंक काम नहीं करता है। क्या यह http://www.codeproject.com/KB/threads/StackWalker.aspx होना चाहिए? – squelart

+0

यह मेरे लिए काम करता है –

+3

संयोग से, अधिक हालिया कोड @ http://stackwalker.codeplex.com/ बनाए रखा गया है लेकिन कोडप्रोजेक्ट पेज मुख्य दस्तावेज के रूप में अभी भी उपयोगी है। – PeterT

-1

आप इसे पीछे की ओर चलकर कर सकते हैं। हकीकत में, हालांकि, प्रत्येक फ़ंक्शन की शुरुआत में एक कॉल स्टैक पर पहचानकर्ता को जोड़ना और अंत में पॉप करना अक्सर आसान होता है, फिर बस उस सामग्री को प्रिंट करना चलें। यह एक पिटा का थोड़ा सा है, लेकिन यह अच्छी तरह से काम करता है और अंत में आपको समय बचाएगा।

+1

क्या आप "पीछे की ओर ढेर चलने" की व्याख्या कर सकते हैं? – Spidey

3

ऐसा करने के लिए कोई मंच स्वतंत्र तरीका नहीं है।

निकटतम चीज़ जो आप कर सकते हैं अनुकूलन के बिना कोड चलाने के लिए है। इस तरह आप प्रक्रिया से संलग्न हो सकते हैं (विज़ुअल सी ++ डीबगर या जीडीबी का उपयोग करके) और उपयोग करने योग्य स्टैक ट्रेस प्राप्त करें।

+0

फ़ील्ड में एम्बेडेड कंप्यूटर पर क्रैश होने पर यह मेरी सहायता नहीं करता है। :( – Kevin

+0

@ केविन: यहां तक ​​कि एम्बेडेड मशीनों पर भी, रिमोट डीबगर स्टब या कम से कम कोर डंप प्राप्त करने का आमतौर पर एक तरीका होता है। हो सकता है कि यह फ़ील्ड पर तैनात न हो, हालांकि ... – ephemient

+0

यदि आप gcc-glibc का उपयोग करते हैं पसंद विंडोज़/लिनक्स/मैक का आपका मंच ... फिर बैकट्रैक() और बैकट्रैस_सिमबॉल्स() सभी तीन प्लेटफार्मों पर काम करेगा। उस कथन को देखते हुए, मैं शब्दों का उपयोग करता हूं "ऐसा करने के लिए कोई [पोर्टेबल] तरीका नहीं है"। –

73

ग्लिबैक बैकट्रैक() फ़ंक्शन प्रदान करता है।

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

+6

glibc fTW ... फिर से। (यह एक और कारण है कि जब मैं सी प्रोग्रामिंग (वह और उसके साथ चलने वाला कंपाइलर) आता है तो मैं ग्लिब को पूर्ण स्वर्ण मानक मानता हूं।) –

+4

लेकिन प्रतीक्षा करें और भी कुछ है!बैकट्रैक() फ़ंक्शन केवल कॉलस्टैक फ़ंक्शंस का प्रतिनिधित्व करने वाले शून्य * पॉइंटर्स की एक सरणी प्रदान करता है। "यह बहुत उपयोगी नहीं है। तर्क।" डर नहीं! glibc एक फ़ंक्शन प्रदान करता है जो सभी शून्य * पते (कॉलस्टैक फ़ंक्शन पते) को मानव पठनीय स्ट्रिंग प्रतीकों में परिवर्तित करता है। 'char ** backtrace_symbols (शून्य * कॉन्स * बफर, int आकार)' –

+0

मुझे लगता है कि कार्यों के लिए प्रतीक नाम के लिए शून्य * - आईएमओ जो कुछ बहुत ही अद्भुत वूडू-ब्लैकमैजिक है। –

2

सोलारिस में pstack कमांड है, जिसे लिनक्स में भी कॉपी किया गया था।

+1

उपयोगी, लेकिन वास्तव में नहीं सी (यह एक बाहरी उपयोगिता है)। – ephemient

+0

भी, विवरण (सेक्शन: प्रतिबंध) "से: pstack वर्तमान में केवल लिनक्स पर काम करता है, केवल 32 बिट ईएलएफ बाइनरी चलाने वाले x86 मशीन पर (64 बिट समर्थित नहीं है)" –

20

विंडोज के लिए StackWalk64() API (32 बिट विंडोज़ पर भी) की जांच करें। यूनिक्स के लिए आपको इसे करने के लिए ओएस के मूल तरीके का उपयोग करना चाहिए, या यदि ग्लैब के बैकट्रैस() में फॉलबैक हो, तो लाभ उठाएं।

नोट हालांकि मूल कोड में स्टैकट्रैक लेना शायद ही कोई अच्छा विचार है - क्योंकि यह संभव नहीं है, लेकिन क्योंकि आप हमें गलत तरीके से प्राप्त करने की कोशिश कर रहे हैं।

ज्यादातर समय लोग असाधारण परिस्थिति में एक स्टैकट्रैक प्राप्त करने का प्रयास करते हैं, जैसे अपवाद पकड़ा जाता है, एक जोर विफल रहता है - - उनमें से सबसे खराब और सबसे गलत - जब आपको घातक "अपवाद" मिलता है या एक सेगमेंटेशन उल्लंघन की तरह सिग्नल।

अंतिम समस्या को ध्यान में रखते हुए, अधिकांश एपीआई आपको स्पष्ट रूप से स्मृति आवंटित करने या आंतरिक रूप से करने की आवश्यकता होगी। नाजुक स्थिति में ऐसा करना जिसमें आपका प्रोग्राम वर्तमान में हो सकता है, अकसर चीजों को और भी बदतर बना सकता है। उदाहरण के लिए, क्रैश रिपोर्ट (या coredump) समस्या के वास्तविक कारण को प्रतिबिंबित नहीं करेगी, लेकिन इसे संभालने का आपका असफल प्रयास)।

मुझे लगता है कि आप उस घातक-त्रुटि-हैंडलिंग चीज को प्राप्त करने की कोशिश कर रहे हैं, क्योंकि ज्यादातर लोग ऐसा लगता है कि स्टैकट्रैक प्राप्त करने की बात आती है। यदि ऐसा है, तो मैं डीबगर (विकास के दौरान) पर निर्भर करता हूं और उत्पादन को प्रक्रिया में coredump (या खिड़कियों पर मिनी डंप) देने पर भरोसा करता हूं। उचित प्रतीक प्रबंधन के साथ, आपको पोस्टिंग मॉर्टम के कारण निर्देश को समझने में कोई परेशानी नहीं होनी चाहिए।

+2

आप मेमोरी आवंटन का प्रयास करने के लिए नाजुक होने के बारे में सही हैं एक सिग्नल या अपवाद हैंडलर में। एक संभावित तरीका प्रोग्राम शुरू होने पर "आपातकालीन" स्थान की एक निश्चित राशि आवंटित करना है, या एक स्थिर बफर का उपयोग करना है। –

+0

एक और तरीका एक coredump सेवा बना रहा है, जो स्वतंत्र रूप से – Kobor42

4

विंडोज के लिए, CaptureStackBackTrace() भी एक विकल्प है, जिसके लिए StackWalk64() से उपयोगकर्ता के अंत में कम तैयारी कोड की आवश्यकता होती है। (इसके अलावा, मेरे पास एक समान परिदृश्य के लिए, CaptureStackBackTrace()StackWalk64() से बेहतर (अधिक विश्वसनीय) काम कर रहा था।)

2

मई मैं आपको अपने लेख पर इंगित कर सकता हूं। यह कोड की केवल कुछ पंक्तियां हैं।

Post Mortem Debugging

हालांकि मैं वर्तमान में x64 implementation of this समस्याएं आ रही हैं।

4

आपको unwind library का उपयोग करना चाहिए।

unw_cursor_t cursor; unw_context_t uc; 
unw_word_t ip, sp; 
unw_getcontext(&uc); 
unw_init_local(&cursor, &uc); 
unsigned long a[100]; 
int ctr = 0; 

while (unw_step(&cursor) > 0) { 
    unw_get_reg(&cursor, UNW_REG_IP, &ip); 
    unw_get_reg(&cursor, UNW_REG_SP, &sp); 
    if (ctr >= 10) break; 
    a[ctr++] = ip; 
} 

आपका दृष्टिकोण तब भी ठीक काम करेगा जब तक आप साझा लाइब्रेरी से कॉल नहीं करते।

आप संबंधित पीसी के स्रोत फ़ंक्शन/लाइन नंबर प्राप्त करने के लिए लिनक्स पर addr2line कमांड का उपयोग कर सकते हैं।

आदमी पृष्ठ से::

+0

"स्रोत समारोह/रेखा संख्या" चलाता है? अगर लिंकिंग को कम कोड आकार के लिए अनुकूलित किया गया है तो क्या होगा? हालांकि, मैं कहूंगा कि यह एक उपयोगी प्रोजेक्ट की तरह दिखता है। एक दयालुता है कि रजिस्टरों को पाने का कोई तरीका नहीं है। मैं निश्चित रूप से इसमें देख लूंगा। क्या आप जानते हैं कि यह बिल्कुल प्रोसेसर स्वतंत्र है? सी संकलक वाले किसी भी चीज़ पर बस काम करता है? – Mawg

+1

ठीक है यह टिप्पणी इसके लायक थी, अगर केवल सहायक addr2line कमांड के उल्लेख के कारण! –

+0

addr2line एएसएलआर के साथ सिस्टम पर स्थानांतरित करने योग्य कोड के लिए विफल रहता है (यानी पिछले दशक के दौरान लोग जो उपयोग कर रहे हैं)। –

23

पश्व-अनुरेखन(), और backtrace_symbols() नहीं है

 #include <execinfo.h> 
    #include <stdio.h> 
    ... 
    void* callstack[128]; 
    int i, frames = backtrace(callstack, 128); 
    char** strs = backtrace_symbols(callstack, frames); 
    for (i = 0; i < frames; ++i) { 
     printf("%s\n", strs[i]); 
    } 
    free(strs); 
    ... 

एक तरह से एक और अधिक सुविधाजनक/OOP तरीके से इस का उपयोग करने के backtrace_symbols का परिणाम (बचाने के लिए है) एक अपवाद वर्ग कन्स्ट्रक्टर में। इस प्रकार, जब भी आप उस प्रकार के अपवाद को फेंक देते हैं तो आपके पास स्टैक ट्रेस होता है। फिर, इसे प्रिंट करने के लिए बस एक फ़ंक्शन प्रदान करें। उदाहरण के लिए:

 

class MyException : public std::exception { 

    char ** strs; 
    MyException(const std::string & message) { 
     int i, frames = backtrace(callstack, 128); 
     strs = backtrace_symbols(callstack, frames); 
    } 

    void printStackTrace() { 
     for (i = 0; i 

...

 

try { 
    throw MyException("Oops!"); 
} catch (MyException e) { 
    e.printStackTrace(); 
} 
 

टा दा!

नोट: अनुकूलन झंडे को सक्षम करने से परिणामी स्टैक ट्रेस गलत हो सकता है। आदर्श रूप में, कोई इस क्षमता का उपयोग डीबग झंडे और अनुकूलन झंडे के साथ करेगा।

+7

जीसीसी को – shuckc

+0

@shuckc को केवल एक प्रतीक स्ट्रिंग में परिवर्तित करने के लिए 'srdc' काम करने के लिए '-गतिशील' तर्क की आवश्यकता होती है, जिसे आवश्यकता होने पर अन्य उपकरणों का उपयोग करके बाहरी रूप से किया जा सकता है। –

0

पिछले कुछ सालों से मैं इयान लांस टेलर के libbacktrace का उपयोग कर रहा हूं। यह जीएनयू सी पुस्तकालय में कार्यों की तुलना में बहुत साफ है जिसके लिए सभी प्रतीकों का निर्यात करने की आवश्यकता है। यह libunwind की तुलना में बैकट्रैस की पीढ़ी के लिए और अधिक उपयोगिता प्रदान करता है। और आखिरी लेकिन कम से कम नहीं, यह एएसएलआर द्वारा पराजित नहीं है क्योंकि बाहरी उपकरण जैसे addr2line की आवश्यकता होती है।

Libbacktrace शुरू में जीसीसी वितरण का हिस्सा था, लेकिन अब यह एक BSD लाइसेंस के तहत एक स्टैंडअलोन पुस्तकालय के रूप में लेखक द्वारा उपलब्ध कराया गया है:

https://github.com/ianlancetaylor/libbacktrace

लेखन के समय, मैं का उपयोग नहीं होता कुछ और जब तक मुझे प्लेटफॉर्म पर बैकट्रैस उत्पन्न करने की आवश्यकता नहीं होती है जो libbacktrace द्वारा समर्थित नहीं है।

संबंधित मुद्दे