मुझे पता है कि ऐसा करने के लिए कोई मानक C फ़ंक्शन नहीं है। मैं सोच रहा था कि विंडोज और * निक्स पर इसको लेकर क्या तकनीकें हैं? (विंडोज़ XP अभी ऐसा करने के लिए मेरा सबसे महत्वपूर्ण ओएस है।)
मुझे पता है कि ऐसा करने के लिए कोई मानक C फ़ंक्शन नहीं है। मैं सोच रहा था कि विंडोज और * निक्स पर इसको लेकर क्या तकनीकें हैं? (विंडोज़ XP अभी ऐसा करने के लिए मेरा सबसे महत्वपूर्ण ओएस है।)
जवाबों:
glibc बैकट्रेस () फ़ंक्शन प्रदान करता है।
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
char ** backtrace_symbols (void *const *buffer, int size)
void backtrace_symbols_fd(void *const *buffer, int size, int fd)
जो उदाहरण के लिए आउटपुट को सीधे stdout / इरेट पर भेज सकता है।
backtrace_symbols()
बेकार है। इसे सभी प्रतीकों को निर्यात करने की आवश्यकता है और यह DWARF (डीबगिंग) प्रतीकों का समर्थन नहीं करता है। कई (अधिकांश) मामलों में libbacktrace एक बेहतर विकल्प है।
बैकट्रेस (), और बैकट्रेस_सिमबोल () हैं:
आदमी पृष्ठ से:
#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);
...
एक और अधिक सुविधाजनक / ओओपी तरीके से इसका उपयोग करने का एक तरीका एक अपवाद वर्ग निर्माता में बैकट्रेस_सिमबोल () के परिणाम को बचाने के लिए है। इस प्रकार, जब भी आप उस प्रकार के अपवाद को फेंकते हैं तो आपके पास स्टैक ट्रेस होता है। फिर, इसे प्रिंट करने के लिए एक फ़ंक्शन प्रदान करें। उदाहरण के लिए:
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 < frames; ++i) {
printf("%s\n", strs[i]);
}
free(strs);
}
};
...
try {
throw MyException("Oops!");
} catch ( MyException e ) {
e.printStackTrace();
}
ता दा!
नोट: अनुकूलन झंडे को सक्षम करने से परिणामी स्टैक ट्रेस गलत हो सकता है। आदर्श रूप से, कोई इस क्षमता का उपयोग डिबग फ्लैग ऑन और ऑप्टिमाइज़ेशन फ़्लैग के साथ करेगा।
विंडोज के लिए StackWalk64 () एपीआई (32 बिट विंडोज पर भी) की जांच करें। UNIX के लिए आपको OS 'के मूल तरीके का उपयोग करना चाहिए, या ग्लिबेक के बैकट्रेस () में, यदि उपलब्ध हो, तो कमबैक करना चाहिए।
हालाँकि, ध्यान दें कि मूल कोड में स्टैकट्रेस लेना शायद ही कभी एक अच्छा विचार होता है - इसलिए नहीं कि यह संभव नहीं है, बल्कि इसलिए कि आप गलत तरीके से गलत चीज़ को हासिल करने की कोशिश कर रहे हैं।
ज्यादातर समय लोग एक असाधारण परिस्थिति में, एक असाधारण परिस्थिति, जैसे कि एक अपवाद पकड़े जाने पर, एक जोरदार असफलता या - उन सभी में सबसे खराब और सबसे गलत - जब आप एक घातक "अपवाद" या संकेत प्राप्त करते हैं, जैसे एक की कोशिश करते हैं विभाजन का उल्लंघन।
अंतिम मुद्दे पर विचार करते हुए, अधिकांश एपीआई को आपको स्पष्ट रूप से मेमोरी आवंटित करने या आंतरिक रूप से करने की आवश्यकता होगी। नाजुक स्थिति में ऐसा करना जिसमें आपका कार्यक्रम वर्तमान में हो सकता है, अकस्मात चीजों को और भी बदतर बना सकता है। उदाहरण के लिए, क्रैश रिपोर्ट (या coredump) समस्या के वास्तविक कारण को नहीं दर्शाएगी, लेकिन इसे संभालने का आपका असफल प्रयास)।
मुझे लगता है कि आप उस घातक-त्रुटि से निपटने वाली चीज को प्राप्त करने की कोशिश कर रहे हैं, क्योंकि ज्यादातर लोग यह कोशिश करते दिखते हैं कि जब स्टैकट्रेस मिलने की बात हो। यदि ऐसा है, तो मैं डिबगर (विकास के दौरान) और प्रक्रिया को उत्पादन में coredump (या विंडोज़ पर मिनी-डंप) पर निर्भर करने पर निर्भर करता हूँ। उचित प्रतीक-प्रबंधन के साथ-साथ, आपको कारण-निर्देश पोस्टमार्टम का पता लगाने में कोई परेशानी नहीं होनी चाहिए।
आपको खोलना पुस्तकालय का उपयोग करना चाहिए ।
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
संबंधित पीसी के स्रोत फ़ंक्शन / लाइन नंबर प्राप्त करने के लिए लिनक्स पर कमांड का उपयोग कर सकते हैं ।
इसे करने के लिए कोई स्वतंत्र मंच नहीं है।
निकटतम चीज़ जो आप कर सकते हैं वह है बिना अनुकूलन के कोड को चलाना। इस तरह आप प्रक्रिया से जुड़ सकते हैं (दृश्य c ++ डिबगर या GDB का उपयोग करके) और एक प्रयोग करने योग्य स्टैक ट्रेस प्राप्त करें।
सोलारिस में pstack कमांड है, जिसे लिनक्स में भी कॉपी किया गया था।
आप स्टैक को पीछे की तरफ करके कर सकते हैं। वास्तविकता में, हालांकि, प्रत्येक फ़ंक्शन की शुरुआत में एक कॉल स्टैक पर पहचानकर्ता को जोड़ना और अंत में इसे पॉप करना आसान होता है, फिर बस उस प्रिंटिंग सामग्री को चलाएं। यह PITA का एक सा है, लेकिन यह अच्छी तरह से काम करता है और अंत में आपका समय बचाएगा।
पिछले कुछ वर्षों से मैं इयान लांस टेलर की कामेच्छा का उपयोग कर रहा हूं। यह GNU C लाइब्रेरी के कार्यों की तुलना में बहुत अधिक साफ है, जिसमें सभी प्रतीकों को निर्यात करने की आवश्यकता होती है। यह लिबुनविंड की तुलना में पीछे की पीढ़ी के लिए अधिक उपयोगिता प्रदान करता है। और अंतिम लेकिन कम से कम नहीं, यह एएसएलआर द्वारा पराजित नहीं है क्योंकि बाहरी उपकरण जैसे आवश्यक उपकरण हैं addr2line
।
Libbacktrace शुरू में GCC वितरण का हिस्सा था, लेकिन अब इसे बीएसडी लाइसेंस के तहत लेखक द्वारा स्टैंडअलोन लाइब्रेरी के रूप में उपलब्ध कराया गया है:
https://github.com/ianlancetaylor/libbacktrace
लेखन के समय, मैं किसी और चीज का उपयोग नहीं करूंगा जब तक कि मुझे एक मंच पर बैकट्रैक उत्पन्न करने की आवश्यकता नहीं है जो कि libbacktrace द्वारा समर्थित नहीं है।