blob: b1be1d57d59522ae04a40d535f7b4dc4f80e79b7 [file] [log] [blame]
// 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_until.h"
#include "src/developer/debug/zxdb/client/frame.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/thread.h"
#include "src/developer/debug/zxdb/client/until_thread_controller.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/input_location_parser.h"
#include "src/developer/debug/zxdb/console/output_buffer.h"
#include "src/developer/debug/zxdb/console/verbs.h"
namespace zxdb {
namespace {
const char kUntilShortHelp[] = "until / u: Runs a thread until a location is reached.";
const char kUntilHelp[] =
R"(until <location>
Alias: "u"
Continues execution of a thread or a process until a given location is
reached. You could think of this command as setting an implicit one-shot
breakpoint at the given location and continuing execution.
Normally this operation will apply only to the current thread. To apply to
all threads in a process, use "process until" (see the examples below).
See also "finish".
Location arguments
Current frame's address (no input)
until
)" LOCATION_ARG_HELP("until")
R"(
Examples
u
until
Runs until the current frame's location is hit again. This can be useful
if the current code is called in a loop to advance to the next iteration
of the current code.
f 1 u
frame 1 until
Runs until the given frame's location is hit. Since frame 1 is
always the current function's calling frame, this command will normally
stop when the current function returns. The exception is if the code
in the calling function is called recursively from the current location,
in which case the next invocation will stop ("until" does not match
stack frames on break). See "finish" for a stack-aware version.
u 24
until 24
Runs the current thread until line 24 of the current frame's file.
until foo.cc:24
Runs the current thread until the given file/line is reached.
thread 2 until 24
process 1 thread 2 until 24
Runs the specified thread until line 24 is reached. When no filename is
given, the specified thread's currently selected frame will be used.
u MyClass::MyFunc
until MyClass::MyFunc
Runs the current thread until the given function is called.
pr u MyClass::MyFunc
process until MyClass::MyFunc
Continues all threads of the current process, stopping the next time any
of them call the function.
)";
Err RunVerbUntil(ConsoleContext* context, const Command& cmd) {
// Decode the location.
//
// The validation on this is a bit tricky. Most uses apply to the current thread and take some
// implicit information from the current frame (which requires the thread be stopped). But when
// doing a process-wide one, don't require a currently stopped thread unless it's required to
// compute the location.
std::vector<InputLocation> locations;
if (cmd.args().empty()) {
// No args means use the current location.
if (!cmd.frame()) {
return Err(ErrType::kInput, "There isn't a current frame to take the location from.");
}
locations.emplace_back(cmd.frame()->GetAddress());
} else if (cmd.args().size() == 1) {
// One arg = normal location (this function can handle null frames).
if (Err err = ParseLocalInputLocation(cmd.frame(), cmd.args()[0], &locations); err.has_error())
return err;
} else {
return Err(ErrType::kInput,
"Expecting zero or one arg for the location.\n"
"Formats: <function>, <file>:<line#>, <line#>, or 0x<address>");
}
auto callback = [](const Err& err) {
if (err.has_error())
Console::get()->Output(err);
};
// Dispatch the request.
if (cmd.HasNoun(Noun::kProcess) && !cmd.HasNoun(Noun::kThread) && !cmd.HasNoun(Noun::kFrame)) {
// Process-wide ("process until ...").
if (Err err = AssertRunningTarget(context, "until", cmd.target()); err.has_error())
return err;
cmd.target()->GetProcess()->ContinueUntil(locations, callback);
} else {
// Thread-specific.
if (Err err = AssertStoppedThreadWithFrameCommand(context, cmd, "until"); err.has_error())
return err;
auto controller = std::make_unique<UntilThreadController>(std::move(locations));
cmd.thread()->ContinueWith(std::move(controller), [](const Err& err) {
if (err.has_error())
Console::get()->Output(err);
});
}
return Err();
}
} // namespace
VerbRecord GetUntilVerbRecord() {
return VerbRecord(&RunVerbUntil, &CompleteInputLocation, {"until", "u"}, kUntilShortHelp,
kUntilHelp, CommandGroup::kStep);
}
} // namespace zxdb