Zxdb 提供指令碼支援,可自動執行重複的偵錯工作、跳至特定應用程式狀態,以及自動驗證偵錯工具行為。指令碼是純文字檔案,內含一系列 zxdb 指令及其預期輸出內容。
執行指令碼
如要在啟動 zxdb 時從指令列執行指令碼,請使用 -S 或 --script-file 選項。
- 使用
ffx debug:
ffx debug connect -- --script-file=my_script.script- 或直接使用
zxdb(請注意,這只適用於離線核心檔案 (例如小型傾印),因此您的指令碼應先使用opendump指令載入核心檔案。詳情請參閱help opendump。
zxdb --script-file=my_script.script指令碼語法
系統會逐行評估指令碼,通常會交替輸入指令和比對輸出內容的行。
指令
開頭為 [zxdb] 的行會解譯為要執行的指令。這些指令的執行方式與在互動式 zxdb 控制台中相同。
[zxdb] attach my_component.cm
你可以使用縮寫和任何標準 zxdb 功能:
[zxdb] t * f
這等同於:
[zxdb] thread * frame
輸出比對
如果某行不是以 [zxdb] 開頭,也不是註解,系統會將其視為模式,用來比對先前執行指令的輸出內容。
由於 zxdb 中的許多指令都是非同步,因此偵錯工具必須知道指令何時實際完成輸出,才能發出下一個指令。Zxdb 會等待輸出內容與指定行相符,再繼續執行下一個指令。這可確保指令碼與偵錯工具的非同步事件保持同步。
[zxdb] attach cobalt.cm
Attached Process
Done.
如果您不在意指令的輸出內容,就不需要指定任何相符的行。您可以編寫下一個 [zxdb] 指令,系統會允許先前的指令立即完成。
如果指令有任何依附元件,可能會導致結果不穩定。例如:
[zxdb] b $main
Created Breakpoint 1 @ $main
[zxdb] run-component fuchsia-pkg://fuchsia.com/zxdb_e2e_inferiors#meta/async_rust_multithreaded.cm
Launched Process 1 state=Running koid=?? name=async_rust_multithreaded.cm component=async_rust_multithreaded.cm
🛑
[zxdb] until foo
# This might lead to flaky results
[zxdb] thread
thread 的結果可以是
▶ 7 #[fasync::run(2)]
8 async fn main() {
9 let _task_a = fasync::Task::spawn(async {});
🛑 on bp 1 async_rust_multithreaded::main() • async_rust_multithreaded.rs:7
[zxdb] until foo
[zxdb] thread
# state koid name
▶ 1 Blocked (Futex) 24769196 initial-thread
2 Blocked (Port) 24769684 executor_worker
3 Blocked (Port) 24769691 executor_worker
19 }
20
▶ 21 async fn foo(i: u64) {
22 fasync::Timer::new(std::time::Duration::from_secs(i)).await;
23 }
或
▶ 7 #[fasync::run(2)]
8 async fn main() {
9 let _task_a = fasync::Task::spawn(async {});
🛑 on bp 1 async_rust_multithreaded::main() • async_rust_multithreaded.rs:7
[zxdb] until foo
19 }
20
▶ 21 async fn foo(i: u64) {
22 fasync::Timer::new(std::time::Duration::from_secs(i)).await;
23 }
🛑 thread 2 async_rust_multithreaded::foo(u64) • async_rust_multithreaded.rs:21
[zxdb] thread
# state koid name
1 Suspended 24775467 initial-thread
▶ 2 Blocked (Exception) 24775973 executor_worker
3 Suspended 24775980 executor_worker
您可以手動快速輸入指令,或使用指令碼執行元件重現此問題。
這是因為 until 和 thread 指令會同時執行。為避免不穩定,建議使用暫停符號 (🛑) 做為預期輸出內容。例如:
[zxdb] until foo
🛑
[zxdb] thread
萬用字元
如果只想比對部分行,或某行包含無法預測的資料 (例如記憶體位址、程序 ID 或檔案路徑),可以使用 ?? 萬用字元。比對行的任意部分 (最多可比對整行)。
[zxdb] frame
▶ 0 MyFunction() • my_file.cc:??
留言
以 # 開頭的行是註解,系統會忽略。註解可用於記錄指令碼,但請注意,註解也支援 UTF-8 字元。
# This is a comment explaining what the next command does.
[zxdb] pause
# Wait for the stop event
🛑
輸出內容順序錯誤
根據預設,指令碼會預期輸出行會以指定的確切順序抵達。如果指令產生的輸出內容順序不確定,您可以在預期輸出內容的區塊中加入 ## allow-out-of-order-output。這樣可確保所有指定行都相符,無論列印順序為何。這項指令必須緊接在 zxdb 指令列之後,且在任何預期輸出內容之前,才能正確納入所有輸出內容,供比對演算法使用。
[zxdb] thread
## allow-out-of-order-output
1 State: Running
2 State: Suspended
結束指令碼
指令碼完成後,系統會自動將您帶入互動式 [zxdb] 指令列。
如果您希望 zxdb 在指令碼結束時自動退出,可以在檔案結尾附加 quit 指令。不過,請確保先前的指令有相符的指定輸出內容,否則 quit 可能會在先前的指令完成前執行。
[zxdb] quit --force
範例
擷取非同步回溯
這個指令碼會附加至元件、暫停元件、列印非同步回溯追蹤,並讓您在互動式控制台中進一步調查。
# Attach to the component
[zxdb] attach hwinfo.cm
Attached Process
Done.
# Pause execution
[zxdb] pause
🛑
# Output the tree of async tasks.
[zxdb] async-backtrace
列印所有執行緒的影格
這個指令碼會附加至元件、等待元件停止運作、列印所有執行緒的回溯追蹤,然後進入互動式控制台。
[zxdb] attach cobalt.cm
Attached Process
Done.
[zxdb] pause
🛑
# Output the backtraces of all threads of the current process.
[zxdb] thread * frame