سؤال

لدي عملية في Linux تتعرض لخطأ تجزئة.كيف يمكنني إخباره بإنشاء تفريغ أساسي عندما يفشل؟

هل كانت مفيدة؟

المحلول

هذا يعتمد على القشرة التي تستخدمها.إذا كنت تستخدم bash، فإن أمر ulimit يتحكم في العديد من الإعدادات المتعلقة بتنفيذ البرنامج، مثل ما إذا كان يجب عليك تفريغ النواة.إذا كتبت

ulimit -c unlimited

فهذا سيخبر باش أن برامجه يمكنها تفريغ النوى من أي حجم.يمكنك تحديد حجم مثل 52M بدلاً من غير محدود إذا كنت تريد ذلك، ولكن من الناحية العملية لا ينبغي أن يكون هذا ضروريًا نظرًا لأن حجم الملفات الأساسية ربما لن يمثل مشكلة بالنسبة لك أبدًا.

في tcsh، ستكتب

limit coredumpsize unlimited

نصائح أخرى

كما هو موضح أعلاه، فإن السؤال الحقيقي الذي يتم طرحه هنا هو كيفية تمكين عمليات التفريغ الأساسية على نظام لم يتم تمكينها فيه.تمت الإجابة على هذا السؤال هنا.

إذا أتيت إلى هنا على أمل أن تتعلم كيفية إنشاء تفريغ أساسي لعملية معلقة، فالإجابة هي

gcore <pid>

إذا لم يكن gcore متاحًا على نظامك

kill -ABRT <pid>

لا تستخدم kill -SEGV لأن ذلك غالبًا ما يستدعي معالج الإشارة مما يزيد من صعوبة تشخيص العملية المتوقفة

ما فعلته في النهاية هو إرفاق gdb بالعملية قبل أن تتعطل، وبعد ذلك عندما حصلت على segfault قمت بتنفيذ الأمر generate-core-file يأمر.هذا الجيل القسري من تفريغ الأساسية.

للتحقق من مكان إنشاء عمليات التفريغ الأساسية، قم بتشغيل:

sysctl kernel.core_pattern

أو:

cat /proc/sys/kernel/core_pattern

أين %e هو اسم العملية و %t وقت النظام.يمكنك تغييره في /etc/sysctl.conf وإعادة التحميل بواسطة sysctl -p.

إذا لم يتم إنشاء الملفات الأساسية (اختبرها عن طريق: sleep 10 & و killall -SIGSEGV sleep)، تحقق من الحدود عن طريق: ulimit -a.

إذا كان حجم ملفك الأساسي محدودًا، فقم بتشغيل:

ulimit -c unlimited

لجعلها غير محدودة.

ثم اختبر مرة أخرى، إذا نجح تفريغ النواة، فسترى "(تم تفريغ النواة)" بعد إشارة خطأ التجزئة على النحو التالي:

خطأ تجزئة:11 (ملقاة الأساسية)

أنظر أيضا: الأساسية ملقاة - ولكن الملف الأساسي ليس في الدليل الحالي؟


أوبونتو

في Ubuntu تتم معالجة مقالب المخلفات الأساسية بواسطة تطبيق ويمكن أن يكون موجودا في /var/crash/.ومع ذلك، يتم تعطيله افتراضيًا في الإصدارات المستقرة.

لمزيد من التفاصيل، يرجى مراجعة: أين أجد التفريغ الأساسي في أوبونتو؟.

ماك

بالنسبة لنظام التشغيل macOS، راجع: كيفية إنشاء عمليات تفريغ أساسية في نظام التشغيل Mac OS X؟

ربما يمكنك القيام بذلك بهذه الطريقة، هذا البرنامج عبارة عن عرض توضيحي لكيفية محاصرة خطأ التجزئة وإخراجه إلى مصحح الأخطاء (هذا هو الكود الأصلي المستخدم تحت AIX) ويطبع تتبع المكدس حتى نقطة خطأ التجزئة.سوف تحتاج إلى تغيير sprintf متغير للاستخدام gdb في حالة لينكس.

#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 لتفريغ النواة كما هو موضح هنا في هذه المدونة هنا.

هناك المزيد من الأشياء التي قد تؤثر على إنشاء التفريغ الأساسي.لقد واجهت هذه:

  • يجب أن يكون دليل التفريغ قابلاً للكتابة.بشكل افتراضي، هذا هو الدليل الحالي للعملية، ولكن يمكن تغيير ذلك عن طريق الإعداد /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. تنفيذ كمد limit coredumpsize unlimited والتحقق من ذلك مع كمد 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. للتحقق من كتابة الملف الأساسي، يمكنك إنهاء العملية ذات الصلة باستخدام cmd kill -s SEGV <PID> (لا ينبغي أن تكون هناك حاجة إليه، فقط في حالة عدم كتابة أي ملف أساسي، يمكن استخدام هذا كفحص):

    # kill -s SEGV <PID>
    

بمجرد كتابة الملف الأساسي، تأكد من إلغاء تنشيط إعدادات التفريغ الأساسي مرة أخرى في الملفات ذات الصلة (1./2./3.)!

لأوبونتو 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));
}

انتظر.يتم ذلك تلقائيًا.لا حاجة للقيام بذلك

ومن الجدير بالذكر أنه إذا كان لديك systemd إعداد، ثم الأمور مختلفة قليلا.عادةً ما يتضمن الإعداد نقل الملفات الأساسية عبر الأنابيب core_pattern قيمة sysctl، من خلال systemd-coredump(8).عادةً ما يتم تكوين الحد الأقصى لحجم الملف الأساسي على أنه "غير محدود" بالفعل.

ومن الممكن بعد ذلك استرداد مقالب الأساسية باستخدام coredumpctl(1).

تخزين مقالب الأساسية، الخ.تم تكوينه بواسطة coredump.conf(5).توجد أمثلة لكيفية الحصول على الملفات الأساسية في صفحة الدليل coredumpctl، لكن باختصار ستبدو بالشكل التالي:

ابحث عن الملف الأساسي:

[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET   16163  1224  1224  11 present /home/vps/test_me

الحصول على الملف الأساسي:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top