| // Copyright 2019 Google LLC |
| // |
| // 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 |
| // |
| // https://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 THIRD_PARTY_MLIR_EDGE_IREE_TOOLS_DEBUGGER_DEBUG_APP_H_ |
| #define THIRD_PARTY_MLIR_EDGE_IREE_TOOLS_DEBUGGER_DEBUG_APP_H_ |
| |
| #include <SDL.h> |
| |
| #include "third_party/absl/strings/string_view.h" |
| #include "third_party/absl/types/optional.h" |
| #include "third_party/mlir_edge/iree/base/status.h" |
| #include "third_party/mlir_edge/iree/vm/debug/debug_client.h" |
| |
| // NOTE: order matters here, imgui must come first: |
| #include "third_party/dear_imgui/imgui.h" |
| // NOTE: must follow imgui.h: |
| #include "third_party/dear_imgui/examples/imgui_impl_opengl3.h" |
| #include "third_party/dear_imgui/examples/imgui_impl_sdl.h" |
| |
| // Workaround for terrible bad SDL/graphics driver leaks. |
| // If you see these macros being used it means that the code between is not |
| // really under our control and not a leak we would be able to prevent. |
| #if defined(__has_feature) |
| #if __has_feature(address_sanitizer) |
| #include <sanitizer/lsan_interface.h> |
| #define IREE_DISABLE_LEAK_CHECKS() __lsan_disable() |
| #define IREE_ENABLE_LEAK_CHECKS() __lsan_enable() |
| #else |
| #define IREE_DISABLE_LEAK_CHECKS() |
| #define IREE_ENABLE_LEAK_CHECKS() |
| #endif // __has_feature(address_sanitizer) |
| #endif // __has_feature |
| |
| namespace iree { |
| namespace vm { |
| namespace debug { |
| |
| // Debug client app UI. |
| // Uses a DebugClient to communicate with a remote DebugServer and ImGui to |
| // display a nifty UI. |
| // |
| // See the ImGui site for more info: https://github.com/ocornut/imgui |
| // The most useful thing is the imgui_demo.cpp file that contains example usage |
| // of most features. |
| class DebugApp : private DebugClient::Listener { |
| public: |
| struct UserBreakpoint { |
| RemoteBreakpoint::Type type = RemoteBreakpoint::Type::kBytecodeFunction; |
| const RemoteBreakpoint* active_breakpoint = nullptr; |
| bool wants_enabled = true; |
| bool is_enabling = false; |
| // TODO(benvanik): reuse BreakpointDef here? |
| std::string module_name; |
| std::string function_name; |
| int function_ordinal = -1; |
| int bytecode_offset = 0; |
| std::string native_function; |
| }; |
| |
| static void PumpMainLoopThunk(void* arg); |
| |
| DebugApp(SDL_Window* window, SDL_GLContext gl_context, |
| const char* glsl_version); |
| ~DebugApp(); |
| |
| // Connects to the service at the specified address. |
| Status Connect(absl::string_view service_address); |
| // Disconnects from the currently connected service, if any. |
| Status Disconnect(); |
| |
| // Returns true if the remote service is paused at our request. |
| bool is_paused() const; |
| |
| // Pumps the main UI loop once. |
| // This polls the DebugClient, SDL input, and renders the UI. |
| // It should be called as frequently as possible to ensure snappy UI updates. |
| // Returns CancelledError if the app is being closed by the user. |
| Status PumpMainLoop(); |
| |
| // Defines how NavigationToCodeView methods behave. |
| enum class NavigationMode { |
| // The target will be opened in a new document tab. |
| kNewDocument, |
| // The target will be opened in the current document tab, replacing the |
| // current contents. |
| kCurrentDocument, |
| // The target will be opened in a document tab that mostly matches (like |
| // the same function in a module at a different offset), otherwise a new |
| // document will be opened. |
| kMatchDocument, |
| }; |
| |
| // Navigates to a particular function offset based on resolution of the given |
| // arguments. Navigation may happen asynchronously if targets need to be |
| // resolved or contents fetched. |
| Status NavigateToCodeView(absl::string_view module_name, int function_ordinal, |
| int offset, NavigationMode navigation_mode); |
| Status NavigateToCodeView(absl::string_view module_name, |
| absl::string_view function_name, int offset, |
| NavigationMode navigation_mode); |
| Status NavigateToCodeView(const RemoteFiberState& fiber_state, |
| int stack_frame_index, |
| NavigationMode navigation_mode); |
| Status NavigateToCodeView(const UserBreakpoint& user_breakpoint, |
| NavigationMode navigation_mode); |
| |
| private: |
| struct CodeViewDocument { |
| // Document display title (and ID). |
| std::string title; |
| // Function (and offset within the function) being displayed. |
| RemoteFunction* function = nullptr; |
| int bytecode_offset = 0; |
| // Set to a bytecode offset to have the document focus there. |
| absl::optional<int> focus_offset; |
| // Cached info for bytecode display. |
| struct { |
| std::vector<std::string> lines; |
| } bytecode_info; |
| }; |
| |
| CodeViewDocument* FindMatchingDocument(absl::string_view module_name, |
| int function_ordinal); |
| RemoteFiberState* GetSelectedFiberState() const; |
| |
| Status RefreshActiveBreakpoints(); |
| bool IsStoppedAtBreakpoint(const UserBreakpoint& user_breakpoint) const; |
| int FindMatchingUserBreakpointIndex(absl::string_view module_name, |
| int function_ordinal, int offset); |
| int FindMatchingUserBreakpointIndex(absl::string_view module_name, |
| absl::string_view function_name, |
| int offset); |
| Status ResumeFromBreakpoint(UserBreakpoint* user_breakpoint); |
| |
| Status OnContextRegistered(const RemoteContext& context) override; |
| Status OnContextUnregistered(const RemoteContext& context) override; |
| Status OnModuleLoaded(const RemoteContext& context, |
| const RemoteModule& module) override; |
| Status OnFiberRegistered(const RemoteFiberState& fiber_state) override; |
| Status OnFiberUnregistered(const RemoteFiberState& fiber_state) override; |
| Status OnBreakpointHit(const RemoteBreakpoint& breakpoint, |
| const RemoteFiberState& fiber_state) override; |
| |
| Status LayoutInitialDockSpace(); |
| |
| Status DrawUI(); |
| Status DrawMainMenu(); |
| Status DrawToolbar(); |
| |
| Status DrawBreakpointListPanel(); |
| StatusOr<bool> DrawBreakpoint(UserBreakpoint* user_breakpoint); |
| Status DrawAddBreakpointDialogs( |
| absl::optional<RemoteBreakpoint::Type> add_breakpoint_type); |
| Status DrawAddBytecodeFunctionBreakpointDialog(); |
| Status DrawAddNativeFunctionBreakpointDialog(); |
| |
| Status DrawModuleListPanel(); |
| Status DrawContext(const RemoteContext& context, |
| const ImGuiTextFilter& filter); |
| Status DrawModule(RemoteModule* module, const ImGuiTextFilter& filter); |
| |
| Status DrawLocalListPanel(); |
| Status DrawLocal(RemoteFiberState* fiber_state, int stack_frame_index, |
| int local_index, const rpc::BufferViewDefT& local); |
| |
| Status DrawFiberStateListPanel(); |
| Status DrawFiberState(const RemoteFiberState& fiber_state); |
| |
| Status DrawCodeViewPanels(); |
| StatusOr<bool> DrawCodeViewDocument(CodeViewDocument* document); |
| Status PrepareBytecodeCodeView(CodeViewDocument* document); |
| Status DrawBytecodeCodeView(CodeViewDocument* document); |
| |
| SDL_Window* window_ = nullptr; |
| SDL_GLContext gl_context_ = nullptr; |
| |
| ImGuiID dockspace_id_; |
| ImGuiID dock_top_id_; |
| ImGuiID dock_left_id_; |
| ImGuiID dock_bottom_id_; |
| ImGuiID dock_bottom_left_id_; |
| ImGuiID dock_bottom_right_id_; |
| ImGuiID dock_right_id_; |
| ImGuiID dock_content_id_; |
| |
| std::unique_ptr<DebugClient> debug_client_; |
| std::vector<UserBreakpoint> user_breakpoint_list_; |
| |
| bool is_paused_ = false; |
| std::vector<const RemoteBreakpoint*> hit_breakpoints_; |
| bool is_stepping_ = false; |
| |
| absl::optional<int> selected_fiber_state_id_; |
| absl::optional<int> selected_stack_frame_index_; |
| |
| std::vector<std::unique_ptr<CodeViewDocument>> documents_; |
| }; |
| |
| } // namespace debug |
| } // namespace vm |
| } // namespace iree |
| |
| #endif // THIRD_PARTY_MLIR_EDGE_IREE_TOOLS_DEBUGGER_DEBUG_APP_H_ |