Как создать дамп ядра в Linux, когда процесс получает сегментации?



У меня есть процесс в Linux, который получает ошибку сегментации. Как я могу сказать ему, чтобы создать дамп ядра, когда он терпит неудачу?

660   10  

10 ответов:

Это зависит от того, какую оболочку вы используете. Если вы используете bash, то команда ulimit управляет несколькими настройками, связанными с выполнением программы, например, следует ли сбрасывать ядро. Если вы наберете

ulimit -c unlimited

тогда это скажет bash, что его программы могут сбрасывать ядра любого размера. Вы можете указать размер, такой как 52M вместо неограниченного, если хотите, но на практике это не должно быть необходимо, так как размер основных файлов, вероятно, никогда не будет проблемой для вы.

в tcsh, вы бы набрали

limit coredumpsize unlimited

как описано выше реальный вопрос здесь заключается в том, как включить дампы ядра в системе, где они не включены. Вот ответ на этот вопрос.

Если вы пришли сюда в надежде узнать, как создать дамп ядра на зависший процесс, ответ

gcore <pid>

Если gcore не доступен в вашей системе, то

kill -ABRT <pid>

Не используйте kill-SEGV, так как это часто вызывает обработчик сигнала, что затрудняет диагностику застрявшего процесс

то, что я сделал в конце, было прикрепить gdb к процессу, прежде чем он разбился, а затем, когда он получил segfault я выполнил . Это вынужденная генерация дампа ядра.

может быть, вы могли бы сделать это таким образом, эта программа является демонстрацией того, как поймать ошибку сегментации и оболочки из отладчика (это исходный код, используемый в разделе AIX) и выводит трассировку стека до точки ошибки сегментации. Вам нужно будет изменить sprintf переменной, чтобы использовать gdb в случае Linux.

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>

static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);

struct sigaction sigact;
char *progname;

int main(int argc, char **argv) {
    char *s;
    progname = *(argv);
    atexit(cleanup);
    init_signals();
    printf("About to seg fault by assigning zero to *s\n");
    *s = 0;
    sigemptyset(&sigact.sa_mask);
    return 0;
}

void init_signals(void) {
    sigact.sa_handler = signal_handler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, (struct sigaction *)NULL);

    sigaddset(&sigact.sa_mask, SIGSEGV);
    sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);

    sigaddset(&sigact.sa_mask, SIGBUS);
    sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);

    sigaddset(&sigact.sa_mask, SIGQUIT);
    sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);

    sigaddset(&sigact.sa_mask, SIGHUP);
    sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);

    sigaddset(&sigact.sa_mask, SIGKILL);
    sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}

static void signal_handler(int sig) {
    if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
    if (sig == SIGSEGV || sig == SIGBUS){
        dumpstack();
        panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
    }
    if (sig == SIGQUIT) panic("QUIT signal ended program\n");
    if (sig == SIGKILL) panic("KILL signal ended program\n");
    if (sig == SIGINT) ;
}

void panic(const char *fmt, ...) {
    char buf[50];
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(buf, fmt, argptr);
    va_end(argptr);
    fprintf(stderr, buf);
    exit(-1);
}

static void dumpstack(void) {
    /* Got this routine from http://www.whitefang.com/unix/faq_toc.html
    ** Section 6.5. Modified to redirect to file to prevent clutter
    */
    /* This needs to be changed... */
    char dbx[160];

    sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
    /* Change the dbx to gdb */

    system(dbx);
    return;
}

void cleanup(void) {
    sigemptyset(&sigact.sa_mask);
    /* Do any cleaning up chores here */
}

возможно, вам придется дополнительно добавить параметр, чтобы получить gdb для сброса ядра, как показано здесь в этом блоге здесь.

чтобы проверить, где генерируются основные дампы, выполните:

sysctl kernel.core_pattern

здесь %e - имя процесса, а %t системное время. Вы можете изменить его в /etc/sysctl.conf и перезагрузки sysctl -p.

если основные файлы не создаются (тест: sleep 10 & и killall -SIGSEGV sleep), проверьте лимиты: ulimit -a.

если размер вашего основного файла ограничен, запустите:

ulimit -c unlimited

чтобы сделать его неограниченным.

затем проверьте еще раз, если ядро демпинг успешен, вы увидите "(core dumped) " после индикации ошибки сегментации, как показано ниже:

ошибка сегментации: 11 (ядро бросила)


Ubuntu

в Ubuntu обычно дампы обрабатываются apport in /var/crash/, но в другом формате, однако он не включен по умолчанию в стабильных выпусках. Подробнее читайте на Ubuntu wiki.

он использует core_pattern сразу пустить по трубам сброс сердечника в программе:

$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c

таким образом, даже основные файлы отключены ulimit,apport будет по-прежнему захватить аварии (Как включить или отключить приложение?).


macOS

для macOS, см.: как создать дампы ядра в Mac OS X?

есть больше вещей, которые могут повлиять на генерацию дампа ядра. Я столкнулся с такими:

  • каталог для дампа должен быть доступен для записи. По умолчанию это текущий каталог процесса, но это может быть изменено путем установки /proc/sys/kernel/core_pattern.
  • в некоторых условиях, значение ядра в /proc/sys/fs/suid_dumpable может помешать созданию ядра.

есть больше ситуаций, которые могут предотвратить поколение, которые описаны в человеке страница-попробуйте man core.

для активации дампа ядра выполните следующие действия:

  1. на /etc/profile комментарий строка:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  2. на /etc/security/limits.conf закомментировать строку:

    *               soft    core            0
    
  3. Выполнить cmd limit coredumpsize unlimited и проверить его с cmd limit:

    # limit coredumpsize unlimited
    # limit
    cputime      unlimited
    filesize     unlimited
    datasize     unlimited
    stacksize    10240 kbytes
    coredumpsize unlimited
    memoryuse    unlimited
    vmemoryuse   unlimited
    descriptors  1024
    memorylocked 32 kbytes
    maxproc      528383
    #
    
  4. чтобы проверить, записывается ли corefile, вы можете убить соответствующий процесс с помощью cmd kill -s SEGV <PID> (не должно быть необходимо, на всякий случай нет ядра файл записывается это может быть использовано в качестве проверки):

    # kill -s SEGV <PID>
    

после записи corefile убедитесь, что вы снова отключили настройки coredump в соответствующих файлах (1./2./3.) !

Для Ubuntu 14.04

  1. Проверьте дамп ядра включен:

    ulimit -a
    
  2. одна из строк должна быть:

    core file size          (blocks, -c) unlimited
    
  3. если нет :

    gedit ~/.bashrc и добавить ulimit -c unlimited чтобы завершить файл и сохранить, повторно запустите терминал.

  4. создайте приложение с отладочной информацией:

    В Makefile -O0 -g

  5. запустите приложение, которое создает ядро дамп (файл дампа ядра с именем 'core' должен быть создан рядом с файлом application_name):

    ./application_name
    
  6. запуск под gdb:

    gdb application_name core
    

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

лучше включить дамп ядра программно с помощью системного вызова setrlimit.

пример:

#include <sys/resource.h>

bool enable_core_dump(){    
    struct rlimit corelim;

    corelim.rlim_cur = RLIM_INFINITY;
    corelim.rlim_max = RLIM_INFINITY;

    return (0 == setrlimit(RLIMIT_CORE, &corelim));
}

Comments

    Ничего не найдено.