プログラムの簡単な動作確認例をいくつか～EHW2018「引継ぎプログラムとの出会い」

# 概要

このエントリは、「Enterprise "hello, world" 2018 Advent Calendar 2018」の12/1向けのものです。このAdvent Calendarでは、複数個のエントリにまたがる話の流れも鑑みつつ、なるべく1エントリで１つのトピックをカバーできるようにする予定です。

このエントリで記載するトピックは、目の前に小さなバイナリが渡されたときに、その動作について確認する方法の一例です。

# 前提

## おことわり

- このエントリでは、自分が属する組織で昔作ったバイナリ、くらいを想定します。
- 言わずもがなですが、対象とするものはライセンス的な観点でまずくないものです。ツールを使ってあれこれしてはまずいものは、このエントリの対象とはしていません。

## 想定読者

「Enterprise "hello, world" 2018」的なネタとしては、下記のような状況を想定しています。

> それは2018年の暮れのこと、僕に一つのプログラムのバイナリが渡され、
>「これを移行して動くようにしといてね☆クリスマスまでに。ドキュメントとかないけど。あはは。あと、現代的なアーキテクチャでよろしく♪」
> という依頼があった。そもそもなんだこれは。
> 
> →まずはどんなプログラムなのかを調べてみることにした。

# 動作確認

渡されたバイナリ（"hello"というファイル名でした）が置いてあるOSにログインして、調べることにします。

## OS

ETH2018としてのエントリの準備として、（移行対象が古い環境のものである雰囲気を出すために）Red Hat 7のリリースを仮想マシンで動かしました。18年前のリリースです。

```
[user@rh7 user]$ uname -a
Linux rh7 2.2.16-22 #1 Tue Aug 22 16:49:06 EDT 2000 i686 unknown
```
## とりあえず動かしてみる

動かしてよいよと教えれている環境とプログラムなので、とりあえず実行してみます。

```
[user@rh7 user]$ ./hello
hello, world
```

はい、例のアレですね。

## サイズを調べる

lsでサイズを見てみると、小さなプログラムですね。

```
[user@rh7 user]$ ls -la hello
-rwxrwxr-x    1 user     user        13441 12月  1 05:55 hello
```

## ファイルタイプを調べる

fileでバイナリの種類を調べます。32bitバイナリで、ダイナミックリンクのものですね。

```
[user@rh7 user]$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked (uses shared libs), not stripped
```

## なんのライブラリを使っているものか

ダイナミックリンクされたファイルということなので、lddで、どんなライブラリを使っているか調べてみます。
libcだけ使っているシンプルなプログラムですね。

```
[user@rh7 user]$ ldd hello
        libc.so.6 => /lib/libc.so.6 (0x4001c000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
```

## 含まれる文字列

stringsで、バイナリに含まれる文字列を眺めてみます。あいさつ文以外は特になさそうですね。

```
[user@rh7 user]$ strings hello
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
printf
__cxa_finalize
__deregister_frame_info
_IO_stdin_used
__libc_start_main
__register_frame_info
GLIBC_2.1.3
GLIBC_2.0
PTRh
QVh\
hello, world
```

## ライブラリ呼び出しを調べてみる

ltraceを使って実行して、ライブラリ呼び出しの様子を眺めてみます。printf

```
[user@rh7 user]$ ltrace ./hello
__libc_start_main(0x0804845c, 1, 0xbffffb44, 0x080482e4, 0x080484bc <unfinished ...>
__register_frame_info(0x08049504, 0x080495dc, 0xbffffae8, 0x0804838e, 0x080482e4) = 0x4013e040
printf("hello, world\n"hello, world
)                          = 13
__deregister_frame_info(0x08049504, 0, 0xbffffac4, 0, 0x40079a34) = 0x080495dc
+++ exited (status 13) +++

```

ここまでくると、やはり文字列を表示しているだけのシンプルなプログラムであることがわかりますが、ものはついでに次の調べもの

## システムコールを調べてみる

straceでシステムコールの呼び出し状況を見てみます。初期化などでいろいろ頑張っていますが、要は最後のwrite1行だけが、このプログラムの入出力ですね。

```
[user@rh7 user]$ strace ./hello
execve("./hello", ["./hello"], [/* 25 vars */]) = 0
uname({sys="Linux", node="rh7", ...})   = 0
brk(0)                                  = 0x80495f4
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40017000
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, 0xbffff1cc)                  = -1 ENOSYS (Function not implemented)
fstat(3, {st_mode=S_IFREG|0644, st_size=16274, ...}) = 0
old_mmap(NULL, 16274, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40018000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=4798370, ...}) = 0
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0P\277\1"..., 4096) = 4096
old_mmap(NULL, 1204008, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4001c000
mprotect(0x40139000, 36648, PROT_NONE)  = 0
old_mmap(0x40139000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11c000) = 0x40139000
old_mmap(0x4013f000, 12072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4013f000
close(3)                                = 0
munmap(0x40018000, 16274)               = 0
getpid()                                = 4216
fstat64(1, 0xbffff2b0)                  = -1 ENOSYS (Function not implemented)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40018000
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
write(1, "hello, world\n", 13hello, world
)          = 13
munmap(0x40018000, 4096)                = 0
_exit(13)                               = ?
```

## 実行時間を測る

移植にあたり、実行時間の目安も調べておきます。一瞬で終わるプログラムですね。

```
[user@rh7 user]$ time ./hello
hello, world

real    0m0.002s
user    0m0.000s
sys     0m0.000s
```

# まとめ

このエントリでは、「Enterprise "hello, world" 2018 Advent Calendar 2018」(EHW2018)の1日目として、Linux/Un*x系のOSで利用できるコマンドを使ってプログラムの動作について確認することをトピックとして取り上げました。

EHW2018のネタとしては、このあと、このプログラムと同じような目的を持つものを現代的なツール群を用いて、なるべくめんどくさく実現していくことを考えています。