| # Tutorial: Debug minidumps using zxdb | |
| A minidump is a memory dump of a process at the time of a crash, which can be | |
| useful to debug the cause of a crash. | |
| This tutorial walks through a debugging workflow that loads a minidump file into | |
| zxdb and then walks through debugging steps to understand the failure captured | |
| by the minidump. | |
| ## Capturing a minidump file {:#capturing-minidump .numbered} | |
| Minidumps can be captured from any debugging session in zxdb with the `savedump` | |
| command. | |
| For example, if you are using zxdb on the `cobalt.cm` component: | |
| ```posix-terminal | |
| ffx component debug cobalt.cm | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Waiting for process matching "job 20999". | |
| Type "filter" to see the current filters. | |
| 👉 To get started, try "status" or "help". | |
| Attached Process 1 state=Running koid=21246 name=cobalt.cm component=cobalt.cm | |
| Loading 15 modules for cobalt.cm ...Done. | |
| ``` | |
| If you wanted to capture a minidump, you would first `pause` the debugger: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| pause | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| 508 const zx_port_packet_t* packet)) | |
| 509 | |
| â–¶ 510 BLOCKING_SYSCALL(port_wait, zx_status_t, /* no attributes */, 3, (handle, deadline, packet), | |
| 511 (_ZX_SYSCALL_ANNO(use_handle("Fuchsia")) zx_handle_t handle, zx_time_t deadline, | |
| 512 zx_port_packet_t* packet)) | |
| 🛑 thread 1 $elf(SYSCALL_zx_port_wait) + 0x7 • syscalls.inc:510 | |
| ``` | |
| Use `savedump` to save a minidump: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| savedump cobalt.dump | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Saving minidump... | |
| Minidump written to cobalt.dump | |
| ``` | |
| Once you have saved the minidump, you can exit the debugger: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| quit | |
| ``` | |
| Your minidump is now saved in your working directory. You are now ready to load | |
| the minidump file and debug it. | |
| ## Loading and debugging a minidump file {:#loading-minidump .numbered} | |
| Loading and debugging a minidump file in zxdb is the same regardless of the | |
| language of the component that you are trying to debug. However, there are some | |
| differences about things to look out for in each language. | |
| * {Rust} | |
| 1. To load the minidump file into zxdb, you can use `ffx debug core`. For | |
| example, to load a minidump file named `archivist_unittest.dump`: | |
| Note: This minidump was captured from a rust unittest with | |
| `fx test --breakpoint=`. For more information, see | |
| [Basic test debugging][basic-test-debugging]. | |
| ```posix-terminal | |
| ffx debug core archivist_unittest.dump | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Opening dump file... | |
| Dump loaded successfully. | |
| 👉 To get started, try "status" or "help". | |
| Attached Process 1 state=Running koid=14446435 name=<_> | |
| Loading 6 modules for <_> Downloading symbols... | |
| Done. | |
| 🛑 (no location information) | |
| Attached Process 2 state=Running koid=14446435 name=<_> | |
| Attaching to previously connected processes: | |
| 14446435: <_> | |
| Loading 6 modules for <_> Done. | |
| Symbol downloading complete. 5 succeeded, 0 failed. | |
| ``` | |
| 1. List the stack frames: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy}\ | |
| ▶ 0 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::test_entry_point::λ(…) • archivist.rs:547 | |
| 1 core::future::future::«impl»::poll<…>(…) • future/future.rs:123 | |
| 2 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:27 | |
| 3 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:122 | |
| 4 fuchsia_async::atomic_future::«impl»::poll<…>(…) • atomic_future.rs:72 | |
| 5 fuchsia_async::atomic_future::AtomicFuture::try_poll(…) • atomic_future.rs:230 | |
| 6 fuchsia_async::runtime::fuchsia::executor::common::Executor::try_poll(…) • executor/common.rs:554 | |
| 7 fuchsia_async::runtime::fuchsia::executor::common::Executor::poll_ready_tasks(…) • executor/common.rs:133 | |
| 8 fuchsia_async::runtime::fuchsia::executor::common::Executor::worker_lifecycle<…>(…) • executor/common.rs:429 | |
| 9 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run<…>(…) • executor/local.rs:104 | |
| 10 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run_singlethreaded<…>(…) • executor/local.rs:70 | |
| 11 fuchsia_async::test_support::«impl»::run_singlethreaded::λ() • test_support.rs:120 | |
| 12 fuchsia_async::test_support::Config::in_parallel(…) • test_support.rs:215 | |
| 13 fuchsia_async::test_support::«impl»::run_singlethreaded(…) • test_support.rs:117 | |
| 14 fuchsia_async::test_support::run_singlethreaded_test<…>(…) • test_support.rs:227 | |
| 15 fuchsia::test_singlethreaded<…>(…) • fuchsia/src/lib.rs:195 | |
| 16 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log() • archivist.rs:524 | |
| 17 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::λ(…) • archivist.rs:525 | |
| 18 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| 19 core::ops::function::FnOnce::call_once<…>(…) • library/core/src/ops/function.rs:250 (inline) | |
| 20 test::__rust_begin_short_backtrace<…>(…) • library/test/src/lib.rs:625 | |
| 21 test::run_test_in_spawned_subprocess(…) • library/test/src/lib.rs:753 | |
| 22 test::test_main_static_abort(…) • library/test/src/lib.rs:199 | |
| 23 archivist_lib_lib_test::main() • archivist/src/lib.rs:1 | |
| 24 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| 25 std::sys::backtrace::__rust_begin_short_backtrace<…>(…) • fuchsia-third_party-rust/library/std/src/sys/backtrace.rs:155 | |
| 26 std::rt::lang_start::λ() • fuchsia-third_party-rust/library/std/src/rt.rs:159 | |
| 27 core::ops::function::impls::«impl»::call_once<…>(…) • library/core/src/ops/function.rs:284 (inline) | |
| 28 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| 29 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 30 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 31 std::rt::lang_start_internal::λ() • library/std/src/rt.rs:141 (inline) | |
| 32 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| 33 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 34 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 35 std::rt::lang_start_internal(…) • library/std/src/rt.rs:141 | |
| 36 std::rt::lang_start<…>(…) • fuchsia-third_party-rust/library/std/src/rt.rs:158 | |
| 37 $elf(main) + 0x21 | |
| 38…40 «libc startup» (-r expands) | |
| ``` | |
| 1. You can now use shortcuts to quickly perform actions across all threads. | |
| Note: The wildcard operator (`*`) performs an action for all threads. You | |
| can use both nouns and verbs with this operator. Commands from the `Step` | |
| section of the help menu are not available because this isn't a real process. | |
| List the frames of each thread: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread * frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=14450503 name="" | |
| ▶ 0 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::test_entry_point::λ(…) • archivist.rs:547 | |
| ``` | |
| 1. List the frames of each thread, but with more detailed information, | |
| you can combine `thread` with the `backtrace` verb: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread * backtrace | |
| ``` | |
| This command helps you see the local variables for each stack frame. Keep | |
| in mind that only the stack memory is captured in the minidump to improve | |
| the capturing time and size. Pointers to heap variables mostly do not | |
| resolve to anything useful. | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=14450503 name="" | |
| ▶ 0 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::test_entry_point::λ(…) • archivist.rs:547 | |
| (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 1 core::future::future::«impl»::poll<…>(…) • future/future.rs:123 | |
| self = Pin<&mut core::pin::Pin<alloc…>{__pointer: (*)0xa2987a4580} | |
| cx = (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 2 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:27 | |
| (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 3 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:122 | |
| (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 4 fuchsia_async::atomic_future::«impl»::poll<…>(…) • atomic_future.rs:72 | |
| self = (*)0xa2987a4520 | |
| cx = (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 5 fuchsia_async::atomic_future::AtomicFuture::try_poll(…) • atomic_future.rs:230 | |
| self = (*)0x9d587a4118 | |
| cx = (*)0x5c626904e0 ➔ Context{waker: (*)0x5c626904c8, local_waker: (*)0x5c626904c8, ext: AssertUnwindSafe<core::task::wake::ExtData>(…), _marker: PhantomData<fn(&())->&()>, _marker2: PhantomData<*mut()>} | |
| 6 fuchsia_async::runtime::fuchsia::executor::common::Executor::try_poll(…) • executor/common.rs:554 | |
| self = (*)0x9b187a9300 | |
| task = (*)0x5c62690588 âž” (*)0x9d587a40f0 | |
| 7 fuchsia_async::runtime::fuchsia::executor::common::Executor::poll_ready_tasks(…) • executor/common.rs:133 | |
| self = (*)0x9b187a9300 | |
| local_collector = (*)0x5c62690600 âž” LocalCollector{collector: (*)0x9b187a9438, last_ticks: 1050997948718604, polls: 1, tasks_pending_max: 10} | |
| 8 fuchsia_async::runtime::fuchsia::executor::common::Executor::worker_lifecycle<…>(…) • executor/common.rs:429 | |
| self = (*)0xa4187a90a0 | |
| 9 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run<…>(…) • executor/local.rs:104 | |
| self = (*)0x5c62690878 ➔ LocalExecutor{ehandle: EHandle{…}} | |
| main_future = AtomicFuture{state: AtomicUsize{1}, future: UnsafeCell{$(alloc::boxed::Box<dyn fuchsia_async::atomic_future::FutureOrResultAccess, alloc::alloc::Global>){…}}} | |
| 10 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run_singlethreaded<…>(…) • executor/local.rs:70 | |
| self = (*)0x5c62690878 ➔ LocalExecutor{ehandle: EHandle{…}} | |
| main_future = Unresumed{run_stream: (*)0xa3187a86a0, test: λ{…}} | |
| 11 fuchsia_async::test_support::«impl»::run_singlethreaded::λ() • test_support.rs:120 | |
| 12 fuchsia_async::test_support::Config::in_parallel(…) • test_support.rs:215 | |
| self = (*)0x5c62690ae8 ➔ Config{repeat_count: 1, max_concurrency: 0, max_threads: 0, timeout: …} | |
| f = <The value of type '*const alloc::sync::ArcInner<(dyn core::ops::function::Fn<(), Output=()> + core::marker::Send + core::marker::Sync)>' is the incorrect size (expecting 8, got 16). Please file a bug.> | |
| 13 fuchsia_async::test_support::«impl»::run_singlethreaded(…) • test_support.rs:117 | |
| test = <The value of type '*const alloc::sync::ArcInner<(dyn core::ops::function::Fn<(usize), Output=core::pin::Pin<alloc::boxed::Box<dyn core::future::future::Future<Output=()>, alloc::alloc::Global>>> + core::marker::Send + core::marker::Sync)>' is the incorrect size (expecting 8, got 16). Please file a bug.> | |
| cfg = Config{repeat_count: 1, max_concurrency: 0, max_threads: 0, timeout: None<Duration>} | |
| 14 fuchsia_async::test_support::run_singlethreaded_test<…>(…) • test_support.rs:227 | |
| test = <Unavailable> | |
| 15 fuchsia::test_singlethreaded<…>(…) • fuchsia/src/lib.rs:195 | |
| f = <Register rdi not available.> | |
| 16 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log() • archivist.rs:524 | |
| 17 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::λ(…) • archivist.rs:525 | |
| (*)0x5c62690bde ➔ λ | |
| 18 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| λ | |
| <Value has no data.> | |
| 19 core::ops::function::FnOnce::call_once<…>(…) • library/core/src/ops/function.rs:250 (inline) | |
| <Register rsi not available.> | |
| <Optimized out> | |
| 20 test::__rust_begin_short_backtrace<…>(…) • library/test/src/lib.rs:625 | |
| f = <Register rsi not available.> | |
| 21 test::run_test_in_spawned_subprocess(…) • library/test/src/lib.rs:753 | |
| desc = <Register rdi not available.> | |
| runnable_test = Static(&core::ops::function::FnOnce::call_once<archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::{closure_env#0}, ()>) | |
| 22 test::test_main_static_abort(…) • library/test/src/lib.rs:199 | |
| tests = <Unavailable> | |
| 23 archivist_lib_lib_test::main() • archivist/src/lib.rs:1 | |
| 24 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| &archivist_lib_lib_test::main | |
| <Value has no data.> | |
| 25 std::sys::backtrace::__rust_begin_short_backtrace<…>(…) • fuchsia-third_party-rust/library/std/src/sys/backtrace.rs:155 | |
| f = &archivist_lib_lib_test::main | |
| 26 std::rt::lang_start::λ() • fuchsia-third_party-rust/library/std/src/rt.rs:159 | |
| 27 core::ops::function::impls::«impl»::call_once<…>(…) • library/core/src/ops/function.rs:284 (inline) | |
| self = $(&(dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)){pointer: (*)0x5c62690f50 âž” $((dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)), vtable = <Invalid data offset 8 in object of size 8.>} | |
| args = <Optimized out> | |
| 28 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| data = <Optimized out> | |
| 29 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 30 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 31 std::rt::lang_start_internal::λ() • library/std/src/rt.rs:141 (inline) | |
| 32 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| data = <Optimized out> | |
| 33 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 34 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 35 std::rt::lang_start_internal(…) • library/std/src/rt.rs:141 | |
| main = $(&(dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)){pointer: (*)0x5c62690f50 âž” $((dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)), vtable: (*)0x13a66000958} | |
| argc = <Register rdx not available.> | |
| argv = <Register rcx not available.> | |
| sigpipe = <Register r8 not available.> | |
| 36 std::rt::lang_start<…>(…) • fuchsia-third_party-rust/library/std/src/rt.rs:158 | |
| main = &archivist_lib_lib_test::main | |
| argc = 2 | |
| argv = (*)0xecf9d19fb0 | |
| sigpipe = 0 | |
| 37 $elf(main) + 0x21 | |
| 38…40 «libc startup» (-r expands) | |
| ``` | |
| 1. List the current threads: | |
| Note: You can also use any of the regular zxdb thread and frame commands. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| # state koid name | |
| â–¶ 1 Core Dump 14450503 | |
| ``` | |
| 1. List a specific thread. For example, `thread 1`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread 1 | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=14450503 name="" | |
| ``` | |
| 1. You can then use `frame` to see this specific stack frame from `thread 1`: | |
| Note: As this component ran on a single thread, this output is The | |
| same as when you ran `frame` after loading the minidump into zxdb. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| ▶ 0 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::test_entry_point::λ(…) • archivist.rs:547 | |
| 1 core::future::future::«impl»::poll<…>(…) • future/future.rs:123 | |
| 2 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:27 | |
| 3 fuchsia_async::test_support::«impl»::run_singlethreaded::λ::λ(…) • test_support.rs:122 | |
| 4 fuchsia_async::atomic_future::«impl»::poll<…>(…) • atomic_future.rs:72 | |
| 5 fuchsia_async::atomic_future::AtomicFuture::try_poll(…) • atomic_future.rs:230 | |
| 6 fuchsia_async::runtime::fuchsia::executor::common::Executor::try_poll(…) • executor/common.rs:554 | |
| 7 fuchsia_async::runtime::fuchsia::executor::common::Executor::poll_ready_tasks(…) • executor/common.rs:133 | |
| 8 fuchsia_async::runtime::fuchsia::executor::common::Executor::worker_lifecycle<…>(…) • executor/common.rs:429 | |
| 9 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run<…>(…) • executor/local.rs:104 | |
| 10 fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run_singlethreaded<…>(…) • executor/local.rs:70 | |
| 11 fuchsia_async::test_support::«impl»::run_singlethreaded::λ() • test_support.rs:120 | |
| 12 fuchsia_async::test_support::Config::in_parallel(…) • test_support.rs:215 | |
| 13 fuchsia_async::test_support::«impl»::run_singlethreaded(…) • test_support.rs:117 | |
| 14 fuchsia_async::test_support::run_singlethreaded_test<…>(…) • test_support.rs:227 | |
| 15 fuchsia::test_singlethreaded<…>(…) • fuchsia/src/lib.rs:195 | |
| 16 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log() • archivist.rs:524 | |
| 17 archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::λ(…) • archivist.rs:525 | |
| 18 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| 19 core::ops::function::FnOnce::call_once<…>(…) • library/core/src/ops/function.rs:250 (inline) | |
| 20 test::__rust_begin_short_backtrace<…>(…) • library/test/src/lib.rs:625 | |
| 21 test::run_test_in_spawned_subprocess(…) • library/test/src/lib.rs:753 | |
| 22 test::test_main_static_abort(…) • library/test/src/lib.rs:199 | |
| 23 archivist_lib_lib_test::main() • archivist/src/lib.rs:1 | |
| 24 core::ops::function::FnOnce::call_once<…>(…) • fuchsia-third_party-rust/library/core/src/ops/function.rs:250 | |
| 25 std::sys::backtrace::__rust_begin_short_backtrace<…>(…) • fuchsia-third_party-rust/library/std/src/sys/backtrace.rs:155 | |
| 26 std::rt::lang_start::λ() • fuchsia-third_party-rust/library/std/src/rt.rs:159 | |
| 27 core::ops::function::impls::«impl»::call_once<…>(…) • library/core/src/ops/function.rs:284 (inline) | |
| 28 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| 29 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 30 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 31 std::rt::lang_start_internal::λ() • library/std/src/rt.rs:141 (inline) | |
| 32 std::panicking::try::do_call<…>(…) • library/std/src/panicking.rs:553 (inline) | |
| 33 std::panicking::try<…>() • library/std/src/panicking.rs:517 (inline) | |
| 34 std::panic::catch_unwind<…>() • library/std/src/panic.rs:350 (inline) | |
| 35 std::rt::lang_start_internal(…) • library/std/src/rt.rs:141 | |
| 36 std::rt::lang_start<…>(…) • fuchsia-third_party-rust/library/std/src/rt.rs:158 | |
| 37 $elf(main) + 0x21 | |
| 38…40 «libc startup» (-r expands) | |
| ``` | |
| 1. Based on the output from the previous step, you may want to dive deeper | |
| into `frame 0`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame 0 | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| archivist_lib_lib_test::archivist::tests::can_log_and_retrieve_log::test_entry_point::λ(…) • archivist.rs:547 | |
| ``` | |
| 1. To see additional lines of code from the current frame, use `list`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| 542 | |
| 543 let mut expected = vec!["my msg1".to_owned(), "my msg2".to_owned()]; | |
| 544 expected.sort(); | |
| 545 | |
| 546 let mut actual = vec![recv_logs.next().await.unwrap(), recv_logs.next().await.unwrap()]; | |
| â–¶ 547 actual.sort(); | |
| 548 | |
| 549 assert_eq!(expected, actual); | |
| 550 | |
| 551 // can log after killing log sink proxy | |
| 552 log_helper.kill_log_sink(); | |
| 553 log_helper.write_log("my msg1"); | |
| 554 log_helper.write_log("my msg2"); | |
| 555 | |
| 556 assert_eq!( | |
| 557 expected, | |
| ``` | |
| Since this frame actually contains some archivist code, you can use | |
| `locals` to see the local variables in this stack frame. | |
| 1. To see all local variables in the current stack frame, use `locals`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| locals | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| _task_context = (*)0x5c626904e0 âž” Context{ | |
| waker: (*)0x5c626904c8 | |
| local_waker: (*)0x5c626904c8 | |
| ext: AssertUnwindSafe<core::task::wake::ExtData>(None(<Value has no data.>)) | |
| _marker: PhantomData<fn(&())->&()> | |
| _marker2: PhantomData<*mut()> | |
| } | |
| actual = <Invalid pointer 0x9c187a04e8> | |
| directory = <Invalid pointer 0x9c187a0460> | |
| expected = <Invalid pointer 0x9c187a04d0> | |
| log_helper = <Invalid pointer 0x9c187a0470> | |
| log_helper2 = <Invalid pointer 0x9c187a04c0> | |
| recv_logs = <Invalid pointer 0x9c187a0468> | |
| ``` | |
| You can then see more information about a specific variable with `print`. | |
| For example: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| print _task_context | |
| ``` | |
| You should see an output like: | |
| Note: The `(*)` indicates that the variable is a pointer. | |
| ```none {:.devsite-disable-click-to-copy} | |
| (*)0x5c626904e0 âž” Context{ | |
| waker: (*)0x5c626904c8 | |
| local_waker: (*)0x5c626904c8 | |
| ext: AssertUnwindSafe<core::task::wake::ExtData>(None(<Value has no data.>)) | |
| _marker: PhantomData<fn(&())->&()> | |
| _marker2: PhantomData<*mut()> | |
| } | |
| ``` | |
| You have successfully loaded and analyzed a minidump for Rust code. | |
| * {C++} | |
| 1. To load the minidump file into zxdb, you can use `ffx debug core`. | |
| For example, to load a minidump file named `cobalt_minidump.dump`: | |
| ```posix-terminal | |
| ffx debug core cobalt_minidump.dump | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Opening dump file... | |
| Dump loaded successfully. | |
| 👉 To get started, try "status" or "help". | |
| Attached Process 1 state=Running koid=15650768 name=<_> | |
| Loading 15 modules for <_> ...Done. | |
| Attached Process 2 state=Running koid=15650768 name=<_> | |
| Attaching to previously connected processes: | |
| 15650768: <_> | |
| Loading 15 modules for <_> Done. | |
| ``` | |
| Now that you have loaded the minidump file, you can now inspect the stacks | |
| for all threads present that were present when the minidump was captured. | |
| 1. List the stack frames: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| ▶ 0…4 «Waiting for event in async::Loop::Run()» (-r expands) | |
| 5 main(…) • cobalt_main.cc:349 | |
| 6…8 «libc startup» (-r expands) | |
| ``` | |
| 1. You can now use shortcuts to quickly perform actions across all threads: | |
| Note: The wildcard operator (`*`) performs an action for all threads. You | |
| can use both nouns and verbs with this operator. Commands from the `Step` | |
| section of the help menu are not available because this isn't a real process. | |
| List the frames of each thread: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread * frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=19601 name="" | |
| ▶ 0…4 «Waiting for event in async::Loop::Run()» (-r expands) | |
| 5 main(…) • cobalt_main.cc:349 | |
| 6…8 «libc startup» (-r expands) | |
| Thread 2 state="Core Dump" koid=26944 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| 5 std::__2::__libcpp_condvar_timedwait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:127 (inline) | |
| 6 std::__2::condition_variable::__do_timed_wait(…) • condition_variable.cpp:54 | |
| 7 std::__2::condition_variable::wait_for<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:196 | |
| 8 std::__2::condition_variable::__do_timed_wait<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:235 | |
| 9 std::__2::condition_variable::wait_until<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:161 | |
| 10 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:240 | |
| 11 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:247 | |
| 12 std::__2::condition_variable_any::wait_for<…>(…) • condition_variable:260 | |
| 13 cobalt::local_aggregation::DelayedLocalAggregateStorage::Run(…) • delayed_local_aggregate_storage.cc:200 | |
| 14 λ(…) • delayed_local_aggregate_storage.cc:45 | |
| 15 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| 16 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| 17 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| 18…19 «pthread startup» (-r expands) | |
| Thread 3 state="Core Dump" koid=26975 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| 5 std::__2::__libcpp_condvar_wait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:122 (inline) | |
| 6 std::__2::condition_variable::wait(…) • condition_variable.cpp:30 | |
| 7 std::__2::condition_variable_any::wait<…>(…) • condition_variable:225 | |
| 8 std::__2::condition_variable_any::wait<…>(…) • condition_variable:231 | |
| 9 cobalt::uploader::ShippingManager::Run(…) • shipping_manager.cc:217 | |
| 10 λ(…) • shipping_manager.cc:76 | |
| 11 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| 12 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| 13 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| 14…15 «pthread startup» (-r expands) | |
| Thread 4 state="Core Dump" koid=26983 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| 5 std::__2::__libcpp_condvar_timedwait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:127 (inline) | |
| 6 std::__2::condition_variable::__do_timed_wait(…) • condition_variable.cpp:54 | |
| 7 std::__2::condition_variable::wait_for<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:196 | |
| 8 std::__2::condition_variable::__do_timed_wait<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:235 | |
| 9 std::__2::condition_variable::wait_until<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:161 | |
| 10 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:240 | |
| 11 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:247 | |
| 12 cobalt::local_aggregation::ObservationGenerator::Run(…) • observation_generator.cc:92 | |
| 13 λ(…) • observation_generator.cc:65 | |
| 14 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| 15 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| 16 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| 17…18 «pthread startup» (-r expands) | |
| ``` | |
| 1. To list the frames of each thread, but with more detailed information, | |
| you can combine `thread` with the `backtrace` verb: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread * backtrace | |
| ``` | |
| This command helps you see the local variables for each stack frame. Keep | |
| in mind that only the stack memory is captured in the minidump to improve | |
| the capturing time and size. Pointers to heap variables mostly do not | |
| resolve to anything useful, these have a format like | |
| `<Invalid pointer 0x285f3fd5a18>`. | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=19601 name="" | |
| ▶ 0…4 «Waiting for event in async::Loop::Run()» (-r expands) | |
| 5 main(…) • cobalt_main.cc:349 | |
| argc = 2 | |
| argv = (*)0x26866821fc0 | |
| 6…8 «libc startup» (-r expands) | |
| Thread 2 state="Core Dump" koid=26944 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| value_ptr = (*)0x285f3fd5904 | |
| current_value = 2 | |
| new_futex_owner = 0 | |
| deadline = 612921722073211 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| futex = <Register rdi not available.> | |
| val = <Register rsi not available.> | |
| clk = <Register rdx not available.> | |
| at = <Register rcx not available.> | |
| new_owner = <Register r8 not available.> | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| futex = (*)0x285f3fd5904 | |
| val = 2 | |
| clk = 0 | |
| at = (*)0x285f3fd5918 | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| c = (*)0x370ff24ae20 | |
| m = (*)0x3707f2b76c8 | |
| ts = (*)0x285f3fd5918 | |
| 5 std::__2::__libcpp_condvar_timedwait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:127 (inline) | |
| __cv = <Register rdi not available.> | |
| __m = <Register rsi not available.> | |
| __ts = <Optimized out> | |
| 6 std::__2::condition_variable::__do_timed_wait(…) • condition_variable.cpp:54 | |
| this = <Register rdi not available.> | |
| lk = <Register rsi not available.> | |
| tp = <Register rdx not available.> | |
| 7 std::__2::condition_variable::wait_for<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:196 | |
| this = (*)0x370ff24ae20 | |
| __lk = <Invalid pointer 0x285f3fd5a18> | |
| __d = <Invalid pointer 0x285f3fd59a8> | |
| 8 std::__2::condition_variable::__do_timed_wait<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:235 | |
| this = (*)0x370ff24ae20 | |
| __lk = <Invalid pointer 0x285f3fd5a18> | |
| __tp = <Invalid pointer 0x285f3fd59b0> | |
| 9 std::__2::condition_variable::wait_until<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:161 | |
| this = (*)0x370ff24ae20 | |
| __lk = <Invalid pointer 0x285f3fd5a18> | |
| __t = <Invalid pointer 0x285f3fd5a60> | |
| 10 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:240 | |
| this = (*)0x370ff24ae20 | |
| __lock = <Invalid pointer 0x285f3fd5ab0> | |
| __t = <Invalid pointer 0x285f3fd5a60> | |
| 11 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:247 | |
| this = (*)0x370ff24ae20 | |
| __lock = <Invalid pointer 0x285f3fd5ab0> | |
| __t = <Invalid pointer 0x285f3fd5a60> | |
| __pred = <Invalid pointer 0x285f3fd5a40> | |
| 12 std::__2::condition_variable_any::wait_for<…>(…) • condition_variable:260 | |
| this = (*)0x370ff24ae20 | |
| __lock = <Invalid pointer 0x285f3fd5ab0> | |
| __d = <Invalid pointer 0x370ff24ae00> | |
| __pred = {locked_state = <Invalid pointer 0x285f3fd5ab0>} | |
| 13 cobalt::local_aggregation::DelayedLocalAggregateStorage::Run(…) • delayed_local_aggregate_storage.cc:200 | |
| this = (*)0x370ff24acf0 | |
| 14 λ(…) • delayed_local_aggregate_storage.cc:45 | |
| this = (*)0x36bff27b228 | |
| 15 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| __f = <Invalid pointer 0x36bff27b228> | |
| 16 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| __t = <Invalid pointer 0x36bff27b220> | |
| {} | |
| 17 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| __vp = (*)0x36bff27b220 | |
| 18…19 «pthread startup» (-r expands) | |
| Thread 3 state="Core Dump" koid=26975 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| value_ptr = (*)0x23b6ad77434 | |
| current_value = 2 | |
| new_futex_owner = 0 | |
| deadline = 9223372036854775807 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| futex = <Register rdi not available.> | |
| val = <Register rsi not available.> | |
| clk = <Register rdx not available.> | |
| at = <Register rcx not available.> | |
| new_owner = <Register r8 not available.> | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| futex = (*)0x23b6ad77434 | |
| val = 2 | |
| clk = 0 | |
| at = (*)0x0 | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| c = (*)0x3673f24a610 | |
| m = (*)0x3707f2b7998 | |
| ts = (*)0x0 | |
| 5 std::__2::__libcpp_condvar_wait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:122 (inline) | |
| __cv = <Register rdi not available.> | |
| __m = <Register rsi not available.> | |
| 6 std::__2::condition_variable::wait(…) • condition_variable.cpp:30 | |
| this = <Register rdi not available.> | |
| lk = <Register rsi not available.> | |
| 7 std::__2::condition_variable_any::wait<…>(…) • condition_variable:225 | |
| this = (*)0x3673f24a610 | |
| __lock = <Invalid pointer 0x23b6ad77608> | |
| 8 std::__2::condition_variable_any::wait<…>(…) • condition_variable:231 | |
| this = (*)0x3673f24a610 | |
| __lock = <Invalid pointer 0x23b6ad77608> | |
| __pred = <Invalid pointer 0x23b6ad77480> | |
| 9 cobalt::uploader::ShippingManager::Run(…) • shipping_manager.cc:217 | |
| this = (*)0x3673f24a530 | |
| 10 λ(…) • shipping_manager.cc:76 | |
| this = (*)0x36bff27a7a8 | |
| 11 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| __f = <Invalid pointer 0x36bff27a7a8> | |
| 12 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| __t = <Invalid pointer 0x36bff27a7a0> | |
| {} | |
| 13 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| __vp = (*)0x36bff27a7a0 | |
| 14…15 «pthread startup» (-r expands) | |
| Thread 4 state="Core Dump" koid=26983 name="" | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| value_ptr = (*)0x149c84b2bc4 | |
| current_value = 2 | |
| new_futex_owner = 0 | |
| deadline = 615784347537787 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| futex = <Register rdi not available.> | |
| val = <Register rsi not available.> | |
| clk = <Register rdx not available.> | |
| at = <Register rcx not available.> | |
| new_owner = <Register r8 not available.> | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| futex = (*)0x149c84b2bc4 | |
| val = 2 | |
| clk = 0 | |
| at = (*)0x149c84b2bd8 | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| c = (*)0x3673f24b128 | |
| m = (*)0x3707f2b6548 | |
| ts = (*)0x149c84b2bd8 | |
| 5 std::__2::__libcpp_condvar_timedwait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:127 (inline) | |
| __cv = <Register rdi not available.> | |
| __m = <Register rsi not available.> | |
| __ts = <Optimized out> | |
| 6 std::__2::condition_variable::__do_timed_wait(…) • condition_variable.cpp:54 | |
| this = <Register rdi not available.> | |
| lk = <Register rsi not available.> | |
| tp = <Register rdx not available.> | |
| 7 std::__2::condition_variable::wait_for<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:196 | |
| this = (*)0x3673f24b128 | |
| __lk = <Invalid pointer 0x149c84b2cd8> | |
| __d = <Invalid pointer 0x149c84b2c68> | |
| 8 std::__2::condition_variable::__do_timed_wait<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:235 | |
| this = (*)0x3673f24b128 | |
| __lk = <Invalid pointer 0x149c84b2cd8> | |
| __tp = <Invalid pointer 0x149c84b2c70> | |
| 9 std::__2::condition_variable::wait_until<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:161 | |
| this = (*)0x3673f24b128 | |
| __lk = <Invalid pointer 0x149c84b2cd8> | |
| __t = <Invalid pointer 0x3673f24b0d8> | |
| 10 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:240 | |
| this = (*)0x3673f24b128 | |
| __lock = <Invalid pointer 0x149c84b2d20> | |
| __t = <Invalid pointer 0x3673f24b0d8> | |
| 11 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:247 | |
| this = (*)0x3673f24b128 | |
| __lock = <Invalid pointer 0x149c84b2d20> | |
| __t = <Invalid pointer 0x3673f24b0d8> | |
| __pred = <Invalid pointer 0x149c84b2d00> | |
| 12 cobalt::local_aggregation::ObservationGenerator::Run(…) • observation_generator.cc:92 | |
| this = (*)0x3673f24b0a0 | |
| clock = (*)0x36bff27aaa0 | |
| 13 λ(…) • observation_generator.cc:65 | |
| this = (*)0x36bff24cf68 | |
| 14 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| __f = <Invalid pointer 0x36bff24cf68> | |
| 15 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| __t = <Invalid pointer 0x36bff24cf60> | |
| {} | |
| 16 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| __vp = (*)0x36bff24cf60 | |
| 17…18 «pthread startup» (-r expands) | |
| ``` | |
| 1. List the current threads: | |
| Note: You can also use any of the regular zxdb thread and frame commands. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| # state koid name | |
| â–¶ 1 Core Dump 19601 | |
| 2 Core Dump 26944 | |
| 3 Core Dump 26975 | |
| 4 Core Dump 26983 | |
| ``` | |
| 1. List a specific thread. For example, `thread 2`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread 2 | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 2 state="Core Dump" koid=26944 name="" | |
| ``` | |
| 1. You can then use `frame` to see this specific stack frame from `thread 2`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| ▶ 0 $elf(CODE_SYSCALL_zx_futex_wait) + 0xa • syscalls.inc:210 | |
| 1 _zx_futex_wait(…) • syscalls.inc:210 | |
| 2 __timedwait_assign_owner(…) • __timedwait.c:23 | |
| 3 __timedwait(…) • threads_impl.h:322 (inline) | |
| 4 pthread_cond_timedwait(…) • pthread_cond_timedwait.c:78 | |
| 5 std::__2::__libcpp_condvar_timedwait(…) • stage2-bins/include/c++/v1/__thread/support/pthread.h:127 (inline) | |
| 6 std::__2::condition_variable::__do_timed_wait(…) • condition_variable.cpp:54 | |
| 7 std::__2::condition_variable::wait_for<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:196 | |
| 8 std::__2::condition_variable::__do_timed_wait<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:235 | |
| 9 std::__2::condition_variable::wait_until<…>(…) • linux-x64/include/c++/v1/__condition_variable/condition_variable.h:161 | |
| 10 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:240 | |
| 11 std::__2::condition_variable_any::wait_until<…>(…) • condition_variable:247 | |
| 12 std::__2::condition_variable_any::wait_for<…>(…) • condition_variable:260 | |
| 13 cobalt::local_aggregation::DelayedLocalAggregateStorage::Run(…) • delayed_local_aggregate_storage.cc:200 | |
| 14 λ(…) • delayed_local_aggregate_storage.cc:45 | |
| 15 std::__2::__invoke<…>(…) • linux-x64/include/c++/v1/__type_traits/invoke.h:150 | |
| 16 std::__2::__thread_execute<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:192 | |
| 17 std::__2::__thread_proxy<…>(…) • linux-x64/include/c++/v1/__thread/thread.h:201 | |
| 18…19 «pthread startup» (-r expands) | |
| ``` | |
| 1. List another specific thread. For example, `thread 1`: | |
| Note: This example is on a different thread to show the difference when | |
| you follow the `thread` noun with `frame`. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread 1 | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| Thread 1 state="Core Dump" koid=19601 name="" | |
| ``` | |
| 1. You can then use `frame` to see this specific stack frame from `thread 1`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| ▶ 0…4 «Waiting for event in async::Loop::Run()» (-r expands) | |
| 5 main(…) • cobalt_main.cc:349 | |
| 6…8 «libc startup» (-r expands) | |
| ``` | |
| 1. Based on the output from the previous step, you may want to dive deeper | |
| into `frame 5`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame 5 | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| main(…) • cobalt_main.cc:349 | |
| ``` | |
| 1. To see additional lines of code from the current frame, use `list`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| 344 | |
| 345 if (!app.ok()) { | |
| 346 FX_LOGS(FATAL) << "Failed to construct the cobalt app: " << app.status(); | |
| 347 } | |
| 348 inspector.Health().Ok(); | |
| â–¶ 349 loop.Run(); | |
| 350 FX_LOGS(INFO) << "Cobalt will now shut down."; | |
| 351 return 0; | |
| 352 } | |
| ``` | |
| Since this frame actually contains some code, you can use `locals` | |
| to see the local variables in this stack frame. | |
| 1. To see all local variables in the current stack frame, use `locals`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| locals | |
| ``` | |
| You should see an output like: | |
| Note: The `(*)` indicates that the variable is a pointer. | |
| ```none {:.devsite-disable-click-to-copy} | |
| argc = 2 | |
| argv = (*)0x26866821fc0 | |
| command_line = <Invalid pointer 0x26866821418> | |
| context = <Invalid pointer 0x26866821100> | |
| event_aggregator_backfill_days = 2 | |
| flag_value = <Invalid pointer 0x268668211d8> | |
| initial_interval = <Invalid pointer 0x26866821138> | |
| inspector = <Invalid pointer 0x268668212f0> | |
| loop = <Invalid pointer 0x26866821108> | |
| max_bytes_per_observation_store = 215040 | |
| min_interval = <Invalid pointer 0x26866821118> | |
| require_lifecycle_service = true | |
| schedule_interval = <Invalid pointer 0x26866821140> | |
| start_event_aggregator_worker = true | |
| status = 0 (ZX_OK) | |
| storage_quotas = { | |
| per_project_reserved_bytes = 1024 | |
| total_capacity_bytes = 731136 | |
| } | |
| test_dont_backfill_empty_reports = false | |
| upload_jitter = 0.2 | |
| upload_schedule = { | |
| target_interval = {__rep_ = 3600} | |
| min_interval = {__rep_ = 10} | |
| initial_interval = {__rep_ = 60} | |
| jitter = 0.2 | |
| } | |
| use_fake_clock = false | |
| use_memory_observation_store = false | |
| ``` | |
| You can then see more information about a specific variable with `print`. | |
| For example: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| print upload_schedule | |
| ``` | |
| You should see an output like: | |
| ```none {:.devsite-disable-click-to-copy} | |
| { | |
| target_interval = {__rep_ = 3600} | |
| min_interval = {__rep_ = 10} | |
| initial_interval = {__rep_ = 60} | |
| jitter = 0.2 | |
| } | |
| ``` | |
| You have successfully loaded and analyzed a minidump for C++ code. | |
| [basic-test-debugging]: /docs/reference/testing/fx-test.md#basic_test_debugging |