blob: 2819cd1cc06146b98d8aa34a657578a6a324601b [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 <stddef.h>
#include <stdint.h>
#include <functional>
#include <string>
#include "garnet/bin/zxdb/client/client_object.h"
#include "garnet/bin/zxdb/client/frame_fingerprint.h"
#include "garnet/bin/zxdb/client/setting_store.h"
#include "garnet/bin/zxdb/client/thread_observer.h"
#include "garnet/lib/debug_ipc/protocol.h"
#include "lib/fxl/macros.h"
#include "lib/fxl/memory/weak_ptr.h"
#include "lib/fxl/observer_list.h"
namespace zxdb {
class Err;
class Frame;
class Process;
class RegisterSet;
class ThreadController;
// The flow control commands on this object (Pause, Continue, Step...) apply
// only to this thread (other threads will continue to run or not run
// as they were previously).
class Thread : public ClientObject {
public:
explicit Thread(Session* session);
~Thread() override;
void AddObserver(ThreadObserver* observer);
void RemoveObserver(ThreadObserver* observer);
fxl::WeakPtr<Thread> GetWeakPtr();
// Guaranteed non-null.
virtual Process* GetProcess() const = 0;
virtual uint64_t GetKoid() const = 0;
virtual const std::string& GetName() const = 0;
// The state of the thread isn't necessarily up-to-date. There are no
// system messages for a thread transitioning to suspended, for example.
// To make sure this is up-to-date, call Process::SyncThreads() or
// Thread::SyncFrames().
virtual debug_ipc::ThreadRecord::State GetState() const = 0;
virtual debug_ipc::ThreadRecord::BlockedReason GetBlockedReason() const = 0;
virtual void Pause() = 0;
virtual void Continue() = 0;
// Continues the thread using the given ThreadController. This is used
// to implement the more complex forms of stepping.
//
// The on_continue callback does NOT indicate that the thread stopped again.
// This is because many thread controllers may need to do asynchronous setup
// that could fail. It is issued when the thread is actually resumed or when
// the resumption fails.
//
// The on_continue callback may be issued reentrantly from within the stack
// of the ContinueWith call if the controller was ready synchronously.
//
// On failure the ThreadController will be removed and the thread will not
// be continued.
virtual void ContinueWith(std::unique_ptr<ThreadController> controller,
std::function<void(const Err&)> on_continue) = 0;
// Notification from a ThreadController that it has completed its job. The
// thread controller should be removed from this thread and deleted.
virtual void NotifyControllerDone(ThreadController* controller) = 0;
virtual void StepInstruction() = 0;
// Access to the stack frames for this thread at its current suspended
// or blocked-in-exception position. If a thread is running, blocked (not in
// an exception), or in any other state, the stack frames are not available.
//
// When a thread is suspended or blocked in an exception, it will have its
// 0th frame available (the current IP and stack position) and the 1st (the
// calling frame) if possible. So such threads will always have at least one
// result in the vector returned by GetFrames(), and normally two.
//
// If the full backtrace is needed, SyncFrames() can be called which will
// compute the full backtrace and issue the callback when complete. This
// backtrace will be cached until the thread is resumed. It has the side
// effect of updating other thread status information.
//
// HasAllFrames() will return true if the full backtrace is currently
// available (= true) or if only the current position is available (= false).
//
// Since the state of a thread isn't available synchronously in a non-racy
// manner, you can always request a Sync of the frames if the frames are not
// all available. If the thread is destroyed before the backtrace can be
// issued, the callback will not be executed.
//
// If the thread is running when the request is processed, the callback will
// be issued but a subsequent call to GetFrames() will return an empty vector
// and HasAllFrames() will return false. This call can race with other
// requests to resume a thread, so you can't make any assumptions about the
// availability of the stack from the callback.
//
// The pointers in the vector returned by GetFrames() can be cached if the
// code listens for ThreadObserver::OnThreadFramesInvalidated() and clears
// the cache at that point.
virtual const std::vector<Frame*>& GetFrames() const = 0;
virtual bool HasAllFrames() const = 0;
virtual void SyncFrames(std::function<void()> callback) = 0;
// Computes the stack frame fingerprint for the stack frame at the given
// index. This function requires that that the previous stack frame
// (frame_index + 1) by present since the stack base is the SP of the
// calling function.
//
// This function can always return the fingerprint for frame 0. Other
// frames requires HasAllFrames() == true or it will assert.
//
// See frame.h for a discussion on stack frames.
virtual FrameFingerprint GetFrameFingerprint(size_t frame_index) const = 0;
// Obtains the state of the registers for a particular thread.
// The thread must be stopped in order to get the values.
//
// The returned structures are architecture independent, but the contents
// will be dependent on the architecture the target is running on.
virtual void GetRegisters(
std::vector<debug_ipc::RegisterCategory::Type> cats_to_get,
std::function<void(const Err&, const RegisterSet&)>) = 0;
// Provides the setting schema for this object.
static fxl::RefPtr<SettingSchema> GetSchema();
SettingStore& settings() { return settings_; }
protected:
fxl::ObserverList<ThreadObserver>& observers() { return observers_; }
SettingStore settings_;
private:
fxl::ObserverList<ThreadObserver> observers_;
fxl::WeakPtrFactory<Thread> weak_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(Thread);
};
} // namespace zxdb