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:

ffx debug connect
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:

Set a breakpoint on the greeting() function:

With the debugger ready, start a new echo component instance:

ffx component run /core/ffx-laboratory:echo 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:

[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:

The print command will output the state of any variables in the current stack frame. Print the current value of names:

Step through the greeting() function a more few times using next:

To let the program continue to completion, use the continue command:

Exit the debugging session to return to the terminal:

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:

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;
}

Build and publish the updated package to the fuchsiasamples.com repository:

bazel run //fuchsia-codelab/echo:pkg.publish -- \
    --repo_name fuchsiasamples.com

Start a new debug session with zxdb:

ffx debug connect

Debug the crashing stack frame

Configure the debugger to attach to the echo component:

Start a new instance of the component:

ffx component run /core/ffx-laboratory:echo fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm --recreate

This time, the debugger detects that an exception was thrown and halts execution:

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:

[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:

Exit the debugging session to return to the terminal:

Destroy the instance

Clean up the echo instance using the following command:

ffx component destroy /core/ffx-laboratory:echo