「VMware」カテゴリーアーカイブ

VMware Workstation 12.1.1 PlayerでUbuntu 16.04を使う

以前、VMware Workstation 12 PlayerでUbuntu 14.04を使おうとしました。

ホストは、Windows 10 Proです。

VMware Toolsをインストールして、いろいろやってみたのですが、どうもうまくいきませんでした。

今回Ubuntu 16.04を使おうとして調べてみると、こちらの方法でうまくいくことがわかりました。

ubuntu 16.04 インストール(2) vmware tools

自分の場合、クリップボード共有(コピーペースト)と共有フォルダを主に使っています。

VMware Toolsをインストールする方法としては、Ubuntuにもともと入っているOpen VM Toolsを使う方法と、以前からあるように手動でインストールする方法があります。

Ubuntu 16.04のデフォルトでは、Open VM Toolsが入っているのですが、共有フォルダが動かなくて困っていたのでした。じゃあということで、手動でインストールするとクリップボード共有がうまく動きません。

結局、もともと入っているOpen VM Toolsをつかって、/etc/fstabの設定を付け加えることで両方動かすことができました。

繰り返しになりますが、少し説明すると、

$ sudo apt install open-vm-tools-desktop

で、クリップボード共有が有効になります。もともと入っていれば問題ないです。

また、/etc/fstabに

.host:/ /mnt/hgfs fuse.vmhgfs-fuse allow_other,auto_unmount,defaults 0 0

と付け加えることで共有フォルダが有効になりました。

画面のリサイズにも対応していて、ありがたく使わせていただいています。

VMware Workstation PlayerでOpenStack Mitakaのネットワークを設定しインスタンスを起動

はじめに

VMware Workstation PlayerでOpenStack Mitakaのインストールをしています。

前回は、OpenStack MitakaをインストールしてDashboardを見るところまでをやりました。

インストールにはこちらのサイトを参考にさせていただきました。今回は、ネットワークを設定しインスタンスを起動してロードバランサを動かすところまでやります。

VMware Workstation PlayerでOpenstack Kiloを動かす手順

ネットワークの設定では、こちらも参考にさせていただきました。

OpenStack Neutronを使ってWebシステムを構築する実践的な方法 (1/3)

不具合の対処

OpenStackのホストとなるCentOSを再起動してみると、httpdサービスとneutron-serverサービスがfailedになって立ち上がりません。動くときもありますので、いつも動かないわけではないようです。

サービスの起動の状態を知るのは次のコマンドでわかります。

#systemctl list-units --type service

エラーメッセージはこんな感じです。

#systemctl status httpd

ERROR: scss.ast: Function not found: function-exists:1

#systemctl status neutron-server

neutron.service start operation timed out. Terminating.

こちらの情報によると /lib/systemd/system/httpd.service.d/openstack-dashboard.conf を実行するときに時間がかかりすぎるのが原因だとか。パッチも作られたようです。

とりあえず次のコマンドで手動で起動すると動きます。httpdが起動するまで少し待つ必要があります。

# systemctl start httpd
# systemctl start neutron-server

また、VMware Workstation PlayerのCPU2コア、メモリ4GBにすると安定して動くようになりました。CPU1コア、メモリ4GBでは、リソースが足りないようです。

ネットワークを設定

VMware Workstation PlayerでOpenstack Kiloを動かす手順に従ってネットワークを動かそうとしました。しかし、502 Bad Gatewayというエラーが出て動きません。

問題の特定にはログファイルを見るしかないようでしたが、OpenStackを始めたばかりでどのログファイルのどこを見ればいいのかよくわかりません。

そこで、OpenStack Neutronを使ってWebシステムを構築する実践的な方法 (1/3)に従ってネットワークが動作することを確かめました。そのあとに手順書に従ってネットワークを動かしました。

@ITのサイトでは、OpenStackのハンズオンを基にした手順が書かれてありわかりやすかったのですが、公開するネットワークの設定の仕方が書いてないため、手探りで設定しました。下記に書いたようにpublicのネットワークを設定しました。

また、手順書のようにtennant_idを一つ一つ手書きするのはとても大変でした。そこで、@ITの記事を参考に次のようにしてネットワークを設定しました。

ちなみに、VMware Workstation Playerの画面で作業するのはコピーペーストできません。コピーペーストできるsshクライアントを用意してVMware Workstation PlayerのCentOSにアクセスして作業するとはかどります。

まずpublicという名前の公開するネットワークを作ります。作成する時のポイントはnet-createのときに、--router:externalを使うことです。これで外部のネットワークだと指定することができます。

OpenStackのホストとなるCentOSのIPアドレスは、192.168.0.140と指定してインストールを行っています。そのIPアドレスを外して、192.168.0.141から192.168.0.199をFloationg IPという名前で使って良いアドレスと指定します。

# neutron net-create public --route:external
# neutron subnet-create --name public_subnet --disable-dhcp --allocation-pool start=192.168.0.141,end=192.168.0.199 public 192.168.0.0/24

次に非公開のネットワークを作ります。OpenStackのインスタンスはまずこのネットワーク上に接続されて作られます。そのあとに上記の公開するネットワークからFloationg IPからIPアドレスを割り当てることで外部のネットワークと通信できるようになります。

neutron net-createでprivate-net1というネットワークを作ります。プライベートネットワークのIPアドレスは 192.168.10.0/24という範囲でネットワークを設定し、101から199まで指定します。 ゲートウェイは192.168.10.1を使います。

# neutron net-create private-net1
# neutron subnet-create --name private-net_subnet1 --enable-dhcp --allocation-pool start=192.168.10.101,end=192.168.10.199 --gateway 192.168.10.1 --dns-nameserver 8.8.8.8 private-net1 192.168.10.0/24

router-createで、router1という仮想ルーターを作ります。router-gateway-setでpublicネットワークにつなげます。publicネットワークでは、Floating IPから192.168.0.141というアドレスが付与されます。router-interface-addで、プライベートなネットワークにつなげます。private-net_subnet1のIPアドレス192.168.10.0/24で最初のアドレス192.168.10.1が使われます。先にゲートウェイを指定していたのと合っている必要があります。router-port-listとsubnet-showで確認できます。

# neutron router-create router1
# neutron router-gateway-set router1 public
# neutron router-interface-add router1 private-net_subnet1
# neutron router-port-list router1
# neutron subnet-show private-net_subnet1

インスタンスを起動

VMware Workstation PlayerでOpenstack Kiloを動かす手順に従ってインスタンスを起動しようとしました。しかし、--is-public と --location というオプションはないといわれ、イメージの登録ができません。

調べてみると、glanceはOpenStack kiloからOpenStack Libertyに変わったときにバージョンが上がってるようです。--os-image-api-version 1 というオプションをつけることでコマンドを使うことができました。

# glance --os-image-api-version 1 image-create --name cirros --is-public True --container-format bare --disk-format qcow2 --location http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img

バージョン2で使うときは、--is-publicを--visibility publicにすることと、--locationは対応するものがないので、イメージをあらかじめローカルにダウンロードしておいて--fileオプションを使って指定するとよいようです。

あとは手順書に従って、インスタンスを作って起動し、ロードバランサを作って動作確認しました。OpenStack KiloとMitakaでは画面が変わっていますが、対応するところはすぐわかると思います。

OpenStackのホストであるCentOS上で次のようにルーティングを設定すると、CentOSからOpenStackのインスタンスに接続できます。動作の確認ができるのでとても助かりました。

# route add -net 192.168.10.0/24 gw 192.168.0.141 br-ex

実際にロードバランサの動作を確認すると、Curlでアクセスしたときはweb_server01とweb_server02の表示が交互に出て、ちゃんとラウンドロビンで動作していることがわかります。

しかし、ChromeでアクセスしてShift-F5でリロードしてみると時々しか変わりません。ブラウザによって動作が異なるようです。原因はわかりませんでした。

インスタンスをKVMで起動

せっかく、VMware Workstation Playerを使ってOpenStackでもCPUの仮想化機能を使えるようにしています。そこで、OpenStackのインスタンスがKVMを使っているのかどうか確かめました。

デフォルトの状態では、OpenStackはQEMUを使ってインスタンスを動かしています。設定ファイルnova.confでvirt_type=kvmとすることで、KVMを使うように設定します。

/etc/nova/nova.conf

virt_type=kvm

実際にKVMが使われているかどうか、確認します。virsh listで、インスタンスのIdを確認して、virsh qemu-monitor-commandでinfo kvmとすることで確認できます。--hmpというのは、Human Monitor Protocolの略で、通常の人間がわかるコマンドを実行するということのようです。

kvm supportがenabledになっていれば、OpenStackのインスタンスでKVMが使われています。そこそこの速度で実行されているのではないでしょうか。

# virsh list

 Id    Name                           State
----------------------------------------------------
 2     instance-00000008              running
 3     instance-00000009              running
# virsh qemu-monitor-command --hmp 2 info kvm
kvm support:enabled

おわりに

neutronのコマンドにneutron lb-*というものと、neutron lbaas-*というものがあります。調べてみると、前者はLBaaS v1で後者はLBaaS v2というようです。v1とv2ではドライバから変わって、互換性はないそうです。v1は廃止予定になっています。せっかく覚えたのになんかもったいないですね。

VMware Workstation PlayerでOpenStack Mitakaを動かしてみた

はじめに

VMware Workstation Player上にOpenStack Mitakaをインストールしました。

OpenStackを気軽に試してみるには、Ubuntuを使うものとCentOSを使うものがあります。メモリーの必要量が少なかったりするので、CentOSを使うものにしました。

RDOとは、Red Hat系のOpenStackのコミュニティのこと。Packstackは、RDOで開発されているOpenStackのインストール作業や設定作業を自動化するインストーラーです。

ハードウェアの必要要件

CPUはVT-xもしくは、AMD-Vを備えたもの
メモリ4GB、6GB以上が望ましい

ここでは、VMware Workstation Playerを使って、仮想環境にOpenStackをインストールします。VMware Workstation Playerは、ホストのVT-x/AMD-Vをゲストから使えるようにする機能があります。これを使ってゲストOSをホストにしてOpenStackを動かしその上でゲストOS(インスタンス)を動かします。

開発環境

ホストOS Windows 10 Pro

VMware WorkStation Player 12.1.1

CentOS-7-x86_64-Minimal-1511.iso

インストールには、こちらのサイトを参考にさせていただきました。ほぼ、そのままでインストールしていきます。VMware Workstaion Playerの設定の仕方から始まって、OpenStackのロードバランサの設定まで細かく書かれてあります。大変参考になりました。

VMware Workstation PlayerでOpenstack Kiloを動かす手順

CentOSのインストール

CentOSは、手順書のとおりにインストールしました。

CentOSのダウンロードに1時間。インストールには20分ほどでインストールできました。Minimalインストールなので、インストール後net-toolsとntpをインストールしました。
NetworkManagerとはうまく共存できないようなので停止して代わりにnetworkサービスを使います。

ネットワークはOpenVSwitchを使います。ブリッジインターフェースを設定します。ホストのWindows 10 ProからOpenStackのホストのCentOSへアクセスするIPアドレスには、192.168.0.140を設定しました。

OpenStackのインストール

手順書を参考にインストールしました。

1つ変えたところは、次のコマンドでkiloのレポジトリをセットアップするのですが、

yum install http://rdo.fedorapeople.org/openstack-kilo/rdo-release-kilo.rpm

CentOSには、Mitakaのパッケージが用意されているので、次のコマンドでセットアップしました。

yum install -y centos-release-openstack-mitaka
yum install -y openstack-packstack

Packstackは、アンサーファイルを作って設定し、インストールします。

インストールには、OpenStackのコンポーネントをダウンロードしながらインストールするので時間がかかりました。

CentOSのインストールとOpenStackのインストールで2時間ほどで、OpenStackのDashboardを見ることができました。

自宅のネットワーク回線が遅いので、速ければもう少し早く終わると思います。

インストールの確認

インストールが正常に終了したところでhttp://192.168.0.140/dashboardにアクセスしてみました。

まだ、ネットワークの設定が終わっていないので、インスタンスを動かすことはできません。

OpenStackの設定ファイルは、/etcの下に散らばっているのですね。

詳細な手順書があったおかげでハマることなく動かすことができました。

次回、ネットワークの構成とインスタンスの起動までやってみます。

VMware Workstation Player 12.1.1でUbuntu 14.04を使うには

はじめに

2016/09/02追記
Ubuntu 16.04の場合は、Open VM Toolsを使い、設定するといいことがわかりました。

Ubuntuの16.04が出たということで、VMware Playerをどうしようか検討していた。

VWware Playerは、Ubuntu 15.04からVMware Workstation 12 Playerのサポートになったようです。
VMware Workstation 12 Player と次の製品との比較

そこで、VMware Workstation Player 12.1.1を使ってみることにしました。

ホストOSはWindows 7で、ゲストOSはUbuntu 14.04です。

共有フォルダ

VMware Workstation Playerにアップグレードして最初に確認したのは共有フォルダです。

案の定動きませんでした。メニューにある管理のVMware Toolsの再インストールを試してみたけれど、アップデートサーバにコンポーネントが見つかりませんでしたと出てインストールもできません。

調べてみると手動でインストールするしかなくて、次のところからtarファイルをダウンロードして解凍しisoファイルを取り出します。
http://softwareupdate.vmware.com/cds/vmw-desktop/ws/

ここの/12.1.1/3770994/windows/packages/tools-linux.tarをダウンロードしました。解凍するとVMware-tools-linux-10.0.6-3595377.isoというファイルが出てきます。

それを、VMware Workstation Playerの取り外し可能デバイスの接続で指定することでインストールしました。

共有フォルダは使えることがわかって一安心です。

ホストゲスト間のコピーペーストと画面の大きさ

VMware Toolsを入れたのはいいのですが、ホストゲスト間でコピーペーストができません。画面の大きさもマウスのドラッグで変えることができませんでした。Ubuntu 14.04ゲストのシステム設定のディスプレイのところから解像度を変えることで画面の大きさを変えることができました。

ネットワーク

ネットワークがつながらなくなっていた。
理由は、ネットワーク接続がブリッジになっていてVirtualBoxと共存したために問題が起きていました。
ネットワークアダプタの設定で、VirtualBox Host-Only Ethernet Adapterのチェックを外したら動きました。
ネットワーク接続がNATならば問題はないと思います。

ディスクの圧縮

ディスクが大きくなっていたので圧縮しようとした。
ゲストOS上でvmware-toolbox-cmdを使うらしいけれど、どこを探してもありません。
Ubuntuには、open-vm-toolsというパッケージが存在しているらしいことを知りました。VMwareがオープンソースにしたものでVMware自身もこちらを使うことを推奨しているそうです。そこで早速使ってみることに。

open-vm-toolsは、apt-getで入れる前にVMware Toolsをアンインストールしないといけませんでした。使ってわかったのですが、共有フォルダが使えません。vmware-toolbox-cmdというコマンドは存在して、sudo vmware-toolbox-cmd disk shrink / とすることでディスクを圧縮することができました。コマンドの指定方法が少し変えられているのか、disk shrinkと2つオプションを指定しないと動きませんでした。

Ubuntuのopen-vm-toolsのサポートをしている方は、vmhgfsドライバは今後VMwareからサポートされないから共有フォルダが動かなくても仕方ないといっています。
vmhgfs doesn't work with linux 3.13 kernel

でも、最新のVMware Tools 10.0.6で共有フォルダを使えることからサポートされないってことはないよね。

まとめ

  • Ubuntu 14.04ゲストで共有フォルダを使うには、最新のVMware Tools 10.0.6を使う必要があります。
  • VMware toolsは、メニューの管理のVMware Toolsの再インストールから行えません。手動でダウンロードしてisoファイルを取り出す必要があります。
  • VMware tools 10.0.6では、ホストゲスト間でコピーペーストが使えません。
  • 画面の大きさもマウスで変更することはできなく、ゲストのgnomeの設定で画面の大きさを変更することで行います。
  • VMware Toolsを手動でインストールすると、vmware-toolbox-cmdコマンドはありません。
  • Ubuntu 14.04にはopen-vm-toolsというパッケージが用意されていて、こちらにvmware-toolbox-cmdがあります。
  • open-vm-toolsでは共有フォルダが使えません。
  • ゲストOS内で、sudo vmware-toolbox-cmd disk shrink / とすることでディスクの大きさを圧縮できます。

Ubuntu 14.04をゲストOSとして使うには、VMware Player 7の方がいいと思います。VMware Workstation Playerでは、あちらを立てればこちらが立たずという状態です。

Ubuntu 14.04を使うときはVMware Playerを最新版に

Windows 7上のVMware Player 6.0.1でゲストOSのUbuntuを14.04にアップデートしました。ところが、共有フォルダが使えなくなってしまいました。

そこで、VMware Toolsを再インストールしてみましたが、動きません。症状は、再インストール時にコンパイルエラーがでています。

結局、VMware Playerを6.0.3にアップデートして、VMware Toolsを再インストールしたら使えるようになりました。

このときのVMware Toolsのバージョンは、9.6.1から9.6.2にバージョンアップしました。

Ubuntu 14.04を使うときは、VMware Playerを最新版にしましょう。

Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する

この記事は、
Windows 7上のVMware Playerにgdbでリモート接続する方法
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する
の1つです。

1. 実際にやってみると

実際にリモートデバッグをしてみると、いちいちセクションの情報を確認して値を設定することが非常に面倒なことがわかると思います。そこで、ゲストOS上でカーネルモジュールをロードする処理と、ホストOS上でgdbを設定する処理をシェルスクリプトで自動化してみます。

基本的にやっていることは、手作業でやっていたことを自動化しただけです。セクション情報をtext.txt、data.txt、bss.txtに保存して、それをゲストOSからホストOSにコピーします。それを使って、gdbの設定を行います。

2. プログラムの説明

load.shは、ゲストOS上でカーネルモジュールをロードするときに使います。

load.sh ---------------------------------------------------

#!/bin/bash

# modnameにカーネルモジュールの.koの名前を入れます。
modname='testmodule'

# devnameは、デバイスファイルの名前です。
devname='/dev/testmodule'

# my_majorにメジャー番号を入れます。
my_major=88

# locationは、VMwareで設定したホストOSにカーネルモジュールやソースをコピーするときの共有フォルダの名前です。
location='/mnt/hgfs/kazu'

# カーネルモジュールが存在すればアンロードします。
if [ -e /sys/module/$modname ]; then
    sudo rmmod $modname
fi

# カーネルモジュールをロードします。
sudo insmod ${modname}.ko

# デバイスファイルがなければ作ります。
if [ ! -e $devname ]; then
    sudo mknod $devname c $my_major 0
    sudo chmod a+rw $devname
fi

# セクション情報を保存します。
sudo cat /sys/module/${modname}/sections/.text >text.txt
sudo cat /sys/module/${modname}/sections/.data >data.txt
sudo cat /sys/module/${modname}/sections/.bss >bss.txt

# セクション情報をコピーします
cp text.txt $location
cp data.txt $location
cp bss.txt $location

# モジュールとソースコードをコピーします。
cp ${modname}.c $location
cp ${modname}.ko $location

--------------------------------------------------

gd.shは、ホストOS上でgdbをリモート接続するときに使います。break_pointに停止させたい関数の名前を設定します。

gd.sh ---------------------------------------------------------

#!/bin/bash
# gdb port number is required
# ./gd.sh number

# モジュールの名前をセットします。
module_name='testmodule'

# ソースの位置をセットします
source_location='/home/kazu/test'

# ブレークポイントを設定します。
break_point='my_ioctl'

# セクション情報を読み込みます。
text=`cat text.txt`
data=`cat data.txt`
bss=`cat bss.txt`

# gdbコマンドを.gdbinitファイルに設定します。
cat <<EOF >.gdbinit
set architecture i386:x86-64
target remote localhost:$1
add-symbol-file ${module_name}.ko $text -s .data $data -s .bss $bss
break $break_point
EOF

# ソースコードを設定した位置にコピーします。
cp ${module_name}.c $source_location

# gdbを実行します。
gdb

----------------------------------------------------

3. 使い方

ゲストOS上に、load.shを置いてください。そこで、

Ubuntu$ chmode +x load.sh

で実行可能にします。これは1度だけやればいいです。

ソースコードを編集した後、makeの後でload.shすることでモジュールのロードと、コピーがされます。

Ubuntu$ make
Ubuntu$ ./load.sh

ホストOSのCygwin上でgd.shを接続するポート番号とともに起動します。

Cygwin$ ./gd.sh 8864

GNU gdb (GDB) 7.6.50.20130728-cvs (cygwin-special)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-cygwin".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".

The target architecture is assumed to be i386:x86-64
0xffffffff8104d386 in ?? ()
add symbol table from file "testmodule.ko" at
        .text_addr = 0xffffffffa03da000
        .data_addr = 0xffffffffa03dc000
        .bss_addr = 0xffffffffa03dc360
Breakpoint 1 at 0xffffffffa03da0f1: file /home/kazu/test/testmodule.c, line 51.
(gdb)

このような表示になって、ゲストOSの実行が止まれば成功です。この状態でcontinueします。

(gdb) continue

その後、ゲストOS上でtestdriverを動かします。

Ubuntu$ ./testdriver

そして、次のようにmy_ioctlで実行が止まれば成功です。

Breakpoint 1, my_ioctl (file=0xffff8800240cdec0, count=32,
    buf=18446612132972596240) at /home/kazu/test/testmodule.c:51
warning: Source file is more recent than executable.
51      {
(gdb)

あとは、手作業で変数の値を見たりできます。面倒な作業が自動化できれば、カーネルモジュールの開発に集中できると思います。

4. 参考にしたサイト

この記事を作るときに、非常に多くのサイトを参考にさせてもらいました。ありがとうございます。もし、何か問題があったら、これらのサイトを参考にしてみてください。

リモートデバッグについて
VMwareのGDB機能を利用する
LinuxでLoadable Moduleをデバッグする
VMware
Qemu and the Kernel
The Kernel Newbie Corner: Kernel and Module Debugging with gdb
Debugging kernel modules
Debug-info for loadable kernel modules
■[Debian] VMwareでLinuxカーネルのデバッグ
Debugging Linux kernels with Workstation 6.0
Debugging Linux Kernel in VMWare with Windows host

カーネルモジュールについて
CS 686: Special Topic: Intel EM64T and VT Extensions (Spring 2007)

gdbの使い方について
gdbコマンド メモ
gdb の使い方・デバッグ方法まとめ

シェルスクリプトについて
UNIX & Linux コマンド・シェルスクリプト リファレンス

Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする

この記事は、
Windows 7上のVMware Playerにgdbでリモート接続する方法
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する
の1つです。

1. カーネルモジュールとそのソースコードをWindowsホストに送り込む

gdbを使ってカーネルモジュールをリモートデバッグするためには、モジュールそのものであるtestmodule.koとそのソースファイルであるtestmodule.cをWindows上で参照する必要があります。testmodule.koが持つシンボル情報、関数の位置が必要になることと、ソースコードを表示するためにソースコードが必要になるためです。

今回は、共有フォルダーを使って、その2つをWindowホストに送り込みます。VMware Playerの設定でkazuというディレクトリがCygwinの/home/kazuを指し示しているとします。Ubuntu 13.04上でファイルを2つコピーします。共有フォルダは/mnt/hgfs/kazuにマウントされているとします。

ubuntu$ cp testmodule.ko /mnt/hgfs/kazu/
ubuntu$ cp testmodule.c /mnt/hgfs/kazu/

testmodule.koというモジュールは、gdbを起動するディレクトリに置きます。
また、testmodule.cというソースは、Cygwin上でLinuxのソースディレクトリと全く同じ位置に置きます。
つまり、Ubuntu 13.04上で/home/kazu/testというディレクトリでモジュールを作った場合、Windows上のCygwinで/home/kazu/testというディレクトリにtestmodule.cはなくてはいけません。

cygwin$ cp testmodule.c /home/kazu/test/

このとき、今回はやっていませんが、共有フォルダをうまく使うとWindows上でコピーする手間が省けます。

2. カーネルモジュールのロードされた位置情報を確認する

ゲストOS上で、/sys/module/モジュール名/sections/ディレクトリにある.text、.data、.bssというファイルにカーネルモジュールの各セクションの開始アドレスが保存されています。それを確認します。このときのポイントは、スーパーユーザーでファイルを見ることです。そうしないと、0x0000000000000000という値になって確認できません。

ubuntu$ sudo cat /sys/module/testmodule/sections/.{text,data,bss}
0xffffffffa030c000
0xffffffffa030e000
0xffffffffa030e360

上から順に、.text、.data、.bssセクションのアドレスになります。.textセクションには、関数の開始アドレスが入っています。C言語のソースコードで、関数の外側にあるグローバル変数は.bssセクションに値が保存されます。また、初期値が設定してあるものは.dataセクションに値が保存されます。そのため、gdbで値を表示するためには、それらのセクションの先頭アドレスを指定しないと値を表示することができません。

3. gdbでリモートデバッグを開始する

今度は、ホストOSのCygwinのターミナルで、gdbを起動します。set architectureでターゲットとなるアーキテクチャーが64bitであることを設定します。target remoteで接続します。ポート番号は、最初は8864で、2回目からは8865になります。

cygwin$ gdb
(gdb) set archi i386:x86-64
The target architecture is assumed to be i386:x86-64
(gdb) tar rem :8864
Remote debugging using :8864
0xffffffff8104d386 in ?? ()

次に、add-symbol-fileというgdbのコマンドで、カーネルモジュールのシンボル情報をロードします。このとき、-sオプションを使って先に確認した.dataと.bssセクションの開始アドレスを使います。アドレスや、セクション名を間違えやすいので注意してください。

(gdb) add-symbol-file testmodule.ko 0xffffffffa030c000 -s .data 0xffffffffa030e000 -s .bss 0xffffffffa030e360

Reading symbols ...done.と表示されたら成功です。

add symbol table from file "testmodule.ko" at
        .text_addr = 0xffffffffa030c000
        .data_addr = 0xffffffffa030e000
        .bss_addr = 0xffffffffa030e360
(y or n) y
Reading symbols from /cygdrive/c/mingw64/msys/1.0/home/kazu/testmodule.ko...done.
(gdb)

次に、停止させたい関数の名前をブレークポイントに登録します。今回は、my_ioctlで停止させます。

(gdb) break my_ioctl
Breakpoint 1 at 0xffffffffa030c0f1: file /home/kazu/test/testmodule.c, line 51.
(gdb)

ブレークポイントが設定されました。
この状態でcontinueでゲストOSに制御を移します。

(gdb) continue

ゲストOSでの操作が可能になったと思います。そして、Ubuntuの中でtestdriverを動かしてみます。testdriverは、ioctl()を使ってカーネルモジュールを呼び出します。

Ubuntu$ ./testdriver

すると、ゲストOSの実行が停止して、ホストOSのCygwin上で次のように表示されます。

Breakpoint 1, my_ioctl (file=0xffff880027111ec0, count=32,
    buf=18446612133350149392) at /home/kazu/test/testmodule.c:51
warning: Source file is more recent than executable.
51      {
(gdb)

ブレークポイントで停止します。このとき、ソースコードをコピーして使っているためにwarningがででいますが、無視してください。これで、カーネルのソースコードを表示したり変数を確認することが可能になりました。

4. カーネルの変数を確認する

まず、listコマンドでソースコードを表示してみます。

(gdb) list
46              printk("<1>\nRemovind %s \n", modname);
47      }
48
49      // ユーザーモードのプログラムで、ioctl()を使ったときに呼び出されます。
50      long my_ioctl( struct file *file, unsigned int count, unsigned long buf)
51      {
52              int i;
53
54              i = 1;
55              global_data = 2;
(gdb)

では、1行ずつ実行してみましょう。nextまたは、nで実行できます。1行実行した前後で、countの値を見てみます。

(gdb) print count
$1 = 32
(gdb) next
54              i = 1;
(gdb) print count
$2 = 100
(gdb)

ブレークポイントで止まった直後は、引数の値が設定されていないために、countは32でした。1行実行して関数の中に入って100に変わりました。この100は、testdriver.cでioctl()を呼んだとき、100バイトと指定してあったものです。また、bufの内容を見てみましょう。x/sと打ち込みます。xは、メモリーを検査するコマンドで、sで文字列として表示します。

(gdb) x/s buf
0x7fff0e9c3b10: "Hello!"
(gdb)

testdriver.cで設定したHello!の文字が見られます。もしくは、print (char *)bufとすることでも表示できます。(char *)にキャストするのは、my_ioctlでbufは、unsigned longになっているためです。

(gdb) print (char *)buf
$15 = 0x7fff0e9c3b10 "Hello!"
(gdb)

つぎに、ローカル変数iとグローバル変数global_dataの変化を調べます。まず、iとglobal_dataを表示しても値が設定されていないので値は何が入っているかわかりません。

(gdb) print i
$2 = -1
(gdb) print global_data
$3 = 0
(gdb)

1行実行すると、iに値が設定されていきます。このとき、55行目のソースコードが表示されますが、これは現在実行したコードではなく、次に実行するコードという意味です。

(gdb) next
55              global_data = 2;
(gdb) print i
$4 = 1
(gdb)

iが1に設定されました。また実行すると、global_dataに値が設定されます。

(gdb) next
56              printk("<1>\n%s is called! \n", modname);
(gdb) print global_data
$5 = 2
(gdb)

global_dataが2になりました。このように1行ずつ実行して値の変化を調べることができます。

4. リモートデバッグの終了

disconnectコマンドで、接続を切断してquitで終了します。

(gdb) disconnect
(gdb) quit

で終了できます。

5. 再接続

add-symbol-fileは、シンボルの再ロードに対応していないようです。ソースコードを修正してもう1度デバッグをするためには、gdbを終了してからもう一度接続する必要があります。

ソースコードを変更した後は、コンパイルします。その後、ロードされているモジュールをアンロードしてから新しいモジュールをロードします。セクション情報を確認します。

Ubuntu$ make
Ubuntu$ sudo rmmod testmodule
Ubuntu$ sudo insmod testmodule.ko
Ubuntu$ sudo cat /sys/module/testmodule/sections/.{text,data,bss}
Ubuntu$ cp testmodule.ko /mnt/hgfs/kazu/
Ubuntu$ cp testmodule.c /mnt/hgfs/kazu/

ソースコードを配置した後、gdbを立ち上げてもう一度同じことをします。ソースコードを変更してカーネルモジュールを再ロードすると、add-symbol-fileのセクション情報が毎回変わってきますので注意してください。

$ cp testmodule.c /home/kazu/test/
$ gdb
(gdb) set archi i386:x86-64
(gdb) tar rem :8865
(gdb) add-symbol-file testmodule.ko 0xffffffffa030c000 -s .data 0xffffffffa030e000 -s .bss 0xffffffffa030e360

このような流れになります。
このときVMware Playerのバグで、8865番になっていることに注意してください。一度8865番になると次は変わらないようです。接続できないときは、起動したゲストOS用の.logファイルを確認してください。

6. うまくリモートデバッグできないときに確認すること

まず、gdbがうまく接続できているかどうか。
.vmxファイルにgdbstubの設定がされているか。
gdbを動かしたときのポート番号があっているか.logファイルで確認する。

ソースコードがgdb上でうまく表示されないときに確認すること。
ソースコードが-g -O0オプションつきでコンパイルしているか。Ubuntu 12.04とUbuntu 12.10では、-O0オプションをつけてコンパイルすることはできませんでした。
ソースコードはコンパイルしているか。
カーネルモジュールはホストOSにちゃんとコピーできているか。
ソースコードを変更したときは、ゲストOSからホストOSにちゃんとコピーできているか。
ソースコードは、LinuxとCygwinで同じ位置に置かれているか。
add-symbol-fileでセクション情報を正確に設定できているか。ソースを変更したときは、gdbを再起動しないといけません。セクション情報も変わっているはずです。

いろいろと落とし穴があります。このようなことをチェックしてください。

次に続きます。
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する

Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する

この記事は、
Windows 7上のVMware Playerにgdbでリモート接続する方法
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する
の1つです。

まず、gdbがVMwareにリモート接続できることを確認してください。

1. デバッグに使うソースコードの説明

今回は3つのソースを用意しました。testmodule.cというモジュールを作りました。このモジュールは、メジャー番号88番でキャラクターデバイスを登録してioctlを処理するモジュールです。
また、Makefileは、そのモジュールをコンパイルするための物です。testdriver.cは、モジュールをテストするために使うユーザーモードのプログラムです。

testmodule.cは次の通りです。モジュールをロードするときに呼ばれるinit_module()とアンロードしたときに呼ばれるcleanup_module()があります。また、ユーザーモードのプログラムでioctl()を実行されたときに呼び出されるmy_ioctl()という関数があります。

file_operations構造体のunlocked_ioctlというメンバー変数にmy_ioctlを設定してregister_chardev()で登録することで、ユーザーモードのプログラムがioctl()を使ったときにカーネルモジュールのmy_ioctl()が実行されます。

init_module()内でregister_chardev()を呼び出す事でメジャー番号88番のキャラクターデバイスを登録しています。また、cleanup_module()のunregister_chardev()でデバイスの登録を解除しています。

testmodule.c -------------------------------------------------------

/*
  testmodule.c
  Linux test driver kernel module
  character device major=88 minor=0

  sudo insmod testmodule.ko
  sudo mknod /dev/testmodule c 88 0
  sudo chmod a+rw /dev/testmodule
*/

#include &amp;amp;amp;lt;linux/module.h&amp;amp;amp;gt;
#include &amp;amp;amp;lt;linux/fs.h&amp;amp;amp;gt;		// for struct file_operations

// modnameにモジュールの名前を設定します。また、my_majorの88番がデバイスの番号です。
char modname[] = &amp;amp;amp;quot;testmodule&amp;amp;amp;quot;;
int my_major = 88;

long my_ioctl( struct file *, unsigned int, unsigned long );

// ユーザーモードのプログラムがioctl()を使ったときにmy_ioctl()を呼び出すよう設定します。
struct file_operations
my_fops =	{
		owner:		THIS_MODULE,
		unlocked_ioctl:		my_ioctl,
		};

// グローバル変数です。
int global_data;

// モジュールをロードしたときに呼び出されます。
int init_module(void)
{
	printk(&amp;amp;amp;quot;\nInstalling %s \n&amp;amp;amp;quot;, modname);
	printk( &amp;amp;amp;quot;(major=%d) \n&amp;amp;amp;quot;, my_major );

	// 設定した名前と番号で、キャラクターデバイスを登録します。
	return register_chrdev( my_major, modname, &amp;amp;amp;amp;my_fops );
}

// モジュールをアンロードしたときに呼び出されます。
void cleanup_module(void)
{
	// キャラクターデバイスの登録を解除します。
	unregister_chrdev( my_major, modname );

	printk(&amp;amp;amp;quot;\nRemovind %s \n&amp;amp;amp;quot;, modname);
}

// ユーザーモードのプログラムで、ioctl()を使ったときに呼び出されます。
long my_ioctl( struct file *file, unsigned int count, unsigned long buf)
{
	int i;

	i = 1;
	global_data = 2;
	printk(&amp;amp;amp;quot;\n%s is called! \n&amp;amp;amp;quot;, modname);

	return 0;
}

MODULE_LICENSE(&amp;amp;amp;quot;GPL&amp;amp;amp;quot;);

-------------------------------------------------------------------

これをコンパイルするMakefileは、次の通りです。

Makefile ------------------------------------------------

ifneq	($(KERNELRELEASE),)
obj-m	:= testmodule.o
ccflags-y	:=-g -O0

else
KDIR	:= /lib/modules/$(shell uname -r)/build
PWD	:= $(shell pwd)
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
	rm -r -f .tmp_versions *.mod.c .*.cmd *.o Module.symvers modules.order

endif

----------------------------------------------------------

Linuxのバージョン3.0になって、Makefileの作り方が少し変わったようです。KERNELRELEASEに値が設定されているかどうかで、2つの部分に分かれます。カーネルを作る時のkbuildというシステムは、KERNELRELEASEに値が設定されているときだけを見るようです。値がないときの設定は、ふつうのmakeが処理するのだそうです。モジュールをコンパイルするときのフラッグを設定するときに、以前はEXTRA_CFLAGSを使っていたと思いますが、ccflags-yに変わったようです。もしくは、モジュールの名前をつけてtestmodule-yとします。
ccflags-yに-gをつけることで、デバッグ情報をカーネルモジュールに埋め込みます。
また、-O0(オーとゼロ)をつけることで、gdb上でステップ実行したときに1行ごとに実行することができます。

このカーネルモジュールをテストするユーザーモードのプログラムが、次のtestdriver.cです。
/dev/testmoduleというデバイスを開いて、ioctl()でHello!という文字列を送り込みます。

testdriver.c -----------------------------------------------

/*
  testdriver.c
  Test testmodule.c
*/

#include  // for printf(), perror()
#include  // for open()
#include  // for exit()

char devname[] = &amp;amp;amp;quot;/dev/testmodule&amp;amp;amp;quot;;

int main(void)
{
    int fd;
    int retval;
    char buf[100] = &amp;amp;amp;quot;Hello!&amp;amp;amp;quot;;

    fd = open(devname, O_RDWR);
    if (fd &amp;amp;amp;lt; 0) {
        perror(devname);
        exit(1);
    }
    retval = ioctl(fd, sizeof(buf), &amp;amp;amp;amp;buf);

    return 0;
}

---------------------------------------------------------------

2. ゲストOSでLinuxカーネルモジュールを作る

ゲストOS上でLinuxカーネルモジュールをつくります。

3つのファイルを、Ubuntu 13.04内の同じディレクトリにおいてください。そしてmakeします。

$ make

これでtestmodule.koというファイルができたら成功です。

3. ユーザーモードのプログラムを作る

ゲストOS上で、ユーザーモードのプログラムを作ります。

$ gcc testdriver.c -o testdriver

とすることで、testdriverというプログラムができれば成功です。

4. 動作確認をする

まず、カーネルモジュールをロードします。モジュールのロードには、スーパーユーザーの権限が必要ですのでsudoを使います。insmodでロードできます。また、ロードされたかどうかlsmodで確認できます。

$ sudo insmod testmodule.ko
$ lsmod |grep testmodule
testmodule 12952 0

次に、ユーザーモードのプログラムからカーネルモジュールにアクセスするためのデバイスファイルを作ります。testmodule.cで登録したキャラクターデバイスで88番のデバイスファイルを作ります。ユーザーモードのプログラムがアクセスできるように読み書きの権限をつけておきます。

$ sudo mknod /dev/testmodule c 88 0
$ sudo chmod a+rw /dev/testmodule

これで、準備はできたので、testdriverをうごかします。

$ ./testdriver

なにもエラーが表示されなければ成功です。本当に実行されたかどうか、ログファイルで確認することができます。less /var/log/kern.logと打って出てきた画面で大文字のGを押してください。ログファイルの最後尾を見ることができます。

$ less /var/log/kern.log

Apr 11 20:51:22 Mars kernel: [ 1913.498362] Installing testmodule
Apr 11 20:51:22 Mars kernel: [ 1913.498366] (major=88)
Apr 11 20:56:28 Mars kernel: [ 2219.260167]
Apr 11 20:56:28 Mars kernel: [ 2219.260167] testmodule is called!

このように、testmodule is called!と表示されているはずです。

5. 後始末をする

ロードしたカーネルモジュールは、ゲストOSを再起動するとロードされなくなりますが、次のようにするとアンロードできます。

$ sudo rmmod testmodule

また、作ったデバイスファイルは削除することができます。

$ sudo rm /dev/testmodule

これで、リモートデバッグをするカーネルモジュールを用意することができました。

次に続きます。
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする

Windows 7上のVMware Playerにgdbでリモート接続する方法

この記事は、
Windows 7上のVMware Playerにgdbでリモート接続する方法
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(2) - リモートデバッグする
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(3) - 自動化する
の1つです。

1. 用意するもの

Windows 7上のVMware Playerで、Linuxのデバイスドライバをリモートデバッグしてみました。デバッグするのに少しコツが必要なので紹介します。

64bitのデバッグをしてみたかったので、全部64bitでそろえてみました。Windows 7は、x64版です。VMware Playerは、32bitと64bitの区別がないようでした。Cygwinは、setup-x86_64.exeをつかって、64bit版をインストールしました。gdbのみ使います。Windows上のgdbとしては、MinGW-x64の物もあるのですが、Ctrl-CでゲストOSの実行を止められないのでCygwinのものを使いました。バージョンによっては、Mingwの物でもいいかもしれません。ゲストOSとしては、Ubuntu 13.10 64bit版をインストールしました。

Windows 7 x64 (ホスト)
VMware Player 6.0.1
Cygwin 64bit
Ubuntu 13.10 64bit (ゲスト)

Cygwinは、32bitでもいいと思いますが、確かめていません。

2. VMware Playerの設定

WindowsにVMware PlayerとCygwinをインストールします。その後、VMware PlayerにUbuntuをインストールします。
全部インストールが終わったところで、ゲストOSの設定ファイルの.vmxファイルに以下の設定を追加します。

debugStub.listen.guest64 = &quot;TRUE&quot;
debugStub.listen.guest64.remote = &quot;TRUE&quot;
debugStub.hideBreakpoints = &quot;TRUE&quot;
monitor.debugOnStartGuest64 = &quot;TRUE&quot;

これでVMware Playerを起動すると、サーバーとして通信していいかを聞くダイアログボックスが現れると思います。許可します。これで、ポート8864番でgdbの接続を待ってくれます。複数のゲストを同時に立ち上げたときは、ポートの番号が8865、8866と増えていきます。もし、32bitのゲストOSの場合は、guest64のところがguest32になって8832番になります。

3. gdbの接続の確認

ゲストOSを起動します。そうしたら、Cygwinのコンソールで、gdbを起動します。そのgdbの中で以下のコマンドを打ち込みます。

(gdb) set architecture i386:x86-64
(gdb) target remote localhost:8864

コマンドは、短縮が可能で以下でもいいです。

(gdb) set archi i386:x86-64
(gdb) tar rem :8864

set architectureは、これからデバッグするゲストOSのモジュールが64bitの物であることを指示します。target remoteは、VMware Playerにポート番号8864番で接続してくださいという命令です。

(gdb) set architecture i386:x86-64
The target architecture is assumed to be i386:x86-64
(gdb) tar rem :8864
Remote debugging using :8864
0xffffffff8104d386 in ?? ()
(gdb)

こんな風に、0xffffffffなんとかと出て、ゲストOSの実行が止まってフリーズしたら成功です。

4. ゲストOS実行の再開

Cygwinのコンソールで、cまたは、continueと打ち込みます。

(gdb) c

とすると、ゲストOSが動き出して操作できるようになると思います。

また、CygwinのコンソールでCtrlキーとCキーを同時に押すと、また0xfffffffffなんとかとでて止まります。

(gdb) c
Continuing.

Program received signal SIGINT, Interrupt.
0xffffffff8104d386 in ?? ()
(gdb)

5. 終了の仕方

gdbで接続している状態で、gdbをquitしてしまうと、ゲストOSが強制終了してしまいます。まず、gdbの接続を切断します。disconnectと打つと次のようになります。disconnectの短縮形はdisconまで打ち込んでください。disだけだと、disableと混同してしまいます。

(gdb) disconnect
Ending remote debugging.
(gdb)

その後でゲストOSを終了します。

6. 再接続の仕方

gdbは、再接続することもできます。

(gdb) tar rem :8865

と打ち込みます。このとき、VMware Player 6.0.1には1度disconnectした後で、ポートが8865になるバグがあるようです。最新の.logファイルで確認することができます。

2014-04-09T16:47:19.737+09:00| vmx| W110: Debug stub: VMware Player is listening for debug connection on port 8865.

一度8865番になると、その後は変わらないようです。その場合は、

(gdb) disconnect
Ending remote debugging.
(gdb) tar rem :8865

とすることでもう1度つなげることができます。

なお、32bitの場合は、8832が8833番になるようです。.logファイルで確認してください。

次のようにすると終了できます。

(gdb) disconnect
Ending remote debugging.
(gdb) quit

次の記事に続きます。
Windows 7上のVMware PlayerでLinuxのデバイスドライバをリモートデバッグする方法(1) - デバッグするカーネルモジュールを用意する