blob: 638ee11eb6709b350d6c11f0bfaa4c12fd4ed481 [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.
#pragma once
#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 "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.
//
// 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);
// 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,
std::function<void(const Err&)> cb) override;
ContinueOp GetContinueOp() override;
StopOp OnThreadStop(
debug_ipc::NotifyException::Type 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 construction_mode_ == kSourceLine, this represents the line
// information and the stack fingerprint of where stepping started.
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