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));