staprunコマンドの使い方

#1 staprunコマンドとは?
systemtapスクリプトから作成したモジュールを、別のホストで実行するときに使います。
gccのようなコンパイラをインストールできないホストでsystemtapを実行するような
状況において有効です。
ただし、モジュールを作成するホストとモジュールを実行するホストのカーネル版数が
同一であることが必要です。

#2 環境
VMware Workstation 14 Player上の仮想マシン(2台)を使いました。
server,client はホスト名です。
ここでは、サーバで作成したモジュールをクライアントで実行してみます。

```console:ネットワーク構成
                     192.168.3.0/24
      .30                                  .20
client ------------------------------------- server 
````

サーバ、クライアントともに、下記の版数です。

```console:カーネル版数
[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

[root@server ~]# uname -r
3.10.0-693.el7.x86_64
```

```console:コマンド版数
[root@client ~]# staprun -V
Systemtap module loader/runner (version 3.1, rpm 3.1-5.el7_4)
Copyright (C) 2005-2017 Red Hat, Inc. and others
This is free software; see the source for copying conditions.
```


#3 オプション一覧

```
[root@client ~]# staprun -h

staprun [-v] [-w] [-V] [-h] [-u] [-c cmd ] [-x pid] [-u user] [-A|-L|-d] [-C WHEN]
        [-b bufsize] [-R] [-r N:URI] [-o FILE [-D] [-S size[,N]]] MODULE [module-options]
-v              Increase verbosity.
-V              Print version number and exit.
-h              Print this help text and exit.
-w              Suppress warnings.
-u              Load uprobes.ko
-c cmd          Command 'cmd' will be run and staprun will
                exit when it does.  The '_stp_target' variable
                will contain the pid for the command.
-x pid          Sets the '_stp_target' variable to pid.
-N pid          Sets the '_stp_namespaces_pid' variable to pid.
-o FILE         Send output to FILE. This supports strftime(3)
                formats for FILE.
-b buffer size  The systemtap module specifies a buffer size.
                Setting one here will override that value.  The
                value should be an integer between 1 and 4095
                which be assumed to be the buffer size in MB.
                That value will be per-cpu in bulk mode.
-L              Load module and start probes, then detach.
-A              Attach to loaded systemtap module.
-C WHEN         Enable colored errors. WHEN must be either 'auto',
                'never', or 'always'. Set to 'auto' by default.
-d              Delete a module.  Only detached or unused modules
                the user has permission to access will be deleted. Use "*"
                (quoted) to delete all unused modules.
-R              Have staprun create a new name for the module before
                inserting it. This allows the same module to be inserted
                more than once.
-r N:URI        Pass N:URI data to tapset functions remote_id()/remote_uri().
-D              Run in background. This requires '-o' option.
-S size[,N]     Switches output file to next file when the size
                of file reaches the specified size. The value
                should be an integer greater than 1 which is
                assumed to be the maximum file size in MB.
                When the number of output files reaches N, it
                switches to the first output file. You can omit
                the second argument.
-T timeout      Specifies upper limit on amount of time reader thread
                will wait for new full trace buffer. Value should be an
                integer >= 1, which is timeout value in ms. Default 200ms.
-F fd           Specifies file descriptor for module relay directory

MODULE can be either a module name or a module path.  If a
module name is used, it is searched in the following directory:
/lib/modules/3.10.0-693.el7.x86_64/systemtap
```

#4 基本的な使い方
ここでは、サーバで作成したモジュールをクライアントで実行してみます。
サーバでsystemtapスクリプトを作成します。
pingを実行すると、プローブした関数の関数名を表示します。
なお、systemtapについては、[ここ(SystemTapの使い方)](https://qiita.com/hana_shin/items/9b265b4f9a51f98d0f4d)を参照してください。

```console:スクリプトの確認(サーバ側)
[root@server stap]# cat icmp.stp
#!/usr/bin/stap

probe kernel.function("ip_output@net/ipv4/ip_output.c")
{
  if(execname() == "ping"){
    printf("pp=%s\n",pp())
  }
}
```

スクリプトからモジュールを作成します。
pオプションは、次の値をとります。4を指定するとcompileしてモジュールを作成します。
`1-5: parse, elaborate, translate, compile, run`
mオプションは、モジュール名を指定します。
ここでは、icmp.koという名前のモジュールを作成します。

```console:モジュールの作成(サーバ側)
[root@server stap]# stap -p4 -m icmp icmp.stp
icmp.ko
```

作成したモジュールを確認します。
icmp.koというモジュールが作成できたことがわかります。

```console:モジュールの確認(サーバ側)
[root@server stap]# ls icmp.*
icmp.ko  icmp.stp
```

サーバからクライアントにモジュールを転送します。
サーバとクライアントは、同じカーネル版数である必要があります。

```console:モジュールの転送(サーバ側)
[root@server stap]# scp icmp.ko root@192.168.3.30:/root/stap
root@192.168.3.30's password:
icmp.ko
```

モジュールをインストールします。

```console:モジュールのインストール(クライアント側)
[root@client stap]# staprun -v icmp.ko
staprun:insert_module:191 Module icmp inserted from file /root/stap/icmp.ko
```

クライアント側でもう1つターミナルを開きます。
開いたターミナルでpingを実行します。
ここでは、デフォルトGWにpingを1回実行してみました。
なお、pingについては、[ここ(pingコマンドの使い方)](https://qiita.com/hana_shin/items/c31b0d05a91244c4db83)を参照してください。

```console:ping実行(クライアント側)
[root@client stap]# ping -c 1 192.168.3.1
```

pingを実行すると、systemtapの実行結果が表示されることがわかります。

```console:実行結果確認((クライアント側)
[root@client stap]# staprun -v icmp.ko
staprun:insert_module:191 Module icmp inserted from file /root/stap/icmp.ko
pp=kernel.function("ip_output@net/ipv4/ip_output.c:352")
```

#Z 参考情報
[第14回「 SystemTap ノススメ」](http://www.intellilink.co.jp/article/column/oss14.html)
[2.3. SYSTEMTAP スクリプトの実行](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/systemtap_beginners_guide/using-usage)
[SystemTap](http://hagio.org/wiki/index.php/SystemTap)