Как сделать дамп памяти?

Для новичков как вообще в Linux, так и в конкретной теме, к которой относится вопрос.

Модератор: Bizdelnick

Аватара пользователя
жучара
Сообщения: 1185
ОС: Debian 12

Как сделать дамп памяти?

Сообщение жучара »

Друзья! Дамп памяти процесса для начала, а там видно будет (возможно вся память так или иначе принадлежит каким-нибудь процессам, я не знаю). Исходник:

Код: Выделить всё

$ cat foo.c
/*foo.c*/
#include <unistd.h> 

int main(int argc, char** argv) {
  while (1) {
    sleep(1);
  };
  return 0;
}
Компилим, запускаем и он просто есть:

Shell

$ gcc foo.c
$ ./a.out
...
Я хочу получить функцию main от и до, она выглядит так (в другой консоли):

Shell

$ objdump -d .text a.out
...
0000000000001139 <main>:
1139: 55 push %rbp
113a: 48 89 e5 mov %rsp,%rbp
113d: 48 83 ec 10 sub $0x10,%rsp
1141: 89 7d fc mov %edi,-0x4(%rbp)
1144: 48 89 75 f0 mov %rsi,-0x10(%rbp)
1148: bf 01 00 00 00 mov $0x1,%edi
114d: e8 de fe ff ff call 1030 <sleep@plt>
1152: eb f4 jmp 1148 <main+0xf>
...
$
Ну то есть эти вот байты надо увидеть. Они есть, но только если смотреть в gdb:

Shell

$ pidof a.out
4987
$ gdb attach $(pidof a.out)
...
Потом несколько лёгких пассов руками и вот мы тут:
fm.png
Итак, функция main лежит по адресу 0x557ebe6f0139. А лежит ли? в консоли gdb делаем её дамп:

dump memory dump_gdb 0x557ebe6f0139 0x557ebe6f0154

Содержимое дампа суть функция main:

Shell

$ hexdump -v -e "1/1 \"0x%02x \"" dump_gdb
0x55 0x48 0x89 0xe5 0x48 0x83 0xec 0x10 0x89 0x7d 0xfc 0x48 0x89 0x75 0xf0 0xbf 0x01 0x00 0x00 0x00 0xe8 0xde 0xfe 0xff 0xff 0xeb 0xf4 $
$
++++++++++++++++++++++++++++++++++++++++++++++++

К каждому процессу не наприаттачиваешься. Дамп всей памяти процесса сделаем и попробуем найти функцию main. Сперва закроем (не описываю, как) отладчик (оттатачимся от процесса a.out), потом удостоверимся, что процесс a.out есть:

Shell

$ pidof a.out
4987
$
А вот и дамп всей памяти процесса:

Shell

$ sudo gcore -a 4987
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f0135219503 in clock_nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
Saved corefile core.4987
[Inferior 1 (process 4987) detached]
$
core.4987 суть дамп процесса 4987. Забегая вперёд- я уж всяко искал там последовательность, которая функция main- нет там её. И в графическом редакторе (wxHexEditor) смотрел и всяко. Сейчас нашлась, например, последовательность 0x55 0x48 0x89 0xe5 0x48 0x83 и то, наверное, в куче какой-нибудь- там всё, что угодно может быть.

...А наша последовательность должна лежать в файле core.4987 . На картинке она лежит по адресу 0x557ebe6f0139, а процесс загружен по адресу 0x557ebe6ef000:

Shell

$ cat /proc/$(pidof a.out)/maps | head -n 2
557ebe6ef000-557ebe6f0000 r--p 00000000 08:01 1055517 /home/user/foo/bar/ch04-process-memory-structure/a.out
557ebe6f0000-557ebe6f1000 r-xp 00001000 08:01 1055517 /home/user/foo/bar/ch04-process-memory-structure/a.out
$
Смещение последовательности в файле core.4987 суть 0x557ebe6f0139 - 0x557ebe6ef000 = 0x1139 (в десятичной системе 4409) В общем, как вы поняли, никакой нужной нам последовательности в файле core.4987 по смещению 0x1139 нет:

Shell

$ dd if=core.4987 of=dump_dd bs=1 skip=4409 count=27
27+0 records in
27+0 records out
27 bytes copied, 0,00159238 s, 17,0 kB/s
$
$ hexdump -v -e "1/1 \"0x%02x \"" dump_dd
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 $
$
Одни ноли. Чёрт его знает, где gdb берёт функцию main. Но ведь берёт же где-то. А я вот не могу дампировать память правильно. ЧЯДНТ? Спасибо. кто откликнется. Debian 12.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5511
ОС: Gentoo

Re: Как сделать дамп памяти?

Сообщение /dev/random »

жучара писал(а):
06.09.2026 09:20
Смещение последовательности в файле core.4987 суть 0x557ebe6f0139 - 0x557ebe6ef000 = 0x1139 (в десятичной системе 4409)
Файл core dump - это ELF, а не прямая побайтовая копия адресного пространства.
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 1185
ОС: Debian 12

Re: Как сделать дамп памяти?

Сообщение жучара »

/dev/random писал:
07.09.2026 12:25
жучара писал(а):
06.09.2026 09:20
Смещение последовательности в файле core.4987 суть 0x557ebe6f0139 - 0x557ebe6ef000 = 0x1139 (в десятичной системе 4409)
Файл core dump - это ELF, а не прямая побайтовая копия адресного пространства.
а в man gcore написано так:
gcore generates a core file for the process(es) specified by process IDs, pids. By default, each core file is written to core.pid, in the current directory.
и нигде не написано что это ELF. Да хоть бы даже и написано было- в этом самом ELF-е отсутствует функция main. И насколько он тогда, получается. верен. именно как ELF?
...Я хочу узнать где gdb в памяти процесса берёт функцию main и тоже получить её дамп. Если единственный способ получить дамп памяти процесса (не какой-то мифический эльф, а действительно дамп действительно памяти и действительно процесса)- это использовать gdb, это очень грустно. По той причине, что он может, не приаттачиться к какому-нибудь процессу и всё, привет, не будет дампа.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5511
ОС: Gentoo

Re: Как сделать дамп памяти?

Сообщение /dev/random »

жучара писал(а):
07.09.2026 16:08
и нигде не написано что это ELF
А почему это должно быть написано? Это детали реализации. В этот файл лезть положено не руками, а утилитами вроде gdb. А о том, что это не побайтовый дамп, вы могли бы и сами догадаться. Дамп всего адресного пространства, включая неразмеченные части, не поместился бы ни на одном жёстком диске, а если пропускать неразмеченные части, то файл должен содержать как минимум метаинформацию о том, какие части размечены (и включены), а какие не размечены (и пропущены). В тупом побайтовом дампе этой метаинформации не будет. Так что они для её хранения пакуют всё в формат ELF, превращая каждую запись из /proc/?/maps в отдельную секцию в этом файле. Вы можете запросить нужную секцию с помощью objdump.
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 1185
ОС: Debian 12

Re: Как сделать дамп памяти?

Сообщение жучара »

/dev/random писал:
07.09.2026 16:19
жучара писал(а):
07.09.2026 16:08
и нигде не написано что это ELF
Дамп всего адресного пространства, включая неразмеченные части, не поместился бы ни на одном жёстком диске
Всего и не надо, надо только адресное пространство одного процесса. Вот адресное пространство процесса a.out

Shell

$ pmap 8385
8385: ./a.out
0000555e045ac000 4K r---- a.out
0000555e045ad000 4K r-x-- a.out
0000555e045ae000 4K r---- a.out
0000555e045af000 4K r---- a.out
0000555e045b0000 4K rw--- a.out
00007f571b3cd000 12K rw--- [ anon ]
00007f571b3d0000 152K r---- libc.so.6
00007f571b3f6000 1368K r-x-- libc.so.6
00007f571b54c000 332K r---- libc.so.6
00007f571b59f000 16K r---- libc.so.6
00007f571b5a3000 8K rw--- libc.so.6
00007f571b5a5000 52K rw--- [ anon ]
00007f571b5c4000 8K rw--- [ anon ]
00007f571b5c6000 4K r---- ld-linux-x86-64.so.2
00007f571b5c7000 152K r-x-- ld-linux-x86-64.so.2
00007f571b5ed000 40K r---- ld-linux-x86-64.so.2
00007f571b5f7000 8K r---- ld-linux-x86-64.so.2
00007f571b5f9000 8K rw--- ld-linux-x86-64.so.2
00007ffc220b0000 132K rw--- [ stack ]
00007ffc221de000 16K r---- [ anon ]
00007ffc221e2000 8K r-x-- [ anon ]
total 2336K
$
Да вы и сами об этом пишите:
/dev/random писал:
07.09.2026 16:19
Так что они для её хранения пакуют всё в формат ELF, превращая каждую запись из /proc/?/maps в отдельную секцию в этом файле. Вы можете запросить нужную секцию с помощью objdump.
Так он мне и нужен, получается. Пусть они зачем-то разбили его на секции. Но да, функции main в нём нет (хоть в objdump, хоть без objdump). Вот этой последовательности нет:
0x55 0x48 0x89 0xe5 0x48 0x83 0xec 0x10 0x89 0x7d 0xfc 0x48 0x89 0x75 0xf0 0xbf 0x01 0x00 0x00 0x00 0xe8 0xde 0xfe 0xff 0xff 0xeb 0xf4
либо она затёрлась во время выполнения, либо я не то дампирую.
...И да, дамп я понимаю, "as is" А если он преобразован во что-то, это и не дамп уже, а чёрт знает что.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5511
ОС: Gentoo

Re: Как сделать дамп памяти?

Сообщение /dev/random »

жучара писал(а):
07.09.2026 16:45
Всего и не надо, надо только адресное пространство одного процесса
Я про "одного процесса" и говорю. Каждый процесс имеет доступ к адресам от 0 до (2^N)-1, где N - разрядность процессора, и один и тот же адрес для разных процессов может содержать разные данные. Это и называется адресным пространством процесса. Для 64битных процессоров это значит, что полный дамп всего адресного пространства одного процесса займёт 16 экзабайт. Но большая часть адресного пространства неразмечена - при обращении к ним происходит ошибка. Поэтому необходимо сохранить только размеченные диапазоны (диапазоны, перечисленные в файле maps). И разумеется, файл должен также содержать информацию о том, какие диапазоны смещений в файле соответствуют каким диапазонам адресов в адресном пространстве процесса, иначе он будет бесполезен для своего главного (я бы даже сказал, единственного) предназначения - посмертной отладки, во время которой процесса (и файла maps) уже нет. Кроме того, для посмертной отладки также нужна информация о потоках, о содержимом регистров процессора и т.д. Вся эта информация пишется в файл как отдельные секции. В том числе и каждый диапазон адресного пространства, упомянутый в maps, сохраняется как отдельная секция.
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 1185
ОС: Debian 12

Re: Как сделать дамп памяти?

Сообщение жучара »

/dev/random писал:
07.09.2026 17:21
жучара писал(а):
07.09.2026 16:45
Всего и не надо, надо только адресное пространство одного процесса
Я про "одного процесса" и говорю. Каждый процесс имеет доступ к адресам от 0 до (2^N)-1, где N - разрядность процессора, и один и тот же адрес для разных процессов может содержать разные данные. Это и называется адресным пространством процесса. Для 64битных процессоров это значит, что полный дамп всего адресного пространства одного процесса займёт 16 экзабайт. Но большая часть адресного пространства неразмечена - при обращении к ним происходит ошибка. Поэтому необходимо сохранить только размеченные диапазоны (диапазоны, перечисленные в файле maps). И разумеется, файл должен также содержать информацию о том, какие диапазоны смещений в файле соответствуют каким диапазонам адресов в адресном пространстве процесса, иначе он будет бесполезен для своего главного (я бы даже сказал, единственного) предназначения - посмертной отладки, во время которой процесса (и файла maps) уже нет. Кроме того, для посмертной отладки также нужна информация о потоках, о содержимом регистров процессора и т.д. Вся эта информация пишется в файл как отдельные секции. В том числе и каждый диапазон адресного пространства, упомянутый в maps, сохраняется как отдельная секция.
Я предполагаю, что нужная мне последовательность находится именно что в размеченном пространстве. Коего не так уж много в моём случае и дамп коего я безуспешно пытаюсь сделать и прошу добрых людей мне помочь. Всё остальное- регистры там, то, сё, вещи, конечно, хорошие, но мне не нужные абсолютно. Пока ненужные. Я отлаживать сейчас ничего не собираюсь, я книжку читаю, там приведена команда cat /proc/402/maps и написано, что она означает:
Диапазон адресов — начальный и конечный адреса отраженного диапазона. Если данная область отражена в файл, то путь к нему указан рядом.
Я хочу просто убедиться, что да, это так. Что в файле a.out есть код и он же есть в дампе памяти в памяти процесса и не абы где а по смещению, которое мы можем исхитриться и найти в файле a.out Хочу убедиться и дальше пойти. Но пока я в этом убеждаюсь только с помощью отладчика gdb, что грустно- уже писал, почему. А так- не тот инструмент я выбрал, наверное, я про gcore.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21549
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как сделать дамп памяти?

Сообщение Bizdelnick »

Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 1185
ОС: Debian 12

Re: Как сделать дамп памяти?

Сообщение жучара »

Bizdelnick писал:
08.09.2026 13:05
man proc_pid_mem
с Вашей подачи я вышел на эту статью
https://habr.com/ru/companies/otus/articles/898448/
А остальное дело техники. В коде я приаттачиваюсь, а потом отаттачиваюсь от трассируемого. Наверное, gdb делает то же самое. Ну, пусть так и будет. Вывод неотформатированный, конечно, но, главное это то, что нужно.

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
        return 1;
    }

    pid_t pid = atoi(argv[1]);

    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
        perror("ptrace attach");
        return 1;
    }

    waitpid(pid, NULL, 0);
    printf("Attached to process %d\n", pid);

//база, это (значение второй строки команды pmap <нужный нам процесс>) + 0x139)
//получаем 4 значения: база, база + 8, база + 0x10, база + 0x10
//и их пихае третьим параметром в функцию ptrace

    printf("0x%lx\n", ptrace(PTRACE_PEEKTEXT, pid, (void *)0x5568dbd18139, NULL));
    printf("0x%lx\n", ptrace(PTRACE_PEEKTEXT, pid, (void *)0x5568DBD18141, NULL));
    printf("0x%lx\n", ptrace(PTRACE_PEEKTEXT, pid, (void *)0x5568DBD18149, NULL));
    printf("0x%lx\n", ptrace(PTRACE_PEEKTEXT, pid, (void *)0x5568DBD18151, NULL));

    // Делаем что хотим…

    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    printf("Detached\n");

    return 0;
}

Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
ormorph
Сообщения: 3361
ОС: Gentoo

Re: Как сделать дамп памяти?

Сообщение ormorph »

Есть функция process_vm_readv, и аналогичный системный вызов ядра, позволяющий это сделать без остановки процесса через ptrace.
Спасибо сказали: