Linuxでデバッグ用のコアファイルを表示するには?

Linuxでデバッグ用のコアファイルを表示するには?

プログラムのデバッグ中にコアファイルの内容を見たいです。コアファイルの内容を表示するには?

答え1

GDBの最小実行可能例

GDBは以前に以下で言及されました:https://unix.stackexchange.com/a/89934/32558この答えを承認することを検討してください。

シンプルc

int myfunc(int i) {
    *(int*)(0) = i;
    return i - 1;
}

int main(int argc, char **argv) {
    (void)argv;
    int i = argc * 2;
    int ret = myfunc(i);
    return ret;
}

コンパイルして実行してコアを生成します。

gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o simple.out simple.c

コアファイルを作成するには、まず現在の端末で実行する必要があります。

ulimit -c unlimited

これは「サイズ制限なしでコアファイルダンプ」を意味します。これは、コアファイルに競合が発生したプロセスのメモリ全体が含まれ、サイズが非常に大きい可能性があるために発生します。

テストのために、Ubuntu 16.04から既存のコアファイルを削除する必要があります(TODO必須?忘れました)。

rm -f core

Ubuntu 22.04からコアファイルを入手するには、apportと戦う必要があります。https://askubuntu.com/questions/1349047/where-do-i-find-core-dump-files-and-how-do-i-view-and-analyze-the-backtrace-st/1442665#1442665たとえば、

echo 'core' | sudo tee /proc/sys/kernel/core_pattern

その後、プログラムを実行します。

./simple.out

端末には以下が含まれます。

Segmentation fault (core dumped)

コアファイルが作成されました。 Ubuntu 16.04では、ファイル名は次のとおりです。

core

Ubuntu 22.04では、echo 'core' | sudo tee /proc/sys/kernel/core_patternファイル名は次のとおりです。

core.<pid>

ここで、PIDはプロセスID、つまり数値です。例:

core.162152

Linuxカーネルの更新がサフィックスの追加を開始したためだと思います.pid。することを確認してください。

これで、コアファイルを次のように使用できます。

gdb simple.out core
gdb simple.out core.162152

今、私たちはGDBセッションに入ります。これは、プログラムがクラッシュしたときとまったく同じ状況ですが、プログラムがすぐに終了するため、「続行」できません。

#0  0x0000557097e0813c in myfunc (i=2) at simple.c:2
2           *(int*)(0) = i; /* line 7 */
(gdb) bt
#0  0x0000557097e0813c in myfunc (i=2) at simple.c:2
#1  0x0000557097e0816b in main (argc=1, argv=0x7ffcffc4ba18) at simple.c:9
(gdb) up
#1  0x0000557097e0816b in main (argc=1, argv=0x7ffcffc4ba18) at simple.c:9
9           int ret = myfunc(i);
(gdb) p argc
$1 = 1

したがって、実行後にbt競合が発生したときにコードがどこにあったかをすぐに知ることができ、時にはエラーを修正するのに十分です。

例に示すように、クラッシュ時にプログラムメモリを調べてエラーの原因を特定できます。プロセス仮想メモリはすべてコアファイルに含まれています。

Ubuntu 16.04および22.04 amd64でテストされました。

GDB経由で直接プログラムを実行することもできます。

問題が簡単に再現可能で(つまり、迅速かつ決定的に競合が発生した場合)、コマンドラインを簡単に制御できる場合(つまり、変更を望まない、または変更できない他のプログラムから呼び出されたプログラムではない)、最善の方法は次のとおりです。と同じです。 GDBを介してプログラムを実行します。

gdb -ex run simple.out

シグナルが受信されると、GDBはデフォルトでシグナルの原因によって中断され、コアファイルを使用するのと同じ状況になります。

直接Binutils分析

よりよく理解するために、GDBなしでコアファイルの内容を観察してみましょう。私たちができるので。

物事の相関関係を確認できるように、独自のメモリアドレスを印刷するプログラムを作成しましょう。

メインプログラム

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

プログラム出力:

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

最初:

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

コメント領域にはより多くのメタデータもあります。特にprstatusPCを含む:

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

これは私たちの実行の標準出力値と正確に一致します。

Ubuntu 16.04 amd64、GCC 6.4.0、binutils 2.26.1でテストされました。

Mozillarrの逆デバッグは究極の「コアファイル」です。

コアファイルを使用すると、中断時にスタックを確認できます。

しかし、一般的に実際にすべきことは、時間をさかのぼって失敗の根本原因をより詳細に把握することです。

素晴らしいMozilla rrを使用するとこれを行うことができますが、トレースファイルが大きくなり、パフォーマンスがわずかに低下します。

例は次のとおりです。https://stackoverflow.com/questions/1470434/how-does-reverse-debugging-work/53063242#53063242

また、見ることができます

答え2

gdbは、コアファイルをスキャンするために使用できるGNUデバッガです。 BTW bt(逆トラッキング)は、プログラムコールスタックをチェックするのに便利なgdbコマンドです。

gdb binary-file core-file

答え3

コマンドラインツールを使用する場合は、次のものを使用できます。データベース:

gdb <program> <core file>

または

gdb <program> -c <core file>

GUIが気に入ったらインストールしてくださいディディをクリックし、デバッグしたいプログラムとコアファイルを開きます。

答え4

#-------------------------------------------------------------------------
#!/usr/bin/ksh
# -------------------------------------------------------------------------

_OUTFILE=XXXX-XXXX-Audit-`date +"%Y%m%d%H%M"`.log
>$_OUTFILE
MAILLIST=""
COREPATH=$PKMS/logs/cores
MARKER=$COREPATH/marker

function Parse
{
   while getopts :p:u:s:l: name
      do
    case $name in
        p) PKMS="$OPTARG" ;;       # $PKMS
        u) DBUSER="$OPTARG" ;;     # $DBUSER 
        s) DBPSWD="$OPTARG" ;;     # $DBPSWD
        l) DBLOCN="$OPTARG" ;;     # $DBLOC 
        *) Usage ;;                     # display usage and exit
       esac
      done
   if [[ -z "${PKMS}"  || -z "${DBUSER}" || -z "${DBPSWD}" || -z "${DBLOCN}" ]] 
   then
    echo $Usage
    exit -1
   fi
}


function getCoreDumps
{
   COREFILES=$COREPATH/newcores.txt
   STACKS=$COREPATH/stacks.txt
   DATE=$(date +%y%m%d%H%M%S)
   >$COREFILES
   >$STACKS
   umask 002

   find $COREPATH -type f -newer $MARKER -name "core" > $COREFILES
   find $COREPATH -type f -newer $MARKER -name "core.?" >> $COREFILES

   rm $STACKS 2>/dev/null

   for i in $(<$COREFILES)
   do
        mv $i $i.$DATE
        chmod g+r,g+w $i.$DATE
        #echo "Coredump recently found at" `date` '\n'>> $STACKS
        echo $i.$DATE >> $STACKS
    #echo >> $STACKS
   done

   NL=$(wc -l $COREFILES  | awk '{ print $1 }')
   if [ "$NL" -gt 0 ]
   then
    echo "New CORE files found:" >> $_OUTFILE
    echo "--- ---- ----- ------" >> $_OUTFILE
    cat $STACKS >> $_OUTFILE
   else
    echo "No new CORE files found" >> $_OUTFILE
    echo "-- --- ---- ----- -----" >> $_OUTFILE
   fi

}



#/usr/bin/clear

echo "\t\t\t\t---------------------------------\t" >> $_OUTFILE
echo "\t\t\t\t
echo "\t\t\t\t---------------------------------\t" >> $_OUTFILE

date "+                             %d/%m/%Y %H:%M:%S"  >> $_OUTFILE

echo "===================" >> $_OUTFILE
echo " APPICATION MACHINES" >> $_OUTFILE
echo "===================" >> $_OUTFILE
echo >> $_OUTFILE
echo >> $_OUTFILE



getCoreDumps
echo >> $_OUTFILE
echo >> $_OUTFILE



echo "===================" >> $_OUTFILE
echo "XXXX APP DataBase Info" >> $_OUTFILE
echo "===================" >> $_OUTFILE

echo >> $_OUTFILE
getAPPDBInfo
echo >> $_OUTFILE
echo >> $_OUTFILE

MAILDATE=$(date +%d/%m/%Y)


mailx -s "XXXX Monitor Log for $PKMS Environment - Dated $MAILDATE" $MAILLIST < $_OUTFILE

touch $MARKER
rm /tmp/XXXXtempOUTFILE
exit 0

関連情報