blob: 8583fa2d632dd35677c4d8aa9349e73993c1a8d6 [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().
virtual debug_ipc::ThreadRecord::State GetState() 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 stopped
// position. If a thread is running, the stack frames are not available.
//
// When a thread is stopped, it will have its 0th frame available (the
// current IP and stack position) and the 1st (the calling frame) if
// possible. So stopped 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. HasAllFrames()
// will return true if the full backtrace is currently available (= true) or
// if only the current position is available (= false).
//
// Since the running/stopped 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 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