2009년 11월 26일 목요일

솔라리스 64비트 바이너리 코어 분석

1. 서론

리눅스와 솔라리스에서 개발할 때 가장 큰 차이는 개발 환경인 듯하다.
리눅스는 설치하면 gcc, gdb 같이 개발에 필요한 대부분의 것이 갖추어져 있다.
솔라리스의 경우 http://www.sunfreeware.com/에서 필요한 툴은 다운 받아 직접 설치해야 한다. 의존성 문제나 기타 여러가지 이유로 해서 상당히 귀찮다. 그리고 가장 큰 문제는 64비트용 gdb가 제공되지 않는다는 것이다.

이 글에서는 Sun Studio의 dbx를 이용한 디버깅 방법을 소개하겠다.

2. 버그 실행 파일 생성

먼저 버그를 내포한 실행 파일을 생성해 보겠다.

# vi test.c

#include

int main(void)
{
printf("test %s\n", 1);
return 1;
}

왜 코어가 발생하는지 설명하지는 않겠다.

아래와 같이 컴파일 한다. 반드시 64비트로 컴파일 한다.
# gcc -m64 -o test test.c

이제 바이너리를 실행하고 코어를 생성해 본다.

# ./test
# ls -al
drwx------ 2 hk9 staff 512 11월 27일 10:18 .
drwxr-xr-x 43 hk9 staff 1536 11월 27일 10:16 ..
-rw------- 1 hk9 staff 1661108 11월 27일 10:18 core
-rwx------ 1 hk9 staff 8168 11월 27일 10:17 test
-rw------- 1 hk9 staff 75 11월 27일 10:16 test.c

3. 코어 분석

- pstack 사용

기본적으로 pstack을 이용해 분석하고, gdb를 이용하는게 일반적이다.

# pstack core
core 'core' of 8496: ./test
ffffffff7f2371b8 strlen (10000090f, ffffffff7ffff898, ffffffff7f29dbf0, ffffffff7fffefe9, 1, 10000090e) + 18
ffffffff7f2a1b94 printf (100000908, 2000, ffffffff7f3ea224, ffffffff7f3ea228, ffffffff7f3e0000, 4) + e4
0000000100000854 main (1, ffffffff7ffff988, ffffffff7ffff998, 100100d60, 100000000, ffffffff7f400100) + 20
00000001000006e4 _start (0, 0, 0, 0, 0, 0) + 7c

printf 함수에서 스트링 출력을 위해 strlen 함수를 호출하다가 코어가 발생했음을 알 수 있다.

- gdb 사용

이제 gdb를 사용해 보자. 근데 뭔가 이상하다.

# gdb test core
GNU gdb 6.6
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 "sparc-sun-solaris2.10"...
(no debugging symbols found)
Reading symbols from /usr/lib/sparcv9/libc.so.1...(no debugging symbols found)...done.

warning: sol_thread_new_objfile: td_ta_new: Debugger service failed
Loaded symbols for /usr/lib/sparcv9/libc.so.1
Reading symbols from /platform/SUNW,Sun-Fire-V440/lib/sparcv9/libc_psr.so.1...(no debugging symbols found)...done.

warning: sol_thread_new_objfile: td_ta_new: Debugger service failed
Loaded symbols for /platform/SUNW,Sun-Fire-V440/lib/sparcv9/libc_psr.so.1
Reading symbols from /lib/sparcv9/ld.so.1...(no debugging symbols found)...done.

warning: sol_thread_new_objfile: td_ta_new: Debugger service failed
Loaded symbols for /lib/sparcv9/ld.so.1

warning: Couldn't find general-purpose registers in core file.

warning: Wrong size fpregset in core file.

warning: Couldn't find general-purpose registers in core file.

warning: Wrong size fpregset in core file.
#0 0x0000000000000000 in ??
()
(gdb) where
#0 0x0000000000000000 in ?? ()
(gdb)

http://www.sunfreeware.com/에서 배포하는 gdb는 32비트용으로 64를 지원하지 않는다. 그래서 엉뚱한 결과를 얻게 된다. 물론 64비트로 gdb를 컴파일 해서 사용할 수도 있지만, 생각처럼 간단한 작업은 아닌 듯하다. 몇 번 시도해봤지만 번번히 실패했다.

- dbx 사용

dbx는 썬 스튜디오에서 제공하는 소스-레벨 디버깅 툴이다. 자세한 사항은 링크를 참조한다..
기본적으로 사용 법은 gdb와 비슷하다. where 명령으로 어디에서 코어가 발생했는지 확인해 보자.

# dbx test core
For information about new features see `help changes'
To remove this message, put `dbxenv suppress_startup_message 7.6' in your .dbxrc
Reading test
core file header read successfully
Reading ld.so.1
Reading libc.so.1
Reading libc_psr.so.1
program terminated by signal SEGV (no mapping at the fault address)
0xffffffff7f2371b8: strlen+0x0018: ldub [%o2], %o1
(dbx) where
=>[1] strlen(0x1, 0x53, 0x1, 0x0, 0x1, 0x53), at 0xffffffff7f2371b8
[2] _ndoprnt(0x10000090f, 0xffffffff7ffff898, 0xffffffff7f29dbf0, 0xffffffff7fffefe9, 0x1, 0x10000090e), at 0xffffffff7f29f960
[3] printf(0x100000908, 0x2000, 0xffffffff7f3ea224, 0xffffffff7f3ea228, 0xffffffff7f3e0000, 0x4), at 0xffffffff7f2a1b94
[4] main(0x1, 0xffffffff7ffff988, 0xffffffff7ffff998, 0x100100d60, 0x100000000, 0xffffffff7f400100), at 0x100000854
(dbx) quit

gdb를 사용했을 경우와 비슷한 결과를 얻을 수 있다.

한가지 더 재미있는 것은 Sun Studio에 내장된 cc 컴파일러로 컴파일 했을 경우
아래와 같이 보다 정확한 디버깅 정보가 표시된다. 역시 Sun 플랫폼에서는 cc 컴파일러를 써야 하는 것 같다.

# cc -g -m64 test.c -o test
# dbx test core
For information about new features see `help changes'
To remove this message, put `dbxenv suppress_startup_message 7.7' in your .dbxrc
Reading test
core file header read successfully
Reading ld.so.1
Reading libc.so.1
Reading libc_psr.so.1
program terminated by signal SEGV (no mapping at the fault address)
0xffffffff7f2371b8: strlen+0x0018: ldub [%o2], %o1
Current function is main
5 printf("test %s\n", 1);
(dbx) where
[1] strlen(0x1, 0x53, 0x1, 0x0, 0x1, 0x53), at 0xffffffff7f2371b8
[2] _ndoprnt(0x1000008bf, 0xffffffff7ffff248, 0xffffffff7f29dbf0, 0xffffffff7fffe999, 0x1, 0x1000008be), at 0xffffffff7f29f960
[3] printf(0x1000008b8, 0x2000, 0xffffffff7f3ea224, 0xffffffff7f3ea228, 0xffffffff7f3e0000, 0x4), at 0xffffffff7f2a1b94
=>[4] main(), line 5 in "test.c"
(dbx) quit

자세한 사용법은 Sun Studio 11: Debugging a Program With dbx
문서를 참고하기 바란다.

4. 마치며

솔라리스 64비트 환경에서는 기본적으로 Sun studio 에서 제공하는 개발환경을 이용하는 것이 가장 현명할 것 같다. 컴파일러만 제공하는 것이 아니라 MS의 Visual Studio처럼 통합 개발환경을 제공하기 때문이다. 하지만 나와 같이 gcc에 길들여진 개발자가 64비트 환경에서 개발할 때 gdb 대신에 dbx를 사용하는 것만으로도 개발에 큰 도움이 되지 않을까 싶다.

댓글 없음:

댓글 쓰기