• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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));