Puncte:12

Unde găsesc fișierele dump de bază și cum văd și analizez backtrace (urma stivei) într-unul?

drapel cn

Când îmi rulez programul C pe Ubuntu 20.04, primesc această eroare de rulare:

Anomalie de segmentare (core-dumping)

Chiar trebuie să găsesc și să văd miez fișier, dar nu îl găsesc nicăieri. Unde este și cum văd backtrace-ul din el?

Puncte:17
drapel cn

Testat în Ubuntu 20.04.

1. Activați fișierele de bază

În primul rând, fugi ulimit -c pentru a vedea care este dimensiunea maximă permisă pentru fișierele de bază de pe sistemul dvs. Pe Ubuntu 20.04 pentru mine, al meu revine 0, ceea ce înseamnă că nu poate fi creat niciun fișier de bază.

ulimit --ajutor arată sensul lui -c:

-c dimensiunea maximă a fișierelor de bază create

Deci, setați dimensiunea permisă a fișierului de bază la nelimitat, așa cum se arată mai jos. Rețineți că cred că acest lucru se aplică numai la singurul terminal în care rulați asta, si o fac nu cred că este persistent la reporniri, așa că trebuie să rulați acest lucru de fiecare dată când doriți să fie create fișiere de bază și în fiecare terminal în care doriți să funcționeze:

# setați dimensiunea maximă a fișierului de descărcare de bază la nelimitat
ulimit -c nelimitat
# verificați că acum este setat la „nelimitat”
ulimit -c

Asta e! Acum, rulați programul și dacă se prăbușește și face un „core dump”, va arunca nucleul ca a miez dosar în același director în care erai când ai apelat executabilul. Numele fișierului este pur și simplu „core”.

2. Vizualizați backtrace în gdb

Ar trebui să fi creat programul C sau C++ cu simboluri de depanare activate, pentru a vedea informații utile în fișierul de bază. Fără simboluri de depanare, puteți vedea numai adresele funcțiilor apelate, nu numele sau numerele de linii reale.

În gcc, utilizați -ggdb -O0 a porni debug simboluri optimizate pentru gdb GNU debugger. De asemenea, puteți utiliza -g -O0, -g3 -O0, etc, dar -ggdb -O0 e cel mai bine. Chiar avem nevoie de nivelul de optimizare 0 (-O0) pentru asta? Da, da. Vezi aici raspunsul meu: Stack Overflow: Care este diferența dintre cele ale unui compilator -O0 opțiunea și -Og opțiune?

Exemple de comenzi pentru construirea și rularea în C și C++: deci, comenzile complete de construire și rulare în C sau C++ ar putea arăta astfel:

# C construiți și rulați comanda pentru „hello_world.c”
gcc -Wall -Wextra -Werror -ggdb -O0 -std=c11 -o hello_world hello_world.c \
&& ./Salut Lume

# C++ construi și rulează comanda pentru „hello_world.c”
g++ -Wall -Wextra -Werror -ggdb -O0 -std=c++17 -o hello_world hello_world.c \
&& ./Salut Lume

Deschideți fișierul de bază în gdb ca aceasta:

gdb path/to/my/path executable/to/core

Presupunând că tocmai ai fugit cale/la/meu/executabil, apoi miez fișierul va fi în același director în care erați tocmai când nucleul a fost aruncat, așa că puteți rula doar acest lucru:

calea gdb/către/nucleul meu/executable

În gdb, vizualizați backtrace (stiva de apeluri de funcție în momentul accidentului) cu:

bt
# sau (exact aceeași comandă)
Unde

# SAU (pentru și mai multe detalii, cum ar fi vizualizarea tuturor argumentelor pentru funcții--
# mulțumesc lui Peter Cordes în comentariile de mai jos)
bt plin

# Pentru ajutor și detalii gdb, consultați:
ajutor bt
# sau
ajutor unde

IMPORTANT: atunci când are loc o descărcare de bază, aceasta NU suprascrie automat niciuna preexistentă miez fișier în directorul curent cu unul nou, așa că trebuie îndepărtați manual bătrânii miez dosar cu rm miez ÎNAINTE de a genera noul fișier de bază atunci când programul se blochează, pentru a avea întotdeauna cel mai recent fișier de bază de analizat.

3. Încearcă-l

  1. Într-un terminal, fugi dormi 30 pentru a începe un proces de somn timp de 30 de secunde.
  2. În timp ce funcționează, apăsați Ctrl + \ pentru a forța o descărcare de miez. Veți vedea acum un miez fișier în directorul în care vă aflați.
  3. Deoarece nu avem un executabil pentru aceasta cu simboluri de depanare în el, vom deschide doar fișierul de bază în gdb în loc de fișierul executabil cu simboluri + fișierul de bază. Deci, fugi gdb -c miez pentru a deschide fișierul de bază tocmai creat de accidentul forțat.
  4. Vei vedea asta. Observați că știe ce comandă ați sunat (dormi 30) când a avut loc descărcarea de miez:
    Core a fost generat de „sleep 30”.
    Programul s-a încheiat cu semnalul SIGQUIT, Quit.
    #0 0x00007f93ed32d334 în ?? ()
    (gdb) 
    
  5. Alerga bt sau Unde pentru a vedea urma. Veți vedea asta:
    (gdb) bt
    #0 0x00007f93ed32d334 în ?? ()
    #1 0x000000000000000a în ?? ()
    #2 0x00007f93ed2960a5 în ?? ()
    #3 0x0000000000000000 în ?? ()
    (gdb)
    
  6. Acestea sunt adresele funcțiilor apelate în stiva de apeluri. Dacă ați avea simboluri de depanare activate, ați vedea multe mai multe informații, inclusiv nume de funcții și numere de linie, ca aceasta (extras dintr-un program C al meu):
    #10 0x00007fc1152b8ebf în __printf (format=<optimized out>) la printf.c:33
    #11 0x0000562bca17b3eb în fast_malloc (num_bytes=1024) la src/fast_malloc.c:225
    #12 0x0000562bca17bb66 în malloc (num_bytes=1024) la src/fast_malloc.c:496
    

4. Uitați de fișierele de bază și doar rulați programul la punctul de blocare în gdb direct!

După cum afirmă @Peter Cordes în comentariile de mai jos, puteți rula programul direct în gdb, lăsându-l să se blocheze acolo, astfel încât să nu aveți nevoie să deschideți un fișier de bază după fapt! El a declarat:

Aceste comenzi GDB nu sunt specifice fișierelor de bază, ele funcționează de fiecare dată când ești oprit la un punct de întrerupere. Dacă aveți o blocare reproductibilă, este adesea mai ușor/mai bine să rulați programul sub GDB (cum ar fi gdb ./a.out) astfel încât GDB va avea procesul în memorie în loc de un fișier de bază. Principalul avantaj este că puteți seta undeva un punct de întrerupere sau un punct de vizionare inainte de lucrul care s-a prăbușit și un singur pas pentru a vedea ce se întâmplă. Sau cu facilitățile de înregistrare ale GDB, este posibil să puteți păși înapoi și vedeți ce a dus la prăbușire, dar asta poate fi fulgerător, lent și necesită mult memorie.

După cum sa menționat mai sus, ar fi trebuit să vă compilați programul cu simboluri de depanare pe și cu Nivelul de optimizare 0, folosind -ggdb -O0. Vedeți exemplul complet de construire și rulare comenzi în C și C++ de mai sus.

Acum rulați programul în gdb:

# Deschideți executabilul în gdb
calea gdb/to/my/executable
# Rulați-l (dacă încă se blochează, veți vedea că se prăbușește)
r 
# Vizualizați backtrace (stiva de apeluri)
bt  
# Închideți când ați terminat 
q

Și dacă vreodată trebuie să înregistrați manual backtrace într-un fișier jurnal pentru a-l analiza mai târziu, puteți face acest lucru astfel (adaptat din note în mine eRCaGuy_dotfiles repo aici):

setați fișierul de jurnal gdb_log.txt
setați conectarea
activați comenzile de urmărire
arată înregistrarea # dovediți că înregistrarea este activată
culoare
pune imprimare destul de pe
bt # vezi backtrace
setați deconectarea  
afișează înregistrarea # dovedește că înregistrarea a fost dezactivată

Terminat! Acum ați salvat backtrace gdb în fișierul „gdb_log.txt”.

Referinte:

  1. [răspunsul de care aveam nevoie este chiar în această întrebare] https://stackoverflow.com/questions/2065912/core-dumped-but-core-file-is-not-in-the-current-directory
  2. https://stackoverflow.com/questions/5115613/core-dump-file-analysis
  3. https://stackoverflow.com/questions/8305866/how-do-i-analyze-a-programs-core-dump-file-with-gdb-when-it-has-command-line-pa/30524347#30524347
  4. [informații foarte utile, inclusiv. cel Ctrl + \ truc pentru a forța o descărcare de miez!] https://unix.stackexchange.com/questions/277331/segmentation-fault-core-dumped-to-where-what-is-it-and-why/409776#409776
  5. [referit de răspunsul de mai sus] https://unix.stackexchange.com/questions/179998/where-to-search-for-the-core-file-generated-by-the-crash-of-a-linux-application/180004#180004
  6. [răspunsul este în întrebarea însăși] Unde găsesc memoria centrală în ubuntu 16.04LTS?
  7. [raspunsul meu] Stack Overflow: Care este diferența dintre cele ale unui compilator -O0 opțiunea și -Og opțiune?

Lectură suplimentară de făcut

  1. [ÎNCĂ TREBUIE SĂ STUDIU ȘI ÎNCERC ASTA] Cum se utilizează LD_PRELOAD cu gdb: https://stackoverflow.com/questions/10448254/how-to-use-gdb-with-ld-preload
Peter Cordes avatar
drapel fr
Dacă aveți simboluri de depanare, `bt full` este frumos: arată argumente și chestii. Sau chiar `thread apply all bt full` pentru un program multithreaded. (Deși este mai mult decât ați dori în mod normal să priviți dintr-o dată, deci este util pentru a trimite un raport de eroare mai mult decât pentru uzul dvs.)
Gabriel Staples avatar
drapel cn
@PeterCordes, mulțumesc. Am adăugat și acum o notă despre `bt full` în răspuns. Sunt nou-nouț în privința depozitelor de miez. Scrierea acestui răspuns ieri a fost atât prima dată când văd un fișier `nucleu`, cât și prima dată când am făcut un backtrace pe unul.
Peter Cordes avatar
drapel fr
Aceste comenzi GDB nu sunt specifice fișierelor de bază, ele funcționează de fiecare dată când ești oprit la un punct de întrerupere. Dacă aveți o blocare reproductibilă, este adesea mai ușor/mai bine să vă rulați programul sub GDB (cum ar fi `gdb ./a.out`), astfel încât GDB va avea procesul în memorie în loc de un fișier de bază. Principalul avantaj este că puteți seta un punct de întrerupere sau un punct de vizionare undeva *înaintea* de lucrul care s-a prăbușit și puteți face un singur pas pentru a vedea ce se întâmplă. Sau, cu facilitățile de înregistrare ale GDB, ați putea să faceți un pas *înapoi* și să vedeți ce a dus la prăbușire, dar acest lucru poate fi slab, lent și necesită mult memorie.
Puncte:1
drapel cn

Găsit prin căutare. Rulez Ubuntu Mate 21.10. Pentru cei care rulează modelul Ubuntu târziu, apport va genera depozite în /var/lib/apport/coredump.

Dacă nu puteți găsi fișierul de descărcare de bază, cat /var/log/apport.log. Când am făcut asta, am văzut:

executabilul nu aparține unui pachet, ignorând
a cerut pid 5545, semnal 11, limită de bază 0, mod dump 1

Observați limita de bază 0, ceea ce înseamnă că nu va fi generat niciun fișier dump de bază. Deci, am rulat comanda afișată în această postare (ulimit -c nelimitat), și de data aceasta apport.log a aratat asta:

scrierea core dump în core._my_prog.1000.e43b2f33-4708-438c-a7d7-05062f381382.5650.795448 (limită: -1)

Nu am putut găsi acest lucru în directorul curent sau în directorul care conține executabilul, așa că am făcut o căutare pe întregul sistem și l-am găsit în /var/lib/apport/coredump.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.