1 /*
2  * Copyright (c) 2021-2022 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.h"
17 
18 #include <chrono>
19 #include <shared_mutex>
20 #if defined(OHOS_PLATFORM)
21 #include <syscall.h>
22 #endif
23 #include <thread>
24 #if defined(OHOS_PLATFORM)
25 #include <unistd.h>
26 #endif
27 #include <unordered_map>
28 
29 #include "common/log_wrapper.h"
30 #include "library_loader.h"
31 
32 #if defined(IOS_PLATFORM)
33 #include "tooling/debugger_service.h"
34 #endif
35 
36 #if defined(ENABLE_FFRT_INTERFACES)
37 #include "ffrt.h"
38 #endif
39 
40 namespace OHOS::ArkCompiler::Toolchain {
41 namespace {
42 enum DispatchStatus : int32_t {
43     UNKNOWN = 0,
44     DISPATCHING,
45     DISPATCHED
46 };
47 
48 using InitializeDebugger = void(*)(void*, const std::function<void(const void*, const std::string&)>&);
49 using UninitializeDebugger = void(*)(void*);
50 using WaitForDebugger = void(*)(void*);
51 using OnMessage = void(*)(void*, std::string&&);
52 using ProcessMessage = void(*)(void*);
53 using GetDispatchStatus = int32_t(*)(void*);
54 
55 OnMessage g_onMessage = nullptr;
56 InitializeDebugger g_initializeDebugger = nullptr;
57 UninitializeDebugger g_uninitializeDebugger = nullptr;
58 WaitForDebugger g_waitForDebugger = nullptr;
59 ProcessMessage g_processMessage = nullptr;
60 GetDispatchStatus g_getDispatchStatus = nullptr;
61 
62 std::atomic<bool> g_hasArkFuncsInited = false;
63 std::unordered_map<const void*, Inspector*> g_inspectors;
64 std::unordered_map<int, std::pair<void*, const DebuggerPostTask>> g_debuggerInfo;
65 std::shared_mutex g_mutex;
66 
67 #if !defined(IOS_PLATFORM)
68 thread_local void* g_handle = nullptr;
69 #endif
70 thread_local void* g_vm = nullptr;
71 
72 #if !defined(IOS_PLATFORM)
73 #if defined(WINDOWS_PLATFORM)
74 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.dll";
75 #elif defined(MAC_PLATFORM)
76 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.dylib";
77 #else
78 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_tooling.so";
79 #endif
80 #endif
81 
HandleClient(void* const server)82 void* HandleClient(void* const server)
83 {
84     LOGI("HandleClient");
85     if (server == nullptr) {
86         LOGE("HandleClient server nullptr");
87         return nullptr;
88     }
89 
90 #if defined(IOS_PLATFORM) || defined(MAC_PLATFORM)
91     pthread_setname_np("OS_DebugThread");
92 #else
93     pthread_setname_np(pthread_self(), "OS_DebugThread");
94 #endif
95 
96     static_cast<WsServer*>(server)->RunServer();
97     return nullptr;
98 }
99 
100 #if !defined(IOS_PLATFORM)
LoadArkDebuggerLibrary()101 bool LoadArkDebuggerLibrary()
102 {
103     if (g_handle != nullptr) {
104         LOGI("LoadArkDebuggerLibrary, handle has already loaded");
105         return true;
106     }
107     g_handle = Load(ARK_DEBUGGER_SHARED_LIB);
108     if (g_handle == nullptr) {
109         LOGE("LoadArkDebuggerLibrary, handle load failed");
110         return false;
111     }
112     return true;
113 }
114 
GetArkDynFunction(const char* symbol)115 void* GetArkDynFunction(const char* symbol)
116 {
117     return ResolveSymbol(g_handle, symbol);
118 }
119 #endif
120 
SendReply(const void* vm, const std::string& message)121 void SendReply(const void* vm, const std::string& message)
122 {
123     std::shared_lock<std::shared_mutex> lock(g_mutex);
124     auto iter = g_inspectors.find(vm);
125     if (iter != g_inspectors.end() && iter->second != nullptr &&
126         iter->second->websocketServer_ != nullptr) {
127         iter->second->websocketServer_->SendReply(message);
128     }
129 }
130 
ResetServiceLocked(void *vm, bool isCloseHandle)131 void ResetServiceLocked(void *vm, bool isCloseHandle)
132 {
133     auto iter = g_inspectors.find(vm);
134     if (iter != g_inspectors.end() && iter->second != nullptr &&
135         iter->second->websocketServer_ != nullptr) {
136         iter->second->websocketServer_->StopServer();
137         delete iter->second;
138         iter->second = nullptr;
139         g_inspectors.erase(iter);
140     }
141 #if !defined(IOS_PLATFORM)
142     if (g_handle != nullptr && isCloseHandle) {
143         CloseHandle(g_handle);
144         g_handle = nullptr;
145     }
146 #endif
147 }
148 
InitializeInspector( void* vm, const DebuggerPostTask& debuggerPostTask, const DebugInfo& debugInfo, int tidForSocketPair = 0)149 bool InitializeInspector(
150     void* vm, const DebuggerPostTask& debuggerPostTask, const DebugInfo& debugInfo, int tidForSocketPair = 0)
151 {
152     std::unique_lock<std::shared_mutex> lock(g_mutex);
153     auto iter = g_inspectors.find(vm);
154     if (iter != g_inspectors.end()) {
155         LOGW("Inspector already exist!");
156         return true;
157     }
158 
159     Inspector *newInspector = new Inspector();
160     g_inspectors.emplace(vm, newInspector);
161 
162     newInspector->tidForSocketPair_ = tidForSocketPair;
163     newInspector->tid_ = pthread_self();
164     newInspector->vm_ = vm;
165     newInspector->debuggerPostTask_ = debuggerPostTask;
166     newInspector->websocketServer_ = std::make_unique<WsServer>(debugInfo,
167         std::bind(&Inspector::OnMessage, newInspector, std::placeholders::_1));
168 
169     pthread_t tid;
170     if (pthread_create(&tid, nullptr, &HandleClient, static_cast<void *>(
171         newInspector->websocketServer_.get())) != 0) {
172         LOGE("Create inspector thread failed");
173         return false;
174     }
175     newInspector->websocketServer_->tid_ = tid;
176 
177     return true;
178 }
179 
180 #if !defined(IOS_PLATFORM)
InitializeArkFunctionsOthers()181 bool InitializeArkFunctionsOthers()
182 {
183     g_initializeDebugger = reinterpret_cast<InitializeDebugger>(
184         GetArkDynFunction("InitializeDebugger"));
185     if (g_initializeDebugger == nullptr) {
186         ResetServiceLocked(g_vm, true);
187         return false;
188     }
189     g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(
190         GetArkDynFunction("UninitializeDebugger"));
191     if (g_uninitializeDebugger == nullptr) {
192         ResetServiceLocked(g_vm, true);
193         return false;
194     }
195     g_waitForDebugger = reinterpret_cast<WaitForDebugger>(
196         GetArkDynFunction("WaitForDebugger"));
197     if (g_waitForDebugger == nullptr) {
198         ResetServiceLocked(g_vm, true);
199         return false;
200     }
201     g_onMessage = reinterpret_cast<OnMessage>(
202         GetArkDynFunction("OnMessage"));
203     if (g_onMessage == nullptr) {
204         ResetServiceLocked(g_vm, true);
205         return false;
206     }
207     g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(
208         GetArkDynFunction("GetDispatchStatus"));
209     if (g_getDispatchStatus == nullptr) {
210         ResetServiceLocked(g_vm, true);
211         return false;
212     }
213     g_processMessage = reinterpret_cast<ProcessMessage>(
214         GetArkDynFunction("ProcessMessage"));
215     if (g_processMessage == nullptr) {
216         ResetServiceLocked(g_vm, true);
217         return false;
218     }
219     return true;
220 }
221 #else
InitializeArkFunctionsIOS()222 bool InitializeArkFunctionsIOS()
223 {
224     using namespace panda::ecmascript;
225     g_initializeDebugger = reinterpret_cast<InitializeDebugger>(&tooling::InitializeDebugger);
226     g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(&tooling::UninitializeDebugger);
227     g_waitForDebugger = reinterpret_cast<WaitForDebugger>(&tooling::WaitForDebugger);
228     g_onMessage = reinterpret_cast<OnMessage>(&tooling::OnMessage);
229     g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(&tooling::GetDispatchStatus);
230     g_processMessage = reinterpret_cast<ProcessMessage>(&tooling::ProcessMessage);
231     return true;
232 }
233 #endif
234 
InitializeArkFunctions()235 bool InitializeArkFunctions()
236 {
237     // no need to initialize again in case of multi-instance
238     if (g_hasArkFuncsInited) {
239         return true;
240     }
241 
242     std::unique_lock<std::shared_mutex> lock(g_mutex);
243     if (g_hasArkFuncsInited) {
244         return true;
245     }
246 #if !defined(IOS_PLATFORM)
247     if (!InitializeArkFunctionsOthers()) {
248         return false;
249     }
250 #else
251     InitializeArkFunctionsIOS()
252 #endif
253 
254     g_hasArkFuncsInited = true;
255     return true;
256 }
257 
258 } // namespace
259 
OnMessage(std::string&& msg)260 void Inspector::OnMessage(std::string&& msg)
261 {
262     g_onMessage(vm_, std::move(msg));
263 
264     // message will be processed soon if the debugger thread is in running or waiting status
265     if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
266         return;
267     }
268     std::this_thread::sleep_for(std::chrono::microseconds(DELAY_CHECK_DISPATCH_STATUS));
269     if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
270         return;
271     }
272 
273     // the debugger thread maybe in idle status, so try to post a task to wake it up
274     if (debuggerPostTask_ != nullptr) {
275         if (tidForSocketPair_ == 0) {
276             debuggerPostTask_([tid = tid_, vm = vm_] {
277                 if (tid != pthread_self()) {
278                     LOGE("Task not in debugger thread");
279                     return;
280                 }
281                 g_processMessage(vm);
282             });
283         } else {
284 #if defined(OHOS_PLATFORM)
285             debuggerPostTask_([tid = tidForSocketPair_, vm = vm_, this] {
286                 uint64_t threadOrTaskId = GetThreadOrTaskId();
287                 if (tid != static_cast<pid_t>(threadOrTaskId)) {
288                     LOGE("Task not in debugger thread for socketpair");
289                     return;
290                 }
291                 g_processMessage(vm);
292             });
293 #endif // defined(OHOS_PLATFORM)
294         }
295     } else {
296         LOGW("No debuggerPostTask provided");
297     }
298 }
299 
300 #if defined(OHOS_PLATFORM)
GetThreadOrTaskId()301 uint64_t Inspector::GetThreadOrTaskId()
302 {
303 #if defined(ENABLE_FFRT_INTERFACES)
304     uint64_t threadOrTaskId = ffrt_this_task_get_id();
305     if (threadOrTaskId != 0) {
306         return threadOrTaskId;
307     } else {
308         return static_cast<uint64_t>(getproctid());
309     }
310 #else
311     return static_cast<uint64_t>(getproctid());
312 #endif // defined(ENABLE_FFRT_INTERFACES)
313 }
314 #endif // defined(OHOS_PLATFORM)
315 
GetDebuggerPostTask(int tid)316 const DebuggerPostTask &GetDebuggerPostTask(int tid)
317 {
318     std::shared_lock<std::shared_mutex> lock(g_mutex);
319     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
320         static DebuggerPostTask tempTask;
321         return tempTask;
322     }
323     return g_debuggerInfo[tid].second;
324 }
325 
GetEcmaVM(int tid)326 void *GetEcmaVM(int tid)
327 {
328     std::shared_lock<std::shared_mutex> lock(g_mutex);
329     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
330         return nullptr;
331     }
332     return g_debuggerInfo[tid].first;
333 }
334 
InitializeDebuggerForSocketpair(void* vm)335 bool InitializeDebuggerForSocketpair(void* vm)
336 {
337 #if !defined(IOS_PLATFORM)
338     if (!LoadArkDebuggerLibrary()) {
339         return false;
340     }
341 #endif
342     if (!InitializeArkFunctions()) {
343         LOGE("Initialize ark functions failed");
344         return false;
345     }
346     g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
347     return true;
348 }
349 
350 // for ohos platform.
StartDebugForSocketpair(int tid, int socketfd)351 bool StartDebugForSocketpair(int tid, int socketfd)
352 {
353     LOGI("StartDebugForSocketpair, tid = %{private}d, socketfd = %{private}d", tid, socketfd);
354     void* vm = GetEcmaVM(tid);
355     if (vm == nullptr) {
356         LOGD("VM has already been destroyed");
357         return false;
358     }
359     g_vm = vm;
360     if (!InitializeDebuggerForSocketpair(vm)) {
361         return false;
362     }
363     const DebuggerPostTask &debuggerPostTask = GetDebuggerPostTask(tid);
364     DebugInfo debugInfo = {socketfd};
365     if (!InitializeInspector(vm, debuggerPostTask, debugInfo, tid)) {
366         LOGE("Initialize inspector failed");
367         return false;
368     }
369 
370     return true;
371 }
372 
373 // for cross-platform, previewer and old process of StartDebugger.
StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId, const DebuggerPostTask& debuggerPostTask, int port)374 bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode,
375     int32_t instanceId, const DebuggerPostTask& debuggerPostTask, int port)
376 {
377     LOGI("StartDebug, componentName = %{private}s, isDebugMode = %{private}d, instanceId = %{private}d",
378         componentName.c_str(), isDebugMode, instanceId);
379     g_vm = vm;
380 #if !defined(IOS_PLATFORM)
381     if (!LoadArkDebuggerLibrary()) {
382         return false;
383     }
384 #endif
385     if (!InitializeArkFunctions()) {
386         LOGE("Initialize ark functions failed");
387         return false;
388     }
389 
390     g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
391 
392     int startDebugInOldProcess = -2; // start debug in old process.
393     DebugInfo debugInfo = {startDebugInOldProcess, componentName, instanceId, port};
394     if (!InitializeInspector(vm, debuggerPostTask, debugInfo)) {
395         LOGE("Initialize inspector failed");
396         return false;
397     }
398 
399     if (isDebugMode && port > 0) {
400         LOGI("Wait for debugger for previewer");
401         g_waitForDebugger(vm);
402     }
403     return true;
404 }
405 
WaitForDebugger(void* vm)406 void WaitForDebugger(void* vm)
407 {
408     LOGI("WaitForDebugger");
409     g_waitForDebugger(vm);
410 }
411 
StopDebug(void* vm)412 void StopDebug(void* vm)
413 {
414     LOGI("StopDebug start, vm is %{private}p", vm);
415     std::unique_lock<std::shared_mutex> lock(g_mutex);
416     auto iter = g_inspectors.find(vm);
417     if (iter == g_inspectors.end() || iter->second == nullptr) {
418         return;
419     }
420 #ifdef PANDA_TARGET_MACOS
421     uint32_t tid = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(g_inspectors[vm]->tid_));
422 #else
423     uint32_t tid = g_inspectors[vm]->tid_;
424 #endif
425     auto debuggerInfo = g_debuggerInfo.find(tid);
426     if (debuggerInfo != g_debuggerInfo.end()) {
427         g_debuggerInfo.erase(debuggerInfo);
428     }
429     g_uninitializeDebugger(vm);
430     ResetServiceLocked(vm, true);
431     LOGI("StopDebug end");
432 }
433 
StopOldDebug(int tid, const std::string& componentName)434 void StopOldDebug(int tid, const std::string& componentName)
435 {
436     LOGI("StopDebug start, componentName = %{private}s, tid = %{private}d", componentName.c_str(), tid);
437     void* vm = GetEcmaVM(tid);
438     if (vm == nullptr) {
439         return;
440     }
441     std::unique_lock<std::shared_mutex> lock(g_mutex);
442     auto iter = g_inspectors.find(vm);
443     if (iter == g_inspectors.end() || iter->second == nullptr) {
444         return;
445     }
446 
447     ResetServiceLocked(vm, false);
448     LOGI("StopDebug end");
449 }
450 
451 // for socketpair process.
StoreDebuggerInfo(int tid, void* vm, const DebuggerPostTask& debuggerPostTask)452 void StoreDebuggerInfo(int tid, void* vm, const DebuggerPostTask& debuggerPostTask)
453 {
454     std::unique_lock<std::shared_mutex> lock(g_mutex);
455     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
456         g_debuggerInfo.emplace(tid, std::make_pair(vm, debuggerPostTask));
457     }
458 }
459 } // namespace OHOS::ArkCompiler::Toolchain
460