Как мне проанализировать файл дампа ядра программы с помощью GDB, если он имеет параметры командной строки?


156

Моя программа работает так:

exe -p param1 -i param2 -o param3

Сбой и генерирование файла дампа ядра core.pid.

Я хочу проанализировать файл дампа

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

Но GDB распознает параметры файла EXE как входные данные GDB.

Как мне проанализировать файл дампа ядра в этой ситуации?


1
Вы уверены, что exeэто не сценарий оболочки (для установки некоторых переменных и т. Д.), Как, например firefox, в Linux?
Василий Старынкевич

Ответы:


182

Вы можете использовать ядро ​​с GDB разными способами, но передача параметров, которые должны быть переданы в исполняемый файл, в GDB не является способом использования файла ядра. Это также может быть причиной того, что вы получили эту ошибку. Вы можете использовать файл ядра следующими способами:

gdb <executable> <core-file>или gdb <executable> -c <core-file>или

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

При использовании файла ядра вам не нужно передавать аргументы. Сценарий сбоя показан в GDB (проверено с версией 7.1 GDB в Ubuntu).

Например:

$ ./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)

Если вы хотите передать параметры в исполняемый файл для отладки в GDB, используйте --args.

Например:

$ 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)

Справочные страницы будут полезны для просмотра других вариантов GDB.


38

Простое использование GDB для отладки файлов coredump:

gdb <executable_path> <coredump_file_path>

Файл coredump для «процесса» создается как файл «core.pid».

После того, как вы попадете внутрь приглашения GDB (при выполнении вышеупомянутой команды), введите:

...
(gdb) where

Это даст вам информацию из стека, где вы сможете проанализировать причину сбоя / сбоя. Другая команда, для тех же целей:

...
(gdb) bt full

Это то же самое, что и выше. По соглашению, он перечисляет всю информацию стека (что в конечном итоге приводит к месту сбоя).


22

Просто пропустите параметры. GDB не нуждается в них:

gdb ./exe core.pid

Но это не работает. Предупреждение вывода GDB: файл ядра может не совпадать с указанным исполняемым файлом. Не удалось прочитать действительное изображение объектного файла из памяти.
Трепер

6
msgstr "основной файл может не соответствовать указанному исполняемому файлу". Вы модифицировали exe после того, как оно произвело ядро? Возможно, вы перестроили его с помощью других параметров командной строки? Это очень важно , чтобы дать GDB в точно такой же двоичный файл , который произвел ядро. Если вы этого не сделаете, вы получите мусор.
Занятый русский

2
Также убедитесь, что двоичный файл, передаваемый в gdb, не удаляется. Вы можете запустить 'file <двоичное имя>', которое показывает, что оно удалено или нет.
Дивакар Шарма

12

objdump+ gdbминимальный работоспособный пример

TL; DR:

Теперь для полной настройки образовательного теста:

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);
}

Скомпилируйте и запустите для генерации ядра:

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

Вывод:

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

GDB указывает нам на точную линию, где произошла ошибка сегментации, что большинство пользователей хотят при отладке:

gdb -q -nh main.out core

затем:

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

который указывает нам прямо на глючную линию 7.

Аргументы CLI хранятся в основном файле и не требуют повторной передачи.

Чтобы ответить на конкретные вопросы об аргументах CLI, мы увидим, что если мы изменим аргументы cli, например, с помощью:

rm -f core
./main.out 1 2

тогда это отражается на предыдущем bactrace без каких-либо изменений в наших командах:

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

Итак, обратите внимание, как сейчас argc=3. Следовательно, это должно означать, что основной файл хранит эту информацию. Я предполагаю, что он просто хранит его в качестве аргументов main, так же, как он хранит аргументы любых других функций.

Это имеет смысл, если учесть, что дамп ядра должен хранить всю память и регистрировать состояние программы, и поэтому он имеет всю информацию, необходимую для определения значения аргументов функции в текущем стеке.

Менее очевидным является то, как проверять переменные среды: как получить переменную среды из дампа памяти. Переменные среды также присутствуют в памяти, поэтому objdump действительно содержит эту информацию, но я не уверен, как удобно перечислить их все за один раз. Один за другим поработали над моими тестами:

p __environ[0]

Анализ Binutils

Используя инструменты binutils, такие как readelfи objdump, мы можем объединить информацию, содержащуюся в coreфайле, такую ​​как состояние памяти.

Большая часть / все это также должно быть видно через GDB, но эти инструменты binutils предлагают более объемный подход, который удобен для определенных случаев использования, в то время как GDB более удобен для более интерактивного исследования.

Первый:

file core

говорит нам, что coreфайл на самом деле является файлом ELF :

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

именно поэтому мы можем проверить это непосредственно с помощью обычных инструментов binutils.

Беглый взгляд на стандарт ELF показывает, что на самом деле ему выделен тип ELF:

Elf32_Ehd.e_type == ET_CORE

Дополнительную информацию о формате можно найти по адресу:

man 5 core

Затем:

readelf -Wa core

дает некоторые советы о структуре файла. Кажется, что память содержится в обычных заголовках программы:

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

и есть еще несколько метаданных, присутствующих в области заметок, в частности, prstatusсодержит ПК :

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 может легко сбросить всю память с помощью:

objdump -s core

который содержит:

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..........

который точно соответствует значению stdout в нашем прогоне.

Это было протестировано на Ubuntu 16.04 amd64, GCC 6.4.0 и binutils 2.26.1.



9

Несколько иной подход позволит вам полностью пропустить GDB. Если все , что вы хотите это трассировка, то Linux-специфические утилиты «catchsegv» будут ловить SIGSEGV и отображать трассировку.


3

Неважно, имеет ли исполняемый файл аргументы или нет. Чтобы запустить GDB для любого двоичного файла с сгенерированным файлом ядра, синтаксис приведен ниже.

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

Позвольте мне взять приведенный ниже пример для большего понимания.

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)

Из приведенного выше вывода вы можете догадаться о ядре, будь то NULL-доступ, SIGABORT и т. Д.

Эти числа от # 0 до # 10 являются кадрами стека GDB. Эти кадры стека не из вашего двоичного файла. В вышеупомянутых 0 - 10 кадрах, если вы подозреваете, что что-то не так, выберите этот кадр

(gdb) frame 8

Теперь, чтобы увидеть более подробную информацию об этом:

(gdb) list +

Для дальнейшего изучения проблемы вы можете напечатать предполагаемые значения переменных здесь в данный момент времени.

(gdb) print thread_name

0

Просто введите команду:

$ gdb <Binary> <codeDump>

Или

$ gdb <binary>

$ gdb) core <coreDump>

Нет необходимости указывать аргумент командной строки. Дамп кода генерируется из-за более раннего упражнения.


-1

Вы можете проанализировать файл дампа основной памяти, используя команду "gdb".

 gdb - The GNU Debugger

 syntax:

 # gdb executable-file core-file

 example: # gdb out.txt core.xxx 

1
out.txt это исполняемый файл? Это похоже на вводящее в заблуждение расширение файла.
Алан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.