14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <csignal>
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/aot_file/aot_file_manager.h"
214514f5e3Sopenharmony_ci#include "ecmascript/extractortool/src/source_map.h"
224514f5e3Sopenharmony_ci#include "ecmascript/frames.h"
234514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h"
244514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile_manager.h"
254514f5e3Sopenharmony_ci#include "ecmascript/dfx/dump_code/jit_dump_elf.h"
264514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_OHOS)
274514f5e3Sopenharmony_ci#include "ecmascript/extractortool/src/zip_file.h"
284514f5e3Sopenharmony_ci#endif
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_cinamespace panda::ecmascript {
314514f5e3Sopenharmony_citypedef bool (*ReadMemFunc)(void *ctx, uintptr_t addr, uintptr_t *val);
324514f5e3Sopenharmony_cibool ArkFrameCheck(uintptr_t frameType);
334514f5e3Sopenharmony_cibool IsJsFunctionFrame(uintptr_t frameType);
344514f5e3Sopenharmony_cibool IsNativeFunctionFrame(uintptr_t frameType);
354514f5e3Sopenharmony_cibool IsAotFunctionFrame(uintptr_t frameType);
364514f5e3Sopenharmony_cibool IsFastJitFunctionFrame(uintptr_t frameType);
374514f5e3Sopenharmony_cibool IsFastJitFunctionFrame(const FrameType frameType);
384514f5e3Sopenharmony_citemplate<typename T>
394514f5e3Sopenharmony_civoid ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor,
404514f5e3Sopenharmony_ci    EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap = nullptr);
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ci
434514f5e3Sopenharmony_cistatic constexpr uint16_t URL_MAX = 1024;
444514f5e3Sopenharmony_cistatic constexpr uint16_t FUNCTIONNAME_MAX = 1024;
454514f5e3Sopenharmony_ci
464514f5e3Sopenharmony_cistruct JsFrameInfo {
474514f5e3Sopenharmony_ci    std::string functionName;
484514f5e3Sopenharmony_ci    std::string fileName;
494514f5e3Sopenharmony_ci    std::string pos;
504514f5e3Sopenharmony_ci    uintptr_t *nativePointer = nullptr;
514514f5e3Sopenharmony_ci};
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_cistruct JsFunction {
544514f5e3Sopenharmony_ci    char functionName[FUNCTIONNAME_MAX];
554514f5e3Sopenharmony_ci    char url[URL_MAX];
564514f5e3Sopenharmony_ci    int32_t line;
574514f5e3Sopenharmony_ci    int32_t column;
584514f5e3Sopenharmony_ci    uintptr_t codeBegin;
594514f5e3Sopenharmony_ci    uintptr_t codeSize;
604514f5e3Sopenharmony_ci};
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_cistruct MethodInfo {
634514f5e3Sopenharmony_ci    uintptr_t methodId;
644514f5e3Sopenharmony_ci    uintptr_t codeBegin;
654514f5e3Sopenharmony_ci    uint32_t codeSize;
664514f5e3Sopenharmony_ci    MethodInfo(uintptr_t methodId, uintptr_t codeBegin, uint32_t codeSize)
674514f5e3Sopenharmony_ci        : methodId(methodId), codeBegin(codeBegin), codeSize(codeSize) {}
684514f5e3Sopenharmony_ci    friend bool operator<(const MethodInfo &lhs, const MethodInfo &rhs)
694514f5e3Sopenharmony_ci    {
704514f5e3Sopenharmony_ci        return lhs.codeBegin < rhs.codeBegin;
714514f5e3Sopenharmony_ci    }
724514f5e3Sopenharmony_ci};
734514f5e3Sopenharmony_ci
744514f5e3Sopenharmony_cistruct CodeInfo {
754514f5e3Sopenharmony_ci    uintptr_t offset;
764514f5e3Sopenharmony_ci    uintptr_t methodId;
774514f5e3Sopenharmony_ci    uint32_t codeSize;
784514f5e3Sopenharmony_ci    CodeInfo(uintptr_t offset, uintptr_t methodId, uint32_t codeSize)
794514f5e3Sopenharmony_ci        : offset(offset), methodId(methodId), codeSize(codeSize) {}
804514f5e3Sopenharmony_ci};
814514f5e3Sopenharmony_ci
824514f5e3Sopenharmony_cistruct JsFrameDebugInfo {
834514f5e3Sopenharmony_ci    EntityId methodId;
844514f5e3Sopenharmony_ci    uint32_t offset;
854514f5e3Sopenharmony_ci    std::string hapPath;
864514f5e3Sopenharmony_ci    std::string filePath;
874514f5e3Sopenharmony_ci    JsFrameDebugInfo(EntityId methodId, uint32_t offset, std::string &hapPath, std::string &filePath)
884514f5e3Sopenharmony_ci        : methodId(methodId), offset(offset), hapPath(hapPath), filePath(filePath) {}
894514f5e3Sopenharmony_ci};
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_cistruct ArkUnwindParam {
924514f5e3Sopenharmony_ci    void *ctx;
934514f5e3Sopenharmony_ci    ReadMemFunc readMem;
944514f5e3Sopenharmony_ci    uintptr_t *fp;
954514f5e3Sopenharmony_ci    uintptr_t *sp;
964514f5e3Sopenharmony_ci    uintptr_t *pc;
974514f5e3Sopenharmony_ci    uintptr_t *methodId;
984514f5e3Sopenharmony_ci    bool *isJsFrame;
994514f5e3Sopenharmony_ci    std::vector<uintptr_t> &jitCache;
1004514f5e3Sopenharmony_ci    ArkUnwindParam(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t *methodId,
1014514f5e3Sopenharmony_ci                   bool *isJsFrame, std::vector<uintptr_t> &jitCache)
1024514f5e3Sopenharmony_ci        : ctx(ctx), readMem(readMem), fp(fp), sp(sp), pc(pc), methodId(methodId),
1034514f5e3Sopenharmony_ci          isJsFrame(isJsFrame), jitCache(jitCache) {}
1044514f5e3Sopenharmony_ci};
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_cistruct JsFrame {
1074514f5e3Sopenharmony_ci    char functionName[FUNCTIONNAME_MAX];
1084514f5e3Sopenharmony_ci    char url[URL_MAX];
1094514f5e3Sopenharmony_ci    int32_t line;
1104514f5e3Sopenharmony_ci    int32_t column;
1114514f5e3Sopenharmony_ci};
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ciclass JSStackTrace {
1144514f5e3Sopenharmony_cipublic:
1154514f5e3Sopenharmony_ci    JSStackTrace() = default;
1164514f5e3Sopenharmony_ci    ~JSStackTrace();
1174514f5e3Sopenharmony_ci    static JSStackTrace *GetInstance();
1184514f5e3Sopenharmony_ci    static std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda);
1194514f5e3Sopenharmony_ci    static CVector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile);
1204514f5e3Sopenharmony_ci    static std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec);
1214514f5e3Sopenharmony_ci    bool GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
1224514f5e3Sopenharmony_ci                        uintptr_t loadOffset, JsFunction *jsFunction);
1234514f5e3Sopenharmony_ci    static void Destory();
1244514f5e3Sopenharmony_ciprivate:
1254514f5e3Sopenharmony_ci    bool AddMethodInfos(uintptr_t mapBase);
1264514f5e3Sopenharmony_ci
1274514f5e3Sopenharmony_ci    CVector<MethodInfo> methodInfo_;
1284514f5e3Sopenharmony_ci    std::unordered_map<uintptr_t, std::shared_ptr<JSPandaFile>> jsPandaFiles_;
1294514f5e3Sopenharmony_ci    std::unordered_map<uintptr_t, CVector<MethodInfo>> methodInfos_;
1304514f5e3Sopenharmony_ci    static JSStackTrace *trace_;
1314514f5e3Sopenharmony_ci    static std::mutex mutex_;
1324514f5e3Sopenharmony_ci};
1334514f5e3Sopenharmony_ci
1344514f5e3Sopenharmony_ciclass JSSymbolExtractor {
1354514f5e3Sopenharmony_cipublic:
1364514f5e3Sopenharmony_ci    JSSymbolExtractor() = default;
1374514f5e3Sopenharmony_ci    ~JSSymbolExtractor();
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_ci    static JSSymbolExtractor* Create();
1404514f5e3Sopenharmony_ci    static bool Destory(JSSymbolExtractor* extractor);
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    void CreateJSPandaFile();
1434514f5e3Sopenharmony_ci    void CreateJSPandaFile(uint8_t *data, size_t dataSize);
1444514f5e3Sopenharmony_ci    void CreateSourceMap(const std::string &hapPath);
1454514f5e3Sopenharmony_ci    void CreateSourceMap(uint8_t *data, size_t dataSize);
1464514f5e3Sopenharmony_ci    void CreateDebugExtractor();
1474514f5e3Sopenharmony_ci    bool ParseHapFileData(std::string& hapName);
1484514f5e3Sopenharmony_ci
1494514f5e3Sopenharmony_ci    uint8_t* GetData();
1504514f5e3Sopenharmony_ci    uintptr_t GetLoadOffset();
1514514f5e3Sopenharmony_ci    uintptr_t GetDataSize();
1524514f5e3Sopenharmony_ci
1534514f5e3Sopenharmony_ci    JSPandaFile* GetJSPandaFile(uint8_t *data = nullptr, size_t dataSize = 0);
1544514f5e3Sopenharmony_ci    DebugInfoExtractor* GetDebugExtractor();
1554514f5e3Sopenharmony_ci    SourceMap* GetSourceMap(uint8_t *data = nullptr, size_t dataSize = 0);
1564514f5e3Sopenharmony_ci    CVector<MethodInfo> GetMethodInfos();
1574514f5e3Sopenharmony_ci
1584514f5e3Sopenharmony_ciprivate:
1594514f5e3Sopenharmony_ci    CVector<MethodInfo> methodInfo_;
1604514f5e3Sopenharmony_ci    uintptr_t loadOffset_ {0};
1614514f5e3Sopenharmony_ci    uintptr_t dataSize_ {0};
1624514f5e3Sopenharmony_ci    uint8_t* data_ {nullptr};
1634514f5e3Sopenharmony_ci    std::shared_ptr<JSPandaFile> jsPandaFile_ {nullptr};
1644514f5e3Sopenharmony_ci    std::unique_ptr<DebugInfoExtractor> debugExtractor_ {nullptr};
1654514f5e3Sopenharmony_ci    std::shared_ptr<SourceMap> sourceMap_ {nullptr};
1664514f5e3Sopenharmony_ci};
1674514f5e3Sopenharmony_ci
1684514f5e3Sopenharmony_ciclass JsStackInfo {
1694514f5e3Sopenharmony_ciprivate:
1704514f5e3Sopenharmony_ci    struct LastBuilderCache {
1714514f5e3Sopenharmony_ci        const JSPandaFile *pf{nullptr};
1724514f5e3Sopenharmony_ci        DebugInfoExtractor *extractor{nullptr};
1734514f5e3Sopenharmony_ci    };
1744514f5e3Sopenharmony_cipublic:
1754514f5e3Sopenharmony_ci    static std::string BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets);
1764514f5e3Sopenharmony_ci    static inline std::string BuildJsStackTrace(JSThread *thread, bool needNative)
1774514f5e3Sopenharmony_ci    {
1784514f5e3Sopenharmony_ci        // If jsErrorObj not be pass in, MachineCode object of its stack frame while not be keep alive
1794514f5e3Sopenharmony_ci        JSHandle<JSObject> jsErrorObj;
1804514f5e3Sopenharmony_ci        return BuildJsStackTrace(thread, needNative, jsErrorObj);
1814514f5e3Sopenharmony_ci    }
1824514f5e3Sopenharmony_ci    static std::string BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj);
1834514f5e3Sopenharmony_ci    static std::vector<JsFrameInfo> BuildJsStackInfo(JSThread *thread, bool currentStack = false);
1844514f5e3Sopenharmony_ci    static std::string BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache,
1854514f5e3Sopenharmony_ci                                        bool enableStackSourceFile = true);
1864514f5e3Sopenharmony_ci    static AOTFileManager *loader;
1874514f5e3Sopenharmony_ci    static JSRuntimeOptions *options;
1884514f5e3Sopenharmony_ci    static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0, JSThread *thread = nullptr);
1894514f5e3Sopenharmony_ci    static inline void BuildCrashInfo(JSThread *thread)
1904514f5e3Sopenharmony_ci    {
1914514f5e3Sopenharmony_ci        BuildCrashInfo(true, 0, thread); // pc is useless for JsCrash, pass 0 as placeholder
1924514f5e3Sopenharmony_ci    }
1934514f5e3Sopenharmony_ci    static std::unordered_map<EntityId, std::string> nameMap;
1944514f5e3Sopenharmony_ci    static std::unordered_map<EntityId, std::vector<uint8>> machineCodeMap;
1954514f5e3Sopenharmony_ci    static void DumpJitCode(JSThread *thread);
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ciprivate:
1984514f5e3Sopenharmony_ci    static std::string BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it,
1994514f5e3Sopenharmony_ci                                             uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj,
2004514f5e3Sopenharmony_ci                                             LastBuilderCache &lastCache);
2014514f5e3Sopenharmony_ci    static constexpr int32_t InitialLength = 50;
2024514f5e3Sopenharmony_ci    static constexpr int32_t InitialDeeps = 5;
2034514f5e3Sopenharmony_ci};
2044514f5e3Sopenharmony_ci} // namespace panda::ecmascript
2054514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
2064514f5e3Sopenharmony_ciextern "C" int ark_parse_js_frame_info(
2074514f5e3Sopenharmony_ci    uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data,
2084514f5e3Sopenharmony_ci    uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction);
2094514f5e3Sopenharmony_ciextern "C" int ark_translate_js_frame_info(
2104514f5e3Sopenharmony_ci    uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction);
2114514f5e3Sopenharmony_ciextern "C" int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam);
2124514f5e3Sopenharmony_ciextern "C" int ark_write_jit_code(
2134514f5e3Sopenharmony_ci    void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray,
2144514f5e3Sopenharmony_ci    const size_t jitSize);
2154514f5e3Sopenharmony_ciextern "C" int step_ark(
2164514f5e3Sopenharmony_ci    void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
2174514f5e3Sopenharmony_ci    uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame);
2184514f5e3Sopenharmony_ciextern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr);
2194514f5e3Sopenharmony_ciextern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr);
2204514f5e3Sopenharmony_ciextern "C" int ark_parse_js_file_info(
2214514f5e3Sopenharmony_ci    uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr,
2224514f5e3Sopenharmony_ci    panda::ecmascript::JsFunction *jsFunction);
2234514f5e3Sopenharmony_ciextern "C" int get_ark_native_frame_info(
2244514f5e3Sopenharmony_ci    int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size);
2254514f5e3Sopenharmony_ciextern "C" int ark_parse_js_frame_info_local(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
2264514f5e3Sopenharmony_ci    uintptr_t loadOffset, panda::ecmascript::JsFunction *jsFunction);
2274514f5e3Sopenharmony_ciextern "C" int ark_destory_local();
2284514f5e3Sopenharmony_ci// define in dfx_signal_handler.h
2294514f5e3Sopenharmony_citypedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext);
2304514f5e3Sopenharmony_ciextern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak));