2012년 4월 8일 일요일

solaris: 오브젝트 덤프를 이용하여 커널 패닉 분석하기

가정

1.  커널 패닉이 발생하여 덤프 파일이 생성되어 있다
2.  커널 패닉이 발생한 위치가 자신이 빌드한 소스에서 발생하였다

위 두가지 가정하에서 커널 패닉이 유발 시킨 자신의 '코드의 위치'를 찾는 방법에 대하여 소개한다.

커널 덤프 확인

디폴트로 설치된 솔라리스 시스템에서 커널 패닉이 발생하면 덤프 파일이 생성되게 된다.
보통 /var/adm/messege 로그를 보면 최근 발생한 패닉의 정보를 확인 할 수 있는데, messege 파일이
생성되지 않는 경우에서 덤프 파일을 이용하여 패닉 정보를 확인하여야 한다.

덤프 파일이 생성되는 위치는 /var/crash/노드이름/ 하위에 생성되는데, 덤프 파일 이름은 unix.#, vmcore.# 이다.
덤프 파일을 확인 하기 위해서는 adb를 사용하면된다.


shell> adb -k unix.0 vmcore.0

physemem 
5b01

0x40027 .....

$<msgbuf     <== 타이핑 후 
엔터

......

0x300014f5b23:  000002a1007a3b50 unix:die+a4 (31, 2a1007a3e20, 
7374616c6c2f636f, 0, ffffffffffffffff, 3720e)

0x300014f5623:    %l0-3: 
0000000000000000 7374616c6c2f636f 000002a1007a3e20 000002a1007a3d18

%l4-7: 
0000000000000031 0000000000002000 0000000000000000 
0000000000000000

0x300014f5123:  000002a1007a3c30 unix:trap+874 (2a1007a3e20, 
0, 10000, 10200, 7374616c, 2a1007a4024)

0x300014f4c23:    %l0-3: 
0000000000000001 0000000000000000 00000300066a4a88 0000000000000031

%l4-7: 
0000000000000005 0000000000000001 0000000000000000 
0000000000000000

0x300014f4723:  000002a1007a3d70 unix:ktl0+48 (0, 2, 
ffffffffffffffff, 0, 81010100, ff00)

0x3000154dde3:    %l0-3: 
0000000000000007 0000000000001400 0000000080001606 000000000102ce88

%l4-7: 
000003000000b5b0 000000000144e280 0000000000000000 
000002a1007a3e20

0x3000168ce63:  000002a1007a3ec0 test_ke:putMemUse+120 (6d, 
2, 3000905bb10, 780ea000, 10, 7374616c6c2f636f)   <=== 여기에서 뭔가 잘못된거 같은 
느낌...

0x3000168d363:    %l0-3: 0000000000078000 000000000000000f 
00000300062f9380 000003000000b408

%l4-7: 0000030009323e48 0000000000000000 
0000030009323e57 0000000078217d98

0x3000154c123:  000002a1007a3f70 
test_ke:retryMalloc+140 (300062f9380, 2, 13aa2d0, 1000, e, 
10)

0x3000168dd63:    %l0-3: 0000000000000000 0000000000000000 
000000000000000f 0000030009323e58

%l4-7: 00000000013ad758 0000000000000020 
00000000013ad000 00000000000013ad

0x3000168d5e3:  000002a1007a4040 
test_ke:getPathForSymlink+818 (2a1007a52d0, 1, 2a1007a56e0, 2, 2a1007a5ae0, 
1)

0x30000438ae3:    %l0-3: 0000000000000026 0000000000001395 
000003000905bae8 00000000013aa300

%l4-7: 0000000000000026 0000000000000000 
0000000000000025 000002a1007a49c1

0x30000438ea3:  000002a1007a4dc0 
test_ke:hooked_link_sys32+2d0 (13a05c0, ffbfe78c, 13a0, 13a0000, 0, 
300092b61c8)

0x30000439263:    %l0-3: 00000000013a01c0 00000000780ea388 
0000000000000000 0000000000000000

%l4-7: fffffffffffffffc fffffffffffffffc 
000002a1007a4e90 000002a1007a4ed4

0x30000439620:

0x300004399e3:  syncing 
file systems...

0x30000439da3:   2

0x3000043e1e3:   1

0x3000043e5a3:   
done

0x3000043e963:  dumping to /dev/dsk/c1t0d0s1, offset 1718288384, 
content: kernel

위와 같이 패닉 위치를 확인 할 수 있다.



오브젝트 덤프 생성 하기

커널 패닉 위치 감은 잡았지만 적확히 소스의 위치를 확인 하기위해서는 오브젝트 덤프를 생성하여야 한다.
위 패닉 정보에서
'0x3000168ce63: 000002a1007a3ec0 mdp_ke:putMemUse+120 (6d, 2, 3000905bb10, 780ea000, 10, 7374616c6c2f636f)'
패닉의 원인으로 가장 유력해 보이지만 소스의 어느 위치인지 모른다.
솔라리스에서 오브젝트 덤프를 생성하기 위해서는 -fast -xcg92 -S 옵션을 주고 오브젝트 파일을 생성하지 않으면 .s파일이
생성 된다.


shell> cc  -D_SOL9_ -D_KERNEL -DSVR4 -DSOL2 -DDEBUG 
-D_SYSCALL32 -D_SYSCALL32_IMPL -DSOLARIS_SPARC -m64  -xO5 -xregs=no%appl -v 
-fast -xcg92 -S  -c module_memchk.c



shell> vi 
module_memchk.s



2513 !  338            !int putMemUse(const char 
*pr_fname, long pr_size, char pr_type)

2514 
!  339            !{

2515

2516 !

2517 ! SUBROUTINE putMemUse

2518 
!

2519 ! OFFSET    SOURCE LINE LABEL   
INSTRUCTION

2520

2521                         .global 
putMemUse

2522

2523

2524             putMemUse:

2525 /* 
000000    339 */     save    %sp,-96,%sp

2526

2527 
!  340            !  MEMCHKLIST  *find_member = NULL;

2528 
!  341            !  int         rtv = 0;

2529 
!  342            !  char        *func  = NULL;

2530 
!  343            !  int         len    = strlen(pr_fname);

2531

2532 /* 
0x0004    343 */     or  %g0,%i0,%o0

2533 /* 0x0008    339 */     sll 
%i2,24,%l6

2534 /* 0x000c    343 */     call    strlen  ! params =  %o0 ! 
Result =  %o0

2535 /* 0x0010    339 */     sra %l6,24,%l7

2536

2537 
!  345            !  if( pr_fname == NULL )

2538

2539 /* 0x0120    345 
*/     cmp %i0,0                                      <== 여기에서 커널 패닉 
발생

2540 /* 0x0018        */     bne .L77001322

2541 /* 
0x001c        */     nop


위와 같이 오브젝트 덤프를 확인 할 수 있다. 덤프 내용을 살펴보면 어셈블과 0x00으로된 주소, 그리고 자신의 코드를 확인
할 수 있다. 앞에서 확인한 커널패닉 로그를 다시 보면
'0x3000168ce63: 000002a1007a3ec0 mdp_ke:putMemUse+120 (6d, 2, 3000905bb10, 780ea000, 10, 7374616c6c2f636f)'
putMemUser함수에서 +120 번째에서 났다는것을 의미 한다.
그러므로 위 코어 더프내용에서 putMemUse 함수를 찾고 그함수 내부에서 0x0120을 찾으면 된다.

댓글 없음:

댓글 쓰기