Создать основной файл с помощью GDB
Я использовал gdb generate-core-file для генерации файла ядра для процесса (mongod), но процесс mmap содержит много файлов данных, а Res этого процесса составляет до 36.1G.
после того, как файл ядра занял 34 ГБ, на диске больше нет свободного места, поэтому я получил:
предупреждение: запись раздела заметки (на устройстве не осталось места) Сохранено corefile core.12038
Я хочу знать, все ли данные mmap будут выгружены в основной файл? Что я могу сделать, если я хочу видеть только некоторые локальные переменные?
Предыстория: у нас возникла проблема с производством, а двоичный файл на производстве не содержит символьной информации. поэтому я хочу создать основной файл и провести анализ в автономном режиме.
2 ответа
Я хочу знать, все ли данные mmap будут выгружены в основной файл?
Обычно ядро создает дамп только для записи mmaps, но не только для чтения. Однако это настраивается: см. Справочную страницу core(5) (часть "Управление тем, какие сопоставления записываются в дамп ядра").
Предыстория: у нас возникла проблема с производством, а двоичный файл на производстве не содержит символьной информации.
"Стандартный" подход заключается в удаленной отладке таких двоичных файлов с gdbserver
и подключиться к нему с gdb
у которого есть доступ к полному отладочному двоичному файлу.
Что я могу сделать, если я хочу видеть только некоторые локальные переменные? Предыстория: у нас возникла проблема с производством, а двоичный файл на производстве не содержит символьной информации.
Вы не упомянули ОС в своем вопросе, так что если вы на Linux
1) Установите на рабочий сервер свою программу с отладочной информацией
2) Если вы не можете сделать это, проанализируйте ассемблерный код интересующей вас функции и получите значения локальных переменных от ассемблера
А затем используйте SystemTap для отслеживания вашей программы.
Позвольте мне проиллюстрировать оба подхода на простом примере. Во-первых, программа C++ для анализа:
>cat main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int f(int arg)
{
int a = arg+1;
int b = arg+2;
int c = a + b;
printf ("printf in program: f, c: %d\n", c);
return c;
}
int main(int argc, char *argv[])
{
printf ("f: %p\n", &f);
int sum = 0;
while (true) {
for (int i= atoi(argv[1]); i < atoi(argv[2]); ++i) {
sum += f(i);
}
sleep(5);
}
printf("Sum: %d\n", sum);
return 0;
}
Поэтому я хочу получить значение локальной переменной "c" в функции f ().
1) Если доступна символьная информация
>cat measure_f.stp
probe process("a.out").statement("*@main.cpp:10")
{
printf("SystemTap, time: %s, the local variable c :%d\n", ctime(gettimeofday_s()), $c)
}
>sudo stap measure_f.stp -c "./a.out 21 23"
f: 0x400634
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :47
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :47
1) Если информация о символах недоступна, используйте ассемблер
Сначала разберите вашу функцию и найдите, какой адрес вы будете контролировать
(gdb) disassemble /m f
Dump of assembler code for function f(int):
6 {
0x0000000000400634 <+0>: push %rbp
0x0000000000400635 <+1>: mov %rsp,%rbp
0x0000000000400638 <+4>: sub $0x20,%rsp
0x000000000040063c <+8>: mov %edi,-0x14(%rbp)
7 int a = arg+1;
0x000000000040063f <+11>: mov -0x14(%rbp),%eax
0x0000000000400642 <+14>: add $0x1,%eax
0x0000000000400645 <+17>: mov %eax,-0xc(%rbp)
8 int b = arg+2;
0x0000000000400648 <+20>: mov -0x14(%rbp),%eax
0x000000000040064b <+23>: add $0x2,%eax
0x000000000040064e <+26>: mov %eax,-0x8(%rbp)
9 int c = a + b;
0x0000000000400651 <+29>: mov -0x8(%rbp),%eax
0x0000000000400654 <+32>: mov -0xc(%rbp),%edx
0x0000000000400657 <+35>: lea (%rdx,%rax,1),%eax
0x000000000040065a <+38>: mov %eax,-0x4(%rbp)
10 printf ("printf in program: f, c: %d\n", c);
0x000000000040065d <+41>: mov -0x4(%rbp),%eax
0x0000000000400660 <+44>: mov %eax,%esi
0x0000000000400662 <+46>: mov $0x4007f8,%edi
0x0000000000400667 <+51>: mov $0x0,%eax
0x000000000040066c <+56>: callq 0x4004f8 <printf@plt>
11 return c;
0x0000000000400671 <+61>: mov -0x4(%rbp),%eax
12 }
0x0000000000400674 <+64>: leaveq
0x0000000000400675 <+65>: retq
Как вы можете видеть, чтобы получить локальную переменную c, необходимо получить 0x000000000040065a, чтобы получить регистр%eax
> cat measure_f_2.stp
probe begin
{
printf("Monitoring process %d\n", $1)
}
probe process($1).statement(0x000000000040065a).absolute
{
printf("SystemTap (2), time: %s, the local variable c (rax):%d\n", ctime(gettimeofday_s()), register("rax"))
}
Поэтому я запустил "./a.out 21 23", а затем запустил сценарий SystemTap.
>sudo stap measure_f_2.stp 11564
Monitoring process 11564
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):47
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):47