| # Control thread execution | |
| When you use zxdb, you can control the execution of threads to help you debug. | |
| As you debug you can control execution through the use of the following: | |
| * Thread | |
| A thread is a unit of execution within a process. It represents a single | |
| sequence of instructions that can be executed independently. | |
| To control execution through threads in zxdb, see [Threads](#threads). | |
| * Stack frame | |
| A stack frame is a section of the call stack that is allocated when a function | |
| is called. It stores information needed for the function's execution, such as: | |
| * Local variables: Variables declared within the function. | |
| * Parameters: Values passed to the function. | |
| * Return address: The location in the code to return to after the | |
| function completes. | |
| To control execution through stack frames in zxdb, see | |
| [Stack Frames](#stack-frames). | |
| ## Threads | |
| In zxdb, a `thread` is a [noun][zxdb-noun] that you can use with zxdb | |
| [verbs][zxdb-verb]. | |
| To list the threads in the current process: | |
| Note: This is the `thread` noun. You can also use `t` to express `thread`. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread | |
| # State Koid Name | |
| ▶ 1 Blocked 1323 initial-thread | |
| 2 Running 3462 worker-thread | |
| ``` | |
| In some cases, you may notice that a thread is marked as `Blocked` which means | |
| that the thread is stopped on a system call. Typically, when you are debugging | |
| an asynchronous application this may also indicate a wait time. | |
| Thread control commands only work on a suspended thread, not blocked or running | |
| threads. There are several ways to suspend a thread: | |
| * A [breakpoint][zxdb-breakpoints] stopped the thread. | |
| * Use the [`pause`](#pause-command) command. | |
| ### `pause` a thread {#pause-command} | |
| For example, to suspend thread `2` with the `pause` command: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread 2 pause | |
| 🛑 syscalls-x86-64.S:67 | |
| 65 m_syscall zx_port_create 60 2 1 | |
| 66 m_syscall zx_port_queue 61 2 1 | |
| ▶ 67 m_syscall zx_port_wait 62 3 0 | |
| 68 m_syscall zx_port_cancel 63 3 1 | |
| 69 m_syscall zx_timer_create 64 3 1 | |
| ``` | |
| When a thread is paused zxdb shows the current source code location. If a thread | |
| is in a system call, like the example above, the source code location resolves | |
| to the location in the assembly-language macro file that generated the system | |
| call. | |
| If you run `pause` without any additional context, zxdb pauses all threads of | |
| all processes that are currently attached. | |
| For example: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| pause | |
| 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)) | |
| 🛑 $elf(SYSCALL_zx_port_wait) + 0x7 • syscalls.inc:510 | |
| ``` | |
| ### `continue` a thread {#continue-thread} | |
| After you have paused a thread and started debugging an issue, you may want to | |
| `continue` the thread. Continuing means resuming execution until your program | |
| completes normally. | |
| For example, to `continue` thread `1`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| thread 1 continue | |
| ``` | |
| If you run `continue` without any additional context, zxdb continues all the | |
| threads of all attached processes. | |
| For example: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| continue | |
| ``` | |
| ### Stepping a thread | |
| When a thread is paused you can control its execution. You can use any of these | |
| commands: | |
| Note: For more information on pausing a thread, see | |
| [`pause` a thread](#pause-command). | |
| * `finish` (`fi`) | |
| Exits the function and stops right after the call. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| finish | |
| ``` | |
| * `next` (`n`) | |
| Advances to the next line, stepping over function calls. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| next | |
| ``` | |
| * `nexti` | |
| Advances to the next instruction, but steps over call instructions for the | |
| target architecture. | |
| Note: In this context, a call instruction is `call` on x64 and `bl` on arm64. | |
| This does not work for all cases. For example, a manually set up call frame | |
| and a `jump` may result stepping into a new stack frame. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| nexti | |
| ``` | |
| * `ss` | |
| List function calls on the current line and step in to the call selected. This | |
| automatically completes any of the other calls that happen to occur first. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| ss | |
| 1 std::string::string | |
| 2 MyClass::MyClass | |
| 3 HelperFunctionCall | |
| 4 MyClass::~MyClass | |
| 5 std::string::~string | |
| quit | |
| > | |
| ``` | |
| * `step` (`s`) | |
| Advances to the next code line. If a function call happens before the next | |
| line, that function is stepped into and execution stops at the | |
| beginning of that function. | |
| You can also supply an argument substring to match a specific function call. | |
| Function names that do not contain the argument substring are skipped and | |
| only matching functions are stepped into. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| step | |
| [zxdb] step MyFunction | |
| ``` | |
| * `stepi` | |
| Advances exactly one machine instruction. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| stepi | |
| ``` | |
| * `until` (`u`) | |
| Given a line location, continues the thread until execution gets there. For | |
| example, to run until line `45` of the current file: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| until 45 | |
| ``` | |
| You can also run until execution gets back to a given stack frame: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame 2 until | |
| ``` | |
| ## Stack frames {#stack-frames} | |
| A stack frame is a function call. When a function calls another function, a new | |
| frame is created. Listing the frames of a thread returns the call stack. | |
| Note: You can only see the stack frames when a thread is suspended. See | |
| [`pause` a specific thread](#pause-command). | |
| To list the stack frames in the current thread: | |
| Note: This is the `frame` noun. You can also use `f` to express `frame`. | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame | |
| ▶ 0 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:203 | |
| 1 fxl::CommandLineFromArgcArgv() • command_line.h:224 | |
| 2 main() • main.cc:174 | |
| ``` | |
| When you work with stack frames, `0` indicates the top of the stack, which | |
| indicates the end of the execution. The bottom of the stack, which is the | |
| highest stack frame number, indicates the start of the execution. | |
| ### Navigating stack frames {#navigate-stack-frames} | |
| You can use the `up` and `down` commands to navigate the frame list. | |
| For example, use `up` to navigate from the current frame `0` to frame `1`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| up | |
| 1 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:204 | |
| ``` | |
| For example, use `down` to navigate from the current frame `1` to frame `0`: | |
| ``` | |
| [zxdb] down | |
| 0 fxl::CommandLineFromIteratorsFindFirstPositionalArg<const char *const *>() • command_line.h:185 | |
| ``` | |
| You can also navigate to a specific frame by using the `frame` command with a | |
| frame number: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame 1 | |
| ``` | |
| ### Use `backtrace` for additional details {#backtrace} | |
| In some cases, you may want to see additional address information that | |
| stack frames don't provide. The `backtrace` command is identical to `frame` but | |
| gives you more detailed address information as well as function parameters. | |
| Note: This is the `backtrace` verb. You can also use `bt` to express | |
| `backtrace`. | |
| To list the stack frames in the current thread, but with more detailed | |
| information, use `backtrace`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| backtrace | |
| ▶ 0 fxl::CommandLineFromIteratorsFindFirstPositionalArg<const char *const *>() • command_line.h:185 | |
| IP = 0x10f982cf2ad0, BP = 0x66b45a01af50, SP = 0x66b45a01af38 | |
| first = (const char* const*) 0x59f4e1268dc0 | |
| last = (const char* const*) 0x59f4e1268dc8 | |
| first_positional_arg = (const char* const**) 0x0 | |
| 1 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:204 | |
| IP = 0x10f982cf2ac0, BP = 0x66b45a01af50, SP = 0x66b45a01af40 | |
| first = <'first' is not available at this address. > | |
| last = <'last' is not available at this address. > | |
| ... | |
| ``` | |
| ### Use `list` to look at source code {#list} | |
| Each stack frame has a code location. Use the `list` command to look at the | |
| source code. | |
| You can list code around the instruction pointer of specific stack frames. | |
| For example, to `list` the source code around the instruction pointer of stack | |
| frame `3`: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| frame 3 list | |
| ``` | |
| When you use `list` without context, zxdb lists the source code | |
| around the instruction pointer of the current stack frame: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list | |
| 183 inline CommandLine CommandLineFromIteratorsFindFirstPositionalArg( | |
| 184 InputIterator first, InputIterator last, | |
| ▶ 185 InputIterator* first_positional_arg) { | |
| 186 if (first_positional_arg) | |
| 187 *first_positional_arg = last; | |
| ``` | |
| #### Additional use cases for `list` | |
| Additionally, you can use `list` to list specific things: | |
| * {Functions} | |
| Use `list` to list functions: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list MyClass::MyFunc | |
| ``` | |
| * {Files} | |
| Use `list` to list specific files: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list --all myfile.cc:1 | |
| ``` | |
| * {File with line numbers} | |
| Use `list` to list specific files with specific line numbers: | |
| ```none {: .devsite-terminal data-terminal-prefix="[zxdb]" } | |
| list foo.cc:43 | |
| ``` | |
| [zxdb-noun]: /docs/development/debugger/commands.md#noun | |
| [zxdb-verb]: /docs/development/debugger/commands.md#verbs | |
| [zxdb-breakpoints]: /docs/development/debugger/breakpoints.md |