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