जब मेरा प्रोग्राम क्रैश हो जाता है तो स्वचालित रूप से एक स्टैकट्रेस कैसे जेनरेट करें


590

मैं जीसीसी संकलक के साथ लिनक्स पर काम कर रहा हूं। जब मेरा C ++ प्रोग्राम क्रैश हो जाता है, तो मैं चाहूंगा कि यह स्वचालित रूप से एक स्टैकट्रेस उत्पन्न करे।

मेरा कार्यक्रम कई अलग-अलग उपयोगकर्ताओं द्वारा चलाया जा रहा है और यह लिनक्स, विंडोज और मैकिंटोश (सभी संस्करणों का उपयोग करके संकलित किया गया है gcc) पर भी चलता है ।

मैं चाहूंगा कि मेरा प्रोग्राम क्रैश होने पर स्टैक ट्रेस जनरेट करने में सक्षम हो और अगली बार जब उपयोगकर्ता इसे चलाता है, तो यह उनसे पूछेगा कि क्या स्टैक ट्रेस मेरे पास भेजना ठीक है ताकि मैं समस्या का पता लगा सकूं। मैं मुझे जानकारी भेजने का काम संभाल सकता हूं लेकिन मुझे नहीं पता कि ट्रेस स्ट्रिंग कैसे उत्पन्न की जाए। कोई विचार?


4
backtrace और backtrace_symbols_fd async-signal-safe नहीं हैं। आपको सिग्नल हैंडलर में इन फ़ंक्शन का उपयोग नहीं करना चाहिए
पराग बाफना

10
backtrace_symbols मॉलॉक को कॉल करते हैं, और इसलिए सिग्नल हैंडलर में इसका उपयोग नहीं किया जाना चाहिए। अन्य दो फ़ंक्शंस (बैकट्रेस और बैकट्रेस_सिमबोलस_फ़्ड) में यह समस्या नहीं है, और आमतौर पर सिग्नल हैंडलर में उपयोग किया जाता है।
cmccabe

3
@cmccabe कि गलत backtrace_symbols_fd आमतौर पर है malloc फोन नहीं करता है लेकिन कुछ अपने catch_error ब्लॉक में गलत हो जाता है हो सकता है यदि
सैम केसर

6
यह इस अर्थ में "हो सकता है" कि backtrace_symbols_fd (या किसी भी backtrace) के लिए कोई POSIX युक्ति नहीं है; हालाँकि, GNU / Linux के backtrace_symbols_fd को linux.die.net/man/3/backtrace_symbols_fd के अनुसार कभी भी मॉलोक नहीं कहा जाता है । इसलिए, यह मान लेना सुरक्षित है कि यह लिनक्स पर मॉलॉक को कभी नहीं बुलाएगा।
कोडेटाकु

यह कैसे दुर्घटनाग्रस्त होता है?
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

जवाबों:


509

लिनक्स के लिए और मेरा मानना ​​है कि अगर आप gcc, या glibc का उपयोग करने वाले किसी भी कंपाइलर का उपयोग कर रहे हैं, तो आप execinfo.hएक विभाजन फॉल्ट प्रिंट करने के लिए बैकट्रेस () फ़ंक्शंस का उपयोग कर सकते हैं और जब आप एक विभाजन दोष प्राप्त करते हैं। परिवाद मैनुअल में प्रलेखन पाया जा सकता है ।

यहां एक उदाहरण कार्यक्रम है जो एक SIGSEGVहैंडलर को स्थापित करता है और stderrजब इसे सेगफल्ट करता है तो स्टैकट्रेस प्रिंट करता है । यहाँ baz()फ़ंक्शन हैंडलर को ट्रिगर करने वाले सेगफ़ॉल्ट का कारण बनता है:

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>


void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

void baz() {
 int *foo = (int*)-1; // make a bad pointer
  printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler
  foo(); // this will call foo, bar, and baz.  baz segfaults.
}

संकलन के साथ -g -rdynamicआपको अपने आउटपुट में प्रतीक सूचना मिलती है, जिसे ग्लिब्क एक अच्छा स्टैकट्रेस बनाने के लिए उपयोग कर सकता है:

$ gcc -g -rdynamic ./test.c -o test

इसे निष्पादित करने से आपको यह आउटपुट मिलता है:

$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]

यह लोड मॉड्यूल, ऑफसेट और फ़ंक्शन को दिखाता है कि स्टैक में प्रत्येक फ्रेम से आया था। यहाँ आप से पहले ढेर के शीर्ष, और libc कार्यों पर संकेत हैंडलर देख सकते हैं mainइसके अलावा करने के लिए main, foo, bar, और baz


53
/Lib/libSegFault.so भी है जिसे आप LD_PRELOAD के साथ उपयोग कर सकते हैं।
सीजरबी

6
ऐसा लगता है कि आपके बैकट्रेस आउटपुट में पहले दो प्रविष्टियों में सिग्नल हैंडलर के अंदर एक रिटर्न एड्रेस होता है और शायद एक sigaction()लीबक में अंदर होता है। जबकि आपकी बैकट्रेस सही प्रतीत होती है, मैंने कभी-कभी यह पाया है कि बैकट्रेस में गलती का वास्तविक स्थान सुनिश्चित करने के लिए अतिरिक्त कदम आवश्यक हैं क्योंकि इसे sigaction()कर्नेल द्वारा अधिलेखित किया जा सकता है ।
jschmier

9
अगर मॉलॉक के अंदर से दुर्घटना आती है तो क्या होगा? क्या आप तब ताला नहीं पकड़ेंगे और फिर "बैकट्रेस" के रूप में अटक सकते हैं जो स्मृति को आवंटित करने की कोशिश करता है?
मटियास निल्सन

7
catchsegvयह नहीं है कि ओपी को क्या चाहिए लेकिन विभाजन के दोषों को पकड़ने और सभी जानकारी प्राप्त करने के लिए बहुत बढ़िया है।
मैट क्लार्कसन

8
एआरएम के लिए, मुझे -फंडविंड-टेबल का भी संकलन करना था। अन्यथा मेरी ढेर की गहराई हमेशा 1 (खाली) थी।
jfritz42

128

"मैन बैकट्रेस" की तुलना में यह बहुत आसान है, लिबसेगफॉल्ट. एसो के रूप में ग्लिबक के साथ वितरित एक छोटा-सा प्रलेखित पुस्तकालय (जीएनयू विशिष्ट) है, जो मुझे लगता है कि प्रोग्राम कैचसेगव का समर्थन करने के लिए उलरिच ड्रेपर द्वारा लिखा गया था (देखें "मैन कैचसेगव")।

इससे हमें 3 संभावनाएँ मिलती हैं। "प्रोग्राम -ओ है" चलाने के बजाय:

  1. Catchsegv के भीतर चलाएं:

    $ catchsegv program -o hai
  2. रनटाइम में libSegFault के साथ लिंक:

    $ LD_PRELOAD=/lib/libSegFault.so program -o hai
  3. संकलन समय पर libSegFault के साथ लिंक करें:

    $ gcc -g1 -lSegFault -o program program.cc
    $ program -o hai
    

सभी 3 मामलों में, आपको कम अनुकूलन (gcc -O0 या -O1) और डीबगिंग प्रतीकों (gcc -g) के साथ स्पष्ट बैकट्रैक मिलेंगे। अन्यथा, आप मेमोरी पतों के ढेर के साथ समाप्त हो सकते हैं।

आप कुछ के साथ स्टैक के निशान के लिए अधिक संकेत भी पकड़ सकते हैं:

$ export SEGFAULT_SIGNALS="all"       # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt"  # SIGBUS and SIGABRT

आउटपुट कुछ इस तरह दिखाई देगा (नीचे की ओर बैकट्रेस देखें):

*** Segmentation fault Register dump:

 EAX: 0000000c   EBX: 00000080   ECX:
00000000   EDX: 0000000c  ESI:
bfdbf080   EDI: 080497e0   EBP:
bfdbee38   ESP: bfdbee20

 EIP: 0805640f   EFLAGS: 00010282

 CS: 0073   DS: 007b   ES: 007b   FS:
0000   GS: 0033   SS: 007b

 Trap: 0000000e   Error: 00000004  
OldMask: 00000000  ESP/signal:
bfdbee20   CR2: 00000024

 FPUCW: ffff037f   FPUSW: ffff0000  
TAG: ffffffff  IPOFF: 00000000  
CSSEL: 0000   DATAOFF: 00000000  
DATASEL: 0000

 ST(0) 0000 0000000000000000   ST(1)
0000 0000000000000000  ST(2) 0000
0000000000000000   ST(3) 0000
0000000000000000  ST(4) 0000
0000000000000000   ST(5) 0000
0000000000000000  ST(6) 0000
0000000000000000   ST(7) 0000
0000000000000000

Backtrace:
/lib/libSegFault.so[0xb7f9e100]
??:0(??)[0xb7fa3400]
/usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775]
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801]

यदि आप गौरी विवरण जानना चाहते हैं, तो सबसे अच्छा स्रोत दुर्भाग्य से स्रोत है: http://sourceware.org/git/?p=glibc.git/a=blob;f=debug/segfault.c और उसके मूल निर्देशिका देखें http://sourceware.org/git/?p=glibc.git;a=tree;f=debug


1
"संभावना 3. संकलन समय पर libSegFault के साथ लिंक" काम नहीं करता है।
HHK

5
@ उत्तर: आपका क्या मतलब है "काम नहीं करता है"। आपने क्या कोशिश की है, किस भाषा / संकलक / टूलकिन / वितरण / हार्डवेयर पर? क्या यह संकलन में विफल रहा? त्रुटि पकड़ने के लिए? सब पर उत्पादन का उत्पादन करने के लिए? उपयोग करने के लिए उत्पादन मुश्किल है? विवरण के लिए धन्यवाद, यह सभी की मदद करेगा।
स्टीफन गौरिचोन

1
'सबसे अच्छा स्रोत दुर्भाग्य से स्रोत है' ... उम्मीद है, किसी दिन, कैचसेग के लिए आदमी पृष्ठ वास्तव में SEGFAULT_SIGNALS का उल्लेख करेगा। उस समय तक, यह जवाब देने के लिए है।
16

मुझे विश्वास नहीं हो रहा है कि मैं 5 साल से C की प्रोग्रामिंग कर रहा हूं और इस बारे में कभी नहीं सुना: /
DavidMFrey

6
@ StéphaneGourichon @HansKratz libSegFault के साथ लिंक -Wl,--no-as-neededकरने के लिए आपको संकलक झंडे में जोड़ना होगा । अन्यथा, ldवास्तव में के खिलाफ लिंक नहीं होगा libSegFault, क्योंकि यह मानता है कि बाइनरी अपने किसी भी प्रतीक का उपयोग नहीं करता है।
फिलिप

122

लिनक्स

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

जब आप सिग्नल हैंडलर में आते हैं तो स्टैक फ्रेम श्रृंखला में पहले दो प्रविष्टियाँ सिग्नल हैंडलर के अंदर एक रिटर्न एड्रेस और एक लिबास के अंदर (lib) में होती हैं। सिग्नल (जो कि गलती का स्थान है) से पहले अंतिम फ़ंक्शन का स्टैक फ्रेम खो गया है।

कोड

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>

/* This structure mirrors the one found in /usr/include/asm/ucontext.h */
typedef struct _sig_ucontext {
 unsigned long     uc_flags;
 struct ucontext   *uc_link;
 stack_t           uc_stack;
 struct sigcontext uc_mcontext;
 sigset_t          uc_sigmask;
} sig_ucontext_t;

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
 void *             array[50];
 void *             caller_address;
 char **            messages;
 int                size, i;
 sig_ucontext_t *   uc;

 uc = (sig_ucontext_t *)ucontext;

 /* Get the address at the time the signal was raised */
#if defined(__i386__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
#elif defined(__x86_64__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
#else
#error Unsupported architecture. // TODO: Add support for other arch.
#endif

 fprintf(stderr, "signal %d (%s), address is %p from %p\n", 
  sig_num, strsignal(sig_num), info->si_addr, 
  (void *)caller_address);

 size = backtrace(array, 50);

 /* overwrite sigaction with caller's address */
 array[1] = caller_address;

 messages = backtrace_symbols(array, size);

 /* skip first stack frame (points here) */
 for (i = 1; i < size && messages != NULL; ++i)
 {
  fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);
 }

 free(messages);

 exit(EXIT_FAILURE);
}

int crash()
{
 char * p = NULL;
 *p = 0;
 return 0;
}

int foo4()
{
 crash();
 return 0;
}

int foo3()
{
 foo4();
 return 0;
}

int foo2()
{
 foo3();
 return 0;
}

int foo1()
{
 foo2();
 return 0;
}

int main(int argc, char ** argv)
{
 struct sigaction sigact;

 sigact.sa_sigaction = crit_err_hdlr;
 sigact.sa_flags = SA_RESTART | SA_SIGINFO;

 if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
 {
  fprintf(stderr, "error setting signal handler for %d (%s)\n",
    SIGSEGV, strsignal(SIGSEGV));

  exit(EXIT_FAILURE);
 }

 foo1();

 exit(EXIT_SUCCESS);
}

उत्पादन

signal 11 (Segmentation fault), address is (nil) from 0x8c50
[bt]: (1) ./test(crash+0x24) [0x8c50]
[bt]: (2) ./test(foo4+0x10) [0x8c70]
[bt]: (3) ./test(foo3+0x10) [0x8c8c]
[bt]: (4) ./test(foo2+0x10) [0x8ca8]
[bt]: (5) ./test(foo1+0x10) [0x8cc4]
[bt]: (6) ./test(main+0x74) [0x8d44]
[bt]: (7) /lib/libc.so.6(__libc_start_main+0xa8) [0x40032e44]

सिग्नल हैंडलर में बैकट्रेस () फ़ंक्शन को कॉल करने के सभी खतरे अभी भी मौजूद हैं और इसे अनदेखा नहीं किया जाना चाहिए, लेकिन मुझे लगता है कि मैंने यहां वर्णित कार्यक्षमता को डिबगिंग क्रैश में काफी मददगार पाया।

यह ध्यान रखना महत्वपूर्ण है कि मैंने जो उदाहरण दिया है वह x86 के लिए लिनक्स पर विकसित / परीक्षण किया गया है। मैंने भी सफलतापूर्वक एआरएम के uc_mcontext.arm_pcबजाय इसे लागू किया है uc_mcontext.eip

यहां उस लेख का लिंक दिया गया है जहां मैंने इस कार्यान्वयन के लिए विवरण सीखा: http://www.linuxjournal.com/article/6391


11
GNU ld का उपयोग करने वाले सिस्टम पर, याद रखें -rdynamicकि लिंकर को सभी प्रतीकों को जोड़ने का निर्देश देने के लिए, न केवल उपयोग किए गए, डायनेमिक टेबल टेबल पर रखने के लिए संकलित करें । यह backtrace_symbols()पतों को फ़ंक्शन नामों में बदलने की अनुमति देता है
jschmier

1
इसके अलावा, आपको एआरएम प्लेटफॉर्म पर स्टैक फ्रेम बनाने के लिए जीसीसी की कमांड लाइन में "-मैप्स-फ्रेम" विकल्प जोड़ने की जरूरत है
15

3
यह बहुत देर हो सकती है, लेकिन क्या हम addr2lineकिसी भी तरह से कमांड का उपयोग कर सकते हैं कि सटीक लाइन प्राप्त करने के लिए जहां दुर्घटना हुई?
उत्साही

4
अधिक हाल के बिल्ड glibc uc_mcontextमें किसी फ़ील्ड का नाम नहीं है eip। अब एक सरणी है जिसे अनुक्रमित करने की आवश्यकता uc_mcontext.gregs[REG_EIP]है, समकक्ष है।
mmlb

6
एआरएम के लिए, मेरी बैकट्राइक्स में हमेशा गहराई तक 1 होती थी जब तक कि मैंने कंपाइलर के लिए -फंडविंड-टेबल विकल्प नहीं जोड़ा।
jfritz42

84

हालांकि एक सही उत्तर प्रदान किया गया है जो बताता है कि GNU libc backtrace()फ़ंक्शन 1 का उपयोग कैसे करें और मैंने अपना स्वयं का उत्तर प्रदान किया है जो बताता है कि सिग्नल हैंडलर से बैकट्रेस सुनिश्चित करने के लिए गलती 2 के वास्तविक स्थान पर , मैं नहीं देखता हूं backtrace से सी + + प्रतीकों उत्पादन demangling के किसी भी उल्लेख ।

C ++ प्रोग्राम से backtraces प्राप्त करते समय, आउटपुट को c++filt1 से प्रतीकों को हटाने के लिए या सीधे 1 का उपयोग करके चलाया जा सकता है ।abi::__cxa_demangle

  • 1 लिनक्स और ओएस एक्स ध्यान दें कि c++filtऔर __cxa_demangleजीसीसी विशिष्ट हैं
  • 2 लिनक्स

निम्नलिखित सी ++ लिनक्स उदाहरण मेरे अन्य उत्तर के रूप में उसी सिग्नल हैंडलर का उपयोग करता है और यह दर्शाता है कि c++filtप्रतीकों को गिराने के लिए कैसे उपयोग किया जा सकता है।

कोड :

class foo
{
public:
    foo() { foo1(); }

private:
    void foo1() { foo2(); }
    void foo2() { foo3(); }
    void foo3() { foo4(); }
    void foo4() { crash(); }
    void crash() { char * p = NULL; *p = 0; }
};

int main(int argc, char ** argv)
{
    // Setup signal handler for SIGSEGV
    ...

    foo * f = new foo();
    return 0;
}

आउटपुट ( ./test):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(crash__3foo+0x13) [0x8048e07]
[bt]: (2) ./test(foo4__3foo+0x12) [0x8048dee]
[bt]: (3) ./test(foo3__3foo+0x12) [0x8048dd6]
[bt]: (4) ./test(foo2__3foo+0x12) [0x8048dbe]
[bt]: (5) ./test(foo1__3foo+0x12) [0x8048da6]
[bt]: (6) ./test(__3foo+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

डिमांगल्ड आउटपुट ( ./test 2>&1 | c++filt):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(foo::crash(void)+0x13) [0x8048e07]
[bt]: (2) ./test(foo::foo4(void)+0x12) [0x8048dee]
[bt]: (3) ./test(foo::foo3(void)+0x12) [0x8048dd6]
[bt]: (4) ./test(foo::foo2(void)+0x12) [0x8048dbe]
[bt]: (5) ./test(foo::foo1(void)+0x12) [0x8048da6]
[bt]: (6) ./test(foo::foo(void)+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

निम्नलिखित मेरे मूल उत्तर से सिग्नल हैंडलर पर बनाता है और abi::__cxa_demangleप्रतीकों को प्रदर्शित करने के लिए कैसे उपयोग किया जा सकता है इसका प्रदर्शन करने के लिए उपरोक्त उदाहरण में सिग्नल हैंडलर को बदल सकता है। यह सिग्नल हैंडलर उपरोक्त उदाहरण के समान ध्वस्त आउटपुट उत्पन्न करता है।

कोड :

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
    sig_ucontext_t * uc = (sig_ucontext_t *)ucontext;

    void * caller_address = (void *) uc->uc_mcontext.eip; // x86 specific

    std::cerr << "signal " << sig_num 
              << " (" << strsignal(sig_num) << "), address is " 
              << info->si_addr << " from " << caller_address 
              << std::endl << std::endl;

    void * array[50];
    int size = backtrace(array, 50);

    array[1] = caller_address;

    char ** messages = backtrace_symbols(array, size);    

    // skip first stack frame (points here)
    for (int i = 1; i < size && messages != NULL; ++i)
    {
        char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;

        // find parantheses and +address offset surrounding mangled name
        for (char *p = messages[i]; *p; ++p)
        {
            if (*p == '(') 
            {
                mangled_name = p; 
            }
            else if (*p == '+') 
            {
                offset_begin = p;
            }
            else if (*p == ')')
            {
                offset_end = p;
                break;
            }
        }

        // if the line could be processed, attempt to demangle the symbol
        if (mangled_name && offset_begin && offset_end && 
            mangled_name < offset_begin)
        {
            *mangled_name++ = '\0';
            *offset_begin++ = '\0';
            *offset_end++ = '\0';

            int status;
            char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);

            // if demangling is successful, output the demangled function name
            if (status == 0)
            {    
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << real_name << "+" << offset_begin << offset_end 
                          << std::endl;

            }
            // otherwise, output the mangled function name
            else
            {
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << mangled_name << "+" << offset_begin << offset_end 
                          << std::endl;
            }
            free(real_name);
        }
        // otherwise, print the whole line
        else
        {
            std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
        }
    }
    std::cerr << std::endl;

    free(messages);

    exit(EXIT_FAILURE);
}

1
इसके लिए धन्यवाद, jschmier। मैंने इस के आउटपुट को addr2line यूटिलिटी में फीड करने के लिए थोड़ी बैश स्क्रिप्ट बनाई। देखें: stackoverflow.com/a/15801966/1797414
arr_sea

4
#Include <cxxabi.h>
Bamaco

1
अच्छा प्रलेखन, और एक सीधी हेडर फ़ाइल 2008 के बाद से यहाँ पोस्ट की गई है ... Panthema.net/2008/2008/0901-stacktrace-demangled आपके दृष्टिकोण के समान है :)
kevinf

abi :: __ cxa_demangle को लगता है कि यह async-signal-safe नहीं है, इसलिए सिग्नल हैंडलर मॉलॉक में कहीं भी गतिरोध कर सकता है।
orcy

के उपयोग std::cerr, free()और exit()सभी POSIX सिस्टम पर गैर async-संकेत सुरक्षित कॉल बुला के खिलाफ प्रतिबंध का उल्लंघन। अगर आपके प्रक्रिया में इस तरह के रूप में किसी भी कॉल में विफल रहता है यह कोड गतिरोध होगा free(), malloc() new, या detete
एंड्रयू हेनले

31

Google ब्रेकपैड , क्रॉस-प्लेटफॉर्म क्रैश डंप जनरेटर और डंप को संसाधित करने के लिए उपकरण देखने लायक हो सकता है ।


यह खंड दोष की तरह सामान पर रिपोर्ट करता है, लेकिन यह किसी भी जानकारी को अनधिकृत C ++ अपवाद पर रिपोर्ट नहीं करता है।
DBedrenko

21

आपने अपना ऑपरेटिंग सिस्टम निर्दिष्ट नहीं किया है, इसलिए इसका उत्तर देना मुश्किल है। यदि आप gnu libc पर आधारित प्रणाली का उपयोग कर रहे हैं, तो आप libc फ़ंक्शन का उपयोग करने में सक्षम हो सकते हैं backtrace()

जीसीसी के पास दो भवन भी हैं जो आपकी सहायता कर सकते हैं, लेकिन जो आपकी वास्तुकला पर पूरी तरह से लागू हो सकते हैं या नहीं भी हो सकते हैं, और वे हैं __builtin_frame_addressऔर __builtin_return_address। जो दोनों एक पूर्णांक स्तर चाहते हैं (तत्काल, मेरा मतलब है कि यह एक चर नहीं हो सकता है)। यदि __builtin_frame_addressकिसी दिए गए स्तर के लिए गैर-शून्य है, तो उसी स्तर के रिटर्न पते को हथियाने के लिए सुरक्षित होना चाहिए।


13

Addr2line उपयोगिता पर मेरा ध्यान आकर्षित करने के लिए उत्साही होने के लिए धन्यवाद।

मैंने यहां प्रदान किए गए उत्तर के आउटपुट को संसाधित करने के लिए एक त्वरित और गंदी स्क्रिप्ट लिखी है : (addr2line उपयोगिता का उपयोग करके jschmier के लिए बहुत धन्यवाद!)।

स्क्रिप्ट एकल तर्क स्वीकार करती है: फ़ाइल का नाम जिसमें jschmier की उपयोगिता से आउटपुट है।

आउटपुट को प्रत्येक स्तर के ट्रेस के लिए कुछ इस तरह प्रिंट करना चाहिए:

BACKTRACE:  testExe 0x8A5db6b
FILE:       pathToFile/testExe.C:110
FUNCTION:   testFunction(int) 
   107  
   108           
   109           int* i = 0x0;
  *110           *i = 5;
   111      
   112        }
   113        return i;

कोड:

#!/bin/bash

LOGFILE=$1

NUM_SRC_CONTEXT_LINES=3

old_IFS=$IFS  # save the field separator           
IFS=$'\n'     # new field separator, the end of line           

for bt in `cat $LOGFILE | grep '\[bt\]'`; do
   IFS=$old_IFS     # restore default field separator 
   printf '\n'
   EXEC=`echo $bt | cut -d' ' -f3 | cut -d'(' -f1`  
   ADDR=`echo $bt | cut -d'[' -f3 | cut -d']' -f1`
   echo "BACKTRACE:  $EXEC $ADDR"
   A2L=`addr2line -a $ADDR -e $EXEC -pfC`
   #echo "A2L:        $A2L"

   FUNCTION=`echo $A2L | sed 's/\<at\>.*//' | cut -d' ' -f2-99`
   FILE_AND_LINE=`echo $A2L | sed 's/.* at //'`
   echo "FILE:       $FILE_AND_LINE"
   echo "FUNCTION:   $FUNCTION"

   # print offending source code
   SRCFILE=`echo $FILE_AND_LINE | cut -d':' -f1`
   LINENUM=`echo $FILE_AND_LINE | cut -d':' -f2`
   if ([ -f $SRCFILE ]); then
      cat -n $SRCFILE | grep -C $NUM_SRC_CONTEXT_LINES "^ *$LINENUM\>" | sed "s/ $LINENUM/*$LINENUM/"
   else
      echo "File not found: $SRCFILE"
   fi
   IFS=$'\n'     # new field separator, the end of line           
done

IFS=$old_IFS     # restore default field separator 

12

ulimit -c <value>यूनिक्स पर कोर फ़ाइल आकार सीमा निर्धारित करता है। डिफ़ॉल्ट रूप से, मूल फ़ाइल आकार सीमा 0. है। आप अपने ulimitमूल्यों को देख सकते हैं ulimit -a

यदि आप अपना प्रोग्राम gdb के भीतर से चलाते हैं, तो यह आपके प्रोग्राम को "सेगमेंटेशन उल्लंघनों" पर रोक देगा ( SIGSEGVआमतौर पर, जब आपने मेमोरी का एक टुकड़ा एक्सेस किया था जिसे आपने आवंटित नहीं किया था) या आप ब्रेकपॉइंट सेट कर सकते हैं।

dd और nemiver जीडीबी के लिए फ्रंट-एंड हैं जो नौसिखिए के लिए बहुत आसान काम करते हैं।


6
स्टैक के निशान की तुलना में कोर डंप असीम रूप से अधिक उपयोगी होते हैं क्योंकि आप डिबगर में कोर डंप को लोड कर सकते हैं और क्रैश के बिंदु पर पूरे कार्यक्रम की स्थिति और इसके डेटा को देख सकते हैं।
एडम हैव्स

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

10

यह ध्यान रखना महत्वपूर्ण है कि एक बार जब आप एक कोर फ़ाइल उत्पन्न करते हैं, तो आपको इसे देखने के लिए gdb टूल का उपयोग करना होगा। अपनी मूल फ़ाइल की समझ बनाने के लिए gdb के लिए, आपको डीबगिंग प्रतीकों के साथ बाइनरी को लिखने के लिए gcc को बताना होगा: ऐसा करने के लिए, आप -g ध्वज के साथ संकलित करते हैं:

$ g++ -g prog.cpp -o prog

फिर, आप या तो "ulimit -c unlimited" सेट कर सकते हैं ताकि इसे कोर डंप कर सकें, या बस अपना प्रोग्राम gdb के अंदर चला सकें। मुझे दूसरा तरीका अधिक पसंद है:

$ gdb ./prog
... gdb startup output ...
(gdb) run
... program runs and crashes ...
(gdb) where
... gdb outputs your stack trace ...

आशा है कि ये आपकी मदद करेगा।


4
आप gdbअपने क्रैश प्रोग्राम से भी कॉल कर सकते हैं । SIGSEGV, SEGILL, SIGBUS, SIGFPE के लिए सेटअप हैंडलर जो gdb कहेगा। विवरण: stackoverflow.com/questions/3151779/… इसका लाभ यह है कि आप सुंदर, एनोटेट बैकट्रेस जैसे bt full, आप सभी थ्रेड्स के स्टैक निशान प्राप्त कर सकते हैं।
वि।

आप उत्तर की तुलना में बैकट्रेस को आसान भी प्राप्त कर सकते हैं: gdb -silent ./prog core --eval-command = backtrace --batch -it backtrace और नज़दीकी डीबगर दिखाएगा
baziorek

10

Ive कुछ समय से इस समस्या को देख रहा था।

और Google प्रदर्शन उपकरण README में गहरे दबे हुए हैं

http://code.google.com/p/google-perftools/source/browse/trunk/README

कामेच्छा के बारे में बात करता है

http://www.nongnu.org/libunwind/

इस लाइब्रेरी की राय सुनना पसंद करेंगे।

-ड्रायनामिक के साथ समस्या यह है कि यह कुछ मामलों में बाइनरी के आकार को अपेक्षाकृत बढ़ा सकता है


2
X86 / 64 पर, मैंने -rdynamic को बाइनरी साइज़ को बहुत अधिक नहीं देखा है। जोड़ना -g एक बहुत बड़ी वृद्धि के लिए बनाता है।
दान

1
मैंने देखा कि लिबुनविंड में लाइन नंबर प्राप्त करने के लिए कार्यक्षमता नहीं है, और मैं मूल नाम के बजाय फ़ंक्शन प्रतीक (जो कि ओवरलोडिंग और इस तरह के लिए obfuscated है) को वापस नहीं लेता है।
हर्बर्ट

1
यह सही है। यह इस सही ढंग से करने के लिए बहुत मुश्किल हो जाता है, लेकिन मैं gaddr2line के साथ उत्कृष्ट सफलता क्या यहां व्यावहारिक जानकारी के बहुत सारे है लिया है blog.bigpixel.ro/2010/09/stack-unwinding-stack-trace-with-gcc
ग्रेगरी

9

Libc के कुछ संस्करणों में ऐसे कार्य होते हैं जो स्टैक के निशान से निपटते हैं; आप उनका उपयोग करने में सक्षम हो सकते हैं:

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

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


9

आप डेथहैंडलर - छोटे सी ++ वर्ग का उपयोग कर सकते हैं जो आपके लिए सब कुछ करता है, विश्वसनीय।


1
दुर्भाग्य से इसे इस्तेमाल करता है execlp()addr2line कॉल प्रदर्शन करने के लिए ... अच्छा पूरी तरह से (किसी न किसी रूप में addr2line कोड शामिल करके जो संभव है) खुद कार्यक्रम में रहने के लिए चाहते हैं
उदाहरण

9

अपने स्रोतों को बदलने के बारे में भूल जाएं और बैकट्रेस () फ़ंक्शन या मैक्रोज़ के साथ कुछ हैक करें - ये सिर्फ खराब समाधान हैं।

ठीक से काम करने वाले समाधान के रूप में, मैं सलाह दूंगा:

  1. डीबग प्रतीकों को बाइनरी में एम्बेड करने के लिए "-g" ध्वज के साथ अपने कार्यक्रम को संकलित करें (चिंता न करें कि यह आपके प्रदर्शन को प्रभावित नहीं करेगा)।
  2. लिनक्स पर अगले कमांड चलाएं: "अलिमिट-सी अनलिमिटेड" - सिस्टम को बड़ा क्रैश डंप बनाने की अनुमति देने के लिए।
  3. जब आपका प्रोग्राम क्रैश हो जाता है, तो कार्यशील निर्देशिका में आप फ़ाइल "कोर" देखेंगे।
  4. अगले कमांड को रनआउट करने के लिए बैकट्रेस प्रिंट करने के लिए चलाएं: gdb -batch -ex "backtrace" ।/your_program_.exe/core।

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


यह गलत लाइन नंबर देता है। क्या इसे सुधारा जा सकता है?
हेयूड

7
ulimit -c unlimited

एक सिस्टम वैरिएबल है, जो आपके एप्लिकेशन के क्रैश होने के बाद कोर डंप बनाने की अनुमति देगा। इस मामले में एक असीमित राशि। बहुत ही डायरेक्टरी में कोर नामक फाइल की तलाश करें। सुनिश्चित करें कि आपने अपना कोड डिबगिंग informations सक्षम के साथ संकलित किया है!

सादर


5
उपयोगकर्ता कोर डंप के लिए नहीं पूछ रहा है। वह एक स्टैक ट्रेस के लिए पूछ रहा है। देखें delorie.com/gnu/docs/glibc/libc_665.html
टॉड

1
एक कोर डंप में दुर्घटना के क्षण में कॉल स्टैक होगा, है ना?
मो।

3
आप मान रहे हैं कि वह यूनिक्स पर है, और बैश का उपयोग कर रहा है।
पॉल टॉम्बलिन

2
यदि आप tcsh का उपयोग कर रहे हैं, तो आपको करना होगाlimit coredumpsize unlimited
शिवबुध १०'१० को १

6

की ओर देखें:

आदमी 3 बैकट्रेस

तथा:

#include <exeinfo.h>
int backtrace(void **buffer, int size);

ये GNU एक्सटेंशन हैं।


2
इस पृष्ठ पर मेरी मदद करने के लिए अतिरिक्त उदाहरण हो सकते हैं जो मैंने कुछ समय पहले बनाए थे: charette.no-ip.com:81/programming/2010-01-25-25_Backtrace
स्टीफन

6

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


यह लिंक मृत प्रतीत होता है।
tglas

5

मैं लिनक्स संस्करण के साथ मदद कर सकता हूं: फ़ंक्शन बैकट्रेस, बैकट्रेस_सिमबोल और बैकट्रेस_सिमबोलस_फड का उपयोग किया जा सकता है। संबंधित मैनुअल पेज देखें।


5

ऐसा लगता है कि अंतिम सी ++ बूस्ट वर्जन में से एक लाइब्रेरी दिखाई दी जो आप चाहते हैं, ठीक उसी तरह प्रदान करने के लिए, शायद कोड मल्टीप्लायर होगा। यह बढ़ावा है :: स्टैकट्रेस , जिसे आप बूस्ट सैंपल की तरह उपयोग कर सकते हैं :

#include <filesystem>
#include <sstream>
#include <fstream>
#include <signal.h>     // ::signal, ::raise
#include <boost/stacktrace.hpp>

const char* backtraceFileName = "./backtraceFile.dump";

void signalHandler(int)
{
    ::signal(SIGSEGV, SIG_DFL);
    ::signal(SIGABRT, SIG_DFL);
    boost::stacktrace::safe_dump_to(backtraceFileName);
    ::raise(SIGABRT);
}

void sendReport()
{
    if (std::filesystem::exists(backtraceFileName))
    {
        std::ifstream file(backtraceFileName);

        auto st = boost::stacktrace::stacktrace::from_dump(file);
        std::ostringstream backtraceStream;
        backtraceStream << st << std::endl;

        // sending the code from st

        file.close();
        std::filesystem::remove(backtraceFileName);
    }
}

int main()
{
    ::signal(SIGSEGV, signalHandler);
    ::signal(SIGABRT, signalHandler);

    sendReport();
    // ... rest of code
}

लिनक्स में आप ऊपर दिए गए कोड को संकलित करते हैं:

g++ --std=c++17 file.cpp -lstdc++fs -lboost_stacktrace_backtrace -ldl -lbacktrace

उदाहरण बैकस्ट को बढ़ावा प्रलेखन से कॉपी किया गया :

0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start

4

* निक्स: आप SIGSEGV को इंटरसेप्ट कर सकते हैं (सामान्य रूप से यह सिग्नल क्रैश होने से पहले उठाया जाता है) और जानकारी को एक फाइल में रखें। (कोर फाइल के अलावा जिसका उपयोग आप उदाहरण के लिए gdb का उपयोग करके डीबग करने के लिए कर सकते हैं)।

जीत: msdn से यह जाँच करें

आप यह देखने के लिए Google के क्रोम कोड को भी देख सकते हैं कि यह कैसे क्रैश को हैंडल करता है। यह एक अच्छा अपवाद हैंडलिंग तंत्र है।


एसईएच स्टैक ट्रेस के उत्पादन में मदद नहीं करता है। हालांकि यह एक समाधान का हिस्सा हो सकता है, यह समाधान लागू करने के लिए कठिन है और वास्तविक समाधान की तुलना में आपके आवेदन के बारे में अधिक जानकारी का खुलासा करने की कीमत पर कम जानकारी प्रदान करता है : एक मिनी डंप लिखें। और आपके लिए यह स्वचालित रूप से करने के लिए विंडोज सेट अप करें।
IInspectable

4

मैंने पाया कि @tgamblin समाधान पूरा नहीं हुआ है। यह stackoverflow के साथ संभाल नहीं कर सकते। मुझे लगता है कि क्योंकि डिफ़ॉल्ट सिग्नल हैंडलर को एक ही स्टैक के साथ बुलाया जाता है और SIGSEGV को दो बार फेंका जाता है। रक्षा के लिए आपको सिग्नल हैंडलर के लिए एक स्वतंत्र स्टैक रजिस्टर करना होगा।

आप इसे नीचे दिए गए कोड से देख सकते हैं। डिफ़ॉल्ट रूप से हैंडलर विफल रहता है। परिभाषित मैक्रो STACK_OVERFLOW के साथ यह सब ठीक है।

#include <iostream>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <cassert>

using namespace std;

//#define STACK_OVERFLOW

#ifdef STACK_OVERFLOW
static char stack_body[64*1024];
static stack_t sigseg_stack;
#endif

static struct sigaction sigseg_handler;

void handler(int sig) {
  cerr << "sig seg fault handler" << endl;
  const int asize = 10;
  void *array[asize];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, asize);

  // print out all the frames to stderr
  cerr << "stack trace: " << endl;
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  cerr << "resend SIGSEGV to get core dump" << endl;
  signal(sig, SIG_DFL);
  kill(getpid(), sig);
}

void foo() {
  foo();
}

int main(int argc, char **argv) {
#ifdef STACK_OVERFLOW
  sigseg_stack.ss_sp = stack_body;
  sigseg_stack.ss_flags = SS_ONSTACK;
  sigseg_stack.ss_size = sizeof(stack_body);
  assert(!sigaltstack(&sigseg_stack, nullptr));
  sigseg_handler.sa_flags = SA_ONSTACK;
#else
  sigseg_handler.sa_flags = SA_RESTART;  
#endif
  sigseg_handler.sa_handler = &handler;
  assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr));
  cout << "sig action set" << endl;
  foo();
  return 0;
} 

4

शहर में नया राजा https://github.com/bombela/backward-cpp आ गया है

अपने कोड में 1 हेडर और 1 लाइब्रेरी स्थापित करने के लिए।

व्यक्तिगत रूप से मैं इसे इस फ़ंक्शन का उपयोग करके कहता हूं

#include "backward.hpp"
void stacker() {

using namespace backward;
StackTrace st;


st.load_here(99); //Limit the number of trace depth to 99
st.skip_n_firsts(3);//This will skip some backward internal function from the trace

Printer p;
p.snippet = true;
p.object = true;
p.color = true;
p.address = true;
p.print(st, stderr);
}

वाह! आखिरकार यह कैसे किया जाना चाहिए! मैंने इस समाधान के पक्ष में केवल समाधान निकाला है।
टालसा

3

मैं उस कोड का उपयोग करूंगा जो दृश्य रिसाव डिटेक्टर में लीक हुई मेमोरी के लिए स्टैक ट्रेस उत्पन्न करता है । यह केवल Win32 पर काम करता है, हालांकि।


और इसके लिए आपको अपने कोड के साथ डिबग प्रतीकों को शिप करना होगा। सामान्य तौर पर वांछनीय नहीं है। एक मिनी डंप लिखें और विंडोज को बिना किसी अपवाद के अपने आप करने के लिए सेट करें।
IInspectable

3

मैंने बहुत सारे उत्तर यहां सिग्नल हैंडलर का प्रदर्शन करते और फिर बाहर निकलते हुए देखे हैं। यह जाने का तरीका है, लेकिन एक बहुत महत्वपूर्ण तथ्य याद रखें: यदि आप उत्पन्न त्रुटि के लिए कोर डंप प्राप्त करना चाहते हैं, तो आप कॉल नहीं कर सकते exit(status)abort()इसके बजाय बुलाओ !


3

Windows- केवल समाधान के रूप में, आप Windows त्रुटि रिपोर्टिंग का उपयोग करके स्टैक ट्रेस (बहुत, बहुत अधिक जानकारी के साथ) के बराबर प्राप्त कर सकते हैं । केवल कुछ रजिस्ट्री प्रविष्टियों के साथ, इसे उपयोगकर्ता-मोड डंप इकट्ठा करने के लिए सेट किया जा सकता है :

सर्विस पैक 1 (SP1) के साथ विंडोज सर्वर 2008 और विंडोज विस्टा के साथ शुरू करके, विंडोज त्रुटि रिपोर्टिंग (WER) को कॉन्फ़िगर किया जा सकता है ताकि उपयोगकर्ता-मोड एप्लिकेशन क्रैश होने के बाद स्थानीय रूप से पूर्ण उपयोगकर्ता-मोड डंप एकत्र किए जाएं और संग्रहीत किए जा सकें। [...]

यह सुविधा डिफ़ॉल्ट रूप से सक्षम नहीं है। सुविधा को सक्षम करने के लिए व्यवस्थापक विशेषाधिकार की आवश्यकता होती है। सुविधा को सक्षम और कॉन्फ़िगर करने के लिए, HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ Windows त्रुटि रिपोर्टिंग \ LocalDumps कुंजी के तहत निम्न रजिस्ट्री मानों का उपयोग करें ।

आप अपने इंस्टॉलर से रजिस्ट्री प्रविष्टियों को सेट कर सकते हैं, जिसमें आवश्यक विशेषाधिकार हैं।

क्लाइंट पर स्टैक ट्रेस जनरेट करने पर उपयोगकर्ता-मोड डंप बनाने के निम्नलिखित फायदे हैं:

  • यह पहले से ही सिस्टम में लागू है। आप या तो उल्लिखित के रूप में WER का उपयोग कर सकते हैं, या अपने आप को MiniDumpWriteDump कह सकते हैं, अगर आपको डंप करने के लिए सूचना की मात्रा पर अधिक सूक्ष्म नियंत्रण की आवश्यकता है। (इसे एक अलग प्रक्रिया से कॉल करना सुनिश्चित करें।)
  • रास्ता अधिक एक स्टैक ट्रेस से पूरा हो गया। दूसरों के बीच इसमें स्थानीय चर, फ़ंक्शन तर्क, अन्य थ्रेड्स के लिए ढेर, लोड किए गए मॉड्यूल और इतने पर हो सकते हैं। डेटा की मात्रा (और परिणामस्वरूप आकार) अत्यधिक अनुकूलन योग्य है।
  • डिबग प्रतीकों को जहाज करने की आवश्यकता नहीं है। यह दोनों आपकी तैनाती के आकार को काफी कम कर देता है, साथ ही आपके आवेदन को रिवर्स-इंजीनियर करना कठिन बना देता है।
  • आपके द्वारा उपयोग किए जाने वाले कंपाइलर से लगभग स्वतंत्र। WER का उपयोग करने के लिए किसी कोड की भी आवश्यकता नहीं होती है। किसी भी तरह, एक प्रतीक डेटाबेस (पीडीबी) प्राप्त करने का एक तरीका ऑफ़लाइन विश्लेषण के लिए बहुत उपयोगी है। मेरा मानना ​​है कि जीसीसी या तो पीडीबी उत्पन्न कर सकता है, या प्रतीक डेटाबेस को पीडीबी प्रारूप में बदलने के लिए उपकरण हैं।

ध्यान दें, कि WER को केवल एप्लिकेशन क्रैश (यानी एक अपवाद के कारण प्रक्रिया समाप्त करने वाली प्रणाली) द्वारा ट्रिगर किया जा सकता है। MiniDumpWriteDumpकिसी भी समय बुलाया जा सकता है। यदि आप किसी दुर्घटना के अलावा अन्य समस्याओं का निदान करने के लिए वर्तमान स्थिति को डंप करने की आवश्यकता है तो यह उपयोगी हो सकता है।

अनिवार्य पढ़ना, यदि आप मिनी डंप की प्रयोज्यता का मूल्यांकन करना चाहते हैं:


2

उपरोक्त उत्तरों के अलावा, यहां आप डेबियन लिनक्स ओएस कैसे बनाते हैं कोर डंप उत्पन्न करते हैं

  1. उपयोगकर्ता के होम फ़ोल्डर में एक "coredumps" फ़ोल्डर बनाएँ
  2. /Etc/security/limits.conf पर जाएं। '' लाइन के नीचे, "सॉफ्ट कोर अनलिमिटेड" टाइप करें, और "रूट सॉफ्ट कोर अनलिमिटेड" अगर कोर डंप्स को सक्षम करने के लिए, कोर डंप के लिए असीमित स्थान की अनुमति दें।
  3. नोट: "* सॉफ्ट कोर अनलिमिटेड" रूट को कवर नहीं करता है, यही वजह है कि रूट को अपनी लाइन में निर्दिष्ट करना पड़ता है।
  4. इन मूल्यों की जांच करने के लिए, लॉग आउट करें, लॉग इन करें और "ulimit -a" टाइप करें। "कोर फ़ाइल का आकार" असीमित पर सेट किया जाना चाहिए।
  5. यह सुनिश्चित करने के लिए .bashrc फ़ाइलों (उपयोगकर्ता और रूट लागू होने पर) की जाँच करें कि ulimit वहाँ सेट नहीं है। अन्यथा, ऊपर दिए गए मूल्य को स्टार्टअप पर अधिलेखित कर दिया जाएगा।
  6. /Etc/sysctl.conf खोलें। नीचे निम्नलिखित दर्ज करें: "kernel.core_pattern = /home//coredumps/%e_%t.dump"। (% e प्रक्रिया का नाम होगा, और% t सिस्टम का समय होगा)
  7. बाहर निकलें और "sysctl -p" टाइप करें नए कॉन्फ़िगरेशन को लोड करने के लिए जाँचें / proc / sys / kernel / core_pattern और सत्यापित करें कि यह वही है जो आपने अभी टाइप किया है।
  8. कोर डंपिंग को कमांड लाइन ("और") पर एक प्रक्रिया चलाकर, और फिर इसे "किल -11" से मारकर परीक्षण किया जा सकता है। यदि कोर डंपिंग सफल है, तो आपको विभाजन दोष संकेत के बाद "(कोर डंप किया गया)" दिखाई देगा।

2

यदि आप अभी भी इसे अकेले जाना चाहते हैं जैसा कि मैंने किया था तो आप इसके खिलाफ लिंक कर सकते हैं bfdऔर उपयोग करने से बच सकते हैं addr2lineजैसा कि मैंने यहां किया है:

https://github.com/gnif/LookingGlass/blob/master/common/src/crash.linux.c

यह उत्पादन का उत्पादन करता है:

[E]        crash.linux.c:170  | crit_err_hdlr                  | ==== FATAL CRASH (a12-151-g28b12c85f4+1) ====
[E]        crash.linux.c:171  | crit_err_hdlr                  | signal 11 (Segmentation fault), address is (nil)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (0) /home/geoff/Projects/LookingGlass/client/src/main.c:936 (register_key_binds)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (1) /home/geoff/Projects/LookingGlass/client/src/main.c:1069 (run)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (2) /home/geoff/Projects/LookingGlass/client/src/main.c:1314 (main)
[E]        crash.linux.c:199  | crit_err_hdlr                  | [trace]: (3) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7f8aa65f809b]
[E]        crash.linux.c:199  | crit_err_hdlr                  | [trace]: (4) ./looking-glass-client(_start+0x2a) [0x55c70fc4aeca]

1

लिनक्स / यूनिक्स / मैकओएसएक्स पर मुख्य फ़ाइलों का उपयोग करें (आप उन्हें एलिमिट या संगत सिस्टम कॉल के साथ सक्षम कर सकते हैं )। विंडोज पर Microsoft त्रुटि रिपोर्टिंग का उपयोग करें (आप भागीदार बन सकते हैं और अपने एप्लिकेशन क्रैश डेटा तक पहुंच प्राप्त कर सकते हैं)।


0

मैं "apport" के गनोम तकनीक के बारे में भूल गया, लेकिन मैं इसका उपयोग करने के बारे में ज्यादा नहीं जानता। इसका उपयोग प्रसंस्करण के लिए स्टैकट्रैक और अन्य निदान उत्पन्न करने के लिए किया जाता है और स्वचालित रूप से बग दर्ज कर सकता है। यह निश्चित रूप से में जाँच के लायक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.