본문 바로가기

[Debugging] Tips

[Crash-Utility] Radix Tree 디버깅: 'tree -t radix -N (struct radix_tree_node *) 구조체 주소'

이번 시간에는 크래시 유틸리티로 라덱스 트리를 디버깅하는 방법을 소개합니다.
 
라딕스 트리(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
>