crashコマンドの使い方(ctl_table編)

fs.mqueue.queues_maxを例に、いろいろな方法で値を取得したいと思います。
簡単な方法は、起動しているマシンから次のようにコマンドを使って取得する方法です。

# sysctl -q fs.mqueue.queues_max
fs.mqueue.queues_max = 256
# cat /proc/sys/fs/mqueue/queues_max 
256

これが、クラッシュしたマシンのvmcoreから調べるとなると別のアプローチが必要になってきます。はじめに、sysctl_table_rootの仮想アドレスを調べ、sysctl_table_rootが何か見つけます。

crash> sym sysctl_table_root
ffffffffbcd06420 (d) sysctl_table_root
crash> whatis sysctl_table_root
struct ctl_table_root sysctl_table_root;
crash> ctl_table_root ffffffffbcd06420
struct ctl_table_root {
  default_set = {
    is_seen = 0x0,
    dir = {
      header = {
        {
          {
            ctl_table = 0xffffffffbcd064a0,
...

このctl_tableを使って、階層をたどって行く方法で値を探してみます。まずは、/proc/sys/fsを探してみます。その後に、その配下のmqueueのctl_tableのアドレスを取得します。

crash> ctl_table 0xffffffffbcd064a0 10000|grep procname|grep fs
  procname = 0xffffffffbcabcbcb "configfs",
  procname = 0xffffffffbca79f0f "ramfs",
  procname = 0xffffffffbcaa46b5 "tracefs",
  procname = 0xffffffffbcab89f0 "fs",
..
crash> ctl_table 0xffffffffbcd064a0 10000|grep -s -e 'procname = 0xffffffffbcab89f0 \"fs\"' -A 5
  procname = 0xffffffffbcab89f0 "fs",
  data = 0x0,
  maxlen = 0,
  mode = 365,
  child = 0xffffffffbcd09b20,

crash> ctl_table 0xffffffffbcd09b20
struct ctl_table {
  procname = 0xffffffffbcabec8b "mqueue",
  data = 0x0,
  maxlen = 0,
  mode = 365,
  child = 0xffffffffbcd09ba0,
  proc_handler = 0x0,
  poll = 0x0,
  extra1 = 0x0,
  extra2 = 0x0
}

0xffffffffbcd09ba0を使って、ctl_tableの値を取得すると、procname="queues_max"の情報を表示できます。ここでdataを表示できますが、このままではアドレスしか表示しないので、工夫が必要です。

crash> ctl_table 0xffffffffbcd09ba0
struct ctl_table {
  procname = 0xffffffffbcabef96 "queues_max",
  data = 0xffffffffbcd0764c,
  maxlen = 4,
  mode = 420,
  child = 0x0,
  proc_handler = 0xffffffffbbd53250,
  poll = 0x0,
  extra1 = 0x0,
  extra2 = 0x0
}

dataサイズを確認すると、intとわかります。

ipc/mq_sysctl.c:
static ctl_table mq_sysctls[] = {
        {
                .procname       = "queues_max",
                .data           = &init_ipc_ns.mq_queues_max,
                .maxlen         = sizeof(int),
...

そこで、rdを使って、メモリをサイズ指定して読んでいきます。そして、16進数から10進数の値に変換すると、256を取得できます。

crash> rd -32 0xffffffffbcd0764c
ffffffffbcd0764c:  00000100                              ....
crash> p/d 0x100
$22 = 256

crashinfoというPythonのextentionを利用しても同様のことができます。

crash> crashinfo  --sysctl|grep queues_max
fs.mqueue.queues_max 256