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#ifndef ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
17#define ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
18
19#include <csignal>
20#include "ecmascript/compiler/aot_file/aot_file_manager.h"
21#include "ecmascript/extractortool/src/source_map.h"
22#include "ecmascript/frames.h"
23#include "ecmascript/js_thread.h"
24#include "ecmascript/jspandafile/js_pandafile_manager.h"
25#include "ecmascript/dfx/dump_code/jit_dump_elf.h"
26#if defined(PANDA_TARGET_OHOS)
27#include "ecmascript/extractortool/src/zip_file.h"
28#endif
29
30namespace panda::ecmascript {
31typedef bool (*ReadMemFunc)(void *ctx, uintptr_t addr, uintptr_t *val);
32bool ArkFrameCheck(uintptr_t frameType);
33bool IsJsFunctionFrame(uintptr_t frameType);
34bool IsNativeFunctionFrame(uintptr_t frameType);
35bool IsAotFunctionFrame(uintptr_t frameType);
36bool IsFastJitFunctionFrame(uintptr_t frameType);
37bool IsFastJitFunctionFrame(const FrameType frameType);
38template<typename T>
39void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor,
40    EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap = nullptr);
41
42
43static constexpr uint16_t URL_MAX = 1024;
44static constexpr uint16_t FUNCTIONNAME_MAX = 1024;
45
46struct JsFrameInfo {
47    std::string functionName;
48    std::string fileName;
49    std::string pos;
50    uintptr_t *nativePointer = nullptr;
51};
52
53struct JsFunction {
54    char functionName[FUNCTIONNAME_MAX];
55    char url[URL_MAX];
56    int32_t line;
57    int32_t column;
58    uintptr_t codeBegin;
59    uintptr_t codeSize;
60};
61
62struct MethodInfo {
63    uintptr_t methodId;
64    uintptr_t codeBegin;
65    uint32_t codeSize;
66    MethodInfo(uintptr_t methodId, uintptr_t codeBegin, uint32_t codeSize)
67        : methodId(methodId), codeBegin(codeBegin), codeSize(codeSize) {}
68    friend bool operator<(const MethodInfo &lhs, const MethodInfo &rhs)
69    {
70        return lhs.codeBegin < rhs.codeBegin;
71    }
72};
73
74struct CodeInfo {
75    uintptr_t offset;
76    uintptr_t methodId;
77    uint32_t codeSize;
78    CodeInfo(uintptr_t offset, uintptr_t methodId, uint32_t codeSize)
79        : offset(offset), methodId(methodId), codeSize(codeSize) {}
80};
81
82struct JsFrameDebugInfo {
83    EntityId methodId;
84    uint32_t offset;
85    std::string hapPath;
86    std::string filePath;
87    JsFrameDebugInfo(EntityId methodId, uint32_t offset, std::string &hapPath, std::string &filePath)
88        : methodId(methodId), offset(offset), hapPath(hapPath), filePath(filePath) {}
89};
90
91struct ArkUnwindParam {
92    void *ctx;
93    ReadMemFunc readMem;
94    uintptr_t *fp;
95    uintptr_t *sp;
96    uintptr_t *pc;
97    uintptr_t *methodId;
98    bool *isJsFrame;
99    std::vector<uintptr_t> &jitCache;
100    ArkUnwindParam(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t *methodId,
101                   bool *isJsFrame, std::vector<uintptr_t> &jitCache)
102        : ctx(ctx), readMem(readMem), fp(fp), sp(sp), pc(pc), methodId(methodId),
103          isJsFrame(isJsFrame), jitCache(jitCache) {}
104};
105
106struct JsFrame {
107    char functionName[FUNCTIONNAME_MAX];
108    char url[URL_MAX];
109    int32_t line;
110    int32_t column;
111};
112
113class JSStackTrace {
114public:
115    JSStackTrace() = default;
116    ~JSStackTrace();
117    static JSStackTrace *GetInstance();
118    static std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda);
119    static CVector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile);
120    static std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec);
121    bool GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
122                        uintptr_t loadOffset, JsFunction *jsFunction);
123    static void Destory();
124private:
125    bool AddMethodInfos(uintptr_t mapBase);
126
127    CVector<MethodInfo> methodInfo_;
128    std::unordered_map<uintptr_t, std::shared_ptr<JSPandaFile>> jsPandaFiles_;
129    std::unordered_map<uintptr_t, CVector<MethodInfo>> methodInfos_;
130    static JSStackTrace *trace_;
131    static std::mutex mutex_;
132};
133
134class JSSymbolExtractor {
135public:
136    JSSymbolExtractor() = default;
137    ~JSSymbolExtractor();
138
139    static JSSymbolExtractor* Create();
140    static bool Destory(JSSymbolExtractor* extractor);
141
142    void CreateJSPandaFile();
143    void CreateJSPandaFile(uint8_t *data, size_t dataSize);
144    void CreateSourceMap(const std::string &hapPath);
145    void CreateSourceMap(uint8_t *data, size_t dataSize);
146    void CreateDebugExtractor();
147    bool ParseHapFileData(std::string& hapName);
148
149    uint8_t* GetData();
150    uintptr_t GetLoadOffset();
151    uintptr_t GetDataSize();
152
153    JSPandaFile* GetJSPandaFile(uint8_t *data = nullptr, size_t dataSize = 0);
154    DebugInfoExtractor* GetDebugExtractor();
155    SourceMap* GetSourceMap(uint8_t *data = nullptr, size_t dataSize = 0);
156    CVector<MethodInfo> GetMethodInfos();
157
158private:
159    CVector<MethodInfo> methodInfo_;
160    uintptr_t loadOffset_ {0};
161    uintptr_t dataSize_ {0};
162    uint8_t* data_ {nullptr};
163    std::shared_ptr<JSPandaFile> jsPandaFile_ {nullptr};
164    std::unique_ptr<DebugInfoExtractor> debugExtractor_ {nullptr};
165    std::shared_ptr<SourceMap> sourceMap_ {nullptr};
166};
167
168class JsStackInfo {
169private:
170    struct LastBuilderCache {
171        const JSPandaFile *pf{nullptr};
172        DebugInfoExtractor *extractor{nullptr};
173    };
174public:
175    static std::string BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets);
176    static inline std::string BuildJsStackTrace(JSThread *thread, bool needNative)
177    {
178        // If jsErrorObj not be pass in, MachineCode object of its stack frame while not be keep alive
179        JSHandle<JSObject> jsErrorObj;
180        return BuildJsStackTrace(thread, needNative, jsErrorObj);
181    }
182    static std::string BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj);
183    static std::vector<JsFrameInfo> BuildJsStackInfo(JSThread *thread, bool currentStack = false);
184    static std::string BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache,
185                                        bool enableStackSourceFile = true);
186    static AOTFileManager *loader;
187    static JSRuntimeOptions *options;
188    static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0, JSThread *thread = nullptr);
189    static inline void BuildCrashInfo(JSThread *thread)
190    {
191        BuildCrashInfo(true, 0, thread); // pc is useless for JsCrash, pass 0 as placeholder
192    }
193    static std::unordered_map<EntityId, std::string> nameMap;
194    static std::unordered_map<EntityId, std::vector<uint8>> machineCodeMap;
195    static void DumpJitCode(JSThread *thread);
196
197private:
198    static std::string BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it,
199                                             uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj,
200                                             LastBuilderCache &lastCache);
201    static constexpr int32_t InitialLength = 50;
202    static constexpr int32_t InitialDeeps = 5;
203};
204} // namespace panda::ecmascript
205#endif  // ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
206extern "C" int ark_parse_js_frame_info(
207    uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data,
208    uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction);
209extern "C" int ark_translate_js_frame_info(
210    uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction);
211extern "C" int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam);
212extern "C" int ark_write_jit_code(
213    void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray,
214    const size_t jitSize);
215extern "C" int step_ark(
216    void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
217    uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame);
218extern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr);
219extern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr);
220extern "C" int ark_parse_js_file_info(
221    uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr,
222    panda::ecmascript::JsFunction *jsFunction);
223extern "C" int get_ark_native_frame_info(
224    int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size);
225extern "C" int ark_parse_js_frame_info_local(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
226    uintptr_t loadOffset, panda::ecmascript::JsFunction *jsFunction);
227extern "C" int ark_destory_local();
228// define in dfx_signal_handler.h
229typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext);
230extern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak));