1 /**
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "inspector_server.h"
17
18 #include "connection/server.h"
19 #include "types/location.h"
20 #include "types/numeric_id.h"
21
22 #include "console_call_type.h"
23 #include "macros.h"
24 #include "tooling/pt_thread.h"
25 #include "utils/json_builder.h"
26 #include "utils/json_parser.h"
27 #include "utils/logger.h"
28
29 #include <functional>
30 #include <regex>
31 #include <string>
32 #include <utility>
33
34 namespace ark::tooling::inspector {
InspectorServer(Server & server)35 InspectorServer::InspectorServer(Server &server) : server_(server)
36 {
37 server_.OnCall("Debugger.enable", [](auto, auto &result, auto &) { result.AddProperty("debuggerId", "debugger"); });
38 }
39
Kill()40 void InspectorServer::Kill()
41 {
42 server_.Kill();
43 }
44
Run()45 void InspectorServer::Run()
46 {
47 server_.Run();
48 }
49
OnValidate(std::function<void ()> && handler)50 void InspectorServer::OnValidate(std::function<void()> &&handler)
51 {
52 server_.OnValidate([handler = std::move(handler)]() {
53 // Pause debugger events processing
54 handler();
55
56 // At this point, the whole messaging is stopped due to:
57 // - Debugger events are not processed by the inspector after the call above;
58 // - Client messages are not processed as we are executing on the server thread.
59 });
60 }
61
OnOpen(std::function<void ()> && handler)62 void InspectorServer::OnOpen(std::function<void()> &&handler)
63 {
64 server_.OnOpen([this, handler = std::move(handler)]() {
65 // A new connection is open, reinitialize the state
66 sessionManager_.EnumerateSessions([this](auto &id, auto thread) {
67 sourceManager_.RemoveThread(thread);
68 if (!id.empty()) {
69 SendTargetAttachedToTarget(id);
70 }
71 });
72
73 // Resume debugger events processing
74 handler();
75 });
76 }
77
OnFail(std::function<void ()> && handler)78 void InspectorServer::OnFail(std::function<void()> &&handler)
79 {
80 server_.OnFail([handler = std::move(handler)]() {
81 // Resume debugger events processing
82 handler();
83 });
84 }
85
CallDebuggerPaused(PtThread thread,const std::vector<BreakpointId> & hitBreakpoints,const std::optional<RemoteObject> & exception,const std::function<void (const FrameInfoHandler &)> & enumerateFrames)86 void InspectorServer::CallDebuggerPaused(PtThread thread, const std::vector<BreakpointId> &hitBreakpoints,
87 const std::optional<RemoteObject> &exception,
88 const std::function<void(const FrameInfoHandler &)> &enumerateFrames)
89 {
90 auto sessionId = sessionManager_.GetSessionIdByThread(thread);
91
92 server_.Call(sessionId, "Debugger.paused", [&](auto ¶ms) {
93 params.AddProperty("callFrames", [this, thread, &enumerateFrames](JsonArrayBuilder &callFrames) {
94 EnumerateCallFrames(callFrames, thread, enumerateFrames);
95 });
96
97 params.AddProperty("hitBreakpoints", [&hitBreakpoints](JsonArrayBuilder &hitBreakpointsBuilder) {
98 AddHitBreakpoints(hitBreakpointsBuilder, hitBreakpoints);
99 });
100
101 if (exception) {
102 params.AddProperty("data", exception->ToJson());
103 }
104
105 params.AddProperty("reason", exception.has_value() ? "exception" : "other");
106 });
107 }
108
CallDebuggerResumed(PtThread thread)109 void InspectorServer::CallDebuggerResumed(PtThread thread)
110 {
111 server_.Call(sessionManager_.GetSessionIdByThread(thread), "Debugger.resumed");
112 }
113
CallDebuggerScriptParsed(PtThread thread,ScriptId scriptId,std::string_view sourceFile)114 void InspectorServer::CallDebuggerScriptParsed(PtThread thread, ScriptId scriptId, std::string_view sourceFile)
115 {
116 auto sessionId = sessionManager_.GetSessionIdByThread(thread);
117 server_.Call(sessionId, "Debugger.scriptParsed", [&sourceFile, &thread, &scriptId](auto ¶ms) {
118 params.AddProperty("executionContextId", thread.GetId());
119 params.AddProperty("scriptId", std::to_string(scriptId));
120 params.AddProperty("url", sourceFile.data());
121 params.AddProperty("startLine", 0);
122 params.AddProperty("startColumn", 0);
123 params.AddProperty("endLine", std::numeric_limits<int>::max());
124 params.AddProperty("endColumn", std::numeric_limits<int>::max());
125 params.AddProperty("hash", "");
126 });
127 }
128
CallRuntimeConsoleApiCalled(PtThread thread,ConsoleCallType type,uint64_t timestamp,const std::vector<RemoteObject> & arguments)129 void InspectorServer::CallRuntimeConsoleApiCalled(PtThread thread, ConsoleCallType type, uint64_t timestamp,
130 const std::vector<RemoteObject> &arguments)
131 {
132 auto sessionId = sessionManager_.GetSessionIdByThread(thread);
133
134 server_.Call(sessionId, "Runtime.consoleAPICalled", [&](auto ¶ms) {
135 params.AddProperty("executionContextId", thread.GetId());
136 params.AddProperty("timestamp", timestamp);
137
138 switch (type) {
139 case ConsoleCallType::LOG:
140 params.AddProperty("type", "log");
141 break;
142 case ConsoleCallType::DEBUG:
143 params.AddProperty("type", "debug");
144 break;
145 case ConsoleCallType::INFO:
146 params.AddProperty("type", "info");
147 break;
148 case ConsoleCallType::ERROR:
149 params.AddProperty("type", "error");
150 break;
151 case ConsoleCallType::WARNING:
152 params.AddProperty("type", "warning");
153 break;
154 default:
155 UNREACHABLE();
156 }
157
158 params.AddProperty("args", [&](JsonArrayBuilder &argsBuilder) {
159 for (const auto &argument : arguments) {
160 argsBuilder.Add(argument.ToJson());
161 }
162 });
163 });
164 }
165
CallRuntimeExecutionContextCreated(PtThread thread)166 void InspectorServer::CallRuntimeExecutionContextCreated(PtThread thread)
167 {
168 auto sessionId = sessionManager_.GetSessionIdByThread(thread);
169
170 std::string name;
171 if (thread != PtThread::NONE) {
172 name = "Thread #" + std::to_string(thread.GetId());
173 }
174
175 server_.Call(sessionId, "Runtime.executionContextCreated", [&](auto ¶ms) {
176 params.AddProperty("context", [&](JsonObjectBuilder &context) {
177 context.AddProperty("id", thread.GetId());
178 context.AddProperty("origin", "");
179 context.AddProperty("name", name);
180 context.AddProperty("uniqueId", GetExecutionContextUniqueId(thread));
181 });
182 });
183 }
184
CallRuntimeExecutionContextsCleared()185 void InspectorServer::CallRuntimeExecutionContextsCleared()
186 {
187 server_.Call("Runtime.executionContextsCleared");
188 }
189
CallTargetAttachedToTarget(PtThread thread)190 void InspectorServer::CallTargetAttachedToTarget(PtThread thread)
191 {
192 auto &sessionId = sessionManager_.AddSession(thread);
193 if (!sessionId.empty()) {
194 SendTargetAttachedToTarget(sessionId);
195 }
196 }
197
CallTargetDetachedFromTarget(PtThread thread)198 void InspectorServer::CallTargetDetachedFromTarget(PtThread thread)
199 {
200 auto sessionId = sessionManager_.GetSessionIdByThread(thread);
201
202 // Pause the server thread to ensure that there will be no dangling PtThreads
203 server_.Pause();
204
205 sessionManager_.RemoveSession(sessionId);
206 sourceManager_.RemoveThread(thread);
207
208 // Now no one will retrieve the detached thread from the sessions manager
209 server_.Continue();
210
211 if (!sessionId.empty()) {
212 server_.Call("Target.detachedFromTarget",
213 [&sessionId](auto ¶ms) { params.AddProperty("session_id", sessionId); });
214 }
215 }
216
OnCallDebuggerContinueToLocation(std::function<void (PtThread,std::string_view,size_t)> && handler)217 void InspectorServer::OnCallDebuggerContinueToLocation(
218 std::function<void(PtThread, std::string_view, size_t)> &&handler)
219 {
220 server_.OnCall(
221 "Debugger.continueToLocation", [this, handler = std::move(handler)](auto &sessionId, auto &, auto ¶ms) {
222 auto location = Location::FromJsonProperty(params, "location");
223 if (!location) {
224 LOG(INFO, DEBUGGER) << location.Error();
225 return;
226 }
227
228 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
229
230 handler(thread, sourceManager_.GetSourceFileName(location->GetScriptId()), location->GetLineNumber());
231 });
232 }
233
OnCallDebuggerGetPossibleBreakpoints(std::function<std::set<size_t> (std::string_view,size_t,size_t,bool)> && handler)234 void InspectorServer::OnCallDebuggerGetPossibleBreakpoints(
235 std::function<std::set<size_t>(std::string_view, size_t, size_t, bool)> &&handler)
236 {
237 // clang-format off
238 server_.OnCall("Debugger.getPossibleBreakpoints",
239 [this, handler = std::move(handler)](auto &, auto &result, const JsonObject ¶ms) {
240 auto start = Location::FromJsonProperty(params, "start");
241 if (!start) {
242 LOG(INFO, DEBUGGER) << start.Error();
243 return;
244 }
245
246 auto scriptId = start->GetScriptId();
247
248 size_t endLine = ~0U;
249 if (auto end = Location::FromJsonProperty(params, "end")) {
250 if (end->GetScriptId() != scriptId) {
251 LOG(INFO, DEBUGGER) << "Script ids don't match";
252 return;
253 }
254
255 endLine = end->GetLineNumber();
256 }
257
258 bool restrictToFunction = false;
259 if (auto prop = params.GetValue<JsonObject::BoolT>("restrictToFunction")) {
260 restrictToFunction = *prop;
261 }
262
263 auto lineNumbers = handler(sourceManager_.GetSourceFileName(scriptId), start->GetLineNumber(),
264 endLine, restrictToFunction);
265
266 result.AddProperty("locations", [scriptId, &lineNumbers](JsonArrayBuilder &array) {
267 for (auto lineNumber : lineNumbers) {
268 array.Add(Location(scriptId, lineNumber).ToJson());
269 }
270 });
271 });
272 // clang-format on
273 }
274
OnCallDebuggerGetScriptSource(std::function<std::string (std::string_view)> && handler)275 void InspectorServer::OnCallDebuggerGetScriptSource(std::function<std::string(std::string_view)> &&handler)
276 {
277 server_.OnCall("Debugger.getScriptSource",
278 [this, handler = std::move(handler)](auto &, auto &result, auto ¶ms) {
279 if (auto scriptId = ParseNumericId<ScriptId>(params, "scriptId")) {
280 auto sourceFile = sourceManager_.GetSourceFileName(*scriptId);
281 result.AddProperty("scriptSource", handler(sourceFile));
282 } else {
283 LOG(INFO, DEBUGGER) << scriptId.Error();
284 }
285 });
286 }
287
OnCallDebuggerPause(std::function<void (PtThread)> && handler)288 void InspectorServer::OnCallDebuggerPause(std::function<void(PtThread)> &&handler)
289 {
290 server_.OnCall("Debugger.pause", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
291 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
292 handler(thread);
293 });
294 }
295
OnCallDebuggerRemoveBreakpoint(std::function<void (PtThread,BreakpointId)> && handler)296 void InspectorServer::OnCallDebuggerRemoveBreakpoint(std::function<void(PtThread, BreakpointId)> &&handler)
297 {
298 server_.OnCall("Debugger.removeBreakpoint",
299 [this, handler = std::move(handler)](auto &sessionId, auto &, auto ¶ms) {
300 if (auto breakpointId = ParseNumericId<BreakpointId>(params, "breakpointId")) {
301 handler(sessionManager_.GetThreadBySessionId(sessionId), *breakpointId);
302 } else {
303 LOG(INFO, DEBUGGER) << breakpointId.Error();
304 }
305 });
306 }
307
OnCallDebuggerRestartFrame(std::function<void (PtThread,FrameId)> && handler)308 void InspectorServer::OnCallDebuggerRestartFrame(std::function<void(PtThread, FrameId)> &&handler)
309 {
310 // clang-format off
311 server_.OnCall("Debugger.restartFrame",
312 [this, handler = std::move(handler)](auto &sessionId, auto &result, auto ¶ms) {
313 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
314
315 auto frameId = ParseNumericId<FrameId>(params, "callFrameId");
316 if (!frameId) {
317 LOG(INFO, DEBUGGER) << frameId.Error();
318 return;
319 }
320
321 handler(thread, *frameId);
322
323 result.AddProperty("callFrames", [](JsonArrayBuilder &) {});
324 });
325 // clang-format on
326 }
327
OnCallDebuggerResume(std::function<void (PtThread)> && handler)328 void InspectorServer::OnCallDebuggerResume(std::function<void(PtThread)> &&handler)
329 {
330 server_.OnCall("Debugger.resume", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
331 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
332 handler(thread);
333 });
334 }
335
OnCallDebuggerSetBreakpoint(std::function<std::optional<BreakpointId> (PtThread,const std::function<bool (std::string_view)> &,size_t,std::set<std::string_view> &)> && handler)336 void InspectorServer::OnCallDebuggerSetBreakpoint(
337 std::function<std::optional<BreakpointId>(PtThread, const std::function<bool(std::string_view)> &, size_t,
338 std::set<std::string_view> &)> &&handler)
339 {
340 // clang-format off
341 server_.OnCall("Debugger.setBreakpoint",
342 [this, handler = std::move(handler)](auto &sessionId, auto &result, auto ¶ms) {
343 auto location = Location::FromJsonProperty(params, "location");
344 if (!location) {
345 LOG(INFO, DEBUGGER) << location.Error();
346 return;
347 }
348
349 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
350
351 auto sourceFile = sourceManager_.GetSourceFileName(location->GetScriptId());
352 std::set<std::string_view> sourceFiles;
353
354 auto id = handler(
355 thread, [sourceFile](auto fileName) { return fileName == sourceFile; },
356 location->GetLineNumber(), sourceFiles);
357 if (!id) {
358 LOG(INFO, DEBUGGER) << "Failed to set breakpoint";
359 return;
360 }
361
362 result.AddProperty("breakpointId", std::to_string(*id));
363 result.AddProperty("actualLocation", location->ToJson());
364 });
365 // clang-format on
366 }
367
OnCallDebuggerSetBreakpointByUrl(std::function<std::optional<BreakpointId> (PtThread,const std::function<bool (std::string_view)> &,size_t,std::set<std::string_view> &)> && handler)368 void InspectorServer::OnCallDebuggerSetBreakpointByUrl(
369 std::function<std::optional<BreakpointId>(PtThread, const std::function<bool(std::string_view)> &, size_t,
370 std::set<std::string_view> &)> &&handler)
371 {
372 server_.OnCall("Debugger.setBreakpointByUrl", [this, handler = std::move(handler)](auto &sessionId, auto &result,
373 const JsonObject ¶ms) {
374 size_t lineNumber;
375 if (auto prop = params.GetValue<JsonObject::NumT>("lineNumber")) {
376 lineNumber = *prop + 1;
377 } else {
378 LOG(INFO, DEBUGGER) << "No 'lineNumber' property";
379 return;
380 }
381
382 std::function<bool(std::string_view)> sourceFileFilter;
383 if (auto url = params.GetValue<JsonObject::StringT>("url")) {
384 sourceFileFilter = [sourceFile = url->find("file://") == 0 ? url->substr(std::strlen("file://")) : *url](
385 auto fileName) { return fileName == sourceFile; };
386 } else if (auto urlRegex = params.GetValue<JsonObject::StringT>("urlRegex")) {
387 sourceFileFilter = [regex = std::regex(*urlRegex)](auto fileName) {
388 return std::regex_match(fileName.data(), regex);
389 };
390 } else {
391 LOG(INFO, DEBUGGER) << "No 'url' or 'urlRegex' properties";
392 return;
393 }
394
395 std::set<std::string_view> sourceFiles;
396 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
397
398 auto id = handler(thread, sourceFileFilter, lineNumber, sourceFiles);
399 if (!id) {
400 LOG(INFO, DEBUGGER) << "Failed to set breakpoint";
401 return;
402 }
403
404 result.AddProperty("breakpointId", std::to_string(*id));
405 result.AddProperty("locations", [this, lineNumber, &sourceFiles, thread](JsonArrayBuilder &locations) {
406 AddBreakpointByUrlLocations(locations, sourceFiles, lineNumber, thread);
407 });
408 });
409 }
410
OnCallDebuggerSetBreakpointsActive(std::function<void (PtThread,bool)> && handler)411 void InspectorServer::OnCallDebuggerSetBreakpointsActive(std::function<void(PtThread, bool)> &&handler)
412 {
413 // clang-format off
414 server_.OnCall("Debugger.setBreakpointsActive",
415 [this, handler = std::move(handler)](auto &sessionId, auto &, const JsonObject ¶ms) {
416 bool active;
417 if (auto prop = params.GetValue<JsonObject::BoolT>("active")) {
418 active = *prop;
419 } else {
420 LOG(INFO, DEBUGGER) << "No 'active' property";
421 return;
422 }
423
424 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
425 handler(thread, active);
426 });
427 // clang-format on
428 }
429
OnCallDebuggerSetPauseOnExceptions(std::function<void (PtThread,PauseOnExceptionsState)> && handler)430 void InspectorServer::OnCallDebuggerSetPauseOnExceptions(
431 std::function<void(PtThread, PauseOnExceptionsState)> &&handler)
432 {
433 // clang-format off
434 server_.OnCall("Debugger.setPauseOnExceptions",
435 [this, handler = std::move(handler)](auto &sessionId, auto &, const JsonObject ¶ms) {
436 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
437
438 PauseOnExceptionsState state;
439 auto stateStr = params.GetValue<JsonObject::StringT>("state");
440 if (stateStr == nullptr) {
441 LOG(INFO, DEBUGGER) << "No 'state' property";
442 return;
443 }
444
445 if (*stateStr == "none") {
446 state = PauseOnExceptionsState::NONE;
447 } else if (*stateStr == "caught") {
448 state = PauseOnExceptionsState::CAUGHT;
449 } else if (*stateStr == "uncaught") {
450 state = PauseOnExceptionsState::UNCAUGHT;
451 } else if (*stateStr == "all") {
452 state = PauseOnExceptionsState::ALL;
453 } else {
454 LOG(INFO, DEBUGGER) << "Invalid 'state' value: " << *stateStr;
455 return;
456 }
457
458 handler(thread, state);
459 });
460 // clang-format on
461 }
462
OnCallDebuggerStepInto(std::function<void (PtThread)> && handler)463 void InspectorServer::OnCallDebuggerStepInto(std::function<void(PtThread)> &&handler)
464 {
465 server_.OnCall("Debugger.stepInto", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
466 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
467 handler(thread);
468 });
469 }
470
OnCallDebuggerStepOut(std::function<void (PtThread)> && handler)471 void InspectorServer::OnCallDebuggerStepOut(std::function<void(PtThread)> &&handler)
472 {
473 server_.OnCall("Debugger.stepOut", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
474 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
475 handler(thread);
476 });
477 }
478
OnCallDebuggerStepOver(std::function<void (PtThread)> && handler)479 void InspectorServer::OnCallDebuggerStepOver(std::function<void(PtThread)> &&handler)
480 {
481 server_.OnCall("Debugger.stepOver", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
482 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
483 handler(thread);
484 });
485 }
486
OnCallRuntimeEnable(std::function<void (PtThread)> && handler)487 void InspectorServer::OnCallRuntimeEnable(std::function<void(PtThread)> &&handler)
488 {
489 server_.OnCall("Runtime.enable", [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
490 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
491 handler(thread);
492 });
493 }
494
OnCallRuntimeGetProperties(std::function<std::vector<PropertyDescriptor> (PtThread,RemoteObjectId,bool)> && handler)495 void InspectorServer::OnCallRuntimeGetProperties(
496 std::function<std::vector<PropertyDescriptor>(PtThread, RemoteObjectId, bool)> &&handler)
497 {
498 // clang-format off
499 server_.OnCall("Runtime.getProperties",
500 [this, handler = std::move(handler)](auto &sessionId, auto &result, const JsonObject ¶ms) {
501 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
502
503 auto objectId = ParseNumericId<RemoteObjectId>(params, "objectId");
504 if (!objectId) {
505 LOG(INFO, DEBUGGER) << objectId.Error();
506 return;
507 }
508
509 auto generatePreview = false;
510 if (auto prop = params.GetValue<JsonObject::BoolT>("generatePreview")) {
511 generatePreview = *prop;
512 }
513
514 result.AddProperty("result", [&](JsonArrayBuilder &array) {
515 for (auto &descriptor : handler(thread, *objectId, generatePreview)) {
516 array.Add(descriptor.ToJson());
517 }
518 });
519 });
520 // clang-format on
521 }
522
OnCallRuntimeRunIfWaitingForDebugger(std::function<void (PtThread)> && handler)523 void InspectorServer::OnCallRuntimeRunIfWaitingForDebugger(std::function<void(PtThread)> &&handler)
524 {
525 server_.OnCall("Runtime.runIfWaitingForDebugger",
526 [this, handler = std::move(handler)](auto &sessionId, auto &, auto &) {
527 auto thread = sessionManager_.GetThreadBySessionId(sessionId);
528 handler(thread);
529 });
530 }
531
SendTargetAttachedToTarget(const std::string & sessionId)532 void InspectorServer::SendTargetAttachedToTarget(const std::string &sessionId)
533 {
534 server_.Call("Target.attachedToTarget", [&sessionId](auto ¶ms) {
535 params.AddProperty("sessionId", sessionId);
536 params.AddProperty("targetInfo", [&sessionId](JsonObjectBuilder &targetInfo) {
537 targetInfo.AddProperty("targetId", sessionId);
538 targetInfo.AddProperty("type", "worker");
539 targetInfo.AddProperty("title", sessionId);
540 targetInfo.AddProperty("url", "");
541 targetInfo.AddProperty("attached", true);
542 targetInfo.AddProperty("canAccessOpener", false);
543 });
544 params.AddProperty("waitingForDebugger", true);
545 });
546 }
547
EnumerateCallFrames(JsonArrayBuilder & callFrames,PtThread thread,const std::function<void (const FrameInfoHandler &)> & enumerateFrames)548 void InspectorServer::EnumerateCallFrames(JsonArrayBuilder &callFrames, PtThread thread,
549 const std::function<void(const FrameInfoHandler &)> &enumerateFrames)
550 {
551 enumerateFrames([this, thread, &callFrames](auto frameId, auto methodName, auto sourceFile, auto lineNumber,
552 auto &scopeChain, auto &objThis) {
553 CallFrameInfo callFrameInfo {frameId, sourceFile, methodName, lineNumber};
554 AddCallFrameInfo(callFrames, callFrameInfo, scopeChain, thread, objThis);
555 });
556 }
557
AddCallFrameInfo(JsonArrayBuilder & callFrames,const CallFrameInfo & callFrameInfo,const std::vector<Scope> & scopeChain,PtThread thread,const std::optional<RemoteObject> & objThis)558 void InspectorServer::AddCallFrameInfo(JsonArrayBuilder &callFrames, const CallFrameInfo &callFrameInfo,
559 const std::vector<Scope> &scopeChain, PtThread thread,
560 const std::optional<RemoteObject> &objThis)
561 {
562 callFrames.Add([&](JsonObjectBuilder &callFrame) {
563 auto [scriptId, isNew] = sourceManager_.GetScriptId(thread, callFrameInfo.sourceFile);
564
565 if (isNew) {
566 CallDebuggerScriptParsed(thread, scriptId, callFrameInfo.sourceFile);
567 }
568
569 callFrame.AddProperty("callFrameId", std::to_string(callFrameInfo.frameId));
570 callFrame.AddProperty("functionName", callFrameInfo.methodName.data());
571 callFrame.AddProperty("location", Location(scriptId, callFrameInfo.lineNumber).ToJson());
572 callFrame.AddProperty("url", callFrameInfo.sourceFile.data());
573
574 callFrame.AddProperty("scopeChain", [&](JsonArrayBuilder &scopeChainBuilder) {
575 for (auto &scope : scopeChain) {
576 scopeChainBuilder.Add(scope.ToJson());
577 }
578 });
579
580 callFrame.AddProperty("this", objThis.value_or(RemoteObject::Undefined()).ToJson());
581 callFrame.AddProperty("canBeRestarted", true);
582 });
583 }
584
AddBreakpointByUrlLocations(JsonArrayBuilder & locations,const std::set<std::string_view> & sourceFiles,size_t lineNumber,PtThread thread)585 void InspectorServer::AddBreakpointByUrlLocations(JsonArrayBuilder &locations,
586 const std::set<std::string_view> &sourceFiles, size_t lineNumber,
587 PtThread thread)
588 {
589 for (auto sourceFile : sourceFiles) {
590 locations.Add([this, lineNumber, thread, sourceFile](JsonObjectBuilder &location) {
591 auto [scriptId, isNew] = sourceManager_.GetScriptId(thread, sourceFile);
592
593 if (isNew) {
594 CallDebuggerScriptParsed(thread, scriptId, sourceFile);
595 }
596
597 Location(scriptId, lineNumber).ToJson()(location);
598 });
599 }
600 }
601
602 /* static */
AddHitBreakpoints(JsonArrayBuilder & hitBreakpointsBuilder,const std::vector<BreakpointId> & hitBreakpoints)603 void InspectorServer::AddHitBreakpoints(JsonArrayBuilder &hitBreakpointsBuilder,
604 const std::vector<BreakpointId> &hitBreakpoints)
605 {
606 for (auto id : hitBreakpoints) {
607 hitBreakpointsBuilder.Add(std::to_string(id));
608 }
609 }
610
611 /* static */
GetExecutionContextUniqueId(const PtThread & thread)612 std::string InspectorServer::GetExecutionContextUniqueId(const PtThread &thread)
613 {
614 static int pid = os::thread::GetPid();
615 std::stringstream ss;
616 ss << pid << ':' << thread.GetId();
617 return ss.str();
618 }
619 } // namespace ark::tooling::inspector
620