본문 바로가기

Linux is..../My Skills

후잡한 실력으로 core debug을 넘보다. -.-b 후잡이니보지마삼

이번주 들어 부쩍 추워졌다.

벌써 겨울인가 싶을정도로....ㅠ이제부터 춥기시작하면 내년 3월 까지 추울텐데...쩝;;

차라리 더운게 낫기 쉽다...


아직 application core dump을 직접 분석해볼 기회가 없어 손놓고 있었는데 우연한 기회로 시도할수 있게되었다.

많이 미흡한 실력인지라 블로그에 올리기도 민망하지만...그래도 난 올려볼란다 심심하니깐ㅎ


고객이 보낸 파일이 정상적인지 비정상적인지도 판단할 실력이 아닌지라,

그냥 출력되는 내용만으로 유추해보고 싶어졌다.


환경 

RedHat Enterprise Linux 5 update 10
httpd-2.2.3-83

사건내역(?)은 이렇다. 사용도중 특정 웹서버 몇대만이 httpd log을 통해 세그먼트폴트를 출력한다는 내용이다.

OS messages에는 메시지가 뿌려지지 않기 때문에 오로지 http log로만 판단이 가능해졌다.

열어 보니 아래와 같이 무수한 pid을 남기면 에러메시지를 남긴다는 건데.....system call특성상 core dump만이 해결실마리로 남았다

먼저 segment란 무엇인가?네이년에도 자세하 설명되어 있겠지만 간략하게 서술한다면

프로그램이나 메모리의 부분. 프로그램의 경우는 주기억에 탑재하는 단위를 세그먼트라 한다. 메모리의 경우는 하나의 주소레지스터로 지정되는 메모리 영역을 가리킨다. IBM PC등에 사용되는 8086계 마이크로 프로세서에서는 주소레지스터가 16비트 폭 밖에 되지 않아서 16KB마다 세그먼트로 된다. IMB의 주기억 영역에 액세스하기 위해서는 세그먼트 레지스터라는 마이크로프로세서의 내부 레지스터 값을 바꾸면서 처리할 필요가 있다. 프로그램이 액세스하는 범위가 64바이트를 초과하는지의 여부에 따라 취급이 달라지므로 프로그래머를 괴롭혔던 8086계에서도 80286이후 마이크로프로세서는 메모리의 세그먼트를 의식하지 않아도 올바로 사용할 수 있게 되었다


문제식별
[notice] child pid 6244 exit signal Segmentation fault (11),


기본적으로 os에서 gdb(GNU Debugger)툴을 제공하기 때문에 그닥 어렵지 않다.

또한 분석함에 있어 보기보다 강력한 오픈소스툴이기에 전반적으로 좋다고 볼수 있겠다.

그럼 하나하나 명령어를 입력해가면 보기로 해보자.


[dhkim@redhat]# file core.18497
core.18497: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from 'httpd'

file명령어를 통해, 출처를 알수 있다. 웹서버(httpd)스리드에 의해 생성되었다는걸 확인이 가능해졌다.
자세한 내용은 man gdb명령어를 통해 알아가보자


[dhkim@redhat]# gdb /usr/sbin/httpd core.18497
[생략]
.
.
.
Core was generated by `/usr/sbin/httpd'.
Program terminated with signal 11, Segmentation fault.
#0  0x00302417 in apr_shm_baseaddr_get () from /usr/lib/libapr-1.so.0

(gdb) where
#0  0x00302417 in apr_shm_baseaddr_get () from /usr/lib/libapr-1.so.0

(gdb) bt
#0  0x00302417 in apr_shm_baseaddr_get () from /usr/lib/libapr-1.so.0
#1  0x00a6df26 in ap_run_child_init ()
#2  0x00a828d4 in ?? ()
#3  0x00a82ed1 in ?? ()
#4  0x00a82faa in ?? ()
#5  0x00a83b0b in ap_mpm_run ()
#6  0x00a59277 in main ()

(gdb) frame 0
#0  0x00302417 in apr_shm_baseaddr_get () from /usr/lib/libapr-1.so.0

(gdb) thread 1
[Switching to thread 1 (Thread 0xb7fa4a60 (LWP 18497))]#0  0x00302417 in apr_shm_baseaddr_get () from /usr/lib/libapr-1.so.0

파일이 정상적인지 그리고 해당 시스템에서 하는 작업이 아니다보니 전반적으로 source을 확인하기 위한 list등 명령어가 출력되지 않는다. 왜인거지?아놔....멍청한..

아무튼 위 내용을 보아 /usr/lib/libapr로부터, shared memory근접한 특정 함수호출함에 있어 비정상적인 인터럽터을 발생시켜, system call영향을 미칠꺼 같다는 생각이 들었다.


http://apr.apache.org/docs/apr/1.4/group__apr__shm.html#gade739e1f5f4e88c93256a63ebfd47d4d

위 thread메시지내용에 대해 확인중, 위 URL을 통해 간략하게 확인할수 있다.

Retrieve the base address of the shared memory segment. NOTE: This address is only usable within the callers address space, since this API does not guarantee that other attaching processes will maintain the same address mapping.


해결

결과론적으로 일반적인 업데이트쪽으로 가이드는 했으나,명확한 결과값으로 인한 가이드가 아니였기에 뭔가 뒤가 구린???생각이 든다...

역시 사람은 배워야 겠다...ㅠㅠ언제?



추가적으로, segfaults에 대해 detail하게 알아보던 중 mm이하 fault.c소스에 대해 알게되었다...redhat도 커널 소스를 공개해서 가끔 보긴하는데 뭔말인지ㅋㅋ 


아래와 같은 형태로 시스템로그에 남게되면, 하기와 같이 디테일하게 접근해보시길....그럼 재미날듯ㅎㅎ
(아는 분도 많겠지만 심심해서 적어봄)

만약 하기와 같은 예제를 발견했다치면,

segfault at 00000000ffffd2dc rip 00000000ffffd2dc rsp 00000000ffffd1bc error 15


1) rip 값은 instruction pointer register value, rsp 값은 stack pointer register value 이라고 보면 됨(여기서 instruction과 stack이 나눠지는게 복잡해지니 여기선 생략;;)
2) "segfault" error 는 오로지 x86_64커널시에만 로그를 떨군다. 고로 x86커널에는 해당안됨....(이유도 생략ㅋ)
3) 예제의 에러값은 특정 페이지faults code를 bit수를 바꾸어 연산처리한 값이라 보면 될꺼 같다(맞는지 모르겠지만, 해석할려니..말 디따 어렵군...)
4) cat /proc/PID/maps로 특정 PID의 maps를 제공하기 때문에 segfaults에러에 대한 실마리를 찾는데 도움된다고 볼수있다.(보면 머리깨짐)

[dhkim@redhat ~]$ cat /proc/2182/maps 
00101000-0020e000 r-xp 00000000 08:08 5247760 /lib/libglib-2.0.so.0.2600.0
0020e000-0020f000 rw-p 0010d000 08:08 5247760 /lib/libglib-2.0.so.0.2600.0
00348000-00391000 r-xp 00000000 08:08 5247777 /lib/libdbus-1.so.3.5.2
00391000-00392000 r--p 00048000 08:08 5247777 /lib/libdbus-1.so.3.5.2
00392000-00393000 rw-p 00049000 08:08 5247777 /lib/libdbus-1.so.3.5.2
00395000-004ac000 r-xp 00000000 08:08 5247770 /lib/libgio-2.0.so.0.2600.0
004ac000-004af000 rw-p 00117000 08:08 5247770 /lib/libgio-2.0.so.0.2600.0
004b8000-004de000 r-xp 00000000 08:08 5244146 /lib/libexpat.so.1.5.2
004de000-004e0000 rw-p 00025000 08:08 5244146 /lib/libexpat.so.1.5.2
00648000-0078f000 r-xp 00000000 08:08 298769 /usr/lib/libxml2.so.2.7.7
0078f000-00794000 rw-p 00146000 08:08 298769 /usr/lib/libxml2.so.2.7.7
00794000-00795000 rw-p 00000000 00:00 0 


* bit 0 == 0: no page found 1: protection fault
* bit 1 == 0: read access 1: write access
* bit 2 == 0: kernel-mode access 1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch

추가적인, 내용이야 많치만 추후 정리해서 나열할 생각이다.