株式会社クリアコード > ククログ

ククログ


Windows Mobile用Fennecのビルド方法

2009年6月1日時点でのWindows Vista上でWindows Mobile用Fennecをビルドする方法を紹介します。時間が経つとビルド方法が変わると思うので、注意してください。

情報源

Fennecのビルド方法に関する情報はMobile/Build/Fennec - MozillaWiki(英語)にあります。最新情報が必要な場合はこのWikiを見てください。

ただし、Wiki上の情報が古いことがあるので注意が必要です。

下準備

Fennecをビルドするために必要なツールをインストールします。 (参考: Mobile/Build/Windows Mobile PrepForBuild - MozillaWiki

まず、Microsoftが提供しているツールをインストールします。

次に、Mozillaが提供しているビルドツールをインストールします。

このビルドツールの中にはMSYSやMercurialなどのツールが入っています。

「c:\mozilla-build\start-msvc9.bat」というバッチファイルがインストールされます。このバッチファイルを実行することにより、bashが起動し、Fennecビルド用環境に入ることができます。

ビルド

ビルドに必要なツールが揃ったので、それらのツールを使ってFennecをビルドする方法を説明します。(参考: Mobile/Build/Windows Mobile BuildingIt - MozillaWiki

FennecのソースコードはMercurialで管理されています。まず、Mercurialでソースコードを取得します。ここからはstart-msvc9.batで起動した環境の中で作業します。

ソースコードは「c:\hg\」以下に置くことにします。

$ mkdir /c/hg/
$ cd /c/hg/
$ hg clone http://hg.mozilla.org/mozilla-central
$ cd mozilla-central
$ hg clone http://hg.mozilla.org/mobile-browser mobile

ソースコードを取得したらビルド用の設定ファイル「.mozconfig」を作成します。.mozconfigは雛形となるファイルを少しずつ変更して作成するとよいでしょう。ここでは、クリアコードが公開している雛形を利用します。

$ wget -O .mozconfig http://www.clear-code.com/repos/svn/fennec/wince.mozconfig

現在、リポジトリ内にデフォルトの.mozconfigを入れてはどうか、という話がでている(Bug 479515 – push default mozconfig to mobile-browser repo)ので、将来的には取得したソースコード中から雛形を利用できるようになることでしょう。

.mozconfigを作成したら、以下のコマンドでビルドできます。

$ time make -f client.mk build

マシンの速度にもよりますが、1時間以上かかるでしょう。timeはビルド時間を計測するためにつけているだけなので、以下のようにtime無しでビルドすることもできます。

$ make -f client.mk build

ビルドの完了を待つ間に、最新版に追従する方法を説明します。

ソースコードのアップデート

Mozillaのソースコードは毎日アップデートされています。最新版のソースコードに追従するためには、ソースコードがあるディレクトリで以下のコマンドを実行します。

$ hg pull && hg update && (cd mobile && hg pull && hg update)

このコマンドを実行することにより、手元のソースコードが最新版になります。

アップデートされたソースコードでビルドしなおす場合も最初のビルドのときと同じコマンドを使います。

$ time make -f client.mk build

マシンの速度やソースコードがどの程度アップデートされたかにもよりますが、30分以上かかるでしょう。ビルドの完了を待つ間に、Fennecのデバッグ方法を説明します。

デバッグ

Fennecのデバッグ方法を説明します。(参考: Mobile/Build/Windows Mobile DebuggingIt - MozillaWiki

まず、Visual StudioでFennecデバッグ用のプロジェクトを作成します。プロジェクトの種類は「Visual C++→スマートデバイス→Win32スマートデバイスプロジェクト」を選んでください。このプロジェクトはデバッガを使うためだけのプロジェクトなので設定はデフォルト値で問題ありません。

プロジェクトを作成したらプロジェクトのプロパティで以下を設定します。

  • 構成プロパティ→デバッグ→リモート実行ファイル: 「\Storage Card\fennec.exe」
  • 構成プロパティ→配置→配置デバイス: 「USA Windows Mobile 6.1.4 Professional VGA Emulator」

設定したらF5でデバッグを開始します。エミュレータが起動するので、Fennecのビルド結果を出力したディレクトリをエミュレータの「ストレージカード」としてアクセスするための設定をします。この設定は1回行えば今後はその設定を利用できます。

「ストレージカード」としてアクセスするためには、エミュレータのウィンドウメニューから「ファイル→構成→全般→共有フォルダ」とアクセスします。「共有フォルダ」に「c:\hg\fennec-debug\mobile\dist\bin」を指定してください。

これで、エミュレータ上で「\Storage Card\fennec.exe」としてFennecを実行できるようになります。もう一度、Visual Studio上でF5を押してデバッグを開始してください。デバッガ上でFennecが起動します。

注: 現在のFennecは初回起動時(プロファイルがない状態で起動した場合)のみ内部で再起動しています。そのため、再起動した段階でデバッガからデタッチしてしまいます。2回目以降の起動ではそのままデバッガ上で動くので、一度タスクマネージャからFennecを終了してF5でデバッグを開始しなおしてください。

エミュレータでのネットワーク接続

エミュレータでネットワークに接続するためにはVirtual PCをインストールする必要があります。

Virtual PCをインストールするとエミュレータでネットワークを利用できるようになります。エミュレータのウィンドウメニューから「ファイル→構成→NE2000 PCMCIAネットワークアダプタを有効にし、次の項目にバインドする」とアクセスします。この項目にチェックを入れるとエミュレータからネットワークにアクセスできるようになるので、エミュレータ上のFennecからWebを閲覧することができるようになります。

Windows Mobile 6.1.4用のエミュレータは英語用のため日本語フォントが入っていません。日本語を表示するためには、Fennecでの日本語表示設定のように別途日本語フォントを入れる必要があります。

リリース用ビルドの作成

エミュレータ上でのFennecのデバッグについて説明したので、次に、実機へFennecをインストールする方法を説明します。

雛形.mozconfigではデバッグ用ビルドの設定が有効になっています。しかし、実機へインストールする場合は最適化されたリリース用ビルドの方がよいでしょう。インストール方法を説明する前に、まず、リリース用ビルドの設定を説明します。

雛形.mozconfigの中に以下のような記述があります。

ac_add_options --enable-debug
ac_add_options --disable-optimize
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../fennec-debug
#ac_add_options --enable-optimize
#mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../fennec-release

この部分のコメントアウトされていない部分がデバッグ用ビルドの設定で、コメントアウトされている部分がリリース用ビルドの設定です。つまり、リリース用ビルドにする場合は以下のように変更します。

#ac_add_options --enable-debug
#ac_add_options --disable-optimize
#mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../fennec-debug
ac_add_options --enable-optimize
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../fennec-release

この.mozconfigを使ってビルドすることにより最適化されたリリース用ビルドを作成することができます。

それでは、リリース用ビルドを使ってWindows Mobile用のインストーラを作成する方法を説明します。

Windows Mobile用のインストーラの作成

Windows Mobile用のインストーラである.cabファイルを作成するには、「$(MOZ_OBJDIR)/mobile/」ディレクトリ($(MOZ_OBJDIR)は.mozconfigで指定したビルド結果出力ディレクト リ)で以下のコマンドを実行します。

$ make installer

雛形.mozconfigのように

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/../fennec-release

としていた場合は、以下のようになります。

$ cd ../fennec-release/mobile
$ make installer

コマンドが完了すると「$(MOZ_OBJDIR)/mobile/dist/」以下にfennec.1.0a1.en-US.wince-arm.cabファイルができます。(ファイル名の中の「1.0a1」はバージョン番号でバージョン毎に異なります。)このファイルをActiveSyncなどで実機へコピーしてインストールすることができます。

まとめ

Windows Vista上でFennecのビルド・デバッグ・インストーラ作成を行う方法を紹介しました。

これで環境環境は用意できると思うので、あとは「開発合宿後も、Fennec の開発活動に関わる意思を有する方」という条件を満たせば、Mozilla Japan主催のMobile Firefox開発合宿に参加できます。興味のある方は参加してはいかがでしょうか。

タグ: Mozilla
2009-06-01

Ruby/groonga 0.0.2リリース

最新のgroongaに対応したRuby/groonga 0.0.2がリリースされました。

Ruby/groonga 0.0.2ではよりAPIが使いやすくなっています。

メソッドの個別化

groongaはgrn_objで抽象化されていて、ハッシュテーブルでも転置インデックスカラムでもgrn_obj_search()で検索できます。Ruby/groongaでもそれを踏襲してGroonga::Object#searchだけを定義して使いまわしていました。しかし、0.0.2ではGroonga::Hash#serachやGroonga::IndexColumn#searchなど、それぞれのオブジェクト毎に定義するようにしました。

こうすることにより以下のような挙動になるため、使いやすいAPIになりました。

  • grn_obj_search()に対応していないオブジェクト(例えばGroonga::Array)に対して#searchしようとするとNoMethodErrorと適切に問題を報告する。
  • 省略可能なオプション引数をより正確に検証して適切なエラーを報告する。
  • それぞれの#search毎にドキュメントを用意することができるので、適切な内容のドキュメントがかかれたAPIになる。

利用できないのであれば、メソッドが定義されていない方がよいAPIだと思います。無駄なものがない方が適切なAPIに誘導しやすくなります。

無駄なものはない方がよいということは、メソッドだけではなく、省略可能なオプション引数にも言えます。1つのメソッドで何でもやろうとすると余計なオプションまで受け付ける必要があります。あるいは、余計なオプションを排除するためのコードが増えてしまいます。こうならないために、適切な粒度で別々のメソッドを定義することが有効です。

例えば、オプション名を検証するコードは以下のように書けます。(エラーメッセージに入力値と問題となった値を両方含めていることにも注意してください。問題を解決するための重要な情報です。)

1
2
3
4
5
6
7
8
def search(options={})
  valid_keys = [:name, :path]
  invalid_keys = options.keys - valid_keys
  unless invalid_keys.empty?
    message = "invalid option name(s): #{invalid_keys.inspect}: #{options.inspect}"
    raise ArgumentError, message
  end
end

もし、1つのメソッドでたくさんの状況を考慮しなければいけないとこのようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def search(type, options={})
  case type
  when :fast
    valid_keys = [...]
  when :remote
    valid_keys = [...]
  else
     raise ArgumentError, "invalid type: ..."
  end

  invalid_keys = options.keys - valid_keys
  unless invalid_keys.empty?
    message = "invalid option name(s): #{invalid_keys.inspect}: #{options.inspect}"
    raise ArgumentError, message
  end

  case type
  when :fast
    query = options[:query]
    ...
  when :remote
    remote = DRbObject.new("druby://#{options[:host]}:2929")
    remote.search(options[:query])
  ...
  end
end

これよりは、メソッドを分けた方がすっきりします。

1
2
3
4
5
6
7
8
9
10
11
def fast_search(options={})
  valid_keys = [...]
  ...
end

def remote_search(options={})
  valid_keys = [...]
  ...
end

...

あとは、総称的なメソッドを1つ用意すればメソッド分割前と同じように使えます。

1
2
3
4
5
6
7
8
9
def search(type, options={})
  case type
  when :fast
    fast_search(options)
  when :remote
    remote_search(options)
  ...
  end   
end

ここまできたらもう一歩です。オブジェクト指向プログラミングでcase whenやswitch caseで分岐している時はオブジェクトが足りない匂いを感じとってください。このような場合はそれぞれの条件毎にオブジェクトを作り、それぞれのオブジェクトで同じ名前のメソッドを定義します。

1
2
3
4
5
6
7
8
9
10
11
class FastSearcher
  def search(options={})
    ...
  end
end

class RemoteSearcher
  def search(options={})
    ...
  end
end

これで、条件分岐がなくなり、総称的なメソッドも定義しなくてもよくなります。それらは言語がやってくれるからです。

1
2
searcher = FastSearcher.new
searcher.search(:query => ...)

と、だいぶ遠回りをしましたが、Ruby/groonga 0.0.2では以上のようなAPI設計ポリシーに従って、オブジェクト毎にメソッドを実装するようになりました。これにより使いやすさが向上しています。

また、メソッドが分割されることにより、ドキュメントを書きやすくなります。読む側も読みやすくなります。

まとめ

Ruby/groonga 0.0.2はAPIの使いやすさが向上しています。これは、適切な粒度に実装を分割したからです。使いやすいAPIを検討しているのであれば、実装の粒度を細かくすることを検討してみてください。無駄がなくすっきりして使いやすいAPIになるかもしれません。

タグ: Ruby
2009-06-05

ActiveLdap 1.0.9リリース

LDAPのエントリをRubyオブジェクトとして操作するためのライブラリActiveLdapの1.0.9がリリースされました。([ANN] ActiveLdap 1.0.9

ActiveLdapを知らない人はチュートリアルを読んで雰囲気を感じてください。

1.0.9

1.0.9の目玉はRuby 1.9.1とRails 2.3.2の対応です。特に、Rails 2.3.2の対応は待ち望まれていた機能です。trunkではずいぶん前から対応していたにも関わらずリリースされていなかったため、ユーザの方には不便な思いをさせてしまっていました。

1.0.9はそのバージョン番号からもわかるかもしれませんが、近いうちに1.1.0がリリースされるという意味が含まれています。逆に言うと、1.1.0に必要な機能を追加するまでRails 2.3.2に対応したリリースがない状況を解決するために、1.1.0の一部機能が未実装のリリースが1.0.9になります。

とはいえ、1.0.9から1.1.0の間にAPI非互換がでるというわけではないので1.0.9とRails 2.3.2の組み合わせは安心して使えます。1.1.0では1.0.9よりも(非互換なしで)パワーアップするということです。

まとめ

Ruby 1.9.1とRails 2.3.2に対応したActiveLdap 1.0.9がリリースされました。Ruby 1.9.1やRails 2.3.2と一緒にActiveLdap 1.0.9を使ってください。

近いうちに1.1.0もリリースされる予定なので、そちらも楽しみにしていてください。

タグ: Ruby
2009-06-08

インターンシップ応募締め切りは今月いっぱい

インターンシップの対象でない方に好評のクリアコードのインターンシップメニューですが、今月(2009年6月)いっぱいで応募を締め切ります。

クリアコードのインターンシップに興味のある学生の方は応募忘れのないようにしましょう。興味のありそうな学生の方を知っている方は教えてあげてください。

2009-06-11

第2回静岡ITPro勉強会の資料公開

6/13に開催された第2回静岡ITPro勉強会に講師の1人として参加し、milter managerについて話しました。

資料: milter manager

勉強会はとても内容の濃いものでした。勉強会の内容は勉強会代表となかさんの第2回 静岡 IT Pro 勉強会、無事終了しました - 静岡 IT Pro 勉強会日誌が詳しいです。ここでは、かいつまんで紹介します。

迷惑メールの現状と対策 - さとうさん

最初にさとうさんが網羅的に迷惑メール対策の現状とおすすめの迷惑メール対策を話してくれました。おすすめの迷惑メール対策は、まず、SMTPセッション中で軽めのフィルタを使って多くの迷惑メールを落として、抜けてきたものはコンテンツベースのフィルタを使って対応するというものです。

1つのフィルタで何もかも解決するのではなく、複数のフィルタを組み合わせて実現するという方針です。1つのフィルタで完璧を求めてしまうと誤判定が増えたり、副作用が大きくでてしまう危険性があるからです。milter managerのベースは、複数のmilterをうまく組み合わせるという部分ですが、これは、さとうさんの方針と重なる部分が大きいです。

ちなみに、milter managerのインストールドキュメント にそってmilter managerをインストールすると、さとうさんの考案したRgreyが実現できます。このあたりからも、milter managerがさとうさんの影響を受けていることがわかります。

今 おさえておきたいドメイン認証技術 - umqさん

次に、umqさんが送信ドメイン認証の概要を話してくれました。Authentication-ResultsがRFCになっていた(RFC5451)ことがわかっ たことが収穫でした。milter managerのtrunkにはAuthentication-Resultsをパースする処理があるのですが、その処理を書いているときに、どこかでこのフォーマットは定義されていないのかと思いながら書いていたのです。いずれRFC5451に合わせたものにする予定です。

milter manager - 須藤

最後はmilter managerの発表でした。いくつか話し忘れたことがあるのが残念です。例えば、RgreyにSPFを組み合わせるとS25Rで誤検出してしまうmail-ew0-f216.google.comというようなGMailからの接続を救済することができます。*1こういうこともできるよ、ということだけではなく、そうすることによりどのような効果があるかも忘れずに話すべきでした。

資料にはmilter managerのことだけではなく、milter-greylist の設定例もあるので、milter-greylistを使っている場合は参考になるでしょう。

また、まっちゃだいふくさんが通常のmilterの動作フローとmilter managerを導入した場合の動作フローの図を描いてくれています。これまでのmilter managerの動作イメージ図より、流れがわかりやすくなっています。こちらの図の方が理解しやすいという方も多いのではないでしょうか。まっちゃだいふくさん、ありがとうございます。

シークレット発表

時間が少し空いたので、急遽、予定にはない発表が行われました。

まず、勉強会の中でSpamAssassinの認知度が低いということがわかったので、滝澤さんがSpamAssassinについて話してくれました。滝澤さん、頼もしいです。

次に、さとうさんが、こんな迷惑メール対策システムが欲しい、ということを話してくれました。様々な情報から自動学習して、メンテナンスフリーで動くシステムです。とても共感できます。

という、とても内容の濃い勉強会でした。

勉強会で広がる輪

勉強会にでるメリットはいくつかありますが、ここで2つ紹介します。

勉強会のメリットの1つは、直接会って話せることでしょう。

さとうさんとは勉強会の前に、迷惑メール対策の実現方法についていろいろやりとりしていましたが、やはり、直接会って話せると進みが違います。

IAjapan 第7回 迷惑メール対策カンファレンスのときに滝澤さんと、「オープンソースソフトウェアで迷惑メール対策を実現している人たちの間で情報共有できたらもっと有効な対策が実現できそうだよね」というような話をしていたのですが、今回、さとうさんともそのような話をすることができました。秋には実現できるかもしれません。

今回のように直接話す機会があったので進んだ話と言えるでしょう。このような機会になった勉強会を運営してくれたスタッフのみなさん、ありがとうございます。

また、きっかけになるということもメリットです。

勉強会のために事前にやりとりをしている中で、今回ドメイン認証関連の発表をしたumqさんがmilter managerのportsを作成してくれました。FreeBSDはmilter managerが公式にサポートしているプラットフォームのため、ぜひ、パッケージを提供したかったのですが、今回の勉強会がきっかけでそれが実現されました。

作成してくれたumqさん、声をかけてくれたまっちゃだいふくさん、さとうさん、ありがとうございます。

まとめ

ここ数ヶ月milter managerについて様々な場で話す機会をもらっています。それぞれの場で雰囲気も聞いてくれる人のタイプも違うため、話す内容やそれぞれの話題の重みを変えて話しているつもりです。そのため、用意をすることは大変ですが、異なる場に行くことにより、話す側として様々なメリットがあると感じています。フィードバックの内容が多様になったり、いろいろな角度からの考えや実状が聞けることだったりします。

現在はたくさんの勉強会が開かれていて、それぞれ異なる場となっています。勉強会に参加したことがある人でも、違う場の勉強会に参加してみるというのはよい経験になるでしょう。また、発表者として参加するのもまたよい経験になるでしょう。

怖がらず、新しいことにふれてみるのもよいのではないでしょうか。

次のmilter manager

今週末はオープンソースカンファレンス2009 Hokkaidoで話します。今回の勉強会で、初めに迷惑メール対策の基本的なことを話した方がよいことがわかりました。さとうさんから、今回さとうさんが話した内容を取り入れてもよいと言ってもらえました。そこで、静岡でさとうさんが話したすばらしい内容の一部を北海道でも紹介する予定です。

*1 SPFを有効にしたmilter-greylistを使っている場合は、デフォルトでSPFがpassする場合はGreylistingをスキップします。

2009-06-16

オープンソースカンファレンス2009 Hokkaido 北海道情報セキュリティ勉強会枠での資料公開

まっちゃだいふくさんに声をかけてもらったことがきっかけで、オープンソースカンファレンス2009 Hokkaidoのせきゅぽろ枠でmilter managerの話をしてきました。声をかけてくれたまっちゃだいふくさん、参加してくれたみなさん、ありがとうございました。

資料: milter manager

また、Ruby札幌がUstreamで配信してくれたので、動画もあります。

動画: OSC 2009 Hokkaido milter manager

内容

今回はmilterとmilter managerの話をする前に、迷惑メール対策の現状と有効な対策方法についても話しました。これは、第2回静岡ITPro勉強会での佐藤さんの公演内容を参考資料として利用しています。利用を快諾してくれた佐藤さんありがとうございます。札幌のみなさんにも迷惑メール対策の現状と有効な対策方法を伝えられたのではないかと思います。

一般的な迷惑メール対策の話の後にmilterとmilter managerの話をしました。第2回静岡ITPro勉強会の時よりも時間が少ないということもあり、今回はあまり突っ込んだ話をせずに、雰囲気が伝わる程度に抑えました。

話の後、司会をしてくれたまっちゃだいふくさんが今回省略したあたりをフォローしてくれました。ありがとうございます。

まっちゃだいふくさんは勉強会の時間外に、いろいろアドバイスをしてくれます。そのため、発表者として参加したこちらもとても勉強になっています。

そして、まっちゃだいふくさんがもってきてくれたお菓子はとてもおいしかったです。

Ruby札幌

せきゅぽろ枠の時間以外はRuby札幌にお世話になりました。

Ruby札幌とせきゅぷろの枠はセミナーに参加したのですが、それ以外の時間はRuby札幌のブースにおじゃまさせてもらいました。daraさんからbuzztterのバックエンドをgroongaにしたいということを聞いたので、Ruby/groongaで実現するために少し相談しました。Ruby/groonga 0.0.3はbuzztterのバックエンドとして使える機能を提供することになるでしょう。

今回、ActiveLdapを使っている島田さん以外のRuby札幌の人たちとも話すことができたのはよかったです。ActiveLdapやRSS Makerあたりのレビューにも参加することができました。

今回、Ruby札幌の人たちはとても人柄がよいことがわかりました。とてもすばらしいです。また、Ruby札幌がRabbitを応援していることもすばらしいです。

まとめ

オープンソースカンファレンス2009 Hokkaidoのせきゅぷろ枠でmilter managerの話をしてきました。この話は、まっちゃだいふくさんのおかげで実現しました。話の後のフォローなどいろいろありがとうございます。

Ruby札幌はすばらしいです。Ruby会議2009ではニュースがあるようですし、その後には札幌Ruby会議02もあるようです。Ruby札幌から目が離せません。

タグ: milter manager | Ruby

この記事の続き

2009-06-21

Mach-Oから公開されている関数名を抜き出す

ELFから公開されている関数名を抜き出すのMach-O版です。ただし、Universal Binaryには対応していません。

Mach-Oのフォーマットの詳細はMac OS X ABI Mach-O File Format Reference(英語)を見てください。

下準備

簡略化のためファイルの内容をすべてメモリに読み込んでから処理します。コツコツ資源を利用したい場合は少しづつ読み込みながら処理することになります。

ファイルの内容を読み込むにはGLibのg_file_get_contents()が便利です。

1
2
3
4
gchar *content;
gsize length;

g_file_get_contents(filename, &content, &length, NULL);

これで、contentの中にファイルの内容が格納されました。これを使って公開されている関数名を抜き出します。

Mach-Oのフォーマットに関する情報はmach-o/loader.hで定義されています。また、シンボルテーブルの各エントリのフォーマットに関する情報はmach-o/nlist.hで定義されています。Mach-Oをパースするときはこれらのヘッダファイルを使うと便利です。ここでもこれらのヘッダファイルを使います。

1
2
#include <mach-o/loader.h>
#include <mach-o/nlist.h>

Mach-Oかどうかを判断

まず、ファイルがMach-Oかどうかを判断します。

Mach-Oは最初にヘッダが入っていて、それを見ることでMach-Oかどうかを判断することができます。ここでは、32bit環境用のMach-Oだけを対象とします。64bit環境用のMach-Oを対象とする場合はコード中のいくつかの型の最後に「_64」を追加します。(例えば、mach_header -> mach_header_64。)どちらにも対応する場合はCutterのソースを参考にしてください。

1
2
3
4
5
6
struct mach_header *header;

header = (struct mach_header *)content;
if (header->magic == MH_MAGIC) {
    /* Mach-Oファイル */
}

共有ライブラリかどうかを判断

Mach-Oであることが確認できたら、共有ライブラリかどうかを確認します。

1
2
3
if (header->filetype == MH_DYLIB) {
    /* 共有ライブラリ */
}

バンドルからもシンボルを取り出すことができるので、バンドルにも対応するのもよいでしょう。

1
2
3
if (header->filetype == MH_DYLIB || header->filetype == MH_BUNDLE) {
    /* 共有ライブラリかバンドル */
}

公開されているシンボルを探索し出力

Mac OS X ABI Mach-O File Format Referenceの「Figure 1 Mach-O file format basic structure」にある通り、ヘッダの後にはロードコマンドと呼ばれる部分が複数続きます。いくつかあるロードコマンドのうち、興味があるのは以下の2つです。

LC_SEGMENT
セグメントに関する情報を提供する。
LC_SYMTAB
シンボルに関する情報を提供する。

シンボル名とシンボルが公開されているかはLC_SYMTABから取得できます。シンボルが関数と関連づけられているかは、シンボルが__TEXTセグメントの__textセクションで定義されているかどうかで判断できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
gsize offset;
uint32_t i, n_commands;
uint32_t section_index = 0, text_section_index = 0;

/* ファイルの先頭からコマンドの先頭までのバイト数 */
offset = sizeof(*header);
/* コマンド数 */
n_commands = header->ncmds;
for (i = 0; i < n_commands; i++) {
    struct load_command *load;

    load = (struct load_command *)(content + offset);
    switch (load->cmd) {
    case LC_SEGMENT: /* セグメント用コマンド */
    {
        struct segment_command *segment;
        struct section *section;
        gint j;

        /* セグメント */
        segment = (struct segment_command *)(content + offset);
        /* __TEXTセグメント以外は興味がない */
        if (!g_str_equal(segment->segname, "__TEXT")) {
            /* セクション数だけ数えてスキップ */
            section_index += section->nsects;
            break;
        }

        /* セクション */
        section = (struct section *)(content + offset + sizeof(*segment));
        for (j = 0; j < segment->nsects; j++, section++) {
            section_index++;
            /* __textセクションが何番目のセクションかを記録 */
            if (g_str_equal(section->sectname, "__text"))
                text_section_index = section_index;
        }
        break;
    }
    case LC_SYMTAB: /* シンボルテーブル用コマンド */
    {
        struct symtab_command *table;
        struct nlist *symbol;
        gchar *string_table;
        gint j;

        /* シンボルテーブルコマンド */
        table = (struct symtab_command *)(content + offset);
        /* シンボルリスト */
        symbol = (struct nlist *)(content + table->symoff);
        /* シンボル名が入っている文字列テーブル */
        string_table = content + table->stroff;
        for (j = 0; j < table->nsyms; j++, symbol++) {
            gboolean defined_in_section = FALSE;

            /* シンボルがセクションで定義されているか */
            if ((symbol->n_type & N_TYPE) == N_SECT)
                defined_in_section = TRUE;

                /* シンボルが__textセクションで定義されていて */
            if (defined_in_section && symbol->n_sect == text_section_index &&
                /* 公開されている */
                symbol->n_type & N_EXT) {
                gchar *name;
                int32_t string_offset;

                string_offset = symbol->n_un.n_strx;
                /* 文字列テーブルからシンボル名を取得 */
                name = string_table + string_offset;
                /* シンボル名の先頭に「_」がついているので2文字目以降を表示 */
                g_print("found: %s\n", name + 1);
            }
        }
        break;
    }
    default:
        break;
    }
    /* 次のコマンドに進む */
    offset += load->cmdsize;
}

参考

まとめ

mach-o/loader.hmach-o/nist.hを使って、BFDライブラリに依存せずに、Mach-Oから公開されている関数名を抜き出す方法を紹介しました。

関数名が取得できたら、GModuleで関数本体を取得することができます。GModuleに渡す関数名の先頭には「_」をつける必要はありません。

いずれ、PEから公開されている関数名を抜き出す方法も紹介するかもしれません。

タグ: Cutter
2009-06-25

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|