'GDB'에 해당되는 글 2건

  1. 2009.05.12 리눅스 시스템 오류의 처리방법 (1)
  2. 2009.03.01 GDB를 사용한 CORE 파일의 분석 (2)
2009.05.12 12:00

리눅스 시스템 오류의 처리방법

출처 : 한빛 네트워크

리눅스 머신이 다운되고 한참 작업이 진행되고 있을 때 모든 일이 수포로 돌아가게 된다. 이 상황을 어떻게 설명할 것이며 더욱이 어떻게 그와 같은 일이 반복되는 것을 어떻게 방지할 수 있을까? 이 기사는 유저 공간 프로그램에 관해 얘기하고자 하는 것은 아니다. 그것들 중 몇 개는 복구의 기회조차 없이 박스를 망칠 것이며 유일하게 내가 알고있는 것은 crashme이다. 대부분 시스템상의 고장은 커널(kernel-oops)로 인하여 발생하거나 하드웨어적인 오류로 인하여 발생한다. 어쨌든 커널 오류(kernel-oops)는 무엇인가? 커널 오류는 커널 코드가 회복할 수 없는 상태에 있을 때 발생한다.

대부분의 경우에 있어 커널은 드라이브에 커널의 상태를 기술할 수 있으며 드라이브는 적당한 툴만 있다면 이미 발생한 것을 결정해준다. Aiee 이나 killing interrupt handler 오류와 같은 몇몇 경우에 있어서 커널이 드라이브에 상태를 적을 수 없을 수도 있다. 인터럽트 핸들러 없이 I/O 인터럽트 처리는 불가능하다. 최악의 상황에서도 어떤 데이터는 복구될 수 있으며 그 원인은 종종 일반적인 것으로 결정될 수 있다. 툴과 사후 정보 진단 도구는 커널 에러 복구에 필수적인 부분이다. 가장 명확한 도구는 시스템 로그이다. dmesg는 시스템과 커널 로그로부터 관련 데이터를 추출하는데 유용한 도구이다. 발생한 커널 오류(kernel-oops)를 추적하기 위한 특별한 도구도 있다. ksymoops은 시스템에 오류가 발생했을 때 오류가 발생한 순간부터 가능한 한 빠른 시간 안에 이전 시스템과 가장 근접한 상태의 시스템이 되도록 해준다.

ksymoops는 함수들의 연결고리를 추적하며 오류 발생 당시 커널이 가지고 있던 오프셋과 함수를 보여준다. 시스템 로그의 정보나 ksymoops로부터 시스템 관리자는 오류 발생 시점에서 커널이 실행 하고자 했던 함수 기능을 결정할 수 있다. 함수 결정후 다른 로드가능한 모듈에 있어서 하드웨어 드라이버나 스왑을 변경 해야 할지 말지 또는 관련된 커널 개발자에게 에러 보고서를 보낼지 말지에 대해 훨씬 쉽게 결정할 수 있다.

dmesg

만약 당신의 시스템이 아직 작동중이라면 일반적으로 콘솔상에 있는 커널 진단 정보를 얻기 위해 dmesg를 실행할 수 있다. 그 메시지는 또한 /proc/kmsg에 작성되지만 dmesg는 나중에 참조하거나 커널 전문가에게 알릴 수 있도록 메시지를 복사할 수 있도록 해준다. 대부분의 유저들은 dmesg를 읽을 수있으며 /proc/kmsg은 퍼미션을 제한한다.

dmesg > filename
유용하게 사용될 수 있는 인자:

-nlevel
메시지 로그에 나타낼 메시지의 레벨을 설정한다. 1은 커널 패닉 메시지, 7은 개발자 버그를 포함한 모든 메시지를 나타낸다.
-sbufsize
메시지 버퍼의 사이즈를 제한한다.
-c
프린트 후 메시지 버퍼를 비운다.

syslogd & klogd

syslogdklogd은 시스템 로그 생성자이다. klogd은 커널의 로깅을 처리하며 종종 syslogd와 함게 번들되거나 설정된다. 로그 생성자는 디버깅 이후에는 쓸모없게 되지만 다음에 혹시 일어날 지도 모를 오류에 대비해 더욱 많은 데이터에 로그할 수 있게 설정될 수도 있다. 시스템 로그파일의 위치를 지정하기 위해서는 /etc/syslogd.conf를 사용하라. 만약 /proc/kmsg이 없다면 커널 로그 파일이 있는 곳을 확인해야 한다. 로드할 수 있는 모듈을 실행하고있는 중이라면 klogd은 반드시 모듈이 로드되거나 끝날 때 신호를 받아야 한다. sysklogd 소스는 모듈 로더나 언로더가 정확하게 klogd 할 수 있도록 modules-2.0.0 패키지에 패치 되어있다. modutils 2.3.1에서부터 모듈 로그가 수립된다. 로그를 사용하기 위해 루트 소유의 허가권이 "644" 또는 "600"인 /var/log/ksymoops을 생성한다. 스크립트 insmod_ksymoops_clean는 구버전을 지우고 cron으로 동작할 것이다.

ksymoops 커널 복구가 불가능 하거나 심각한 에러를 발견하면 커널은 그 상태를 커널 로그 파일에 출력한다. 이것은 레지스터 및 커널 스택의 내용, 디폴트 되는 동안 실행되는 함수의 자취와 같은 내용을 포함한다. 위와 같은 자료는 매우 유용하지만 머신이 읽어낼 수 있는 형식이며 개개의 머신 설정에 의존하는 어드레스이다. 따라서 무엇이 잘못되었는지 결정하고자 할 때 커널 로그 파일만으로는 쓸모가 없다. 이것이 ksymoops가 가져오는 곳이다. ksymoops는 머신이 읽을 수 있는 커널오류(kernel-oops)를 인간이 읽을 수 있는 텍스트로 전환시킨다. 그것은 커널 컴파일의 일부분으로써 생성되는 올바른 System.map 파일에 의존하며 적절할 경우 klogd가 정확하게 로드가능한 모듈을 처리하도록 해준다. ksymoops은 일반적으로 시스템 로그 생성자로부터 사용할 수 있는 Oops.file로써 'oops text'를 요구한다. 그 파일이 발견되지 않는다면 콘솔(필요하다면 손으로 직접 복사한 것)이나 dmesg로부터 실수를 찾아내야 한다. ksymoops 결과는 커널문제를 포함할 수도 있는 메시지 리스트이다. 가능한 위치일 경우 ksymoops은 문제발생시점에 있어 주소를 함수 이름으로 전환해준다.

>>EIP; c0113f8c <sys_init_module+49c/4d0> Trace; c011d3f5 <sys_mremap+295/370> Trace; c011af5f <do_generic_file_read+5bf/5f0> Trace; c011afe9 <file_read_actor+59/60> Trace; c011d2bc <sys_mremap+15c/370> Trace; c010e80f <do_sigaltstack+ff/1a0> Trace; c0107c39 <overflow+9/c> Trace; c0107b30 <tracesys+1c/23> Trace; 00001000 Before first symbol

man ksymoops은 매우 자세하게 라인을 설명하지만 대부분의 시스템 관리자에게 중요한 것은 문제가 발생한 함수 이름 리스트이다. 일단 핵심 함수와 그것을 호출한 함수를 알 수 있다면 커널 에러의 원인으로써 의심할 수 있다. ksymoops의 결과는 입력에 상응할 것임을 인지하라. 만약 System.map 파일이 잘못된 것이라면 로드가능한 모듈은 로드되어 들어오거나 나갈 때 보고하지 않을 것이다. 이때 vmlinux, ksyms, lsmod, object 파일들은 오류 발생 시점의 것들과는 다를 것이고 ksymoops는 잘못된 결과를 생성할 것이다. 가장 정확한 데이터를 얻고 싶다면 오류 발생 후 확실히 커널을 변경하기 전에 가능한 한 빨리 실행해야 한다.

gdb

만약 당신이 C에 익숙한 프로그래머라면 커널 자체를 디버그 하기 원할지도 모른다. 어디에 있는 커널에 문제가 있는지 결정하기 위해서 ksymoops 결과를 사용한 후 디버그 하고 잘못된 함수를 디어셈블하기 위한 gdb를 사용하라.

gdb /usr/src/linux/vmlinux gdb> disassemble offending_function

커널 문제 수정하기 당신은 수정해야 할 문제를 알고 있다. 드라이버와 로드가능한 모듈도 알고 있다. 그럼 이제 무엇을 해야 할까? 적당한 패치를 설치하고 드라이버가 올바른지 체크해라. 커널을 재컴파일하고 새로운 lilo 입구에 그것을 추가해라. 그리고 새로운 커널을 테스트 해라. 만약 문제를 수정하지 않았다면 리눅스 커널 리스트나 개발자에게 수정하지 못한 문제를 보내 보아라.

커널 문제 보고하기

만약 당신이 리눅스 커널 메일링 리스트나 개발자에게 버그를 보고한다면 "ISSUE: one line summary from [1.]"과 같은 제목으로 linux-kernel@vger.kernel.org에 관련 사항을 보내라.

  1. 한 줄로 간단히 문제 요약
  2. 문제나 보고 사항에 대한 전반적인 설명
  3. 키워드(예를 들면 모듈, 네트워킹, 커널)
  4. 커널 버전(/proc/version부터)
  5. 오류 결과 출력: ksymoops를 사용하여 추출해낸 상징적 정보를 가진 메시지
  6. 문제를 유발시키는 예제 프로그램이나 작은 셸 프로그램(가능할경우)
  7. 환경
  8. 소프트웨어($LINUXHOME/scripts/ver_linux에 있는ver_linux 스크립트 사용)
  9. 프로세서 정보(/proc/cpuinfo로부터)
  10. 모듈 정보(/proc/modules로부터)
  11. 스카시 정보(/proc/scsi/scsi로부터)
  12. 만약 있다면 시스템로그와 관련된 분야
  13. 커널 설정 파일과 심볼릭 맵
  14. 하드웨어 설명
  15. 문제가 있을 것 같은 정보(/proc를 보고 당신이 관계있다고 생각되는 모든 정보를 포함해라)
  16. 다른 중요점, 패치, 수정사항, 기타 등등

리눅스 커널의 FAQ에서는 만약 오류가 있는 머신이 오버클럭한 CPU를 사용하거나 VMware에서 vmmon을 운영하는 중이라면 오류 데이터가 쓸모없는 것이라고 공지한 것을 참고하기 바란다. 만약 위와 같은 문제를 가지고 있다면 문제를 수정하고 보고하기 전에 다시 한 번 테스트 하기 바란다. 일반적인 하드웨어 오류 만약 코드에 부정기적인 에러가 반복해서 나타난다면 CPU 팬에 이상이 있을 수 있다. 컴퓨터 하드웨어 장비에 대해 어느 정도 알고 있다면 CPU 팬이 작동되고 있는지 아닌지 소리를 들어볼 수 있을 것이다. 만약 소리가 들리지 않는다면 가장 간단하게 테스트 해보는 방법은 직접 열고 들여다 보는 것이다. 직접 보았을 때 CPU 팬이 돌아가고 있지 않다면 장비를 완전히 중지시킨 다음 팬을 교체해야 한다. 그렇게 하는 것이 CPU를 살리는 방법이기 때문이다.

CPU 팬이 돌아가고 있음에도 부정기적인 에러가 반복해서 나타난다면 RAM을 의심해봐라. 램을 테스트 하는 일반적인 방법에는 두 가지가 있다. 우선 첫째는 의심이 가는 램 스틱을 제거한 후 나머지 하나로 테스트 해보는 것이고 둘째는 커널을 계속해서 컴파일해보는 것이다. 이때 signal 11이라는 메시지가 보이면 램에 오류가 있는 것이다. 마지막으로 하드웨어 오류가 일어나는 일반적인 원인은 하드 드라이브의 블록이 잘못 지정되었기 때문이다. 이때 드라이브를 테스트하고 싶다면 badblocks 프로그램을 사용하라. 마지막 한마디 정전으로 인하여 머신이 다운되지만 않는다면 로컬 LUG에 컴퓨터 가동에 대한 기록을 얻을 수 있다. 그렇지만 정전에 관해서는 도움을 줄 수 없다.^^ 더 많은 정보를 얻기 위해서

  • man ksymoops
  • man dmesg
  • man syslogd
  • man klogd
  • man insmod
  • linux-kernel FAQ
  • $LINUXDIR/linux/Documentation/oops-tracing.txt
  • $LINUXDIR/linux/README
  • man gdb
  • info gdb

Trackback 0 Comment 1
  1. Favicon of https://blog.pages.kr 날으는물고기 2009.05.12 12:03 신고 address edit & del reply

    dmesg explained
    http://linuxgazette.net/issue59/nazario.html

2009.03.01 10:16

GDB를 사용한 CORE 파일의 분석

프로세스가 비정상적으로 종료될 경우, core 파일을 통하여 원인 분석을 할 수 있으며,

프로세스가 비정상적으로 종료될 경우, core 파일을 남길지 여부는 다음과 같은 명령어를 통해서
설정이 가능합니다.



 [step 1] 비정상 종료 되는 샘플 프로그램 작성

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

void Abnormal()
{
    int n = 1024;
    char *p = (char *)malloc(sizeof(char) * 1);

    free(p);
    free(p);                /* double free */
}

void AbnormalContainer()
{
    Abnormal();
}

void Normal()
{
    printf("normal function.\n");
}

int main(int argc, char **argv)
{
    AbnormalContainer();
    Normal();
    return 0;
}

 

[step 2] 비정상 종료되는 샘플 소스 컴파일

[root@linux temp]# gcc -o main main.c -g

※ 주 의 사 항

    gdb를 사용하여 core파일을 분석하기 위해서는 반드시 실행파일 컴파일시에 -g 옵션을 사용해야 합니다.

 

[step 3] 비정상 종료되는 샘플 실행

[root@linux temp]# ./main
*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000000601010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3cd3472832]
/lib64/libc.so.6(cfree+0x8c)[0x3cd3475f2c]
./main[0x400577]
./main[0x400587]
./main[0x4005b2]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3cd341e074]
./main[0x400499]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fd:00 47153195                           /root/temp/main
00600000-00601000 rw-p 00000000 fd:00 47153195                           /root/temp/main
00601000-00622000 rw-p 00601000 00:00 0                                  [heap]
3cd2200000-3cd221b000 r-xp 00000000 fd:00 61440048                       /lib64/ld-2.7.so
3cd241a000-3cd241b000 r--p 0001a000 fd:00 61440048                       /lib64/ld-2.7.so
3cd241b000-3cd241c000 rw-p 0001b000 fd:00 61440048                       /lib64/ld-2.7.so
3cd3400000-3cd354d000 r-xp 00000000 fd:00 61440050                       /lib64/libc-2.7.so
3cd354d000-3cd374d000 ---p 0014d000 fd:00 61440050                       /lib64/libc-2.7.so
3cd374d000-3cd3751000 r--p 0014d000 fd:00 61440050                       /lib64/libc-2.7.so
3cd3751000-3cd3752000 rw-p 00151000 fd:00 61440050                       /lib64/libc-2.7.so
3cd3752000-3cd3757000 rw-p 3cd3752000 00:00 0
3cddc00000-3cddc0d000 r-xp 00000000 fd:00 61440308                       /lib64/libgcc_s-4.1.2-20070925.so.1
3cddc0d000-3cdde0d000 ---p 0000d000 fd:00 61440308                       /lib64/libgcc_s-4.1.2-20070925.so.1
3cdde0d000-3cdde0e000 rw-p 0000d000 fd:00 61440308                       /lib64/libgcc_s-4.1.2-20070925.so.1
2aaaaaaab000-2aaaaaaad000 rw-p 2aaaaaaab000 00:00 0
2aaaaaacc000-2aaaaaacd000 rw-p 2aaaaaacc000 00:00 0
2aaaac000000-2aaaac021000 rw-p 2aaaac000000 00:00 0
2aaaac021000-2aaab0000000 ---p 2aaaac021000 00:00 0
7fffc8065000-7fffc807a000 rw-p 7ffffffea000 00:00 0                      [stack]
7fffc81fd000-7fffc81ff000 r-xp 7fffc81fd000 00:00 0                      [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

[root@linux temp]# ls -al
total 476
drwxr-xr-x  2 root root   4096 2008-08-06 09:05 ./
drwxr-xr-- 32 root root   4096 2008-08-06 09:04 ../
-rw-------  1 root root 454656 2008-08-06 09:05 core.2805
-rwxrwxr-x  1 root root   8935 2008-08-06 09:04 main*
-rw-r--r--  1 root root    260 2008-08-06 09:04 main.c

 

[step 4] gdb를 사용한 core 파일 분석

gdb를 사용하여 core파일을 분석하기 위해서는, 다음과 같이 gdb를 실행시키면 됩니다.

[root@linux temp]# gdb ./main ./core.2876
GNU gdb Red Hat Linux (6.6-45.fc8rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...
Using host libthread_db library "/lib64/libthread_db.so.1".

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib64/libc.so.6...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib64/libgcc_s.so.1...done.
Loaded symbols for /lib64/libgcc_s.so.1
Core was generated by `./main'.
Program terminated with signal 6, Aborted.
#0  0x0000003cd3430ec5 in raise () from /lib64/libc.so.6
(gdb) backtrace                      --> backtrace 명령어를 사용해서 죽기 직전까지 호출되었던 스택 정보 확인
#0  0x0000003cd3430ec5 in raise () from /lib64/libc.so.6
#1  0x0000003cd3432970 in abort () from /lib64/libc.so.6
#2  0x0000003cd346b0db in __libc_message () from /lib64/libc.so.6
#3  0x0000003cd3472832 in _int_free () from /lib64/libc.so.6
#4  0x0000003cd3475f2c in free () from /lib64/libc.so.6
#5  0x0000000000400577 in Abnormal () at main.c:10

#6  0x0000000000400587 in AbnormalContainer () at main.c:15
#7  0x00000000004005b2 in main (argc=1, argv=0x7fffc8077798) at main.c:25
Missing separate debuginfos, use: debuginfo-install gcc.x86_64 glibc.x86_64
(gdb) break Abnormal             --> 마지막으로 호출된 함수에 break point 설정
Breakpoint 1 at 0x400550: file main.c, line 6.
(gdb) r                                  --> 실행후 차례대로 디버깅
Starting program: /root/temp/main

Breakpoint 1, Abnormal () at main.c:6
6               int n = 1024;
(gdb) s
7               char *p = (char *)malloc(sizeof(char) * 1);
(gdb) s
9               free(p);
(gdb) s
10              free(p);                /* double free */
(gdb) s
*** glibc detected *** /root/temp/main: double free or corruption (fasttop): 0x0000000000601010 ***

출처 : http://blog.daum.net/aswip


Trackback 0 Comment 2
  1. Favicon of https://blog.pages.kr 날으는물고기 2009.03.01 10:17 신고 address edit & del reply

    GDB GNU Debugger Intro
    http://www.ffnn.nl/pages/articles/linux/gdb-gnu-debugger-intro.php

  2. Favicon of https://blog.pages.kr 날으는물고기 2009.03.01 10:17 신고 address edit & del reply

    GNU GDB Core Dump Debugging
    http://bloggerdigest.blogspot.com/2006/09/gnu-gdb-core-dump-debugging.html