Mein Programm funktioniert so:
exe -p param1 -i param2 -o param3
Es stürzte ab und generierte eine Core-Dump-Datei core.pid
Ich möchte die Core-Dump-Datei mit analysieren
gdb ./exe -p param1 -i param2 -o param3 core.pid
aber die gdb erkennt die Parameter von exe
als gdb-Eingabe.
Wie kann man in dieser Situation eine Core-Dump-Datei analysieren?
Sie können den Kern mit gdb auf viele Arten verwenden, aber die Übergabe von Parametern, die an die ausführbare Datei übergeben werden sollen, an gdb ist nicht die Möglichkeit, die Kerndatei zu verwenden. Dies könnte auch der Grund dafür sein, dass Sie diesen Fehler erhalten haben. Sie können die Kerndatei auf folgende Weise verwenden:gdb <executable> <core-file>
oder gdb <executable> -c <core-file>
oder
gdb <executable>
...
(gdb) core <core-file>
Wenn Sie eine Core-Datei verwenden, müssen Sie keine Argumente übergeben. Das Absturzszenario wird in gdb gezeigt (geprüft mit gdb Version 7.1 unter Ubuntu) . Beispiel:
$ ./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)
Wenn Sie Parameter an die ausführbare Datei übergeben möchten, die in gdb debugiert werden soll, verwenden Sie --args
.
Zum Beispiel:
$ 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)
Man-Seiten werden hilfreich sein, um andere gdb-Optionen anzuzeigen.
Einfache Verwendung von GDB zum Debuggen von Coredump-Dateien:
gdb <executable_path> <coredump_file_path>
Die Coredump-Datei für einen "Prozess" wird als "core.pid" -Datei erstellt Wenn Sie sich in der gdb-Prompt befinden, geben Sie Folgendes ein:
...
(gdb) where
Damit erhalten Sie die Informationen über den Stack, wo Sie die Ursache des Absturzes/Fehlers analysieren können Anderer Befehl, für die gleichen Zwecke ist;
...
(gdb) bt full
Dies ist dasselbe wie oben. Konventionell werden die gesamten Stack-Informationen aufgelistet (die letztendlich zum Absturzort führen).
Überspringen Sie einfach die Params, gdb braucht sie nicht:
gdb ./exe core.pid
Von RMS gdb Debugger Tutorial :
Prompt > myprogram
Segmentation fault (core dumped)
Prompt > gdb myprogram
...
(gdb) core core.pid
...
Stellen Sie sicher, dass es sich bei Ihrer Datei wirklich um ein core
-Bild handelt - überprüfen Sie es mit file
.
Ein etwas anderer Ansatz erlaubt es Ihnen, GDB vollständig zu überspringen. Wenn Sie nur eine Rückverfolgung wünschen, wird das linuxspezifische Dienstprogramm 'catchsegv' SIGSEGV abfangen und eine Rückverfolgung anzeigen.
Es spielt keine Rolle, ob ausführbare Dateien Argumente haben oder nicht. Um GDB auf einer Binärdatei mit einer generierten Kerndatei auszuführen, finden Sie unten Syntax.
Syntax:
gdb <binary name> <generated core file>
Eg:
gdb l3_entity 6290-corefile
lassen Sie mich das unten stehende Beispiel zum besseren Verständnis nehmen.
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)
Aus der obigen Ausgabe können Sie etwas über den Kern erraten, ob es sich um einen NULL-Zugriff oder um SIGABORT usw. handelt.
Diese Zahlen # 0 bis # 10 sind die Stack-Frames von GDB. Diese Stack-Frames gehören nicht zu Ihrer Binärdatei. Wenn Sie in den obigen 0 - 10 Bildern einen Fehler vermuten, wählen Sie diesen aus
(gdb) frame 8
Um mehr Details darüber zu erfahren:
(gdb) list +
Um das Problem weiter zu untersuchen, können Sie zu diesem Zeitpunkt die verdächtigen Variablenwerte hier drucken.
(gdb) print thread_name
Sie können die Core-Dump-Datei mit dem Befehl "gdb" analysieren.
gdb - The GNU Debugger
syntax:
# gdb executable-file core-file
ex: # gdb out.txt core.xxx
Vielen Dank.
objdump
+ gdb
minimal lauffähig Beispiel
TL; DR:
objdump -s core
, um Speicher zu sichern
GDB, um eine fehlerhafte Zeile zu finden, zuvor erwähnt unter: Wie analysiert man die Core-Dump-Datei eines Programms mit gdb?
Nun zum vollständigen Testaufbau:
haupt 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);
}
Kompilieren und ausführen, um den Kern zu generieren:
gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out
Ausgabe:
text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)
GDB weist uns auf die genaue Zeile, in der der Segfault stattfand, was die meisten Benutzer beim Debuggen wollen:
gdb -q -nh main.out core
dann:
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
was uns direkt auf die fehlerhafte Linie 7 zeigt.
Binutils-Analyse
Zuerst:
file core
sagt uns, dass die core
-Datei tatsächlich eine ELF-Datei ist:
core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'
deshalb können wir sie mit den üblichen binutils-Werkzeugen direkter prüfen.
Weitere Informationen zum Format finden Sie unter:
man 5 core
Dann:
readelf -Wa core
gibt einige Hinweise zur Dateistruktur. Der Speicher scheint in normalen Programmköpfen enthalten zu sein:
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
in einem Notizbereich sind weitere Metadaten vorhanden. Ich denke, der PC muss da sein (TODO bestätigen):
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
kann den gesamten Speicher einfach abspeichern mit:
objdump -s core
was beinhaltet:
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..........
was genau mit dem Standardwert in unserem Lauf übereinstimmt.
Getestet in Ubuntu 16.04 AMD64, GCC 6.4.0, binutils 2.26.1.
Geben Sie einfach den Befehl ein
$ gdb <Binary> <codeDump>
oder
$ gdb <binary>
$ gdb) core <coreDump>
Es müssen keine Befehlszeilenargumente angegeben werden. Der Code-Dump wurde aufgrund einer früheren Übung generiert.