<?xml version="1.0" encoding="utf-8"?>

<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  xmlns:admin="http://webns.net/mvcb/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:cc="http://web.resource.org/cc/"
  xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="http://vanilla-room.cocolog-nifty.com/blog/">
<title>vanillaの日記</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/</link>
<description>自作のソフトウェアやプログラミング全般についての話題とあれこれ</description>
<dc:language>ja-JP</dc:language>
<dc:creator></dc:creator>
<dc:date>2009-11-12T00:23:38+09:00</dc:date>
<admin:generatorAgent rdf:resource="http://www.typepad.com/" />


<items>
<rdf:Seq><rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype12posts.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype11posts.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype10posts.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/10/cfftype2-charst.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3212sehstruc.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3211getselec.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/09/win3210-163f.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/09/odbc-f213.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/08/post-33cd.html" />
<rdf:li rdf:resource="http://vanilla-room.cocolog-nifty.com/blog/2009/08/win329-67d1.html" />
</rdf:Seq>
</items>

</channel>

<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype12posts.html">
<title>OpenTypeフォントの続き(12)・・・PostScriptアウトラインの更に続き</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype12posts.html</link>
<description>前回は位置が固定であるHeaderからGlobal Subr INDEXまで見た...</description>
<content:encoded>&lt;p&gt;前回は位置が固定であるHeaderからGlobal Subr INDEXまで見たので残りのいくつかのデータをとっとと見て行こう。&lt;/p&gt;

&lt;p&gt;残りのデータはオフセット経由でアクセスされる。&lt;/p&gt;

&lt;p&gt;まずは、CharStrings INDEX。&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/11/11/cff3_1.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/11/11/cff3_1_2.jpg&quot;&gt;&lt;img title=&quot;Cff3_1_2&quot; height=&quot;231&quot; alt=&quot;Cff3_1_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/11/11/cff3_1_2.jpg&quot; width=&quot;300&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;肝となるデータである。CharStrings INDEXにはフォントに含まれる各グリフのアウトラインを記述するプログラムが格納される。前回も述べたがこのプログラムはCharstringと呼ばれ、そのフォーマットはTop DICTのCharstringTypeキーによって指定される。MinionPro-Itの場合、Top DICTにCharstringTypeキーが含まれていないので、デフォルト値2のType2 Charstringとなる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;CharStrings INDEXのcountフィールドはフォントに含まれるグリフの数を表す。上の画像より1851個のグリフが含まれている事が分かる。また、CFFにおいて各グリフはGID(Glyph Identifier)によって識別されるが、CharStrings INDEX内の先頭のグリフから順にGIDが0、1、2・・となる。上の画像ではGIDが265のグリフが表示されている。厳密にはCFFのGIDとOpenTypeフォントの文字コードからcmapテーブルによって変換されるグリフインデックスは別物であるが、PostScriptアウトラインのOpenTypeフォントの場合、OpenTypeフォントのグリフインデックス=CFFのGIDとなる。ちなみに、CharStrings INDEXへのオフセットはフォントのTop DICTのcharstringキーの値として指定される(このオフセットはCFFフォーマットの先頭からのオフセット)。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Charset。&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/11/11/cff3_2.jpg&quot;&gt;&lt;img title=&quot;Cff3_2&quot; height=&quot;229&quot; alt=&quot;Cff3_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/11/11/cff3_2.jpg&quot; width=&quot;300&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Charsetにはグリフ(GID)と名前(SID)のマッピング情報が格納される。詳細は省略するが、例えば、先ほどのCharStrings INDEXの画像でGIDが256のグリフが表示されていたが、このグリフのSIDは上の画像より1465であることがわかる(GID 0のグリフの名前は省略されているので、[Index]列が256-1=255のエントリ)。また、String INDEXよりSIDが1465の文字列はc_kであるから、GIDが256のグリフの名前はc_kである<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" /><img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Encoding。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Encodingを持ったフォントが見つからん<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。たぶん、文字コードとSIDかGIDのマッピング情報が格納される(SIDかGIDのどっちかは仕様書読んでも理解できません<img class="emoticon sad" src="http://emojies.cocolog-nifty.com/emoticon/sad.gif" alt="sad" />)。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Private DICT。&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/11/11/cff3_3.jpg&quot;&gt;&lt;img title=&quot;Cff3_3&quot; height=&quot;232&quot; alt=&quot;Cff3_3&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/11/11/cff3_3.jpg&quot; width=&quot;300&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;そのまんまであるが、Private DICTにはフォントにプライベートな情報が格納される<img class="emoticon sweat02" src="http://emojies.cocolog-nifty.com/emoticon/sweat02.gif" alt="sweat02" /><img class="emoticon sweat02" src="http://emojies.cocolog-nifty.com/emoticon/sweat02.gif" alt="sweat02" />。Subrキーはこのフォントだけからアクセスできるサブルーチンが格納されたLocal Subr INDEXへのオフセットを表す。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Local Subr INDEX。&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/11/11/cff3_4.jpg&quot;&gt;&lt;img title=&quot;Cff3_4&quot; height=&quot;230&quot; alt=&quot;Cff3_4&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/11/11/cff3_4.jpg&quot; width=&quot;300&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;はやくも燃え尽き気味<img class="emoticon sweat02" src="http://emojies.cocolog-nifty.com/emoticon/sweat02.gif" alt="sweat02" /><img class="emoticon sweat01" src="http://emojies.cocolog-nifty.com/emoticon/sweat01.gif" alt="sweat01" />&lt;/p&gt;

&lt;p&gt;とりあえず、バージョンを1.2として最新版をアップロードしておきました。Type2 Charstringの解析はまだですが、とりあえず、グリフの形状が分かるようになったのでこれでいいかなと・・・&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>フォント</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-11-12T00:23:38+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype11posts.html">
<title>OpenTypeフォントの続き(11)・・・PostScriptアウトラインの続き</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype11posts.html</link>
<description>準備ができたので今回は実際にPostScriptアウトライン形式のOpenTyp...</description>
<content:encoded>&lt;p&gt;準備ができたので今回は実際にPostScriptアウトライン形式のOpenTypeフォントを解析してみるのだが、PostScriptアウトライン形式のOpenTypeフォントってどこで無料で手に入るんだ<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" /><img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />？？と思ってたら、いいものが既にインストールされていた。&lt;/p&gt;

&lt;p&gt;たいていの人が既にインストールしてあるであろう無償のPDFビューアのAdobe ReaderをインストールするといくつかPostScriptアウトライン形式のOpenTypeフォントがインストールされるのでこれを解析してみる。ということでここでは、&amp;lt;Adobe Readerのインストールフォルダ&amp;gt;\Resource\Fontフォルダにある欧文用のMinonPro-It(ファイル名MinionPro-It.otf)というOpenTypeフォントを使って話を進める(別のフォルダCIDFontに小塚明朝、小塚ゴシックという日本語用のPostScriptアウトライン形式のOpenTypeフォントがあるのだが、これらのフォントは脇においておく)。&lt;/p&gt;

&lt;p&gt;実際に解析結果を示しながら話を進めるが、最初にAdobeというかPostScript系のフォントはある程度、歴史を知らないとなぜこういう構造や仕組みになっているかなど理解に苦しむかも知れない<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。実際、CFFフォーマットを理解するために、その前身？のType1やCID-Keyedフォントの仕様書や更にはPostScriptの言語リファレンスまで自分はかいつまんで読むはめになった<img class="emoticon sweat02" src="http://emojies.cocolog-nifty.com/emoticon/sweat02.gif" alt="sweat02" /><img class="emoticon sweat01" src="http://emojies.cocolog-nifty.com/emoticon/sweat01.gif" alt="sweat01" />。&lt;/p&gt;

&lt;p&gt;ということで、まずは前回示したCFFフォーマットのレイアウトにおける位置が固定であるHeaderからGlobal Subr INDEXまでの解析結果を順に見ていく。&lt;/p&gt;

&lt;p&gt;まずは、Header。&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Cff2_1&quot; alt=&quot;Cff2_1&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/11/07/cff2_1.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;文字通りヘッダ情報が格納される。Major、Minorは順にCFFフォマーットのメジャーバジョーン番号、マイナーバージョン番号を表す。&lt;/p&gt;

&lt;p&gt;Name INDEX。&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Cff2_2&quot; alt=&quot;Cff2_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/11/07/cff2_2.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Name INDEXには含まれるフォントの名前が前回説明したINDEXデータとして格納される。含まれるフォントの数はこのName INDEXのcountフィールドによって決定される。上の画像より1個のフォントが含まれていることがわかる。ちなみに、他のデータはそのままにしてこのフォントの名前の先頭文字をヌル文字(0x00)にすることで、フォントを論理削除できる。&lt;/p&gt;

&lt;p&gt;Top DICT INDEX。&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Cff2_3_2&quot; alt=&quot;Cff2_3_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/11/07/cff2_3_2.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;Top DICT INDEXには、含まれるフォントのトップレベルの情報が前回説明したDICTデータとして格納される。もちろん、フォントの各情報はキー・値のペアとして表されるが、定義済みのTop DICTキーには例えば次のようなものがある。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;&lt;caption&gt;Top DICTキー&lt;/caption&gt;&lt;tbody&gt;&lt;tr bgcolor=&quot;#c0c0c0&quot;&gt;&lt;td width=&quot;200&quot;&gt;キー&lt;/td&gt;

&lt;td width=&quot;100&quot;&gt;値&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;version(0)&lt;/td&gt;

&lt;td&gt;SID&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Notice(1)&lt;/td&gt;

&lt;td&gt;SID&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Copyright(12 0)&lt;/td&gt;

&lt;td&gt;SID&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;FullName(2)&lt;/td&gt;

&lt;td&gt;SID&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;FamilyName(3)&lt;/td&gt;

&lt;td&gt;SID&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td colspan=&quot;2&quot;&gt;省略&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;FontBBox(5)&lt;/td&gt;

&lt;td&gt;配列&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td colspan=&quot;2&quot;&gt;省略&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;charset(15)&lt;/td&gt;

&lt;td&gt;数値&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Encoding(15)&lt;/td&gt;

&lt;td&gt;数値&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;CharStrings(15)&lt;/td&gt;

&lt;td&gt;数値&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td colspan=&quot;2&quot;&gt;省略&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;1列目はキーの名前で、括弧内はキー自身の値つまりキー値である。例えば、フォントの完全名を指定するFullNameキーの値はSIDを表すので、このSIDを使い次のString INDEXの対応するエントリを見れば、フォントの完全名がわかる。また、フォントのバウンディングボックス(境界矩形)を指定するFontBBoxキーの値は4つの要素を持つ配列(順に矩形の左端のx座標、下端のy座標、右端のx座標、上端のy座標)である。charset、Encoding、CharStringsへのCFFフォーマットの先頭からのオフセットをそれぞれ指定するcharset、Encoding、CharStringsキーの値は単純な数値である。定義されているすべてのキーとその詳細は仕様書を参照ということで<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" /><img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />・・・・ちなみに、上の画像では、計10個のキーが定義されてるが、デフォルト値を持つキーは省略できる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;String INDEX。&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Cff2_4&quot; alt=&quot;Cff2_4&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/11/07/cff2_4.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;String INDEXには含まれるフォント間で共通のフォント名以外の文字列が格納される。ちなみに、これらの文字列はSID(String Identifier)と呼ばれる2バイトの符号無し整数によって参照される。また、一般的な文字列は標準文字列として計391個(SID:：0-390まで）定義済みであるので、String INDEXに含まれる各文字列のSIDは先頭の文字列から順に、391、392、393・・・となる。上の画像より1616個の文字列が格納されていることが分かる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Global Subr INDEX。&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Cff2_5&quot; alt=&quot;Cff2_5&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/11/07/cff2_5.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Global Subr INDEXには各フォント間で共有されるサブルーチンが格納される。CFFフォーマットでは各グリフのアウトラインが単純なデータというより一種のプログラム(Type2 Charstringなどと呼ばれる)によって定義されるが、サブルーチンとはこのプログラムから呼び出されるサブプログラムの事である(通常のコンピュータプログラム言語におけるサブルーチンと同一の概念)。上の画像より1024個のグローバルなサブルーチンが格納されている事が分かる。各サブルーチンの中身についてはまだ解析してないので表示してない・・・&lt;/p&gt;

&lt;p&gt;と長くなったので今回はここまで<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。残りの解析に手間取ってる<img class="emoticon sweat02" src="http://emojies.cocolog-nifty.com/emoticon/sweat02.gif" alt="sweat02" />ので、とりあえず、ここまでの解析に対応したT2FAnalyzerの最新版をアップロードしておきました。ダウンロードは脇のいつものリンクから。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>フォント</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-11-07T07:40:30+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype10posts.html">
<title>OpenTypeフォントの続き(10)・・・PostScriptアウトライン</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/11/opentype10posts.html</link>
<description>一連のOpenTypeフォントのシリーズでOpenTypeフォントは、グリフデー...</description>
<content:encoded>&lt;p&gt;一連のOpenTypeフォントのシリーズでOpenTypeフォントは、グリフデータとしてTrueType形式のアウトラインまたはPostScript形式のアウトラインを含むことができると書いたが、今回はPostScriptアウトラインについて。&lt;/p&gt;

&lt;p&gt;PostScriptアウトラインに関するグリフデータは&lt;a href=&quot;http://vanilla-room.cocolog-nifty.com/blog/2008/02/opentype2name_3388.html&quot;&gt;第2回&lt;/a&gt;で述べたようにCFFテーブルに格納され、このテーブルは&lt;strong&gt;CFF&lt;/strong&gt;(&lt;strong&gt;Compact Font Format&lt;/strong&gt;)と呼ばれる形式のフォーマットになっているが、このCFFフォーマットについて書いてみる。&lt;/p&gt;

&lt;p&gt;CFFフォーマットは複数のフォントを格納でき、Type1、CID-Keyedフォントよりコンパクトなバイナリ表現のフォーマットである。CFFフォーマットがコンパクトな理由は、バイナリ表現を使用したり、フォント間で共通のデータを共有したり、また、頻繁に出現するデータに対してデフォルト値を与えたりしているためである。(Type1やCID-Keyedフォントって何？って話はここでは触れない。)&lt;/p&gt;

&lt;p&gt;ということで、まずは、CFFフォーマットで使われるデータ型から。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;&lt;caption&gt;CFFデータ型&lt;/caption&gt;&lt;tbody&gt;&lt;tr bgcolor=&quot;#c0c0c0&quot;&gt;&lt;td&gt;名前&lt;/td&gt;

&lt;td&gt;範囲&lt;/td&gt;

&lt;td&gt;説明&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Card8&lt;/td&gt;

&lt;td&gt;0-255&lt;/td&gt;

&lt;td&gt;1バイト符号無し整数&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Card16&lt;/td&gt;

&lt;td&gt;0-65536&lt;/td&gt;

&lt;td&gt;2バイト符号無し整数&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;OffSize&lt;/td&gt;

&lt;td&gt;1-4&lt;/td&gt;

&lt;td&gt;オフセットのサイズを指定する1バイト符号無し整数&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Offset&lt;/td&gt;

&lt;td&gt;可変&lt;/td&gt;

&lt;td&gt;1,2,3または4バイトオフセット&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;SID&lt;/td&gt;

&lt;td&gt;0-64999&lt;/td&gt;

&lt;td&gt;2バイトストリングID&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Card8、Card16はそれぞれ1、2バイトの符号無し整数を表すデータ型である。OffSizeは対応するOffsetで表されるデータ型のフィールドのサイズを表し、1-4の範囲の値を取る。例えば、この値が1なら対応するOffset型のフィールドのサイズは1バイトになる。順に2なら2バイト、3なら3バイト、4なら4バイトである。&lt;/p&gt;

&lt;p&gt;CFFフォーマットのレイアウトの概要は次のようになる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;&lt;caption&gt;CFFレイアウト&lt;/caption&gt;&lt;tbody&gt;&lt;tr bgcolor=&quot;#c0c0c0&quot;&gt;&lt;td&gt;名前&lt;/td&gt;

&lt;td&gt;説明&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Header&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Name INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Top DICT INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;String INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Global Subr INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Encodings&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Charsets&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;FDSelect&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;CharStrings INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Font DICT INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Private DICT&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Local Subr INDEX&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Copyright and Trademark Notices&lt;/td&gt;

&lt;td&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;上の表のようにCFFフォーマットはいくつかのデータの集合として定義されている。また、上の表を見てわかるようにINDEXやDICTと共通の名前を持ったデータがあるが、最初にこれらについて説明する。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;ちなみに、HeaderからGlobal Subr INDEXまでの最初の5つの位置は固定であり、残りはオフセット経由でアクセスされる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;まずはINDEXデータについて。&lt;/p&gt;

&lt;p&gt;INDEXデータは可変サイズのオブジェクトの配列であり、次のような構造になる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;&lt;caption&gt;INDEXデータ&lt;/caption&gt;&lt;tbody&gt;&lt;tr bgcolor=&quot;#c0c0c0&quot;&gt;&lt;td&gt;型&lt;/td&gt;

&lt;td&gt;名前&lt;/td&gt;

&lt;td&gt;説明&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Card16&lt;/td&gt;

&lt;td&gt;count&lt;/td&gt;

&lt;td&gt;INDEXデータ内のオブジェクトの数&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;OffSize&lt;/td&gt;

&lt;td&gt;offSize&lt;/td&gt;

&lt;td&gt;オフセット配列の要素のサイズ&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Offset&lt;/td&gt;

&lt;td&gt;offsets[count+1]&lt;/td&gt;

&lt;td&gt;オフセット配列(オフセット配列の直前のバイトからのオフセット)&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Card8&lt;/td&gt;

&lt;td&gt;data[varies]&lt;/td&gt;

&lt;td&gt;オブジェクトデータ&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;countフィールドはINDEXデータ内に含まれるオブジェクトの数を表す。offSizeフィールドは続くオフセット配列の要素のサイズを表す。offsetsフィールドは各オブジェクトへのオフセットの配列であり、INDEXデータ内の各オブジェクトへはこのオフセットを使ってアクセスする。また、このオフセット配列の要素数はINDEXデータ内に含まれるオブジェクトの数+1つまりcount+1であり、i番目のオブジェクトのサイズは&lt;/p&gt;&lt;blockquote dir=&quot;ltr&quot;&gt;&lt;p&gt;i番目のオブジェクトのサイズ=offsets[i+1] - offsets[i]&lt;/p&gt;&lt;/blockquote&gt;&lt;p dir=&quot;ltr&quot;&gt;で一様に求まる。このオフセットはオフセット配列の直前のバイトからのオフセットつまりoffSizeフィールドからのオフセットを表すので、オフセット配列の最初の要素offsets[0]は常に1になる。ちなみに、countフィールドが0の空のINDEXの場合、残りのフィールドは存在しない。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;例えば、各フォント間で共有される文字列はString INDEXに上記の構造においてオブジェクトとして格納されている。同様に、フォント毎の情報は次に説明するDICTデータとして表現されるが、これらの情報はTop DICT INDEXに上記の構造においてオブジェクトとして格納されている(ややこしいが、Top DICT INDEX全体は上記のINDEXデータでINDEXデータ内に含まれる各オブジェクトが次に説明するDICTデータである)。&lt;/p&gt;

&lt;p&gt;次はDICTデータについて。&lt;/p&gt;

&lt;p&gt;DICT(DICTionary)データはキー・値のペアのコレクションであり、キーは1または2バイトのデータ、値は可変長の整数または実数を表すデータである(ちなみに、値には複数個の整数や実数の配列としても格納できる)。&lt;/p&gt;

&lt;p&gt;DICTデータの各キー・値のペアは特別なルールでエンコードされていて、ここでは、詳細については省略するが、簡単に説明すると&lt;/p&gt;

&lt;p&gt;値を表すバイトデータ、キーを表すバイトデータ、値を表すバイトデータ、キーを表すバイトデータ・・・・・&lt;/p&gt;

&lt;p&gt;のようにエンコードされる。キー・値のペアの値のデータが先にくる。また、(先頭の)バイトデータによって値とキーが区別できるようになっているので、DICTデータの先頭から1バイトずつ処理すればデコードできるようになっている。例えば、DICTデータをデコードするプログラムは次のようになる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;
const
  NibbleTable: array [0..15] of AnsiChar =
    (&#39;0&#39;, &#39;1&#39;, &#39;2&#39;, &#39;3&#39;, &#39;4&#39;, &#39;5&#39;, &#39;6&#39;, &#39;7&#39;, &#39;8&#39;, &#39;9&#39;, &#39;.&#39;, &#39;E&#39;, &#39;E&#39;, #0, &#39;-&#39;, #0);
var
  I: Integer;
  B0, B1, B2, B3, B4: Byte;
  D: Double;
  Nibbles: array [0..1] of Byte;
  S: string;
  Key: Word;
  Value, V: Variant;
begin
  repeat
    // 値の読み込み
    B0 := Stream.ReadByte;
    case B0 of
    0..21: // key
      raise ECFFException.Create(SCffReadError);
    22..27: // reserved
      raise ECFFException.Create(SCffReadError);
    28: // 3-byte整数フォーマット
      begin
        B1 := Stream.ReadByte;
        B2 := Stream.ReadByte;
        V := Smallint((B1 shl 8) or B2);
      end;
    29: // 5-byte整数フォーマット
      begin
        B1 := Stream.ReadByte;
        B2 := Stream.ReadByte;
        B3 := Stream.ReadByte;
        B4 := Stream.ReadByte;
        V := Integer((B1 shl 24) or (B2 shl 16) or (B3 shl 8) or B4);
      end;
    30: // 実数フォーマット
      begin
        S := &#39;&#39;;
        repeat
          B1 := Stream.ReadByte;
          Nibbles[0] := B1 shr 4;
          Nibbles[1] := B1 and $F;
          for I := Low(Nibbles) to High(Nibbles) do
            case Nibbles[I] of
            0..9, 10, 11, 12, 14:
              begin
                S := S + NibbleTable[Nibbles[I]];
                if Nibbles[I] = 12 then
                  S := S + &#39;-&#39;;
              end;
            13: ECFFException.Create(SCffReadError);
            15: ;// do nothing
            end;
        until (Nibbles[0] = 15) or (Nibbles[1] = 15);
        if not TryStrToFloat(S, D) then
          raise ECFFException.Create(SCffReadError);
        V := D; // 実数は実数のバリアントとして格納
      end;
    31: // reserved
      ECFFException.Create(SCffReadError);
    32..246:  // 1-byte整数フォーマット
      V := Shortint(B0 - 139);
    247..250: // 2-byte整数フォーマット
      begin
        B1 := Stream.ReadByte;
        V := Smallint((B0 - 247)*256 + B1 + 108);
      end;
    251..254: // 2-byte整数フォーマット
      begin
        B1 := Stream.ReadByte;
        V := Smallint(-(B0 - 251)*256 - B1 - 108);
      end;
    255: // reserved
      ECFFException.Create(SCffReadError);
    end;
    if VarIsEmpty(Value) then
      Value := V
    else
    // 配列の場合、バリアント配列として格納
    if not VarIsArray(Value) then
      Value := VarArrayOf([Value, V])
    else
    begin
      VarArrayRedim(Value, VarArrayHighBound(Value, 1) + 1);
      Value[VarArrayHighBound(Value, 1)] := V;
    end;
  until Stream.PeekByte in [0..21];

  // キーの読み込み
  B0 := Stream.ReadByte;
  if B0 = CffDictKeyEscape then
  begin
    // 2-byteのキー
    B1 := Stream.ReadByte;
    Key := (B0 shl 8) or B1;
  end else
    // 1-byteのキー
    Key := B0;
  Result := TCffKeyValue.Create(Key, Value);
end;
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;具体的には先頭バイトが0-21ならキー、28、29、247-254なら整数の値、30なら実数の値という具合になっている<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。上記のプログラムは１つのキー・値ペアをデコードするプログラムであるが、通常、DICTデータへのオフセットと共にDICTデータ全体のサイズが与えられるので、与えられたサイズに達するまでデコードすれば、DICTデータに含まれるすべてのキー・値のペアをデコードできる。&lt;/p&gt;

&lt;p&gt;と、抽象的なことばかりだとイメージが掴みにくいかもしれないので、次回以降具体的にこれらの中身を見ていこうと思う。また、次回でCFFの解析に対応したT2FAnalzyerの最新版も同時にアップロードしようと思う<img class="emoticon happy02" src="http://emojies.cocolog-nifty.com/emoticon/happy02.gif" alt="happy02" />。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>フォント</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-11-04T01:28:07+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/10/cfftype2-charst.html">
<title>CFF/Type2 Charstring</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/10/cfftype2-charst.html</link>
<description>データベース絡みの事をやっていたのであるが、行き詰まったので、気...</description>
<content:encoded>&lt;p&gt;データベース絡みの事をやっていたのであるが、行き詰まった<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />ので、気分転換にちょっと本格的にT2FAnalyzerで要望のあったCFF(Compact Font Format)/Type2 Charstringの解析に向けて、仕様書を読み始めた。&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/typography/otspec/5176.CFF.pdf&quot;&gt;Adobe Technical Note #5176: &amp;quot;The Compact Font Format Specification&amp;quot;&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/typography/otspec/5177.Type2.pdf&quot;&gt;Adobe Technical Note #5177: &amp;quot;Type 2 Charstring Format&amp;quot;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Type2 Charstringというものがグリフのアウトラインを記述してるようであるが、TrueTypeアウトラインのglyfテーブルと違って、CFFアウトラインは一種のプログラムじゃん<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。このプログラムの実行環境であるType2 Charstringインタプリタもどきみたいなの作らんとアウトラインの形状をラスタライズできそうにもないな(TrueTypeインストラクションほど複雑そうではないが・・)<img class="emoticon wobbly" src="http://emojies.cocolog-nifty.com/emoticon/wobbly.gif" alt="wobbly" />。&lt;/p&gt;

&lt;p&gt;うーん。&lt;/p&gt;

&lt;p&gt;漠然とCFF/Type2の全体のイメージが掴めたので、CFF/Type2の解析部分のプログラミングを開始しました<img class="emoticon happy02" src="http://emojies.cocolog-nifty.com/emoticon/happy02.gif" alt="happy02" />。&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=684,height=752,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/10/26/cfftype2.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mb&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/10/26/cfftype2_2.jpg&quot;&gt;&lt;img title=&quot;Cfftype2_2&quot; height=&quot;329&quot; alt=&quot;Cfftype2_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/10/26/cfftype2_2.jpg&quot; width=&quot;300&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>フォント</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-10-26T14:05:39+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3212sehstruc.html">
<title>Win32デバッグ(12)・・・SEH(Structured Exception Handling)</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3212sehstruc.html</link>
<description>まぁ、どうしようか悩んだが、とりあえず、進める所まで進んでみます。...</description>
<content:encoded>&lt;p&gt;まぁ、どうしようか悩んだが、とりあえず、進める所まで進んでみます<img class="emoticon sad" src="http://emojies.cocolog-nifty.com/emoticon/sad.gif" alt="sad" />。&lt;/p&gt;

&lt;p&gt;ということで今回のお題目は例外。結論から言うとDelphiではtry-except文による例外処理にしろ、try-finally文の終了処理にしろ、Windowsの&lt;strong&gt;SEH&lt;/strong&gt;(&lt;strong&gt;Structured Exception Handling&lt;/strong&gt;)を使って実装されているのだが、そのSEHについて。&lt;/p&gt;

&lt;p&gt;SEHはWindowsによって提供されている構造化例外処理のためのメカニズムのことであるが、その流れについて説明する。&lt;/p&gt;

&lt;p&gt;まず、0による除算や不正なメモリへのアクセスなどのハードウェア例外にしろ、Win32 APIの&lt;strong&gt;RaiseException&lt;/strong&gt;関数によるソフトウェア例外にしろ、スレッド内で例外が発生するとOSに制御が移る。そして、OSは例外が発生したスレッドのCPUレジスタなどのコンテキスト情報の保存など必要な処理を行った後、例外をハンドルするための例外ハンドラを検索し、呼び出す。&lt;/p&gt;

&lt;p&gt;具体的には、まず、OSは例外が発生したスレッドの&lt;strong&gt;スレッド環境ブロック&lt;/strong&gt;(&lt;strong&gt;TEB&lt;/strong&gt;:&lt;strong&gt;Thread Environment Block&lt;/strong&gt;)または&lt;strong&gt;スレッド情報ブロック&lt;/strong&gt;(&lt;strong&gt;TIB&lt;/strong&gt;:&lt;strong&gt;Thread Information Block&lt;/strong&gt;)と呼ばれる領域の先頭4バイト(at FS:[0])の値を取得する。この4バイトの値は例外ハンドラのリンクリストの先頭をポイントしているので、この値から先頭の例外ハンドラから順に呼び出していくのである(つまり、ここに例外ハンドラを登録すれば例外発生時に例外ハンドラが呼び出されるようになるのだが、通常は、Delphiにしろ、C++にしろ、言語提供の例外処理などを利用すれば、コンパイラによって登録するコードが挿入されるので、普通は自前で登録しないが・・)。&lt;/p&gt;

&lt;p&gt;リンクリストのノードは次のようなEXCEPTION_REGISTRATION構造体になっている。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;c&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;
// 基本的なOS定義の例外フレーム
struct EXCEPTION_REGISTRATION {
  EXCEPTION_REGISTRATION* prev;
  FARPROC                 handler;
};
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;prevメンバは次のノードへのアドレス、handlerメンバーには例外ハンドラのアドレスつまりOSから呼び出されるコールバック関数のアドレスを表す。呼び出されるコールバック関数のプロトタイプは次のようになる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;c&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;
EXCEPTION_DISPOSITION
  __cdecl _except_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void * EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void * DispatcherContext
  );

typedef struct _EXCEPTION_RECORD {
  DWORD ExceptionCode;
  DWORD ExceptionFlags;
  struct _EXCEPTION_RECORD *ExceptionRecord;
  PVOID ExceptionAddress;
  DWORD NumberParameters;
  DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
&lt;/textarea&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;第1引数は&lt;strong&gt;EXCEPTION_RECORD&lt;/strong&gt;構造体のアドレスである。EXCEPTION_RECORD構造体は例外の種類を表すコードや例外発生時のアドレスなどの発生した例外に関する様々な情報が格納されているので、例外ハンドラはこれらの情報を見て例外を処理するかを決定する。Delphiのtry-except文では例外オブジェクトのクラスとexceptのon句に指定したクラス(on E: ExceptionClass doのExceptionClassの部分)を比較して判定している。&lt;/p&gt;

&lt;p&gt;呼び出された例外ハンドラで例外を処理せず、OSに次の例外ハンドラを呼び出させる場合はExceptionSearchException(1)を返して例外ハンドラからOSにリターンする。&lt;/p&gt;

&lt;p&gt;また、例外が発生したアドレスから例外の原因を修正(0による除算が発生した場合、除数を0以外の値に修正)するなどして、再実行する場合はExceptionContinueExecute(0)を返してOSにリターンする。Delphiではこれは行われない。&lt;/p&gt;

&lt;p&gt;例外ハンドラで例外を処理する場合は、例外ハンドラからOSにリターンせず、通常は、Win32APIの&lt;strong&gt;RtlUnwind&lt;/strong&gt;などでアンワインド(巻き戻し)したり、スタックフレームを適切に設定し直して、処理を続行する。Delphiではexceptのon句の後に指定した処理から実行が再開される。&lt;/p&gt;

&lt;p&gt;RtlUnwindによるアンワインドはMSDNのドキュメントみても何の事だかさっぱり理解できないと思うが、簡単に言うと、例外ハンドラのリンクリストから不必要になった例外ハンドラのノードを削除することである。また、このとき、例外ハンドラの2回目の呼び出しが行われる。この2回目の呼び出しのときに、通常は終了処理を行う。Delphiではtry-finally文のfinally句の後に指定した終了処理がこの2回目の呼び出しのときに、実行される。&lt;/p&gt;

&lt;p&gt;とまぁ、おおざっぱに書くとこんなところであろうが、詳細は&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.microsoft.com/msj/0197/Exception/Exception.aspx&quot;&gt;A Crash Course on theDepths of Win32 Structured Exception Handling&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=&quot;http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx&quot;&gt;The Exception Model&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=&quot;http://www.jorgon.freeserve.co.uk/Except/Except.htm&quot;&gt;Win32 Exception handling for assembler programmers&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;すべて、英語で書かれているが、特に一番上の記事にはSEHについて分かりやすく、詳細に書かれているのでお勧めです。自分は頑張って読みました<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>Delphi</dc:subject>
<dc:subject>Windows</dc:subject>
<dc:subject>デバッグ</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-10-07T08:21:28+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3211getselec.html">
<title>Win32デバッグ(11)・・・番外編</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/10/win3211getselec.html</link>
<description>今回は寄り道。というより、前回までに示したコードに少し問題があった。 第１回で ...</description>
<content:encoded>&lt;p&gt;今回は寄り道。というより、前回までに示したコードに少し問題があった。&lt;/p&gt;

&lt;p&gt;第１回で&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;strong&gt;ReadProcessMemory&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;WriteProcessMemory&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;を使えば、プロセスハンドルからそのプロセスのアドレス空間を読み書きできるし、また、&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;strong&gt;GetThreadContext&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SetThreadContext&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;を使えば、スレッドハンドルからそのスレッドのコンテキスト(レジスタの値)を読み書きできる。&lt;/p&gt;

&lt;p&gt;と書いたが、大切な事が抜けていた<img class="emoticon shock" src="http://emojies.cocolog-nifty.com/emoticon/shock.gif" alt="shock" />。&lt;/p&gt;

&lt;p&gt;ということで、例えば、あるスレッドが次に実行する命令を読み込むプログラムを上記のAPIを使って書いてみる。x86アキーテクチャではインストラクションポインタ(EIP)レジスタが次に実行される命令をポイントするので、例えば、次のようになる(繰り返すが、対象スレッドは停止してないとまずいと思う)。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;
var
  Context: TContext;
  ByteRead: DWORD;
  Instruction: DWORD;
begin
  // プロセスハンドル、スレッドハンドルは
  // 既に与えられてると想定

  FillChar(Context, SizeOf(Context), $00);
  Context.ContextFlags := CONTEXT_FULL;
  // レジスタ値の取得
  GetThreadContext(hThread, Context);

  ReadProcessMemory(hProcess, Pointer(Context.Eip),
    @Instruction, SizeOf(Instruction), ByteRead);
end;
&lt;/textarea&gt;&lt;/p&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;x86命令は可変長の命令で何バイト読みこめばよいか？という問題があるが、上記のプログラムではとりあえず4バイト読み込んでいる。上記のプログラムを実際に動かすと正しく動いているように見えるが、問題があるのである。&lt;/p&gt;

&lt;p&gt;何が問題かと言うと、ReadProcessMemory/WriteProcessMemoryの第2引数には読み書きするメモリの仮想アドレスを渡すのであり、上記のプログラムでは、EIPレジスタの値を渡しているのであるが、EIPレジスタの値は仮想アドレスの値ではないのである。EIPレジスタに格納されているのは確かにアドレスであるが、CSレジスタに格納されているセグメントセレクタによってポイントされるセグメント(コードセグメント)内の相対アドレス(segment-relative address)なのである。&lt;/p&gt;

&lt;p&gt;ということで、仮想アドレスに変換する必要があるのであるが、そのために使うAPIが&lt;strong&gt;GetThreadSelectorEntry&lt;/strong&gt;である。GetThreadSelectorEntryによって引数で指定したセグメントの仮想アドレス空間内のセグメントのベースアドレスが求まるので、それを使って正しく先ほどのプログラムを書き換えると次のようになる。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;


&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;
var
  Context: TContext;
  LDTEntry: TLDTEntry;
  CsBase: DWORD;
  ByteRead: DWORD;
  Instruction: DWORD;
begin
  // プロセスハンドル、スレッドハンドルは
  // 既に与えられてると想定

  FillChar(Context, SizeOf(Context), $00);
  Context.ContextFlags := CONTEXT_FULL;
  // レジスタ値の取得
  GetThreadContext(hThread, Context);

  // コードセグメントのベースアドレスの計算
  GetThreadSelectorEntry(hThread, Context.SegCs, LDTEntry);
  CsBase := LDTEntry.BaseLow + (LDTEntry.BaseMid shl 8) + (LDTEntry.BaseHi shl 16);

  ReadProcessMemory(hProcess, Pointer(Context.Eip + CsBase),
    @Instruction, SizeOf(Instruction), ByteRead);
end;
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;と、肝心な事を忘れた<img class="emoticon dash" src="http://emojies.cocolog-nifty.com/emoticon/dash.gif" alt="dash" />。&lt;/p&gt;

&lt;p&gt;ちなみに、最初に示したプログラムが動いてしまうのは、どうも、NT環境ではコードセグメントのベースアドレスが常に0になるからのようである。特にESPレジスタによってポイントされるスタックトップを読み書きするような場合、スレッド毎に異なるスタックセグメント(SSレジスタ)が割り当てられるので、なお更まずい。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>Windows</dc:subject>
<dc:subject>デバッグ</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-10-06T05:49:49+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/09/win3210-163f.html">
<title>Win32デバッグ(10)・・・泣</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/09/win3210-163f.html</link>
<description>このネタも10回目に突入してしまった。 早速、前回やり残し...</description>
<content:encoded>&lt;p&gt;このネタも10回目に突入してしまった<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。&lt;/p&gt;

&lt;p&gt;早速、前回やり残した事をやる。前回で逆アセンブラスクラスを設計したので、今回は問題となっていたデバッグ情報からルーチンの終了位置のアドレスを求める部分を逆アセンブルして求めるよう次のように書き換える。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;procedure TDebugger.CreateBreakpoints(AModule: TModule);
label
&amp;nbsp; DisasmError;
var
&amp;nbsp; I: Integer;
&amp;nbsp; Breakpoint: TBreakpoint;
&amp;nbsp; Disasm: TDisassembler;
&amp;nbsp; SectionHeaders: TSectionHeaders;
&amp;nbsp; StartAddress, EndAddress: PAnsiChar;
&amp;nbsp; StartByte, EndByte: Byte;
&amp;nbsp; Symbol: TSymbol;
&amp;nbsp; EndOffset: Integer;
&amp;nbsp; Bytes: array of Byte;
begin
&amp;nbsp; if (FDisasmClass &amp;lt;&amp;gt; nil) and (AModule.Symbols &amp;lt;&amp;gt; nil) then
&amp;nbsp; begin
&amp;nbsp; &amp;nbsp; AModule.Symbols.LockList;
&amp;nbsp; &amp;nbsp; SectionHeaders := AModule.ReadSectionHeaders;
&amp;nbsp; &amp;nbsp; for I := 0 to AModule.Symbols.Count - 1 do
&amp;nbsp; &amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;Symbol := TSymbol(AModule.Symbols[I]);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if Symbol &amp;lt;&amp;gt; nil then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if (Symbol.Length &amp;gt;= 2) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; (1 &amp;lt;= Symbol.Section) and (Symbol.Section &amp;lt;= Length(SectionHeaders)) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; StartAddress := PAnsiChar(AModule.ModuleBase) +
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;SectionHeaders[Symbol.Section - 1].VirtualAddress + Symbol.StartOffset;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; SetLength(Bytes, Symbol.Length);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; try
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;AModule.Process.ReadBuffer(StartAddress, Pointer(Bytes), Length(Bytes));

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;EndOffset := 0;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;Disasm := FDisasmClass.Create(Pointer(Bytes)); // 逆アセンブラオブジェクト生成
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;try
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; while Disasm.Offset &amp;lt; Length(Bytes) do
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; if not Disasm.Next then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;goto DisasmError;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; if VarIsEmpty(Disasm.Opcode3) and VarIsEmpty(Disasm.Opcode2) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;// RET命令検出
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (Disasm.Opcode1 = $C2) or (Disasm.Opcode1 = $C3) or
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; (Disasm.Opcode1 = $CA) or (Disasm.Opcode1 = $CB) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; EndOffset := Disasm.Offset - Disasm.Length;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if EndOffset &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; // RET命令が検出された場合だけブレークポイント設定
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; EndAddress := StartAddress + EndOffset;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; if (AModule.Breakpoints[StartAddress] = nil) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; (AModule.Breakpoints[EndAddress] = nil) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;StartByte := AModule.Process.ReadByte(StartAddress);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;EndByte := AModule.Process.ReadByte(EndAddress);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (StartByte &amp;lt;&amp;gt; OPCODE_INT3) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;(EndByte&amp;nbsp; &amp;nbsp;&amp;lt;&amp;gt; OPCODE_INT3) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint := AModule.Breakpoints.Add(StartAddress);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint.OriginalCode := StartByte;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint.Symbol := Symbol;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint.Start := True;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint := AModule.Breakpoints.Add(EndAddress);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint.OriginalCode := EndByte;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Breakpoint.Symbol := Symbol;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; DisasmError:
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;finally
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Disasm.Free;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; finally
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;SetLength(Bytes, 0);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp; end;
&amp;nbsp; end;
end;
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;で、再びドライバプログラムを実行してターゲットプログラムをプロファイルしてみたところ、ターゲットプログラムが正常に動作した<img class="emoticon happy02" src="http://emojies.cocolog-nifty.com/emoticon/happy02.gif" alt="happy02" />。プロファイルしたターゲットプログラムはコンソールアプリで次の通り。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;program TD32Target;

{$APPTYPE CONSOLE}

uses
&amp;nbsp; SysUtils;

function Sum(A1, A2: Integer): Integer;
begin
&amp;nbsp; Result := A1 + A2;
end;

function Mul(A1, A2: Integer): Integer;
begin
&amp;nbsp; Result := A1*A2;
end;

function Calc(A1, A2: Integer): Integer;
begin
&amp;nbsp; Result := Mul(A1,A2) + Sum(A1, A2);
end;

var
&amp;nbsp; I: Integer;
&amp;nbsp; A1, A2: Integer;
&amp;nbsp; S: string;
&amp;nbsp; R: Integer;
begin
&amp;nbsp; for I := 0 to 10 - 1 do
&amp;nbsp; begin
&amp;nbsp; &amp;nbsp; A1 := Random(10);
&amp;nbsp; &amp;nbsp; A2 := Random(10);
&amp;nbsp; &amp;nbsp; R := Calc(A1, A2);
&amp;nbsp; &amp;nbsp; S := IntToStr(R);
&amp;nbsp; &amp;nbsp; WriteLn(S);
&amp;nbsp; end;
end.
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;意味のないプログラムであるが、関数Calcが10回呼び出され、その結果がコンソールに表示されるだけである。また、関数Calcからは関数SumとMulが呼び出される。このターゲットプログラムのコールツリーは次のようになった。&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=1022,height=823,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/09/30/win32debug_10_1.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=1022,height=823,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/09/30/win32debug_10_1_2.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=1022,height=823,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/09/30/win32debug_10_1_3.jpg&quot;&gt;&lt;img title=&quot;Win32debug_10_1_3&quot; height=&quot;322&quot; alt=&quot;Win32debug_10_1_3&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/09/30/win32debug_10_1_3.jpg&quot; width=&quot;400&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;上の画面から確かに関数Calcが呼び出され、関数Calcから関数SumとMulが呼び出されているのが分かるだが、呼び出された回数つまりヒットカウントが10ではなく1になってるのである・・・全部合計すると10回なのであるが、ノードが分かれている・・・&lt;/p&gt;

&lt;p&gt;がーん<img class="emoticon sad" src="http://emojies.cocolog-nifty.com/emoticon/sad.gif" alt="sad" />。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;で、デバッグして原因を調べたところ、肝心な事をすっかり忘れていた<img class="emoticon sad" src="http://emojies.cocolog-nifty.com/emoticon/sad.gif" alt="sad" />。それは、最近の言語でたいていはサポートされている例外処理・終了処理である。Delphiでいうところの&lt;strong&gt;try&lt;/strong&gt;-&lt;strong&gt;except&lt;/strong&gt;,&lt;strong&gt;try&lt;/strong&gt;-&lt;strong&gt;finally&lt;/strong&gt;文である。この実現のためにコンパイラが生成してるコードに対応できていなかったのである。つまり、今までの設計では、ルーチンは必ずCALL命令で呼び出されRET命令でリータンする、また、RET命令は必ずルーチン内で1箇所だけ(現状、１つのルーチンに対して開始位置と終了位置の2つだけのブレークポイントを作成してるため)という仕様？前提？が甘かったのである・・・(JMP命令なども無視してるし・・・)&lt;/p&gt;

&lt;p&gt;はぁ。&lt;/p&gt;

&lt;p&gt;どうしよう？？&lt;/p&gt;

&lt;p&gt;と、本来はすべてが上手くいき今回で最終回にする予定であったのだが。どうしよう。&lt;/p&gt;

&lt;p&gt;また、ドライバプログラムも含めて動作する形でソースをアップロードする予定であったのだが、どうせおかしなコールグラフが表示されるのでやめておく。&lt;/p&gt;

&lt;p&gt;と言う事で次回に続くかは本気で分からない・・ははは。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>Windows</dc:subject>
<dc:subject>デバッグ</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-09-30T01:49:13+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/09/odbc-f213.html">
<title>ODBCヘッダー</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/09/odbc-f213.html</link>
<description>また、さぼってた。なんというかプログラミングに対する情熱？自...</description>
<content:encoded>&lt;p&gt;また、さぼってた<img class="emoticon wobbly" src="http://emojies.cocolog-nifty.com/emoticon/wobbly.gif" alt="wobbly" />。なんというかプログラミングに対する情熱？自体が最近なくなってきた<img class="emoticon wobbly" src="http://emojies.cocolog-nifty.com/emoticon/wobbly.gif" alt="wobbly" />。要するに作りたいものがなくなってきた。&lt;/p&gt;

&lt;p&gt;そんな事はさておき、今回は以前やりかけの事がたくさんあると書いたが、その内のとりあえず公開できそうな物を公開してみる。ということで、今回はODBC(Open DataBase Connectivity)のDelphi用ヘッダーファイル。Cのヘッダーファイルを以前に頑張って移植した<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。&lt;/p&gt;

&lt;p&gt;まぁ、今更ODBC？みたいな感があるが・・・Unicodeに対応するDelphi2009以前のDelphi用ですのであしからず。また、ODBCの関数を使う時は現状、LoadLibraryで自分でDLLをロードして下さい<img class="emoticon sad" src="http://emojies.cocolog-nifty.com/emoticon/sad.gif" alt="sad" />。ダウンロードは&lt;a href=&quot;http://cid-011d6139819c0b60.skydrive.live.com/browse.aspx/Public/ODBC/Delphi%20Headers?view=details&quot;&gt;SkyDrive&lt;/a&gt;から。&lt;/p&gt;

&lt;p&gt;本当はODBCのコンポーネントを作っていたのだが、まだ、公開できる状態ではないので、ヘッダーファイルだけでも・・・&lt;/p&gt;

&lt;p&gt;ところでDelphiの最新版であるDelphi 2010が発売されたのであるが、Unicodeアプリを作れる環境がほしいので久しぶりに購入しようかなと思ってたり。でも、作りたいものがなくなってきたこともあり悩んでます。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>Delphi</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-09-24T14:19:34+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/08/post-33cd.html">
<title>間隔(インターバル)型の続き</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/08/post-33cd.html</link>
<description>以前の続きであるが、今回は間隔型のODBCでの対応について。 ODBCではSQL...</description>
<content:encoded>&lt;p&gt;&lt;a href=&quot;http://vanilla-room.cocolog-nifty.com/blog/2009/08/post.html&quot;&gt;以前&lt;/a&gt;の続きであるが、今回は間隔型のODBCでの対応について。&lt;/p&gt;

&lt;p&gt;ODBCではSQL92の間隔型に相当するデータ型が定義されていて、そのSQLデータ型は次のようになる。&lt;/p&gt;&lt;blockquote dir=&quot;ltr&quot;&gt;&lt;p&gt;年月間隔&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_YEAR&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_MONTH&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_YEAR_TO_MONTH&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;日時間隔&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_DAY&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_HOUR&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_MINUTE&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_SECOND&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_DAY_TO_HOUR&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_DAY_TO_MINUTE&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_DAY_TO_SECOND&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_HOUR_TO_MINUTE&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_HOUR_TO_SECOND&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;SQL_INTERVAL_MINUTE_TO_SECOND&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;これら間隔型のデータをアプリケーションから入出力する時に、Cデータ型のSQL_C_CHARにマップつまり文字列として入出力してもよいのだが、間隔型専用のSQL_C_INTERVALの接頭辞で始まるCデータ型(SQL_C_INTERVAL_YEAR等)にマップして入出力することもできる。SQL_C_INTERVALの接頭辞で始まるCデータ型は&lt;strong&gt;SQL_INTERVAL_STRUCT&lt;/strong&gt;構造体として定義され、次のようになっている。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;textarea cols=&quot;80&quot; name=&quot;code&quot; class=&quot;c&quot;&gt;
typedef struct tagSQL_INTERVAL_STRUCT
{
   SQLINTERVAL interval_type; 
   SQLSMALLINT interval_sign;
   union {
         SQL_YEAR_MONTH_STRUCT   year_month;
         SQL_DAY_SECOND_STRUCT   day_second;
         } intval;
} SQL_INTERVAL_STRUCT;
typedef enum 
{
   SQL_IS_YEAR = 1,
   SQL_IS_MONTH = 2,
   SQL_IS_DAY = 3,
   SQL_IS_HOUR = 4,
   SQL_IS_MINUTE = 5,
   SQL_IS_SECOND = 6,
   SQL_IS_YEAR_TO_MONTH = 7,
   SQL_IS_DAY_TO_HOUR = 8,
   SQL_IS_DAY_TO_MINUTE = 9,
   SQL_IS_DAY_TO_SECOND = 10,
   SQL_IS_HOUR_TO_MINUTE = 11,
   SQL_IS_HOUR_TO_SECOND = 12,
   SQL_IS_MINUTE_TO_SECOND = 13
} SQLINTERVAL;

typedef struct tagSQL_YEAR_MONTH
{
   SQLUINTEGER year;
   SQLUINTEGER month; 
} SQL_YEAR_MONTH_STRUCT;

typedef struct tagSQL_DAY_SECOND
{
   SQLUINTEGER day;
   SQLUINTEGER hour;
   SQLUINTEGER minute;
   SQLUINTEGER second;
   SQLUINTEGER fraction;
} SQL_DAY_SECOND_STRUCT;
&lt;/textarea&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;まぁ、ここらへんはODBCのドキュメントに書いてあるので・・&lt;/p&gt;

&lt;p&gt;ここでは、ちょっとWindowsのお話でも。.NET Frameworkでは間隔を扱うTimeSpan構造体というものが定義されているが、WindowsのネイティブAPIで間隔を扱うAPIなんてものがあるのかな？と前から思っていたら偶然発見した<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。&lt;/p&gt;

&lt;p&gt;まずは、&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb759980(VS.85).aspx&quot;&gt;StrFromTimeInterval&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;間隔を文字列表現に変化するAPIであるが、実際に使って10万ミリ秒を変換してみた。 &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;img title=&quot;Interval2_1&quot; alt=&quot;Interval2_1&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/photos/uncategorized/2009/08/23/interval2_1.jpg&quot; border=&quot;0&quot; /&gt; &lt;/p&gt;

&lt;p&gt;このAPIはShell Lightwight Utility Functionsと呼ばれるAPIで将来のWindowsでは変更または利用不可になるかもしれないとの事・・・エクスプローラでファイルをコピーすると残りXX秒とかダイアログに表示されるが、そこで使われているのだろうか？？&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;次は、Vistaで追加された&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd318091(VS.85).aspx&quot;&gt;GetDurationFormat&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd318092(VS.85).aspx&quot;&gt;GetDurationFormatEx&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;こちらも文字列表現に変換するAPIであるが、StrFromTimeIntervalと違いロケールや書式を指定できるとの事。これに合わせて、GetLocaleInfoなどでロケールに関する様々な情報を取得・設定できるが、間隔用のフォーマットの&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd373842(VS.85).aspx&quot;&gt;LOCALE_SDURATION&lt;/a&gt;定数が追加されている。Vistaもってないのでこららを試すことできないが・・・ &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>DB2</dc:subject>
<dc:subject>Oracle</dc:subject>
<dc:subject>Windows</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-08-23T06:24:42+09:00</dc:date>
</item>
<item rdf:about="http://vanilla-room.cocolog-nifty.com/blog/2009/08/win329-67d1.html">
<title>Win32デバッグ(9)・・・逆アセンブラ</title>
<link>http://vanilla-room.cocolog-nifty.com/blog/2009/08/win329-67d1.html</link>
<description>前回で、どうもx86命令を逆アセンブルする必要が出てきたので今回は逆アセンブルに...</description>
<content:encoded>&lt;p&gt;前回で、どうもx86命令を逆アセンブルする必要が出てきたので今回は逆アセンブルについて。&lt;/p&gt;

&lt;p&gt;まずは、逆アセンブラを自作する方向で進めていたのであるが、ご存知のようにx86命令は可変長であったり、SSE命令などの拡張命令がどんどん追加されていったり、面倒そうなので、とりあえず、既存の逆アセンブラライブラリを利用する事にした。&lt;/p&gt;

&lt;p&gt;ということで既存の逆アセンブラライブラリをいくつか挙げてみる。&lt;/p&gt;

&lt;table border=&quot;1&quot;&gt;&lt;caption&gt;逆アセンブラライブラリ&lt;/caption&gt;&lt;tbody&gt;&lt;tr bgcolor=&quot;#c0c0c0&quot;&gt;&lt;td&gt;名前&lt;/td&gt;

&lt;td&gt;サイト&lt;/td&gt;

&lt;td&gt;ライセンス&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;BeaEngine&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://beatrix2004.free.fr/&quot;&gt;http://beatrix2004.free.fr/&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;LGPL&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;diStorm64&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://www.ragestorm.net/distorm/&quot;&gt;http://www.ragestorm.net/distorm/&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;BSD&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Hacker Disassembler Engine(HDE)&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://patkov-site.narod.ru/&quot;&gt;http://patkov-site.narod.ru/&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;Free&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;libdisasm&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://bastard.sourceforge.net/libdisasm.html&quot;&gt;http://bastard.sourceforge.net/libdisasm.html&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;Free/Open Source&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;SysDasm&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://rootkit.com/newsread.php?newsid=208&quot;&gt;http://rootkit.com/newsread.php?newsid=208&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;Free/Open Source&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;Udis86&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://udis86.sourceforge.net/&quot;&gt;http://udis86.sourceforge.net/&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;Free/Open Source&lt;/td&gt;&lt;/tr&gt;

&lt;tr bgcolor=&quot;#f0f0f0&quot;&gt;&lt;td&gt;VirtualBox Disassembler Library&lt;/td&gt;

&lt;td&gt;&lt;a href=&quot;http://www.woodmann.com/forum/showthread.php?t=11904&quot;&gt;http://www.woodmann.com/forum/showthread.php?t=11904&lt;/a&gt;&lt;/td&gt;

&lt;td&gt;?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;各逆アセンブラライブラリの詳細については、各ライブラリのサイトを参照。ここではどのライブラリを使うかだが、ここでは上記の１つであるHacker Disassembler Engine(HDE)を使うことにした。理由は最終更新日が最近(2009年3月)であるのと、軽量である点だ。他のライブラリは結構高機能で逆アセンブルした機械語をアセンブラのニーモニックのテキスト形式に変換できたりするが、今回はx86命令のRET命令を検出できればよいので、命令長やオプコードなど最小限の情報だけを取得できるHDEにした(ちなみに、上記BeaEngineのサイトにLength Disassemblerというものもあるようだ・・)。&lt;/p&gt;

&lt;p&gt;次に、新しいクラスを設計するが、その前にx86命令の大まかな命令フォーマットを知らないと設計できないので、x86命令の命令フォーマットを少し。x86命令の命令フォーマットは次のようになる。&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=659,height=321,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/08/14/x86instformat.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a onclick=&quot;window.open(this.href, &#39;_blank&#39;, &#39;width=659,height=321,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&#39;); return false&quot; href=&quot;http://vanilla-room.cocolog-nifty.com/.shared/image.html?/photos/uncategorized/2009/08/14/x86instformat_2.jpg&quot;&gt;&lt;img title=&quot;X86instformat_2&quot; height=&quot;256&quot; alt=&quot;X86instformat_2&quot; src=&quot;http://vanilla-room.cocolog-nifty.com/blog/images/2009/08/14/x86instformat_2.jpg&quot; width=&quot;527&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;先程も述べたように可変長なのであるが、各フィールドの詳細はIntelの&lt;a href=&quot;http://www.intel.com/products/processor/manuals/index.htm&quot;&gt;マニュアル&lt;/a&gt;を参照ということで。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;まずは、抽象クラスで逆アセンブルを行うTDisassemblerクラス。&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;&amp;nbsp; TDisassembler = class
&amp;nbsp; private
&amp;nbsp; &amp;nbsp; FBuffer: Pointer;
&amp;nbsp; &amp;nbsp; FOffset: Integer;
&amp;nbsp; private
&amp;nbsp; &amp;nbsp; FPrefixes: TByteDynArray;
&amp;nbsp; &amp;nbsp; FOpcode3: Variant;
&amp;nbsp; &amp;nbsp; FOpcode2: Variant;
&amp;nbsp; &amp;nbsp; FOpcode1: Byte;
&amp;nbsp; &amp;nbsp; FModRM: Variant;
&amp;nbsp; &amp;nbsp; FSIB: Variant;
&amp;nbsp; &amp;nbsp; FDisplacement: Variant;
&amp;nbsp; &amp;nbsp; FImmediate: Variant;
&amp;nbsp; &amp;nbsp; FLength: Byte;
&amp;nbsp; protected
&amp;nbsp; &amp;nbsp; function DoNext(P: Pointer; var APrefixes: TByteDynArray;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var AOpcode3: Variant; var AOpcode2: Variant; var AOpcode1: Byte;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var AModRM: Variant; var ASIB: Variant; var ADisplacement: Variant; var AImmediate: Variant;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var ALength: Byte): Boolean; virtual; abstract;
&amp;nbsp; public
&amp;nbsp; &amp;nbsp; constructor Create(ABuffer: Pointer);
&amp;nbsp; &amp;nbsp; destructor Destroy; override;
&amp;nbsp; public
&amp;nbsp; &amp;nbsp; function Next: Boolean;
&amp;nbsp; public
&amp;nbsp; &amp;nbsp; property Prefixes: TByteDynArray read FPrefixes;
&amp;nbsp; &amp;nbsp; property Opcode3: Variant read FOpcode3;
&amp;nbsp; &amp;nbsp; property Opcode2: Variant read FOpcode2;
&amp;nbsp; &amp;nbsp; property Opcode1: Byte read FOpcode1;
&amp;nbsp; &amp;nbsp; property ModRM: Variant read FModRM;
&amp;nbsp; &amp;nbsp; property SIB: Variant read FSIB;
&amp;nbsp; &amp;nbsp; property Displacement: Variant read FDisplacement;
&amp;nbsp; &amp;nbsp; property Immediate: Variant read FImmediate;
&amp;nbsp; &amp;nbsp; property Length: Byte read FLength;
&amp;nbsp; public
&amp;nbsp; &amp;nbsp; property Buffer: Pointer read FBuffer;
&amp;nbsp; &amp;nbsp; property Offset: Integer read FOffset;
&amp;nbsp; end;
&amp;nbsp; TDisassemblerClass = class of TDisassembler;
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;各プロパティは先ほどのx86命令フォーマットの各フィールドに対応する。そのうちのいくつかのプロパティの型がVariant型なのは、対応するフィールドが必ずしも存在するとは限らないからである。DoNextメソッドは現在位置からx86命令を解析し、次に命令の先頭にポインタを進める抽象メソッドであるので、下位クラスではDoNextメソッドをオーバーライドしなければいけない、また、解析が成功したらTrueを返す。&lt;/p&gt;

&lt;p&gt;そして、TDisassemblerクラスを継承し、HDEを使った逆アセンブラクラスTHdeDisassemblerのDoNextメソッドを次のように実装する。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;textarea class=&quot;delphi&quot; name=&quot;code&quot; cols=&quot;80&quot;&gt;{ THde32Disassembler }

function THde32Disassembler.DoNext(P: Pointer; var APrefixes: TByteDynArray;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var AOpcode3: Variant; var AOpcode2: Variant; var AOpcode1: Byte;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var AModRM: Variant; var ASIB: Variant; var ADisplacement: Variant; var AImmediate: Variant;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;var ALength: Byte): Boolean;
var
&amp;nbsp; hs: hde32s;
begin
&amp;nbsp; Result := hde32_disasm(P, hs) &amp;lt;&amp;gt; 0;
&amp;nbsp; if Result then
&amp;nbsp; begin
&amp;nbsp; &amp;nbsp; Result := ((hs.flags and F_ERROR) = 0) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ((hs.flags and F_ERROR_OPCODE) = 0) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ((hs.flags and F_ERROR_LENGTH) = 0) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ((hs.flags and F_ERROR_LOCK) = 0) and
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ((hs.flags and F_ERROR_OPERAND) = 0);
&amp;nbsp; &amp;nbsp; if Result then
&amp;nbsp; &amp;nbsp; begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if ((hs.flags and F_PREFIX_REPNZ) &amp;lt;&amp;gt; 0) or
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;((hs.flags and F_PREFIX_REPX) &amp;lt;&amp;gt; 0) or
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;((hs.flags and F_PREFIX_REP) &amp;lt;&amp;gt; 0) then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; SetLength(APrefixes, System.Length(APrefixes) + 1);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; APrefixes[System.Length(APrefixes) - 1] := hs.p_rep;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_PREFIX_66) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; SetLength(APrefixes, System.Length(APrefixes) + 1);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; APrefixes[System.Length(APrefixes) - 1] := hs.p_66;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_PREFIX_67) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; SetLength(APrefixes, System.Length(APrefixes) + 1);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; APrefixes[System.Length(APrefixes) - 1] := hs.p_67;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_PREFIX_LOCK) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; SetLength(APrefixes, System.Length(APrefixes) + 1);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; APrefixes[System.Length(APrefixes) - 1] := hs.p_lock;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_PREFIX_SEG) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;begin
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; SetLength(APrefixes, System.Length(APrefixes) + 1);
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; APrefixes[System.Length(APrefixes) - 1] := hs.p_seg;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;end;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;AOpcode1 := hs.opcode;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if hs.opcode2 &amp;lt;&amp;gt; $00 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; AOpcode2 := hs.opcode2;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_MODRM) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; AModRM := hs.modrm;
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_SIB) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ASIB := hs.sib;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_DISP8) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ADisplacement := hs.disp.disp8
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;else
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_DISP16) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ADisplacement := hs.disp.disp16
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;else
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_DISP32) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; ADisplacement := hs.disp.disp32;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_IMM8) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; AImmediate := hs.imm.imm8
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;else
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_IMM16) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; AImmediate := hs.imm.imm16
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;else
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hs.flags and F_IMM32) &amp;lt;&amp;gt; 0 then
&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; AImmediate := hs.imm.imm32;

&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;ALength := hs.len;
&amp;nbsp; &amp;nbsp; end;
&amp;nbsp; end;
end;
&lt;/textarea&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;ここは、使用する各逆アセンブラライブラリに依存するので詳しくは省略・・&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;後、一息なのであるが、今回はここまで<img class="emoticon bearing" src="http://emojies.cocolog-nifty.com/emoticon/bearing.gif" alt="bearing" />。&lt;/p&gt;

&lt;p&gt;最後に、HDEはC言語のライブラリなので、Delphiで利用するためには、ヘッダを移植し、ライブラリ自体はCコンパイラでコンパイルし、Delphiの$Lコンパイラ指令を使ってリンクすればよいはず。&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</content:encoded>


<dc:subject>Windows</dc:subject>
<dc:subject>デバッグ</dc:subject>

<dc:creator>vanilla</dc:creator>
<dc:date>2009-08-15T00:45:48+09:00</dc:date>
</item>


</rdf:RDF>
