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 
30 namespace panda::ecmascript {
31 typedef bool (*ReadMemFunc)(void *ctx, uintptr_t addr, uintptr_t *val);
32 bool ArkFrameCheck(uintptr_t frameType);
33 bool IsJsFunctionFrame(uintptr_t frameType);
34 bool IsNativeFunctionFrame(uintptr_t frameType);
35 bool IsAotFunctionFrame(uintptr_t frameType);
36 bool IsFastJitFunctionFrame(uintptr_t frameType);
37 bool IsFastJitFunctionFrame(const FrameType frameType);
38 template<typename T>
39 void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor,
40     EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap = nullptr);
41 
42 
43 static constexpr uint16_t URL_MAX = 1024;
44 static constexpr uint16_t FUNCTIONNAME_MAX = 1024;
45 
46 struct JsFrameInfo {
47     std::string functionName;
48     std::string fileName;
49     std::string pos;
50     uintptr_t *nativePointer = nullptr;
51 };
52 
53 struct 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 
62 struct MethodInfo {
63     uintptr_t methodId;
64     uintptr_t codeBegin;
65     uint32_t codeSize;
MethodInfopanda::ecmascript::MethodInfo66     MethodInfo(uintptr_t methodId, uintptr_t codeBegin, uint32_t codeSize)
67         : methodId(methodId), codeBegin(codeBegin), codeSize(codeSize) {}
operator <panda::ecmascript::MethodInfo68     friend bool operator<(const MethodInfo &lhs, const MethodInfo &rhs)
69     {
70         return lhs.codeBegin < rhs.codeBegin;
71     }
72 };
73 
74 struct CodeInfo {
75     uintptr_t offset;
76     uintptr_t methodId;
77     uint32_t codeSize;
CodeInfopanda::ecmascript::CodeInfo78     CodeInfo(uintptr_t offset, uintptr_t methodId, uint32_t codeSize)
79         : offset(offset), methodId(methodId), codeSize(codeSize) {}
80 };
81 
82 struct JsFrameDebugInfo {
83     EntityId methodId;
84     uint32_t offset;
85     std::string hapPath;
86     std::string filePath;
JsFrameDebugInfopanda::ecmascript::JsFrameDebugInfo87     JsFrameDebugInfo(EntityId methodId, uint32_t offset, std::string &hapPath, std::string &filePath)
88         : methodId(methodId), offset(offset), hapPath(hapPath), filePath(filePath) {}
89 };
90 
91 struct 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;
ArkUnwindParampanda::ecmascript::ArkUnwindParam100     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 
106 struct JsFrame {
107     char functionName[FUNCTIONNAME_MAX];
108     char url[URL_MAX];
109     int32_t line;
110     int32_t column;
111 };
112 
113 class JSStackTrace {
114 public:
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();
124 private:
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 
134 class JSSymbolExtractor {
135 public:
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 
158 private:
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 
168 class JsStackInfo {
169 private:
170     struct LastBuilderCache {
171         const JSPandaFile *pf{nullptr};
172         DebugInfoExtractor *extractor{nullptr};
173     };
174 public:
175     static std::string BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets);
BuildJsStackTrace(JSThread *thread, bool needNative)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);
BuildCrashInfo(JSThread *thread)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 
197 private:
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
206 extern "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);
209 extern "C" int ark_translate_js_frame_info(
210     uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction);
211 extern "C" int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam);
212 extern "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);
215 extern "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);
218 extern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr);
219 extern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr);
220 extern "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);
223 extern "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);
225 extern "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);
227 extern "C" int ark_destory_local();
228 // define in dfx_signal_handler.h
229 typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext);
230 extern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak));