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 "ecmascript/debugger/debugger_api.h"
17
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/debugger/js_debugger.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/interpreter/frame_handler.h"
22 #include "ecmascript/interpreter/slow_runtime_stub.h"
23 #include "ecmascript/interpreter/fast_runtime_stub-inl.h"
24 #include "ecmascript/jspandafile/js_pandafile_executor.h"
25 #include "ecmascript/jspandafile/program_object.h"
26 #include "ecmascript/js_handle.h"
27 #include "ecmascript/jspandafile/js_pandafile_manager.h"
28 #include "ecmascript/method.h"
29 #include "ecmascript/module/js_module_manager.h"
30 #include "ecmascript/module/js_module_source_text.h"
31 #include "ecmascript/napi/jsnapi_helper.h"
32 #include "ecmascript/tagged_array.h"
33 #include "ecmascript/tagged_dictionary.h"
34
35 namespace panda::ecmascript::tooling {
36 using panda::ecmascript::base::ALLOW_BINARY;
37 using panda::ecmascript::base::ALLOW_HEX;
38 using panda::ecmascript::base::ALLOW_OCTAL;
39 using panda::ecmascript::base::NumberHelper;
40
41 // FrameHandler
GetStackDepth(const EcmaVM * ecmaVm)42 uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm)
43 {
44 uint32_t count = 0;
45 FrameHandler frameHandler(ecmaVm->GetJSThread());
46 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
47 if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) {
48 continue;
49 }
50 ++count;
51 }
52 return count;
53 }
54
NewFrameHandler(const EcmaVM * ecmaVm)55 std::shared_ptr<FrameHandler> DebuggerApi::NewFrameHandler(const EcmaVM *ecmaVm)
56 {
57 return std::make_shared<FrameHandler>(ecmaVm->GetJSThread());
58 }
59
StackWalker(const EcmaVM * ecmaVm,std::function<StackState (const FrameHandler *)> func)60 bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::function<StackState(const FrameHandler *)> func)
61 {
62 FrameHandler frameHandler(ecmaVm->GetJSThread());
63 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
64 if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) {
65 continue;
66 }
67 StackState state = func(&frameHandler);
68 if (state == StackState::CONTINUE) {
69 continue;
70 }
71 if (state == StackState::FAILED) {
72 return false;
73 }
74 return true;
75 }
76 return true;
77 }
78
GetBytecodeOffset(const EcmaVM * ecmaVm)79 uint32_t DebuggerApi::GetBytecodeOffset(const EcmaVM *ecmaVm)
80 {
81 return FrameHandler(ecmaVm->GetJSThread()).GetBytecodeOffset();
82 }
83
GetMethod(const EcmaVM * ecmaVm)84 std::unique_ptr<PtMethod> DebuggerApi::GetMethod(const EcmaVM *ecmaVm)
85 {
86 FrameHandler frameHandler(ecmaVm->GetJSThread());
87 Method* method = frameHandler.GetMethod();
88 std::unique_ptr<PtMethod> ptMethod = std::make_unique<PtMethod>(
89 method->GetJSPandaFile(), method->GetMethodId(), method->IsNativeWithCallField());
90 return ptMethod;
91 }
92
SetVRegValue(FrameHandler * frameHandler,size_t index,Local<JSValueRef> value)93 void DebuggerApi::SetVRegValue(FrameHandler *frameHandler, size_t index, Local<JSValueRef> value)
94 {
95 return frameHandler->SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value));
96 }
97
GetBytecodeOffset(const FrameHandler * frameHandler)98 uint32_t DebuggerApi::GetBytecodeOffset(const FrameHandler *frameHandler)
99 {
100 return frameHandler->GetBytecodeOffset();
101 }
102
GetMethod(const FrameHandler * frameHandler)103 Method *DebuggerApi::GetMethod(const FrameHandler *frameHandler)
104 {
105 return frameHandler->GetMethod();
106 }
107
IsNativeMethod(const EcmaVM * ecmaVm)108 bool DebuggerApi::IsNativeMethod(const EcmaVM *ecmaVm)
109 {
110 FrameHandler frameHandler(ecmaVm->GetJSThread());
111 return DebuggerApi::IsNativeMethod(&frameHandler);
112 }
113
IsNativeMethod(const FrameHandler * frameHandler)114 bool DebuggerApi::IsNativeMethod(const FrameHandler *frameHandler)
115 {
116 if (!frameHandler->HasFrame()) {
117 return false;
118 }
119 Method* method = frameHandler->GetMethod();
120 return method->IsNativeWithCallField();
121 }
122
GetJSPandaFile(const EcmaVM * ecmaVm)123 JSPandaFile *DebuggerApi::GetJSPandaFile(const EcmaVM *ecmaVm)
124 {
125 Method *method = FrameHandler(ecmaVm->GetJSThread()).GetMethod();
126 return const_cast<JSPandaFile *>(method->GetJSPandaFile());
127 }
128
GetEnv(const FrameHandler * frameHandler)129 JSTaggedValue DebuggerApi::GetEnv(const FrameHandler *frameHandler)
130 {
131 return frameHandler->GetEnv();
132 }
133
GetSp(const FrameHandler * frameHandler)134 JSTaggedType *DebuggerApi::GetSp(const FrameHandler *frameHandler)
135 {
136 return frameHandler->GetSp();
137 }
138
GetVregIndex(const FrameHandler * frameHandler,std::string_view name)139 int32_t DebuggerApi::GetVregIndex(const FrameHandler *frameHandler, std::string_view name)
140 {
141 Method *method = DebuggerApi::GetMethod(frameHandler);
142 if (method->IsNativeWithCallField()) {
143 LOG_DEBUGGER(ERROR) << "GetVregIndex: native frame not support";
144 return -1;
145 }
146 DebugInfoExtractor *extractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
147 if (extractor == nullptr) {
148 LOG_DEBUGGER(ERROR) << "GetVregIndex: extractor is null";
149 return -1;
150 }
151 auto table = extractor->GetLocalVariableTable(method->GetMethodId());
152 auto iter = table.find(name.data());
153 if (iter == table.end()) {
154 return -1;
155 }
156 return iter->second;
157 }
158
GetVRegValue(const EcmaVM * ecmaVm,const FrameHandler * frameHandler,size_t index)159 Local<JSValueRef> DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm,
160 const FrameHandler *frameHandler, size_t index)
161 {
162 auto value = frameHandler->GetVRegValue(index);
163 JSHandle<JSTaggedValue> handledValue(ecmaVm->GetJSThread(), value);
164 return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
165 }
166
167 // JSThread
GetAndClearException(const EcmaVM * ecmaVm)168 Local<JSValueRef> DebuggerApi::GetAndClearException(const EcmaVM *ecmaVm)
169 {
170 auto exception = ecmaVm->GetJSThread()->GetException();
171 JSHandle<JSTaggedValue> handledException(ecmaVm->GetJSThread(), exception);
172 ecmaVm->GetJSThread()->ClearException();
173 return JSNApiHelper::ToLocal<JSValueRef>(handledException);
174 }
175
SetException(const EcmaVM * ecmaVm,Local<JSValueRef> exception)176 void DebuggerApi::SetException(const EcmaVM *ecmaVm, Local<JSValueRef> exception)
177 {
178 ecmaVm->GetJSThread()->SetException(JSNApiHelper::ToJSTaggedValue(*exception));
179 }
180
ClearException(const EcmaVM * ecmaVm)181 void DebuggerApi::ClearException(const EcmaVM *ecmaVm)
182 {
183 return ecmaVm->GetJSThread()->ClearException();
184 }
185
186 // NumberHelper
StringToDouble(const uint8_t * start,const uint8_t * end,uint8_t radix)187 double DebuggerApi::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix)
188 {
189 return NumberHelper::StringToDouble(start, end, radix, ALLOW_BINARY | ALLOW_HEX | ALLOW_OCTAL);
190 }
191
192 // JSDebugger
CreateJSDebugger(const EcmaVM * ecmaVm)193 JSDebugger *DebuggerApi::CreateJSDebugger(const EcmaVM *ecmaVm)
194 {
195 return new JSDebugger(ecmaVm);
196 }
197
DestroyJSDebugger(JSDebugger * debugger)198 void DebuggerApi::DestroyJSDebugger(JSDebugger *debugger)
199 {
200 delete debugger;
201 }
202
RegisterHooks(JSDebugger * debugger,PtHooks * hooks)203 void DebuggerApi::RegisterHooks(JSDebugger *debugger, PtHooks *hooks)
204 {
205 debugger->RegisterHooks(hooks);
206 }
207
SetBreakpoint(JSDebugger * debugger,const JSPtLocation & location,Local<FunctionRef> condFuncRef)208 bool DebuggerApi::SetBreakpoint(JSDebugger *debugger, const JSPtLocation &location,
209 Local<FunctionRef> condFuncRef)
210 {
211 return debugger->SetBreakpoint(location, condFuncRef);
212 }
213
RemoveBreakpoint(JSDebugger * debugger,const JSPtLocation & location)214 bool DebuggerApi::RemoveBreakpoint(JSDebugger *debugger, const JSPtLocation &location)
215 {
216 return debugger->RemoveBreakpoint(location);
217 }
218
RemoveAllBreakpoints(JSDebugger * debugger)219 void DebuggerApi::RemoveAllBreakpoints(JSDebugger *debugger)
220 {
221 return debugger->RemoveAllBreakpoints();
222 }
223
224 // ScopeInfo
GetProperties(const EcmaVM * vm,const FrameHandler * frameHandler,int32_t level,uint32_t slot)225 Local<JSValueRef> DebuggerApi::GetProperties(const EcmaVM *vm, const FrameHandler *frameHandler,
226 int32_t level, uint32_t slot)
227 {
228 JSTaggedValue env = frameHandler->GetEnv();
229 for (int i = 0; i < level; i++) {
230 JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv();
231 ASSERT(!taggedParentEnv.IsUndefined());
232 env = taggedParentEnv;
233 }
234 JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot);
235 JSHandle<JSTaggedValue> handledValue(vm->GetJSThread(), value);
236 return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
237 }
238
SetProperties(const EcmaVM * vm,const FrameHandler * frameHandler,int32_t level,uint32_t slot,Local<JSValueRef> value)239 void DebuggerApi::SetProperties(const EcmaVM *vm, const FrameHandler *frameHandler,
240 int32_t level, uint32_t slot, Local<JSValueRef> value)
241 {
242 JSTaggedValue env = frameHandler->GetEnv();
243 for (int i = 0; i < level; i++) {
244 JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv();
245 ASSERT(!taggedParentEnv.IsUndefined());
246 env = taggedParentEnv;
247 }
248 JSTaggedValue target = JSNApiHelper::ToJSHandle(value).GetTaggedValue();
249 LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(vm->GetJSThread(), slot, target);
250 }
251
GetLevelSlot(const FrameHandler * frameHandler,std::string_view name)252 std::pair<int32_t, uint32_t> DebuggerApi::GetLevelSlot(const FrameHandler *frameHandler, std::string_view name)
253 {
254 int32_t level = 0;
255 uint32_t slot = 0;
256 JSTaggedValue curEnv = frameHandler->GetEnv();
257 for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv(), level++) {
258 LexicalEnv *lexicalEnv = LexicalEnv::Cast(curEnv.GetTaggedObject());
259 if (lexicalEnv->GetScopeInfo().IsHole()) {
260 continue;
261 }
262 auto result = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer();
263 ScopeDebugInfo *scopeDebugInfo = reinterpret_cast<ScopeDebugInfo *>(result);
264 auto iter = scopeDebugInfo->scopeInfo.find(name.data());
265 if (iter == scopeDebugInfo->scopeInfo.end()) {
266 continue;
267 }
268 slot = iter->second;
269 return std::make_pair(level, slot);
270 }
271 return std::make_pair(-1, 0);
272 }
273
GetGlobalValue(const EcmaVM * vm,Local<StringRef> name)274 Local<JSValueRef> DebuggerApi::GetGlobalValue(const EcmaVM *vm, Local<StringRef> name)
275 {
276 JSTaggedValue result;
277 JSTaggedValue globalObj = vm->GetGlobalEnv()->GetGlobalObject();
278 JSThread *thread = vm->GetJSThread();
279
280 JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name);
281 JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key);
282 if (!globalRec.IsUndefined()) {
283 ASSERT(globalRec.IsPropertyBox());
284 result = PropertyBox::Cast(globalRec.GetTaggedObject())->GetValue();
285 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
286 }
287
288 JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key);
289 if (!globalVar.IsHole()) {
290 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, globalVar));
291 } else {
292 result = SlowRuntimeStub::TryLdGlobalByNameFromGlobalProto(thread, globalObj, key);
293 return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result));
294 }
295
296 return Local<JSValueRef>();
297 }
298
SetGlobalValue(const EcmaVM * vm,Local<StringRef> name,Local<JSValueRef> value)299 bool DebuggerApi::SetGlobalValue(const EcmaVM *vm, Local<StringRef> name, Local<JSValueRef> value)
300 {
301 JSTaggedValue result;
302 JSTaggedValue globalObj = vm->GetGlobalEnv()->GetGlobalObject();
303 JSThread *thread = vm->GetJSThread();
304
305 JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name);
306 JSTaggedValue newVal = JSNApiHelper::ToJSTaggedValue(*value);
307 JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key);
308 if (!globalRec.IsUndefined()) {
309 result = SlowRuntimeStub::TryUpdateGlobalRecord(thread, key, newVal);
310 return !result.IsException();
311 }
312
313 JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key);
314 if (!globalVar.IsHole()) {
315 result = SlowRuntimeStub::StGlobalVar(thread, key, newVal);
316 return !result.IsException();
317 }
318
319 return false;
320 }
321
GetCurrentModule(const EcmaVM * ecmaVm)322 JSTaggedValue DebuggerApi::GetCurrentModule(const EcmaVM *ecmaVm)
323 {
324 JSThread *thread = ecmaVm->GetJSThread();
325 FrameHandler frameHandler(thread);
326 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
327 if (frameHandler.IsEntryFrame()) {
328 continue;
329 }
330 Method *method = frameHandler.GetMethod();
331 // Skip builtins method
332 if (method->IsNativeWithCallField()) {
333 continue;
334 }
335 JSTaggedValue func = frameHandler.GetFunction();
336 JSTaggedValue module = JSFunction::Cast(func.GetTaggedObject())->GetModule();
337 if (module.IsUndefined()) {
338 continue;
339 }
340 return module;
341 }
342 UNREACHABLE();
343 }
344
GetModuleVariables(const EcmaVM * vm,Local<ObjectRef> & moduleObj,JSThread * thread)345 void DebuggerApi::GetModuleVariables(const EcmaVM *vm, Local<ObjectRef> &moduleObj, JSThread *thread)
346 {
347 JSTaggedValue currentModule = vm->GetModuleManager()->GetCurrentModule();
348 if (currentModule.IsUndefined()) {
349 return;
350 }
351
352 JSTaggedValue dictionary = SourceTextModule::Cast(currentModule.GetTaggedObject())->GetNameDictionary();
353 if (dictionary.IsUndefined()) {
354 return;
355 }
356
357 JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
358 JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined());
359 if (dictionary.IsTaggedArray()) {
360 JSTaggedValue localExportEntries = SourceTextModule::Cast(
361 currentModule.GetTaggedObject())->GetLocalExportEntries();
362 ASSERT(localExportEntries.IsTaggedArray());
363 JSHandle<TaggedArray> localExportArray = JSHandle<TaggedArray>(
364 thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
365 uint32_t exportEntriesLen = localExportArray->GetLength();
366 JSHandle<TaggedArray> dict = JSHandle<TaggedArray>(thread, TaggedArray::Cast(dictionary.GetTaggedObject()));
367 uint32_t valueLen = dict->GetLength();
368 if (exportEntriesLen != valueLen) {
369 LOG_FULL(FATAL) << "Key does not match value";
370 }
371
372 JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
373 for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
374 ee.Update(localExportArray->Get(idx));
375 JSTaggedValue key = ee->GetLocalName();
376 name.Update(key);
377 JSTaggedValue moduleValue = dict->Get(idx);
378 if (moduleValue.IsHole()) {
379 moduleValue = JSTaggedValue::Undefined();
380 }
381 value.Update(moduleValue);
382 if (key.IsString()) {
383 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
384 Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value);
385 PropertyAttribute descriptor(variableValue, true, true, true);
386 moduleObj->DefineProperty(vm, variableName, descriptor);
387 }
388 }
389 }
390 }
391
HandleUncaughtException(const EcmaVM * ecmaVm,std::string & message)392 void DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message)
393 {
394 JSThread *thread = ecmaVm->GetJSThread();
395 [[maybe_unused]] EcmaHandleScope handleScope(thread);
396 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
397
398 JSHandle<JSTaggedValue> exHandle(thread, thread->GetException());
399 if (exHandle->IsJSError()) {
400 JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
401 JSHandle<EcmaString> name(JSObject::GetProperty(thread, exHandle, nameKey).GetValue());
402 JSHandle<JSTaggedValue> msgKey = globalConst->GetHandledMessageString();
403 JSHandle<EcmaString> msg(JSObject::GetProperty(thread, exHandle, msgKey).GetValue());
404 message = ConvertToString(*name) + ": " + ConvertToString(*msg);
405 } else {
406 JSHandle<EcmaString> ecmaStr = JSTaggedValue::ToString(thread, exHandle);
407 message = ConvertToString(*ecmaStr);
408 }
409 thread->ClearException();
410 }
411
GenerateFuncFromBuffer(const EcmaVM * ecmaVm,const void * buffer,size_t size,std::string_view entryPoint)412 Local<FunctionRef> DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer,
413 size_t size, std::string_view entryPoint)
414 {
415 JSPandaFileManager *mgr = JSPandaFileManager::GetInstance();
416 const auto *jsPandaFile = mgr->LoadJSPandaFile(ecmaVm->GetJSThread(), "", entryPoint, buffer, size);
417 if (jsPandaFile == nullptr) {
418 return JSValueRef::Undefined(ecmaVm);
419 }
420
421 JSHandle<Program> program = mgr->GenerateProgram(const_cast<EcmaVM *>(ecmaVm), jsPandaFile, entryPoint);
422 JSTaggedValue func = program->GetMainFunction();
423 return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(ecmaVm->GetJSThread(), func));
424 }
425
EvaluateViaFuncCall(EcmaVM * ecmaVm,Local<FunctionRef> funcRef,std::shared_ptr<FrameHandler> & frameHandler)426 Local<JSValueRef> DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, Local<FunctionRef> funcRef,
427 std::shared_ptr<FrameHandler> &frameHandler)
428 {
429 JSNApi::EnableUserUncaughtErrorHandler(ecmaVm);
430
431 JsDebuggerManager *mgr = ecmaVm->GetJsDebuggerManager();
432 bool prevDebugMode = mgr->IsDebugMode();
433 mgr->SetEvalFrameHandler(frameHandler);
434 mgr->SetDebugMode(false); // in order to catch exception
435 ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
436 std::vector<Local<JSValueRef>> args;
437 auto result = funcRef->Call(ecmaVm, JSValueRef::Undefined(ecmaVm), args.data(), args.size());
438 mgr->SetDebugMode(prevDebugMode);
439 ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
440 mgr->SetEvalFrameHandler(nullptr);
441
442 return result;
443 }
444
IsExceptionCaught(const EcmaVM * ecmaVm)445 bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm)
446 {
447 FrameHandler frameHandler(ecmaVm->GetJSThread());
448 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
449 if (frameHandler.IsEntryFrame()) {
450 return false;
451 }
452 auto method = frameHandler.GetMethod();
453 if (ecmaVm->FindCatchBlock(method, frameHandler.GetBytecodeOffset())) {
454 return true;
455 }
456 }
457 return false;
458 }
459
GetPatchExtractor(const EcmaVM * ecmaVm,const std::string & url)460 DebugInfoExtractor *DebuggerApi::GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url)
461 {
462 const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
463 return hotReloadManager->GetPatchExtractor(url);
464 }
465
GetBaseJSPandaFile(const EcmaVM * ecmaVm,const JSPandaFile * jsPandaFile)466 const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile)
467 {
468 const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
469 return hotReloadManager->GetBaseJSPandaFile(jsPandaFile);
470 }
471
472 } // namespace panda::ecmascript::tooling
473