Jak automatycznie wygenerować stacktrace po awarii mojego programu
Pracuję na Linuksie z kompilatorem GCC. Gdy mój program C++ ulega awarii, chciałbym, aby automatycznie generował stacktrace.
Mój program jest uruchamiany przez wielu różnych użytkowników i działa również na Linuksie, Windows i Macintosh(wszystkie wersje są kompilowane przy użyciu gcc
).
Chciałbym, aby mój program był w stanie wygenerować ślad stosu, gdy ulegnie awarii i następnym razem, gdy użytkownik uruchomi go, zapyta go, czy można wysłać ślad stosu do mnie, abym mógł wyśledzić problem. Mogę poradzić sobie z wysyłaniem informacji do mnie, ale nie wiem, jak wygenerować ciąg śladowy. Jakieś pomysły?
28 answers
Dla Linuksa i wierzę, że Mac OS X, Jeśli używasz gcc lub dowolnego kompilatora używającego glibc, możesz użyć funkcji backtrace() w execinfo.h
, aby wydrukować stacktrace i wyjść z wdziękiem, gdy pojawi się błąd segmentacji. Dokumentację można znaleźć w podręczniku libc .
Oto przykładowy program, który instaluje funkcję obsługi SIGSEGV
i wypisuje stacktrace do stderr
, Gdy się segfaultuje. Funkcja baz()
powoduje, że segfault uruchamia opiekun:
#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.
}
Kompilacja z -g -rdynamic
pobiera informacje o symbolach w wyjściu, które glibc może użyć do utworzenia ładnego stosu:
$ gcc -g -rdynamic ./test.c -o test
Wykonanie tego daje Ci to wyjście:
$ ./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]
Pokazuje moduł obciążenia, przesunięcie i funkcję, z której pochodzi każda ramka w stosie. Tutaj możesz zobaczyć obsługę sygnału na szczycie stosu, a funkcje libc przed main
oprócz main
, foo
, bar
, i baz
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-20 10:39:36
Linux
Podczas korzystania z funkcji backtrace () w execinfo.h aby wydrukować stacktrace i wyjść z wdziękiem, gdy pojawi się błąd segmentacji został już zasugerowany , nie widzę wzmianki o zawiłościach niezbędnych do zapewnienia, że wynikająca z niego ścieżka wsteczna wskazuje na rzeczywistą lokalizację błędu(przynajmniej dla niektórych architektur - x86 & ARM).
Pierwsze dwa wpisy w łańcuchu ramek stosu po wejściu do obsługi sygnału zawierają adres zwrotny wewnątrz obsługa sygnału i jedna wewnątrz sigaction () w libc. Ramka stosu ostatniej funkcji wywołanej przed sygnałem (która jest lokalizacją błędu) jest tracona.
Kod
#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);
}
Wyjście
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]
Wszystkie zagrożenia związane z wywołaniem funkcji backtrace() w funkcji obsługi sygnału nadal istnieją i nie należy ich przeoczyć, ale funkcjonalność, którą tutaj opisałem, jest bardzo pomocna w debugowaniu awarii.
Należy pamiętać, że podany przeze mnie przykład został opracowany/przetestowany na Linuksie dla x86. Udało mi się również zaimplementować to na ARM używając uc_mcontext.arm_pc
zamiast uc_mcontext.eip
.
Oto link do artykułu, w którym zapoznałem się ze szczegółami tej implementacji: http://www.linuxjournal.com/article/6391
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22
Jest to nawet łatwiejsze niż "Man backtrace", istnieje trochę udokumentowana biblioteka (specyficzna dla GNU) dystrybuowana z glibc jako libSegFault.so, który według mnie został napisany przez Ulricha Dreppera do obsługi programu catchsegv (patrz "man catchsegv").
To daje nam 3 możliwości. Zamiast uruchomić "program-o hai":-
Run within catchsegv:
$ catchsegv program -o hai
-
Połączenie z libSegFault w czasie wykonywania:
$ LD_PRELOAD=/lib/libSegFault.so program -o hai
-
Link z libSegFault przy kompilacji czas:
$ gcc -g1 -lSegFault -o program program.cc $ program -o hai
We wszystkich 3 przypadkach otrzymasz wyraźniejsze ścieżki zwrotne z mniejszą optymalizacją (gcc-o0 lub-O1) i symbolami debugowania (gcc-g). W przeciwnym razie możesz po prostu skończyć ze stertą adresów pamięci.
Możesz również złapać więcej sygnałów dla śladów stosu za pomocą czegoś takiego:
$ export SEGFAULT_SIGNALS="all" # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt" # SIGBUS and SIGABRT
Wynik będzie wyglądał mniej więcej tak (zwróć uwagę na backtrace na dole):
*** 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]
Jeśli chcesz poznać krwawe szczegóły, najlepszym źródłem jest niestety źródło: Zobacz http://sourceware.org/git/?p=glibc.git;a=blob; f=debug / segfault.C i jego Katalog nadrzędny http://sourceware.org/git/?p=glibc.git;a = tree; f=debug
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-22 03:59:02
Pomimo tego, że dostarczono poprawną odpowiedź opisującą jak korzystać z funkcji GNU libc backtrace()
1 i podałem moją własną odpowiedź , która opisuje, jak zapewnić backtrace z punktów obsługi sygnału do rzeczywistej lokalizacji błędu2, nie widzę żadnej wzmianki o demanglowaniu symboli C++ z backtrace.
Podczas uzyskiwania ścieżek wstecznych z programu C++, wyjście może być uruchamiane przez c++filt
1 na demangle symbole lub za pomocą abi::__cxa_demangle
1 bezpośrednio.
-
1 Linux & OS X
zauważ, że
c++filt
i__cxa_demangle
są specyficzne dla GCC - 2 Linux
Poniższy przykład C++ Linuksa używa tej samej obsługi sygnału, co moja inna odpowiedź i pokazuje, w jaki sposób c++filt
można użyć do demangle symboli.
Kod :
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;
}
Wyjście (./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]
Demangled Output (./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]
Poniższy przykład opiera się na obsłudze sygnału z mojej oryginalnej odpowiedzi i może zastąpić obsługę sygnału w powyższym przykładzie, aby zademonstrować, jak abi::__cxa_demangle
może być używany do demangle symbole. Ta funkcja obsługi sygnału wytwarza takie samo demangled wyjście jak w powyższym przykładzie.
Kod :
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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22
Może warto przyjrzeć się Google Breakpad , wieloplatformowemu generatorowi zrzutów awaryjnych i narzędziom do przetwarzania zrzutów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 14:15:07
Nie podałeś swojego systemu operacyjnego, więc trudno na to odpowiedzieć. Jeśli korzystasz z systemu opartego na gnu libc, możesz skorzystać z funkcji libc backtrace()
.
GCC ma również dwa wbudowane elementy, które mogą Ci pomóc, ale które mogą lub nie mogą być w pełni zaimplementowane na Twojej architekturze, a są to __builtin_frame_address
i __builtin_return_address
. Oba chcą natychmiastowego poziomu liczby całkowitej(przez natychmiastowy, mam na myśli, że nie może to być zmienna). Jeśli __builtin_frame_address
dla danego poziomu jest niezerowe, powinno być bezpiecznie chwycić adres zwrotny tego samego poziomu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-25 00:19:03
ulimit -c <value>
ustawia limit rozmiaru pliku rdzenia w systemie unix. Domyślnie limit rozmiaru pliku rdzenia wynosi 0. Możesz zobaczyć swoje ulimit
wartości za pomocą ulimit -a
.
Ponadto, jeśli uruchomisz swój program z poziomu gdb, zatrzyma on twój program na "naruszeniach segmentacji" (SIGSEGV
, zazwyczaj gdy uzyskałeś dostęp do pamięci, której nie przydzieliłeś) lub możesz ustawić punkty przerwania.
Ddd i nemiver to front-endy dla gdb, które znacznie ułatwiają pracę z nim początkującym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-25 00:20:28
Niektóre wersje libc zawierają funkcje, które radzą sobie ze śladami stosu; możesz z nich korzystać:
Http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Pamiętam, że używałem libunwind dawno temu, aby uzyskać ślady stosu, ale może to nie być obsługiwane na twojej platformie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 20:51:24
Ważne jest, aby pamiętać, że po wygenerowaniu pliku core będziesz musiał użyć narzędzia gdb, aby go obejrzeć. Aby gdb miało sens dla Twojego pliku core, musisz powiedzieć gcc, aby ustawił plik binarny z symbolami debugowania: aby to zrobić, kompilujesz z flagą-g:
$ g++ -g prog.cpp -o prog
Następnie możesz ustawić "ulimit-C unlimited", aby pozwolić mu zrzucić rdzeń, lub po prostu uruchomić program wewnątrz gdb. Bardziej podoba mi się drugie podejście:
$ gdb ./prog
... gdb startup output ...
(gdb) run
... program runs and crashes ...
(gdb) where
... gdb outputs your stack trace ...
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 20:57:12
Przyglądałem się temu problemowi od jakiegoś czasu.
I zakopane głęboko w Google Performance Tools README
Http://code.google.com/p/google-perftools/source/browse/trunk/README
Rozmowy o libunwind
Http://www.nongnu.org/libunwind/
Chciałbym usłyszeć opinie o tej bibliotece.
Problem z-rdynamic polega na tym, że w niektórych przypadkach może stosunkowo znacznie zwiększyć rozmiar binarny
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 02:55:24
Dziękuję enthusiasticgeek za zwrócenie mojej uwagi na narzędzie addr2line.
Napisałem szybki i brudny skrypt, aby przetworzyć wyjście odpowiedzi podanej tutaj : (Wielkie dzięki dla jschmier!) za pomocą narzędzia addr2line.
Skrypt przyjmuje pojedynczy argument: nazwę pliku zawierającego wyjście z narzędzia jschmier.
Wyjście powinno wydrukować coś w stylu poniżej dla każdego poziomu ślad:
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;
Kod:
#!/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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22
ulimit -c unlimited
Jest zmienną systemową, która pozwoli na utworzenie zrzutu pamięci po awarii aplikacji. W tym przypadku nieograniczona ilość. Poszukaj pliku o nazwie core w tym samym katalogu. Upewnij się, że skompilowałeś kod z włączoną informacją o debugowaniu!
Pozdrawiam
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 20:52:38
Win: a może StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:24:21
Możesz użyć DeathHandler - małej klasy C++, która robi wszystko za Ciebie, niezawodnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-01 06:38:05
Zapomnij o zmianie źródeł i zrób kilka hacków z funkcją backtrace() lub makrami - to tylko słabe rozwiązania.
Jako prawidłowo działające rozwiązanie radziłbym:
- Skompiluj swój program z flagą "- g " w celu osadzenia symboli debugowania w systemie binarnym(nie martw się, nie wpłynie to na wydajność).
- w Linuksie Uruchom następne polecenie: "ulimit-C unlimited" - aby umożliwić systemowi wykonywanie dużych zrzutów awaryjnych.
- po awarii programu, w katalogu roboczym zobaczysz plik "core".
- Uruchom następne polecenie, aby wydrukować backtrace na stdout: gdb-batch-ex "backtrace"./ your_program_exe ./ core
To wyświetli właściwą czytelną ścieżkę wsteczną Twojego programu w sposób czytelny dla człowieka(z nazwami plików źródłowych i numerami linii). Ponadto takie podejście daje swobodę automatyzacji systemu: mieć krótki skrypt, który sprawdza, czy proces stworzył zrzut pamięci, a następnie wysyła backtracks pocztą e-mail do programistów, lub zaloguj to do jakiegoś logowania system.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-06 12:37:15
Spójrz na:
Man 3 backtrace
I:
#include <exeinfo.h>
int backtrace(void **buffer, int size);
Są to rozszerzenia GNU.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 20:55:21
Mogę pomóc z wersją Linuksa: można użyć funkcji backtrace, backtrace_symbols i backtrace_symbols_fd. Zobacz odpowiednie strony podręcznika.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:01:04
Zobacz funkcję śledzenia stosu w ACE (adaptacyjne środowisko komunikacyjne). Jest już napisany, aby objąć wszystkie główne platformy (i nie tylko). Biblioteka jest licencjonowana w stylu BSD, więc możesz nawet skopiować / wkleić kod, jeśli nie chcesz używać ACE.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 00:07:57
*nix: możesz przechwycić SIGSEGV (Zwykle ten sygnał jest wywoływany przed awarią) i zachować informacje w pliku. (oprócz pliku core, którego można użyć do debugowania np. za pomocą gdb).
Win: Sprawdź to {[2] } z msdn.
Możesz również spojrzeć na kod Google chrome, aby zobaczyć, jak radzi sobie z awariami. Ma ładny mechanizm obsługi wyjątków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:09:52
Stwierdziłem, że rozwiązanie @tgamblin nie jest kompletne. Nie poradzi sobie ze stackoverflow. Myślę, że ponieważ domyślnie program obsługi sygnału jest wywoływany z tym samym stosem i SIGSEGV jest rzucany dwa razy. Aby chronić musisz zarejestrować niezależny stos dla obsługi sygnału.
Możesz to sprawdzić poniższym kodem. Domyślnie funkcja obsługi nie działa. Przy zdefiniowanym makrze STACK_OVERFLOW wszystko jest w porządku.
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 11:59:22
Użyłbym kodu, który generuje ślad stosu dla wycieku pamięci w Visual Leak Detector . Działa to tylko na Win32.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:00:42
Widziałem wiele odpowiedzi tutaj wykonując obsługę sygnału, a następnie wychodząc.
To jest droga do zrobienia, ale pamiętaj o bardzo ważnym fakcie: jeśli chcesz uzyskać zrzut pamięci dla wygenerowanego błędu, nie możesz wywołać exit(status)
. Zamiast tego zadzwoń abort()
!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-12 23:23:10
Przybył nowy król w mieście https://github.com/bombela/backward-cpp
1 Nagłówek do umieszczenia w kodzie i 1 biblioteka do zainstalowania.
Osobiście nazywam to za pomocą tej funkcji
#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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-10 22:29:34
Oprócz powyższych odpowiedzi, tutaj jak zrobić Debian Linux OS generować zrzut pamięci
- Utwórz folder "coredumps" w folderze domowym użytkownika
- Przejdź do /etc / security / limits.conf. Poniżej linii ''wpisz" soft core unlimited " i "root soft core unlimited", jeśli włączysz zrzuty rdzeni dla roota, aby umożliwić nieograniczone miejsce na zrzuty rdzeni.
- Uwaga: "* soft core unlimited " nie obejmuje roota, dlatego root musi być podany we własnej linii.
- aby sprawdzić te wartości, Wyloguj się, Zaloguj się ponownie i wpisz "ulimit-a". "Rozmiar pliku rdzenia" powinien być ustawiony na nieograniczony.
- Sprawdź .pliki bashrc (użytkownik i root, jeśli dotyczy), aby upewnić się, że ulimit nie jest tam ustawiony. W przeciwnym razie powyższa wartość zostanie nadpisana podczas uruchamiania.
- Open / etc / sysctl.conf. Na dole wpisz: "kernel.core_pattern = / home/ / coredumps / %e_%t.dump". (%e będzie nazwą procesu, a %t będzie czasem systemowym)
- Wyjdź i wpisz "sysctl-p", aby załadować nowa konfiguracja Sprawdź /proc / sys / kernel / core_pattern i sprawdź, czy pasuje do tego, co właśnie wpisałeś.
- dumping rdzenia można przetestować uruchamiając proces z linii poleceń (" &"), a następnie zabijając go za pomocą "kill -11 ". Jeśli core dumping się powiedzie, zobaczysz "(core dumping) " po wskazaniu błędu segmentacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-08 19:13:58
Na Linuksie / unix/MacOSX używaj plików core (możesz je włączyć za pomocą ulimit lub zgodnego wywołania systemowego ). W systemie Windows użyj raportowania błędów firmy Microsoft(możesz zostać partnerem i uzyskać dostęp do danych awarii aplikacji).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:16:42
Jeśli twój program ulegnie awarii, to sam system operacyjny generuje informacje o zrzutie awarii. Jeśli używasz *nix OS, po prostu nie musisz mu tego uniemożliwiać(sprawdź opcje "coredump" polecenia ulimit).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 21:01:26
Zapomniałem o technologii GNOME "apport", ale nie znam się na jej używaniu. Służy do generowania ścieżek stosowych i innych diagnostycznych do przetwarzania i może automatycznie zapisywać błędy. Na pewno warto to sprawdzić.
Jako rozwiązanie tylko dla Windows, możesz uzyskać odpowiednik śledzenia stosu (z dużo, dużo więcej informacji) za pomocą Raportowanie błędów systemu Windows. Wystarczy kilka wpisów rejestru, aby ustawić zbierać zrzuty trybu użytkownika :
Począwszy od systemu Windows Server 2008 i Windows Vista z dodatkiem Service Pack 1 (SP1), Raportowanie błędów systemu Windows (Wer) można skonfigurować tak, aby pełne zrzuty trybu użytkownika były gromadzone i przechowywane lokalnie po awarii aplikacji trybu użytkownika. [...]
Ta funkcja nie jest domyślnie włączona. Włączenie tej funkcji wymaga uprawnień administratora. Aby włączyć i skonfigurować tę funkcję, użyj następujących wartości rejestru w kluczu HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps.
Możesz ustawić wpisy rejestru z instalatora, który ma wymagane uprawnienia.
Tworzenie zrzutu trybu użytkownika ma następujące zalety w porównaniu z generowaniem śladu stosu na kliencie:
- jest już zaimplementowany w systemie. Możesz użyć WER, jak opisano powyżej, lub wywołać Minidump Writedump samodzielnie, jeśli potrzebujesz bardziej drobnoziarnistej kontroli nad ilością informacji do zrzutu. (Upewnij się, aby wywołać go z innego procesu.)
- sposób bardziej kompletny niż ślad stosu. Między innymi może zawierać zmienne lokalne, argumenty funkcji, stosy dla innych wątków, załadowane moduły i tak dalej. Ilość danych (i w związku z tym rozmiar) jest wysoce konfigurowalny.
- Nie ma potrzeby wysyłania symboli debugowania. To zarówno drastycznie zmniejsza rozmiar wdrożenia, jak i utrudnia inżynierię wsteczną aplikacji.
- W dużej mierze niezależny od używanego kompilatora. Używanie WER nie wymaga nawet żadnego kodu. Tak czy inaczej, posiadanie sposobu na uzyskanie bazy danych symboli (PDB) jest Bardzo przydatne do analizy offline. Wierzę, że GCC może albo generować PDB, albo są narzędzia do konwersji symbolu bazy danych do formatu PDB.
Zwróć uwagę, że WER może być wywołane tylko przez awarię aplikacji (tj. system kończący proces z powodu nieobsługiwanego wyjątku). MiniDumpWriteDump
może być wywołany w każdej chwili. Może to być pomocne, jeśli musisz zrzucić aktualny stan, aby zdiagnozować problemy inne niż awaria.
Lektura obowiązkowa, jeśli chcesz ocenić przydatność mini zrzutów:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-01 13:00:47