blob: 4ef752178689f1cf60aa05f5ca59a8130c59cb39 [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_THREAD_IMPL_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_THREAD_IMPL_H_
#include <cstdint>
#include <list>
#include "gtest/gtest_prod.h"
#include "src/developer/debug/zxdb/client/thread.h"
#include "src/developer/debug/zxdb/expr/eval_context.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace unwinder {
class Memory;
class Registers;
class AsyncUnwinder;
} // namespace unwinder
namespace zxdb {
class Breakpoint;
class FrameImpl;
class ProcessImpl;
class ThreadImpl final : public Thread, public Stack::Delegate {
public:
ThreadImpl(ProcessImpl* process, const debug_ipc::ThreadRecord& record);
~ThreadImpl() override;
ProcessImpl* process() const { return process_; }
// Thread implementation:
Process* GetProcess() const override;
uint64_t GetKoid() const override;
const std::string& GetName() const override;
std::optional<debug_ipc::ThreadRecord::State> GetState() const override;
debug_ipc::ThreadRecord::BlockedReason GetBlockedReason() const override;
std::optional<StopInfo> CurrentStopInfo() const override;
void Pause(fit::callback<void()> on_paused) override;
void Continue(bool forward_exception) override;
void ContinueWith(std::unique_ptr<ThreadController> controller,
fit::callback<void(const Err&)> on_continue) override;
void AddPostStopTask(PostStopTask task) override;
void CancelAllThreadControllers() override;
void ResumeFromAsyncThreadController(std::optional<debug_ipc::ExceptionType> type) override;
void JumpTo(uint64_t new_address, fit::callback<void(const Err&)> cb) override;
void NotifyControllerDone(ThreadController* controller) override;
void StepInstructions(uint64_t count) override;
const Stack& GetStack() const override;
Stack& GetStack() override;
// Updates the thread metadata with new state from the agent. Does not issue any notifications.
// When an exception is hit for example, everything needs to be updated first to a consistent
// state and then we issue notifications. Callers may set |skip_frames| to true, which will not
// set the stack of this thread to |record|. This can be useful when the client decides to fully
// synchronize the stack from the Agent before setting the rest of the metadata from an exception
// that should be kept when control is returned to the user.
void SetMetadata(const debug_ipc::ThreadRecord& record, bool skip_frames = false);
// Notification of an exception. Call after SetMetadata() in cases where a stop may be required.
// This function will check controllers and will either stop (dispatching notifications) or
// transparently continue accordingly.
//
// The breakpoints will include all breakpoints, including internal ones.
void OnException(const StopInfo& info);
bool HasActiveThreadControllers() const { return !controllers_.empty(); }
private:
FRIEND_TEST(ThreadImplTest, StopNoStack);
// Stack::Delegate implementation.
void SyncFramesForStack(const Stack::SyncFrameOptions& options,
fit::callback<void(const Err&)> callback) override;
std::unique_ptr<Frame> MakeFrameForStack(const debug_ipc::StackFrame& input,
Location location) override;
Location GetSymbolizedLocationForAddress(uint64_t address) override;
void DidUpdateStackFrames() override;
// Helper for when local unwinding using CFI fails (the local unwinder will only try to use CFI).
// This function is called to perform the unwinding on the target which will have synchronous
// access to the process's memory, making the unwinding logic much simpler.
void SyncFramesFromTarget(fit::callback<void(const Err&)> callback);
// Uses the given registers to invoke the unwinder with the available local debug info. If
// unwinding fails, falls back to unwinding on the target. |cb| is guaranteed to be issued
// asynchronously from this function.
void UnwindWithRegisters(unwinder::Registers regs, fit::callback<void(const Err&)> cb);
// Invalidates the thread state and cached frames. Used when we know that some operation has
// invalidated our state but we aren't sure what the new state is yet.
void ClearState();
// Runs the next post-stop task and queues up a continuation of this function when it has
// completed. This will have the effect of sequentially running all of the post-stop tasks and
// then dispatching the stop notification or continuing the program (as per |should_stop|) and
// forwarding exceptions (as per |should_forward|).
void RunNextPostStopTaskOrNotify(const StopInfo& info, bool should_stop, bool should_forward);
void ResolveConditionalBreakpoint(const std::string& cond, Breakpoint* bp,
fit::callback<void(bool)> cb);
ProcessImpl* const process_;
uint64_t koid_;
Stack stack_;
std::string name_;
std::optional<debug_ipc::ThreadRecord::State> state_;
debug_ipc::ThreadRecord::BlockedReason blocked_reason_ =
debug_ipc::ThreadRecord::BlockedReason::kNotBlocked;
// Ordered list of ThreadControllers that apply to this thread. This is a stack where back() is
// the topmost controller that applies first.
std::vector<std::unique_ptr<ThreadController>> controllers_;
// Tasks to run when the ThreadController::OnThreadStop functions complete.
bool handling_on_stop_ = false;
std::list<PostStopTask> post_stop_tasks_;
// State for thread controllers that return "kFuture" to resume from a stop later.
//
// This tracks the number of times a thread controller has responded "kFuture" without issuing a
// stop or continue. This prevents infinite loops if there is a bug in the thread controllers.
StopInfo async_stop_info_;
int nested_stop_future_completion_ = 0;
// The current stop info, if we're currently stopped in an exception. Otherwise nullopt.
std::optional<StopInfo> current_stop_info_ = std::nullopt;
// Indicates if observer notifications are permitted to be sent. This is set to false during
// construction to prevent notifications before the thread is set up and the "new thread"
// notification has been sent to register it.
bool allow_notifications_ = false;
fxl::WeakPtrFactory<ThreadImpl> weak_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(ThreadImpl);
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_THREAD_IMPL_H_