이번 시간에는 크래시 유틸리티로 라덱스 트리를 디버깅하는 방법을 소개합니다.
라딕스 트리(Radix Tree)를 보기 위한 명령어
크래시 유틸리티로 라덱스 트리 노드를 보기 위한 명령어 포멧은 다음과 같습니다.
tree -t radix -N (struct radix_tree_node *) 구조체 주소
예제 명령어 및 결과 ( struct radix_tree_node 구조체 주소가 0xFFFFFFFF3A806E79 인 경우)
crash> tree -t radix -N 0xFFFFFFFF3A806E79
ffffffff3f53c180
ffffffff3f53c4c0
ffffffff3f555180
ffffffff3f5554c0
ffffffff3f56e180
ffffffff3f56e4c0
ffffffff3f587180
ffffffff3f5874c0
ffffffff3f5a0180
ffffffff3f5a04c0
ffffffff3f5b9180
ffffffff3f5b94c0
ffffffff3f5d2180
ffffffff3f5d24c0
ffffffff3f5eb180
ffffffff3f5eb4c0
fffffffe4683d480
ffffffff3657a480
Case Study: worker_pool_idr 전역변수로 라덱스 트리 디버깅해보기
워커풀은 라덱스 트리로 구성돼 있습니다.
#define for_each_pool(pool, pi) \
idr_for_each_entry(&worker_pool_idr, pool, pi) \
if (({ assert_rcu_or_pool_mutex(); false; })) { } \
else
worker_pool_idr 전역변수 타입은 struct idr worker_pool_idr입니다.
crash64> whatis worker_pool_idr
struct idr worker_pool_idr;
crash64>
struct idr 구조체 idr_rt 필드 타입은 struct radix_tree_root입니다.
crash64> struct idr
struct idr {
struct radix_tree_root idr_rt;
unsigned int idr_base;
unsigned int idr_next;
}
worker_pool_idr.idr_rt 필드의 라덱스 트리 노드 주소는 0xffffffff3a806e79입니다.
crash64> p worker_pool_idr.idr_rt.rnode
$2 = (struct radix_tree_node *) 0xffffffff3a806e79
다음 명령어를 입력하면 라덱스 트리 모든 노드를 볼 수 있습니다.
crash64_kaslr> tree -t radix -N 0xFFFFFFFF3A806E79
ffffffff3f53c180
ffffffff3f53c4c0
ffffffff3f555180
ffffffff3f5554c0
ffffffff3f56e180
ffffffff3f56e4c0
ffffffff3f587180
ffffffff3f5874c0
ffffffff3f5a0180
ffffffff3f5a04c0
ffffffff3f5b9180
ffffffff3f5b94c0
ffffffff3f5d2180
ffffffff3f5d24c0
ffffffff3f5eb180
ffffffff3f5eb4c0
fffffffe4683d480
ffffffff3657a480
위 주소 리스트는 struct worker_pool 구조체이며 다음과 같이 확인할 수 있습니다.
1: ffffffff3f53c4c0 struct worker_pool 디버깅
[0]: watchdog_ts = 4295299595 // 워커 터치 시간
[1]: 해당 워커풀에 큐잉한 워크
[2]: 실행 중인 워커: 0xFFFFFFFEE11F5B80
(struct worker_pool *) (struct worker_pool*)0xffffffff3f53c180 = 0xFFFFFFFF3F53C180 = end+0x68B4978180 -> (
(spinlock_t) lock = ((struct raw_spinlock) rlock = ((arch_spinlock_t) raw_lock = ((atomic_t) val = ((int) counter = 0), (u8) locked = 0, (u8)
(int) cpu = 0,
(int) node = 0,
(int) id = 0,
(unsigned int) flags = 0,
(long unsigned int) watchdog_ts = 4295299595, "//<<--[0]"
(struct list_head) worklist = (
(struct list_head *) next = 0xFFFFFF9689B2D098 = binder_deferred_work.entry -> ( "//<<--[1]"
(struct list_head *) next = 0xFFFFFF9689A052C8 = delayed_fput_work.work.entry, "//<<--[1]"
(struct list_head *) prev = 0xFFFFFFFF3F53C1A0 = end+0x68B49781A0),
(struct list_head *) prev = 0xFFFFFF9689B65710 = nd_tbl.gc_work.work.entry), "//<<--[1]"
(int) nr_workers = 3,
(int) nr_idle = 2,
(struct list_head) idle_list = ((struct list_head *) next = 0xFFFFFFFEE4BF0680 = end+0x685A02C680, (struct list_head *) prev = 0xFFFFFFFEE07B
(struct timer_list) idle_timer = ((struct hlist_node) entry = ((struct hlist_node *) next = 0xDEAD000000000200
(struct timer_list) mayday_timer = ((struct hlist_node) entry = ((struct hlist_node *) next = 0xDEAD000000000200
(struct hlist_head [64]) busy_hash = (
[0] = ((struct hlist_node *) first = 0x0 = ),
...
[45] = ((struct hlist_node *) first = 0x0 = ),
[46] = ((struct hlist_node *) first = 0xFFFFFFFEE11F5B80 = end+0x6856631B80), "//<<--[2]"
[47] = ((struct hlist_node *) first = 0x0 = ),
...
[63] = ((struct hlist_node *) first = 0x0 = )),
(struct worker *) manager = 0x0 = ,
(struct list_head) workers = ((struct list_head *) next = 0xFFFFFFFEE07B9BC8 = end+0x6855BF5BC8, (struct list_head *) prev = 0xFFFFFFFEE11F5B
(struct completion *) detach_completion = 0x0 = ,
(struct ida) worker_ida = ((struct radix_tree_root) ida_rt = ((spinlock_t) xa_lock = ((struct raw_spinlock) rlock = ((arch_spinlock_t) raw_lo
(struct workqueue_attrs *) attrs = 0xFFFFFFFE46881C00 = end+0x67BBCBDC00,
(struct hlist_node) hash_node = ((struct hlist_node *) next = 0x0 = , (struct hlist_node * *) pprev = 0x0 = ),
(int) refcnt = 1,
(atomic_t) nr_running = ((int) counter = 1),
(struct callback_head) rcu = ((struct callback_head *) next = 0x0 = , (void (*)()) func = 0x0 = ))
리눅스 커널 디버깅 중 라딕스 트리를 만났을 때 이 명령어를 잘 활용합시다.
>
> Written-by: Austin Kim, 09/29/2019
> Posted-by: Austin Kim, 09/30/2019
>
'[Debugging] Tips' 카테고리의 다른 글
[리눅스커널][Trace32] wakelock 디버깅 - container_of (0) | 2023.05.04 |
---|---|
[안드로이드][리눅스커널] 시그널 - 유저 공간 abort(SIGABRT) 시 동작 시 흐름 (0) | 2023.05.04 |
[리눅스커널] 안드로이드/라즈베리 파이 부팅 실패 100% 해결하는 디버깅 패치 (0) | 2023.05.04 |
[TRACE32] 유저 공간 콜스택 복원하기 - ARMv8(Aarch64) (0) | 2023.05.04 |
[리눅스커널] 인터럽트 핸들러 실행 시각 측정 디버깅 패치 (0) | 2023.05.04 |