본문 바로가기

[Debugging] Tips

[리눅스] 라즈베리 파이: coredump 추출 방법 + gdb 디버깅 방법!

이번 포스트에서는 라즈베리 파이에서 coredump가 생성되도록 설정하는 방법과 GDB로 coredump를 로딩하는 방법을 소개합니다.
 
coredump 생성
 
1. coredump 파일 사이즈 설정
 
'ulimit -a' 명령어를 입력하면 coredump 파일의 사이즈가 출력됩니다.
 
root@raspberrypi:/home/pi/work/test_coredump# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 13451
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 13451
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
 
'ulimit -c unlimited' 명령어를 입력해 coredump 파일 사이즈를 최대로 설정합니다.
 
root@raspberrypi:/home/pi/work/test_coredump# ulimit -c unlimited
root@raspberrypi:/home/pi/work/test_coredump# ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 13451
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 13451
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
 
2. /etc/security/limits.conf 수정
 
/etc/security/limits.conf 파일을 열어서 다음과 같이 수정합니다.
 
...
#<domain>      <type>  <item>         <value>
#
 
*               soft    core            unlimited
#root            hard    core            100000
#*               hard    rss             10000
 
'*               soft    core            unlimited' 구문은 원래 주석이었는데,
다음과 같이 주석을 제거합시다.
 
(before)
#*               soft    core            unlimited
 
(after)
*               soft    core            unlimited
 
3. '/proc/sys/kernel/core_uses_pid' 설정
 
'/proc/sys/kernel/core_uses_pid'을 1로 설정합시다.
 
root@raspberrypi:/home/pi/work/test_coredump# echo 1 > /proc/sys/kernel/core_uses_pid
root@raspberrypi:/home/pi/work/test_coredump# cat /proc/sys/kernel/core_uses_pid
1
 
4. '/etc/sysctl.d/core.conf' 파일 수정
 
/etc/sysctl.d/core.conf 파일을 열고 아래 구문을 추가합시다.
 
kernel.core_pattern = /var/lib/coredumps/core-%e-sig%s-user%u-group%g-pid%p-time%t
kernel.core_uses_pid = 1
fs.suid_dumpable = 2
 
5. '/var/lib/coredumps' 설정
 
/var/lib/coredumps 디렉토리를 만들고 쓰고 읽기 권한을 부여합니다.
 
$ mkdir /var/lib/coredumps/
$ chmod 777 /var/lib/coredumps/
 
coredump 생성을 위한 테스트 프로그램
 
coredump 생성을 위한 설정을 마무리했으니 coredump가 생성되도록
샘플 코드를 구성합시다.
 
1. 코드 구현부
 
다음과 같은 코드를 입력한 후 raspbian_test_crash.c 파일로 저장합니다.
 
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 
#define PROC_TIMES      50
#define SLEEP_DURATION  2
#define FORK_MAX_TIMES  3
 
void raspbian_proc_process(void);
 
void raspbian_proc_process(void)
{
    int proc_times = 0;
 
    for(proc_times = 0; proc_times < PROC_TIMES; proc_times++) {
            printf("raspbian tracing \n");
            sleep(SLEEP_DURATION);
 
            if (proc_times > 5)
                *((int *) 0) = 0;  // force crash
    }
 
}
 
int main()
{
    pid_t pid;
    int fork_times = 0;
 
    printf("About to fork process \n");
 
    pid = fork();
 
    if ( pid == 0 )  {
        printf("start execution of child process\n");
        raspbian_proc_process();
    }
 
    else if ( pid > 0 ) {
        printf("start execution of parent process\n");
        raspbian_proc_process();
    }
 
    return 0;
}
 
위 코드는 강제로 어보트를 유발하는 목적의 루틴인데요.
아래와 같이 // force crash 주석문으로 표기된 코드에서 어보트가 유발됩니다.
 
            if (proc_times > 5)
                *((int *) 0) = 0;  // force crash
 
2. Makefile
 
컴파일을 효율적으로 할 수 있게 다음과 같이 Makefile을 작성합니다.
 
raspbian_crash: raspbian_test_crash.c
    gcc -g -o raspbian_crash raspbian_test_crash.c
 
위 구문에서 '-g' 옵션을 적용해야 GDB로 디버깅할 수 있습니다.
 
3. 빌드
 
make 명령어를 입력해 소스를 빌드합시다.
 
root@raspberrypi:/home/pi/work/test_coredump# make
gcc -g -o raspbian_crash raspbian_test_crash.c
 
coredump 생성하기
 
이제 coredump를 생성할 준비가 끝났습니다. 이제 raspbian_crash를 실행해 coredump
를 추출할 차례입니다.
 
1. raspbian_crash 실행하기
 
'./raspbian_crash' 명령어를 입력해 raspbian_crash을 실행합시다.
 
root@raspberrypi:/home/pi/work/test_coredump# ./raspbian_crash
About to fork process
start execution of parent process
raspbian tracing
start execution of child process
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
raspbian tracing
Segmentation fault (core dumped)
 
5초 후에 어보트가 발생해 코어 덤프가 생성됐다는 메시지가 보입니다.
 
ls 명령어를 입력하니 역시 2개 coredump 파일이 보이네요.
 
root@raspberrypi:/home/pi/work/test_coredump# ls
core.1124  core.1125  Makefile  raspbian_crash  raspbian_fork  raspbian_test_crash.c
 
GDB 실행하기
 
1. GDB 실행
 
GDB를 다음 옵션을 적용해 실행합시다.
 
$ gdb raspbian_crash core.1125 
 
root@raspberrypi:/home/pi/work/test_coredump# gdb raspbian_crash core.1125
GNU gdb (Raspbian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
 
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from raspbian_crash...done.
 
warning: exec file is newer than core file.
[New LWP 1125]
Core was generated by `./raspbian_crash'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000104a8 in raspbian_proc_process () at raspbian_test_crash.c:20
20                                      *((int *) 0) = 0;  // force crash
(gdb)
 
GDB 프로그램이 친절하게 어보트가 유발된 코드를 알려주네요.
이 상태에서 콜 스택을 확인합시다.
 
(gdb) bt
#0  0x000104a8 in raspbian_proc_process () at raspbian_test_crash.c:20
#1  0x00010514 in main () at raspbian_test_crash.c:36
 
콜 스택이 출력됩니다.
 
정리
 
이번 포스트에서 소개된 내용을 참고하면
라즈베리 파이에서 coredump를 생성해서 GDB 실습을 할 수 있습니다.