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 #include <thread>
21 #include <unordered_map>
22
23 #include "log_wrapper.h"
24 #include "library_loader.h"
25
26 #if defined(IOS_PLATFORM)
27 #include "tooling/debugger_service.h"
28 #endif
29
30 namespace OHOS::ArkCompiler::Toolchain {
31 namespace {
32 enum DispatchStatus : int32_t {
33 UNKNOWN = 0,
34 DISPATCHING,
35 DISPATCHED
36 };
37
38 using InitializeDebugger = void(*)(void*, const std::function<void(const void*, const std::string&)>&);
39 using UninitializeDebugger = void(*)(void*);
40 using WaitForDebugger = void(*)(void*);
41 using OnMessage = void(*)(void*, std::string&&);
42 using ProcessMessage = void(*)(void*);
43 using GetDispatchStatus = int32_t(*)(void*);
44
45 OnMessage g_onMessage = nullptr;
46 InitializeDebugger g_initializeDebugger = nullptr;
47 UninitializeDebugger g_uninitializeDebugger = nullptr;
48 WaitForDebugger g_waitForDebugger = nullptr;
49 ProcessMessage g_processMessage = nullptr;
50 GetDispatchStatus g_getDispatchStatus = nullptr;
51
52 std::atomic<bool> g_hasArkFuncsInited = false;
53 std::unordered_map<const void*, Inspector*> g_inspectors;
54 std::shared_mutex g_mutex;
55
56 #if !defined(IOS_PLATFORM)
57 thread_local void* g_handle = nullptr;
58 #endif
59 thread_local void* g_vm = nullptr;
60
61 #if !defined(IOS_PLATFORM)
62 #if defined(WINDOWS_PLATFORM)
63 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dll";
64 #elif defined(MAC_PLATFORM)
65 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dylib";
66 #else
67 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.so";
68 #endif
69 #endif
70
HandleClient(void * const server)71 void* HandleClient(void* const server)
72 {
73 LOGI("HandleClient");
74 if (server == nullptr) {
75 LOGE("HandleClient server nullptr");
76 return nullptr;
77 }
78 static_cast<WsServer*>(server)->RunServer();
79 return nullptr;
80 }
81
82 #if !defined(IOS_PLATFORM)
LoadArkDebuggerLibrary()83 bool LoadArkDebuggerLibrary()
84 {
85 if (g_handle != nullptr) {
86 LOGE("Already opened");
87 return false;
88 }
89 g_handle = Load(ARK_DEBUGGER_SHARED_LIB);
90 if (g_handle == nullptr) {
91 return false;
92 }
93 return true;
94 }
95
GetArkDynFunction(const char * symbol)96 void* GetArkDynFunction(const char* symbol)
97 {
98 return ResolveSymbol(g_handle, symbol);
99 }
100 #endif
101
SendReply(const void * vm,const std::string & message)102 void SendReply(const void* vm, const std::string& message)
103 {
104 std::shared_lock<std::shared_mutex> lock(g_mutex);
105 auto iter = g_inspectors.find(vm);
106 if (iter != g_inspectors.end() && iter->second != nullptr &&
107 iter->second->websocketServer_ != nullptr) {
108 iter->second->websocketServer_->SendReply(message);
109 }
110 }
111
ResetServiceLocked()112 void ResetServiceLocked()
113 {
114 auto iter = g_inspectors.find(g_vm);
115 if (iter != g_inspectors.end() && iter->second != nullptr &&
116 iter->second->websocketServer_ != nullptr) {
117 iter->second->websocketServer_->StopServer();
118 delete iter->second;
119 iter->second = nullptr;
120 g_inspectors.erase(iter);
121 }
122 #if !defined(IOS_PLATFORM)
123 if (g_handle != nullptr) {
124 CloseHandle(g_handle);
125 g_handle = nullptr;
126 }
127 #endif
128 }
129
InitializeInspector(void * vm,const std::string & componentName,int32_t instanceId,const DebuggerPostTask & debuggerPostTask)130 bool InitializeInspector(void* vm, const std::string& componentName, int32_t instanceId,
131 const DebuggerPostTask& debuggerPostTask)
132 {
133 std::unique_lock<std::shared_mutex> lock(g_mutex);
134 auto iter = g_inspectors.find(vm);
135 if (iter != g_inspectors.end()) {
136 LOGE("Already have the same vm in the map");
137 return false;
138 }
139
140 Inspector *newInspector = new Inspector();
141 if (!g_inspectors.emplace(vm, newInspector).second) {
142 delete newInspector;
143 return false;
144 }
145
146 newInspector->tid_ = pthread_self();
147 newInspector->vm_ = vm;
148 newInspector->debuggerPostTask_ = debuggerPostTask;
149 newInspector->websocketServer_ = std::make_unique<WsServer>(componentName,
150 std::bind(&Inspector::OnMessage, newInspector, std::placeholders::_1), instanceId);
151
152 pthread_t tid;
153 if (pthread_create(&tid, nullptr, &HandleClient, static_cast<void *>(
154 newInspector->websocketServer_.get())) != 0) {
155 LOGE("Create inspector thread failed");
156 return false;
157 }
158 newInspector->websocketServer_->tid_ = tid;
159
160 return true;
161 }
162
InitializeArkFunctions()163 bool InitializeArkFunctions()
164 {
165 // no need to initialize again in case of multi-instance
166 if (g_hasArkFuncsInited) {
167 return true;
168 }
169
170 std::unique_lock<std::shared_mutex> lock(g_mutex);
171 if (g_hasArkFuncsInited) {
172 return true;
173 }
174 #if !defined(IOS_PLATFORM)
175 g_initializeDebugger = reinterpret_cast<InitializeDebugger>(
176 GetArkDynFunction("InitializeDebugger"));
177 if (g_initializeDebugger == nullptr) {
178 ResetServiceLocked();
179 return false;
180 }
181 g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(
182 GetArkDynFunction("UninitializeDebugger"));
183 if (g_uninitializeDebugger == nullptr) {
184 ResetServiceLocked();
185 return false;
186 }
187 g_waitForDebugger = reinterpret_cast<WaitForDebugger>(
188 GetArkDynFunction("WaitForDebugger"));
189 if (g_waitForDebugger == nullptr) {
190 ResetServiceLocked();
191 return false;
192 }
193 g_onMessage = reinterpret_cast<OnMessage>(
194 GetArkDynFunction("OnMessage"));
195 if (g_onMessage == nullptr) {
196 ResetServiceLocked();
197 return false;
198 }
199 g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(
200 GetArkDynFunction("GetDispatchStatus"));
201 if (g_getDispatchStatus == nullptr) {
202 ResetServiceLocked();
203 return false;
204 }
205 g_processMessage = reinterpret_cast<ProcessMessage>(
206 GetArkDynFunction("ProcessMessage"));
207 if (g_processMessage == nullptr) {
208 ResetServiceLocked();
209 return false;
210 }
211 #else
212 using namespace panda::ecmascript;
213 g_initializeDebugger = reinterpret_cast<InitializeDebugger>(&tooling::InitializeDebugger);
214 g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(&tooling::UninitializeDebugger);
215 g_waitForDebugger = reinterpret_cast<WaitForDebugger>(&tooling::WaitForDebugger);
216 g_onMessage = reinterpret_cast<OnMessage>(&tooling::OnMessage);
217 g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(&tooling::GetDispatchStatus);
218 g_processMessage = reinterpret_cast<ProcessMessage>(&tooling::ProcessMessage);
219 #endif
220
221 g_hasArkFuncsInited = true;
222 return true;
223 }
224 } // namespace
225
OnMessage(std::string && msg)226 void Inspector::OnMessage(std::string&& msg)
227 {
228 g_onMessage(vm_, std::move(msg));
229
230 // message will be processed soon if the debugger thread is in running or waiting status
231 if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
232 return;
233 }
234 std::this_thread::sleep_for(std::chrono::microseconds(DELAY_CHECK_DISPATCH_STATUS));
235 if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
236 return;
237 }
238
239 // the debugger thread maybe in idle status, so try to post a task to wake it up
240 if (debuggerPostTask_ != nullptr) {
241 debuggerPostTask_([tid = tid_, vm = vm_] {
242 if (tid != pthread_self()) {
243 LOGE("Task not in debugger thread");
244 return;
245 }
246 g_processMessage(vm);
247 });
248 } else {
249 LOGW("No debuggerPostTask provided");
250 }
251 }
252
StartDebug(const std::string & componentName,void * vm,bool isDebugMode,int32_t instanceId,const DebuggerPostTask & debuggerPostTask)253 bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId,
254 const DebuggerPostTask& debuggerPostTask)
255 {
256 g_vm = vm;
257 #if !defined(IOS_PLATFORM)
258 if (!LoadArkDebuggerLibrary()) {
259 return false;
260 }
261 #endif
262 if (!InitializeArkFunctions()) {
263 LOGE("Initialize ark functions failed");
264 return false;
265 }
266
267 g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
268
269 if (!InitializeInspector(vm, componentName, instanceId, debuggerPostTask)) {
270 LOGE("Initialize inspector failed");
271 return false;
272 }
273
274 if (isDebugMode) {
275 g_waitForDebugger(vm);
276 }
277 return true;
278 }
279
StopDebug(const std::string & componentName)280 void StopDebug(const std::string& componentName)
281 {
282 LOGI("StopDebug: %{private}s", componentName.c_str());
283 std::unique_lock<std::shared_mutex> lock(g_mutex);
284 auto iter = g_inspectors.find(g_vm);
285 if (iter == g_inspectors.end() || iter->second == nullptr) {
286 return;
287 }
288
289 g_uninitializeDebugger(g_vm);
290 ResetServiceLocked();
291 LOGI("StopDebug end");
292 }
293 } // namespace OHOS::ArkCompiler::Toolchain
294