1# Main parts description 2 3Two big parts, the `Inspector` and `InspectorServer` classes, isolate debugger and server logic respectively. Their brief description follows. 4 5## Inspector 6 7The main class, it is responsible for interoperability with the runtime and managing other modules. It starts a separate server thread to listen to client requests. 8 9The `Inspector` class implements `PtHooks` interface and manages debugger events correspondingly. 10 11`Inspector` uses the following modules. 12 13### DebuggableThread 14 15Represents an application thread being debugged. It encapsulates a `ThreadState` and processes logic of thread suspensions. Threads have the following three levels of suspension: 16 17#### Paused 18 19The thread is paused (`state_.IsPaused()` is `true`) means that a breakpoint was hit, or a step was performed, etc., and the thread should not execute the following instructions until it will be unpaused. 20 21#### Suspended 22 23The thread is suspended (`suspended_` is `true`) means that the thread actually is going to sleep now, but it still can process asynchronous requests to the object repository ([see below](./inspector.md#objectrepository)). 24 25Before and after the suspension (i.e. setting `suspended_` to `true`) the `pre_suspend_` and `post_suspend_` callbacks are called respectively. The latter sends a `Debugger.paused` event in the current implementation of `Inspector`. 26 27The thread could be resumed when still remaining paused. In this case it suspends again. This opportunity is used by the `Touch()` call during new connection processing to notify the client about the thread state (when suspending, the corresponding `Debugger.paused` event is sent). 28 29#### Wait for suspension 30 31When the thread is suspended, the `thread_->Suspend()` call is performed. It increases managed thread's suspension counter. Then, when `thread_->WaitSuspension()` is called, it waits until a resume call will decreases the counter and it becomes zero. 32 33Before and after waiting for suspension `pre_wait_suspension_` and `post_wait_suspension_` callbacks are called respectively. They release and take a read-lock on debugger events processing (in the current implementation of `Inspector`) to allow / disallow new connections processing. 34 35If thread's suspension counter becomes zero, but `suspended_` is still `true`, this means that a request to the object repository was sent. The request is executed, then the counter is increased and the thread is waiting for suspension again. 36 37### ThreadState 38 39An FSM-like state of an application thread. It processes events from the runtime and client requests and decides (due to breakpoints, stepping state etc.) when to pause or unpause the thread. 40 41### ObjectRepository 42 43Makes remote objects corresponding to managed objects (maps managed objects to IDs) and primitives. Also manages fake frame objects. 44 45To store managed objects in a GC-safe manner, `HandleScope` is used. Due to limitation of handle scopes, an object repository could be used only from the corresponding application thread. That's why asynchronous requests to object repositories ([see above](./inspector.md#wait-for-suspension)) were implemented. 46 47An object repository is valid during a pause only. It is destroyed when the thread is resumed, and remote object mapping become invalid. 48 49### DebugInfoCache 50 51The service provides necessary debug info for the application. It caches the info during module loads. 52 53The debug info could be backed by disassembled code to allow debugging when source code is not available. The module tracks fake disassembled source file names to substitute their contents when corresponding source code requests occur. 54 55### Debugger 56 57Inspector utilizes the runtime instrumentation capabilities with the help of a `DebugInterface` object. 58 59## InspectorServer 60 61The class is responsible for communication with client. It wraps the `Server` class and gives a convenient Inspector protocol based API. It hides all Inspector protocol related details inside and translates them to the language of runtime (e.g. session and source IDs). The implementation is pretty straightforward. It uses the following helper modules. 62 63### Server 64 65This provides a low-level JSON-based interface to a connection. 66 67### SessionManager 68 69The module is responsible for translation between runtime threads and Inspector session IDs. 70 71### SourceManager 72 73The class is responsible for translation between source file names and Inspector source file IDs. Also, it keeps track of which session was informed about the ID (so the `InspectorServer` could send the corresponding "Debugger.scriptParsed" message). 74 75# Threading model overview 76 77In the multi-thread version, the two main kinds of threads are considered: 78- The server thread, it is a single thread responsible for processing client requests; 79- Application threads, these are the execution threads of the debuggable application. 80 81The main idea is that the user requests are processed by the server thread, while the debugger events are processed by application threads. This fact is used to simplify provision of thread safety in several places. 82 83For example, in `InspectorServer::CallTargetDetachedFromTarget`, when the server is paused, we are sure that we could safely remove the corresponding thread from the session and source managers. It is because: 84- the server thread sleeps; 85- and we are executing on the corresponding application thread. 86 87So, we do not consider the case, when someone else in Inspector could access the corresponding `PtThread` objects. 88 89Another example is processing of a new connection in `Inspector`. On validation, a write-lock on debugger events processing is held. Then, during the connection open hook, we safely reset debuggable thread states because: 90- we are executing on the server thread; 91- and application threads could not process events due to the aforementioned write-lock. 92 93We do not consider that someone else in Inspector could access the debuggable thread states. 94 95`DebuggableThread`'s safety also actively relies on these assumptions. For example, we do not consider the case of simultaneous calls to `OnSingleStep` and `OnMethodEntry`. Follow the inline comments for more information. 96 97# Diagrams 98 99The diagrams below are split in two parts (`Inspector` and `InspectorServer` perspectives) for simplification. 100 101A single step event and a "Continue to" request are chosen as the most interesting cases. 102 103## Single step event (***an application thread***) 104 105### Inspector perspective 106 107```mermaid 108sequenceDiagram 109 autonumber 110 111 participant InspectorServer 112 participant Inspector 113 participant DebuggableThread 114 participant Debugger 115 participant DebugInfoCache 116 participant ObjectRepository 117 118 Inspector->>+DebuggableThread: OnSingleStep() 119 loop while paused 120 DebuggableThread->>+Inspector: Post-suspend callback 121 Inspector->>+InspectorServer: CallDebuggerPaused() 122 InspectorServer->>+Inspector: Enumerate frames callback 123 Inspector->>+Debugger: EnumerateFrames() 124 loop for each frame 125 Debugger->>+Inspector: Handle frame callback 126 Inspector->>+DebugInfoCache: GetSourceLocation() for frame 127 DebugInfoCache-->>-Inspector: 128 129 Inspector->>+DebugInfoCache: GetLocals() for frame 130 DebugInfoCache-->>-Inspector: 131 132 Inspector->>+ObjectRepository: CreateFrameObject() for frame 133 ObjectRepository-->>-Inspector: 134 135 Inspector->>+InspectorServer: Handle frame callback 136 InspectorServer-->>-Inspector: 137 Inspector-->>-Debugger: 138 end 139 Debugger-->>-Inspector: 140 Inspector-->>-InspectorServer: 141 InspectorServer-->>-Inspector: 142 Inspector-->>-DebuggableThread: 143 144 loop while suspended 145 DebuggableThread->>+Inspector: Pre-wait suspension callback 146 Inspector->>Inspector: Release debugger events lock 147 Inspector-->>-DebuggableThread: 148 149 DebuggableThread->>DebuggableThread: Wait for suspension 150 151 DebuggableThread->>+Inspector: Post-wait suspension callback 152 Inspector->>Inspector: Read-lock debugger events lock 153 Inspector-->>-DebuggableThread: 154 155 DebuggableThread->>DebuggableThread: Process an object repository request, if any 156 end 157 end 158 DebuggableThread-->>-Inspector: 159``` 160 161### InspectorServer perspective 162 163```mermaid 164sequenceDiagram 165 autonumber 166 167 participant Inspector 168 participant InspectorServer 169 participant Server 170 participant SessionManager 171 participant SourceManager 172 173 Inspector->>+InspectorServer: CallDebuggerPaused() 174 InspectorServer->>+SessionManager: GetSessionIdByThread() 175 SessionManager-->>-InspectorServer: 176 177 InspectorServer->>+Server: Call("Debugger.paused") 178 Server->>+InspectorServer: Fill parameters callback 179 InspectorServer->>+Inspector: Enumerate frames callback 180 loop for each frame 181 Inspector->>+InspectorServer: Handle frame callback 182 InspectorServer->>+SourceManager: GetSourceFileId() 183 SourceManager-->>-InspectorServer: 184 InspectorServer-->>-Inspector: 185 end 186 Inspector-->>-InspectorServer: 187 InspectorServer-->>-Server: 188 Server-->>-InspectorServer: 189 InspectorServer-->>-Inspector: 190``` 191 192## "Continue to" request (***the server thread***) 193 194### InspectorServer perspective 195 196```mermaid 197sequenceDiagram 198 autonumber 199 200 participant Inspector 201 participant InspectorServer 202 participant Server 203 participant SessionManager 204 participant SourceManager 205 206 Server->>+InspectorServer: "Debugger.continueToLocation" callback 207 InspectorServer->>+SessionManager: GetThreadBySessionId() 208 SessionManager-->>-InspectorServer: 209 210 InspectorServer->>+SourceManager: GetSourceFileName() 211 SourceManager-->>-InspectorServer: 212 213 InspectorServer->>+Inspector: ContinueToLocation() 214 Inspector->>+InspectorServer: CallDebuggerResumed() 215 InspectorServer->>+SessionManager: GetSessionIdByThread() 216 SessionManager-->>-InspectorServer: 217 218 InspectorServer->>+Server: Call("Debugger.resumed") 219 Server-->>-InspectorServer: 220 InspectorServer-->>-Inspector: 221 Inspector-->>-InspectorServer: 222 InspectorServer-->>-Server: 223``` 224 225### Inspector perspective 226 227```mermaid 228sequenceDiagram 229 autonumber 230 231 participant InspectorServer 232 participant Inspector 233 participant DebuggableThread 234 participant DebugInfoCache 235 236 InspectorServer->>+Inspector: ContinueToLocation() 237 Inspector->>+DebugInfoCache: GetContinueToLocations() 238 DebugInfoCache-->>-Inspector: 239 240 Inspector->>+DebuggableThread: ContinueTo() 241 DebuggableThread->>DebuggableThread: Resume managed thread 242 243 DebuggableThread->>+Inspector: Post-resume callback 244 Inspector->>+InspectorServer: CallDebuggerResumed() 245 InspectorServer-->>-Inspector: 246 Inspector-->>-DebuggableThread: 247 DebuggableThread-->>-Inspector: 248 Inspector-->>-InspectorServer: 249``` 250 251## Runtime perspective 252 253The diagram below represents high-level scheme of communication between ArkTS Runtime and Inspector debugger. 254 255 256