link もっと前
   2017年 7月 3日 -
      2017年 7月 3日  
link もっと後

link 未来から過去へ表示(*)
link 過去から未来へ表示

日々

link permalink

仮想アドレスから物理アドレスへ

ちょっと用事があって、ユーザプロセスの仮想アドレスから、物理アドレスへの変換を行うプログラムを作りました。名前は v2p(virt2phys)です。何の捻りもありません。ソースコードは GitHub に置いています。

やっていることは /proc/pid/pagemap を読んで、わかりやすい形式で表示しているだけです。言葉で説明するより動いている姿の方がわかりやすいと思います。

実験に使った環境は Debian GNU/Linux Testing amd64 版です。別に Debian じゃなくても最近の Linux なら動くと思います。

このツールの実行には、プロセス ID と仮想アドレスが必要です。まず解析に使うプロセスを作って、プロセス ID を調べます。

cat を実行&中断
$ cat
[Press Ctrl+Z]
[1]+  Stopped                 cat

$ ps
  PID TTY          TIME CMD
 2148 pts/4    00:00:00 bash
14010 pts/4    00:00:00 cat  ★★cat の PID を覚えておく★★
14015 pts/4    00:00:00 ps

プロセス ID がわかったら、物理アドレスに変換したい仮想アドレスを決めます。ここでは例としてヒープ領域の先頭アドレスを変換しましょう。

cat のヒープ領域の仮想アドレス
$ cat /proc/14010/maps
55ff09a4f000-55ff09a57000 r-xp 00000000 08:11 5505114                    /bin/cat
55ff09c56000-55ff09c57000 r--p 00007000 08:11 5505114                    /bin/cat
55ff09c57000-55ff09c58000 rw-p 00008000 08:11 5505114                    /bin/cat
55ff0b2cb000-55ff0b2ec000 rw-p 00000000 00:00 0                          [heap]    ★★これを使う★★
7fdbeb6a3000-7fdbeb838000 r-xp 00000000 08:11 4980859                    /lib/x86_64-linux-gnu/libc-2.24.so
7fdbeb838000-7fdbeba38000 ---p 00195000 08:11 4980859                    /lib/x86_64-linux-gnu/libc-2.24.so
...(snip)...
7ffdde79c000-7ffdde7be000 rw-p 00000000 00:00 0                          [stack]
7ffdde7fb000-7ffdde7fd000 r--p 00000000 00:00 0                          [vvar]
7ffdde7fd000-7ffdde7ff000 r-xp 00000000 00:00 0                          [vdso]

プロセス ID と仮想アドレスがわかったので、物理アドレスに変換します。

仮想アドレスから物理アドレスへ
$ sudo ./src/v2p 14010 0x55ff0b2cb000 0x4000
pid: 14010:
 virt:0x55ff0b2cb000, phys:0x73a42b000
 virt:0x55ff0b2cc000, phys:(not present)
 virt:0x55ff0b2cd000, phys:(not present)
 virt:0x55ff0b2ce000, phys:(not present)

変換できました。特権のない状態で実行すると全て 0x00000000 になってしまいますので、お気をつけください。

表示の意味は特に何の捻りもなく、物理アドレスをそのまま示しています。ちなみに (not present) と表示される場合は、まだカーネルからページが割り当てられておらず、仮想アドレスに対応する物理アドレスが存在しないことを意味しています。

デマンドページング

これだけだと GitHub に書いた Readme そのものだし、へぇー…って感じがするだけで面白くないので、cat に gdb でアタッチしてヒープ領域を触ったらどうなるか見てみます。

gdb でアタッチして 3番目と 5番目のページを read する
$ sudo ./src/v2p 14010 0x55ff0b2cb000 0x6000
pid: 14010:
 virt:0x55ff0b2cb000, phys:0x73a42b000
 virt:0x55ff0b2cc000, phys:(not present)
 virt:0x55ff0b2cd000, phys:(not present) ★これを読む★
 virt:0x55ff0b2ce000, phys:(not present)
 virt:0x55ff0b2cf000, phys:(not present) ★これを読む★
 virt:0x55ff0b2d0000, phys:(not present)


$ gdb -p 14010
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
0x00007fdbeb77e690 in __read_nocancel ()
    at ../sysdeps/unix/syscall-template.S:84
84      ../sysdeps/unix/syscall-template.S: そのようなファイルやディレクトリはありません.

(gdb) x/4x 0x55ff0b2cd000
0x55ff0b2cd000: 0x00000000      0x00000000      0x00000000      0x00000000

(gdb) x/4x 0x55ff0b2cf000
0x55ff0b2cf000: 0x00000000      0x00000000      0x00000000      0x00000000


$ sudo ./src/v2p 14010 0x55ff0b2cb000 0x4000
pid: 14010:
 virt:0x55ff0b2cb000, phys:0x73a42b000
 virt:0x55ff0b2cc000, phys:(not present)
 virt:0x55ff0b2cd000, phys:0x1cb695000 ★ゼロページが割り当たる★
 virt:0x55ff0b2ce000, phys:(not present)
 virt:0x55ff0b2cf000, phys:0x1cb695000 ★ゼロページが割り当たる★
 virt:0x55ff0b2d0000, phys:(not present)

試しに 3番目と 5番目の領域からデータを読み出してみました、どちらも 0 データが見えます。読み出したあとは 0x1cb695000(数字は環境によって違います)という同じアドレスが割り当たりました。このアドレスは全て 0 で埋まっている特殊なページを指していて、読み出したときにとにかく 0 データを返せば良い領域に使われるらしいです。

じゃあ今度は書いてみたらどうなるでしょう?

gdb でアタッチして 2番目と 3番目のページを read する
$ sudo ./src/v2p 14010 0x55ff0b2cb000 0x6000
pid: 14010:
 virt:0x55ff0b2cb000, phys:0x73a42b000
 virt:0x55ff0b2cc000, phys:(not present) ★これに書く★
 virt:0x55ff0b2cd000, phys:0x1cb695000   ★これに書く★
 virt:0x55ff0b2ce000, phys:(not present)
 virt:0x55ff0b2cf000, phys:0x1cb695000
 virt:0x55ff0b2d0000, phys:(not present)


(gdb) set *((long *)(0x55ff0b2cc000))=0x89abcdef

(gdb) x/4x 0x55ff0b2cc000
0x55ff0b2cc000: 0x89abcdef      0x00000000      0x00000000      0x00000000

(gdb) set *((long *)(0x55ff0b2cd000))=0x12345678

(gdb) x/4x 0x55ff0b2cd000
0x55ff0b2cd000: 0x12345678      0x00000000      0x00000000      0x00000000


$ sudo ./src/v2p 14010 0x55ff0b2cb000 0x4000
pid: 14010:
 virt:0x55ff0b2cb000, phys:0x73a42b000
 virt:0x55ff0b2cc000, phys:0x73c76a000 ★ページが割り当たる★
 virt:0x55ff0b2cd000, phys:0x72edd0000 ★ゼロページが外され、別のページが割り当たる★
 virt:0x55ff0b2ce000, phys:(not present)
 virt:0x55ff0b2cf000, phys:0x1cb695000
 virt:0x55ff0b2d0000, phys:(not present)

2番目の (not present) な領域にも書けますし、3番目のゼロページが割り当たっている領域にも書けます。読み出してみても、ちゃんと書けていることがわかります。

書き込んだあとの仮想アドレスと物理アドレスの対応を見ると、2番目は read した時とは違ってゼロページではなさそうなアドレスが割当たります。3番目はゼロページが外され、別のページが割り当てられます。

不思議に見えるかも知れませんが、ゼロページは 0 データを返す専門なので、書き込みができません、というかカーネルが書き込みを許しません。ゼロページに書き込もうとした場合はゼロページを外して別のページを割り当て、以降はそのページを使って下さい、という仕組みになっています。

[編集者: すずき]
[更新: 2017年 7月 4日 00:29]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2017年 7月 3日 -
      2017年 7月 3日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 7/17 22:53

カレンダー

<2017>
<<<07>>>
------1
2345678
9101112131415
16171819202122
23242526272829
3031-----

最近のコメント 5件

  • link 18年07月04日
    すずき 「NEON にも対応してみましたが、やはり...」
    (更新:07/11 21:26)
  • link 18年05月30日
    すずき 「情報ありがとうございます。PT2 2枚差...」
    (更新:06/02 17:27)
  • link 18年05月30日
    通りすがりですみませ... 「私のPC(Win10)ではB−CAS1枚...」
    (更新:06/02 16:42)
  • link 18年05月20日
    すずき 「数えたことはありませんが Windows...」
    (更新:05/22 22:26)
  • link 18年05月20日
    hdk 「Linux も、先日の Meltdown...」
    (更新:05/21 22:55)

最近の記事 3件

link もっとみる
  • link 18年07月17日
    すずき 「[エアコンが臭い] 「エアコンの嫌なニオイが完全に消えた」 "窓全...」
    (更新:07/17 22:53)
  • link 18年07月16日
    すずき 「[AArch64 向け Linux 開発環境の構築 その 2] そ...」
    (更新:07/17 22:46)
  • link 18年07月07日
    すずき 「[Android と MPEG2-TS その 3] その 1、その...」
    (更新:07/17 22:46)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報