WWDC Quick Look 💓 By SwiftGGTeam
Debug Swift debugging with LLDB

Debug Swift debugging with LLDB

元の動画を見る

ハイライト

LLDB にはデバッガとコンパイラの 2 つの役割があります。デバッガ側はデバッグ情報と Swift リフレクション メタデータに依存して変数表示機能を提供し、コンパイラ側は Swift モジュールに依存して式評価機能を提供します。いつpo失敗しても変数ビューが正常である場合、問題はモジュールのインポート手順にあります。

主要内容

サードパーティのフレームワークを統合しています。このフレームワークは、CI システムによって毎晩構築されます。デバッグ バージョンをダウンロードしましたが、デバッグ中に奇妙な問題が発生しました。ブレークポイントにヒットする可能性がありますが、poこのコマンドはエラーを報告し、シングルステップ トレースでもアセンブリ コードのみが表示されます。

(02:30) これが実際のセッションの様子です。講演者のエイドリアンはテキスト アドベンチャー ゲームを書きました。 TerminalInterface フレームワークを統合した後、デバッガーが突然「失敗」しました。

ソースコードが表示されないのはなぜですか?

(03:54) コンパイラーはマシンコードを生成するときに、デバッグ情報も生成し、コードアドレスをソースファイルと行番号にマップします。これらのデバッグ情報は、最終的に .dSYM バンドルにパッケージ化されます。 LLDB は Spotlight を介して .dSYM を見つけるため、ファイルがどこに配置されているかは関係ありません。

問題は、フレームワークが CI サーバー上に構築されており、デバッグ情報にはサーバー上のソース ファイル パスが記録されていることです。/Volumes/BUILD_SERVER/projects/...、ローカルパスは完全に異なります。

(05:48) LLDB は、この問題を解決するソース マップ メカニズムを提供します。スキームエディターでプロジェクトレベルを設定できます。.lldbinitファイル、パスを自動的に再マップします:

settings set target.source-map /Volumes/BUILD_SERVER/projects /Users/demo/Desktop/Adventure/3rdparty

設定が完了したら、再度実行するとソースコードを確認できます。

### なぜpoエラーは報告されますが、変数ビューは正常です

(08:33) これはさらに深い問題です。popLLDB などのコマンドは、本質的に完全な Swift コンパイラである LLDB の式評価器に依存します。型情報を理解するには、Swift モジュールをインポートする必要があります。

(11:12) Xcode 14 以降、LLDB のデバッガー側とコンパイラー側は明確に分離されています。

  • デバッガー側: デバッグ情報と Swift リフレクション メタデータから型を取得し、変数ビューを駆動し、v注文
  • コンパイラ側: Swift モジュール、ドライバーから型を取得exprppo注文

ここで変数ビューが機能しますが、poエラーの理由 - モジュールのインポートが失敗しました。

(11:38) Xcode 14 の新機能swift-healthcheckコマンドを使用して、式エバリュエーターで構成の問題を診断します。実行後、LLDB が TerminalInterface フレームワークの内部実装の詳細である「ターミナル UI」モジュールをインポートできないことがわかりました。

静的ライブラリと Swift モジュール

(14:53) 問題の根本は、フレームワークが静的ライブラリを使用しており、静的ライブラリの Swift モジュールがリンカーに登録されていないことです。動的ライブラリと実行可能ファイルはこの登録を自動的に完了しますが、静的ライブラリは単なるオブジェクト ファイルのコレクションであるため、それらをリンクするターゲットによって手動で登録する必要があります。

Apple リンカーを使用する場合は、次のように渡す必要があります。-add_ast_pathSwift モジュールを登録するオプション:

ld … -add_ast_path /path/to/My.swiftmodule

(15:57) 登録が成功したかどうかを確認します。

dsymutil -s MyApp | grep .swiftmodule

(16:08) Linux プラットフォームでは、次を使用できます。-modulewrapSwift モジュールをオブジェクト ファイルに変換し、バイナリにリンクします。

swiftc -modulewrap My.swiftmodule -o My.swiftmodule.o

修復されたフレームワークはこのモジュールを再登録しました。poシングルステップトラッキングは通常に戻ります。

詳細

Source Path Remapping

(06:37) コードがリモート サーバーまたは CI システム上でビルドされる場合、デバッグ情報のソース ファイル パスがローカル パスと一致しません。 LLDBtarget.source-map設定により、これらのパスを再マップできます。

Xcodeで設定する.lldbinit

  1. [製品] > [スキーム] > [スキームの編集] を開きます。
  2. [診断] タブで LLDB 初期化ファイルのパスを指定します。
  3. ファイルに次のように書き込みます。
settings set target.source-map /Volumes/BUILD_SERVER/projects /Users/demo/Desktop/Adventure/3rdparty

キーポイント:

  • settings set target.source-map2 つのパラメータを受け入れます: 古いパス プレフィックスと新しいパス プレフィックス
  • プロジェクトに保存された設定.lldbinitファイルに保存すると、各デバッグが自動的に有効になります
  • .dSYM バンドルの plist ファイルでのパス マッピング ディクショナリの設定もサポート

(08:13) より徹底的なアプローチは、次のように使用することです。-debug-prefix-map、マシン依存のパス接頭辞を統一のプレースホルダーに置き換えます。

swiftc -debug-prefix-map $PWD=/BUILDROOT ...

この方法では、すべてのビルド マシンが同じプレースホルダー パスを使用するため、LLDB でマッピングを 1 回構成するだけで済みます。

LLDB 式評価器の診断

(11:59)poまたはpコマンドが失敗した場合は、次を実行します。

swift-healthcheck

このコマンドは、Swift 式エバリュエーターの構成ログを出力し、モジュールのインポートの失敗などの問題を特定するのに役立ちます。

変数表示コマンドの違い

(08:32) LLDB には変数を表示するための複数のコマンドが用意されており、その背後にあるメカニズムは異なります。

# オブジェクトの説明を出力(description/debugDescription を呼び出す)
po words
expr -O -- words

# 式を評価(コンパイラー側)
p words
expr words

# 変数を表示(デバッガー側、コンパイルしない)
v words
frame variable words

キーポイント:

  • poそしてpコンパイラ側の式評価器に依存しており、完全な Swift モジュールが必要です
  • vモジュールのインポートに依存せずに、デバッグ情報から変数値を直接読み取ります
  • いつpo失敗しましたがv通常、問題はモジュールのインポート リンクにあるはずです。

スタティックライブラリのSwiftモジュール登録

(15:47) カスタム ビルド システムの場合は、静的ライブラリの Swift モジュールが正しく登録されていることを確認してください。

# リンク時に Swift module を登録
ld -o MyApp main.o -add_ast_path /path/to/My.swiftmodule

# 登録が成功したかを検証
dsymutil -s MyApp | grep .swiftmodule

キーポイント:

  • ダイナミック ライブラリと実行可能ファイルのビルド システムは、Swift モジュールを自動的に登録します。
  • 静的ライブラリはリンカを経由しないため、リンク先を手動で登録する必要があります
  • 通常、Xcode はこれを自動的に処理しますが、カスタム ビルド ルールには注意が必要です

シリアル化デバッグ オプションを回避する

(18:23) Swift コンパイラは、Clang ヘッダー検索パスをバイナリ .swiftmodule ファイルにシリアル化します。 This can cause problems when debugging across machines.

コマンドラインの無効化:

swiftc -no-serialize-debugging-options ...

Xcode で設定します。

SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO

無効化した後は、LLDB で検索パスを手動構成できます。

settings set target.swift-extra-clang-flags ...
settings set target.swift-framework-search-paths ...
settings set target.swift-module-search-paths ...

重要ポイント

  • やるべきこと: CI/CD ビルドフローに自動化された debug 成果物の配布を構成する

  • 実行する価値がある理由: 開発チームはローカルで再コンパイルせずに、CI がビルドした成果物を直接デバッグできます

  • 開始方法: ビルド スクリプトで使用します-debug-prefix-map統一されたパス、調整.lldbinittarget.source-map設定

  • やるべきこと: module インポートの問題を自動検出して修正する LLDB デバッグ補助ツールを構築する

  • 実行する価値がある理由:swift-healthcheck は診断情報を提供するため、それを土台により使いやすい診断インターフェイスを構築できます

  • 開始方法: 分析swift-healthcheck出力は一般的なモジュール パスの問題を検出し、修復ソリューションを自動的に推奨します。

  • 内容: サードパーティのバイナリ フレームワーク用の完全なデバッグ サポート パッケージを提供します。

  • 実行する価値がある理由: フレームワークを統合する開発者がトレースと式の評価を段階的に実行できるようにします。

  • 開始方法: 静的ライブラリの Swift モジュールが-add_ast_pathで登録されていることを確認し、代替として.swiftinterfaceを提供します

  • やるべきこと: Xcode プロジェクトでチーム共有を構成する.lldbinit

  • 実行する価値がある理由: チームのデバッグ環境構成を統一して、全員がソース マップを手動で設定することを回避します。

  • 開始方法: Scheme の [Diagnostics] タブでプロジェクト レベルの LLDB Init ファイルを指定します。

関連セッション

コメント

GitHub Issues · utterances