• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![](./images/inspector-debugger-sequence.svg)
256