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