はじめにMac OS Xには、個々のサブシステムの開発とデバッグを支援するために、エンジニアリングチームが追加したデバッグ機能がいくつか含まれています。これらの機能の多くは、リリース後のシステムにも残っており、コードのデバッグに利用できます。このテクニカルノートでは、広く役立つデバッグ機能をいくつか説明します。 別の場所で文書化されているデバッグ機能については、機能の簡単な概要と既存ドキュメントへのリンクを記載しています。 このテクニカルノートでは、デバッグ機能を網羅的には文書化しておらず、将来もそうする予定はありません。 警告:このテクニカルノートで説明するデバッグ機能はサポート対象外です。アップルは、Mac OS Xの進化に応じて各機能を変更または削除する権利を留保します。変更または削除は以前にもあり、今後もあることが予想されます。これらの機能はデバッグ専用です。このテクニカルノートで説明する機能の存在または動作に依存する製品を出荷してはなりません。 重要:このテクニカルノートは(Xcode 2.0をインストールした)Mac OS X 10.4をベースにしており、該当するシステムに関しては正確です。このテクニカルノートで説明する詳細の多くはリリースによって異なるため、新旧のシステムでは若干の差が生じる可能性があります。 注:このテクニカルノートの前バージョンは、(Xcode 1.5をインストールした)Mac OS X 10.3.5をベースにしていました。そのドキュメントを更新する過程で、そこで説明されていたデバッグ機能はすべて再テストしました。ほとんどの機能には大きな変更はありません。その場合には説明を変更していません。つまり、掲載した例のいくつかは実際には10.3.5から受け継いだものであり、10.4では若干異なる結果を示す可能性があります。しかし、例の全体的な要旨は現在も間違っていません。 特定のデバッグ機能が10.4で大きく変わっている場合は、10.4の動作を反映するように説明を書き換え、その中で10.3.xの動作にも言及しました。 このテクニカルノートでは、高度なデバッグテクニックを取り上げています。Mac OS Xの開発を始めたばかりであれば、以下の資料を参照してください。
基礎このテクニカルノートでは、Mac OS Xの個々のデバッグ機能について後のセクションで詳細に説明します。これら機能の多くでは、機能の有効化と無効化、出力の表示に同じテクニックを使用します。このセクションでは、これらの共通テクニックについて説明します。 デバッグ機能の有効化いくつかのデバッグ機能はデフォルトで有効になっています。しかし、ほとんどの機能は、次の方法のいずれかを使用して有効にする必要があります。 環境変数多くの場合、特定の環境変数を設定することで、デバッグ機能を有効にできます。その最も簡単な方法は、「ターミナル」からアプリケーションを起動して、コマンドラインで環境変数を指定することです。リスト1には リスト1:sh互換シェルにおける環境変数の設定 $ MallocStackLogging=1 /Applications/TextEdit.app/Contents/MacOS/TextEdit malloc[1002]:recording stacks using standard recorder […] リスト2:csh互換シェルにおける環境変数の設定 % setenv MallocStackLogging 1 % /Applications/TextEdit.app/Contents/MacOS/TextEdit malloc[1004]: recording stacks using standard recorder […] 注:Mac OS X 10.3以降のデフォルトシェルは、 重要: または、2つの「ターミナル」ウインドウを開き、一方のウインドウをデバッグ専用とし、他のすべてのコマンドには他方のウインドウを使用するという方法もあります。 さらに、リスト3に示すように、GDBで環境変数を設定することもできます。 リスト3:GDBにおける環境変数の設定 $ gdb /Applications/TextEdit.app GNU gdb 5.3-20030128 (Apple version gdb-330.1) […] (gdb) set env MallocStackLogging 1 (gdb) r Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit malloc[1062]: recording stacks using standard recorder […] アプリケーションのビルドとデバッグにXcodeを使用する場合は、実行可能ファイルインスペクタを使用して環境変数を設定できます。図1にその一例を示します。 図1:Xcodeにおける環境変数の設定
最後に、Mac OS Xには、特定ユーザが起動するすべてのプロセスに環境変数を設定する仕組みがあります。詳細については、テクニカルQ&AのQA1067「Setting environment variables for user processes」 を参照してください。 環境設定その他のデバッグ機能を有効にするには、 リスト4:defaultsを使用した環境設定 $ defaults write com.apple.TextEdit NSTraceEvents YES $ /Applications/TextEdit.app/Contents/MacOS/TextEdit 2004-08-30 16:47:55.851 TextEdit[1135] timeout = 62998416724.149353 seco… 2004-08-30 16:47:55.894 TextEdit[1135] got apple event of class 61657674… […] デバッグを完了したら、リスト5に示すように、再度 リスト5:defaultsを使用した環境設定の削除 $ defaults delete com.apple.TextEdit NSTraceEvents
Cocoaアプリケーションでは、コマンドラインで一時的な環境設定を行えます。たとえば、リスト6に、永続的な環境設定を変更せずにリスト4と同等の結果を達成する方法を示します。 リスト6:一時的な環境設定 $ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSTraceEvents YES 2004-10-25 17:28:41.143 TextEdit[5774] timeout = 62993575878.857864 seco… 2004-10-25 17:28:41.179 TextEdit[5774] got apple event of class 61657674… […] ファイルいくつかのデバッグ機能は、ファイルシステム内に特定のファイルが存在することで有効になります。リスト7にその一例を示します。ファイル リスト7:デバッグを有効にする特定ファイルの作成 $ sudo touch /var/log/do_dnserver_log [… ここで再起動 …] $ cat /var/log/dnserver.log ------------------------------------------------- […] create_client "KernelEventAgent" BFF7FA80 (1203) […] received_message_from "KernelEventAgent" register "DISCONNECT" […] […] この例の詳細については、「CFNotificationCenter」を参照してください。 呼び出し可能ルーチン多くのシステムフレームワークには、デバッグ情報を リスト8:GDBからのデバッグルーチンの呼び出し
(gdb) call (void) GDBComponentList()
Cnt tRef# (address) Type/SubT/Manu Flags EntryPnt File Parnt ThingName
0 10008 0180d540 adec/.mp3/appl 10000000 00000000 -3 00000 (Not loade…
[…]
2 1012c 005c3be0 clok/micr/appl 10000003 8b1586a8 1 00000 (Not loade…
Inst:0x850003; Err=0; Storage:0x1fe6f0
Inst:0x890004; Err=0; Storage:0x1fe6f8
0 10065 0180fd08 clok/soun/appl 00000005 00000000 -3 00000 (Not loade…
[…]
There are 9 component manager files:
0: refs 2, path [/System/Library/Components/VCH263Codec.component]…
1: refs 94, path [/System/Library/QuickTime/QuickTimeComponents.co…
2: refs 5, path [/System/Library/Components/IOQTComponents.compone…
3: refs 2, path [/System/Library/QuickTime/QuickTimeVR.component],…
4: refs 7, path [/System/Library/QuickTime/QuickTimeFirewireDV.com…
5: refs 1, path [/System/Library/QuickTime/QuickTimeMPEG4.componen…
6: refs 1, path [/System/Library/Components/PDFImporter.component]…
7: refs 1, path [/System/Library/QuickTime/ApplePixletVideo.compon…
8: refs 1, path [/System/Library/QuickTime/QuickTimeStreaming.comp…
ルーチンからの出力が表示されない場合は、次のセクションで述べるように、コンソールログを調べる必要があります。 重要:この手法を自分のコードに使用する場合は、 現実には、これはインテル用のコードにのみ影響します。 デバッグ出力の確認デバッグ出力を生成するプログラムは一般に、3つの異なるメカニズムのいずれかを使用して生成します。
他の2つのメカニズムはずっと単純です。システムログは、「コンソール」アプリケーション( カーネルトレース機能は、高度に特化した低レイテンシー、高可用性ログメカニズムです。多くの場合、カーネルトレース機能にログを記録するプログラムには、ログを表示する手段も含まれています(たとえば、ktraceを使用して生成されるトレースファイルを出力するには、kdumpを使用します)。 コンソール出力多くのプログラム、そして実に多くのシステムフレームワークが、
実行中のプログラムにアタッチしても(GDBの アーキテクチャの考慮事項このテクニカルノートに掲載した事例は、PowerPCベースのMacintoshを使用したものです。しかし、インテルベースのマシンでも問題なく動作します。唯一の大きな違いはパラメータの受け渡しに関するものです。PowerPCアーキテクチャではレジスタを使用してパラメータを渡しますが、インテルアーキテクチャではスタックを使用してパラメータを渡します。 PowerPCでは、経験則として、最初のパラメータはGPR3 (General Purpose Register 3)に、2番目のパラメータはGPR4にというように渡されます。これらを確認するためのGDB構文は インテルに関しては、2つの経験則があります。
いずれの場合もインテルでは、関数の結果がレジスタEAX ( ルーチンがC++のメンバ関数の場合は、 リスト9:PowerPCにおけるパラメータ $ gdb /Applications/TextEdit.app GNU gdb 6.1-20040303 (Apple version gdb-434) […] (gdb) fb CFStringCreateWithFormat Function "CFStringCreateWithFormat" not defined. Breakpoint 1 (CFStringCreateWithFormat) pending. (gdb) r Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit Reading symbols for shared libraries […] done Breakpoint 1 at 0x90741e80 Pending breakpoint 1 - "CFStringCreateWithFormat" resolved Breakpoint 1, 0x90741e80 in CFStringCreateWithFormat () (gdb) # 最初のパラメータは、"alloc" (gdb) p/a $r3 $1 = 0x0 (gdb) # 2番目のパラメータは、"formatOptions" (gdb) p/a $r4 $2 = 0x0 (gdb) # 3番目のパラメータは、"format" (gdb) p/a $r5 $3 = 0xa0742454 <kCFURLLocalhost+340> (gdb) call (void) CFShow($r5) %@%c (gdb) finish Run till exit from #0 0x90741e80 in CFStringCreateWithFormat () 0x9073eaf8 in CFURLCreateWithFileSystemPathRelativeToBase () (gdb) # 関数の結果 (gdb) p/a $r3 $4 = 0x306a40 (gdb) call (void) CFShow($r3) /Applications/TextEdit.app/Contents/MacOS/ リスト10:インテルにおけるパラメータ $ gdb /Applications/TextEdit.app GNU gdb 6.1-20040303 (Apple version gdb-425) […] (gdb) fb CFStringCreateWithFormat Function "CFStringCreateWithFormat" not defined. Breakpoint 1 (CFStringCreateWithFormat) pending. (gdb) r Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit Reading symbols for shared libraries […] done Breakpoint 1 at 0x9078f111 Pending breakpoint 1 - "CFStringCreateWithFormat" resolved Breakpoint 1, 0x9078f111 in CFStringCreateWithFormat () (gdb) # 最初のパラメータは、"alloc" (gdb) p/a *(int *)($ebp+8) $1 = 0x0 (gdb) # 2番目のパラメータは、"formatOptions" (gdb) p/a *(int *)($ebp+12) $2 = 0x0 (gdb) # 3番目のパラメータは、"format" (gdb) p/a *(int *)($ebp+16) $3 = 0xa078bd88 <dyld_func_lookup_pointer+16100> (gdb) call (void) CFShow($3) %@%c (gdb) finish Run till exit from #0 0x9078f111 in CFStringCreateWithFormat () 0x9078b6c1 in CFURLCreateWithFileSystemPathRelativeToBase () (gdb) # 関数の結果 (gdb) p/a $eax $4 = 0x306ce0 (gdb) call (void) CFShow($eax) /Applications/TextEdit.app/Contents/MacOS/ (gdb) # ここでブレークポイントをクリアして、 (gdb) # CFStringCreateWithFormat の最初の命令に設定しなおす。 (gdb) delete 1 (gdb) # 次のコマンドにおける"*"の構文に注目。 (gdb) # これは、ルーチンの最初の命令にブレークポイントを設定する。 (gdb) b *CFStringCreateWithFormat Breakpoint 2 at 0x9078f10b (gdb) c Continuing. Breakpoint 2, 0x9078f10b in CFStringCreateWithFormat () (gdb) # CFStringCreateWithFormat の最初の命令の位置で止まった。 (gdb) # スタックフレームはまだ作成されていない。 (gdb) # 各パラメータを、スタックポインタからの相対位置を指定して出力させる。 (gdb) p/a *(int *)($esp+4) $5 = 0x0 (gdb) p/a *(int *)($esp+8) $7 = 0x0 (gdb) p/a *(int *)($esp+12) $8 = 0xa078bd88 <dyld_func_lookup_pointer+16100> (gdb) call (void) CFShow($8) %@%c 重要:これらは経験則にすぎません。ルーチンに非標準のパラメータまたは非標準の関数結果がある場合は、これらの経験則が適用されないため、詳細については資料を参照してください。 ここで標準パラメータとは、整数(単独のレジスタに置けるもの)、列挙、およびポインタ(配列のポインタや関数のポインタなどを含みます)です。非標準パラメータは浮動小数点数、ベクトル、構造体、およびレジスタより大きな整数です。 すべてのMac OS Xアーキテクチャにおける呼び出し規則の詳細については、『Mac OS X ABI Function Call Guide』を参照してください。 最後に、個々の命令に関する情報を探す場合は、Shark(Xcodeデベロッパツールに含まれている)のHelpメニューにPowerPCとインテル用の命令リファレンスがあります。 CrashReporterCrashReporterはクラッシュするすべてのプログラムに関する情報を記録する貴重なデバッグ機能です。詳細については、テクニカルノートのTN2123「CrashReporter」を参照してください。CrashReporterは常時有効であり、必要なのは出力を見ることだけです。 BSDBSDサブシステムはプロセス、メモリ、ファイル、およびネットワークインフラを実装するため、Mac OS X上のすべてのアプリケーションにとって不可欠です。BSDには、利用可能な優れたデバッグ機能がいくつか実装されています。 コアダンプコアダンプは、プリミティブなデバッグ機能であると過小評価されています。実際には、難しい問題をデバッグするとき、特に問題をローカルで再現できない場合は、コアダンプが非常に役立つことがあります。 システム全体でコアダンプを有効にするには、ファイル 注:Mac OS X 10.4より前には、システム全体でコアダンプを有効にするのに、 または、「ターミナル」からプログラムを実行する場合は、あらかじめシェルでコアダンプのサイズ制限を簡単に引き上げることができます。リスト11にその一例を示します。 リスト11:無制限のコアダンプサイズ $ ulimit -c unlimited $ /Applications/TextEdit.app/Contents/MacOS/TextEdit […] コアダンプ機能をテストするには、リスト12に示すように、 リスト12:SIGABRTの送信によるコアダンプのテスト $ ps | grep TextEdit 374 p1 S+ 0:00.58 /Applications/TextEdit.app/Contents/MacOS/TextEdit 379 std S+ 0:00.01 grep TextEdit $ kill -ABRT 374 この場合、アプリケーションは「Abort trap (core dumped)」というメッセージを出力して終了します。コアダンプは リスト13:コアダンプの使用
Abort trap (core dumped)
$ ls -lh /cores
total 296856
-r-------- 1 quinn admin 144M 29 Oct 10:23 core.374
$ otool -c /cores/core.374
/cores/core.374:
Argument strings on the stack at:0xc0000000
/Applications/TextEdit.app/Contents/MacOS/TextEdit
/Applications/TextEdit.app/Contents/MacOS/TextEdit
TERM_PROGRAM=Apple_Terminal
TERM=xterm-color
SHELL=/bin/bash
TERM_PROGRAM_VERSION=100
USER=quinn
__CF_USER_TEXT_ENCODING=0x1F5:0:15
PATH=/bin:/sbin:/usr/bin:/usr/sbin
PWD=/Users/quinn
SHLVL=1
HOME=/Users/quinn
LOGNAME=quinn
SECURITYSESSIONID=20f550
_=/Applications/TextEdit.app/Contents/MacOS/TextEdit
$ gdb -c /cores/core.374
GNU gdb 5.3-20030128 (Apple version gdb-292) (Sat Sep 20 03:22:27 GMT 2003)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.Type "show warranty" for details.
This GDB was configured as "powerpc-apple-darwin".
Core was generated by `/Applications/TextEdit.app/Contents/MacOS/TextEdit'.
#0 0x900075c8 in ?? ()
(gdb) bt
#0 0x900075c8 in ?? ()
#1 0x90007118 in ?? ()
#2 0x901960bc in ?? ()
#3 0x927d5ecc in ?? ()
#4 0x927dc640 in ?? ()
#5 0x927fe6d0 in ?? ()
#6 0x92dd2a80 in ?? ()
#7 0x92de93fc in ?? ()
#8 0x92dfd730 in ?? ()
#9 0x92eb9a1c in ?? ()
#10 0x00007d98 in ?? ()
#11 0x00007c0c in ?? ()
リスト13から分かるように、コアダンプにはデバッガシンボルが含まれていません。シンボルファイルが手元にあれば、 リスト14:シンボルの追加 (gdb) add-symbol-file /System/Library/Frameworks/AppKit.framework/AppKit […] (gdb) add-symbol-file /System/Library/Frameworks/CoreFoundation.framework\ /CoreFoundation […] (gdb) add-symbol-file /System/Library/Frameworks/System.framework/System […] #12 0x00007c0c in ?? () (gdb) add-symbol-file /System/Library/Frameworks/Carbon.framework/\ Frameworks/HIToolbox.framework/HIToolbox […] (gdb) bt #0 0x900075c8 in mach_msg_trap () #1 0x90007118 in mach_msg () #2 0x90191930 in __CFRunLoopRun () #3 0x901960bc in CFRunLoopRunSpecific () #4 0x927d5ecc in RunCurrentEventLoopInMode () #5 0x927dc640 in ReceiveNextEventCommon () #6 0x927fe6d0 in BlockUntilNextEventMatchingListInMode () #7 0x92dd2a80 in _DPSNextEvent () #8 0x92de93fc in -[NSApplication nextEventMatchingMask:untilDate:inMode:… #9 0x92dfd730 in -[NSApplication run] () #10 0x92eb9a1c in NSApplicationMain () #11 0x00007d98 in ?? () #12 0x00007c0c in ?? () 重要:コアダンプは大きくなります。リスト13の例では、「テキストエディット」のコアダンプは144MBです。当然のことながら、コアダンプを有効にしている場合は、必ず メモリアロケータデフォルトのメモリアロケータには、環境変数を通じて有効にできるいくつかのデバッグ機能が含まれています。これらはmanページで完全に文書化されています。表1に、そのうちのいくつかの便利なデバッグ機能を示します。 表1:便利なメモリアロケータ環境変数
重要:これらの環境変数は、特別なメモリライブラリ(MallocDebugまたは保護メモリアロケータなど)を必要としません。実のところ、これらはデフォルトの非デバッグメモリアロケータによってサポートされているため、常時利用可能です。 デフォルトのメモリアロケータも、プログラミング上の一般的な問題を検出すると、メッセージのログを記録します。たとえば、同じメモリブロックを二度解放するか、割り当てていないメモリを解放すると、 リスト15:freeが出力する一般的なメッセージ *** malloc[4691]:Deallocation of a pointer not malloced:0x1000; \ This could be a double free(), or free() called with the middle of \ an allocated block; Try setting environment variable MallocHelp to \ see tools to help debug この種の問題をデバッグするには、GDB内でプログラムを実行し、 MallocDebugとObjectAllocMac OS Xには、メモリ割り当てデバッグ用に2つのGUIアプリケーション、MallocDebugとObjectAllocが含まれています。これらのツールの詳細については、文書『Memory Performance』を参照してください。 保護メモリアロケータMac OS Xには保護メモリアロケータの リスト16:libgmallocの有効化 $ gdb /Applications/TextEdit.app GNU gdb 6.1-20040303 (Apple version gdb-434) […] (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib (gdb) r Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit Allocations will be placed on word (4 byte) boundaries. - Small buffer overruns may not be noticed. - Applications using AltiVec instructions may fail. GuardMalloc-11 Reading symbols for shared libraries […]
注:Mac OS X 10.3.xでは、 Mac OS X 10.3.xにおける 標準C++ライブラリ標準C++ライブラリはいくつかのデバッグ機能をサポートしています。
コマンドラインツールMac OS Xには、デバッグ用の優れたコマンドラインツールがいくつか含まれています。表2に筆者の愛用ツールを示します。 表2:重要なコマンドラインツール
ダイナミックリンカ(dyld)Mac OS Xダイナミックリンカ(dyld)は、環境変数を使用して有効にできるいくつかのデバッグ機能をサポートしています。これらはmanページで完全に文書化されています。表3に、そのうちのいくつかの便利な変数を示します。 表3:ダイナミックリンカの環境変数
これらのうち、 コードを動的にロードしようとしてロードに失敗した場合は、ダイナミックリンカルーチン また、dlopenを使ってコードをロードする場合は、dlerrorを使用して同様の情報を取得できます。 デバッグライブラリMac OS Xの多くのフレームワークには、実運用版とデバッグ版の両方が含まれています。デバッグ版には、接尾辞「_debug」が付いています。たとえば、Core Foundationフレームワークの実運用版は リスト17:_debugライブラリの使用 $ DYLD_IMAGE_SUFFIX=_debug /Applications/TextEdit.app/Contents/MacOS/TextEdit 2004-08-30 18:32:06.051 TextEdit[1393] CFLog (0):Assertions enabled […] 「ターミナル」でうまくいかない場合は、Xcodeで実行ファイルインスペクタを使用して同じことを実行できます。図2では、「Use … suffix when loading frameworks」ポップアップが「debug」に設定されているのを確認することができます。 図2:Xcodeでデバッグライブラリを有効化
デバッグライブラリの正確な動作はフレームワークによって異なります。ほとんどのデバッグライブラリには、次のものが含まれています。
日常的なデバッグ処理の一部として、デバッグライブラリを使用することを強くお勧めします。 注:特に明記しないかぎり、このテクニカルノートのデバッグ機能はデバッグライブラリの使用を必要としません。 1つのデバッグライブラリだけを有効化状況によっては、1つのデバッグライブラリだけを有効にしたい場合もあります。たとえば、アップルイベントの問題をデバッグするために、AEフレームワークの「_debug」版を有効にしたいとします。しかし、 幸い、多少乱暴ながらも、簡単な解答があります。デバッグ版を非デバッグ版にコピーするだけです。リスト18にその一例を示します。 リスト18:AEデバッグライブラリのみをアクティブにする $ cd /System/Library/Frameworks/ApplicationServices.framework/\ Frameworks/AE.framework/Versions/A/ $ sudo cp -n AE AE_original Password: ******** $ sudo cp AE_debug AE コピーが完了したら、変更を有効にするために再起動する必要があります。 重要:このテクニックはデバッグに役立ちますが、弊害がいくつかあります。たとえば、デバッグライブラリは非デバッグライブラリと異なるアドレスに事前バインドされているため、事前バインドプログラムは事前バインドした状態では開始できず、起動が遅くなります。したがって、これは専用テストコンピュータにおいてのみ実行するか、それが現実的でない場合は、テスト用システムを起動したメインコンピュータ上で実行します。さらに、デバッグを完了したらすぐに、ライブラリを元に戻してください。 非デバッグライブラリに戻すには、リスト19に示すように、元のライブラリをコピーするだけです。 リスト19:AEデバッグライブラリを非アクティブにする $ sudo cp AE_original AE Password: ******** 注:ライブラリ名を変更するのではなくコピーすることを勧める理由は、ライブラリの最新コピーを誤って上書きするのを難しくするためです。 デバッグライブラリのバージョニングデバッグライブラリは、システムインストーラではなく、Xcodeインストーラによってインストールされます。システムソフトウェアをアップデートしても、デバッグライブラリは更新されません。そのため、デバッグライブラリが実運用ライブラリと同期していないことがよくあります(通常は、デバッグライブラリの方が古い)。これによって、いくつかの予期しない非互換性の問題が生じる可能性があります。 たとえば、Mac OS X 10.4をインストールし、次にXcode 2.0をインストールして、その後システムをMac OS X 10.4.3にアップデートした場合は、デバッグライブラリを有効にすると、アプリケーションを起動できなくなることがあります。その理由は、Mac OS X 10.4.3では、アップルがCoreServicesフレームワークに新しいルーチンを追加し、そのルーチンを使用するようにDesktopServicesPrivフレームワークを更新したためです。しかし、これらのフレームワークの一方(CoreServices)にはデバッグ版が存在しますが、もう一方(DesktopServicesPriv)には存在しません。そのため、デバッグライブラリを有効にすると、デバッグ版のCoreServices(Xcode 2.0によってインストールされ、バージョン10.4と同等)と実運用版のDesktopServicesPriv(バージョン10.4.3にアップデートされたソフトウェア)が使用されるため、この組み合わせはロードできません。 この問題はMac OS Xにはいつもつきまとっているため、アップルではこれを解決する方法を検討しています(r. 4379270)。当面の間、デバッグライブラリを使用する最も信頼できる方法は、デバッグ専用のパーティションをセットアップすることです。このパーティションで、まず対象となるメジャーOSリリースをクリーンインストールし、次にそのリリースに合ったデベロッパツールをインストールします。たとえば、Mac OS X 10.4をクリーンインストールし、次にXcode 2.0をインストールします。その後、このパーティションのソフトウェアアップデートを無効にします。これによって、実運用版およびデバッグ版のライブラリを、同期の取れた状態で使用を開始でき、同期を保ったままにできます。 プロファイルライブラリ多くのライブラリは、「_profile」という接尾辞が付いたプロファイル版もサポートしています。プロファイルライブラリには、デバッグライブラリと同様の制限がたくさんあります。 ウインドウサーバの回避状況によっては、ウインドウサーバなしで操作するほうが便利な場合もあります。たとえば、
このレベルでの作業を完了したら、( 重要:この環境はシングルユーザモードではありません。ほとんどのシステムデーモンはまだ実行されていて、システムのGUIコンポーネントだけが停止されます。 デーモンほとんどのシステムデーモンには、何らかのデバッグ機能が含まれています。多くの場合、デーモンのデバッグ機能はそのmanページに説明されています。このセクションでは、特に興味深い機能をいくつか説明します。 launchdlaunchdはカーネルが最初に実行するプロセスであり(Mac OS X 10.4以降)、システムにおける他のプロセスをすべて起動します。 launchctllaunchctlコマンドを使用すると、 表4:便利なlaunchctlコマンド群
注: 一時的な変更を行うには、これらのコマンドの1つを引数として使用して 重要: 変更を永続的なものとするには、このコマンドを/etc/launchd.confに追加します。 launchdログ記録
リスト20:ファイルへのlaunchd動作の記録 $ sudo cp /etc/syslog.conf /etc/syslog.conf-orig Password: ******** $ ( cat /etc/syslog.conf-orig ; echo "launchd.* /var/log/launchd.log" ) | \ sudo cp /dev/stdin /etc/syslog.conf $ sudo kill -HUP `cat /var/run/syslog.pid` デフォルトでは、 リスト21:launchdログ記録を増やす $ sudo launchctl log level debug Password: ******** 特定ジョブのデバッグ最後に、 表5:デバッグに役立つプロパティ
lookupd
リスト22にその一例を示します。上記の手順を完了したら、 リスト22:lookupdデバッグの有効化 $ sudo dscl . create /dsRecTypeStandard:Config/lookupd Debug YES Password: ******** $ sudo dscl . create /dsRecTypeStandard:Config/lookupd Trace YES $ sudo cp /etc/syslog.conf /etc/syslog.conf-orig $ sed 's/netinfo.err/netinfo.debug/' /etc/syslog.conf-orig | \ sudo cp /dev/stdin /etc/syslog.conf $ sudo kill -HUP `cat /var/run/syslog.pid` $ sudo kill -HUP `cat /var/run/lookupd.pid` リスト23に、これらの変更を取り消す方法を示します。 リスト23:lookupdデバッグの無効化 $ sudo dscl . delete /dsRecTypeStandard:Config/lookupd $ sudo mv /etc/syslog.conf-orig /etc/syslog.conf $ sudo kill -HUP `cat /var/run/syslog.pid` $ sudo kill -HUP `cat /var/run/lookupd.pid`
出力(CUPS)Mac OS X 10.2以降では、コアプリンティングアーキテクチャとしてCUPS (Common UNIX Printing System)を使用しています。CUPSには、CUPS設定ファイル( 重要:このファイルを変更したら、変更を有効にするために、CUPSデーモンに リスト24:CUPSデーモンの再起動 sudo /System/Library/StartupItems/PrintingServices/PrintingServices restart CUPSドライバまたはフィルタを開発している場合は、 リスト25:CUPSへのログ記録 // デバッグメッセージ fprintf(stderr, "DEBUG:page_width = %.0f\n", page_width); // 警告メッセージ fprintf(stderr, "WARNING:Printer not responding\n"); // エラーメッセージ fprintf(stderr, "ERROR:Lost connection with printer\n"); Core ServicesCore Servicesには、メッセージを出力してデバッガに入る多くのルーチン( 図3:XcodeにおけるUSERBREAKの設定
Code Fragment Manager (CFM)Mac OS XのCFM互換環境では、2つの便利な環境変数、 Core FoundationCore Foundation (CF)フレームワークのあらゆるバリエーションが、 リスト26:GDBからCFShowを呼び出す
$ gdb /Applications/TextEdit.app
GNU gdb 5.3-20030128 (Apple version gdb-330.1) […]
(gdb) fb CFRunLoopAddSource
No symbol table is loaded.Use the "file" command.
Breakpoint 1 at 0x0
(gdb) r
[…]
Breakpoint 1, 0x901b5764 in CFRunLoopAddSource ()
(gdb) call (void) CFShow($r3)
<CFRunLoop 0x116290 [0xa01900e0]>{
locked = false,
wait port = 0xf03,
stopped = false,
current mode = (none),
common modes = <CFSet 0x1162c0 [0xa01900e0]>{
count = 1,
capacity = 4,
values = (
1 : <CFString 0xa0195b38 [0xa01900e0]>{
contents = "kCFRunLoopDefaultMode"
}
)
},
common mode items = (null),
modes = <CFSet 0x116310 [0xa01900e0]>{
count = 1,
capacity = 17,
values = (
20 : <CFRunLoopMode 0x1163a0 [0xa01900e0]>{
name = kCFRunLoopDefaultMode,
locked = false,
port set = 0x1003,
sources = (null),
observers == (null),
timers = (null)
},
)
}
}
重要: 注:リスト26に、 その他にも、 また、Core Foundationフレームワークには、広範なデバッグ支援を提供するデバッグ版もあります。たとえば、Core Foundationの非デバッグ版では、ルーチンに渡されるパラメータの妥当性はチェックされませんが、デバッグ版ではパラメータが全面的にチェックされます。これは、コードの多くのCore Foundation関連のバグを見つけ出すのに役立ちます。 Core Foundationのデバッグライブラリは、 表6:CFZombieLevel環境変数のビット定義
警告: CFNotificationCenterCFNotificationCenterログを有効にするには、ファイル この例は「ファイル」にあります。 注:Mac OS X 10.3.xでは、対応するファイルは また、Mac OS X 10.3.xでは、クライアント側のログ記録をサポートしていました。ファイル Component ManagerComponent Managerは さらに、 最後に、コンポーネントがロードできない場合は、ダイナミックリンカ機能を使用して問題をデバッグできます。詳細については、「ダイナミックリンカ(dyld)」を参照してください。 File ManagerCore ServicesのFile Manager(一般にはCarbon File Manager、または単にFile Managerと呼ばれている)は、
File Managerには、GDBから呼び出し可能な便利なルーチンがいくつかあります。最も役に立つ リスト27:PrintVolumeInfoの使用
(gdb) call (void) PrintVolumeInfo(1)
1:vol=-100 "X2"
2:vol=-101 "X1"
3:vol=-102 "Guy Smiley"
4:vol=-130 "UFS Victim"
5:vol=-105 "Network"
6:returned error -35
(gdb) call (void) PrintVolumeInfo(0)
Volume Information:
"X2" mountpoint:"/"
vRef=-100 volID=-100 diskID=disk0s10
"X1" mountpoint:"/Volumes/X1"
vRef=-101 volID=-101 diskID=disk0s9
"Guy Smiley" mountpoint:"/Volumes/Guy Smiley"
vRef=-102 volID=-102 diskID=disk0s11
"UFS Victim" mountpoint:"/Volumes/UFS Victim"
vRef=-130 volID=-130 diskID=disk3s2
"Network" mountpoint:"/Network"
vRef=-105 volID=-105 diskID=/Network
その他にも、GDBから呼び出し可能な2つのルーチンがありますが、これらは主として、Mac OS X上のVFSプラグインを開発している人々にとって興味あるものです。これらのルーチンによって、ディレクトリ列挙キャッシュとファイルIDツリーを出力できますが、これらはどちらもFile Managerが非volfsボリュームに対して維持している互換性構造です(volfsについては、テクニカルQ&AのQA1113「The "/.vol" directory and "volfs"」を参照)。
ファイルIDツリーは リスト28:ファイルIDツリーの出力
$ sudo gdb
Password:********
GNU gdb 6.1-20040303 (Apple version gdb-425) […]
(gdb) call (int) close(2)
$1 = 0
(gdb) shell tty
/dev/ttyp2
(gdb) call (int) open("/dev/ttyp2", 2)
$2 = 2
(gdb) call (void *) FileIDTreeStorageServerDump("fsnode_all")
$3 = (void *) 0x316320
(gdb) call (void) CFShow($3)
Shared universes:
501(3): mod seed = 2
Shared segments ([domainID][segmentID](<unused entries>):<address>
[0][0](32/480):0x200e00
[1][0](496/16):0x300e00
[2][0](504/8):0x504b00
Entries scheduled for removal:
69000000(108)@1: FSObjectVolumeEntry:vRefNum: -105
0(5): mod seed = 2
Shared segments ([domainID][segmentID](<unused entries>):<address>
[0][0](32/480):0x400c00
[1][0](496/16):0x500c00
[2][0](504/8):0x300800
Entries scheduled for removal:
69000000(108)@1: FSObjectVolumeEntry:vRefNum: -105
checked-in processes:
204(0/0x7000040):seed 2(0), idle
211(0/0x6000040):seed 2(0), idle
248(501/0x7000040):seed 2(0), idle
114(501/0x6000040):seed 1(0), idle
120(501/0x5000040):seed 2(0), idle
183(0/0x5000040):seed 1(0), idle
No transactions in progress
注:Mac OS X 10.3.xでは、ファイルIDツリーは各プロセスによって個別に維持されていました。当該システムでは、 Folder ManagerFolder Managerは、 GestaltCore Servicesは リスト29:Gestaltデバッグルーチンの使用
(gdb) call (void) DebugDumpGestalt()
DebugDumpGestalt
'a/ux':0x2a65c6ac (proc)
'addr':0x00000007
[…]
(gdb) call (void) DebugGestalt(0x766d2020)
'vm ':0x00000011
(gdb) call (void) DebugGestaltStr("vm ")
'vm ':0x00000011
スレッド化Core Servicesスレッド化 API(MPスレッドおよびThread Manager)では、 WebサービスWebサービスでは、2つの便利な環境変数、 DiskとDiscDisk Arbitration
Disc Recording
重要:バグ(r. 4413303)のために、この機能はMac OS X 10.4.xでは正常に機能しません。 Disk Utility
ApplicationServicesアップルイベントApple Event Managerには、デバッグ用の広範なサポート機能が組み込まれています。このサポート機能について学ぶ最善の方法は、リスト30に示すように、GDBを使用して リスト30:Apple Event Managerデバッグ用ヘルプ
(gdb) call (void) GDBPrintHelpDebuggingAppleEvents()
The AppleEvent Manager has been completely rewritten for this
version of Mac OS X. The internal structure of an AEDesc is
now a pointer to a sparse tree.If you're having problems
it could be because you're accessing the dataHandle of an
AEDesc directly.
Also of note is that AEGetDescData and AEGetDescDataSize only
work with value descriptors created by AECreateDesc - you cannot
get the data size of an AERecord or AEList, for example.
To print the contents of an AppleEvent from GDB, you can:
(gdb) call (void) GDBPrintAEDesc(descPtr)
To view all currently installed AppleEvent coercion handlers:
(gdb) call (void) GDBPrintAECoercionTables()
To view all contents install AppleEvent handlers:
(gdb) call (void) GDBPrintAEHandlerTables()
Additionally, to log information about AppleEvent manager calls,
you can set environment variables that will produce debugging output
to the console:
% setenv AEDebug 1 # general debug output
% setenv AEDebugSends 1 # print sent events
% setenv AEDebugReceives 1 # print received events and replies
% setenv AEDebugVerbose 1 # print result information on (most) \
calls (very verbose)
% setenv AEDebugOSL 1 # print result information from OSL
% setenv AEDebugFile /tmp/logfile # send debug output to this file
注:上記のテキストで、「this version of Mac OS X」はMac OS X 10.2を指しています。 一部の環境変数、特に デバッグライブラリを使用している場合は、
重要:後者2つの項目は、デバッグの出力先にのみ影響を与えます。デバッグ出力を得るには、上記の環境変数のいずれかを使用するか、
リモートアップルイベントリモートアップルイベントに関する問題がある場合は、アップルイベントサーバプロセスでログ記録を有効にすると便利なこともあります。それには、 リスト31:リモートアップルイベントデバッグの有効化 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" \
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<true/>
<key>Label</key>
<string>com.apple.AEServer</string>
<key>ProgramArguments</key>
<array>
<string>/System/Library/Frameworks/ApplicationServices.\
framework/Frameworks/AE.framework/Versions/A/Support/AEServer</string>
<string>--debug</string>
</array>
<key>inetdCompatibility</key>
<dict>
<key>Wait</key>
<false/>
</dict>
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>eppc</string>
<key>SockType</key>
<string>stream</string>
<key>Bonjour</key>
<true/>
</dict>
</dict>
</dict>
</plist>
この変更を有効にするには、リモートアップルイベントを停止して再開する必要があります。これは「システム環境設定」の「共有」パネルで行えます。ログ情報はシステムログに記録されます。 重要: 注:Mac OS X 10.3.xでは、アップルイベントサーバはxinetdによって実行されていました。環境設定ファイルは Process Managerプロセスをデバッグしたいけれども、GDBから開始したくない状況も考えられます。たとえば、GUIアプリケーションをデバッグするためにリモートコンピュータにsshでアクセスした場合、GDBから直接開始することはできません。アプリケーションが適切でないMachブートストラップ名前空間にあり、ペーストボードサーバのような重要なサービスに接続できないためです。通常、これは問題になりません。リモートユーザにアプリケーションを起動するよう依頼し、起動後にGDBの この問題に対しては、Process Managerが良い解決策を提供します。 リスト32:一時停止されたプロセスによって生成されるシステムログメッセージ Sep 7 14:18:37 guy-smiley QuickTime Player:Blocking on INIT_Processes \ for 15 seconds; attach to pid 4344 if you want. Core GraphicsQuartz Debugには、便利なデバッグ機能がいくつかあります。詳細については、テクニカルQ&A QA1236「Debugging Graphics with QuartzDebug」を参照してください。 QuickDrawQuickDrawでは、QuickDraw状態に関する情報を取得するためにGDBから呼び出せるルーチンがいくつかエクスポートされています。最初の3つのルーチン、 リスト33:QuickDraw出力ルーチン
(gdb) set $window = (void *) FrontWindow()
(gdb) set $port = (void *) GetWindowPort($window)
(gdb) call (int) QDDebugPrintPortInfo($port)
Dumping port 0x435670...
PixMap: 0x1FE72C
Base Address: 0xB0028000 [onscreen, buffered]
RowBytes: 0xFFFF9400
Bounds: (0, 0, 106, 352) (352w x 106h)
Depth: 0020
Port bounds: (0, 0, 106, 352) (352w x 106h)
Port shape: 0x1FE798 (0, 0, 106, 352) (352w x 106h) …
Vis rgn: 0x1FE730 (0, 0, 106, 352) (352w x 106h) …
Clip rgn: 0x1FE738 (-32000, -32000, 32000, 32000) …
Fore Color: 0000 0000 0000
Back Color: FFFF FFFF FFFF
[…]
$21 = 0
(gdb) call (int) QDDebugPrintCGSInfo($port)
CGS info for port 0x435670
CGSWindowID: 19798
Shape: 0x59E734 (99, 785, 205, 1137) (352w x …
Vis Region: 0x59E72C (0, 0, 0, 0) (0w x 0h) [rect]
Dirty Region: 0x59E730 (0, 0, 0, 0) (0w x 0h) [rect]
$20 = 0
(gdb) # 0x1FE730 is "Vis rgn" from QDDebugPrintPortInfo
(gdb) set $rgn=0x1FE730
(gdb) call (int)QDDebugDumpRegion($rgn)
Size = 116 Bounds = (0, 0, 106, 352) (352w x 106h) NEW FORMAT
0: 2 350
1: 1 351
2: 0 352
104: 1 351
105: 2 350
106:
$21 = 0
残りのルーチンは、リージョン形状を点滅させることで、画面上のリージョンを視覚化するように設計されています。リスト34に、これらのルーチンを呼び出す方法を示します。残念ながらこのドキュメントでは結果を見ることができないので、自分で試してみる必要があります。簡易変数 リスト34:QuickDraw点滅ルーチン (gdb) call (int) QDDebugFlashRegion($port, $rgn) $23 = 0 (gdb) call (void) QDDebugFlashClipRgn($port) (gdb) call (void) QDDebugFlashPortShape($port) (gdb) call (void) QDDebugFlashVisRgn($port) (gdb) call (int) QDDebugFlashCGSWindowShape($port) $24 = 0 (gdb) call (int) QDDebugFlashCGSWindowOpaqueShape($port) $25 = 0 (gdb) call (int) QDDebugFlashCGSVisRgn($port) $26 = 0 (gdb) call (int) QDDebugFlashCGSDirtyRgn($port) $27 = 0 Carbon (HIToolbox)CarbonのHIToolboxには、デバッグに便利な多数の機能が含まれています。
HIToolboxオブジェクト出力ルーチン以下に、さまざまなHIToolboxオブジェクト出力ルーチンを示します。 リスト35:HIToolboxイベント出力
(gdb) call (int)GDBPrintEventQueue()
Printing event queue 0x7632536c...
RunLoop: 0x40c560
Count: 4 Header: 0x1805010 Head: 0x49faf0 Tail: 0x489d10
EventRef Event Kind Time P Cnt Desc
-------- -------------------- ---------- - --- --------------------
49FAF0 kEventMouseDown 219335.28 H 001 x=879, y=61, button 1
489530 kEventWindowActivate 219335.46 H 002 0x4350A0 "Untitled 1"
43A4E0 kEventAppActiveWindo 218971.143 S 002
489D10 kEventWindowUpdate 219335.473 L 002 0x4A3C10 "Untitled 1 Properties"
$2 = 0
(gdb) # 0x489D10は最後のコマンドからのkEventWindowUpdateイベント
(gdb) call (void) _DebugPrintEvent(0x489D10)
Displaying event 489D10...
Class wind
Kind 1
When 219335
Priority Low
RetainCount 2
Queued Yes
Info kEventWindowUpdate, 0x4A3C10 "Untitled 1 Properties"
Parameters
param: ----
type: wind
size: 4
data: 004A3C10
J<リスト36:HIToolboxメニュー出力
(gdb) call (void) DebugPrintMenuList()
Index MenuRef ID Title
----- ---------- ------ -----
1 0x0041F330 -21629 <Apple>
2 0x0042EC00 128 QuickTime Player
3 0x0043C4B0 129 File
4 0x00445B70 130 Edit
[…]
<hierarchical menus>
0x0042CF90 140 Open Recent
(gdb) # 0x0042EC00はQuickTime Playerメニュー
(gdb) set $menu=0x0042EC00
(gdb) call (void) DebugPrintMenu($menu)
MenuRef: 0x0042EC00
Title : QuickTime Player
ID : 128
Width : 0
Height : 0
Enabled : true
Attributes : CondenseSeparators, ReceivedInit
Modal level : 0
Refcount : 3
Element : 0x004435B0
Item Count : 12
Item Icon Cmd Key Mark CmdID E V Text
---- ---- -------- -------- ----- - - ----
0001 0000 0x00 ' ' 0x00 ' ' Y Y About QuickTime Player
0002 0000 0x00 ' ' 0x00 ' ' N Y -
0003 0000 0x00 ' ' 0x00 ' ' pref Y Y Preferences
[…]
HIObject
Ref count : 3
Event Target : 0x42f040
Event Handler : 0x436f10
(gdb) call (void) DebugPrintMenuItem($menu, 1)
Menu: 0x0042EC00 Item: 1 Info:
Text: About QuickTime Player
Mark: <none>
Cmd Key: <none>
Icon: <none>
Style Normal
Command ID: 0 (0x00000000)
Modifiers: 0x00
[…]
リスト37:HIToolboxウインドウおよびダイアログの出力
(gdb) call (void) DebugPrintWindowList()
Window Class WID Vis Hil Level Title Group
---------- -------- ---- --- --- ----- --------------------- -----------…
0x004350A0 Document 4ED4 Y Y 0 Untitled 1 0x76E47A89 …
0x004A3C10 Document 4EED Y N 0 Untitled 1 Properties 0x76E47A89 …
(gdb) # 0x004350A0は、「Untitled 1」(名称未設定1)ウインドウ
(gdb) set $window=0x004350A0
(gdb) # 0x004A3C10は「Untitled 1 Properties」(名称未設定1のプロパティ)ダイアログ
(gdb) set $dialogWindow=0x004A3C10
(gdb) call (void) DebugPrintWindow($window)
Window 0x004350A0
Title : Untitled 1
Class : Document
Group : 0x76E47A89 "com.apple.HIToolbox.windowgroups.document"
Scope : all
Attributes : Collapse Box, In WindowMenu
Visible : Yes
Collapsed : No
Latent visibility : <none>
Highlighted : Yes
Structure region : 1FE80C #0, #0, #106, #352 (#352w x #106h) [non-rect]
[…]
(gdb) call (void) DebugPrintAllWindowGroups()
Window group tree
-------------------------------------------------------------------------…
1 level 0 group 0x76E0BFE9 "com.apple.hitoolbox.windowgroups.root"
2 level 0 group 0x76E47A89 "com.apple.HIToolbox.windowgroups.doc…
(gdb) # 0x76E47A89 is the second window group
(gdb) call (void) DebugPrintWindowGroup(0x76E47A89)
WindowGroup 0x76E47A89 "com.apple.HIToolbox.windowgroups.document"
Attributes: <none>
Refcount: 1
Previous group: <none>
Next group: <none>
Parent group: 0x76E0BFE9 "com.apple.hitoolbox.windowgroups.root"
[…]
(gdb) set $dialog = (void *) GetDialogFromWindow($dialogWindow)
(gdb) call (void) GDBShowDialogInfo($dialog)
Dialog: 0x76ED59A1
Window: 0x004A3C10 "Untitled 1 Properties"
TextHandle: 0x0059EC7C
Default Item: 1
Cancel Item: 0
Keyboard Focus Item: 0
RefCon: 0x06054AB5 (101010101)
リスト38:HIToolboxコントロール出力
(gdb) call (void) GDBShowControlHierarchy($window)
Dumping info for window 0x4A3C10
Window found.Dumping views...
Root 0x4ba260 , ID ''/0, (-32768,-32768,32767,32767), Embedder, Vis, Act,…
Control 0x4c24d0 <appl/sbar> ( "" ), ID ''/0, (172,301,226,317), Vis,…
Control 0x4c6080 <appl/sbar> ( "" ), ID ''/0, (75,301,142,317), Vis, …
Control 0x4c49c0 <appl/push> ( "Delete" ), ID ''/0, (241,220,261,290)…
Control 0x4c4790 <appl/push> ( "Edit?" ), ID ''/0, (241,135,261,205),…
Control 0x4c17c0 <appl/push> ( "Add?" ), ID ''/0, (241,50,261,120), V…
Control 0x4be1d0 <appl/popb> ( "" ), ID ''/0, (12,176,28,316), Vis, A…
Control 0x4ba1f0 <appl/popb> ( "" ), ID ''/0, (12,24,28,164), Vis, Ac…
(gdb) # 0x4c24d0は最初のスクロールバーコントロール
(gdb) call (void) GDBShowControlInfo(0x4c24d0)
HIScrollBar
Size : Auto
Live Tracking : No
Control 0x004C24D0 ""
Control Kind : 'appl', 'sbar'
Control ID : '', 0
Window : 0x004A3C10 "Untitled 1 Properties"
Parent : 0x004BA260
Minimum : 0 (0x00000000)
Maximum : 0 (0x00000000)
Value : 0 (0x00000000)
[…]
HIObject
Ref count : 1
Event Target : 0x4c39a0
Event Handler : 0x4c3a10
最後に、 HIToolboxリージョン点滅リスト39に示すルーチンは、リージョンを点滅させることで画面上でリージョンを視覚化します。残念ながらこのドキュメントでは結果を見ることができないので、自分で試してみる必要があります。 リスト39:HIToolboxリージョン点滅ルーチン (gdb) call (void) DebugFlashWindowVisRgn($window) (gdb) call (void) DebugFlashWindowUpdateRgn($window) HIToolboxイベントのデバッグCarbonイベントの登場で、ツールボックスにおけるイベントのフローが把握しにくいことがよくあります。HIToolboxは、これを支援する2つのデバッグ機能を備えています。 EventDebug環境変数
リスト40:EventDebug出力
$ EventDebug=1 /Applications/QuickTime\ Player.app/Contents/MacOS/\
QuickTime\ Player
Event Posted: Queue: 0x763059ae, Event: kEventAppleEvent, 221132.233, S …
SendEventToEventTarget entered
Sending Event to 0x4128E0: hiob 2
Called handler 0x927F3200. Event was handled
Leaving target 0x4128E0 with result 0
SendEventToEventTarget entered
Sending Event to 0x41E6F0: hiob 2
SendEventToEventTarget entered
Sending Event to 0x41EC30: hiob 2
SendEventToEventTarget entered
Sending Event to 0x41EC30: hiob 2
Called handler 0x927F3200. Event was handled
Leaving target 0x41EC30 with result 0
Called handler 0x927FBB50. Event was handled
Leaving target 0x41EC30 with result 0
Called handler 0x927F3200. Event was handled
Leaving target 0x41E6F0 with result 0
[…]
イベントトレース
この問題に対する1つの解決策は、イベント単位のトレースを有効にすることです。これを実行するには、GDBから リスト41:イベントトレース
(gdb) call (void) TraceEventByName("kEventRawKeyDown")
(gdb) c
Continuing.
Event Posted: Queue: 0x76309338, Event: kEventRawKeyDown, 221443.183, S
SendEventToEventTarget entered
Sending Event to 0x415750: kEventRawKeyDown
SendEventToEventTarget entered
Sending Event to 0x413050: kEventRawKeyDown
Called handler 0x928CD05C. Event was NOT handled
Leaving target 0x413050 with result -9874
SendEventToEventTarget entered
Sending Event to 0x42DE30: kEventRawKeyDown
Leaving target 0x42DE30 with result -9874
Sending Event to 0x4351F0: kEventRawKeyDown
Leaving target 0x4351F0 with result -9874
Sending Event to 0x4126F0: kEventRawKeyDown
Called handler 0x929597E0. Event was NOT handled
Called handler 0x927F4F40. Event was NOT handled
Leaving target 0x4126F0 with result -9874
Leaving target 0x415750 with result -9874
Event Removed: Queue: 0x76309338, Event: kEventRawKeyDown, 221443.183, S
Event Pulled (C): kEventRawKeyDown, 221443.183, S
HIToolboxイベント統計情報HIToolboxでイベント統計情報を出力できるようにする2つの環境変数があります。 その他のHIToolboxデバッグ機能
重要:Mac OS X 10.4以降では、これが正常に機能するように、プロファイル版のHIToolboxフレームワーク(
CocoaすべてのCocoaオブジェクト( リスト42:GDBのpoコマンドの使用
$ gdb /Applications/TextEdit.app
GNU gdb 6.1-20040303 (Apple version gdb-434) […]
(gdb) fb -[NSCFDictionary copyWithZone:]
Function "-[NSCFDictionary copyWithZone:]" not defined.
Breakpoint 1 (-[NSCFDictionary copyWithZone:])pending.
(gdb) r
[…]
Breakpoint 1 at 0x928ea1d4
Pending breakpoint 1 - "-[NSCFDictionary copyWithZone:]" resolved
Breakpoint 1, 0x928ea1d4 in -[NSCFDictionary copyWithZone:] ()
(gdb) po $r3
Reading symbols for shared libraries . done
<NSCFDictionary 0x32d6d0>{
copyright = ;
author = ;
OpenPanelFollowsMainWindow = 0;
UseTransitionalDocType = 0;
UseInlineCSS = 0;
[…]
}
注: Objective-C
表7:便利なObjective-Cランタイムデバッグ環境変数
Cocoaコードをアセンブリレベルでデバッグする際には、次のObjective-Cランタイムの特徴に留意してください。
リスト43に、GDBからこの情報を使用する方法の一例を示します。 リスト43:Objective-Cランタイムの「秘密」 $ gdb /Applications/TextEdit.app GNU gdb 5.3-20030128 (Apple version gdb-330.1) […] (gdb) r Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit […] ^C Program received signal SIGINT, Interrupt. 0x900074c8 in mach_msg_trap () (gdb) # Objective-Cのメソッドディスパッチャにブレークポイントを設定する (gdb) b objc_msgSend Breakpoint 1 at 0x908311f4 (gdb) # 実行を継続する... (gdb) c Continuing. Breakpoint 1, 0x908311f4 in objc_msgSend () (gdb) # ブレークポイントに達した。オブジェクトの最初の4ワードをダンプする (gdb) x/4x $r3 0x10cc10:0xa0a04e18 0x00000001 0x00000000 0x00000000 (gdb) # セレクタを出力する (gdb) x/s $r4 0x9083ed94 <_errDoesntRecognize+884>:"init" (gdb) # オブジェクトを'po'する。その前にブレークポイントを無効にする必要がある (gdb) dis 1 (gdb) po $r3 <NSAutoreleasePool:0x10cc10> (gdb) # 'isa'ポインタを出力する。 (gdb) po 0xa0a04e18 NSAutoreleasePool シンボルなしでデバッグするときには、Objective-Cランタイムからデバッグに役立つ関数を使用できます。表8に示すルーチンは特に便利です。 表8:便利なObjective-Cランタイム関数
「テキストエディット」はシンボルなしで提供されていますが、その「テキストエディット」の リスト44:Objective-Cランタイムを使用してシンボルなしでデバッグ
$ gdb /Applications/TextEdit.app
GNU gdb 6.1-20040303 (Apple version gdb-413) […]
(gdb) r
Starting program:/Applications/TextEdit.app/Contents/MacOS/TextEdit
[…]
^C
Program received signal SIGINT, Interrupt.
0x9000a778 in mach_msg_trap ()
(gdb) # -[Controller applicationShouldTerminate:] にブレークポイントを設定したいが
(gdb) # アプリケーションのシンボルはすべてストリップされている。したがって
(gdb) # 簡単にはできない。
(gdb) info func applicationShouldTerminate
All functions matching regular expression "applicationShouldTerminate":
(gdb) # ControllerクラスのClassオブジェクトを取得する
(gdb) call (void *)objc_getClass("Controller")
$1 = (void *) 0x1caa8
(gdb) # "applicationShouldTerminate:"メソッドに対応するSELオブジェクトを取得する
(gdb) call (void *)sel_getUid("applicationShouldTerminate:")
$2 = (void *) 0x909f36a0
(gdb) # 対象クラスに対応するIMPを取得する
(gdb) call (void *)class_getInstanceMethod($1, $2)
$3 = (void *) 0x325bd8
(gdb) # IMPをダンプする
(gdb) x/3x $3
0x325bd8:0x909f36a0 0x00018ea4 0x0000a7b0
(gdb) # すべてが順調であることを確認するために最初のワードを出力する
(gdb) x/s 0x909f36a0
0x909f36a0 <_errNewVars+220620>:"applicationShouldTerminate:"
(gdb) # 3番目のワードはコードへのポインタ
(gdb) x/8i 0x0000a7b0
0xa7b0:mflr r0
0xa7b4:stmw r23,-36(r1)
0xa7b8:lis r4,2
0xa7bc:stw r0,8(r1)
0xa7c0:mr r3,r5
0xa7c4:li r26,0
0xa7c8:stwu r1,-112(r1)
0xa7cc:lwz r4,-15200(r4)
(gdb) # コードにブレークポイントを設定する
(gdb) b *0x0000a7b0
Breakpoint 1 at 0xa7b0
(gdb) # 実行を再開し、アプリケーションを終了する
(gdb) c
Continuing.
Reading symbols for shared libraries ............ done
Reading symbols for shared libraries . done
Breakpoint 1, 0x0000a7b0 in ?? ()
(gdb) # ブレークポイントに達した。パラメータを出力する。まずは
(gdb) # すべてのメソッドに共通する暗黙の"self"および"SEL"パラメータから始め、
(gdb) # 続いてメソッド固有の"app"パラメータを出力する
(gdb) po $r3
<Controller:0x328b50>
(gdb) x/s $r4
0x909f36a0 <_errNewVars+220620>:"applicationShouldTerminate:"
(gdb) po $r5
<NSApplication:0x3198e0>
Objective-Cランタイム関数とデータ構造の詳細について、 警告:このテクニカルノートで説明している多くのことと同様に、Objective-Cランタイムの内部動作は非公開です。それらはこれまでにも変更されてきましたし、今後も変更されます。この情報をデバッグに利用するのは問題ありませんが、お客様に出すコードではこの情報に依存しないでください。 FoundationFoundationには、環境変数を使用して有効にできる多数のデバッグ機能があります。表9に、中でも特に興味深いものをいくつか示します。これらの詳細ついては、 表9:「NSDebug.h」の環境変数
重要:Foundationのデバッグ機能を有効または無効にするには、他のシステムコンポーネントの場合のように1または0ではなく、環境変数の値を「YES」または「NO」に設定してください。 Cocoaでプログラミングする際に最も一般的に見られるバグの形態は、オブジェクトの過剰解放によるものです。これは一般的にアプリケーションがクラッシュする原因となります。しかし、クラッシュが発生するのは最終参照カウントが解放されたとき(そして解放されたオブジェクトと通信しようとしたとき)で、通常はバグの実際の場所から遠いところで起こります。このような問題をデバッグするには、 リスト45:NSZombieの効果 $ NSZombieEnabled=YES DragNDropOutlineView 2004-04-30 14:56:28.238 DragNDropOutlineView[803] *** *** Selector \ '_propagateDirtyRectsToOpaqueAncestors' sent to dealloced instance \ 0x530540 of class AnimatingOutlineView. このような問題をさらにデバッグするには、GDBを使用して、
リスト46:NSScriptingDebugLogLevelの有効化
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSScriptingDebugLogLevel 1
[…] Suite NSCoreSuite, apple event code 0x3f3f3f3f
[…] Suite NSTextSuite, apple event code 0x3f3f3f3f
[…] Suite TextEdit, apple event code 0x74786474
[…] Command: NSCoreSuite.Get
Direct Parameter: <NSPropertySpecifier: version>
Receivers: <NSPropertySpecifier: version>
Arguments: {}
[…] Property Value: 1.4
[…] Result: <NSAppleEventDescriptor: 'utxt'($0031002E0034$)
AppKit
AppKitイベント
リスト47:NSTraceEventsの使用 $ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSTraceEvents YES 2004-09-07 16:21:23.334 TextEdit[4520] timeout = 62997727116.666718 seco… 2004-09-07 16:21:23.341 TextEdit[4520] got apple event of class 61657674… 2004-09-07 16:21:23.454 TextEdit[4520] still in loop, timeout = 62997727… 2004-09-07 16:21:23.455 TextEdit[4520] timeout = 62997727116.546562 seco… 2004-09-07 16:21:27.793 TextEdit[4520] Received event:Kitdefined at:0.… 2004-09-07 16:21:27.804 TextEdit[4520] In Application:NSEvent:type… 2004-09-07 16:21:27.804 TextEdit[4520] timeout = 62997727112.196404 seco… 2004-09-07 16:21:27.805 TextEdit[4520] Received event:LMouseDown at:37… 2004-09-07 16:21:27.805 TextEdit[4520] In Application:NSEvent:type… 2004-09-07 16:21:27.805 TextEdit[4520] In Window:NSEvent:type=LMou… 2004-09-07 16:21:27.809 TextEdit[4520] In Application:NSEvent:type… […] AppKitビュー
図4:NSShowAllViewsを有効にしたテキストエディット
図5:実行中のNSShowAllDrawing
点滅の継続時間を制御するには、 その他のAppKitデバッグ機能
リスト48:NSDragManagerLogLevelの使用
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSDragManagerLogLevel 6
2004-09-07 16:26:42.031 TextEdit[4523] mouseDown location:{29, 389}, ba…
2004-09-07 16:26:42.033 TextEdit[4523] offset of image lower left relati…
2004-09-07 16:26:42.033 TextEdit[4523] type NeXT Rich Text Format v1.0 p…
2004-09-07 16:26:42.034 TextEdit[4523] type NSStringPboardType:data <CF…
2004-09-07 16:26:42.034 TextEdit[4523] type NeXT plain ascii pasteboard …
2004-09-07 16:26:42.036 TextEdit[4523] type CorePasteboardFlavorType 0x7…
2004-09-07 16:26:42.036 TextEdit[4523] type CorePasteboardFlavorType 0x7…
2004-09-07 16:26:42.049 TextEdit[4523] type CorePasteboardFlavorType 0x5…
2004-09-07 16:26:42.050 TextEdit[4523] type CorePasteboardFlavorType 0x7…
[…]
リスト49:NSAccessibilityDebugLogLevelの使用
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSAccessibilityDebugLogLevel 3
2004-09-07 16:36:34.990 TextEdit[4526] creating id<=element table
2004-09-07 16:36:34.990 TextEdit[4526] creating id=>element
2004-09-07 16:36:35.001 TextEdit[4526] Element<=>UniqueId Tables
--- id<=element --- size 1
42 <- (0x1576e0): <NSTextView: 0x1576e0>
Frame = {{0.00, 0.00}, {460.00, 395.00}}, Bounds = {{0.00, 0.00}, …
Horizontally resizable: NO, Vertically resizable: YES
MinSize = {460.00, 395.00}, MaxSize = {340282346638528859811704183…
2004-09-07 16:36:35.003 TextEdit[4526] Element<=>UniqueId Tables
[…]
ドキュメント改訂履歴
掲載日: 2006-07-25 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|