Výpis zhroucení, výpis paměti, výpis jádra, výpis systému… všechny produkují stejný výsledek:soubor obsahující stav paměti aplikace v konkrétním čase – obvykle při zhroucení aplikace.
Vědět, jak s těmito soubory zacházet, vám může pomoci najít hlavní příčinu (příčiny) selhání. I když nejste vývojář, soubory výpisu vytvořené ve vašem systému mohou být velmi užitečné (a také přístupné) pro pochopení softwaru.
Toto je praktický článek a můžete postupovat podle příkladu klonováním úložiště ukázkové aplikace pomocí:
git clone https://github.com/hANSIc99/core_dump_example.git
Jak signály souvisí s výpisy
Další zdroje pro Linux
- Cheat pro příkazy Linuxu
- Cheat sheet pro pokročilé příkazy systému Linux
- Bezplatný online kurz:Technický přehled RHEL
- Síťový cheat pro Linux
- Cheat sheet SELinux
- Cheat pro běžné příkazy pro Linux
- Co jsou kontejnery systému Linux?
- Naše nejnovější články o Linuxu
Signály jsou druhem meziprocesové komunikace mezi operačním systémem a uživatelskými aplikacemi. Linux používá signály definované ve standardu POSIX. Ve vašem systému můžete najít standardní signály definované v /usr/include/bits/signum-generic.h
. Pokud chcete více o používání signálů ve vaší aplikaci, existuje také informativní stránka se signálem člověka. Zjednodušeně řečeno, Linux používá signály ke spouštění dalších aktivit na základě toho, zda byly očekávané nebo neočekávané.
Když ukončíte běžící aplikaci, aplikace obvykle obdrží SIGTERM
signál. Protože se očekává tento typ výstupního signálu, tato akce nevytvoří výpis paměti.
Následující signály způsobí vytvoření souboru výpisu (zdroj:GNU C Library):
- SIGFPE:Chybná aritmetická operace
- SIGILL:Nezákonný pokyn
- SIGSEGV:Neplatný přístup k úložišti
- SIGBUS:Chyba sběrnice
- SIGABRT:Chyba zjištěná programem a hlášená voláním přerušení
- SIGIOT:Označeno jako archaické na Fedoře, tento signál se používá ke spuštění při
abort()
na PDP-11 a nyní mapuje na SIGABRT
Vytváření souborů výpisu
Přejděte na core_dump_example
adresáře, spusťte make
a spusťte ukázku pomocí -c1
přepínač:
./coredump -c1
Aplikace by se měla ukončit ve stavu 4 s chybou:
„Abgebrochen (Speicherabzug geschrieben)“ se zhruba překládá jako „Chyba segmentace (vyhození jádra).
Zda vytvoří výpis jádra nebo ne, je určeno limitem prostředků uživatele spouštějícího proces. Limity zdrojů můžete upravit pomocí ulimit
příkaz.
Zkontrolujte aktuální nastavení pro vytváření výpisu jádra:
ulimit -c
Pokud je výstupem unlimited
, pak používá (doporučené) výchozí nastavení. V opačném případě opravte limit pomocí:
ulimit -c unlimited
Chcete-li zakázat vytváření výpisů jádra typu:
ulimit -c 0
Číslo určuje zdroj v kilobajtech.
Co jsou základní výpisy?
Způsob, jakým jádro zpracovává výpisy jádra, je definován v:
/proc/sys/kernel/core_pattern
Používám Fedoru 31 a v mém systému soubor obsahuje:
/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h
To ukazuje, že výpisy jádra jsou předávány systemd-coredump
užitečnost. Obsah core_pattern
se může mezi různými verzemi linuxových distribucí značně lišit. Když systemd-coredump
se používá, soubory výpisu jsou uloženy komprimované pod /var/lib/systemd/coredump
. Nemusíte se přímo dotýkat souborů; místo toho můžete použít coredumpctl
. Například:
coredumpctl list
zobrazí všechny dostupné soubory výpisu uložené ve vašem systému.
S coredumpctl dump
, můžete načíst informace z posledního uloženého souboru výpisu:
[stephan@localhost core_dump_example]$ ./coredump
Aplikace spuštěna…
(…….)
Zpráva:Proces 4598 (coredump) uživatele 1000 vyhozených jader.
Stopová stopa vlákna 4598:
#0 0x00007f4bbaf22625 __GI_raise (libc.so.6)
#1 0x00007f4bbaf0b8d9 __GI_abort (libc.so.6) />#2 0x00007f4bbaf664af __libc_message (libc.so.6)
#3 0x00007f4bbaf6da9c malloc_printerr (libc.so.6)
#4 0x00007f4bbaf6f49c /02060160602010libc _09c n/a (/home/stephan/Dokumente/core_dump_example/coredump)
#6 0x00000000004013b1 n/a (/home/stephan/Dokumente/core_dump_example/coredump)
# libf4x000d_7_3 6)
#8 0x000000000040113e n/a (/home/stephan/Dokumente/core_dump_example/coredump)
Odmítnutí výpisu jádra do tty (použijte přesměrování shellu nebo zadejte — výstup).
To ukazuje, že proces byl zastaven SIGABRT
. Trasování zásobníku v tomto zobrazení není příliš podrobné, protože neobsahuje názvy funkcí. Nicméně pomocí coredumpctl debug
, můžete jednoduše otevřít soubor výpisu pomocí ladicího programu (ve výchozím nastavení GDB). Zadejte bt
(zkratka pro backtrace), abyste získali podrobnější pohled:
Jádro bylo vygenerováno pomocí `./coredump -c1'.
Program ukončen signálem SIGABRT, Aborted.
#0 __GI_raise (sig=sig@entry=6) na ../sysdeps/unix /sysv/linux/raise.c:50
50 return ret;
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) na ../sysdeps/unix/ sysv/linux/raise.c:50
#1 0x00007fc37a9aa8d9 v __GI_abort () na abort.c:79
#2 0x00007fc37aa054af v __libc_message@entdom=entryt=actiont_tryt=entrym 0x7fc37ab14f4b "%s\n") na adrese ../sysdeps/posix/libc_fatal.c:181
#3 0x00007fc37aa0ca9c v malloc_printerr (str=str@entry=0x7fc37ab(130e0"):invalid point. c:5339
#4 0x00007fc37aa0e49c v _int_free (av=, p= , have_lock=0) na malloc.c:4173
#5 0x000000000040120 v zdarma*e) ()
#6 0x0000000000401401 v hlavním ()
Adresy paměti:main()
a freeSomething()
jsou poměrně nízké ve srovnání s následujícími snímky. Vzhledem k tomu, že sdílené objekty jsou mapovány na oblast na konci virtuálního adresového prostoru, můžete předpokládat, že SIGABRT
bylo způsobeno voláním ve sdílené knihovně. Paměťové adresy sdílených objektů nejsou mezi voláními konstantní, takže je zcela v pořádku, když mezi voláními vidíte různé adresy.
Trasování zásobníku ukazuje, že následující volání pocházejí z malloc.c
, což znamená, že něco s (de-)alokací paměti se mohlo pokazit.
Ve zdrojovém kódu můžete vidět (i bez znalosti C++), že se pokusil uvolnit ukazatel, který nebyl vrácen funkcí správy paměti. To má za následek nedefinované chování a způsobuje SIGABRT
:
void freeSomething(void *ptr){
free(ptr);
}
int nTmp =5;
int *ptrNull =&nTmp;
freeSomething( ptrNull);
Nástroj systemd coredump lze nakonfigurovat v /etc/systemd/coredump.conf
. Rotaci čištění souborů výpisu lze nakonfigurovat v /etc/systemd/system/systemd-tmpfiles-clean.timer
.
Můžete najít další informace o coredumpctl
na jeho manuálové stránce.
Kompilace se symboly ladění
Otevřete Makefile
a zakomentujte poslední část řádku 9. Nyní by měl vypadat takto:
CFLAGS =-Wall -Werror -std=c++11 -g
-g
přepínač umožňuje kompilátoru vytvářet informace o ladění. Spusťte aplikaci, tentokrát pomocí -c2
přepínač:
./coredump -c2
Získáte výjimku s plovoucí desetinnou čárkou. Otevřete výpis v GDB pomocí:
coredumpctl debug
Tentokrát jste nasměrováni přímo na řádek ve zdrojovém kódu, který způsobil chybu:
Čtení symbolů z /home/stephan/Dokumente/core_dump_example/coredump…
[Nové LWP 6218]
Jádro bylo vygenerováno pomocí `./coredump -c2'.
Program byl ukončen signálem SIGFPE, aritmetická výjimka.
#0 0x0000000000401233 v zeroDivide () na main.cpp:29
29 nRes =5 / nDivider;
(gdb)
Zadejte list
abyste získali lepší přehled o zdrojovém kódu:
(gdb) seznam
24 int zeroDivide(){
25 int nDivider =5;
26 int nRes =0;
27 < D 0 vid {() br />28 nDivider--;
29 nRes =5 / nDivider;
30 }
31 před 31 br> 3 zpětPoužijte příkaz
info locals
k načtení hodnot lokálních proměnných od okamžiku, kdy aplikace selhala:(gdb) info locals
nDivider =0
nRes =5V kombinaci se zdrojovým kódem můžete vidět, že jste narazili na dělení nulou:
nRes = 5 / 0
Závěr
Vědět, jak zacházet se soubory výpisu, vám pomůže najít a opravit těžko reprodukovatelné náhodné chyby v aplikaci. A pokud to není vaše aplikace, předání výpisu jádra vývojáři mu pomůže problém najít a opravit.
Linux