Ant-Veil

Caspar Blog

Analyse Kernel Structures With Crash Utility

| Comments

关于 Kdump 和 Crash 的背景知识,不是本文的重点,可以参考下列文章:

这次碰到的问题是,系统当时死锁了,抓了个 vmcore 来研究,现在要看层层包含的某个结构体的一个 rw_semaphore 结构体变量的信息。当时这一层层的基本结构大体是这样的:

有两个链表,分别叫做: setsset_devs; 顾名思义,第一个 sets 是一堆 set 结构体组成的链表;第二个 set_devs 是一堆 set_dev 结构体组成的链表。两个结构体如下:

1
2
3
4
5
6
7
8
9
10
11
struct set {
    struct list_head *list;
    blah blah blah;
    struct list_head *set_devs;
};

struct set_dev {
    struct list_head *list;
    blah blah blah;
    struct rw_semaphore rw_sem;
};

最终任务是要找到 set_devs 这个列表里所有 set_devlock 这个信号量成员变量的信息。

首先,打开 vmcore (确保 kernel debuginfo 都在):

1
sudo crash /usr/lib/debug/lib/modules/3.10.0/vmlinux /var/crash/vmcore

如果要分析的结构体在内核模块中,还需要用 mod -s/-S 来加载内核模块的 debuginfo.

然后找到 sets 这个链表的入口地址。很幸运,模块里这个链表是全局的,直接找到 symbol 就可以用:

1
2
3
4
5
6
7
crash> p sets
sets = $1 = {
  next = 0xffffc90056696030,
  prev = 0xffffc90056696030
}
crash> p &sets // 顺手确认一下链表是否为空,如果 &sets == sets->next 就为空
$2 = (struct list_head *) 0xffffffffa04401f0 <sets>

我们就得到了一个不为空的链表的第一个元素(从上面也可以看到是唯一的一个)。由于内核里的链表只有指针没有元素内容,我们需要用类似 container_of 的机制来从成员反查链表元素的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
crash> set -l set.list 0xffffc90056696030
struct set {
  <snip>
  list = {
    next = 0xffffffffa04401f0 <sets>,
    prev = 0xffffffffa04401f0 <sets>
  },
  <snip>
  set_devs = {
    next = 0xffffc90050f67000,
    prev = 0xffffc90056ee4000
  },    
}

这样我们又得到了一个链表的 LIST_HEAD 地址:

1
2
3
4
5
crash> list_head 0xffffc90050f67000
struct list_head {
  next = 0xffffc90065f2a000,
  prev = 0xffffc90056696da8
}

得到第一个元素地址后反查 set_dev 结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
crash> struct set_dev -l set_dev.list 0xffffc90065f2a000
struct set_dev {
  list = {
    next = 0xffffc900583dc000,
    prev = 0xffffc90050f67000
  },
  <snip>
  rw_sem = {
    count = 0,
    wait_lock = {
      raw_lock = {
        {
          head_tail = 0,
          tickets = {
            head = 0,
            tail = 0
          }
        }
      }
    },
    wait_list = {
      next = 0xffffc90065f2ab48,
      prev = 0xffffc90065f2ab48
    }
  },
}

找到 rw_sem 结构体信息,这正是我们想要的。然后依次往下找即可。btw, 我忘记链表是循环链表了,所以我傻乎乎地手工查了半个小时最后才发现自己重复了……

所以问题来了,crash 里面有快捷的方法可以挨个链表元素查找么……

Comments