| // Copyright 2019 The SwiftShader Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef VK_DEBUG_THREAD_HPP_ |
| #define VK_DEBUG_THREAD_HPP_ |
| |
| #include "Context.hpp" |
| #include "ID.hpp" |
| #include "Location.hpp" |
| |
| #include "marl/mutex.h" |
| #include "marl/tsa.h" |
| |
| #include <condition_variable> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| namespace vk { |
| namespace dbg { |
| |
| class File; |
| class VariableContainer; |
| class ServerEventListener; |
| |
| // Scope is a container for variables and is used to provide source data for the |
| // DAP 'Scope' type: |
| // https://microsoft.github.io/debug-adapter-protocol/specification#Types_Scope |
| class Scope |
| { |
| public: |
| using ID = dbg::ID<Scope>; |
| |
| inline Scope(ID id, |
| const std::shared_ptr<File> &file, |
| const std::shared_ptr<VariableContainer> &variables); |
| |
| // The unique identifier of the scope. |
| const ID id; |
| |
| // The file this scope is associated with. |
| const std::shared_ptr<File> file; |
| |
| // The scope's variables. |
| const std::shared_ptr<VariableContainer> variables; |
| }; |
| |
| Scope::Scope(ID id, |
| const std::shared_ptr<File> &file, |
| const std::shared_ptr<VariableContainer> &variables) |
| : id(id) |
| , file(file) |
| , variables(variables) |
| {} |
| |
| // Frame holds a number of variable scopes for one of a thread's stack frame, |
| // and is used to provide source data for the DAP 'StackFrame' type: |
| // https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame |
| class Frame |
| { |
| public: |
| using ID = dbg::ID<Frame>; |
| |
| inline Frame(ID id, std::string function); |
| |
| // The unique identifier of the stack frame. |
| const ID id; |
| |
| // The name of function for this stack frame. |
| const std::string function; |
| |
| // The current execution location within the stack frame. |
| Location location; |
| |
| // The scope for the frame's arguments. |
| std::shared_ptr<Scope> arguments; |
| |
| // The scope for the frame's locals. |
| std::shared_ptr<Scope> locals; |
| |
| // The scope for the frame's registers. |
| std::shared_ptr<Scope> registers; |
| |
| // The scope for variables that should only appear in hover tooltips. |
| std::shared_ptr<Scope> hovers; |
| }; |
| |
| Frame::Frame(ID id, std::string function) |
| : id(id) |
| , function(std::move(function)) |
| {} |
| |
| // Thread holds the state for a single thread of execution. |
| class Thread |
| { |
| public: |
| using ID = dbg::ID<Thread>; |
| |
| using UpdateFrame = std::function<void(Frame &)>; |
| |
| // The current execution state. |
| enum class State |
| { |
| Running, // Thread is running. |
| Stepping, // Thread is currently single line stepping. |
| Paused // Thread is currently paused. |
| }; |
| |
| Thread(ID id, Context *ctx); |
| |
| // setName() sets the name of the thread. |
| void setName(const std::string &); |
| |
| // name() returns the name of the thread. |
| std::string name() const; |
| |
| // enter() pushes the thread's stack with a new frame created with the given |
| // file and function, then calls f to modify the new frame of the stack. |
| void enter(const std::shared_ptr<File> &file, const std::string &function, const UpdateFrame &f = nullptr); |
| |
| // exit() pops the thread's stack frame. |
| // If isStep is true, then this will be considered a line-steppable event, |
| // and the debugger may pause at the function call at the new top most stack |
| // frame. |
| void exit(bool isStep = false); |
| |
| // frame() returns a copy of the thread's top most stack frame. |
| Frame frame() const; |
| |
| // stack() returns a copy of the thread's current stack frames. |
| std::vector<Frame> stack() const; |
| |
| // depth() returns the number of stack frames. |
| size_t depth() const; |
| |
| // state() returns the current thread's state. |
| State state() const; |
| |
| // update() calls f to modify the top most frame of the stack. |
| // If the frame's location is changed and isStep is true, update() |
| // potentially blocks until the thread is resumed with one of the methods |
| // below. |
| // isStep is used to distinguish same-statement column position updates |
| // from full line updates. Note that we cannot simply examine line position |
| // changes as single-line loops such as `while(true) { foo(); }` would not |
| // be correctly steppable. |
| void update(bool isStep, const UpdateFrame &f); |
| |
| // resume() resumes execution of the thread by unblocking a call to |
| // update() and setting the thread's state to State::Running. |
| void resume(); |
| |
| // pause() suspends execution of the thread by blocking the next call to |
| // update() and setting the thread's state to State::Paused. |
| void pause(); |
| |
| // stepIn() temporarily resumes execution of the thread by unblocking a |
| // call to update(), and setting the thread's state to State::Stepping. |
| // The next call to update() will suspend execution again. |
| void stepIn(); |
| |
| // stepOver() temporarily resumes execution of the thread by unblocking a |
| // call to update(), and setting the thread's state to State::Stepping. |
| // The next call to update() within the same stack frame will suspend |
| // execution again. |
| void stepOver(); |
| |
| // stepOut() temporarily resumes execution of the thread by unblocking a |
| // call to update(), and setting the thread's state to State::Stepping. |
| // The next call to update() at the stack frame above the current frame will |
| // suspend execution again. |
| void stepOut(); |
| |
| // The unique identifier of the thread. |
| const ID id; |
| |
| private: |
| Context *const ctx; |
| |
| void onLocationUpdate(marl::lock &lock) REQUIRES(mutex); |
| |
| mutable marl::mutex mutex; |
| std::string name_ GUARDED_BY(mutex); |
| std::vector<std::shared_ptr<Frame>> frames GUARDED_BY(mutex); |
| State state_ GUARDED_BY(mutex) = State::Running; |
| std::weak_ptr<Frame> pauseAtFrame GUARDED_BY(mutex); |
| |
| std::condition_variable stateCV; |
| }; |
| |
| } // namespace dbg |
| } // namespace vk |
| |
| #endif // VK_DEBUG_THREAD_HPP_ |