| # Debugging components |
| |
| <<../../../_common/components/_debugging_intro.md>> |
| |
| <<../../../_common/components/_debugging_analyze.md>> |
| |
| ## Exercise: Using the Fuchsia debugger |
| |
| In this exercise, you'll use the Fuchsia debugger (`zxdb`) to inspect a running |
| instance of the `echo` component and understand the cause of a crash. |
| |
| <<../_common/_start_femu_with_packages.md>> |
| |
| ### Start a debug session |
| |
| Once the emulator has started up, start a `zxdb` debugging session with the |
| `ffx debug connect` command: |
| |
| ```posix-terminal |
| ffx debug connect |
| ``` |
| |
| ```none {:.devsite-disable-click-to-copy} |
| Connecting (use "disconnect" to cancel)... |
| Connected successfully. |
| π To get started, try "status" or "help". |
| [zxdb] |
| ``` |
| |
| After successfully connecting, the `zxdb` prompt is ready to accept commands. |
| |
| ### Attach to the component |
| |
| Before launching the component, configure `zxdb` to attach to an instance of |
| `echo`. This enables the debugger to attach as soon as the process starts: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>attach echo |
| </pre> |
| |
| Set a breakpoint on the `greeting()` function: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>break greeting |
| </pre> |
| |
| With the debugger ready, start a new `echo` component instance: |
| |
| |
| ```posix-terminal |
| ffx component run fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm |
| ``` |
| |
| ### Explore the debug session |
| |
| Upon reaching the breakpoint in `greeting()`, execution stops and the debugger |
| waits for a new command. Use the `list` command to show where execution is |
| currently paused: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] list |
| 17 |
| 18 // Return a proper greeting for the list |
| βΆ 19 std::string greeting(std::vector<std::string>& names) { |
| 20 // Join the list of names based on length |
| 21 auto number_of_names = names.size(); |
| 22 switch (number_of_names) { |
| 23 case 0: |
| 24 return "Nobody!"; |
| 25 case 1: |
| 26 return join(names, ""); |
| 27 case 2: |
| 28 return join(names, " and "); |
| 29 default: |
| ``` |
| |
| Step into the `greeting()` function using the `next` command: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>next |
| </pre> |
| |
| The `print` command will output the state of any variables in the current stack |
| frame. Print the current value of `names`: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>print names |
| <span class="no-select">{"Alice", "Bob", "Spot"}</span> |
| </pre> |
| |
| Step through the `greeting()` function a more few times using `next`: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>next |
| </pre> |
| |
| To let the program continue to completion, use the `continue` command: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>continue |
| </pre> |
| |
| Exit the debugging session to return to the terminal: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>exit |
| </pre> |
| |
| ### Introduce some crashing code |
| |
| Next, you'll add some code to `main()` to cause the component to crash |
| (or panic). Simulate this behavior by adding an `strlen(nullptr)` reference just |
| after the arguments are collected: |
| |
| `echo/main.cc`: |
| |
| ```cpp |
| int main(int argc, const char* argv[], char* envp[]) { |
| // ... |
| |
| {{ '<strong>' }}// Simulate a crash {{ '</strong>' }} |
| {{ '<strong>' }}std::strlen(nullptr);{{ '</strong>' }} |
| |
| // Print a greeting to syslog |
| std::cout << "Hello, " << echo::greeting(arguments) << "!" << std::endl; |
| |
| return 0; |
| } |
| ``` |
| |
| Run `bazel build` and verify that the build completes successfully: |
| |
| ```posix-terminal |
| bazel build --config=fuchsia_x64 //fuchsia-codelab/echo:pkg \ |
| --publish_to=$HOME/.package_repos/sdk-samples |
| ``` |
| |
| Start a new debug session with `zxdb`: |
| |
| ```posix-terminal |
| ffx debug connect |
| ``` |
| |
| ### Debug the crashing stack frame |
| |
| Configure the debugger to attach to the `echo` component: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>attach echo |
| </pre> |
| |
| Start a new instance of the component: |
| |
| ```posix-terminal |
| ffx component run fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm --recreate |
| ``` |
| |
| This time, the debugger detects that an exception was thrown and halts execution: |
| |
| ```{:.devsite-disable-click-to-copy} |
| Attached Process 1 state=Running koid=1164808 name=echo.cm |
| ββββββββββββββββββββββββββββββββββββββββββββββββ |
| Page fault reading address 0x0 (second chance) |
| ββββββββββββββββββββββββββββββββββββββββββββββββ |
| Process 1 (koid=1164808) thread 1 (koid=1164810) |
| Faulting instruction: 0x43e0fd349210 |
| |
| π strlen(const char*) β’ strlen.c:21 |
| [zxdb] |
| ``` |
| |
| Use the `frame` command to inspect the stack trace at the point of the crash: |
| |
| ```none {:.devsite-disable-click-to-copy} |
| [zxdb] frame |
| βΆ 0 strlen(β¦) β’ strlen.c:21 |
| {{ '<strong>' }}1 main(β¦) β’ main.cc:27{{ '</strong>' }} |
| 2 Β«libc startupΒ» (-r expands) |
| 3 Β«libc startupΒ» (-r expands) |
| 4 $elf(_start) + 0x11 |
| ``` |
| |
| Notice line 1 in the stack trace indicates the point in `main.cc` where the |
| crash happened, corresponding to the `nullptr` reference. |
| |
| The current stack frame (frame 0) is deep within the system library, but you |
| can inspect any stack frame by prefixing the command with the frame number from |
| the stack trace. |
| |
| Print the value of the arguments at the point of the crash by passing the |
| frame number as follows: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>frame 1 print arguments |
| <span class="no-select">{"Alice", "Bob", "Spot"}</span> |
| </pre> |
| |
| Exit the debugging session to return to the terminal: |
| |
| <pre class="devsite-click-to-copy"> |
| <span class="no-select">[zxdb] </span>exit |
| </pre> |
| |
| ### Destroy the instance |
| |
| Clean up the `echo` instance using the following command: |
| |
| ```posix-terminal |
| ffx component destroy /core/ffx-laboratory:echo |
| ``` |