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 static constexpr uint16_t PACKAGENAME_MAX = 1024; 46 static constexpr uint32_t JS_STACK_TRACE_DEPTH_MAX = 64; 47 48 struct ArkStepParam { 49 uintptr_t *fp; 50 uintptr_t *sp; 51 uintptr_t *pc; 52 bool *isJsFrame; 53 }; 54 55 struct JsFrameInfo { 56 std::string functionName; 57 std::string fileName; 58 std::string packageName; 59 std::string pos; 60 }; 61 62 struct JsFunction { 63 char functionName[FUNCTIONNAME_MAX]; 64 char packageName[PACKAGENAME_MAX]; 65 char url[URL_MAX]; 66 int32_t line; 67 int32_t column; 68 uintptr_t codeBegin; 69 uintptr_t codeSize; 70 }; 71 72 struct MethodInfo { 73 uintptr_t methodId; 74 uintptr_t codeBegin; 75 uint32_t codeSize; MethodInfoMethodInfo76 MethodInfo(uintptr_t methodId, uintptr_t codeBegin, uint32_t codeSize) 77 : methodId(methodId), codeBegin(codeBegin), codeSize(codeSize) {} 78 friend bool operator<(const MethodInfo &lhs, const MethodInfo &rhs) 79 { 80 return lhs.codeBegin < rhs.codeBegin; 81 } 82 }; 83 84 struct CodeInfo { 85 uintptr_t offset; 86 uintptr_t methodId; 87 uint32_t codeSize; CodeInfoCodeInfo88 CodeInfo(uintptr_t offset, uintptr_t methodId, uint32_t codeSize) 89 : offset(offset), methodId(methodId), codeSize(codeSize) {} 90 }; 91 92 struct ArkUnwindParam { 93 void *ctx; 94 ReadMemFunc readMem; 95 uintptr_t *fp; 96 uintptr_t *sp; 97 uintptr_t *pc; 98 uintptr_t *methodId; 99 bool *isJsFrame; 100 std::vector<uintptr_t> &jitCache; ArkUnwindParamArkUnwindParam101 ArkUnwindParam(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t *methodId, 102 bool *isJsFrame, std::vector<uintptr_t> &jitCache) 103 : ctx(ctx), readMem(readMem), fp(fp), sp(sp), pc(pc), methodId(methodId), 104 isJsFrame(isJsFrame), jitCache(jitCache) {} 105 }; 106 107 struct JsFrame { 108 char functionName[FUNCTIONNAME_MAX]; 109 char packageName[PACKAGENAME_MAX]; 110 char url[URL_MAX]; 111 int32_t line; 112 int32_t column; 113 }; 114 115 class JSStackTrace { 116 public: 117 JSStackTrace() = default; 118 ~JSStackTrace(); GetInstance()119 static JSStackTrace *GetInstance() 120 { 121 return trace_; 122 } 123 static std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda); 124 static CVector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile); 125 static std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec); 126 bool GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, JsFunction *jsFunction); 127 static void AddReference(); 128 static void ReleaseReference(); 129 private: 130 std::shared_ptr<JSPandaFile> FindJSpandaFile(uintptr_t mapBase); 131 const CVector<MethodInfo> &FindMethodInfos(uintptr_t mapBase); 132 void SetJSpandaFile(uintptr_t mapBase, std::shared_ptr<JSPandaFile> pandafile); 133 void SetMethodInfos(uintptr_t mapBase, CVector<MethodInfo> &infos); 134 bool InitializeMethodInfo(uintptr_t mapBase); 135 136 std::shared_mutex pfMutex_; 137 std::shared_mutex infosMutex_; 138 CVector<MethodInfo> methodInfo_; // empty vector 139 std::unordered_map<uintptr_t, std::shared_ptr<JSPandaFile>> jsPandaFiles_; 140 std::unordered_map<uintptr_t, CVector<MethodInfo>> methodInfos_; 141 static JSStackTrace *trace_; 142 static std::mutex mutex_; 143 static size_t count_; 144 }; 145 146 class JSSymbolExtractor { 147 public: 148 JSSymbolExtractor() = default; 149 ~JSSymbolExtractor(); 150 151 static JSSymbolExtractor* Create(); 152 static bool Destory(JSSymbolExtractor* extractor); 153 154 void CreateJSPandaFile(); 155 void CreateJSPandaFile(uint8_t *data, size_t dataSize); 156 void CreateSourceMap(const std::string &hapPath); 157 void CreateSourceMap(uint8_t *data, size_t dataSize); 158 void CreateDebugExtractor(); 159 bool ParseHapFileData(std::string& hapName); 160 161 uint8_t* GetData(); 162 uintptr_t GetLoadOffset(); 163 uintptr_t GetDataSize(); 164 165 JSPandaFile* GetJSPandaFile(uint8_t *data = nullptr, size_t dataSize = 0); 166 DebugInfoExtractor* GetDebugExtractor(); 167 SourceMap* GetSourceMap(uint8_t *data = nullptr, size_t dataSize = 0); 168 CVector<MethodInfo> GetMethodInfos(); 169 170 private: 171 CVector<MethodInfo> methodInfo_; 172 uintptr_t loadOffset_ {0}; 173 uintptr_t dataSize_ {0}; 174 uint8_t* data_ {nullptr}; 175 std::shared_ptr<JSPandaFile> jsPandaFile_ {nullptr}; 176 std::unique_ptr<DebugInfoExtractor> debugExtractor_ {nullptr}; 177 std::shared_ptr<SourceMap> sourceMap_ {nullptr}; 178 }; 179 180 class JsStackInfo { 181 private: 182 struct LastBuilderCache { 183 const JSPandaFile *pf{nullptr}; 184 DebugInfoExtractor *extractor{nullptr}; 185 }; 186 public: 187 static inline std::string BuildJsStackTrace(JSThread *thread, bool needNative, 188 bool needNativeStack = true, uint32_t depth = UINT32_MAX) 189 { 190 // If jsErrorObj not be pass in, MachineCode object of its stack frame while not be keep alive 191 JSHandle<JSObject> jsErrorObj; 192 return BuildJsStackTrace(thread, needNative, jsErrorObj, needNativeStack, depth); 193 } 194 static std::string BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj, 195 bool needNativeStack, uint32_t depth = UINT32_MAX); 196 static std::vector<JsFrameInfo> BuildJsStackInfo(JSThread *thread, bool currentStack = false); 197 static void AppendMethodTrace(std::string &data, const JSThread *thread, Method *method, uint32_t pcOffset, 198 LastBuilderCache &lastCache, bool enableStackSourceFile = true); 199 static AOTFileManager *loader; 200 static JSRuntimeOptions *options; 201 static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0, JSThread *thread = nullptr); BuildCrashInfo(JSThread * thread)202 static inline void BuildCrashInfo(JSThread *thread) 203 { 204 BuildCrashInfo(true, 0, thread); // pc is useless for JsCrash, pass 0 as placeholder 205 } 206 static std::unordered_map<EntityId, std::string> nameMap; 207 static std::unordered_map<EntityId, std::vector<uint8>> machineCodeMap; 208 static void DumpJitCode(JSThread *thread); 209 210 private: 211 static void AppendJsStackTraceInfo(std::string &data, JSThread *thread, Method *method, FrameIterator &it, 212 const JSHandle<JSObject> &jsErrorObj, 213 LastBuilderCache &lastCache, 214 bool needBaselineSpecialHandling, 215 uint32_t pcOffset); 216 static constexpr int32_t InitialLength = 50; 217 static constexpr int32_t InitialDeeps = 5; 218 }; 219 } // namespace panda::ecmascript 220 #endif // ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H 221 extern "C" int ark_parse_js_frame_info( 222 uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, 223 uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction); 224 extern "C" int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam); 225 extern "C" int ark_write_jit_code( 226 void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray, 227 const size_t jitSize); 228 extern "C" int step_ark( 229 void *ctx, panda::ecmascript::ReadMemFunc readMem, panda::ecmascript::ArkStepParam *arkStepParam); 230 extern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr); 231 extern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr); 232 extern "C" int ark_parse_js_file_info( 233 uintptr_t byteCodePc, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr, 234 panda::ecmascript::JsFunction *jsFunction); 235 extern "C" int ark_parse_js_frame_info_local(uintptr_t byteCodePc, uintptr_t mapBase, 236 uintptr_t loadOffset, panda::ecmascript::JsFunction *jsFunction); 237 extern "C" int ark_create_local(); 238 extern "C" int ark_destroy_local(); 239 // define in dfx_signal_handler.h 240 typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext); 241 extern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak));