• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetImportModule(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)345 JSHandle<JSTaggedValue> DebuggerApi::GetImportModule(const EcmaVM *ecmaVm,
346                                                      const JSHandle<JSTaggedValue> &currentModule, std::string &name)
347 {
348     JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries();
349     if (importEntries.IsUndefined()) {
350         return currentModule;
351     }
352 
353     JSThread *thread = ecmaVm->GetJSThread();
354     JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject()));
355     size_t importEntriesLen = importArray->GetLength();
356     JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString();
357     JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
358     JSMutableHandle<TaggedArray> environment(thread, thread->GlobalConstants()->GetUndefined());
359     JSMutableHandle<JSTaggedValue> importModule(thread, thread->GlobalConstants()->GetUndefined());
360     for (size_t idx = 0; idx < importEntriesLen; idx++) {
361         ee.Update(importArray->Get(idx));
362         JSTaggedValue localName = ee->GetLocalName();
363         JSTaggedValue importName = ee->GetImportName();
364         // Skip 'import * as name from xxx'
365         if (localName.IsString() && !JSTaggedValue::SameValue(importName, starString.GetTaggedValue())) {
366             std::string varName = EcmaStringAccessor(localName).ToStdString();
367             if (varName != name) {
368                 continue;
369             }
370             JSTaggedValue moduleEnvironment = SourceTextModule::Cast(
371                 currentModule->GetTaggedObject())->GetEnvironment();
372             environment.Update(moduleEnvironment);
373             JSTaggedValue resolvedBinding = environment->Get(idx);
374             ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
375             importModule.Update(binding->GetModule());
376             name = EcmaStringAccessor(importName).ToStdString();
377             return importModule;
378         }
379     }
380     return currentModule;
381 }
382 
GetModuleVariableIndex(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)383 int32_t DebuggerApi::GetModuleVariableIndex(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> &currentModule,
384                                             std::string &name)
385 {
386     JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
387     if (dictionary.IsUndefined()) {
388         return -1;
389     }
390 
391     JSThread *thread = ecmaVm->GetJSThread();
392     if (dictionary.IsTaggedArray()) {
393         JSTaggedValue localExportEntries = SourceTextModule::Cast(
394             currentModule->GetTaggedObject())->GetLocalExportEntries();
395         ASSERT(localExportEntries.IsTaggedArray());
396         JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
397         uint32_t exportEntriesLen = localExportArray->GetLength();
398         JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
399         for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
400             ee.Update(localExportArray->Get(idx));
401             JSTaggedValue localKey = ee->GetLocalName();
402             JSTaggedValue exportKey = ee->GetExportName();
403             if (localKey.IsString() && exportKey.IsString()) {
404                 std::string localName = EcmaStringAccessor(localKey).ToStdString();
405                 std::string exportName = EcmaStringAccessor(exportKey).ToStdString();
406                 if (localName == name || exportName == name) {
407                     return idx;
408                 }
409             }
410         }
411     }
412     return -1;
413 }
414 
GetRequestModuleIndex(const EcmaVM * ecmaVm,JSTaggedValue moduleRequest,const JSHandle<JSTaggedValue> & currentModule)415 int32_t DebuggerApi::GetRequestModuleIndex(const EcmaVM *ecmaVm, JSTaggedValue moduleRequest,
416                                            const JSHandle<JSTaggedValue> &currentModule)
417 {
418     JSThread *thread = ecmaVm->GetJSThread();
419     JSHandle<SourceTextModule> module(thread, SourceTextModule::Cast(currentModule->GetTaggedObject()));
420     JSHandle<JSTaggedValue> required(thread, moduleRequest);
421     JSHandle<SourceTextModule> requiredModule = JSHandle<SourceTextModule>::Cast(
422         SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required));
423     JSTaggedValue requireModule = requiredModule->GetEcmaModuleRecordName();
424     JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules());
425     int32_t requestedModulesLen = static_cast<int32_t>(requestedModules->GetLength());
426     for (int32_t idx = 0; idx < requestedModulesLen; idx++) {
427         JSTaggedValue requestModule = requestedModules->Get(idx);
428         if (JSTaggedValue::SameValue(requireModule, requestModule)) {
429             return idx;
430         }
431     }
432     return -1;
433 }
434 
GetModuleValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name)435 Local<JSValueRef> DebuggerApi::GetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> &currentModule,
436                                               std::string &name)
437 {
438     Local<JSValueRef> result;
439     JSHandle<JSTaggedValue> module = GetImportModule(ecmaVm, currentModule, name);
440     int32_t index = GetModuleVariableIndex(ecmaVm, module, name);
441     if (index == -1) {
442         return result;
443     }
444 
445     JSTaggedValue dictionary = SourceTextModule::Cast(module->GetTaggedObject())->GetNameDictionary();
446     if (dictionary.IsUndefined()) {
447         return result;
448     }
449 
450     JSThread *thread = ecmaVm->GetJSThread();
451     if (dictionary.IsTaggedArray()) {
452         TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject());
453         JSTaggedValue moduleValue = array->Get(index);
454         result = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, moduleValue));
455         return result;
456     }
457     return result;
458 }
459 
SetModuleValue(const EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & currentModule,std::string & name,Local<JSValueRef> value)460 bool DebuggerApi::SetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> &currentModule,
461                                  std::string &name, Local<JSValueRef> value)
462 {
463     JSHandle<JSTaggedValue> module = GetImportModule(ecmaVm, currentModule, name);
464     int32_t index = GetModuleVariableIndex(ecmaVm, module, name);
465     if (index == -1) {
466         return false;
467     }
468 
469     JSTaggedValue dictionary = SourceTextModule::Cast(module->GetTaggedObject())->GetNameDictionary();
470     if (dictionary.IsUndefined()) {
471         return false;
472     }
473 
474     JSThread *thread = ecmaVm->GetJSThread();
475     JSTaggedValue curValue = JSNApiHelper::ToJSTaggedValue(*value);
476     if (dictionary.IsTaggedArray()) {
477         TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject());
478         array->Set(thread, index, curValue);
479     }
480     return true;
481 }
482 
InitializeExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)483 void DebuggerApi::InitializeExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
484                                             const JSHandle<JSTaggedValue> &currentModule)
485 {
486     JSTaggedValue localExportEntries = SourceTextModule::Cast(
487         currentModule->GetTaggedObject())->GetLocalExportEntries();
488     if (localExportEntries.IsUndefined()) {
489         return;
490     }
491 
492     JSThread *thread = ecmaVm->GetJSThread();
493     JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
494     uint32_t exportEntriesLen = localExportArray->GetLength();
495     JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
496     JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
497     JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined());
498     JSTaggedValue moduleValue = JSTaggedValue::Undefined();
499     for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
500         ee.Update(localExportArray->Get(idx));
501         JSTaggedValue key = ee->GetLocalName();
502         name.Update(key);
503         value.Update(moduleValue);
504         if (key.IsString()) {
505             Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
506             Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value);
507             PropertyAttribute descriptor(variableValue, true, true, true);
508             moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
509         }
510     }
511 }
512 
GetLocalExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule,bool isImportStar)513 void DebuggerApi::GetLocalExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
514                                           const JSHandle<JSTaggedValue> &currentModule, bool isImportStar)
515 {
516     JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary();
517     if (dictionary.IsUndefined()) {
518         InitializeExportVariables(ecmaVm, moduleObj, currentModule);
519         return;
520     }
521 
522     JSThread *thread = ecmaVm->GetJSThread();
523     JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
524     JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined());
525     if (dictionary.IsTaggedArray()) {
526         JSTaggedValue localExportEntries = SourceTextModule::Cast(
527             currentModule->GetTaggedObject())->GetLocalExportEntries();
528         ASSERT(localExportEntries.IsTaggedArray());
529         JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject()));
530         uint32_t exportEntriesLen = localExportArray->GetLength();
531         JSHandle<TaggedArray> dict(thread, TaggedArray::Cast(dictionary.GetTaggedObject()));
532         uint32_t valueLen = dict->GetLength();
533         if (exportEntriesLen != valueLen) {
534             LOG_FULL(FATAL) << "Key does not match value";
535         }
536 
537         JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
538         for (uint32_t idx = 0; idx < exportEntriesLen; idx++) {
539             ee.Update(localExportArray->Get(idx));
540             JSTaggedValue key;
541             if (isImportStar) {
542                 key = ee->GetExportName();
543             } else {
544                 key = ee->GetLocalName();
545             }
546             name.Update(key);
547             JSTaggedValue moduleValue = dict->Get(idx);
548             if (moduleValue.IsHole()) {
549                 moduleValue = JSTaggedValue::Undefined();
550             }
551             value.Update(moduleValue);
552             if (key.IsString()) {
553                 Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
554                 Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value);
555                 PropertyAttribute descriptor(variableValue, true, true, true);
556                 moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
557             }
558         }
559     }
560 }
561 
GetIndirectExportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)562 void DebuggerApi::GetIndirectExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
563                                              const JSHandle<JSTaggedValue> &currentModule)
564 {
565     JSTaggedValue indirectExportEntries = SourceTextModule::Cast(
566         currentModule->GetTaggedObject())->GetIndirectExportEntries();
567     if (indirectExportEntries.IsUndefined()) {
568         return;
569     }
570     ASSERT(indirectExportEntries.IsTaggedArray());
571     JSThread *thread = ecmaVm->GetJSThread();
572     JSHandle<TaggedArray> indirectExportArray(thread, TaggedArray::Cast(indirectExportEntries.GetTaggedObject()));
573     uint32_t indirectExportEntriesLen = indirectExportArray->GetLength();
574     JSMutableHandle<IndirectExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
575     JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
576     for (uint32_t idx = 0; idx < indirectExportEntriesLen; idx++) {
577         ee.Update(indirectExportArray->Get(idx));
578         JSTaggedValue key = ee->GetImportName();
579         name.Update(key);
580         if (key.IsString()) {
581             Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
582             JSTaggedValue moduleRequest = ee->GetModuleRequest();
583             int32_t index = GetRequestModuleIndex(ecmaVm, moduleRequest, currentModule);
584             JSTaggedValue importNamespace = ecmaVm->GetModuleManager()->GetModuleNamespace(index);
585             JSHandle<JSTaggedValue> importModule(thread,
586                 ModuleNamespace::Cast(importNamespace.GetTaggedObject())->GetModule());
587             std::string importName = EcmaStringAccessor(ee->GetImportName()).ToStdString();
588             Local<JSValueRef> value = GetModuleValue(ecmaVm, importModule, importName);
589             PropertyAttribute descriptor(value, true, true, true);
590             moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
591         }
592     }
593 }
594 
GetImportVariables(const EcmaVM * ecmaVm,Local<ObjectRef> & moduleObj,const JSHandle<JSTaggedValue> & currentModule)595 void DebuggerApi::GetImportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj,
596                                      const JSHandle<JSTaggedValue> &currentModule)
597 {
598     JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries();
599     if (importEntries.IsUndefined()) {
600         return;
601     }
602 
603     JSTaggedValue moduleEnvironment = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetEnvironment();
604     if (moduleEnvironment.IsUndefined()) {
605         return;
606     }
607 
608     JSThread *thread = ecmaVm->GetJSThread();
609     JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject()));
610     int32_t importEntriesLen = static_cast<int32_t>(importArray->GetLength());
611     JSHandle<TaggedArray> environment(thread, TaggedArray::Cast(moduleEnvironment.GetTaggedObject()));
612     JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString();
613     JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined());
614     JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined());
615     for (int32_t idx = 0; idx < importEntriesLen; idx++) {
616         ee.Update(importArray->Get(idx));
617         JSTaggedValue key = ee->GetImportName();
618         JSTaggedValue localName = ee->GetLocalName();
619         name.Update(localName);
620         if (!key.IsString()) {
621             continue;
622         }
623         if (JSTaggedValue::SameValue(key, starString.GetTaggedValue())) {
624             JSTaggedValue moduleRequest = ee->GetModuleRequest();
625             int32_t index = GetRequestModuleIndex(ecmaVm, moduleRequest, currentModule);
626             JSTaggedValue importNamespace = ecmaVm->GetModuleManager()->GetModuleNamespace(index);
627             JSHandle<JSTaggedValue> importModule(thread,
628                 ModuleNamespace::Cast(importNamespace.GetTaggedObject())->GetModule());
629             Local<ObjectRef> importModuleObj = ObjectRef::New(ecmaVm);
630             GetLocalExportVariables(ecmaVm, importModuleObj, importModule, true);
631             Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
632             PropertyAttribute descriptor(static_cast<Local<JSValueRef>>(importModuleObj), true, true, true);
633             moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
634             continue;
635         }
636         JSTaggedValue resolvedBinding = environment->Get(idx);
637         if (resolvedBinding.IsHole()) {
638             continue;
639         }
640         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
641         JSHandle<JSTaggedValue> importModule(thread, binding->GetModule());
642         std::string importName = EcmaStringAccessor(key).ToStdString();
643         Local<JSValueRef> value = GetModuleValue(ecmaVm, importModule, importName);
644         Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name);
645         PropertyAttribute descriptor(value, true, true, true);
646         moduleObj->DefineProperty(ecmaVm, variableName, descriptor);
647     }
648 }
649 
HandleUncaughtException(const EcmaVM * ecmaVm,std::string & message)650 void DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message)
651 {
652     JSThread *thread = ecmaVm->GetJSThread();
653     [[maybe_unused]] EcmaHandleScope handleScope(thread);
654     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
655 
656     JSHandle<JSTaggedValue> exHandle(thread, thread->GetException());
657     if (exHandle->IsJSError()) {
658         JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString();
659         JSHandle<EcmaString> name(JSObject::GetProperty(thread, exHandle, nameKey).GetValue());
660         JSHandle<JSTaggedValue> msgKey = globalConst->GetHandledMessageString();
661         JSHandle<EcmaString> msg(JSObject::GetProperty(thread, exHandle, msgKey).GetValue());
662         message = ConvertToString(*name) + ": " + ConvertToString(*msg);
663     } else {
664         JSHandle<EcmaString> ecmaStr = JSTaggedValue::ToString(thread, exHandle);
665         message = ConvertToString(*ecmaStr);
666     }
667     thread->ClearException();
668 }
669 
GenerateFuncFromBuffer(const EcmaVM * ecmaVm,const void * buffer,size_t size,std::string_view entryPoint)670 Local<FunctionRef> DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer,
671                                                        size_t size, std::string_view entryPoint)
672 {
673     JSPandaFileManager *mgr = JSPandaFileManager::GetInstance();
674     const auto *jsPandaFile = mgr->LoadJSPandaFile(ecmaVm->GetJSThread(), "", entryPoint, buffer, size);
675     if (jsPandaFile == nullptr) {
676         return JSValueRef::Undefined(ecmaVm);
677     }
678 
679     JSHandle<Program> program = mgr->GenerateProgram(const_cast<EcmaVM *>(ecmaVm), jsPandaFile, entryPoint);
680     JSTaggedValue func = program->GetMainFunction();
681     return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(ecmaVm->GetJSThread(), func));
682 }
683 
EvaluateViaFuncCall(EcmaVM * ecmaVm,Local<FunctionRef> funcRef,std::shared_ptr<FrameHandler> & frameHandler)684 Local<JSValueRef> DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, Local<FunctionRef> funcRef,
685     std::shared_ptr<FrameHandler> &frameHandler)
686 {
687     JSNApi::EnableUserUncaughtErrorHandler(ecmaVm);
688 
689     JsDebuggerManager *mgr = ecmaVm->GetJsDebuggerManager();
690     bool prevDebugMode = mgr->IsDebugMode();
691     mgr->SetEvalFrameHandler(frameHandler);
692     mgr->SetDebugMode(false); // in order to catch exception
693     ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
694     std::vector<Local<JSValueRef>> args;
695     auto result = funcRef->Call(ecmaVm, JSValueRef::Undefined(ecmaVm), args.data(), args.size());
696     mgr->SetDebugMode(prevDebugMode);
697     ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub();
698     mgr->SetEvalFrameHandler(nullptr);
699 
700     return result;
701 }
702 
IsExceptionCaught(const EcmaVM * ecmaVm)703 bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm)
704 {
705     FrameHandler frameHandler(ecmaVm->GetJSThread());
706     for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
707         if (frameHandler.IsEntryFrame()) {
708             return false;
709         }
710         auto method = frameHandler.GetMethod();
711         if (ecmaVm->FindCatchBlock(method, frameHandler.GetBytecodeOffset())) {
712             return true;
713         }
714     }
715     return false;
716 }
717 
GetPatchExtractor(const EcmaVM * ecmaVm,const std::string & url)718 DebugInfoExtractor *DebuggerApi::GetPatchExtractor(const EcmaVM *ecmaVm, const std::string &url)
719 {
720     const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
721     return hotReloadManager->GetPatchExtractor(url);
722 }
723 
GetBaseJSPandaFile(const EcmaVM * ecmaVm,const JSPandaFile * jsPandaFile)724 const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile)
725 {
726     const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager();
727     return hotReloadManager->GetBaseJSPandaFile(jsPandaFile);
728 }
729 
730 }  // namespace panda::ecmascript::tooling
731