리눅스 프로젝트를 개발하면 코어덤프(coredump)를 열어서 크래시가 발생한 원인을 분석할 때가 많습니다.
많은 개발자 분들이 코어덤프를 열어서 크래시가 발생한 원인을 분석하죠.
코어덤프를 열어 gdb를 사용해 디버깅할 때 가장 짜증나는 것 중 하나는 공유 라이브러리를 제대로 로딩하지 못해
콜 스택이 보이지 않을 때 입니다.
이번에는 코어덤프를 로딩할 때 필요한 정보 중 하나인 공유 라이브러리의 정보(패스/이름)을 확인하는 방법을 소개합니다.
깨진 콜 스택 확인하기
먼저 콜 스택을 보겠습니다.
(gdb) bt
#0 0x0000007f7def1808 in __glibc_raise (sig=sig@entry=6) at /usr/glibc/raise.c:1354
#1 0x0000007f7def2d80 in __glibc_abort () at /usr/glibc/abort.c:489
#2 0x0000007f7deeadbc in __assert_fail_base() at /usr/glibc/assert.c:912
#3 0x0000007f7deeae6c in __glibc___assert_fail () at /usr/glibc/assert.c:1014
#4 0x0000007f7e4f13ec in power_railway_delay () at /usr/src/powerrail/powerrail.c:9489
#5 0x0000007f7efa5af4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
위 메시지를 보면 #5 줄에서 콜 스택이 깨진 걸 볼 수 있습니다.
#5 0x0000007f7efa5af4 in ?? ()
0x0000007f7efa5af4 주소가 뭔지 모르겠다는 소리죠.
공유 라이브러리 이름 확인하기
이번에는 'info share' 명령어를 입력해 공용 라이브러리의 경로를 확인합시다.
(gdb) info share
From To Syms Read Shared Object Library
No /usr/lib/libPowerRailwayManagement.so
0x0000007f7ee1cf30 0x0000007f7eec9c9c Yes /usr/lib/librsi.so.0.1
가장 첫 번째 줄을 보면 libPowerRailwayManagement.so 라이브러리가 제대로 로딩이 안 됐다고 확인됩니다.
No /usr/lib/libPowerRailwayManagement.so
공유 라이브러리 오프셋 확인하기
리눅스 터미널을 하나 더 열고, './readelf -n coredump' 명령어를 입력해 코어덤프에 있는 NT_FILE 노트를 확인합시다. 참고로 NT_FILE 노트에는 코어덤프에서 공유 라이브러리 정보가 포함돼 있습니다.
baldcandy.kim# ./readelf -n coredump
Displaying notes found at file offset 0x00005168 with length 0x00010c58:
Owner Data size Description
CORE 0x00000188 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000080 NT_SIGINFO (siginfo_t data)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00002b9d NT_FILE (mapped files)
Page size: 4096
Start End Page Offset
...
0x0000007f7ef21000 0x0000007f7f18a000 0x0000000000000000
/usr/lib/libPowerRailwayManagement.so
0x0000007f7f18a000 0x0000007f7f19a000 0x0000000000000269
/usr/lib/libPowerRailwayManagement.so
0x0000007f7f19a000 0x0000007f7f1a3000 0x0000000000000269
/usr/lib/libPowerRailwayManagement.so
0x0000007f7f1a3000 0x0000007f7f1a5000 0x0000000000000272
/usr/lib/libPowerRailwayManagement.so
libPowerRailwayManagement.so 라이브러리의 실행 오프셋은 0x0000007f7ef21000임을 알 수 있습니다.
이번에는 libPowerRailwayManagement.so 라이브러리 파일을 찾아서 헤더 정보를 확인합시다.
이를 위해 'readelf -S libPowerRailwayManagement.so' 명령어를 입력해야 합니다.
baldcandy.kim# readelf -S libPowerRailwayManagement.so
There are 27 section headers, starting at offset 0x273728:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.build-i NOTE 00000000000001c8 000001c8
0000000000000024 0000000000000000 A 0 0 4
...
[10] .plt PROGBITS 0000000000074b60 00074b60
000000000000a110 0000000000000010 AX 0 0 16
[11] .text PROGBITS 000000000007ec70 0007ec70
0000000000160ebc 0000000000000000 AX 0 0 16
'[11]' 번째 줄을 보면 .text 섹션 헤더의 오프셋은 0x0007ec70으로 확인됩니다.
결국 libPowerRailwayManagement.so 라이브러리의 오프셋은 다음 계산식으로 0x7F7EF9FC70입니다.
0x7F7EF9FC70 = 0x0000007f7ef21000 + 0x0007ec70
공유 라이브러리 로딩하기
다시 GDB 프로그램 화면으로 되돌아와, 다음 명령어를 입력해 라이브러리 패스를 추가합시다.
'add-symbol-file ./libPowerRailwayManagement.so 0x7F7EF9FC70'
(gdb) add-symbol-file ./libPowerRailwayManagement.so 0x7F7EF9FC70
add symbol table from file "./libPowerRailwayManagement.so" at
.text_addr = 0x7f7ef9fc70
(y or n) y
명령어를 입력하면 '(y or n)' 텍스트가 출력되면서 .text_addr를 0x7f7ef9fc70로 지정하도 되는지 묻습니다.
바로 'y'를 선택합니다. 그러면 다음과 같은 화면이 보일 것입니다.
(y or n) y
Reading symbols from ./libPowerRailwayManagement.so...(no debugging symbols found)...done.
공유 라이브러리를 로딩한 다음 콜 스택을 확인하니 깨진 콜 스택이 복구해 볼 수 있습니다.
(gdb) bt
#0 0x0000007f7def1808 in __glibc_raise (sig=sig@entry=6) at /usr/glibc/raise.c:1354
#1 0x0000007f7def2d80 in __glibc_abort () at /usr/glibc/abort.c:489
#2 0x0000007f7deeadbc in __assert_fail_base() at /usr/glibc/assert.c:912
#3 0x0000007f7deeae6c in __glibc___assert_fail () at /usr/glibc/assert.c:1014
#4 0x0000007f7e4f13ec in power_railway_delay () at /usr/src/powerrail/powerrail.c:9489
#5 0x0000007f7efa5af4 in PowerManager::set_powerrail_delay()
#6 0x0000007f7efaf774 in PowerManager::set_powerrail_run()
#7 0x0000007f7efb17e8 in PowerManager::powerrail_set_railway()
#8 0x0000007f7efb3018 in PowerManager::powerrail_init(void*) ()
#9 0x0000007f7efb3c60 in ?? ()
#10 0x0000007f7e26b020 in start_thread (arg=0x147f7e28f010 <__pthread_keys+15752>) at /usr/src/pthread_create.c:11335
#11 0x0000007f7df88970 in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:89
아래는 공유 라이브러리를 로딩하기 전의 깨진 콜 스택 정보입니다.
(gdb) bt
#0 0x0000007f7def1808 in __glibc_raise (sig=sig@entry=6) at /usr/glibc/raise.c:1354
#1 0x0000007f7def2d80 in __glibc_abort () at /usr/glibc/abort.c:489
#2 0x0000007f7deeadbc in __assert_fail_base() at /usr/glibc/assert.c:912
#3 0x0000007f7deeae6c in __glibc___assert_fail () at /usr/glibc/assert.c:1014
#4 0x0000007f7e4f13ec in power_railway_delay () at /usr/src/powerrail/powerrail.c:9489
#5 0x0000007f7efa5af4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
---
"이 포스팅이 유익하다고 생각되시면 공감 혹은 댓글로 응원해주시면 감사하겠습니다.
"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!"
Thanks,
Guillermo Austin Kim(austindh.kim@gmail.com)
---
'[Debugging] Tips' 카테고리의 다른 글
[리눅스커널] 크래시 유틸리티(Crash-Utility): 슬랩 페이지의 갯수를 확인하는 방법 (0) | 2023.05.04 |
---|---|
[리눅스커널] TRACE32: 'v.type' 명령어로 구조체와 enum 필드를 바로 확인하기 (0) | 2023.05.04 |
[리눅스] GDB 프로그램 사용 위치 파악: 'which -a' (0) | 2023.05.04 |
[리눅스커널] 부팅 과정 유익한 패치 (0) | 2023.05.04 |
유용한 TRACE32(T32) 명령어 (0) | 2023.05.04 |