Come posso analizzare il file di dump principale di un programma con GDB quando ha i parametri della riga di comando?


156

Il mio programma funziona in questo modo:

exe -p param1 -i param2 -o param3

E 'caduto e ha generato un file core dump, core.pid.

Voglio analizzare il file di dump principale di

gdb ./exe -p param1 -i param2 -o param3 core.pid

Ma GDB riconosce i parametri del file EXE come input di GDB.

Come analizzo un file di dump principale in questa situazione?


1
Sei sicuro che exenon sia uno script di shell (per impostare alcune variabili, ecc.) Come ad esempio firefoxsu Linux?
Basile Starynkevitch,

Risposte:


182

Puoi usare il core con GDB in molti modi, ma passare i parametri che devono essere passati all'eseguibile a GDB non è il modo di usare il file core. Questo potrebbe anche essere il motivo per cui hai riscontrato quell'errore. È possibile utilizzare il file principale nei seguenti modi:

gdb <executable> <core-file>oppure gdb <executable> -c <core-file>oppure

gdb <executable>
...
(gdb) core <core-file>

Quando si utilizza il file principale non è necessario passare argomenti. Lo scenario di crash è mostrato in GDB (verificato con GDB versione 7.1 su Ubuntu).

Per esempio:

$ ./crash -p param1 -o param2
Segmentation fault (core dumped)
$ gdb ./crash core
GNU gdb (GDB) 7.1-ubuntu
...
Core was generated by `./crash -p param1 -o param2'. <<<<< See this line shows crash scenario
Program terminated with signal 11, Segmentation fault.
#0  __strlen_ia32 () at ../sysdeps/i386/i686/multiarch/../../i586/strlen.S:99
99    ../sysdeps/i386/i686/multiarch/../../i586/strlen.S: No such file or directory.
    in ../sysdeps/i386/i686/multiarch/../../i586/strlen.S
(gdb)

Se si desidera passare i parametri all'eseguibile per il debug in GDB, utilizzare --args.

Per esempio:

$ gdb --args ./crash -p param1 -o param2
GNU gdb (GDB) 7.1-ubuntu
...
(gdb) r
Starting program: /home/@@@@/crash -p param1 -o param2

Program received signal SIGSEGV, Segmentation fault.
__strlen_ia32 () at ../sysdeps/i386/i686/multiarch/../../i586/strlen.S:99
99    ../sysdeps/i386/i686/multiarch/../../i586/strlen.S: No such file or directory.
    in ../sysdeps/i386/i686/multiarch/../../i586/strlen.S
(gdb)

Le pagine man saranno utili per vedere altre opzioni GDB.


38

Semplice utilizzo di GDB, per eseguire il debug dei file coredump:

gdb <executable_path> <coredump_file_path>

Un file coredump per un "processo" viene creato come file "core.pid".

Dopo essere entrato nel prompt GDB (all'esecuzione del comando sopra), digitare:

...
(gdb) where

Questo ti porterà con le informazioni, dello stack, in cui puoi analizzare la causa dell'incidente / errore. Altro comando, per gli stessi scopi è:

...
(gdb) bt full

Questo è lo stesso di cui sopra. Per convenzione, elenca tutte le informazioni sullo stack (che alla fine porta alla posizione dell'arresto anomalo).


22

Salta i parametri. GDB non ne ha bisogno:

gdb ./exe core.pid

Ma questo non funziona. L'avviso di output gdb: il file core potrebbe non corrispondere al file eseguibile specificato. Impossibile leggere un'immagine del file oggetto valida dalla memoria.
Treper,

6
"il file core potrebbe non corrispondere all'eseguibile specificato". Hai modificato exe dopo aver prodotto il core? Hai forse ricostruito con diverse opzioni della riga di comando? E 'molto importante dare GDB l' esatto stesso binario che ha prodotto il nucleo. Se non lo fai, otterrai spazzatura fuori.
Impiegato russo il

2
Assicurati anche che il binario passato a gdb non venga rimosso. È possibile eseguire 'file <nome binario>' che indica che è stato rimosso o meno.
Diwakar Sharma,

12

objdump+ gdbesempio minimo eseguibile

TL; DR:

Ora per la configurazione completa del test educativo:

main.c

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int myfunc(int i) {
    *(int*)(NULL) = i; /* line 7 */
    return i - 1;
}

int main(int argc, char **argv) {
    /* Setup some memory. */
    char data_ptr[] = "string in data segment";
    char *mmap_ptr;
    char *text_ptr = "string in text segment";
    (void)argv;
    mmap_ptr = (char *)malloc(sizeof(data_ptr) + 1);
    strcpy(mmap_ptr, data_ptr);
    mmap_ptr[10] = 'm';
    mmap_ptr[11] = 'm';
    mmap_ptr[12] = 'a';
    mmap_ptr[13] = 'p';
    printf("text addr: %p\n", text_ptr);
    printf("data addr: %p\n", data_ptr);
    printf("mmap addr: %p\n", mmap_ptr);

    /* Call a function to prepare a stack trace. */
    return myfunc(argc);
}

Compila ed esegui per generare core:

gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out

Produzione:

text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)

GDB ci indica la linea esatta in cui si è verificato l'errore di segmentazione, che è ciò che la maggior parte degli utenti desidera durante il debug:

gdb -q -nh main.out core

poi:

Reading symbols from main.out...done.
[New LWP 27479]
Core was generated by `./main.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000400635 in myfunc (i=1) at main.c:7
7           *(int*)(NULL) = i;
(gdb) bt
#0  0x0000000000400635 in myfunc (i=1) at main.c:7
#1  0x000000000040072b in main (argc=1, argv=0x7ffec6739328) at main.c:28

che ci indica direttamente la buggy line 7.

Gli argomenti della CLI sono memorizzati nel file principale e non è necessario passarli di nuovo

Per rispondere alle domande specifiche dell'argomento CLI, vediamo che se cambiamo gli argomenti cli, ad esempio con:

rm -f core
./main.out 1 2

quindi questo si riflette nella bactrace precedente senza alcuna modifica nei nostri comandi:

Reading symbols from main.out...done.
[New LWP 21838]
Core was generated by `./main.out 1 2'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000564583cf2759 in myfunc (i=3) at main.c:7
7           *(int*)(NULL) = i; /* line 7 */
(gdb) bt
#0  0x0000564583cf2759 in myfunc (i=3) at main.c:7
#1  0x0000564583cf2858 in main (argc=3, argv=0x7ffcca4effa8) at main.c:2

Quindi nota come ora argc=3. Pertanto, ciò deve significare che il file core memorizza tali informazioni. Immagino che lo memorizzi solo come argomenti dimain , proprio come memorizza gli argomenti di qualsiasi altra funzione.

Questo ha senso se si considera che il core dump deve archiviare l'intera memoria e registrare lo stato del programma, e quindi ha tutte le informazioni necessarie per determinare il valore degli argomenti della funzione nello stack corrente.

Meno ovvio è come controllare le variabili d'ambiente: Come ottenere variabili d'ambiente da un dump principale Le variabili d'ambiente sono presenti anche nella memoria, quindi l'objdump contiene tali informazioni, ma non sono sicuro di come elencarle tutte in una sola volta comodamente , uno per uno come segue ha funzionato nei miei test:

p __environ[0]

Analisi di binutils

Usando strumenti binutils come readelfe objdump, possiamo eseguire il dump di massa delle informazioni contenute nel corefile come lo stato della memoria.

La maggior parte / tutto deve anche essere visibile tramite GDB, ma quegli strumenti binutils offrono un approccio più voluminoso che è conveniente per alcuni casi d'uso, mentre GDB è più conveniente per un'esplorazione più interattiva.

Primo:

file core

ci dice che il corefile è in realtà un file ELF :

core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'

ecco perché siamo in grado di ispezionarlo più direttamente con i soliti strumenti binutils.

Un rapido sguardo allo standard ELF mostra che in realtà esiste un tipo ELF ad esso dedicato:

Elf32_Ehd.e_type == ET_CORE

Ulteriori informazioni sul formato sono disponibili all'indirizzo:

man 5 core

Poi:

readelf -Wa core

fornisce alcuni suggerimenti sulla struttura del file. La memoria sembra essere contenuta nelle normali intestazioni del programma:

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  NOTE           0x000468 0x0000000000000000 0x0000000000000000 0x000b9c 0x000000     0
  LOAD           0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x001000 R E 0x1000
  LOAD           0x003000 0x0000000000600000 0x0000000000000000 0x001000 0x001000 R   0x1000
  LOAD           0x004000 0x0000000000601000 0x0000000000000000 0x001000 0x001000 RW  0x1000

e ci sono altri metadati presenti nell'area delle note, in particolare prstatuscontiene il PC :

Displaying notes found at file offset 0x00000468 with length 0x00000b9c:
  Owner                 Data size       Description
  CORE                 0x00000150       NT_PRSTATUS (prstatus structure)
  CORE                 0x00000088       NT_PRPSINFO (prpsinfo structure)
  CORE                 0x00000080       NT_SIGINFO (siginfo_t data)
  CORE                 0x00000130       NT_AUXV (auxiliary vector)
  CORE                 0x00000246       NT_FILE (mapped files)
    Page size: 4096
                 Start                 End         Page Offset
    0x0000000000400000  0x0000000000401000  0x0000000000000000
        /home/ciro/test/main.out
    0x0000000000600000  0x0000000000601000  0x0000000000000000
        /home/ciro/test/main.out
    0x0000000000601000  0x0000000000602000  0x0000000000000001
        /home/ciro/test/main.out
    0x00007f8d939ee000  0x00007f8d93bae000  0x0000000000000000
        /lib/x86_64-linux-gnu/libc-2.23.so
    0x00007f8d93bae000  0x00007f8d93dae000  0x00000000000001c0
        /lib/x86_64-linux-gnu/libc-2.23.so
    0x00007f8d93dae000  0x00007f8d93db2000  0x00000000000001c0
        /lib/x86_64-linux-gnu/libc-2.23.so
    0x00007f8d93db2000  0x00007f8d93db4000  0x00000000000001c4
        /lib/x86_64-linux-gnu/libc-2.23.so
    0x00007f8d93db8000  0x00007f8d93dde000  0x0000000000000000
        /lib/x86_64-linux-gnu/ld-2.23.so
    0x00007f8d93fdd000  0x00007f8d93fde000  0x0000000000000025
        /lib/x86_64-linux-gnu/ld-2.23.so
    0x00007f8d93fde000  0x00007f8d93fdf000  0x0000000000000026
        /lib/x86_64-linux-gnu/ld-2.23.so
  CORE                 0x00000200       NT_FPREGSET (floating point registers)
  LINUX                0x00000340       NT_X86_XSTATE (x86 XSAVE extended state)

objdump può scaricare facilmente tutta la memoria con:

objdump -s core

che contiene:

Contents of section load1:

 4007d0 01000200 73747269 6e672069 6e207465  ....string in te
 4007e0 78742073 65676d65 6e740074 65787420  xt segment.text 

Contents of section load15:

 7ffec6739220 73747269 6e672069 6e206461 74612073  string in data s
 7ffec6739230 65676d65 6e740000 00a8677b 9c6778cd  egment....g{.gx.

Contents of section load4:

 1612010 73747269 6e672069 6e206d6d 61702073  string in mmap s
 1612020 65676d65 6e740000 11040000 00000000  egment..........

che corrisponde esattamente al valore stdout nella nostra corsa.

Questo è stato testato su Ubuntu 16.04 amd64, GCC 6.4.0 e binutils 2.26.1.


10

Dal tutorial del debugger GDB di RMS :

prompt > myprogram
Segmentation fault (core dumped)
prompt > gdb myprogram
...
(gdb) core core.pid
...

Assicurati che il tuo file sia davvero coreun'immagine - controlla usando file.


9

Un approccio leggermente diverso ti permetterà di saltare completamente GDB. Se tutto ciò che desideri è un backtrace, l'utilità specifica di Linux "catchsegv" rileverà SIGSEGV e visualizzerà un backtrace.


3

Non importa se l'eseguibile ha argomenti o meno. Per eseguire GDB su qualsiasi file binario con un file core generato, la sintassi è di seguito.

Syntax:
gdb <binary name> <generated core file>
Eg:
gdb l3_entity 6290-corefile

Consentitemi di prendere l'esempio seguente per una maggiore comprensione.

bash-4.1$ **gdb l3_entity 6290-corefile**

**Core was generated** by `/dir1/dir2/dir3/l3_entity **Program terminated with signal SIGABRT, Aborted.**
#0
#1
#2
#3
#4
#5
#6
#7
#8
#9
#10
(gdb)

Dall'output sopra, puoi indovinare qualcosa sul core, che si tratti di un accesso NULL, SIGABORT, ecc.

Questi numeri da # 0 a # 10 sono i frame di stack di GDB. Questi frame stack non sono del tuo binario. Nei precedenti 0 - 10 frame se si sospetta qualcosa di sbagliato, selezionare quel frame

(gdb) frame 8

Ora per vedere maggiori dettagli a riguardo:

(gdb) list +

Per approfondire ulteriormente il problema, è possibile stampare qui i valori delle variabili sospette qui.

(gdb) print thread_name

0

Digita semplicemente il comando:

$ gdb <Binary> <codeDump>

O

$ gdb <binary>

$ gdb) core <coreDump>

Non è necessario fornire alcun argomento della riga di comando. Il dump del codice generato a causa di un esercizio precedente.


-1

È possibile analizzare il file di dump principale utilizzando il comando "gdb".

 gdb - The GNU Debugger

 syntax:

 # gdb executable-file core-file

 example: # gdb out.txt core.xxx 

1
out.txt è un file eseguibile? Sembra un'estensione di file fuorviante.
Alan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.