blob: 5e300b021734d35384b6794322f6cc273e6c6e71 [file] [log] [blame]
// Copyright 2018 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.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_STEP_THREAD_CONTROLLER_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_STEP_THREAD_CONTROLLER_H_
#include <optional>
#include "src/developer/debug/zxdb/client/frame_fingerprint.h"
#include "src/developer/debug/zxdb/client/step_mode.h"
#include "src/developer/debug/zxdb/client/thread_controller.h"
#include "src/developer/debug/zxdb/common/address_ranges.h"
#include "src/developer/debug/zxdb/symbols/file_line.h"
namespace zxdb {
class FinishThreadController;
// Implements a low-level "step into" command. It knows how to step by source lines, over a range of
// addresses, or by single instruction.
//
// This is the main low-level thread controller used by other ones. Generally programmatic uses
// (e.g. from with "step over") will use this class. It will not generally be used directly, a
// user-level "step into" should use the StepIntoThreadController which provides some additional
// functionality.
//
// When stepping by file/line, this class will generate synthetic exceptions and adjust the stack to
// simulate stepping into inline function calls (even though there is no actual call instruction).
class StepThreadController : public ThreadController {
public:
// Constructor for kSourceLine and kInstruction modes. It will initialize itself to the thread's
// current position when the thread is attached.
explicit StepThreadController(StepMode mode);
// Steps given the source file/line.
explicit StepThreadController(const FileLine& line);
// Constructor for a kAddressRange mode (the mode is implicit). Continues execution as long as the
// IP is in range.
explicit StepThreadController(AddressRanges ranges);
~StepThreadController() override;
// Controls whether the thread will stop when it encounters code with no symbols. When false, if a
// function is called with no symbols, it will automatically step out or through it.
//
// This only affects "step by line" mode which is symbol-aware.
bool stop_on_no_symbols() const { return stop_on_no_symbols_; }
void set_stop_on_no_symbols(bool stop) { stop_on_no_symbols_ = stop; }
// ThreadController implementation.
void InitWithThread(Thread* thread, fit::callback<void(const Err&)> cb) override;
ContinueOp GetContinueOp() override;
StopOp OnThreadStop(debug_ipc::ExceptionType stop_type,
const std::vector<fxl::WeakPtr<Breakpoint>>& hit_breakpoints) override;
const char* GetName() const override { return "Step"; }
private:
enum class StepIntoInline {
// Actually performs the inline step, modifying the hidden ambiguous Stack items as necessary.
kCommit,
// Does the operations to compute whether an inline step can be completed and returns the
// corresponding result, but does not actually change any state.
kQuery
};
// Attempts to step into an inline function that starts and the current stack addresss. This will
// make it look like the user stepped into the inline function even though no code was executed.
//
// If there is an inline to step into, this will fix up the current stack to appear as if the
// inline function is stepped into and return true. False means there was not an inline function
// starting at the current address.
bool TrySteppingIntoInline(StepIntoInline command);
// Version of OnThreadStop that handles the case where the current code has no line information.
StopOp OnThreadStopOnUnsymbolizedCode();
StepMode step_mode_;
// When step_mode_ == kSourceLine, this represents the line information and the stack fingerprint
// of where stepping started. The file/line may be given in the constructor or we may need to
// compute it upon init from the current location (whether it needs setting is encoded by the
// optional).
std::optional<FileLine> file_line_;
FrameFingerprint original_frame_fingerprint_;
// Range of addresses we're currently stepping in. This may change when we're stepping over source
// lines and wind up in a region with no line numbers. It will be empty when stepping by
// instruction.
AddressRanges current_ranges_;
bool stop_on_no_symbols_ = false;
// Used to step out of unsymbolized functions. When non-null, the user wants to skip unsymbolized
// code and has stepped into an unsymbolized function.
std::unique_ptr<FinishThreadController> finish_unsymolized_function_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_STEP_THREAD_CONTROLLER_H_