| ログイン | ご入会 |
ADC連絡先
|
|
はじめにMac OS X には、個々のサブシステムの開発とデバッグを支援するために、エンジニアリングチームが追加したデバッグ機能がいくつか含まれています。 これら機能の多くは、リリース後のシステムにも残っており、コードのデバッグに利用できます。 このテクニカルノートでは、広く役立つデバッグ機能をいくつか説明します。 別の場所で文書化されているデバッグ機能については、機能の簡単な概要と既存ドキュメントへのリンクを記載しています。 このテクニカルノートでは、デバッグ機能を網羅的には文書化しておらず、将来もそうする予定はありません。 警告: このテクニカルノートで説明するデバッグ機能はサポート対象外です。 アップルは、Mac OS X の進化に応じて各機能を変更または削除する権利を留保します。変更または削除は以前にもあり、今後もあることが予想されます。 これらの機能はデバッグ専用です。 このテクニカルノートで説明する機能の存在または動作に依存する製品を出荷してはなりません。 重要: このテクニカルノートは(Xcode 1.5 をインストールした)Mac OS X 10.3.5 をベースにしており、該当するシステムに関しては正確です。 このテクニカルノートで説明する詳細の多くはリリースによって異なるため、新旧のシステムでは若干の差が生じる可能性があります。 このテクニカルノートでは、高度なデバッグテクニックを取り上げています。 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: デバッグを有効にする特定ファイルの作成 $ touch /var/tmp/do_xnc_log [... ここでいったんログアウトし、再度ログインします ...] $ cat /var/tmp/xnc_logs/loginwindow ------------------------------------------------- [0xa000a1ec] created notification center 0x40ccb0 0 [0xa000a1ec] register 0x40ccb0 _NSAppleEventManagerDidFailToDispatchNoti… [...] 呼び出し可能ルーチン多くのシステムフレームワークには、デバッグ情報を リスト 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 の CrashReporterCrashReporter はクラッシュするすべてのプログラムに関する情報を記録する貴重なデバッグ機能です。 詳細については、テクニカルノートの TN2123「CrashReporter」 を参照してください。 CrashReporter は常時有効であり、必要なのは出力を見ることだけです。 BSDBSD サブシステムはプロセス、メモリ、ファイル、およびネットワークインフラを実装するため、Mac OS X 上のすべてのアプリケーションにとって不可欠です。 BSD には、利用可能な優れたデバッグ機能がいくつか実装されています。 コアダンプコアダンプは、プリミティブなデバッグ機能であると過小評価されています。 実際には、難しい問題をデバッグするとき、特に問題をローカルで再現できない場合は、コアダンプが非常に役立つことがあります。 システム全体でコアダンプを有効にするには、 リスト 9: 無制限のコアダンプサイズ $ ulimit -c unlimited $ /Applications/TextEdit.app/Contents/MacOS/TextEdit [...] コアダンプ機能をテストするには、リスト 10 に示すように、 リスト 10: 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)」というメッセージを出力して終了します。 コアダンプは リスト 11: コアダンプの使用
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 ?? ()
リスト 11 から分かるように、コアダンプにはデバッガシンボルが含まれていません。 シンボルファイルが手元にあれば、 リスト 12: シンボルの追加 (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 ?? () 重要: コアダンプは大きくなります。 リスト 11 の例では、「テキストエディット」のコアダンプは 144 MB です。 当然のことながら、コアダンプを有効にしている場合は、必ず メモリアロケータデフォルトのメモリアロケータには、環境変数を通じて有効にできるいくつかのデバッグ機能が含まれています。 これらは man ページで完全に文書化されています。 表 1 に、そのうちのいくつかの便利なデバッグ機能を示します。 表 1: 便利なメモリアロケータ環境変数
重要: これらの環境変数は、特別なメモリライブラリ(MallocDebug または保護メモリアロケータなど)を必要としません。 実のところ、これらはデフォルトの非デバッグメモリアロケータによってサポートされているため、常時利用可能です。 デフォルトのメモリアロケータも、プログラミング上の一般的な問題を検出すると、メッセージのログを記録します。 たとえば、同じメモリブロックを二度解放するか、割り当てていないメモリを解放すると、 リスト 13: 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 には保護メモリアロケータの リスト 14: libgmalloc の有効化 $ gdb /Applications/TextEdit.app GNU gdb 5.3-20030128 (Apple version gdb-330.1) [...] (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib (gdb) set env DYLD_FORCE_FLAT_NAMESPACE 1 (gdb) set env MALLOC_FILL_SPACE 1 (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-8 Reading symbols for shared libraries [...]
コマンドラインツールMac OS X には、デバッグ用の優れたコマンドラインツールがいくつか含まれています。 表 2 に筆者の愛用ツールを示します。 表 2: 重要なコマンドラインツール
ダイナミックリンカ(dyld)Mac OS X ダイナミックリンカ(dyld)は、環境変数を使用して有効にできるいくつかのデバッグ機能をサポートしています。 これらは man ページで完全に文書化されています。 表 3 に、そのうちのいくつかの便利な変数を示します。 表 3: ダイナミックリンカの環境変数
もちろん、 デバッグライブラリMac OS X の多くのフレームワークには、実運用版とデバッグ版の両方が含まれています。 デバッグ版には、接尾辞「_debug」が付いています。 たとえば、Core Foundation フレームワークの実運用版は リスト 15: _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」版を有効にしたいとします。 しかし、 幸い、多少乱暴ながらも、簡単な解答があります。デバッグ版を非デバッグ版にコピーするだけです。リスト 16 にその一例を示します。 リスト 16: AE デバッグライブラリのみをアクティブにする $ cd /System/Library/Frameworks/ApplicationServices.framework/\ Frameworks/AE.framework/Versions/A/ $ sudo cp -n AE AE_original Password: ******** $ sudo cp AE_debug AE コピーが完了したら、変更を有効にするために再起動する必要があります。 重要: このテクニックはデバッグに役立ちますが、弊害がいくつかあります。 たとえば、デバッグライブラリは非デバッグライブラリと異なるアドレスに事前バインドされているため、事前バインドプログラムは事前バインドした状態では開始できず、起動が遅くなります。 したがって、これは専用テストコンピュータにおいてのみ実行するか、それが現実的でない場合は、テスト用システムを起動したメインコンピュータ上で実行します。 さらに、デバッグを完了したらすぐに、ライブラリを元に戻してください。 非デバッグライブラリに戻すには、リスト 17 に示すように、元のライブラリをコピーするだけです。 リスト 17: AE デバッグライブラリを非アクティブにする $ sudo cp AE_original AE Password: ******** 注意: ライブラリ名を変更するのではなくコピーすることを勧める理由は、ライブラリの最新コピーを誤って上書きするのを難しくするためです。 ウインドウサーバの回避状況によっては、ウインドウサーバなしで操作するほうが便利な場合もあります。 たとえば、
このレベルでの作業を完了したら、( 重要: この環境はシングルユーザモードではありません。 ほとんどのシステムデーモンはまだ実行されていて、システムの GUI コンポーネントだけが停止されます。 Core ServicesCore Services には、メッセージを出力してデバッガに入る多くのルーチン( 図 3: Xcode における USERBREAK の設定
Code Fragment Manager(CFM)Mac OS X の CFM 互換環境では、2 つの便利な環境変数、 Core FoundationCore Foundation(CF)フレームワークのあらゆるバリエーションが、 リスト 18: 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)
},
)
}
}
重要: 注意: リスト 18 に、 その他にも、 また、Core Foundation フレームワークには、広範なデバッグ支援を提供するデバッグ版もあります。 たとえば、Core Foundation の非デバッグ版では、ルーチンに渡されるパラメータの妥当性はチェックされませんが、デバッグ版ではパラメータが全面的にチェックされます。 これは、コードの多くの Core Foundation 関連のバグを見つけ出すのに役立ちます。 Core Foundation のデバッグライブラリは、 表 4: CFZombieLevel 環境変数のビット定義
CFNotificationCenterCFNotificationCenter ログを有効にするには、
Component ManagerComponent Manager は さらに、 File ManagerCore Services の File Manager(一般には Carbon File Manager と呼ばれている)には、GDB から呼び出し可能な便利なルーチンがいくつかあります。 最も役に立つ リスト 19: 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
この他にも、 最後に、File Manager は Folder ManagerFolder Manager は、 GestaltCore Services は、 リスト 20: 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
出力(CUPS)Mac OS X 10.2 以降では、コアプリンティングアーキテクチャとして CUPS(Common UNIX Printing System)を使用しています。 CUPS には、CUPS 設定ファイル( 重要: このファイルを変更したら、変更を有効にするために、CUPS デーモンに リスト 21: CUPS デーモンの再起動 sudo /System/Library/StartupItems/PrintingServices/PrintingServices restart CUPS ドライバまたはフィルタを開発している場合は、 リスト 22: 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"); ApplicationServicesアップルイベントApple Event Manager には、デバッグ用の広範なサポート機能が組み込まれています。 このサポート機能について学ぶ最善の方法は、リスト 23 に示すように、GDB を使用して リスト 23: 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 つの項目は、デバッグの出力先にのみ影響を与えます。 デバッグ出力を得るには、上記の環境変数のいずれかを使用するか、 リモートアップルイベントリモートアップルイベントに関する問題がある場合は、アップルイベントサーバプロセスでログ記録を有効にすると便利なこともあります。 これを行うには、 リスト 24: リモートアップルイベントデバッグの有効化
# EPPC はリモート AppleEvents サービスです
#
service eppc
{
disable = no
socket_type = stream
wait = no
user = eppc
server = /System/Library/Frameworks/\
ApplicationServices.framework/Frameworks/AE.framework/\
Versions/A/Support/AEServer
server_args = --debug
groups = yes
flags = REUSE
}
この変更を有効にするには、リモートアップルイベントを停止して再開する必要があります。これは「システム環境設定」の「共有」パネルで行えます。 ログ情報はシステムログに記録されます。 重要: Process Managerプロセスをデバッグしたいけれども、GDB から開始したくないという状況も考えられます。 たとえば、GUI アプリケーションをデバッグするためにリモートコンピュータに ssh でアクセスした場合、GDB から直接開始することはできません、アプリケーションが適切でない Mach ブートストラップ名前空間にあり、ペーストボードサーバのような重要なサービスに接続できないためです。 通常、これは問題になりません。 リモートユーザにアプリケーションを起動するよう依頼し、起動後に GDB の この問題に対しては、Process Manager が良い解決策を提供します。 リスト 25: 一時停止されたプロセスによって生成されるシステムログメッセージ Sep 7 14:18:37 guy-smiley QuickTime Player: Blocking on INIT_Processes \ for 15 seconds; attach to pid 4344 if you want. QuickDrawQuickDraw では、QuickDraw 状態に関する情報を取得するために GDB から呼び出せるルーチンがいくつかエクスポートされています。 最初の 3 つのルーチン、 リスト 26: 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) echo 0x1FE730 is "Vis rgn" from QDDebugPrintPortInfo\n
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
残りのルーチンは、リージョン形状を点滅させることで、画面上のリージョンを視覚化するように設計されています。 リスト 27 に、これらのルーチンを呼び出す方法を示します。残念ながらこの記事では結果を見ることはできないので、自分で試してみる必要があります。 簡易変数 リスト 27: 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 オブジェクト出力ルーチンを示します。 リスト 28: 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) echo 0x489D10 is the kEventWindowUpdate event from last command\n
0x489D10 is the kEventWindowUpdate event from last command
(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<
リスト 29: 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) echo 0x0042EC00 is the QuickTime Player menu\n
0x0042EC00 is the QuickTime Player menu
(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
[…]
リスト 30: 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) echo 0x004350A0 is the "Untitled 1" window\n
0x004350A0 is the "Untitled 1" window
(gdb) set $window=0x004350A0
(gdb) echo 0x004A3C10 is the "Untitled 1 Properties" dialog\n
0x004A3C10 is the "Untitled 1 Properties" dialog
(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) echo 0x76E47A89 is the second window group\n
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)
リスト 31: 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) echo 0x4c24d0 is first scrollbar control\n
echo 0x4c24d0 is first scroll bar control
(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 リージョンの点滅リスト 32 に示すルーチンは、リージョンを点滅させるのに使用できます。画面上でリージョンを視覚化することができます。残念ながらこの記事では結果を見ることができないので、自分で試してみる必要があります。 リスト 32: HIToolbox リージョン点滅ルーチン (gdb) call (void) DebugFlashWindowVisRgn(0x004351E0) (gdb) call (void) DebugFlashWindowUpdateRgn(0x004351E0) HIToolbox イベントデバッグCarbon イベントの登場で、ツールボックスにおけるイベントの流れが理解しにくいことがよくあります。 HIToolbox は、これを支援する 2 つのデバッグ機能を提供します。 EventDebug 環境変数
リスト 33: 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 から リスト 34: イベントトレース
(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 デバッグ機能
Cocoaすべての Cocoa オブジェクト( リスト 35: GDB の po コマンドの使用
$ gdb /Applications/TextEdit.app
GNU gdb 5.3-20030128 (Apple version gdb-330.1) […]
(gdb) fb *'-[NSDictionary hash]'
No symbol table is loaded. Use the "file" command.
Breakpoint 1 at 0x0
(gdb) r
[…]
Breakpoint 1, 0x90a233d8 in -[NSDictionary hash] ()
(gdb) po $r3
<NSAttributeDictionary 0x159330>{
NSParagraphStyle = Alignment 4, LineSpacing 0, \
ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, \
TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, \
LineHeightMultiple 0, LineBreakMode 2, Tabs (28L, 56L, 84L, \
112L, 140L, 168L, 196L, 224L, 252L, 280L, 308L, 336L), \
DefaultTabInterval 0;
NSColor = NSCalibratedWhiteColorSpace 1 1;
NSFont = "CGS LucidaGrande 13.00 pt. P [] (0x00158af0) \
fobj=0x00156f50, spc=4.11";
_NSOriginalFontAttributeName = "CGS LucidaGrande 13.00 pt. \
P [] (0x00158af0) fobj=0x00156f50, spc=4.11";
}
注意: Cocoa コードをアセンブリレベルでデバッグする際には、次の Objective-C ランタイムの特徴に留意してください。
リスト 36 に、GDB からこの情報を使用する方法の一例を示します。 リスト 36: 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) echo Set a breakpoint on the Objective-C method dispatcher.\n Set a breakpoint on the Objective-C method dispatcher. (gdb) b objc_msgSend Breakpoint 1 at 0x908311f4 (gdb) echo Continue execution...\n Continue execution... (gdb) c Continuing. Breakpoint 1, 0x908311f4 in objc_msgSend () (gdb) echo Hit the breakpoint; dump the first 4 words of the object.\n Hit the breakpoint; dump the first 4 words of the object. (gdb) x/4x $r3 0x10cc10: 0xa0a04e18 0x00000001 0x00000000 0x00000000 (gdb) echo Print the selector.\n Print the selector. (gdb) x/s $r4 0x9083ed94 <_errDoesntRecognize+884>: "init" (gdb) echo Want to 'po' object; must disable the breakpoint first.\n Want to 'po' object; must disable the breakpoint first. (gdb) dis 1 (gdb) po $r3 <NSAutoreleasePool: 0x10cc10> (gdb) echo Print the 'isa' pointer.\n Print the 'isa' pointer. (gdb) po 0xa0a04e18 NSAutoreleasePool FoundationFoundation には、環境変数を使用して有効にできる多数のデバッグ機能があります。 表 5 に、中でも特に興味深いものをいくつか示します。これらの詳細ついては、 表 5: 「NSDebug.h」の環境変数
重要: Foundation のデバッグ機能を有効または無効にするには、他のシステムコンポーネントの場合のように 1 または 0 ではなく、環境変数の値を「YES」または「NO」に設定してください。 Cocoa でプログラミングする際に最も一般的に見られるバグの形態は、オブジェクトの過剰解放によるものです。 これは一般的にアプリケーションがクラッシュする原因となります。しかし、クラッシュが発生するのは最終参照カウントが解放されたときで、多くの場合、これはバグの実際の場所から遠いところで起こります。 このような問題をデバッグするには、 リスト 37: NSZombie の効果 $ NSZombieEnabled=YES DragNDropOutlineView 2004-04-30 14:56:28.238 DragNDropOutlineView[803] *** *** Selector \ '_propagateDirtyRectsToOpaqueAncestors' sent to dealloced instance \ 0x530540 of class AnimatingOutlineView. このような問題をさらにデバッグするには、GDB を使用して、
リスト 38: NSScriptingDebugLogLevel の有効化
$ defaults write com.apple.TextEdit NSScriptingDebugLogLevel YES
$ /Applications/TextEdit.app/Contents/MacOS/Te…
[…]
2004-09-07 15:57:21.449 TextEdit[4417] Command: NSCoreSuite.Get
Direct Parameter: <NSPropertySpecifier: version>
Receivers: <NSPropertySpecifier: version>
Arguments: {}
2004-09-07 15:57:21.449 TextEdit[4417] Property Value: 1.3
2004-09-07 15:57:21.449 TextEdit[4417] Result: <NSAppleEventDescriptor: …
[…]
AppKit
AppKit イベント
リスト 39: NSTraceEvents の使用 $ defaults write com.apple.TextEdit NSTraceEvents YES $ /Applications/TextEdit.app/Contents/MacOS/TextEdit 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 デバッグ機能
リスト 40: NSDragManagerLogLevel の使用
$ defaults write com.apple.TextEdit NSDragManagerLogLevel 6
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit
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…
[…]
リスト 41: NSAccessibilityDebugLogLevel の使用
$ defaults write com.apple.TextEdit NSAccessibilityDebugLogLevel 3
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit
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
[…]
ドキュメントの改訂履歴
掲載日: 2004-12-02 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||