WinDBG によるデバッグ方法(ダイジェスト)

Visual Studio のプロジェクトが存在せず、nmake や cl などを使ってビルドされる C/C++ プログラムをデバッグしようとして、いろいろ困ったのでメモ。


1. WinDBG のインストール

Windows SDK をインストールすれば一緒に入ってくる。

2. プログラムは /Zi オプション付きでコンパイルする。(デバッグ情報が .pdb ファイルとして生成される)

3. WinDBG を起動し、File > Open Source File ... でとりあえず main 関数のあるソースファイルを開く

4. File > Symbol File Path ... で .pdb ファイルのあるディレクトリを指定

5. File > Open Executable ... でデバッグ対象の .exe ファイルを開く。この時、ファイルオープンダイアログの左下にコマンドラインオプションや実行時ディレクトリを指定できる。

6. Locals(ローカル変数のウォッチ)、Calls(コールスタック)、Watch、Command などいろいろなビューを開きまくる。ワークスペースを保存しておくと後で嬉しいかも。

7. Command ウインドウで以下のようなコマンドでとりあえず頑張る
bp ブレークポイントを設定。何はともあれ bp main
Debug > Resolve Unqualified Symbols にチェックを入れておいたほうがよいかも
g で実行開始
p で step over
t で step in
ソースウインドウで F9 (Breakpoint 設定) / F10 (Step Over) / F11 (Step In) でもよいかも


8. コマンドラインオプションを変えて起動し直したい(ブレークポイントやウォッチ式などはそのまま残したい)場合や起動時ディレクトリを変えたい場合は、g コマンドなどでプログラムをいったん終了させるか .kill コマンドで強制終了させてから .createdir や .create を使用する。


とここまで頑張ったけど、Visual Studio で快適にデバッグできる方法があったりして・・・ガクブル


pykd とか mona.py を使うための布石だもんね・・・(強がり)

Windows の PATH 環境変数の各パスは ” ” (ダブルクオーテーション)で囲まなくても良い ー むしろ囲っちゃダメ

Visual C++コンパイラコマンドラインから起動しようとして、その準備として vcvarsall.bat を実行しようとしてハマったのでメモ。

vcvarsall.bat は cl.exe などの置かれているディレクトリへのパスを環境変数として設定したりするバッチファイルですが、これを実行したところ、以下のようなエラーになってしまいました。

> vcvarsall.bat
"~~~" の使い方が誤っています。

このあと、PATH 環境変数の中身と思わしきものがダーッと表示されてしまい、cl.exe などへはパスが通りませんでした。

Visual Studio に付属の Developer Command Prompt を立ち上げても同じエラーです。

いろいろ調べたところ、"C:\Program Files (x86)\Hoge Fuga\bin" みたいにパスをダブルクオーテーションで囲んだものを指定していて、かつ、その囲まれたパスの中に ( )(丸カッコ) が含まれているときにこのようなエラーになるようです。

カッコが含まれないパスはダブルクオーテーションで囲んであってもエラーにはならないようですが、そもそも PATH 環境変数はセミコロンで区切るのでパスの中に空白が含まれていても問題はなく、ダブルクオーテーションで囲む意味がないので、この際なのでダブルクオーテーションは全部取ってしまいました。


それにしても、Windows の PATH 環境変数は設定しづらいですよね、、、
設定ダイアログを出すまでの手順が多すぎるし、設定ダイアログの UI が最悪です。(どうして一行しか表示できない小さなテキストボックスで編集しないといけないんだ・・・)

Rapid Environment Editor というソフトを使ってみたところ、らくらく編集できました。

Cygwin の PATH 文字列と Windows の PATH 文字列の相互変換

答えを先に書くと、cygpath コマンドを使います。

Cygwin の形式(/cygdrive/c/... )→ Windows 形式(C:\... )

$ cygpath -w /cygdrive/c
C:\

Windows 形式 → Cygwin 形式

$ cygpath C:\\
/cygdrive/c


Cygwin から Windows のプログラムを起動しようとする場合、そのようなプログラムは Windows 式のパスしか受け付けない可能性が高いので、このように変換してやる必要があります。
逆に Windows 用のプログラムがファイルに書いたパスなどを読み取って Cygwin 側で処理したい場合もこのように変換する必要がありますね。


cygpath コマンドは、ルールに則って文字列を変換するだけのようなので、実在していないパスでも変換してくれるようです。

cygpath -w /a/b/c
C:\CygWin\a\b\c

エレクトロラックス エルゴラピード

コードレス掃除機を探していて、コストコで見つけたのがこちら:

エレクトロラックス エルゴラピード


型番は ZB2901 というものなので一世代前のものだと思いますが、コストコでは 1万2,800円くらいで売っていました。
( ネットで探した最安価格より1,000円以上安いですね。さすがコストコ

価格も手頃だったのですが、数週間使ってみてこれは本当に買ってよかったと思える製品でした。
もともとメインの掃除機(国内メーカー製の紙パック式掃除機)があってサブの掃除機を探していたので、期待値がそれほど高くなかったというのもあるかもしれませんが、メインの掃除機を使わなくなりそうな勢いです。

このエルゴラピードを買った時、我が家ではこんな視点で掃除機を探していました。

コードレスだけどパワフル

我が家は3階建ての戸建て住宅で各階の面積はそれほど広くないのだけど、どこか一箇所のコンセントだけでは家中に掃除機を掛けることができません。各階に移動するたびにコンセントの抜き差しが発生します。各階だけではなく階段にも掃除機を掛けるとなると、階段を下から上まで掃除し終わったあとに元いた階に戻ってコンセントを抜くといった作業が発生してしまいます。それで、コンセント抜き差し問題を解決してくれそうなコードレスという点は必須条件で探していました。

ただ、コードレスのイメージは「吸引力が貧弱」というものでした。
その点、この掃除機はサイクロン式ということもあるのだと思いますが、十分すぎる吸引力です。
メインの掃除機を掛けたあとにこの掃除機をもう一度掛けてもダストカップにしっかりホコリが溜まっているくらいです。

ルンバなどのロボット掃除機にも興味はありましたが、3フロアに分かれていると3台買わないと全フロアをカバーできないわけですが、主に金銭的な理由でそういうわけにもいきません。
また、ホコリやゴミが目についたときとかに結局自分の手で掃除したくなっちゃうと思うので、そういう時は手軽に使える掃除機がやっぱり欲しくなりそうな気がします。
それよりなにより、我が家には1歳の赤ちゃんがいるのでロボット掃除機は時期尚早かなとも思いました。(掃除機と戦って壊しそうという意味でw)

デザインがいい

日本メーカーの白物家電は・・・(以下略
エレクトロラックススウェーデン発祥のメーカーなので、北欧デザインの本体はインテリアとしてもオシャレな感じがします。

この製品を実際に買って使ってみてから気づいた点

  • 2 in 1
    • 買う前に気づけ、と言われてしまうかもしれませんが、このエルゴラピードは掃除機のメインユニット部分だけをカパッと取り外して、ハンディタイプにもなるのです!(本体に書かれている 2 in 1 の由来でもある)ハンディ部分は車の掃除などに使えるので便利です。
  • LED ライト
    • ノズルの前面に LED ライトが付いているので、暗いところを照らしてくれます。隅っこの方に落ちてるゴミなどが見えやすくて意外と便利です。
  • 簡単に使いはじめられる
    • 奥さんが一人で充電ステーションなどをセットアップして使えました。掃除が終わったらダストカップを外してフィルタを掃除したりしないといけないのですが、それもなんの迷いもなくできていました。

結論

というわけで、この掃除機はとってもおすすめです。

xinetd で走らせてるサービス(デーモン)の状態を知る方法

xinetd でどのポートでどのサービスを動かしていたかをお手軽に調べたりしたい場合の方法をメモ。

http://superuser.com/questions/318040/how-to-get-status-information-form-xinetd より。

$ sudo pkill -USR1 -x xinetd
$ cat /var/run/xinetd.dump

USR1 というシグナルを xinetd に送ると /var/run/xinetd.dump にダンプされる。

これで見られる情報は各サービスの設定ファイルに書いた以上のものはあまりないのだけれど、現時点で動いているサービスの情報を一覧して見られるのは便利といえば便利。

渋谷でレゴブロック売ってない問題

[2015.01.29追記]

以下の記事によると、2月5日にビックカメラ渋谷東口店がリニューアルすると玩具売場ができ、レゴも販売されるようです。これは楽しみです。オープンしたらチェックしに行こうと思います。


渋谷駅東口にビックカメラ「別館」-スポーツ用品初展開 - シブヤ経済新聞


そういえばドン・キホーテにもレゴがちょっとだけ置かれていましたね。
ビックカメラにレゴ売り場ができればそれには見劣りする感じかと思いますが。



プログラマならたいていの方は何らかの理由をつけてレゴブロックを仕事に持ち込みたいと考えていると思います。
私もその口です。

私の手口は、

1. ブレストなどを主催し、参加者にアイディアをたくさん出してもらって、それを紙に書いてもらう
2. 紙に書かれたたくさんのアイディアを壁一面に貼っていく時に磁石が必要ということにする(幸いオフィスの壁には磁石がくっつく)
3. アスクルで買ったような無難な磁石じゃせっかくのいいアディアも台無しだから(詭弁)、http://isogawa.asablo.jp/blog/2011/01/12/5634353
を参考にレゴを磁石にして貼り付けよう、うんそうしよう、みんなの中の子供心を刺激していいアイディアを思いついてもらおう

という三段論法で行こうと思い、レゴを入手したいと思いました。

磁石は、こんなこともあろうかと過去に個人で100個ほど購入していたのを供出することにしたので、あとはレゴを購入すれば良いだけの簡単なお仕事です。


ところが!!

私の職場のある渋谷で、レゴを買おうとしたら大変困ったことになりました。

駅近のヤマダ電機とかビックカメラでレゴを売っていないのです。新宿だったらありそうなのに。
東急ハンズにもパルコにもマルイにも西武にも109にもヒカリエにもレゴは売られていません。(探しに行きましたが見つけられませんでした)

東急百貨店本店のおもちゃ売り場でようやくレゴを見つけましたが、おもちゃ売り場自体がこじんまりとしていてフロアのほんの一角でしかなく(上のフロアのジュンク堂書店が1フロア全体を占めていてものすごいワクワク感を放っているのとは対照的)、レゴはさらにその中のごくわずかのスペースを占めているだけでその他のおもちゃと一緒に申し訳程度にそろえてあるというくらいの品揃えで、せっかくのレゴ売り場なのにワクワク感がありません。

というわけで、正確にはレゴを売っているお店は皆無というわけではないのですが、品揃え豊富なお店が無いのです。
最低でもクリックブリックくらいの品揃えはほしいところです。
欲を言えば海外のレゴショップくらいの規模のお店が日本にもほしい・・・


「(渋谷で)ここにならレゴ売ってるよ!」というみなさまからの情報をお待ちしております。

テキストファイルの中に書かれた数字をコマンドラインで集計する方法

何らかの文字で区切られたデータファイルがあって、その中の特定のカラムの合計を計算したいとします。

たとえばデータファイルは以下のような感じです。

$ cat datafile.dat
data1: 0, 123, 222, "some text"
data34: 11, 3, 24, "another text"
data209: 456, 99, 76, "hoge fuga"
  :

この中の、"text" という文字列が含まれている行だけ、123, 3, ... と縦に並んでいる部分を合計したいとします。

そこで、まず "text" という文字列が含まれている行だけを grep で抜き出します。

$ cat datafile.dat | grep text
data1: 0, 123, 222, "some text"
data34: 11, 3, 24, "another text"
  :

次に、123, 3, ... の列だけ抜き出します。

$ cat datafile.dat | grep text | cut -f 3 -d ':' -d ','
 123
 3
  :

awk でもできると思いますが cut を使ってみました。
'-d' を繰り返すことで区切り文字を複数指定できます。(上記の例では : を区切り文字にしなくても -f 2 -d ',' でもうまく行くと思いますが、あくまでも例なので、、、)
空白も取り除きたければ -d ' ' として空白も区切り文字に入れてしまうこともできます。

これを足し算の式にします。

$ cat datafile.dat | grep text | cut -f 3 -d ':' -d ',' | paste -sd+
 123+ 3 ...

最後に bc に食わせて計算します。

$ cat datafile.dat | grep text | cut -f 3 -d ':' -d ',' | paste -sd+ | bc
5586

以上、自分用メモでした。

boot2docker で Docker の使用するポートが CrashPlan と競合するときの対処法

OS X で Docker を使えるようになったとのことだったのですが、私の環境でも下記の記事と同じように CrashPlan がインストールされていたのでポートが競合してしまい、boot2docker init がエラーになってしまいました。

$ boot2docker init
[2014-02-15 15:35:15] DOCKER_PORT=4243 on localhost is used by an other process! Change the port to a free port.

OS XでDockerをインストール(by boot2docker)時に競合するCrashPlanのポートを4243から変更する方法 - akiyan.com

この記事では CrashPlan の使用する方のポート番号を変更していましたが、私は Docker のほうが使用するポート番号を変えてみました。

やり方は以下のとおり。

$ mkdir -p ~/.boot2docker
$ echo "DOCKER_PORT=42430" >> ~/.boot2docker/profile

今回はデフォルトの 4243 から 42430 に変更しましたが、基本的には ~/.boot2docker/profile というファイルに DOCKER_PORT=xxxx という行を書くだけです。

boot2docker init コマンド実行時のエラーメッセージでこのことを説明するような Pull Request が取り込まれていたので、そのうち親切なエラーメッセージが表示されるようになるでしょう。

RSA 秘密鍵/公開鍵ファイルのフォーマット

openssl コマンドで生成される RSA 秘密鍵ファイルのフォーマットの中身が気になったので調べてみた。
初心者にわかりやすく説明されたサイトが意外と見当たらなかったようなのでまとめておく。

まず、鍵の生成に使ったコマンドはこんな感じ:

$ openssl genrsa 2048 > rsaprivate.key

2048 というのは鍵の bit 数。

以下の説明では、あまり長い鍵だとわかりにくくなっちゃうので短くして 256 bit の鍵にしてみた。
よい子のみんなはこんな短い鍵は使っちゃダメだよ。


256 bit の秘密鍵ファイルをダンプしてみるとこんな感じ:

$ cat rsaprivate.key
-----BEGIN RSA PRIVATE KEY-----
MIGrAgEAAiEAvnrd8LBnzAGxCW+i7KtVQSiTsssMtbwcs5styeKsn2kCAwEAAQIh
AKBF8glb5Xqa0cQG0ygg4hIFdipmvEJhiCuhX93krDCBAhEA51bAM0gFPvxyk9Xe
ioIOBQIRANLJEv4Xw7MwT7EEEARL5RUCEBa8bu1bUbCsDPK8nT+NoqUCEQCIzFCU
MY4j7BW8N3vBnhPlAhBgs4tSfe6RbpertixmCygk
-----END RSA PRIVATE KEY-----

秘密鍵の中身は本当はこんな公の場に晒しちゃいけないけど、この鍵は単に説明用に生成しただけで、実際には何にも使わないから心配しないでね。

現時点で主流の 2048 bit だともっと長くなるよ。

このファイルのフォーマットは PEM 形式といって、固定のヘッダ・フッタの間に BASE64エンコードされたデータが入っている。

こんなイメージ:

-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA
-----END RSA PRIVATE KEY-----


BASE64 をデコードして、元のデータを取り出してみよう。

$ cat rsaprivate.key | awk /^[^-]/{print} | base64 -d

awk でヘッダとフッタを取り除いたあとにデコードをしているよ。

なにやら文字化けしたようなデータが表示されてしまったかな?
この、デコードして得られた元のデータは、秘密鍵の情報を DER (Distinguished Encoding Rule) という形式でエンコードしたバイナリになっているらしい。

その DER のデータを読み解くと、秘密鍵の情報が得られるんだけど、その内容は ASN.1 という規則に則って以下のような Syntax だと定められているよ。

RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER, -- n
    publicExponent    INTEGER, -- e
    privateExponent   INTEGER, -- d
    prime1            INTEGER, -- p
    prime2            INTEGER, -- q
    exponent1         INTEGER, -- d mod (p-1)
    exponent2         INTEGER, -- d mod (q-1)
    coefficient       INTEGER, -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
}

参考(1): PKCS#1
参考(2): ITU-T X.690 PKCS#1

ここで、version は INTEGER 型なんだけど、取りうる値の範囲が 0 か 1 しかなくて、1 だと otherPrimeInfos があるけど 0 だと存在しないよ。


それじゃ、さっきデコードしたデータをとりあえず16進ダンプしてみよう。

$ xxd <(cat rsaprivate.key | awk /^[^-]/{print} | base64 -d)
0000000: 3081 ab02 0100 0221 00be 7add f0b0 67cc  0......!..z...g.
0000010: 01b1 096f a2ec ab55 4128 93b2 cb0c b5bc  ...o...UA(......
0000020: 1cb3 9b2d c9e2 ac9f 6902 0301 0001 0221  ...-....i......!
0000030: 00a0 45f2 095b e57a 9ad1 c406 d328 20e2  ..E..[.z.....( .
0000040: 1205 762a 66bc 4261 882b a15f dde4 ac30  ..v*f.Ba.+._...0
0000050: 8102 1100 e756 c033 4805 3efc 7293 d5de  .....V.3H.>.r...
0000060: 8a82 0e05 0211 00d2 c912 fe17 c3b3 304f  ..............0O
0000070: b104 1004 4be5 1502 1016 bc6e ed5b 51b0  ....K......n.[Q.
0000080: ac0c f2bc 9d3f 8da2 a502 1100 88cc 5094  .....?........P.
0000090: 318e 23ec 15bc 377b c19e 13e5 0210 60b3  1.#...7{......`.
00000a0: 8b52 7dee 916e 97ab b62c 660b 2824       .R}..n...,f.($


さっきも言ったけどこのバイナリデータは DER というフォーマットになっている。
DER フォーマットは、ASN.1 というツリー構造のデータをバイナリに変換する(シリアライズする)ときに使われるフォーマットの一つで、同じデータから複数の表現が出てこないようになっているらしい。

例えば整数の表現は DER では可変長なんだけど、1 という数(データ)を表現するときには可変長なので 0x01 とも表現できるし 0x00000001 とも表現できるはずなんだけども、DER ではオクテット(バイト)単位で一番短くなる 0x01 しか認めていないんだ。

秘密鍵のバイナリデータが違うから違う鍵だと思っていたら実は同じ鍵だった!なんてことがあったら悪い人に悪用されて困ったことになりそうだから、きっとそうならないようにしているのかな。


DER フォーマットは基本的
ID(可変長)、コンテンツの長さ(可変長)、コンテンツ
という、いわゆる TLV の繰り返し・入れ子の構造になっているよ。

ID は本当は可変長なんだけど、RSA 秘密鍵のファイルの場合は 1 バイト固定だと思って構わないよ。

ID の 1 バイトめは、さらにビットごとに以下のようにわかれている。

bit 7 6 5 4 3 2 1 0
クラス プリミティブ型か複合型か タグ

ここでタグの値が 31(5 bit 全部 1)なら後続のオクテットがあって可変長になるんだけど、RSA 秘密鍵ではここが 31 になることはないよ。

クラスというのは、以下の表のようになっていて、タグが公式のものかはたまたプライベートなものか、というようなことを表しているよ。
RSA 秘密鍵では Universal しか出てこなくて、タグは全部公式な規格で定められたものしか使われていないよ。

bit 7 bit 6 意味
0 0 Universal
0 1 Application 固有
1 0 Context 固有
1 1 Private

bit 5 は、コンテンツの型がプリミティブ型なのか複合型なのかを表していて、0 だとプリミティブ型、1 だと複合型になる。
複合型というのは、プリミティブや他の複合型を組み合わせて作られる型で、C 言語でいう構造体とか配列みたいなものだと思っておけば OK。

というわけで、最初に ID の 1 バイトを読むと、そのコンテンツがどんな型のデータなのかがわかる。

さっきの例だと先頭の1バイトは 0x30 になっているね。

bit 7 bit 6 bit 5 bit 4 3 2 1 0
0 0 1 1 0 0 0 0

こうだね。

bit 5 が 1 になっているのでこれは複合型。
タグが 0x10 なので、コンテンツは SEQUENCE 型という複合型になっていることがわかる。
(タグの値と型の対応は ITU-T Rec. X.680 のセクション 8.4 にある Table 1 - Universal class tag assignments に定められているよ。)


SEQUENCE は、コンテンツの中に TLV がまた現れて、その出現順も決められているときに使われる複合型だよ。
秘密鍵の場合は n とか e とか p とか q とかの記録されている順番が大事だから SEQUENCE になっているんだね。


さて、つぎはその SEQUENCE の長さを見てみよう。
「長さフィールド」の長さ自体も可変長なんだけど、これは最初の1バイトを読んでみれば全体で何バイト読み取ればよいのかがわかるよ。

さっきの例だと 0x30 の次は 0x81 になっているね。

0x81

bit 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 1

0x81 は最上位ビット(bit 7)が立っているので、長さフィールドは1バイトに収まっていないことを意味する。逆に最上位ビットが立っていない場合はその1バイト自体がコンテンツの長さになるよ。
最上位ビット以外のビット(bit 6〜0)を見ると、0x01 になっている。

これは続く 1 バイトで長さを表しているということになる。

なので次の1バイトを読む。
0xab だね。

つまり、この SEQUENCE 型のコンテンツは 0xab(= 171 バイト)だっていうこと。
ちなみに 0xab の次のバイトから 171 バイト読み進めると、EOF に到達するね。
つまりこのデータにはこの SEQUENCE 型しか入っていないことになる。

コンテンツの解読を進めていこう。

SEQUENCE 型のコンテンツは、TLV が再び繰り返し入っていると説明したね。
でも各 TLV は可変長なので、何個の TLV が入っているかはよくわからない。
RSA 秘密鍵の ASN.1 の定義からは、少なくとも 9 個の INTEGER 型のデータが入っているはずだけどね。

じゃあ早速最初のデータの TLV を見てみよう。

0xab の次のバイトは 0x02 になっているね。
この ID は、Universal クラス、Primitive 型で INTEGER 型のタグを持っている。

つまり、SQEUQNCE の中に入っている最初の TLV は INTEGER 型のデータだってこと。

長さを見てみよう。
まずは1バイト読み取る。0x01 だね。最上位ビットが立っていないので、この 0x01 という値そのものがコンテンツの長さを表している。
つまりこの INTEGER 型は 1 バイトのデータだということがわかる。

じゃあ次の 1 バイトのコンテンツを読み取ろう。0x00 だね。この INTEGER 型の値は 0 ということだ。

RSA 秘密鍵の ASN.1 による定義を見てみると、これは version = 0 ということに相当するね。

次の TLV を見てみよう。
つぎの ID も 0x02 だ。これまた INTEGER 型。
長さは 0x21 つまり 33 バイト。

00 be 7a dd f0 b0 67 cc 01 b1 09 6f a2 ec ab 55
41 28 93 b2 cb 0c b5 bc 1c b3 9b 2d c9 e2 ac 9f
69

33バイトの整数って、ピンと来ないかもしれないけど、いわゆる多倍長整数というやつだね。
256 bit の鍵なので、32バイトで十分なんだけど、最上位ビットが立ってしまうのを防ぐために最上位に 0 のバイトをくっつけているので 33 バイトになってしまうんだね。

これは RSA 秘密鍵の modulus が 0x00be7addf0b067cc01b1096fa2ecab55412893b2cb0cb5bc1cb39b2dc9e2ac9f69 という多倍長整数だということだね。大きすぎてよくわからないけど、10進数に直すと
86156528347631080411887474184796200056952828735035413778633685555551033663337
という数みたいだよ。

256 bit の鍵でこんな大きな数になるのに、この程度の長さの鍵だとコンピュータの力をもってすれば解くことができてしまうんだね。


さて、33バイト読み取った次のデータは何だろう。
また ID は 0x02 だけど今度は長さは 0x03 だね。3バイトの整数ということだ。
3バイトは 0x01 0x00 0x01 になっているよ。

これは RSA 秘密鍵の e (publicExponent) に相当するね。
0x010001 = 65537 だよ。

同様にして、最後まで読んでいくと
d (privateExponent) = 0x00a045f2095be57a9ad1c406d32820e21205762a66bc4261882ba15fdde4ac3081
p (prime1) = 0x00e756c03348053efc7293d5de8a820e05
q (prime2) = 0x00d2c912fe17c3b3304fb10410044be515
d mod (p-1) (exponent1) = 0x16bc6eed5b51b0ac0cf2bc9d3f8da2a5
d mod (q-1) (exponent2) = 0x0088cc5094318e23ec15bc377bc19e13e5
(inverse of q) mod p (coefficient) = 0x60b38b527dee916e97abb62c660b2824
ということがわかるね。

簡単だったでしょ?



ちなみに、こんな面倒なことをしなくても、

$ openssl asn1parse -inform PEM < rsaprivate.key 
    0:d=0  hl=3 l= 171 cons: SEQUENCE          
    3:d=1  hl=2 l=   1 prim: INTEGER           :00
    6:d=1  hl=2 l=  33 prim: INTEGER           :BE7ADDF0B067CC01B1096FA2ECAB55412893B2CB0CB5BC1CB39B2DC9E2AC9F69
   41:d=1  hl=2 l=   3 prim: INTEGER           :010001
   46:d=1  hl=2 l=  33 prim: INTEGER           :A045F2095BE57A9AD1C406D32820E21205762A66BC4261882BA15FDDE4AC3081
   81:d=1  hl=2 l=  17 prim: INTEGER           :E756C03348053EFC7293D5DE8A820E05
  100:d=1  hl=2 l=  17 prim: INTEGER           :D2C912FE17C3B3304FB10410044BE515
  119:d=1  hl=2 l=  16 prim: INTEGER           :16BC6EED5B51B0AC0CF2BC9D3F8DA2A5
  137:d=1  hl=2 l=  17 prim: INTEGER           :88CC5094318E23EC15BC377BC19E13E5
  156:d=1  hl=2 l=  16 prim: INTEGER           :60B38B527DEE916E97ABB62C660B2824

これで一発だよ。


ちなみに、公開鍵っていうのは秘密鍵から modulus と publicExponent だけを抜き出したものだよ。

だから、ここまで来ることができたあなたは、公開鍵の PEM ファイルも読めるようになったはずだよ。

Ruby をソースからビルドして rbenv で使う方法

まず、Ruby 本体に手を加えてそれをフィードバックする可能性があるなら、GitHub 上で fork してからそれを clone ましょう。そうでなくて単に最新の Ruby を追いかけたい!というような場合は、https://github.com/ruby/ruby.git を clone すればよいでしょう。

clone したら trunk ブランチをチェックアウトします。(GitHub 上でデフォルトのブランチを trunk ブランチにしておくと良いと思います。)

$ git clone git@github.com:<username>/ruby.git ~/ruby 

もしくは

$ git clone https://github.com/ruby/ruby.git ~/ruby

その後、

$ cd ~/ruby
$ git checkout trunk

とします。
チェックアウトしたばかりだと configure ファイルがないので、README に書かれているとおりに autoconf を実行します。

$ autoconf

これで configure が生成されます。

次に、以下の記事に書かれているような方法で、./configure を実行します。
このとき、--prefix オプションで ~/.rbenv の中にインストールされるようにします。
独自ビルドした ruby を rbenv で使う

$ ./configure --prefix=$HOME/.rbenv/versions/fix9367 --enable-shared --enable-debug-env CPPFLAGS='-DRUBY_DEBUG_ENV -DARRAY_DEBUG'

私の場合は Bug#9367 の修正を行いたかったので、インストール先は ~/.rbenv/versions/fix9367 としました。

それ以外のオプションは上記記事と同じにしてあります。

configure が完了したら、make します。

$ make

その後、README に従って make check を行いましょう。

$ make check

なんか私の環境ではエラーが起きてしまいました(汗)

とりあえずインストールしてみましょう。

$ make install

こちらは無事成功したようです。

$ rbenv versions
  system
  
    :

  fix9367

インストールしたバージョンが一覧に現れました。

$ mkdir ~/tmp
$ cd $_
$ rbenv local fix9367

これで ~/tmp 以下にいるときは fix9367 が使われるようになります。

$ cat .ruby-version
fix9367

試しにバージョンを確認してみると:

$ ruby -v
ruby 2.2.0dev (2014-01-05 trunk 44507) [x86_64-linux]

このあたりの表示は clone してきた時の最新の状態になっているようですね。ソースツリーのどこかのファイルを書き換えたりするとこのバージョン表記も変更できるのかもしれません。

gcc などの出力に色をつけるプログラム

コマンドラインgcc などのコンパイラを実行したり複数のファイルを make によってビルドするときなどに、ついついコンパイラからの出力メッセージを目視してしまう私のような情弱は、ある程度規模が大きなプログラムになると警告やエラーメッセージが他の正常な出力に埋もれて見つけにくくなってしまいます。
EmacsVim から直接コマンドを起動して出力をエディタの中でゴニョゴニョしているというスーパーハカーなあなたはこの記事を読まなくてもよいかもしれません)


膨大な出力メッセージがあってもエラーが発生した場合は最終的にビルドが止まりますので気づくことができますが、警告は見逃してしまいがちです。

そこで colorgcc 他、いろいろとコンパイラの出力に色をつける系のプログラムが世の中にはあります。

しかし以下のような理由で、既存のプログラムではなかなか私のような用途には対応しづらそうな感じがしました。

  1. 複数のバージョンのコンパイラやクロスコンパイラを使っていると、colorgcc 他各種ツールのような「コンパイラ置換えアプローチ」は使いづらい
  2. 人から送られてきたビルドログや CI サーバに残っているビルドログをあとから簡単に色付けして見たいけど、それをやってくれるプログラムはなさそう

これらのことを簡単に実現するには、コンパイラの出力をパイプで受け取り色づけして出力するようなフィルタプログラムがあれば良いのではないかと思って探して見ましたがなかなか見つかりません。

仕方が無いので作ってみたのですが、どうしてそういうフィルタプログラムが存在しないのか、作ってみてわかった気がします。

  1. コンパイラ等はたいていエラーメッセージを stderr に出力します。しかしフィルタプログラムが stderr をパイプ経由で渡してもらうにはひと手間必要です(2>&1 のような余計なものをユーザに書いてもらう必要が生じ、普段使いには敷居が高いです)
  2. フィルタプログラム側からは、コンパイラの終了コードを簡単には取得できません。しかしながらコンパイラの終了コードを透過的にフィルタプログラムの終了コードとしてあげないと、コンパイルの成功・失敗に応じて処理を分ける場合にそのフィルタプログラムが使えなくなります。
  3. コンパイラを置き換えると既存のビルドスクリプト等に全く手を加えなくても色付けできますが、フィルタアプローチの場合はビルドスクリプトを書き換えないと色付けすることができない場合があるかもしれません。ただ、何らかの事情によりビルドスクリプトを変更できない場合でも、そのビルドスクリプト自体からの出力を受け取って色付けすれば良さそうなのでそれほど問題ないかもしれません。(個人的には、ビルド環境のコンパイラを置き換えるよりはビルドスクリプトを書き換えるほうがマシな気はしますが)

おそらくこのあたりの理由で、既存のプログラムはコンパイラそのものを置き換える仕組みになっているのではないかと思います。(全然違うかもしれませんが)

今回、シェルスクリプトと組み合わせることによってそれらの問題をある程度解決することができた気がするので GitHub に上げてみました。
https://github.com/bearmini/crror

crror という名前は color + error から来ています。(カラー、もしくはクラーとでも発音しましょうかね)

使い方は至って簡単で、既存のコンパイルのコマンドの先頭に crror とつけていただくだけです。
たとえば、

$ crror make clean all

という感じです。これで、make clean all の出力に色がつきます。
終了コードも make コマンドの終了コードを透過的に使用します。

また、build.log というファイルがあって、その内容を色付けして見たい場合は

$ crror build.log | less -R

という感じでイケます。

現時点ではいろいろ制約があります。たとえば起動スクリプトbash のみサポートですし、stderr を拾うために結局フィルタではなくコマンドっぽく使わないといけない感じになってしまいました。すなわち、make | crror という感じで使いたかったのですが、crror make というふうに使わないといけなくなりました。
(内部的にはフィルタで実装してしまったので、stderr と stdout が統合されてしまっているのが欠点といえば欠点かもしれません)

clang (LLVM) はデフォルトで色付きの出力をサポートしているようですし、gcc も 4.9 からは色つき出力をサポートするようですので、このプログラムもそれが一般的になるまでのつなぎ程度でしかないですが、また、私の気づいていない他の欠点もあるとは思いますが、よろしければ使ってみてください。

Ruby コミュニティにコードを contribute する方法

うっかり Ruby の標準添付ライブラリに好ましくないと思われる挙動を見つけてしまって、直してはみたもののその修正をどうやって contribute すればよいのかと思って調べてみたけどよくわからなかったので http://www.ruby-lang.org/en/ の説明をいろいろ漁ってこんな感じかな〜と思った手順をまとめてみます。(日本語 http://www.ruby-lang.org/ja/ の方は英語版と若干異なる内容だったのと、なんとなく情報量少なめだったので英語の方を参考にしました。ただ、英語のほうも svn 主体の説明になっていてなんとなく outdated な感じでした)

私がやってみたのは以下のような手順です。

  1. Ruby のコードに修正したいバグ(もしくは追加したい機能)を見つける
  2. Redmineruby-trunk プロジェクト (https://bugs.ruby-lang.org/projects/ruby-trunk) に報告する(新しいチケットを作る)
  3. GitHubruby/ruby (https://github.com/ruby/ruby) を fork する
  4. fork したリポジトリをローカルに clone してきて trunk ブランチを checkout する
  5. バグを修正する(もしくは機能を追加する)
  6. もちろんテストも書く
  7. GitHub でプルリクする ← イマココ

まだ PR が取り込まれたわけではないのでこの手順で合ってるかどうかよくわかりません。


今後も継続的に開発に参加するつもりならメーリングリストを購読したりすべきなんでしょうけど、普段は Ruby のユーザで、自分のプログラムのバグかと思って問題を追いかけていたらたまたま Ruby 本体のバグにあたってしまった、というような状況の私みたいな人には、ML に参加して云々というのはちょっと敷居が高いですね。

Redmine で Issue 発行して GitHub でプルリクするだけなら、私のような一見さんでも気軽に貢献できるというものです。

ただ、自分の修正をテストするときに、ローカルで変更した Ruby を使ってテストを走らせるようにする方法がよくわかりませんでした。

なので私は仕方が無いので ~/.rbenv/ の下の当該 .rb ファイルを直接書き換えたりしてテストしました・・・
単一の .rb ファイルで変更はそれほど多くなかったからそのような方法でなんとかなったものの、.c とかを修正したらどうやってテストすればいいのでしょうかね。

そのあたりの情報、どなたか教えてプリーズ

[追記]
多分、以下のような方法で自前 Ruby を rbenv に取り込んで、そいつを使ってデバッグしたりすると既存の環境を壊したりしなくて済むので良い気がします。

Ruby をソースからビルドして rbenv で使う方法 - bearmini's blog

Android SDK のコマンドを実行しようとしたら No such file or directory と言われて焦った件

dexdump を使おうとして、2 回もハマったので、自分用メモ。

結論から言うと、

$ sudo apt-get install ia32-libs

で解決。

私は Ubuntu 12.04 の x86_64 バージョンを使っているので Android SDK も 64bit 版のものをダウンロードして使っていますが、Android SDK のツールの中には 32bit のものがあるんですね。これを実行するのに多分 ia32-libs が要るんだと思います。

$ which dexdump 

してもちゃんと見つかるし、

$ dexdump
-bash: /home/username/adb-bundle-linux-x86_64/sdk/build-tools/android-4.3/dexdump: No such file or directory

という感じにそもそも bash のエラーメッセージにはちゃんと dexdump までのパスが表示されてるので、PATH が解決できてないというわけでもなさそう。

ls -l でパーミッションとかオーナーとか見ても問題なし、どうして見つからないのか??と小一時間悩んだ挙句、StackOverflow で http://stackoverflow.com/questions/13571145/android-adb-not-found を発見して無事解決。

Tizen Native API のメソッド名末尾についてる N の意味

この記事は Tizen Advent Calendar 2013 に参加予定の記事です。



Tizen で Native アプリを開発していると、ときどき API の関数名の末尾に N が付いているのを見かけます。

たとえば身近なところでいうと

  • Tizen::Base::Collection::ArrayList::GetEnumeratorN()
  • Tizen::Net::Http::HttpRequest::ReadBodyN()
  • Tizen::Ui::Control::GetCanvasN()

といったようなメソッドたちです。

これは、「このメソッドの中で new によってメモリの確保が行われるので呼び出し元が責任を持ってそのメモリを解放してね♥」 という意味です。

覚え方: New の N(メソッドの中でオブジェクトを new している)

N で終わるメソッドを呼び出すときは可能ならば戻り値を std::auto_ptr とか std::shared_ptr とか std::unique_ptr とかを使って受け取るなどして、解放忘れを防ぎましょう。


なお、イベントハンドラ名に N が付いている場合、そこに渡されてくる引数のポインタを delete しなければならないという意味になります。

たとえば身近なところでいうと

  • Tizen::App::App::OnUserEventReceivedN()
  • Tizen::Io::IMessagePortListener::OnMessageReceivedN()

などがあります。

これらのメソッドをオーバーライドして実装するときは、引数のポインタを忘れずに delete しましょう。


余談ですが、このようにプラットフォームが確保したメモリをユーザコードの中で解放する、あるいは逆にユーザコードの中で確保したメモリをプラットフォーム側で解放する(Tizen::Ui::Container::AddControl() など)、というコーディング規約は当初すっごく気持ち悪く感じました。(今でもだいぶ気持ち悪いけど)

あと、Tizen::Ui::Container::AddControl() で思い出しましたが、今でこそ Deprecated になった Tizen::Ui::Container::AddControl(const Control& control) というメソッドは、そのメソッドの仕様を二度見、三度見(えっ、・・・えっ・・・、えっ・・?!?)しましたし、軽く冷や汗をかいてひと通り我が目を疑った後にこのライブラリと今後しばらく付き合っていくのかと考えると意識がうっすらと遠のいたのを今でも覚えています。
const 参照で渡したコントロールのインスタンスを、コンテナ側で delete してくれるってどういうことよ!?っていう。
今は Tizen::Ui::Container::AddControl(Control* pControl) になったのでいくらかマシですね。


クラスライブラリの設計の筋の良さ的にはぜひ Qt for Tizen に普及してもらいたいです。

Tizen の sdb コマンド向け bash completion のご紹介

この記事は Tizen Advent Calendar 2013 に参加予定の記事です。


Tizen でアプリを開発していると、コマンドラインからアプリのインストールやアンインストール、ファイルのコピー、デバイスのシェルへのアクセスなど、いろいろと便利な sdb コマンドを使い倒されている方も多いかと思います。sdb コマンドは Android の adb コマンドみたいなものですね。

sdb コマンド自体は大変便利なのですが、デバイス上のファイルを開発用 PC にコピーしてきたいといった時にファイルのパスが補完されなくてちょっと残念です。

ということで、sdb コマンドでも補完を使うための bash completion を以前作りました。

https://github.com/bearmini/tizen_bash_completion

(もし標準でもっと高機能なのがあったり、他の誰かがすでに作ってたりしたら恥ずかしいなぁ。まあ見つけられなかったから作ったんだけど・・・)

使い方は github から clone したあと tizen_sdb_bash_completion.sh を .bashrc かどこかで source するだけです。
(GitHub の README には、/etc/bash_completion.d/ にコピーしろという侵襲的な説明を書いてしまいましたが、そんなことしなくても使えます)


今のところ、補完対象サブコマンドは以下のとおりです:

  • install

ローカル側のファイル名(*.tpk, *.wgt など)を補完してインストールできます。

  • uninstall

デバイスにインストール済みのアプリのパッケージ ID 一覧を補完してアンインストールできます。

  • push

ローカル側のファイルパスおよびデバイス側の push 先パスを補完できます。

  • pull

デバイス上のファイルパスおよびローカル側の pull 先パスを補完できます。

  • その他 dlog とか root とかもサポートしていますがおまけみたいなものですね

複数のデバイスが接続されているときは -d/-e/-s などでデバイスを特定する必要があります。-s に指定するシリアル番号も補完対象です。

sdb pull の補完では末尾に余計な記号がついちゃう場合があります。
(ディレクトリ名の末尾に / を付けたかったので、デバイス上で実行する ls コマンドに F オプションをつけたのですが、そうすると他の種類のファイルの末尾に * とか @ とかがついてしまうことがあります。これがついたまま実行すると、エラーになりがちです。)
これはなんとかしたいですね。
(scp の補完も同じ感じだった気がするから難しいのかもしれないけど・・・)






上記 4 つのコマンドの補完が効くだけでも大幅に効率アップすること請け合いですが、追加でサポートしてほしいサブコマンドや sdb 以外のコマンドのご要望がありましたらコメントなり何なりでお知らせください。
pull request も絶賛受付中です。