• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
17 #include <sys/time.h>
18 
19 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
20 #include "ecmascript/platform/aot_crash_info.h"
21 #include "ecmascript/platform/os.h"
22 #include "ecmascript/stubs/runtime_stubs-inl.h"
23 #include "ecmascript/jit/jit.h"
24 #if defined(PANDA_TARGET_OHOS)
25 #include "ecmascript/extractortool/src/extractor.h"
26 #endif
27 #if defined(ENABLE_EXCEPTION_BACKTRACE)
28 #include "ecmascript/platform/backtrace.h"
29 #endif
30 namespace panda::ecmascript {
31 [[maybe_unused]] static bool g_needCheck = true;
32 
33 std::unordered_map<EntityId, std::string> JsStackInfo::nameMap;
34 std::unordered_map<EntityId, std::vector<uint8>> JsStackInfo::machineCodeMap;
35 
IsFastJitFunctionFrame(const FrameType frameType)36 bool IsFastJitFunctionFrame(const FrameType frameType)
37 {
38     return frameType == FrameType::FASTJIT_FUNCTION_FRAME || frameType == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
39 }
40 
BuildMethodTrace(Method * method,uint32_t pcOffset,LastBuilderCache & lastCache,bool enableStackSourceFile)41 std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache,
42                                           bool enableStackSourceFile)
43 {
44     std::string data;
45     data.reserve(InitialLength);
46     data.append("    at ");
47     std::string name = method->ParseFunctionName();
48     if (name.empty()) {
49         data.append("anonymous (");
50     } else {
51         data.append(name).append(" (");
52     }
53     // source file
54     DebugInfoExtractor *debugExtractor = nullptr;
55     const JSPandaFile *pandaFile = method->GetJSPandaFile();
56     if (pandaFile == lastCache.pf) {
57         debugExtractor = lastCache.extractor;
58     } else {
59         debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(pandaFile);
60         lastCache.pf = pandaFile;
61         lastCache.extractor = debugExtractor;
62     }
63     if (enableStackSourceFile) {
64         const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
65         if (sourceFile.empty()) {
66             data.push_back('?');
67         } else {
68             data += sourceFile;
69         }
70     } else {
71         data.append("hidden");
72     }
73 
74     data.push_back(':');
75     // line number and column number
76     auto callbackLineFunc = [&data](int32_t line) -> bool {
77         data += std::to_string(line + 1);
78         data.push_back(':');
79         return true;
80     };
81     auto callbackColumnFunc = [&data](int32_t column) -> bool {
82         data += std::to_string(column + 1);
83         return true;
84     };
85     panda_file::File::EntityId methodId = method->GetMethodId();
86     if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, pcOffset) ||
87         !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, pcOffset)) {
88         data.push_back('?');
89     }
90     data.append(")\n");
91     return data;
92 }
93 
BuildInlinedMethodTrace(const JSPandaFile * pf,std::map<uint32_t,uint32_t> & methodOffsets)94 std::string JsStackInfo::BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets)
95 {
96     std::string data;
97     std::map<uint32_t, uint32_t>::reverse_iterator it;
98     for (it = methodOffsets.rbegin(); it != methodOffsets.rend(); it++) {
99         uint32_t methodId = it->second;
100         std::string name;
101         if (methodId == 0) {
102             name = "unknown";
103         } else {
104             name = std::string(MethodLiteral::GetMethodName(pf, EntityId(methodId)));
105             if (name == "") {
106                 name = "anonymous";
107             }
108         }
109         data.append("    at ");
110         data.append(name);
111         data.append(" (maybe inlined).");
112         data.append(" depth: ");
113         data.append(std::to_string(it->first));
114 
115         data.push_back('\n');
116     }
117     return data;
118 }
119 
DumpJitCode(JSThread * thread)120 void JsStackInfo::DumpJitCode(JSThread *thread)
121 {
122     JSTaggedType exception = thread->GetException().GetRawData();
123     auto &jitCodeMaps = thread->GetJitCodeMaps();
124     auto jitCode = jitCodeMaps.find(exception);
125     if (jitCode == jitCodeMaps.end()) {
126         return;
127     }
128     std::set<MachineCode*> memos;
129     JsJitDumpElf jitDumpElf;
130     jitDumpElf.Init();
131     int64 idx = 0;
132     size_t offset = 0;
133     auto jitCodeVec = jitCodeMaps[exception];
134     for (size_t i = 0; i < jitCodeVec->size(); i++) {
135         auto item = (*jitCodeVec)[i];
136         auto machineCode = std::get<0>(item);
137         std::string methodName = std::get<1>(item);
138         uintptr_t pcOffset = std::get<2>(item);
139         auto res = memos.insert(machineCode);
140         if (res.second) {
141             LOG_ECMA(ERROR) << "jit : js crash at method : " << methodName << ", offset :" << pcOffset;
142             char *funcAddr = reinterpret_cast<char *>(machineCode->GetFuncAddr());
143             size_t len = machineCode->GetTextSize();
144             std::vector<uint8> vec(len);
145             if (memmove_s(vec.data(), len, funcAddr, len) != EOK) {
146                 LOG_ECMA(ERROR) << "Fail to get machineCode on function addr: " << funcAddr;
147             }
148             jitDumpElf.AppendData(vec);
149             jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, methodName);
150             offset += len;
151         }
152     }
153     std::string fileName = "jitCode-" + std::to_string(getpid());
154     std::string realOutPath;
155     std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(AotCrashInfo::GetSandBoxPath());
156     if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) {
157         return;
158     }
159     std::string outFile = realOutPath + "/" + fileName;
160     int fd = open(outFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
161     jitDumpElf.WriteJitElfFile(fd);
162     close(fd);
163 }
164 
AssembleJitCodeMap(JSThread * thread,const JSHandle<JSObject> & jsErrorObj,JSFunction * func,Method * method,uintptr_t offset)165 void AssembleJitCodeMap(JSThread *thread, const JSHandle<JSObject> &jsErrorObj, JSFunction *func, Method *method,
166                         uintptr_t offset)
167 {
168     ASSERT(!jsErrorObj.GetTaggedValue().IsUndefined());
169     JSTaggedValue machineCodeTagVal = func->GetMachineCode();
170     MachineCode *machineCode = MachineCode::Cast(machineCodeTagVal.GetTaggedObject());
171     std::string methodName = method->ParseFunctionName();
172     if (methodName.empty()) {
173         methodName = "anonymous";
174     }
175     thread->SetJitCodeMap(jsErrorObj.GetTaggedValue().GetRawData(), machineCode, methodName, offset);
176 }
177 
BuildJsStackTrace(JSThread * thread,bool needNative,const JSHandle<JSObject> & jsErrorObj)178 std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj)
179 {
180     std::string data;
181     data.reserve(InitialDeeps * InitialLength);
182     JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
183     FrameIterator it(current, thread);
184     uintptr_t baselineNativePc = 0;
185 
186     LastBuilderCache lastCache;
187     for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
188         if (it.GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME) {
189             auto *frame = it.GetFrame<BaselineBuiltinFrame>();
190             baselineNativePc = frame->GetReturnAddr();
191             continue;
192         }
193         if (!it.IsJSFrame()) {
194             continue;
195         }
196         auto method = it.CheckAndGetMethod();
197         if (method == nullptr) {
198             continue;
199         }
200         if (!method->IsNativeWithCallField()) {
201             uint32_t pcOffset = 0;
202             if (it.GetFrameType() == FrameType::ASM_INTERPRETER_FRAME && baselineNativePc != 0) {
203                 // the pcOffste in baseline frame slot is always uint64::max(), so pcOffset should be computed
204                 JSHandle<JSFunction> function(thread, it.GetFunction());
205                 pcOffset = RuntimeStubs::RuntimeGetBytecodePcOfstForBaseline(function, baselineNativePc);
206                 baselineNativePc = 0;
207             } else {
208                 pcOffset = it.GetBytecodeOffset();
209             }
210             data += BuildJsStackTraceInfo(thread, method, it, pcOffset, jsErrorObj, lastCache);
211         } else if (needNative) {
212             auto addr = method->GetNativePointer();
213             std::stringstream strm;
214             strm << addr;
215             data.append("    at native method (").append(strm.str()).append(")\n");
216         }
217     }
218     if (data.empty()) {
219 #if defined(ENABLE_EXCEPTION_BACKTRACE)
220         std::ostringstream stack;
221         Backtrace(stack);
222         data = stack.str();
223 #endif
224     }
225     return data;
226 }
227 
BuildJsStackTraceInfo(JSThread * thread,Method * method,FrameIterator & it,uint32_t pcOffset,const JSHandle<JSObject> & jsErrorObj,LastBuilderCache & lastCache)228 std::string JsStackInfo::BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it,
229                                                uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj,
230                                                LastBuilderCache &lastCache)
231 {
232     const JSPandaFile *pf = method->GetJSPandaFile();
233     std::map<uint32_t, uint32_t> methodOffsets = it.GetInlinedMethodInfo();
234     FrameType frameType = it.GetFrameType();
235     if (IsFastJitFunctionFrame(frameType)) {
236         JSFunction *func = static_cast<JSFunction*>(it.GetFunction().GetTaggedObject());
237         if (!jsErrorObj.GetTaggedValue().IsUndefined()) {
238             AssembleJitCodeMap(thread, jsErrorObj, func, method, it.GetOptimizedReturnAddr());
239         }
240     }
241     return BuildInlinedMethodTrace(pf, methodOffsets) +
242            BuildMethodTrace(method, pcOffset, lastCache, thread->GetEnableStackSourceFile());
243 }
244 
BuildCrashInfo(bool isJsCrash,uintptr_t pc,JSThread * thread)245 void JsStackInfo::BuildCrashInfo(bool isJsCrash, uintptr_t pc, JSThread *thread)
246 {
247     if (JsStackInfo::loader == nullptr || JsStackInfo::options == nullptr) {
248         return;
249     }
250     if (!JsStackInfo::loader->IsEnableAOT() && !Jit::GetInstance()->IsEnableFastJit() &&
251         !JsStackInfo::options->IsEnablePGOProfiler()) {
252         return;
253     }
254     ohos::RuntimeInfoType type;
255     if (isJsCrash) {
256         type = ohos::RuntimeInfoType::JS;
257     } else if (pc != 0 && JsStackInfo::loader != nullptr && JsStackInfo::loader->InsideAOT(pc)) {
258         type = ohos::RuntimeInfoType::AOT_CRASH;
259     } else {
260         type = ohos::RuntimeInfoType::OTHERS;
261     }
262     ohos::AotRuntimeInfo::GetInstance().BuildCrashRuntimeInfo(type);
263     if (isJsCrash && thread != nullptr) {
264         DumpJitCode(thread);
265     }
266 }
267 
BuildJsStackInfo(JSThread * thread,bool currentStack)268 std::vector<struct JsFrameInfo> JsStackInfo::BuildJsStackInfo(JSThread *thread, bool currentStack)
269 {
270     std::vector<struct JsFrameInfo> jsFrame;
271     uintptr_t *native = nullptr;
272     JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
273     FrameIterator it(current, thread);
274     for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) {
275         if (!it.IsJSFrame()) {
276             continue;
277         }
278         auto method = it.CheckAndGetMethod();
279         if (method == nullptr) {
280             continue;
281         }
282         struct JsFrameInfo frameInfo;
283         if (native != nullptr) {
284             frameInfo.nativePointer = native;
285             native = nullptr;
286         }
287         if (!method->IsNativeWithCallField()) {
288             std::string name = method->ParseFunctionName();
289             if (name.empty()) {
290                 frameInfo.functionName = "anonymous";
291             } else {
292                 frameInfo.functionName = name;
293             }
294             // source file
295             DebugInfoExtractor *debugExtractor =
296                 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
297             const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId());
298             if (sourceFile.empty()) {
299                 frameInfo.fileName = "?";
300             } else {
301                 frameInfo.fileName = sourceFile;
302             }
303             // line number and column number
304             int lineNumber = 0;
305             auto callbackLineFunc = [&frameInfo, &lineNumber](int32_t line) -> bool {
306                 lineNumber = line + 1;
307                 frameInfo.pos = std::to_string(lineNumber) + ":";
308                 return true;
309             };
310             auto callbackColumnFunc = [&frameInfo](int32_t column) -> bool {
311                 frameInfo.pos += std::to_string(column + 1);
312                 return true;
313             };
314             panda_file::File::EntityId methodId = method->GetMethodId();
315             uint32_t offset = it.GetBytecodeOffset();
316             if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
317                 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
318                 frameInfo.pos = "?";
319             }
320             jsFrame.push_back(std::move(frameInfo));
321             if (currentStack) {
322                 return jsFrame;
323             }
324         } else {
325             JSTaggedValue function = it.GetFunction();
326             JSHandle<JSTaggedValue> extraInfoValue(
327                 thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo());
328             if (extraInfoValue->IsJSNativePointer()) {
329                 JSHandle<JSNativePointer> extraInfo(extraInfoValue);
330                 native = reinterpret_cast<uintptr_t *>(extraInfo->GetData());
331             }
332         }
333     }
334     return jsFrame;
335 }
336 
ReadUintptrFromAddr(int pid,uintptr_t addr,uintptr_t & value,bool needCheckRegion)337 bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value, bool needCheckRegion)
338 {
339     if (pid == getpid()) {
340         if (needCheckRegion) {
341             bool flag = false;
342             auto callback = [addr, &flag](Region *region) {
343                 uintptr_t regionBegin = region->GetBegin();
344                 uintptr_t regionEnd = region->GetEnd();
345                 if (regionBegin <= addr && addr <= regionEnd) {
346                     flag = true;
347                 }
348             };
349             if (JsStackInfo::loader != nullptr) {
350                 const Heap *heap = JsStackInfo::loader->GetHeap();
351                 if (heap != nullptr) {
352                     heap->EnumerateRegions(callback);
353                 }
354             }
355             if (!flag) {
356                 LOG_ECMA(ERROR) << "addr not in Region, addr: " << addr;
357                 return false;
358             }
359         }
360         value = *(reinterpret_cast<uintptr_t *>(addr));
361         return true;
362     }
363     long *retAddr = reinterpret_cast<long *>(&value);
364     // note: big endian
365     for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
366         *retAddr = PtracePeektext(pid, addr);
367         if (*retAddr == -1) {
368             LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr;
369             return false;
370         }
371         addr += sizeof(long);
372         retAddr++;
373     }
374     return true;
375 }
376 
GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType,uintptr_t & typeOffset,uintptr_t & prevOffset)377 bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset)
378 {
379     FrameType type = static_cast<FrameType>(frameType);
380     switch (type) {
381         case FrameType::OPTIMIZED_FRAME:
382             typeOffset = OptimizedFrame::GetTypeOffset();
383             prevOffset = OptimizedFrame::GetPrevOffset();
384             break;
385         case FrameType::OPTIMIZED_ENTRY_FRAME:
386             typeOffset = OptimizedEntryFrame::GetTypeOffset();
387             prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset();
388             break;
389         case FrameType::BASELINE_BUILTIN_FRAME:
390             typeOffset = BaselineBuiltinFrame::GetTypeOffset();
391             prevOffset = BaselineBuiltinFrame::GetPrevOffset();
392             break;
393         case FrameType::ASM_BRIDGE_FRAME:
394             typeOffset = AsmBridgeFrame::GetTypeOffset();
395             prevOffset = AsmBridgeFrame::GetPrevOffset();
396             break;
397         case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
398             typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset();
399             prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset();
400             break;
401         case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
402         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
403         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
404             typeOffset = OptimizedJSFunctionFrame::GetTypeOffset();
405             prevOffset = OptimizedJSFunctionFrame::GetPrevOffset();
406             break;
407         case FrameType::LEAVE_FRAME:
408             typeOffset = OptimizedLeaveFrame::GetTypeOffset();
409             prevOffset = OptimizedLeaveFrame::GetPrevOffset();
410             break;
411         case FrameType::LEAVE_FRAME_WITH_ARGV:
412             typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset();
413             prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset();
414             break;
415         case FrameType::BUILTIN_CALL_LEAVE_FRAME:
416             typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset();
417             prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset();
418             break;
419         case FrameType::INTERPRETER_FRAME:
420         case FrameType::INTERPRETER_FAST_NEW_FRAME:
421             typeOffset = InterpretedFrame::GetTypeOffset();
422             prevOffset = InterpretedFrame::GetPrevOffset();
423             break;
424         case FrameType::INTERPRETER_BUILTIN_FRAME:
425             typeOffset = InterpretedBuiltinFrame::GetTypeOffset();
426             prevOffset = InterpretedBuiltinFrame::GetPrevOffset();
427             break;
428         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
429         case FrameType::ASM_INTERPRETER_FRAME:
430             typeOffset = AsmInterpretedFrame::GetTypeOffset();
431             prevOffset = AsmInterpretedFrame::GetPrevOffset();
432             break;
433         case FrameType::BUILTIN_FRAME:
434         case FrameType::BUILTIN_ENTRY_FRAME:
435             typeOffset = BuiltinFrame::GetTypeOffset();
436             prevOffset = BuiltinFrame::GetPrevOffset();
437             break;
438         case FrameType::BUILTIN_FRAME_WITH_ARGV:
439         case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
440             typeOffset = BuiltinWithArgvFrame::GetTypeOffset();
441             prevOffset = BuiltinWithArgvFrame::GetPrevOffset();
442             break;
443         case FrameType::INTERPRETER_ENTRY_FRAME:
444             typeOffset = InterpretedEntryFrame::GetTypeOffset();
445             prevOffset = InterpretedEntryFrame::GetPrevOffset();
446             break;
447         case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
448             typeOffset = AsmInterpretedEntryFrame::GetTypeOffset();
449             prevOffset = AsmInterpretedEntryFrame::GetPrevOffset();
450             break;
451         case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
452             typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset();
453             prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset();
454             break;
455         case FrameType::FASTJIT_FUNCTION_FRAME:
456         case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME:
457             typeOffset = FASTJITFunctionFrame::GetTypeOffset();
458             prevOffset = FASTJITFunctionFrame::GetPrevOffset();
459             break;
460         default:
461             return false;
462     }
463     return true;
464 }
465 
ArkFrameCheck(uintptr_t frameType)466 bool ArkFrameCheck(uintptr_t frameType)
467 {
468     return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME ||
469            static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME;
470 }
471 
IsFunctionFrame(uintptr_t frameType)472 bool IsFunctionFrame(uintptr_t frameType)
473 {
474     return static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_FRAME ||
475            static_cast<FrameType>(frameType) == FrameType::INTERPRETER_CONSTRUCTOR_FRAME ||
476            static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FRAME ||
477            static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FAST_NEW_FRAME ||
478            static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
479            static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME ||
480            static_cast<FrameType>(frameType) == FrameType::FASTJIT_FUNCTION_FRAME ||
481            static_cast<FrameType>(frameType) == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
482 }
483 
ReadMethodInfo(panda_file::MethodDataAccessor & mda)484 std::optional<MethodInfo> JSStackTrace::ReadMethodInfo(panda_file::MethodDataAccessor &mda)
485 {
486     uintptr_t methodId = mda.GetMethodId().GetOffset();
487     auto codeId = mda.GetCodeId();
488     if (!codeId) {
489         return std::nullopt;
490     }
491     panda_file::CodeDataAccessor cda(mda.GetPandaFile(), codeId.value());
492     uint32_t codeSize = cda.GetCodeSize();
493     uintptr_t codeBegin = reinterpret_cast<uintptr_t>(cda.GetInstructions());
494     return std::make_optional<MethodInfo>(methodId, codeBegin, codeSize);
495 }
496 
ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)497 CVector<MethodInfo> JSStackTrace::ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)
498 {
499     CVector<MethodInfo> result;
500     if (jsPandaFile == nullptr) {
501         LOG_ECMA(ERROR) << "Read all methods info in file failed, file is nullptr.";
502         return result;
503     }
504     const panda_file::File *pf = jsPandaFile->GetPandaFile();
505     Span<const uint32_t> classIndexes = jsPandaFile->GetClasses();
506     for (const uint32_t index : classIndexes) {
507         panda_file::File::EntityId classId(index);
508         if (jsPandaFile->IsExternal(classId)) {
509             continue;
510         }
511         panda_file::ClassDataAccessor cda(*pf, classId);
512         cda.EnumerateMethods([&result, jsPandaFile](panda_file::MethodDataAccessor &mda) {
513             auto info = JSStackTrace::ReadMethodInfo(mda);
514             if (!info) {
515                 return;
516             }
517             result.push_back(info.value());
518         });
519     }
520 
521     std::sort(result.begin(), result.end());
522     return result;
523 }
524 
TranslateByteCodePc(uintptr_t realPc,const CVector<MethodInfo> & vec)525 std::optional<CodeInfo> JSStackTrace::TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec)
526 {
527     int32_t left = 0;
528     ASSERT(vec.size() > 0);
529     int32_t right = static_cast<int32_t>(vec.size()) - 1;
530     for (; left <= right;) {
531         int32_t mid = (left + right) / 2;
532         bool isRight = realPc >= (vec[mid].codeBegin + vec[mid].codeSize);
533         bool isLeft = realPc < vec[mid].codeBegin;
534         // codeBegin <= realPc < codeBegin + codeSize
535         if (!isRight && !isLeft) {
536             return std::make_optional<CodeInfo>(realPc - vec[mid].codeBegin, vec[mid].methodId, vec[mid].codeSize);
537         } else if (isRight) {
538             left = mid + 1;
539         } else {
540             right = mid -1;
541         }
542     }
543     return std::nullopt;
544 }
545 
SaveFuncName(EntityId entityId,const std::string & name)546 void SaveFuncName(EntityId entityId, const std::string &name)
547 {
548     size_t length = 256; // maximum stack length
549     if (JsStackInfo::nameMap.size() > length) {
550         auto it = JsStackInfo::nameMap.begin();
551         JsStackInfo::nameMap.erase(it);
552     }
553     JsStackInfo::nameMap.emplace(entityId, name);
554 }
555 
556 template<typename T>
ParseJsFrameInfo(JSPandaFile * jsPandaFile,DebugInfoExtractor * debugExtractor,EntityId methodId,uintptr_t offset,T & jsFrame,SourceMap * sourceMap=nullptr)557 void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor,
558                       EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap = nullptr)
559 {
560     if (jsPandaFile == nullptr) {
561         LOG_ECMA(ERROR) << "Parse jsFrame info failed, jsPandaFile is nullptr.";
562         return;
563     }
564     std::string name = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
565     name = name.empty() ? "anonymous" : name;
566     SaveFuncName(methodId, name);
567     std::string url = debugExtractor->GetSourceFile(methodId);
568 
569     // line number and column number
570     int lineNumber = 0;
571     int columnNumber = 0;
572     auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
573         lineNumber = line + 1;
574         return true;
575     };
576     auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool {
577         columnNumber = column + 1;
578         return true;
579     };
580 
581     if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
582         !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
583         lineNumber = 0;
584         columnNumber = 0;
585     }
586 
587     if (sourceMap != nullptr) {
588         sourceMap->TranslateUrlPositionBySourceMap(url, lineNumber, columnNumber);
589     }
590 
591     size_t urlSize = url.size() + 1;
592     size_t nameSize = name.size() + 1;
593     if (strcpy_s(jsFrame.url, urlSize, url.c_str()) != EOK ||
594         strcpy_s(jsFrame.functionName, nameSize, name.c_str()) != EOK) {
595         LOG_ECMA(FATAL) << "jsFrame strcpy_s failed";
596         UNREACHABLE();
597     }
598     jsFrame.line = lineNumber;
599     jsFrame.column = columnNumber;
600 }
601 
ArkParseJsFrameInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorptr,JsFunction * jsFunction)602 bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset,
603                          uint8_t *data, uint64_t dataSize, uintptr_t extractorptr, JsFunction *jsFunction)
604 {
605     if (data == nullptr) {
606         LOG_ECMA(ERROR) << "Parse JSframe info failed, buffer is nullptr.";
607         return false;
608     }
609     loadOffset = loadOffset % PageSize();
610     auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
611     if (extractor == nullptr) {
612         LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr.";
613         return false;
614     }
615     auto jsPandaFile = extractor->GetJSPandaFile(data, dataSize);
616     if (jsPandaFile == nullptr) {
617         LOG_ECMA(ERROR) << "Parse JSframe info failed, panda file is nullptr.";
618         return false;
619     }
620     auto debugExtractor = extractor->GetDebugExtractor();
621     auto methodInfos = extractor->GetMethodInfos();
622     if (methodInfos.empty()) {
623         LOG_ECMA(ERROR) << "Read all method info from JSPandaFile failed, methodInfos is empty.";
624         return false;
625     }
626     uintptr_t realOffset = byteCodePc - mapBase - loadOffset;
627     uintptr_t pfBasePtr = reinterpret_cast<uintptr_t>(jsPandaFile->GetBase());
628     auto codeInfo = JSStackTrace::TranslateByteCodePc(realOffset + pfBasePtr, methodInfos);
629     if (!codeInfo) {
630         LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc;
631         return false;
632     }
633     if (!methodId) {
634         methodId = codeInfo->methodId;
635     }
636     auto offset = codeInfo->offset;
637     ParseJsFrameInfo(jsPandaFile, debugExtractor, EntityId(methodId), offset, *jsFunction, extractor->GetSourceMap());
638 
639     jsFunction->codeBegin = byteCodePc - offset;
640     jsFunction->codeSize = codeInfo->codeSize;
641     return true;
642 }
643 
ArkTranslateJsFrameInfo(uint8_t * data,size_t dataSize,JsFunction * jsFunction)644 bool ArkTranslateJsFrameInfo(uint8_t *data, size_t dataSize, JsFunction *jsFunction)
645 {
646     SourceMap sourceMap;
647     std::string strUrl = jsFunction->url;
648     sourceMap.Init(data, dataSize);
649     bool ret = sourceMap.TranslateUrlPositionBySourceMap(strUrl, jsFunction->line, jsFunction->column);
650     size_t strUrlSize = strUrl.size() + 1;
651     if (strcpy_s(jsFunction->url, strUrlSize, strUrl.c_str()) != EOK) {
652         LOG_FULL(FATAL) << "strcpy_s failed";
653         UNREACHABLE();
654     }
655     return ret;
656 }
657 
GetBytecodeOffset(void * ctx,ReadMemFunc readMem,uintptr_t frameType,uintptr_t currentPtr)658 uintptr_t GetBytecodeOffset(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr)
659 {
660     // currentPtr points to the frametype.
661     uintptr_t bytecodePc = 0;
662     FrameType type = static_cast<FrameType>(frameType);
663     switch (type) {
664         case FrameType::ASM_INTERPRETER_FRAME:
665         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
666             currentPtr -= AsmInterpretedFrame::GetTypeOffset();
667             currentPtr += AsmInterpretedFrame::GetPcOffset(false);
668             readMem(ctx, currentPtr, &bytecodePc);
669             return bytecodePc;
670         }
671         case FrameType::INTERPRETER_FRAME:
672         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
673             currentPtr -= InterpretedFrame::GetTypeOffset();
674             currentPtr += InterpretedFrame::GetPcOffset(false);
675             readMem(ctx, currentPtr, &bytecodePc);
676             return bytecodePc;
677         }
678         // aot get native pc
679         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
680         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
681             currentPtr -= OptimizedJSFunctionFrame::GetTypeOffset();
682             currentPtr += OptimizedJSFunctionFrame::GetReturnAddrOffset();
683             readMem(ctx, currentPtr, &bytecodePc);
684             return bytecodePc;
685         }
686         case FrameType::FASTJIT_FUNCTION_FRAME:
687         case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
688             currentPtr -= FASTJITFunctionFrame::GetTypeOffset();
689             readMem(ctx, currentPtr, &bytecodePc);
690             return bytecodePc;
691         }
692         default: {
693             break;
694         }
695     }
696     return 0;
697 }
698 
ArkGetFunction(void * ctx,ReadMemFunc readMem,uintptr_t currentPtr,uintptr_t frameType)699 uintptr_t ArkGetFunction(void *ctx, ReadMemFunc readMem, uintptr_t currentPtr, uintptr_t frameType)
700 {
701     FrameType type = static_cast<FrameType>(frameType);
702     uintptr_t funcAddr = currentPtr;
703     switch (type) {
704         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
705         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
706             funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset();
707             funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset();
708             break;
709         }
710         case FrameType::ASM_INTERPRETER_FRAME:
711         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
712             funcAddr -= AsmInterpretedFrame::GetTypeOffset();
713             funcAddr += AsmInterpretedFrame::GetFunctionOffset(false);
714             break;
715         }
716         case FrameType::INTERPRETER_FRAME:
717         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
718             funcAddr -= InterpretedFrame::GetTypeOffset();
719             funcAddr += InterpretedFrame::GetFunctionOffset();
720             break;
721         }
722         case FrameType::FASTJIT_FUNCTION_FRAME:
723         case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
724             funcAddr -= FASTJITFunctionFrame::GetTypeOffset();
725             funcAddr += FASTJITFunctionFrame::GetFunctionOffset();
726             break;
727         }
728         default: {
729             return 0;
730         }
731     }
732     uintptr_t function = 0;
733     if (!readMem(ctx, funcAddr, &function)) {
734         return 0;
735     }
736     return function;
737 }
738 
ArkCheckIsJSFunctionBaseOrJSProxy(void * ctx,ReadMemFunc readMem,uintptr_t objAddr,bool & isJSFunctionBase)739 bool ArkCheckIsJSFunctionBaseOrJSProxy(void *ctx, ReadMemFunc readMem, uintptr_t objAddr, bool &isJSFunctionBase)
740 {
741     bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U);
742     bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT);
743     if (isHeapObj && !isInvalidValue) {
744         ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U),
745                      "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr);
746         uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET;
747         uintptr_t hclass = 0;
748         if (!readMem(ctx, hclassAddr, &hclass)) {
749             return false;
750         }
751         if (hclass != 0) {
752             uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET);
753             uintptr_t bits = 0;
754             if (!readMem(ctx, bitsAddr, &bits)) {
755                 return false;
756             }
757             JSType jsType = JSHClass::ObjectTypeBits::Decode(bits);
758             isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION);
759             bool isJSProxy = (jsType == JSType::JS_PROXY);
760             return isJSFunctionBase || isJSProxy;
761         }
762     }
763     return false;
764 }
765 
ArkCheckAndGetMethod(void * ctx,ReadMemFunc readMem,uintptr_t value)766 uintptr_t ArkCheckAndGetMethod(void *ctx, ReadMemFunc readMem, uintptr_t value)
767 {
768     bool isJSFunctionBase = 0;
769     if (ArkCheckIsJSFunctionBaseOrJSProxy(ctx, readMem, value, isJSFunctionBase)) {
770         if (isJSFunctionBase) {
771             value += JSFunctionBase::METHOD_OFFSET;
772         } else {
773             value += JSProxy::METHOD_OFFSET;
774         }
775         uintptr_t method = 0;
776         if (!readMem(ctx, value, &method)) {
777             return 0;
778         }
779         return method;
780     }
781     return 0;
782 }
783 
ArkGetMethodIdFromMethod(void * ctx,ReadMemFunc readMem,uintptr_t method,uintptr_t & methodId)784 bool ArkGetMethodIdFromMethod(void *ctx, ReadMemFunc readMem, uintptr_t method, uintptr_t &methodId)
785 {
786     uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET;
787     uintptr_t methodLiteral = 0;
788     if (!readMem(ctx, methodLiteralAddr, &methodLiteral)) {
789         return false;
790     }
791     methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral);
792     return true;
793 }
794 
ArkGetMethodId(void * ctx,ReadMemFunc readMem,uintptr_t frameType,uintptr_t currentPtr,uintptr_t & methodId)795 bool ArkGetMethodId(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr, uintptr_t &methodId)
796 {
797     uintptr_t function = ArkGetFunction(ctx, readMem, currentPtr, frameType);
798     if (!function) {
799         LOG_ECMA(DEBUG) << "Failed to get function";
800         return false;
801     }
802 
803     uintptr_t method = ArkCheckAndGetMethod(ctx, readMem, function);
804     if (!method) {
805         LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function;
806         return false;
807     }
808 
809     if (!ArkGetMethodIdFromMethod(ctx, readMem, method, methodId)) {
810         LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method;
811         return false;
812     }
813     return true;
814 }
815 
ArkGetNextFrame(void * ctx,ReadMemFunc readMem,uintptr_t & currentPtr,uintptr_t & frameType,uintptr_t & pc,uintptr_t * methodId)816 bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t &currentPtr,
817                      uintptr_t &frameType, uintptr_t &pc, uintptr_t *methodId)
818 {
819     currentPtr -= sizeof(FrameType);
820     if (!readMem(ctx, currentPtr, &frameType)) {
821         return false;
822     }
823     if (ArkFrameCheck(frameType)) {
824         return true;
825     }
826     bool ret = false;
827     if (IsFunctionFrame(frameType)) {
828         pc = GetBytecodeOffset(ctx, readMem, frameType, currentPtr);
829         ret = true;
830         if (methodId != nullptr) {
831             ret = ArkGetMethodId(ctx, readMem, frameType, currentPtr, *methodId);
832         }
833     }
834 
835     uintptr_t typeOffset = 0;
836     uintptr_t prevOffset = 0;
837     if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
838         return false;
839     }
840     currentPtr -= typeOffset;
841     currentPtr += prevOffset;
842     if (!readMem(ctx, currentPtr, &currentPtr)) {
843         return false;
844     }
845 
846     if (ret) {
847         return true;
848     }
849     return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc, methodId);
850 }
851 
ArkGetMethodIdWithJit(ArkUnwindParam * arkUnwindParam,uintptr_t frameType,uintptr_t currentPtr)852 bool ArkGetMethodIdWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t frameType, uintptr_t currentPtr)
853 {
854     uintptr_t function = ArkGetFunction(arkUnwindParam->ctx, arkUnwindParam->readMem, currentPtr, frameType);
855     if (!function) {
856         LOG_ECMA(DEBUG) << "Failed to get function";
857         return false;
858     }
859 
860     uintptr_t method = ArkCheckAndGetMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, function);
861     if (!method) {
862         LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function;
863         return false;
864     }
865 
866     if (!ArkGetMethodIdFromMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, method, *arkUnwindParam->methodId)) {
867         LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method;
868         return false;
869     }
870 
871     if (IsFastJitFunctionFrame(static_cast<FrameType>(frameType))) {
872         uintptr_t machineCode = 0;
873         uintptr_t functionAddr = function + JSFunction::MACHINECODE_OFFSET;
874         arkUnwindParam->readMem(arkUnwindParam->ctx, functionAddr, &machineCode);
875         uintptr_t size = 0;
876         uintptr_t funcAddr = 0;
877         if (machineCode) {
878             arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::INSTRSIZ_OFFSET, &size);
879             arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::FUNCADDR_OFFSET, &funcAddr);
880         }
881         if (size && funcAddr) {
882             // take the lower four bytes
883             size &= 0xFFFFFFFF;
884             std::vector<uint8> codeVec;
885             for (size_t l = 0; l < size; l++) {
886                 uintptr_t tmp = 0;
887                 arkUnwindParam->readMem(arkUnwindParam->ctx, funcAddr + l, &tmp);
888                 codeVec.push_back(tmp);
889             }
890             arkUnwindParam->jitCache.push_back(*arkUnwindParam->methodId);
891             JsStackInfo::machineCodeMap[EntityId(*arkUnwindParam->methodId)] = codeVec;
892         }
893     }
894     return true;
895 }
896 
ArkGetNextFrameWithJit(ArkUnwindParam * arkUnwindParam,uintptr_t & currentPtr,uintptr_t & frameType)897 bool ArkGetNextFrameWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t &currentPtr, uintptr_t &frameType)
898 {
899     currentPtr -= sizeof(FrameType);
900     if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, &frameType)) {
901         return false;
902     }
903     if (ArkFrameCheck(frameType)) {
904         return true;
905     }
906     bool ret = false;
907     if (IsFunctionFrame(frameType)) {
908         *arkUnwindParam->pc = GetBytecodeOffset(arkUnwindParam->ctx, arkUnwindParam->readMem, frameType, currentPtr);
909         ret = true;
910         if (arkUnwindParam->methodId != nullptr) {
911             ret = ArkGetMethodIdWithJit(arkUnwindParam, frameType, currentPtr);
912         }
913     }
914 
915     uintptr_t typeOffset = 0;
916     uintptr_t prevOffset = 0;
917     if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
918         return false;
919     }
920     currentPtr -= typeOffset;
921     currentPtr += prevOffset;
922     if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, &currentPtr)) {
923         return false;
924     }
925 
926     if (ret) {
927         return true;
928     }
929     return ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType);
930 }
931 
ArkWriteJitCode(void * ctx,ReadMemFunc readMem,int fd,const uintptr_t * const jitCodeArray,const size_t jitSize)932 bool ArkWriteJitCode([[maybe_unused]] void *ctx, [[maybe_unused]] ReadMemFunc readMem,
933                      int fd, const uintptr_t *const jitCodeArray, const size_t jitSize)
934 {
935     JsJitDumpElf jitDumpElf;
936     jitDumpElf.Init();
937     std::set<uintptr_t> memos;
938     int64 idx = 0;
939     size_t offset = 0;
940     for (size_t i = 0; i < jitSize; i++) {
941         uintptr_t methodId = jitCodeArray[i];
942         auto res = memos.insert(methodId);
943         if (res.second) {
944             std::vector<uint8> codeVec = JsStackInfo::machineCodeMap[EntityId(methodId)];
945             std::string name = JsStackInfo::nameMap[EntityId(methodId)];
946             size_t len = codeVec.size();
947             jitDumpElf.AppendData(codeVec);
948             jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, name);
949             offset += len;
950         }
951     }
952     jitDumpElf.WriteJitElfFile(fd);
953     JsStackInfo::nameMap.clear();
954     JsStackInfo::machineCodeMap.clear();
955     return true;
956 }
957 
StepArkWithRecordJit(ArkUnwindParam * arkUnwindParam)958 bool StepArkWithRecordJit(ArkUnwindParam *arkUnwindParam)
959 {
960     constexpr size_t FP_SIZE = sizeof(uintptr_t);
961     uintptr_t currentPtr = *arkUnwindParam->fp;
962     if (currentPtr == 0) {
963         LOG_ECMA(ERROR) << "fp is nullptr in StepArkWithRecordJit()!";
964         return false;
965     }
966 
967     uintptr_t frameType = 0;
968     if (ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType)) {
969         if (ArkFrameCheck(frameType)) {
970             currentPtr += sizeof(FrameType);
971             *arkUnwindParam->sp = currentPtr;
972             bool ret = arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->fp);
973             currentPtr += FP_SIZE;
974             ret &= arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->pc);
975             *arkUnwindParam->isJsFrame = false;
976             return ret;
977         } else {
978             *arkUnwindParam->fp = currentPtr;
979             *arkUnwindParam->sp = currentPtr;
980             *arkUnwindParam->isJsFrame = true;
981         }
982     } else {
983         LOG_ECMA(ERROR) << "ArkGetNextFrame failed, currentPtr: " << currentPtr << ", frameType: " << frameType;
984         return false;
985     }
986     return true;
987 }
988 
StepArk(void * ctx,ReadMemFunc readMem,uintptr_t * fp,uintptr_t * sp,uintptr_t * pc,uintptr_t * methodId,bool * isJsFrame)989 bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
990              uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame)
991 {
992     constexpr size_t FP_SIZE = sizeof(uintptr_t);
993     uintptr_t currentPtr = *fp;
994     if (currentPtr == 0) {
995         LOG_ECMA(ERROR) << "fp is nullptr in StepArk()!";
996         return false;
997     }
998 
999     uintptr_t frameType = 0;
1000     if (ArkGetNextFrame(ctx, readMem, currentPtr, frameType, *pc, methodId)) {
1001         if (ArkFrameCheck(frameType)) {
1002             currentPtr += sizeof(FrameType);
1003             *sp = currentPtr;
1004             bool ret = readMem(ctx, currentPtr, fp);
1005             currentPtr += FP_SIZE;
1006             ret &= readMem(ctx, currentPtr, pc);
1007             *isJsFrame = false;
1008             return ret;
1009         } else {
1010             *fp = currentPtr;
1011             *sp = currentPtr;
1012             *isJsFrame = true;
1013         }
1014     } else {
1015         LOG_ECMA(ERROR) << std::hex << "ArkGetNextFrame failed, addr: " << currentPtr;
1016         return false;
1017     }
1018 
1019     return true;
1020 }
1021 
ArkGetFunction(int pid,uintptr_t currentPtr,uintptr_t frameType)1022 uintptr_t ArkGetFunction(int pid, uintptr_t currentPtr, uintptr_t frameType)
1023 {
1024     FrameType type = static_cast<FrameType>(frameType);
1025     uintptr_t funcAddr = currentPtr;
1026     switch (type) {
1027         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
1028         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
1029             funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset();
1030             funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset();
1031             break;
1032         }
1033         case FrameType::ASM_INTERPRETER_FRAME:
1034         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
1035             funcAddr -= AsmInterpretedFrame::GetTypeOffset();
1036             funcAddr += AsmInterpretedFrame::GetFunctionOffset(false);
1037             break;
1038         }
1039         case FrameType::INTERPRETER_FRAME:
1040         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
1041             funcAddr -= InterpretedFrame::GetTypeOffset();
1042             funcAddr += InterpretedFrame::GetFunctionOffset();
1043             break;
1044         }
1045         case FrameType::INTERPRETER_BUILTIN_FRAME: {
1046             funcAddr -= InterpretedBuiltinFrame::GetTypeOffset();
1047             funcAddr += InterpretedBuiltinFrame::GetFunctionOffset();
1048             break;
1049         }
1050         case FrameType::BUILTIN_FRAME_WITH_ARGV: {
1051             funcAddr += sizeof(FrameType);
1052             auto topAddress = funcAddr +
1053                 (static_cast<int>(BuiltinWithArgvFrame::Index::StackArgsTopIndex) * sizeof(uintptr_t));
1054             uintptr_t argcAddress = static_cast<uintptr_t>(funcAddr + (static_cast<int>
1055                                     (BuiltinWithArgvFrame::Index::NumArgsIndex) * sizeof(uintptr_t)));
1056             if (!ReadUintptrFromAddr(pid, argcAddress, argcAddress, g_needCheck)) {
1057                 return 0;
1058             }
1059             auto numberArgs = argcAddress + NUM_MANDATORY_JSFUNC_ARGS;
1060             funcAddr = topAddress - static_cast<uint32_t>(numberArgs) * sizeof(uintptr_t);
1061             break;
1062         }
1063         case FrameType::BUILTIN_ENTRY_FRAME:
1064         case FrameType::BUILTIN_FRAME: {
1065             funcAddr -= BuiltinFrame::GetTypeOffset();
1066             funcAddr += BuiltinFrame::GetStackArgsOffset();
1067             break;
1068         }
1069         case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
1070             funcAddr -= OptimizedBuiltinLeaveFrame::GetTypeOffset();
1071             funcAddr += OptimizedBuiltinLeaveFrame::GetFunctionOffset();
1072             break;
1073         }
1074         case FrameType::FASTJIT_FUNCTION_FRAME:
1075         case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
1076             funcAddr -= FASTJITFunctionFrame::GetTypeOffset();
1077             funcAddr += FASTJITFunctionFrame::GetFunctionOffset();
1078             break;
1079         }
1080         case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
1081         case FrameType::OPTIMIZED_FRAME:
1082         case FrameType::OPTIMIZED_ENTRY_FRAME:
1083         case FrameType::ASM_BRIDGE_FRAME:
1084         case FrameType::LEAVE_FRAME:
1085         case FrameType::LEAVE_FRAME_WITH_ARGV:
1086         case FrameType::INTERPRETER_ENTRY_FRAME:
1087         case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
1088         case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
1089         case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
1090         case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: {
1091             return 0;
1092         }
1093         default: {
1094             LOG_FULL(FATAL) << "Unknown frame type: " << static_cast<uintptr_t>(type);
1095             UNREACHABLE();
1096         }
1097     }
1098     uintptr_t function = 0;
1099     if (!ReadUintptrFromAddr(pid, funcAddr, function, g_needCheck)) {
1100         return 0;
1101     }
1102     return function;
1103 }
1104 
ArkCheckIsJSFunctionBaseOrJSProxy(int pid,uintptr_t objAddr,bool & isJSFunctionBase)1105 bool ArkCheckIsJSFunctionBaseOrJSProxy(int pid, uintptr_t objAddr, bool &isJSFunctionBase)
1106 {
1107     bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U);
1108     bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT);
1109     if (isHeapObj && !isInvalidValue) {
1110         ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U),
1111                      "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr);
1112         uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET;
1113         uintptr_t hclass = 0;
1114         if (!ReadUintptrFromAddr(pid, hclassAddr, hclass, g_needCheck)) {
1115             return false;
1116         }
1117         if (hclass != 0) {
1118             uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET);
1119             uintptr_t bits = 0;
1120             if (!ReadUintptrFromAddr(pid, bitsAddr, bits, g_needCheck)) {
1121                 return false;
1122             }
1123             JSType jsType = JSHClass::ObjectTypeBits::Decode(bits);
1124             isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION);
1125             bool isJSProxy = (jsType == JSType::JS_PROXY);
1126             return isJSFunctionBase || isJSProxy;
1127         }
1128     }
1129     return false;
1130 }
1131 
ArkCheckAndGetMethod(int pid,uintptr_t value)1132 uintptr_t ArkCheckAndGetMethod(int pid, uintptr_t value)
1133 {
1134     bool isJSFunctionBase = 0;
1135     if (ArkCheckIsJSFunctionBaseOrJSProxy(pid, value, isJSFunctionBase)) {
1136         if (isJSFunctionBase) {
1137             value += JSFunctionBase::METHOD_OFFSET;
1138         } else {
1139             value += JSProxy::METHOD_OFFSET;
1140         }
1141         uintptr_t method = 0;
1142         if (!ReadUintptrFromAddr(pid, value, method, g_needCheck)) {
1143             return 0;
1144         }
1145         return method;
1146     }
1147     return 0;
1148 }
1149 
ArkGetMethodIdandJSPandaFileAddr(int pid,uintptr_t method,uintptr_t & methodId,uintptr_t & jsPandaFileAddr)1150 bool ArkGetMethodIdandJSPandaFileAddr(int pid, uintptr_t method, uintptr_t &methodId, uintptr_t &jsPandaFileAddr)
1151 {
1152     uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET;
1153     uintptr_t methodLiteral = 0;
1154     if (!ReadUintptrFromAddr(pid, methodLiteralAddr, methodLiteral, g_needCheck)) {
1155         return false;
1156     }
1157     methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral);
1158     uintptr_t constantpoolAddr = method + Method::CONSTANT_POOL_OFFSET;
1159     uintptr_t constantpool = 0;
1160     if (!ReadUintptrFromAddr(pid, constantpoolAddr, constantpool, g_needCheck)) {
1161         return false;
1162     }
1163     if (constantpool == JSTaggedValue::VALUE_UNDEFINED) {
1164         return false;
1165     }
1166     uintptr_t lengthAddr = constantpool + TaggedArray::LENGTH_OFFSET;
1167     uintptr_t length = 0;
1168     if (!ReadUintptrFromAddr(pid, lengthAddr, length, g_needCheck)) {
1169         return false;
1170     }
1171     jsPandaFileAddr = constantpool + TaggedArray::DATA_OFFSET +
1172                     JSTaggedValue::TaggedTypeSize() * (length - ConstantPool::JS_PANDA_FILE_INDEX);
1173     if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFileAddr, g_needCheck)) {
1174         return false;
1175     }
1176     return true;
1177 }
1178 
ArkGetOffsetFromMethod(int pid,uintptr_t currentPtr,uintptr_t method)1179 uint32_t ArkGetOffsetFromMethod(int pid, uintptr_t currentPtr, uintptr_t method)
1180 {
1181     uintptr_t pc = 0;
1182     if (!ReadUintptrFromAddr(pid, currentPtr, pc, g_needCheck)) {
1183         return 0;
1184     }
1185     uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET;
1186     uintptr_t byteCodeArray = 0;
1187     if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, g_needCheck)) {
1188         return 0;
1189     }
1190     uintptr_t offset = pc - byteCodeArray;
1191     return static_cast<uint32_t>(offset);
1192 }
1193 
ArkGetBytecodeOffset(int pid,uintptr_t method,uintptr_t frameType,uintptr_t currentPtr)1194 uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, uintptr_t currentPtr)
1195 {
1196     FrameType type = static_cast<FrameType>(frameType);
1197     switch (type) {
1198         case FrameType::ASM_INTERPRETER_FRAME:
1199         case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
1200             currentPtr -= AsmInterpretedFrame::GetTypeOffset();
1201             currentPtr += AsmInterpretedFrame::GetPcOffset(false);
1202             return ArkGetOffsetFromMethod(pid, currentPtr, method);
1203         }
1204         case FrameType::INTERPRETER_FRAME:
1205         case FrameType::INTERPRETER_FAST_NEW_FRAME: {
1206             currentPtr -= InterpretedFrame::GetTypeOffset();
1207             currentPtr += InterpretedFrame::GetPcOffset(false);
1208             return ArkGetOffsetFromMethod(pid, currentPtr, method);
1209         }
1210         // aot need stackmaps
1211         case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
1212         case FrameType::OPTIMIZED_JS_FUNCTION_FRAME:
1213         case FrameType::FASTJIT_FUNCTION_FRAME:
1214         case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
1215             break;
1216         }
1217         default: {
1218             break;
1219         }
1220     }
1221     return 0;
1222 }
1223 
ArkGetFilePath(std::string & fileName)1224 std::string ArkGetFilePath(std::string &fileName)
1225 {
1226     auto lastSlash = fileName.rfind("/");
1227     if (lastSlash == std::string::npos) {
1228         LOG_ECMA(ERROR) << "ArkGetFilePath can't find fisrt /: " << fileName;
1229         return "";
1230     }
1231     if (lastSlash == 0) {
1232         LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName;
1233         return "";
1234     }
1235 
1236     auto secondLastSlash = fileName.rfind("/", lastSlash - 1);
1237     if (secondLastSlash == std::string::npos) {
1238         LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName;
1239         return "";
1240     }
1241 
1242     std::string mapPath = fileName.substr(secondLastSlash + 1);
1243     return mapPath;
1244 }
1245 
ArkIsNativeWithCallField(int pid,uintptr_t method)1246 bool ArkIsNativeWithCallField(int pid, uintptr_t method)
1247 {
1248     uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET;
1249     uintptr_t callField = 0;
1250     if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, g_needCheck)) {
1251         return true;
1252     }
1253     return Method::IsNativeBit::Decode(callField);
1254 }
1255 
ArkReadCStringFromAddr(int pid,uintptr_t descAddr)1256 std::string ArkReadCStringFromAddr(int pid, uintptr_t descAddr)
1257 {
1258     std::string name;
1259     bool key = true;
1260     while (key) {
1261         uintptr_t desc = 0;
1262         if (!ReadUintptrFromAddr(pid, descAddr, desc, g_needCheck)) {
1263             LOG_ECMA(ERROR) << "ArkReadCStringFromAddr failed, descAddr: " << descAddr;
1264             return name;
1265         }
1266         size_t shiftAmount = 8;
1267         for (size_t i = 0; i < sizeof(long); i++) {
1268             char bottomEightBits = static_cast<char>(desc);
1269             desc = desc >> shiftAmount;
1270             if (!bottomEightBits) {
1271                 key = false;
1272                 break;
1273             }
1274             name += bottomEightBits;
1275         }
1276         if (!key) {
1277             break;
1278         }
1279         descAddr += sizeof(long);
1280     }
1281     return name;
1282 }
1283 
ArkGetFileName(int pid,uintptr_t jsPandaFileAddr,std::string & hapPath)1284 std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr, std::string &hapPath)
1285 {
1286     size_t size = sizeof(JSPandaFile) / sizeof(long);
1287     uintptr_t *jsPandaFilePart = new uintptr_t[size]();
1288     if (jsPandaFilePart == nullptr) {
1289         LOG_ECMA(FATAL) << "ArkGetFileName:jsPandaFilePart is nullptr";
1290     }
1291     for (size_t i = 0; i < size; i++) {
1292         if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], g_needCheck)) {
1293             LOG_ECMA(ERROR) << "ArkGetFilePath failed, jsPandaFileAddr: " << jsPandaFileAddr;
1294             delete []jsPandaFilePart;
1295             return "";
1296         }
1297         jsPandaFileAddr += sizeof(long);
1298     }
1299     JSPandaFile *jsPandaFile = reinterpret_cast<JSPandaFile *>(jsPandaFilePart);
1300 
1301     uintptr_t hapPathAddr = reinterpret_cast<uintptr_t>(
1302         const_cast<char *>(jsPandaFile->GetJSPandaFileHapPath().c_str()));
1303     hapPath = ArkReadCStringFromAddr(pid, hapPathAddr);
1304 
1305     uintptr_t descAddr = reinterpret_cast<uintptr_t>(
1306         const_cast<char *>(jsPandaFile->GetJSPandaFileDesc().c_str()));
1307     delete []jsPandaFilePart;
1308     return ArkReadCStringFromAddr(pid, descAddr);
1309 }
1310 
ArkReadData(const std::string & hapPath,const std::string & fileName,size_t & dataSize)1311 std::unique_ptr<uint8_t[]> ArkReadData([[maybe_unused]] const std::string &hapPath,
1312                                        [[maybe_unused]] const std::string &fileName,
1313                                        [[maybe_unused]] size_t &dataSize)
1314 {
1315     std::unique_ptr<uint8_t[]> dataPtr = nullptr;
1316 #if defined(PANDA_TARGET_OHOS)
1317     bool newCreate = false;
1318     std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
1319         ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
1320     if (extractor == nullptr) {
1321         LOG_ECMA(ERROR) << "Ark read data failed, hapPath: " << hapPath;
1322         return dataPtr;
1323     }
1324     if (!extractor->ExtractToBufByName(fileName, dataPtr, dataSize)) {
1325         LOG_ECMA(ERROR) << "Ark read data failed, hap/hsp path: " << hapPath << ", file name: " << fileName;
1326         return dataPtr;
1327     }
1328 #endif
1329     return dataPtr;
1330 }
1331 
OpenJSPandaFileByReadData(const std::string & hapPath,const std::string & fileName)1332 std::shared_ptr<JSPandaFile> OpenJSPandaFileByReadData(const std::string &hapPath, const std::string &fileName)
1333 {
1334     size_t dataSize = 0;
1335     auto data = ArkReadData(hapPath, fileName, dataSize);
1336     if (data == nullptr) {
1337         return nullptr;
1338     }
1339     auto pf = panda_file::OpenPandaFileFromMemory(data.get(), dataSize);
1340     if (pf == nullptr) {
1341         return nullptr;
1342     }
1343     return std::make_shared<JSPandaFile>(pf.release(), fileName.c_str());
1344 }
1345 
ArkParseJsFrameDebugInfos(const std::vector<JsFrameDebugInfo> & JsFrameDebugInfos,size_t size,JsFrame * jsFrame,size_t & jsFrameIndex)1346 void ArkParseJsFrameDebugInfos([[maybe_unused]] const std::vector<JsFrameDebugInfo> &JsFrameDebugInfos,
1347                                [[maybe_unused]] size_t size, [[maybe_unused]] JsFrame *jsFrame,
1348                                [[maybe_unused]] size_t &jsFrameIndex)
1349 {
1350 #if defined(PANDA_TARGET_OHOS)
1351     jsFrameIndex = 0;
1352     size = JsFrameDebugInfos.size() > size ? size : JsFrameDebugInfos.size();
1353     std::unordered_map<std::string, std::shared_ptr<JSPandaFile>> jsPandaFileTable;
1354     for (size_t i = 0; i < size; ++i) {
1355         auto fileIter = jsPandaFileTable.find(JsFrameDebugInfos[i].hapPath);
1356         if (fileIter == jsPandaFileTable.end()) {
1357             auto jsPandaFile = OpenJSPandaFileByReadData(JsFrameDebugInfos[i].hapPath, JsFrameDebugInfos[i].filePath);
1358             if (jsPandaFile != nullptr) {
1359                 jsPandaFileTable.emplace(JsFrameDebugInfos[i].hapPath, jsPandaFile);
1360                 auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get());
1361                 ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId,
1362                     JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]);
1363                 jsFrameIndex++;
1364             }
1365         } else {
1366             auto jsPandaFile = fileIter->second;
1367             auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get());
1368             ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId,
1369                 JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]);
1370             jsFrameIndex++;
1371         }
1372     }
1373 #endif
1374 }
1375 
ArkGetJsFrameDebugInfo(int pid,uintptr_t currentPtr,uintptr_t frameType,std::vector<JsFrameDebugInfo> & JsFrameDebugInfos)1376 bool ArkGetJsFrameDebugInfo(int pid, uintptr_t currentPtr, uintptr_t frameType,
1377                             std::vector<JsFrameDebugInfo> &JsFrameDebugInfos)
1378 {
1379     uintptr_t function = ArkGetFunction(pid, currentPtr, frameType);
1380     if (!function) {
1381         return false;
1382     }
1383 
1384     uintptr_t method = ArkCheckAndGetMethod(pid, function);
1385     if (!method || ArkIsNativeWithCallField(pid, method)) {
1386         return false;
1387     }
1388     uintptr_t jsPandaFileAddr = 0;
1389     uintptr_t methodId = 0;
1390     if (!ArkGetMethodIdandJSPandaFileAddr(pid, method, methodId, jsPandaFileAddr)) {
1391         LOG_ECMA(ERROR) << "ArkGetJsFrameDebugInfo failed, method: " << method;
1392         return false;
1393     }
1394     uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr);
1395     std::string hapPath;
1396     std::string fileName = ArkGetFileName(pid, jsPandaFileAddr, hapPath);
1397     if (fileName.empty() || hapPath.empty()) {
1398         LOG_ECMA(DEBUG) << "ArkGetJsFrameDebugInfo get filename or hapPath failed, fileName: "
1399                         << fileName << ", hapPath: "<< hapPath;
1400         return false;
1401     }
1402     std::string filePath = ArkGetFilePath(fileName);
1403     if (filePath.empty()) {
1404         return false;
1405     }
1406     JsFrameDebugInfo JsFrameDebugInfo(EntityId(methodId), offset, hapPath, filePath);
1407     JsFrameDebugInfos.push_back(std::move(JsFrameDebugInfo));
1408     return true;
1409 }
1410 
ArkGetNextFrame(int pid,uintptr_t frameType,uintptr_t & currentPtr)1411 bool ArkGetNextFrame(int pid, uintptr_t frameType, uintptr_t &currentPtr)
1412 {
1413     uintptr_t typeOffset = 0;
1414     uintptr_t prevOffset = 0;
1415     if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) {
1416         LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
1417         return false;
1418     }
1419     currentPtr -= typeOffset;
1420     currentPtr += prevOffset;
1421     if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, g_needCheck)) {
1422         return false;
1423     }
1424     if (currentPtr == 0) {
1425         LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!";
1426         return false;
1427     }
1428     return true;
1429 }
1430 
GetArkNativeFrameInfo(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,JsFrame * jsFrame,size_t & size)1431 bool GetArkNativeFrameInfo([[maybe_unused]] int pid, [[maybe_unused]] uintptr_t *pc,
1432                            [[maybe_unused]] uintptr_t *fp, [[maybe_unused]] uintptr_t *sp,
1433                            [[maybe_unused]] JsFrame *jsFrame, [[maybe_unused]] size_t &size)
1434 {
1435 #if defined(PANDA_TARGET_OHOS)
1436     constexpr size_t FP_SIZE = sizeof(uintptr_t);
1437     uintptr_t currentPtr = *fp;
1438     if (pid == getpid()) {
1439         g_needCheck = false;
1440     }
1441     if (currentPtr == 0) {
1442         LOG_ECMA(ERROR) << "fp is nullptr in GetArkNativeFrameInfo()!";
1443         return false;
1444     }
1445 
1446     if (pid == getpid() && JsStackInfo::loader != nullptr &&
1447         !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) {
1448         LOG_ECMA(ERROR) << "invalid pc in StepArkManagedNativeFrame()!";
1449         return false;
1450     }
1451 
1452     std::vector<JsFrameDebugInfo> JsFrameDebugInfos;
1453     bool ret = true;
1454     while (true) {
1455         currentPtr -= sizeof(FrameType);
1456         uintptr_t frameType = 0;
1457         if (!ReadUintptrFromAddr(pid, currentPtr, frameType, g_needCheck)) {
1458             return false;
1459         }
1460         if (g_needCheck && IsFunctionFrame(frameType)) {
1461             ArkGetJsFrameDebugInfo(pid, currentPtr, frameType, JsFrameDebugInfos);
1462         } else if (ArkFrameCheck(frameType)) {
1463             currentPtr += sizeof(FrameType);
1464             *sp = currentPtr;
1465             ret &= ReadUintptrFromAddr(pid, currentPtr, *fp, g_needCheck);
1466             currentPtr += FP_SIZE;
1467             ret &= ReadUintptrFromAddr(pid, currentPtr, *pc, g_needCheck);
1468             break;
1469         }
1470 
1471         if (!ArkGetNextFrame(pid, frameType, currentPtr)) {
1472             return false;
1473         }
1474     }
1475     if (g_needCheck && !JsFrameDebugInfos.empty()) {
1476         ArkParseJsFrameDebugInfos(JsFrameDebugInfos, size, jsFrame, size);
1477     } else {
1478         size = 0;
1479     }
1480     return ret;
1481 #else
1482     return false;
1483 #endif
1484 }
1485 
GetData()1486 uint8_t* JSSymbolExtractor::GetData()
1487 {
1488     return data_;
1489 }
1490 
GetLoadOffset()1491 uintptr_t JSSymbolExtractor::GetLoadOffset()
1492 {
1493     return loadOffset_;
1494 }
1495 
GetDataSize()1496 uintptr_t JSSymbolExtractor::GetDataSize()
1497 {
1498     return dataSize_;
1499 }
1500 
ParseHapFileData(std::string & hapName)1501 bool JSSymbolExtractor::ParseHapFileData([[maybe_unused]] std::string& hapName)
1502 {
1503     bool ret = false;
1504 #if defined(PANDA_TARGET_OHOS)
1505     if (hapName.empty()) {
1506         LOG_ECMA(ERROR) << "Get file data failed, path empty.";
1507         return false;
1508     }
1509     bool newCreate = false;
1510     std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(hapName, newCreate);
1511     if (extractor == nullptr) {
1512         LOG_ECMA(ERROR) << "GetExtractor failed, hap path: " << hapName;
1513         return false;
1514     }
1515 
1516     std::string pandaFilePath = "ets/modules.abc";
1517     auto data = extractor->GetSafeData(pandaFilePath);
1518     if (!data) {
1519         LOG_ECMA(ERROR) << "GetSafeData failed, hap path: " << hapName;
1520         return false;
1521     }
1522 
1523     data_ = data->GetDataPtr();
1524     dataSize_ = data->GetDataLen();
1525     loadOffset_ = static_cast<uintptr_t>(data->GetOffset());
1526     ret = true;
1527     auto zipFile = std::make_unique<ZipFile>(hapName);
1528     if (zipFile == nullptr || !zipFile->Open()) {
1529         return false;
1530     }
1531     auto &entrys = zipFile->GetAllEntries();
1532     if (ret) {
1533         std::string filePath = "ets/sourceMaps.map";
1534         if (entrys.find(filePath) == entrys.end()) {
1535             LOG_ECMA(INFO) << "Can't find sourceMaps.map in hap/hsp";
1536             return ret;
1537         }
1538         CreateSourceMap(hapName);
1539     }
1540 #endif
1541     return ret;
1542 }
1543 
ArkParseJSFileInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,const char * filePath,uintptr_t extractorptr,JsFunction * jsFunction)1544 bool ArkParseJSFileInfo([[maybe_unused]] uintptr_t byteCodePc, [[maybe_unused]] uintptr_t methodId,
1545                         [[maybe_unused]] uintptr_t mapBase, [[maybe_unused]] const char* filePath,
1546                         [[maybe_unused]] uintptr_t extractorptr, [[maybe_unused]] JsFunction *jsFunction)
1547 {
1548     bool ret = false;
1549 #if defined(PANDA_TARGET_OHOS)
1550     if (filePath == nullptr) {
1551         LOG_ECMA(ERROR) << "FilePath from dfx is nullptr.";
1552         return false;
1553     }
1554     auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
1555     if (extractor == nullptr) {
1556         LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr.";
1557         return false;
1558     }
1559     if (extractor->GetJSPandaFile() == nullptr) {
1560         std::string hapName = std::string(filePath);
1561         extractor->ParseHapFileData(hapName);
1562         extractor->CreateJSPandaFile();
1563     }
1564     ret = ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, extractor->GetLoadOffset(),
1565                               extractor->GetData(), extractor->GetDataSize(), extractorptr, jsFunction);
1566 #endif
1567     return ret;
1568 }
1569 
~JSSymbolExtractor()1570 JSSymbolExtractor::~JSSymbolExtractor()
1571 {
1572     if (sourceMap_ != nullptr) {
1573         sourceMap_.reset();
1574     }
1575     if (debugExtractor_ != nullptr) {
1576         debugExtractor_.reset();
1577     }
1578     if (jsPandaFile_ != nullptr) {
1579         jsPandaFile_.reset();
1580     }
1581     methodInfo_.clear();
1582 }
1583 
Create()1584 JSSymbolExtractor* JSSymbolExtractor::Create()
1585 {
1586     auto extractor = new JSSymbolExtractor();
1587     return extractor;
1588 }
1589 
Destory(JSSymbolExtractor * extractor)1590 bool JSSymbolExtractor::Destory(JSSymbolExtractor *extractor)
1591 {
1592     if (extractor == nullptr) {
1593         LOG_ECMA(ERROR) << "Destory ark symbol extractor failed, extractor is nullptr.";
1594         return false;
1595     }
1596     delete extractor;
1597     extractor = nullptr;
1598     return true;
1599 }
1600 
GetMethodInfos()1601 CVector<MethodInfo> JSSymbolExtractor::GetMethodInfos()
1602 {
1603     if (methodInfo_.empty()) {
1604         methodInfo_ = JSStackTrace::ReadAllMethodInfos(jsPandaFile_);
1605     }
1606 
1607     return methodInfo_;
1608 }
1609 
GetJSPandaFile(uint8_t * data,size_t dataSize)1610 JSPandaFile* JSSymbolExtractor::GetJSPandaFile(uint8_t *data, size_t dataSize)
1611 {
1612     if (jsPandaFile_ == nullptr && data != nullptr) {
1613         CreateJSPandaFile(data, dataSize);
1614     }
1615     return jsPandaFile_.get();
1616 }
1617 
CreateJSPandaFile()1618 void JSSymbolExtractor::CreateJSPandaFile()
1619 {
1620     auto pf = panda_file::OpenPandaFileFromSecureMemory(data_, dataSize_);
1621     if (pf == nullptr) {
1622         LOG_ECMA(ERROR) << "Failed to open panda file.";
1623         return;
1624     }
1625     jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), "");
1626 }
1627 
CreateJSPandaFile(uint8_t * data,size_t dataSize)1628 void JSSymbolExtractor::CreateJSPandaFile(uint8_t *data, size_t dataSize)
1629 {
1630     auto pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize);
1631     if (pf == nullptr) {
1632         LOG_ECMA(ERROR) << "Failed to open panda file.";
1633         return;
1634     }
1635     jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), "");
1636 }
1637 
GetSourceMap(uint8_t * data,size_t dataSize)1638 SourceMap* JSSymbolExtractor::GetSourceMap(uint8_t *data, size_t dataSize)
1639 {
1640     if (sourceMap_ == nullptr && data != nullptr) {
1641         JSSymbolExtractor::CreateSourceMap(data, dataSize);
1642     }
1643     return sourceMap_.get();
1644 }
1645 
CreateSourceMap(const std::string & hapPath)1646 void JSSymbolExtractor::CreateSourceMap([[maybe_unused]] const std::string &hapPath)
1647 {
1648 #if defined(PANDA_TARGET_OHOS)
1649     if (sourceMap_ == nullptr) {
1650         sourceMap_ = std::make_shared<SourceMap>();
1651         sourceMap_->Init(hapPath);
1652     }
1653 #endif
1654 }
1655 
CreateSourceMap(uint8_t * data,size_t dataSize)1656 void JSSymbolExtractor::CreateSourceMap(uint8_t *data, size_t dataSize)
1657 {
1658     sourceMap_ = std::make_shared<SourceMap>();
1659     sourceMap_->Init(data, dataSize);
1660 }
1661 
GetDebugExtractor()1662 DebugInfoExtractor* JSSymbolExtractor::GetDebugExtractor()
1663 {
1664     if (debugExtractor_ == nullptr) {
1665         JSSymbolExtractor::CreateDebugExtractor();
1666     }
1667     return debugExtractor_.get();
1668 }
1669 
CreateDebugExtractor()1670 void JSSymbolExtractor::CreateDebugExtractor()
1671 {
1672     debugExtractor_ = std::make_unique<DebugInfoExtractor>(jsPandaFile_.get());
1673 }
1674 
ArkCreateJSSymbolExtractor()1675 uintptr_t ArkCreateJSSymbolExtractor()
1676 {
1677     auto extractor = JSSymbolExtractor::Create();
1678     auto extractorptr = reinterpret_cast<uintptr_t>(extractor);
1679     return extractorptr;
1680 }
1681 
ArkDestoryJSSymbolExtractor(uintptr_t extractorptr)1682 bool ArkDestoryJSSymbolExtractor(uintptr_t extractorptr)
1683 {
1684     auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr);
1685     return JSSymbolExtractor::Destory(extractor);
1686 }
1687 
GetInstance()1688 JSStackTrace *JSStackTrace::GetInstance()
1689 {
1690     static JSStackTrace *jsStackTrace = new JSStackTrace();
1691     return jsStackTrace;
1692 }
1693 
~JSStackTrace()1694 JSStackTrace::~JSStackTrace()
1695 {
1696     methodInfo_.clear();
1697     methodInfos_.clear();
1698     jsPandaFiles_.clear();
1699 }
1700 
AddMethodInfos(uintptr_t mapBase)1701 bool JSStackTrace::AddMethodInfos(uintptr_t mapBase)
1702 {
1703     auto pandaFile =
1704         JSPandaFileManager::GetInstance()->FindJSPandaFileByMapBase(mapBase);
1705     jsPandaFiles_[mapBase] = pandaFile;
1706     auto methodInfos = JSStackTrace::ReadAllMethodInfos(pandaFile);
1707     methodInfos_[mapBase] = std::move(methodInfos);
1708     if (pandaFile == nullptr) {
1709         LOG_ECMA(ERROR) << "Can't find JSPandaFile by mapBase: " << mapBase;
1710     }
1711     return true;
1712 }
1713 
GetJsFrameInfo(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,JsFunction * jsFunction)1714 bool JSStackTrace::GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
1715                                   uintptr_t loadOffset, JsFunction *jsFunction)
1716 {
1717     bool ret = true;
1718     auto iter = methodInfos_.find(mapBase);
1719     if (iter == methodInfos_.end()) {
1720         ret = AddMethodInfos(mapBase);
1721     }
1722     loadOffset = loadOffset % PageSize();
1723     byteCodePc = byteCodePc - loadOffset;
1724     auto codeInfo = TranslateByteCodePc(byteCodePc, methodInfos_[mapBase]);
1725     if (!codeInfo) {
1726         LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc;
1727         return false;
1728     }
1729     if (!methodId) {
1730         methodId = codeInfo->methodId;
1731     }
1732     auto offset = codeInfo->offset;
1733     auto debugInfoExtractor =
1734         JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFiles_[mapBase].get());
1735     ParseJsFrameInfo(jsPandaFiles_[mapBase].get(), debugInfoExtractor, EntityId(methodId), offset, *jsFunction);
1736     jsFunction->codeBegin = byteCodePc - offset;
1737     jsFunction->codeSize = codeInfo->codeSize;
1738     return ret;
1739 }
1740 
Destory(JSStackTrace * trace)1741 void JSStackTrace::Destory(JSStackTrace* trace)
1742 {
1743     if (trace == nullptr) {
1744         return;
1745     }
1746     delete trace;
1747     trace = nullptr;
1748 }
1749 
ArkParseJsFrameInfoLocal(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,JsFunction * jsFunction)1750 bool ArkParseJsFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
1751                               uintptr_t loadOffset, JsFunction *jsFunction)
1752 {
1753     bool ret =
1754         JSStackTrace::GetInstance()->GetJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, jsFunction);
1755     return ret;
1756 }
1757 
ArkDestoryLocal()1758 void ArkDestoryLocal()
1759 {
1760     auto trace = JSStackTrace::GetInstance();
1761     return JSStackTrace::Destory(trace);
1762 }
1763 
1764 } // namespace panda::ecmascript
1765 
ark_create_js_symbol_extractor(uintptr_t * extractorptr)1766 __attribute__((visibility("default"))) int ark_create_js_symbol_extractor(uintptr_t *extractorptr)
1767 {
1768     *extractorptr = panda::ecmascript::ArkCreateJSSymbolExtractor();
1769     return 1;
1770 }
1771 
ark_destory_js_symbol_extractor(uintptr_t extractorptr)1772 __attribute__((visibility("default"))) int ark_destory_js_symbol_extractor(uintptr_t extractorptr)
1773 {
1774     if (panda::ecmascript::ArkDestoryJSSymbolExtractor(extractorptr)) {
1775         return 1;
1776     }
1777     return -1;
1778 }
1779 
ark_destory_local()1780 __attribute__((visibility("default"))) int ark_destory_local()
1781 {
1782     panda::ecmascript::ArkDestoryLocal();
1783     return 1;
1784 }
1785 
step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam * arkUnwindParam)1786 __attribute__((visibility("default"))) int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam)
1787 {
1788     if (panda::ecmascript::StepArkWithRecordJit(arkUnwindParam)) {
1789         return 1;
1790     }
1791     return -1;
1792 }
1793 
ark_write_jit_code(void * ctx,panda::ecmascript::ReadMemFunc readMem,int fd,const uintptr_t * const jitCodeArray,const size_t jitSize)1794 __attribute__((visibility("default"))) int ark_write_jit_code(
1795     void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray,
1796     const size_t jitSize)
1797 {
1798     if (panda::ecmascript::ArkWriteJitCode(ctx, readMem, fd, jitCodeArray, jitSize)) {
1799         return 1;
1800     }
1801     return -1;
1802 }
1803 
step_ark(void * ctx,panda::ecmascript::ReadMemFunc readMem,uintptr_t * fp,uintptr_t * sp,uintptr_t * pc,uintptr_t * methodId,bool * isJsFrame)1804 __attribute__((visibility("default"))) int step_ark(
1805     void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
1806     uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame)
1807 {
1808     if (panda::ecmascript::StepArk(ctx, readMem, fp, sp, pc, methodId, isJsFrame)) {
1809         return 1;
1810     }
1811     return -1;
1812 }
1813 
ark_parse_js_frame_info(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorptr,panda::ecmascript::JsFunction * jsFunction)1814 __attribute__((visibility("default"))) int ark_parse_js_frame_info(
1815     uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data,
1816     uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction)
1817 {
1818     if (panda::ecmascript::ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, data,
1819                                                dataSize, extractorptr, jsFunction)) {
1820         return 1;
1821     }
1822     return -1;
1823 }
1824 
ark_parse_js_file_info(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,const char * filePath,uintptr_t extractorptr,panda::ecmascript::JsFunction * jsFunction)1825 __attribute__((visibility("default"))) int ark_parse_js_file_info(
1826     uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr,
1827     panda::ecmascript::JsFunction *jsFunction)
1828 {
1829     if (panda::ecmascript::ArkParseJSFileInfo(byteCodePc, methodId, mapBase, filePath, extractorptr, jsFunction)) {
1830         return 1;
1831     }
1832     return -1;
1833 }
1834 
ark_translate_js_frame_info(uint8_t * data,size_t dataSize,panda::ecmascript::JsFunction * jsFunction)1835 __attribute__((visibility("default"))) int ark_translate_js_frame_info(
1836     uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction)
1837 {
1838     if (panda::ecmascript::ArkTranslateJsFrameInfo(data, dataSize, jsFunction)) {
1839         return 1;
1840     }
1841     return -1;
1842 }
1843 
get_ark_native_frame_info(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,panda::ecmascript::JsFrame * jsFrame,size_t & size)1844 __attribute__((visibility("default"))) int get_ark_native_frame_info(
1845     int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp,
1846     panda::ecmascript::JsFrame *jsFrame, size_t &size)
1847 {
1848     if (panda::ecmascript::GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) {
1849         return 1;
1850     }
1851     return -1;
1852 }
1853 
ark_parse_js_frame_info_local(uintptr_t byteCodePc,uintptr_t methodId,uintptr_t mapBase,uintptr_t loadOffset,panda::ecmascript::JsFunction * jsFunction)1854 __attribute__((visibility("default"))) int ark_parse_js_frame_info_local(
1855     uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset,
1856     panda::ecmascript::JsFunction *jsFunction)
1857 {
1858     if (panda::ecmascript::ArkParseJsFrameInfoLocal(byteCodePc, methodId, mapBase, loadOffset, jsFunction)) {
1859         return 1;
1860     }
1861     return -1;
1862 }
1863