본문 바로가기

컴퓨터 일반

코어 덤프 관리

Adam Zhang, 썬 마이크로시스템즈, 2007년 4월  

요약: 프로세스의 비정상적인 종료는 코어 덤프 파일을 생성하도록 합니다. 코어 덤프 파일은 프로그래머 혹은 서포트 엔지니어들에게 비정상적인 종료의 원인이 무엇인지 결정하는데 큰 도움을 줍니다. 왜냐하면 이 파일은 크래시 타임시의 런타임 상태에 대한 가치를 따질 수 없는 정보를 제공하기 때문입니다. 이 글은 코어 덤프에 대한 정보를 제공하고 솔라리스 운영체제에서 코어 덤프를 관리하는데 사용 될 수 있는 기능들과 분석툴들에 대해 설명합니다.

주의: 이 글에 포함된 정보는 주로 솔라리스10을 위한 것입니다.

순서:

  • 코어 덤프의 종류들: 프로세스와 시스템
  • 프로세스 코어 덤프의 원인
  • 프로세스 코어 덤프를 관리하는 방법
  • 프로세스 코어 덤프를 수동으로 생성하는 방법
  • 프로세스 코어 덤프 파일을 분석하는 방법
  • 시스템 코어 덤프의 원인
  • 시스템 코어 덤프가 생성되는 방법
  • 시스템 코어 덤프를 관리하는 방법
  • 시스템 코어 덤프를 수동으로 생성하는 방법
  • 시스템 코어 덤프 파일을 분석하는 방법
  • 참고자료
코어 덤프의 종류들: 프로세스와 시스템

코어 덤프는 파일로써 프로세스에 대한 내용과 더불어 프로세서 레지스터의 값 같은 다른 유용한 정보들이 같이 저장되어 있습니다. 두가지 종류의 코어 덤프가 존재 하는데: 시스템 코어 덤프와 프로세스 코어 덤프가 바로 그것입니다. 이것들은 여러가지 측면에서 특히 생성되는 방법과 이것들을 분석하는 방법에 있어서 큰 차이가 있습니다.

프로세스 코어 덤프의 원인

어플리케이션 프로세스가 특정한 시그널을 받고 종료 됐을때 시스템은 코어 덤프를 생성하고 프로세스를 정지 시킵니다. 대부분의 경우 어플리케이션을 크래쉬로 이끄는 시그널은 SIGSEGV 혹은 SIGBUS 입니다.

SIGSEGV 는 어플리케이션이 비정상적인 메모리 주소에 접근하고 있는 것을 가르킵니다. 이러한 상황은 C/C++ 프로그램에서 포인터 조작이 잘못됐을때 자주 발생합니다.

솔라리스에서 여러분은 libumem(3LIB) 라이브러리를 유저-모드 메모리 할당자로써 libc 대신 사용할 수 있습니다. libumem 라이브러리는 메모리 누출, 버퍼 오버플로우, 할당해제된 데이타에 대한 접근 시도, 그리고 수 많은 메모리 할당 에러들을 찾는데 도움을 줍니다. 또한 메모리 할당자로써 매우 빠르고 멀티쓰레드 어플리케이션에서 확장성이 뛰어 납니다.

SIGBUS 는 어플리케이션이 CPU 메모리 정렬 규칙을 따르지 않는 메모리 주소에 접근할때 발생합니다. 이것은 보통 UltraSPARC 프로세서에서 자주 발생합니다. x86/x64 CPU 의 시스템들은 정렬되지 않은 메모리 주소를 다룰 수 있지만 퍼포먼스의 문제가 발생합니다.

썬 스튜디오 C/C++ 컴파일러는 -xmemalign 옵션을 가지고 있어서 컴파일 타임에서 식별해 낼 수 있는 정렬되지 않은 메모리 주소들이 있을때 UltraSPARC CPU 에서의동작을 조정하는데 사용할 수 있습니다. -xmemalign 옵션은 컴파일러가정렬되지 않은 메모리의 접근에 대해 추가적인 load/store 명령을 생성하도록 합니다. 그러나 -xmemalign 옵션은 런타임시의 정렬되지 않은 메모리 접근을 다루지는 못합니다. 만약 정렬되지 않은 메모리에 대한 접근이 런타임시에 발생한다면 개발자는 소스 코드를 수정해야 한다.

기본적인 목적이 코어 덤프를 생성하는 다른 시그널들이 존재 합니다. 예를 들어 SIGFPE 는 부동 소숫점 예외를 가르 킵니다. Signal(3HEAD) 멘 페이지에서 좀 더 자세한 정보를 제공하고 있습니다.

프로세스 코어 덤프를 관리하는 방법

솔라리스는 3가지의 코어 덤프 파일을 각각의 비정상적으로 종료된 프로세스마다 생성하려고 시도 합니다. 코어 덤프 파일중에 하나는 프로세스별(per-process) 코어 파일로 불리고 현재 디렉토리에 위치하게 됩니다. 다른 코어 덤프 파일은 글로벌 코어 파일로 불리고 시스템 전역의 장소에 생성됩니다. 만약 프로세스가 로컬 존에서 실행되고 있다면 3번째 코어 파일은 글로벌 존에 생성 됩니다.

여러분은 coreadm(1M) 커맨드를 이용해서 코어 덤프 파일을 관리할 수 있습니다. 모든 설정은 /etc/coreadm.conf 설정 파일에 저장됩니다.

아래는 전형적인 시나리오로 코어 덤프에 대한 현재 시스템의 설정을 보여 줍니다:

-bash-3.00# coreadm
     global core file pattern:
     global core file content: default
       init core file pattern: core
       init core file content: default
            global core dumps: disabled
       per-process core dumps: enabled
      global setid core dumps: disabled
 per-process setid core dumps: disabled
     global core dump logging: disabled

이전의 출력에서:

  • global core dumps: disabled 는 어떠한 글로벌 코어 덤프도 생성되지 않을 것임을 가르킴.
  • per-process core dumps: enabled 는 프로세스별 코어 덤프가 각각의 비정상적인 프로세스마다 생성될 것임을 가르킴.
  • init core file pattern 는 내용이 살아 있는 프로세스 부터 프로세스-별 코어 덤프까지의 정보를 모두 취합할 것임을 가르킴.

또한 coreadm 커맨드를 통해서 코어 덤프 파일 이름을 조정할 수 있습니다:

-bash-3.00# coreadm -i core.%f.%p

이 커맨드는 프로세스-별 코어 파일 이름에 프로그램 파일 이름 (%f) 과 런타임 프로세스 ID (%p) 를 추가시킨 것입니다. 코어 덤프 파일은 프로세스의 현재 작업 디렉토리에 생성될 것입니다.

-bash-3.00# coreadm -g /globalcore/core.%f.%p -e global

기본적으로 글로벌 코어 덤프는 비활성화 되어 있습니다. 여러분은 coreadm 커맨드를 -e global 옵션을 주고 실행해서 활성화 시킬 수 있습니다. -g 옵션은 프로그램 이름 (%f) 과 런타임 프로세스 ID (%p) 를 코어 파일 이름에 추가시키도록 할 수 있습니다.

이전에 언급했던 대로 coreadm 은 코어 파일에 저장될 프로세스의 부분을 지정할 수 있습니다. 이전에서 만약 사후 분석을 수행한다고 했을때 여러분은 의존 라이브러리들과 런타임 모듈들의 모든 버전 정보들을 얻을 필요가 있을 것입니다. 왜냐하면 코어 덤프 파일은 이러한 정보를 포함하고 있지 않기 때문입니다. 프로그래머가 본래 머신의 환경과 똑같은 환경을 재생성하는 것은 매우 어려운 일입니다.

기본적인 설정으로 솔라리스는 "기본" 패턴을 각각의 프로세스 코어 덤프에 적용하는데 이 것은 즉 프로세스 코어 덤프가 스택, 힙, 텍스트, 공유 메모리(SHM), intimate 공유 메모리(ISM), 그리고 동적인 intimate 공유 메모리(DISM) 정보와 다른 정보들을 모두 포함하게 됩니다. 프로세스 코어 덤프 파일의 텍스트 부분은 또한 어떠한 의존 라이브러리들도 없이 코어 파일로 부터 직접 읽기가 가능한 스택 트레이스를 얻을 수 있도록 도와 주는 부분적인 심볼 테이블(dynsm)을 포함 합니다. 만약 dynsm 이 불충분하다면 coreadm 을 이용해서 모든 심볼 테이블을 포함하도록 할 수 있습니다:

-bash-3.00# coreadm -G all -i all

이전의 커맨드는 글로벌 코어 파일 (-G) 과 프로세스-별 코어 파일 (-i) 이 프로세스의 모든 부분을 포함하도록 합니다.

coreadm 을 이용해서 변경이 올바르게 되어 있는지 확인합니다:

-bash-3.00# coreadm
     global core file pattern: /globalcore/core.%f.%p
     global core file content: all
       init core file pattern: core.%f.%p
       init core file content: all
            global core dumps: enabled
       per-process core dumps: enabled
      global setid core dumps: disabled
 per-process setid core dumps: disabled
     global core dump logging: disabled

coreadm 커맨드는 coreadm 서비스의 설정 파일을 수정하는데 사용되고 이것은 서비스 관리 설비(SMF) 에서 다음과 같은 서비스 인식자를 가집니다: svc:/system/coreadm:default.

프로세스 코어 덤프를 수동으로 생성하는 방법

솔라리스는 분석의 목적을 위해서 현재 실행되고 있는 라이브 프로세스의 코어 덤프를 생성할 필요가 있을때를 위해서 gcore(1) 커맨드를 제공합니다:

-bash-3.00# echo $$
2770
-bash-3.00# gcore $$
gcore: core.2770 dumped

라이브 프로세스 ID가 생성되는 코어 덤프 파일에 자동적으로 추가 됩니다. 이전의 예제에서 현재 쉘의 프로세스가 덤프 됐고 프로세스 ID 는 2770 입니다.

주의: 코어 덤프를 생성할때 고려해야할 몇가지 제약 조건들이 있습니다. 예를 들어 목적 디렉토리의 퍼미션, 목적 디렉토리의 존재 여부, 파일 시스템의 마운트 옵션, 그리고 프로세스의 리소스 제한 등 입니다. 리소스 제한에 대한 정보는 setrlimit(2) 과 ulimit(1) 을 참고하시기 바랍니다.

프로세스 코어 덤프 파일을 분석하는 방법

솔라리스에는 코어 덤프 파일을 분석하는 수 많은 툴들이 존재 합니다: dbx(1), mdb(1), 그리고 pstack(1). 가장 편리한 방법은 pstack 툴을 이용해서 프로세스의 스택을 검사하는 것입니다. 이 툴은 멀티쓰레드 프로그램의 정보 또한 보여 줍니다:

 -bash-3.00# pstack core.2580  | more
 core 'core.2580' of 2580:       java_vm
 -----------------  lwp# 1 / thread# 1  --------------------
  fef40a27 read     (b, 804280c, 1)
  feb11ba8 __1cDhpiEread6FipvI_I_ (b, 804280c, 1) + a8
  feb11aef JVM_Read (b, 804280c, 1) + 2f
  fe77045e ???????? (80685b8, 8042864, 22)
  ...
  feb1d55c jni_CallStaticVoidMethod (80685b8, 8069020, 80e8355,
0) + 14c
  080516c2 main     (2, 8047168, 8047174) + 50c
  08050daa ???????? (2, 80472cc, 80472d4, 0, 80472d5, 8047301)
 -----------------  lwp# 2 / thread# 2  --------------------
  fef40d27 lwp_cond_wait (8067ae8, 8067ad0, fb3a9c08, 0)
  fef2de3f _lwp_cond_timedwait (8067ae8, 8067ad0, fb3a9c50) + 35
 ...
  fef3fc32 _thr_setup (fef82400) + 4e
  fef3ff20 _lwp_start (fef82400, 0, 0, fb3a9ff8, fef3ff20,
fef82400)
 -----------------  lwp# 3 / thread# 3  --------------------
  fef40d27 lwp_cond_wait (8116588, 8116570, 0, 0)
  feab737c __1cCosHSolarisFEventEpark6M_v_ (8116548) + 4c
 ...

일반적으로 프로그램의 심볼 테이플이 strip 되지 않았고 런타임 스택 트레이스가 사용 가능하다면 여러분은 문제의 50 퍼센트 이상이 해결되었다고 생각해도 됩니다.

dbx 는 썬 스튜디오 소프트웨어의 의해 무료로 제공 되는 소스-레벨 디버깅 툴입니다. 썬 스튜디오 소프트웨어는 솔라리스와 리눅스에서 무료로 사용할 수 있는 최적화된 C, C++, Fortran 컴파일러를 포함하고 있습니다. dbx 는 프로그램의 상태를 조사할 뿐만 아니라 프로그램의 퍼포먼스 데이타 또한 수집합니다. 아래에 코어 파일을 dbx 를 이용해서 분석하는 전형적인 시나리오가 있습니다. dbx 에 대한 좀 더 자세한 정보는 Sun Studio 11: Debugging a Program With dbx 문서를 참고하시기 바랍니다.

  -bash-3.00# /opt/SUNWspro/bin/dbx   tServer   core
  For information about new features see 'help changes'
  To remove this message, put 'dbxenv suppress_startup_message 7.5'
in your .dbxrc
  Reading tServer
  core file header read successfully
  Reading ld.so.1
  Reading libpthread.so.1
  Reading librt.so.1
  Reading libsocket.so.1
  Reading libnsl.so.1
  Reading libc.so.1
  Reading libthread.so.1
  Reading libCrun.so.1
  Reading libm.so.1
  Reading libkstat.so.1
  t@1 (l@1) program terminated by signal SEGV (no mapping at
the fault address)
  0xffffffff7ce3ce90: strcmp+0x0014:      ldub     [%i1], %i5
  Current function is txnAtomMatchRqst
    177  && strcmp(pMsg->inHeader.msgVer, "01" == 0)) {
  (dbx) threads                    ** show all the threads
  o>    t@1  a  l@1   ?()   signal SIGSEGV in  strcmp()
     t@2  b  l@2   tTimerThread()   LWP suspended in  __pollsys()
  (dbx) thread -info t@1           ** show the thread information

    Thread t@1 (0xffffffff7a500000) at priority 0
    state: active on    l@1
    base function: 0x0: 0x0000000000000000() stack:
0xffffffff80000000[8388608]
    flags: (none)
    masked signals: (none)
    Currently active in strcmp
  (dbx) where                      ** show the thread stack
  current thread: t@1
   [1] strcmp(0x100263d63, 0x0, 0xac, 0x0, 0x30, 0x31), at
0xffffffff7ce3ce90
  =>[2] tAtomMatchRqst(), line 177 in "tAtomMatchRqst.c"
   [3] tFlow(), line 96 in "tFlow.c"
   [4] tServer(rqst = 0x1001e6c58), line 73 in "tServer.c"
   [5] _tsvcdsp(0x1700, 0x0, 0x10004ca60, 0x1001e55c0, 0x0,
0x1001d9440), at 0xffffffff7e15d138
   [6] _trunserver(0x1001e3844, 0x1001da958, 0x0,
0xffffffff7e3525c8, 0x1400, 0x1001ee400), at 0xffffffff7e180ea0
   [7] _tstartserver(0x0, 0xffffffff7ffff568, 0x1001bcc38,
0x1001d9440, 0x0, 0x0), at 0xffffffff7e15be28
   [8] main(0xf, 0xffffffff7ffff568, 0xffffffff7ffff5e8, 0x0,
0x0, 0x100000000), at 0x1000099ec
  (dbx) quit
  -bash-3.00#

이전의 예제에서 여러분은 dbx 를 사용해서 비정상적인 쓰레드를 "o," 마크를 통해서 확인 할 수 있고 소스 코드를 보여 줌으로써 근본 원인을 알아낼 수가 있었습니다. 물론 이것은 여러분의 어플리케이션 소스 코드와 컴파일 단계에서 디버그 정보 추가를 하지 않았다면 불가능했을 것입니다.

여러분이 어셈블리 언어, 하드웨어 특성과 친숙하다면 mdb 를 사용해서 코어 파일을 디버그 할 수 있습니다. 왜냐하면 mdb 는 저-레벨 디버깅 유틸리티로 솔라리스 OS 자체와 프로그램을 양쪽에서 모두 쓸 수 있습니다.

시스템 코어 덤프의 원인

솔라리스가 크래쉬되고 코어 덤프를 생성하는 데에는 수 많은 이유들이 존재 합니다. 소프트웨어 적인 문제 즉 드라이버나 프로그램 뿐만 아니라 하드웨어 오류 자체도 시스템의 코어 덤프를 유발할 수 있습니다.

시스템 코어 덤프가 생성되는 방법

데이타 무결성이 훼손됐거나 하드웨어에서 오류가 발생한 것을 감지 한다면 솔라리스는 panic() 을 호출합니다. panic() 루틴은 마치 OS 가 정지한 것처럼 모든 프로세스들을 인터럽트 합니다. 이때 메모리 상의 OS 를 그대로 복사한 시스템 코어 덤프를 생성하고 이것을 덤프 디바이스에 저장 합니다. 크래쉬 후에 운영체제는 savecore(1) 를 통해서 덤프 디바이스로 부터 코어 덤프를 savecore 디렉토리로 다음 번 부팅 동안 가져 옵니다. savecore 루틴은 두가지 파일을 생성합니다. 하나는 unix.<X> 로 OS 심볼 테이블 이고 다른 하나는 vmcore.<X> 로 코어 덤프 데이타 파일 입니다. 기본적으로 덤프 디바이스는 swap 파티션이고 savcore 디렉토리는 /var/crash/<hostname> 으로 설정되어 있습니다. 파일이름 끝에 붙는 <X> 는 정수로 savecore 가 매번 돌때 마다 증가합니다.

시스템 코어 덤프를 관리하는 방법

여러분은 dumpadm(1M) 을 사용해서 덤프 디바이스와 savecore 디렉토리를 관리할 수 있습니다:

-bash-3.00# dumpadm -d /dump  -s /savecore
      Dump content: kernel pages
      Dump device: /dump (dedicated)
Savecore directory: /savecore
Savecore enabled: yes

변경 사항을 점검하거나 현재의 설정을 보기 위해 아무런 옵션 없이 dumpadm 만을 사용합니다:

-bash-3.00# dumpadm
      Dump content: kernel pages
      Dump device: /dump (dedicated)
Savecore directory: /savecore
Savecore enabled: yes

여러분은 dumpadm 을 이용해서 덤프의 내용을 설정할 수 있고 savecore(1) 작업을 부트시간 동안에 활성화 할 수 있습니다. operation during the boot.

모든 설정 정보들은 /etc/dumpadm.conf 설정 파일에 저장 됩니다. 시스템 크래쉬 덤프 서비스는 또한 SMF 로 관리되고 서비스 인식자는 다음과 같습니다: svc:/system/dumpadm:default.

시스템 코어 덤프를 수동으로 생성하는 방법

어떤 경우에 여러분은 코어 덤프 파일을 수동으로 저장해서 현재 라이브 시스템의 스냅샷을 취할 필요가 있습니다. 솔라리스에서 사용할 수 있는 여러가지 방법들이 있습니다. 예를 들어 reboot -d 를 이용해서 재부팅과 동시에 코어 덤프의 생성을 강제할 수 있습니다. 혹은 savecore -L 을 이용해서 라이브 OS 코어 덤프를 생성할 수 있습니다. 만약 savecore(1M) 를 이용해서 라이브 코어 덤프를 생성하길 원한다면 여러분은 반드시 dumpadm 을 사용하여 non-swap 디바이스를 덤프 디바이스로 설정해줘야 합니다. 왜냐하면 라이브 코어 덤프는 swap 디바이스를 가상 메모리의 일부로 사용하기 때문입니다.

종종 시스템은 크래쉬 없이 멈출 경우가 있습니다. 만약 썬 UltraSPARC 프로세서 기반의 머신을 사용한다면 Stop-A 를 눌러서 OpenBoot PROM (OBP) 모드로 들어갈 수 있고 sync OBP 커맨드를 통해서 크래쉬 코어 덤프를 강제로 생성해 줄 수 있습니다.

x86 플랫폼에서는 해당되는 OBP 유닛이 없습니다. 그러나 kmdb(1M) 를 사용할 수 있습니다. kmdb 를 사용해서 코어 덤프를 생성하려면 시스템 부팅시에 모듈을 로딩해와야 합니다.

솔라리스10 1/06 혹은 그이후의 버전에서의 단계입니다.

  1. /boot/grub/menu.lst 파일을 편집해서 -k string 을 initrd 줄에 아래처럼 추가 시킨다:
    title Solaris 10 11/06 s10x_u3wos_10 X86
    root (hd0,1,a)
    kernel /platform/i86pc/multiboot -k
    module /platform/i86pc/boot_archive
    

    이것은 OS 가 kmdb 와 함께 부팅되도록 한다.

  2. 머신을 수동으로 재시작 시킨다.

이 방법 대신 솔라리스10 GA 버전에서는 시스템 부팅 스테이지에서 Select (B)oot or (I)nterpreter: 메세지가 보일 때 b -k 를 입력할 수도 있습니다.

이러한 단계들을 수행한 후에는 F1-A 눌러서 시스템을 kmdb 로 들어가도록 합니다. 이 동작은 반드시 콘솔 모드에서 수행되어야 합니다. 왜냐하면 kmdb 는 시스템 과 GUI 어플리케이션을 일시 정지시키기 때문입니다. 만약 데스크탑 시스템을 사용한다면 솔라리스는 콘솔 모드의 전환이 실패할 것이고 데스크탑이 멈추게 될 것입니다. 그러나 kmdb 는 실행중이고 여러분은 여전히 커맨드를 입력할 수 있습니다.

$<systemdump

systemdump 커맨드는 코어 덤프 파일을 생성합니다. 덤프 디바이스와 savecore 디렉토리는 여전히 dumpadm 의 영향을 받습니다.

종종 시스템이 kmdb 혹은 OBP 를 사용하더라도 아무런 응답없이 정지하는 경우가 있습니다. 이러한 경우에는 "deadman timer." 를 사용 합니다. deadman timer 는 OS가 시스템 정지시에 커널 panic 을 강제하도록 허락 합니다. 이 기능은 x86 과 SPARC 시스템에서 사용 가능합니다. 다음의 라인을 /etc/system 에 추가하고 재부팅하여 deadman timer 가 활성화 되도록 합니다.

set snooping=1

활성화된 deadman timer 는 1초에 한번씩 레벨 15 인터럽트를 발생시킵니다. 이것은 커널 lbolt 변수가 업데이트 됐는지 확인할 것입니다. 만약 deadman timer 가 특정 시간동안 lbolt 변수가 증가되지 않았음을 감지 한다면(기본은 50초) panic 을 유발 시킵니다. 시간 간격은 /etc/system 에서 설정 가능합니다. 다음의 예는 deadman timer 가 120초 동안 lbolt 변수의 업데이트를 기다립니다:

set snoop_interval=120000000

시스템 코어 덤프 파일을 분석하는 방법

이 글에서는 시스템 코어 덤프 파일을 수정하는 방법에 대한 해결책을 제시할 수 없습니다. 왜냐하면 이러한 분석은 OS 커널과 하드뒈어에 대한 매우 저-수준의 컴퓨팅 지식을 요구하기 때문입니다. 아래에는 여러분의 참고를 위해 몇가지 기본적인 가이드라인을 제시해 드립니다:

  1. 시스템 콘솔과 /var/adm/messages 파일을 확인한다. 왜냐하면 이것들이 시스템이 처한 문제점들을 발견하는데에 필요한 정보들을 포함하고 있기 때문이다.
  2. strings(1) 커맨드를 이용해서 코어 덤프 파일을 처리한다. 이 커맨드는 어떠한 바이너리 파일도 ASCII 문자열로 출력해 준다. 여러분은 이러한 ASCII 문자열들을 볼 필요가 있다.
  3. 여러분이 겪은 에러들을 SunSolve web site 사이트에서 찾아보거나 Solaris Crash Analysis Tool (CAT) 을 이용한다.
참고자료