2015年9月6日日曜日

バイナリファイルの可視化(ARMの機械語コードの縦縞が見たい!)

0. 要旨

「ARMの機械語コードをビットマップ表示のできるバイナリエディタで開いてみると、縦に線が見える」という噂がある。
しかし、hexeditにはそんな機能はない。そうだ、機械語コードにちょいっとヘッダをつけて、PNMファイルにしてしまおう。


1. ARMの機械語

最近、「熱血!アセンブラ入門」という本を読んでいる。
熱血!アセンブラ入門 サポートページからファイル一式も手に入れて、環境もばっちり整えて、ひたすらコード(ソースコードとアセンブリコードと機械語コード)で遊んでいるのだ。
そんな中でARMの機械語コードの縦線の話があるなら、やるしかない。

以下、登場する機械語コードは上記の熱血!アセンブラ入門 サポートページ
「環境構築の方法」で配布されている配布物を、うちでコンパイルしたものである。

2. PNM形式

PNM形式は画像形式の一種であって、4行(白黒なら3行)のヘッダの後に、ASCIIの数字、またはバイナリの数値を羅列した形式である。
(ASCII、バイナリ)と(白黒、グレイ、カラー)の直積で6種類があり、それぞれP1からP6のマジックナンバーが与えられている。wikipediaPNM画像の作成をご覧いただきたい。

単純な形式なので「そのバイトの値」を目で見るにはもってこいだ。
今回は、バイナリ、白黒のP4にする。

P4のファイル形式は、次のようになっている。
1行め:P4と書く
2行め:#と書く
3行め:横と縦のサイズを空白で区切って書く
4行め:ビット列が続く(0は白、1は黒で左上から右に順番に絵の色を指定していると解釈される)
拡張子は、P4だと白黒だから、pbmになる。

3. 画像にしよう

では、早速やってみよう。
サンプルコードをARM向けにコンパイルした実効形式のファイルがarm-elf.xである。

wc -c arm-elf.x|awk '{printf "P4\n#\n128 %d\n",$1/16}'>arm-elf.pbm ; cat arm-elf.x >> arm-elf.pbm

(コードは改行されているように見えるけれど、もちろん一行で。)
横のサイズを128にしたのは、hexeditを80x24のターミナルで開くと、1行を16byte=128bitで表示されるからである。

意図したとおりのヘッダがついたか確認してみよう。
$ less arm-elf.pbm
P4
#
128 877
^?ELF^A^A^Aa^@.....
よしできているようだ。

では画像として開こう。

4. 画像を見よう

eogでもemacsでもgimpでもdisplayでもpbmは認識される。
(ただし、displayとemacsではズームインの仕方がわからなった
emacsの虫眼鏡をクリックしたら、[I-search:]ですって)。
なお、eogはanti-aliasingがかかることがある。
Edit->Preferenceで Smooth image when zoomed-inのチェックを外しておこう。

全体像を次に示す(ブログにアップするために、pbmをpngにeogで変換した)。



左上で0と1との対応を確認しよう。
コードの最初の部分をhexeditと絵で次に示す。


arm-elf.xの始まりは
7F 45 4C 46 ...
だから
0111 1111 0100 0101  ...
だから
白黒黒黒 黒黒黒黒 白黒白白 白黒白黒 ...
と正しくなっているようだ。

機械語コードの部分をhexeditと絵を次に示す。
機械語部分は、0x1400バイトめ(320行め=0x1400/0x4、1行4バイトだから)から始まるので、そのあたりにズームインした。



よし。縦縞が見えた。

5. グレイスケールでも見てみよう

PNMのP4はグレイスケールの画像形式である。ここでは8ビットで1ピクセルを表すようにしてみよう。

wc -c arm-elf.x |awk '{printf "P4\n#\n16 %d\n",$1/16/8\n255}'>arm-elf.pgm ; cat arm-elf.x >> arm-elf.pgm

機械語コード部分を示す。


よし。縦縞だ。

6. まとめ

機械語コードは、catとawkで画像化できて、viewerで絵として見られる。

以上
(2016年12月10日、誤字修正)

2015年7月25日土曜日

gaucheでxmlから特定の要素を抜き出す

1. 背景

windosw updateをオフラインで実行する過程で、
オフラインのwindowsマシンは、windows updateの状況が書かれたXMLファイルを出力する。
出力されるファイルは次のようなものである。
<XMLOut>
  <CatalogInfo>
    <CreationDate>2015-07-14T04:38:16Z    </CreationDate>
  </CatalogInfo>
  <Check ID="500" Grade="2" Type="5" Cat="1" Rank="1" Name="Developer Tools, Runtimes, and Redistributables のセキュリティ更新プログラム" URL1="Help/Check5311.html" URL2="Help/Check5311fix.html" GroupID="48ce8c86-6850-4f68-8e9d-7dc8535ced60" GroupName="Developer Tools, Runtimes, and Redistributables">
    <Advice>不足しているセキュリティ更新プログラムが 2 個あります。
    </Advice>
    <Detail>
      <UpdateData ID="MS11-025" GUID="bb49cc19-8847-4986-aa93-5e905421e55a" BulletinID="MS11-025" KBID="2538242" Type="1" IsInstalled="false" Severity="3" RestartRequired="false">
    <Title>Microsoft Visual C++ 2005 Service Pack 1 再頒布可能パッケージのセキュリティ更新プログラム (KB2538242)
    </Title>
    <References>
      <BulletinURL>http://www.microsoft.com/technet/security/bulletin/MS11-025.mspx
      </BulletinURL>
      <InformationURL>http://go.microsoft.com/fwlink/?LinkId=216804
      </InformationURL>
      <DownloadURL>http://download.windowsupdate.com/msdownload/update/software/secu/2011/06/vcredist_x86_b8fab0bb7f62a24ddfe77b19cd9a1451abd7b847.exe
      </DownloadURL>
    </References>
      </UpdateData>
      <UpdateData ID="MS11-025" GUID="729a0dcb-df9e-4d02-b603-ed1aee074428" BulletinID="MS11-025" KBID="2538243" Type="1" IsInstalled="false" Severity="3" RestartRequired="false">
    <Title>Microsoft Visual C++ 2008 Service Pack 1 再頒布可能パッケージのセキュリティ更新プログラム (KB2538243)
    </Title>
    <References>
      <BulletinURL>http://www.microsoft.com/technet/security/bulletin/MS11-025.mspx
      </BulletinURL>
      <InformationURL>http://go.microsoft.com/fwlink/?LinkId=216803
      </InformationURL>
      <DownloadURL>http://download.windowsupdate.com/msdownload/update/software/secu/2011/05/vcredist_x86_470640aa4bb7db8e69196b5edb0010933569e98d.exe
      </DownloadURL>
    </References>
      </UpdateData>
    </Detail>
  </Check>
  (中略)
</XMLOut>

(もともとのファイルは改行があまりないので、blogに掲載するためにemacsのsgml-modeでsgml-pretty-printで整形した。)

ここで、各UpdateDataにおいて、IsInstalled="false"になっている項目を、DownloadURLからダウンロードしてくる必要がある。
さて、どうやろうか。手動でやるのは問題外である。
いろいろ方法はありそうだが、XMLのライブラリがあるscript言語を使ってみよう。
私が一番親しいscript言語は、Gaucheである。

2. Gaucheのxmlモジュール

GaucheにはXMLのためのモジュールがいくつかある。
今回は、sxml.ssax、sxml.sxpathでやりたいことがやれた。
詳しくは、Referenceを参照のこと。[1]

まず、ssax:xml->sxmlでファイルから読み込んだXMLをS式(sxml形式と読んでいる)に変換する。

(define (read-xml file-name)
  (call-with-input-file file-name
    (lambda (port)
      (ssax:xml->sxml port '() ))) )
は、XMLファイルを引数として受け取り、ファイル内のXMLと同じ構造のS式を返す関数を定義する。
ssax:xml->sxml の第3引数namespace-prefix-assigは
'()としたが問題は起きなかった。

次に、このS式を処理して必要なURLだけをファイルに書き出したい。
それにはsxpathが使える。
(sxpath '(XMLOut Check))は、(ルートから)XMLOut -> Checkとたどった時の要素のリスト(Checkがたくさんあることが想定されるから)を取り出すClosureを返す。

したがって、sxmlであるsxml-wholeに対して、((sxpath '(XMLOut Check)) sxml-whole)でXMLOut -> Checkとたどった時の要素のリストが返る。

3. まとめ

これらを組み合わせると、windowsの出力したXMLを食べて、必要なDownloadURLの一覧を出力するscriptができる。
#!/usr/local/bin/gosh 
(use sxml.ssax)
(use sxml.sxpath)

(define (read-xml file-name)
  (call-with-input-file file-name
    (lambda (port)
      (ssax:xml->sxml port '() ))) )
(define (get-url-unless-installed update-data)
  (if (string=? "false"
  (cadar ((sxpath '(|@| IsInstalled)) update-data)))
      (cadar
       ((sxpath '(References DownloadURL)) update-data))
      #f))

(define (main argv)
  (let ((sxml-whole (read-xml (list-ref argv 1))))    
    (map (lambda (y) (print  y))
  
  (filter (lambda (x) x) 
   (apply append
   (map (lambda (check)
          (map get-url-unless-installed
        ((sxpath '(Detail UpdateData)) check)))
        ((sxpath '(XMLOut Check)) sxml-whole))
   )
   ))
    ))

これで、gaucheでxmlから特定の要素を抜き出すことができた。

[1] Gauche ユーザリファレンス: 12. ライブラリモジュール - ユーティリティ
http://practical-scheme.net/gauche/man/gauche-refj_149.html#g_t_00e3_0083_00a9_00e3_0082_00a4_00e3_0083_0096_00e3_0083_00a9_00e3_0083_00aa_00e3_0083_00a2_00e3_0082_00b8_00e3_0083_00a5_00e3_0083_00bc_00e3_0083_00ab-_002d-_00e3_0083_00a6_00e3_0083_00bc_00e3_0083_0086_00e3_0082_00a3_00e3_0083_00aa_00e3_0083_0086_00e3_0082_00a3

2015年2月1日日曜日

気温と高度の関係

一般に「100m高くなると、0.6℃気温が下がる」言われている。

ところで、飛行機に乗るとエンターテイメント端末で、現在の高度、速度、外気温が表示できることがある。
最近、飛行機に乗る機会があったので、表示された高度、外気温、時刻をメモしてきた。
高度と外気温の関係をプロットしてみたものが図1である。



図1 気温と高度の関係

実線が離陸時、破線が着陸時のデータである。黒と青は往路と復路で別の日(いずれも1月の晴れの日)である。往路の到着地は、出発地から西に820kmの地点(復路は逆)。

注目するポイントがいくつかある。
1. 「100m高くなると、0.6℃気温が下がる」は、大体当てはまっているようだ。

2. 10000m付近で気温の低下が止まっている。対流圏界面が見えているかもしれない。

3. 1500mから2000m付近でグラフが折れまがっているものがある。空気のかたまりの境界を通過しているのかもしれない。
(青実線(day2,up)は2000m付近のデータが飛んでいる。雲はなかったので、見かけ上は温度一定だが、実際は黒破線(day1, down)と同様に一度上がっているかもしれない。)

教訓

「自分で」測定してみたわけではないけれど、データをさわってみると見えてくることがある。


参考文献

気象庁, "大気の構造と流れ", http://www.jma.go.jp/jma/kishou/know/whitep/1-1-1.html, 2015年2月1日閲覧