• 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 
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 
108     static JSStackTrace *GetInstance();
109     static std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda);
110     static CVector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile);
111     static std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec);
112     bool GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
113                         uintptr_t loadOffset, JsFunction *jsFunction);
114     static void Destory(JSStackTrace* trace);
115 private:
116     bool AddMethodInfos(uintptr_t mapBase);
117 
118     CVector<MethodInfo> methodInfo_;
119     std::unordered_map<uintptr_t, std::shared_ptr<JSPandaFile>> jsPandaFiles_;
120     std::unordered_map<uintptr_t, CVector<MethodInfo>> methodInfos_;
121 };
122 
123 class JSSymbolExtractor {
124 public:
125     JSSymbolExtractor() = default;
126     ~JSSymbolExtractor();
127 
128     static JSSymbolExtractor* Create();
129     static bool Destory(JSSymbolExtractor* extractor);
130 
131     void CreateJSPandaFile();
132     void CreateJSPandaFile(uint8_t *data, size_t dataSize);
133     void CreateSourceMap(const std::string &hapPath);
134     void CreateSourceMap(uint8_t *data, size_t dataSize);
135     void CreateDebugExtractor();
136     bool ParseHapFileData(std::string& hapName);
137 
138     uint8_t* GetData();
139     uintptr_t GetLoadOffset();
140     uintptr_t GetDataSize();
141 
142     JSPandaFile* GetJSPandaFile(uint8_t *data = nullptr, size_t dataSize = 0);
143     DebugInfoExtractor* GetDebugExtractor();
144     SourceMap* GetSourceMap(uint8_t *data = nullptr, size_t dataSize = 0);
145     CVector<MethodInfo> GetMethodInfos();
146 
147 private:
148     CVector<MethodInfo> methodInfo_;
149     uintptr_t loadOffset_ {0};
150     uintptr_t dataSize_ {0};
151     uint8_t* data_ {nullptr};
152     std::shared_ptr<JSPandaFile> jsPandaFile_ {nullptr};
153     std::unique_ptr<DebugInfoExtractor> debugExtractor_ {nullptr};
154     std::shared_ptr<SourceMap> sourceMap_ {nullptr};
155 };
156 
157 class JsStackInfo {
158 private:
159     struct LastBuilderCache {
160         const JSPandaFile *pf{nullptr};
161         DebugInfoExtractor *extractor{nullptr};
162     };
163 public:
164     static std::string BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets);
BuildJsStackTrace(JSThread * thread,bool needNative)165     static inline std::string BuildJsStackTrace(JSThread *thread, bool needNative)
166     {
167         // If jsErrorObj not be pass in, MachineCode object of its stack frame while not be keep alive
168         JSHandle<JSObject> jsErrorObj;
169         return BuildJsStackTrace(thread, needNative, jsErrorObj);
170     }
171     static std::string BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj);
172     static std::vector<JsFrameInfo> BuildJsStackInfo(JSThread *thread, bool currentStack = false);
173     static std::string BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache,
174                                         bool enableStackSourceFile = true);
175     static AOTFileManager *loader;
176     static JSRuntimeOptions *options;
177     static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0, JSThread *thread = nullptr);
BuildCrashInfo(JSThread * thread)178     static inline void BuildCrashInfo(JSThread *thread)
179     {
180         BuildCrashInfo(true, 0, thread); // pc is useless for JsCrash, pass 0 as placeholder
181     }
182     static std::unordered_map<EntityId, std::string> nameMap;
183     static std::unordered_map<EntityId, std::vector<uint8>> machineCodeMap;
184     static void DumpJitCode(JSThread *thread);
185 
186 private:
187     static std::string BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it,
188                                              uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj,
189                                              LastBuilderCache &lastCache);
190     static constexpr int32_t InitialLength = 50;
191     static constexpr int32_t InitialDeeps = 5;
192 };
193 } // namespace panda::ecmascript
194 #endif  // ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H
195 extern "C" int ark_parse_js_frame_info(
196     uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data,
197     uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction);
198 extern "C" int ark_translate_js_frame_info(
199     uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction);
200 extern "C" int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam);
201 extern "C" int ark_write_jit_code(
202     void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray,
203     const size_t jitSize);
204 extern "C" int step_ark(
205     void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
206     uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame);
207 extern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr);
208 extern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr);
209 extern "C" int ark_parse_js_file_info(
210     uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr,
211     panda::ecmascript::JsFunction *jsFunction);
212 extern "C" int get_ark_native_frame_info(
213     int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size);
214 extern "C" int ark_parse_js_frame_info_local(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase,
215     uintptr_t loadOffset, panda::ecmascript::JsFunction *jsFunction);
216 extern "C" int ark_destory_local();
217 // define in dfx_signal_handler.h
218 typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext);
219 extern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak));