| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/console/commands/verb_step.h" |
| |
| #include "src/developer/debug/zxdb/client/frame.h" |
| #include "src/developer/debug/zxdb/client/step_into_thread_controller.h" |
| #include "src/developer/debug/zxdb/client/step_over_thread_controller.h" |
| #include "src/developer/debug/zxdb/client/thread.h" |
| #include "src/developer/debug/zxdb/console/command.h" |
| #include "src/developer/debug/zxdb/console/command_utils.h" |
| #include "src/developer/debug/zxdb/console/console.h" |
| #include "src/developer/debug/zxdb/console/output_buffer.h" |
| #include "src/developer/debug/zxdb/console/verbs.h" |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| const char kStepShortHelp[] = "step / s: Step one source line, going into subroutines."; |
| const char kStepHelp[] = |
| R"(step [ <function-fragment> ] |
| |
| Alias: "s" |
| |
| When a thread is stopped, "step" will execute one source line and stop the |
| thread again. This will follow execution into subroutines. If the thread is |
| running it will issue an error. |
| |
| By default, "step" will single-step the current thread. If a thread context |
| is given, the specified thread will be stepped. You can't step a process. |
| Other threads in the process will be unchanged so will remain running or |
| stopped. |
| |
| If the thread ends up in a new function, that function's prologue will be |
| automatically skipped before the operation complets. An option to control |
| whether this happens can be added in the future if desired (bug 45309). |
| |
| See also "stepi". |
| |
| Stepping into specific functions |
| |
| If provided, the parameter will specify a specific function call to step |
| into. |
| |
| The string will be matched against the symbol names of subroutines called |
| directly from the current line. Execution will stop if the function name |
| contains this fragment, and automatically complete that function call |
| otherwise. |
| |
| Unsymbolized functions |
| |
| The step command follows the "skip-unsymbolized" setting when an unsymbolized |
| function is encountered. See "get skip-unsymbolized" for more. |
| |
| Examples |
| |
| s |
| step |
| Step the current thread. |
| |
| t 2 s |
| thread 2 step |
| Steps thread 2 in the current process. |
| |
| s Pri |
| Steps into a function with the substring "Pri" anywhere in its name. If |
| you have a complex line such as: |
| |
| Print(GetFoo(), std::string("bar"); |
| |
| The "s Pri" command will step over the GetFoo() and std::string() calls, |
| and leave execution at the beginning of the "Print" subroutine. |
| )"; |
| |
| Err RunVerbStep(ConsoleContext* context, const Command& cmd) { |
| if (Err err = AssertStoppedThreadWithFrameCommand(context, cmd, "step"); err.has_error()) |
| return err; |
| |
| // All controllers do this on completion. |
| auto completion = [](const Err& err) { |
| if (err.has_error()) |
| Console::get()->Output(err); |
| }; |
| |
| if (cmd.args().empty()) { |
| // Step for a single line. |
| auto controller = std::make_unique<StepIntoThreadController>(StepMode::kSourceLine, |
| &ScheduleAsyncPrintReturnValue); |
| cmd.thread()->ContinueWith(std::move(controller), std::move(completion)); |
| } else if (cmd.args().size() == 1) { |
| // Step into a specific named subroutine. This uses the "step over" controller with a special |
| // condition. |
| auto controller = std::make_unique<StepOverThreadController>(StepMode::kSourceLine); |
| controller->set_subframe_should_stop_callback( |
| [substr = cmd.args()[0]](const Frame* frame) -> bool { |
| const Symbol* symbol = frame->GetLocation().symbol().Get(); |
| if (!symbol) |
| return false; // Unsymbolized location, continue. |
| return symbol->GetFullName().find(substr) != std::string::npos; |
| }); |
| cmd.thread()->ContinueWith(std::move(controller), std::move(completion)); |
| } else { |
| return Err("Too many arguments for 'step'."); |
| } |
| |
| return Err(); |
| } |
| |
| } // namespace |
| |
| VerbRecord GetStepVerbRecord() { |
| return VerbRecord(&RunVerbStep, {"step", "s"}, kStepShortHelp, kStepHelp, CommandGroup::kStep, |
| SourceAffinity::kSource); |
| } |
| |
| } // namespace zxdb |