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スマートデバイスプロジェクト」を選んでください。このプロジェクトはデバッガを使うためだけのプロジェクトなので設定はデフォルト値で問題ありません。
プロジェクトを作成したらプロジェクトのプロパティで以下を設定します。
設定したら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用のインストーラである.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開発合宿に参加できます。興味のある方は参加してはいかがでしょうか。
最新の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になりました。
利用できないのであれば、メソッドが定義されていない方がよい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になるかもしれません。
LDAPのエントリをRubyオブジェクトとして操作するためのライブラリActiveLdapの1.0.9がリリースされました。([ANN] ActiveLdap 1.0.9)
ActiveLdapを知らない人はチュートリアルを読んで雰囲気を感じてください。
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もリリースされる予定なので、そちらも楽しみにしていてください。
インターンシップの対象でない方に好評のクリアコードのインターンシップメニューですが、今月(2009年6月)いっぱいで応募を締め切ります。
クリアコードのインターンシップに興味のある学生の方は応募忘れのないようにしましょう。興味のありそうな学生の方を知っている方は教えてあげてください。
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さんが送信ドメイン認証の概要を話してくれました。Authentication-ResultsがRFCになっていた(RFC5451)ことがわかっ たことが収穫でした。milter managerのtrunkにはAuthentication-Resultsをパースする処理があるのですが、その処理を書いているときに、どこかでこのフォーマットは定義されていないのかと思いながら書いていたのです。いずれRFC5451に合わせたものにする予定です。
最後は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について様々な場で話す機会をもらっています。それぞれの場で雰囲気も聞いてくれる人のタイプも違うため、話す内容やそれぞれの話題の重みを変えて話しているつもりです。そのため、用意をすることは大変ですが、異なる場に行くことにより、話す側として様々なメリットがあると感じています。フィードバックの内容が多様になったり、いろいろな角度からの考えや実状が聞けることだったりします。
現在はたくさんの勉強会が開かれていて、それぞれ異なる場となっています。勉強会に参加したことがある人でも、違う場の勉強会に参加してみるというのはよい経験になるでしょう。また、発表者として参加するのもまたよい経験になるでしょう。
怖がらず、新しいことにふれてみるのもよいのではないでしょうか。
今週末はオープンソースカンファレンス2009 Hokkaidoで話します。今回の勉強会で、初めに迷惑メール対策の基本的なことを話した方がよいことがわかりました。さとうさんから、今回さとうさんが話した内容を取り入れてもよいと言ってもらえました。そこで、静岡でさとうさんが話したすばらしい内容の一部を北海道でも紹介する予定です。
*1 SPFを有効にしたmilter-greylistを使っている場合は、デフォルトでSPFがpassする場合はGreylistingをスキップします。
まっちゃだいふくさんに声をかけてもらったことがきっかけで、オープンソースカンファレンス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札幌のブースにおじゃまさせてもらいました。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札幌から目が離せません。
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かどうかを判断することができます。ここでは、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_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.h
とmach-o/nist.h
を使って、BFDライブラリに依存せずに、Mach-Oから公開されている関数名を抜き出す方法を紹介しました。
関数名が取得できたら、GModuleで関数本体を取得することができます。GModuleに渡す関数名の先頭には「_」をつける必要はありません。
いずれ、PEから公開されている関数名を抜き出す方法も紹介するかもしれません。