1 /*
2  * Copyright (c) 2023 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 #include "dfx_ark.h"
17 
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <dlfcn.h>
22 #include <pthread.h>
23 
24 #include "dfx_define.h"
25 #include "dfx_log.h"
26 #include "string_util.h"
27 
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace {
31 #undef LOG_DOMAIN
32 #undef LOG_TAG
33 #define LOG_DOMAIN 0xD002D11
34 #define LOG_TAG "DfxArk"
35 
36 const char ARK_LIB_NAME[] = "libark_jsruntime.so";
37 
38 void* g_handle = nullptr;
39 pthread_mutex_t g_mutex;
40 int (*g_getArkNativeFrameInfoFn)(int, uintptr_t*, uintptr_t*, uintptr_t*, JsFrame*, size_t&);
41 int (*g_stepArkFn)(void*, OHOS::HiviewDFX::ReadMemFunc, uintptr_t*, uintptr_t*, uintptr_t*, uintptr_t*, bool*);
42 int (*g_stepArkWithJitFn)(OHOS::HiviewDFX::ArkUnwindParam*);
43 int (*g_jitCodeWriteFileFn)(void*, OHOS::HiviewDFX::ReadMemFunc, int, const uintptr_t* const, const size_t);
44 int (*g_parseArkFileInfoFn)(uintptr_t, uintptr_t, uintptr_t, const char*, uintptr_t, JsFunction*);
45 int (*g_parseArkFrameInfoLocalFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, JsFunction*);
46 int (*g_parseArkFrameInfoFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uint8_t*, uint64_t, uintptr_t, JsFunction*);
47 int (*g_translateArkFrameInfoFn)(uint8_t*, uint64_t, JsFunction*);
48 int (*g_arkCreateJsSymbolExtractorFn)(uintptr_t*);
49 int (*g_arkDestoryJsSymbolExtractorFn)(uintptr_t);
50 int (*g_arkCreateLocalFn)();
51 int (*g_arkDestroyLocalFn)();
52 
GetLibArkHandle()53 bool GetLibArkHandle()
54 {
55     if (g_handle != nullptr) {
56         return true;
57     }
58     g_handle = dlopen(ARK_LIB_NAME, RTLD_LAZY);
59     if (g_handle == nullptr) {
60         LOGU("Failed to load library(%s).", dlerror());
61         return false;
62     }
63     return true;
64 }
65 }
66 
67 #define DLSYM_ARK_FUNC(FuncName, DlsymFuncName) { \
68     pthread_mutex_lock(&g_mutex); \
69     do { \
70         if ((DlsymFuncName) != nullptr) { \
71             break; \
72         } \
73         if (!GetLibArkHandle()) { \
74             break; \
75         } \
76         *(void**)(&(DlsymFuncName)) = dlsym(g_handle, (FuncName)); \
77         if ((DlsymFuncName) == NULL) { \
78             LOGE("Failed to dlsym(%s), error: %s", (FuncName), dlerror()); \
79             break; \
80         } \
81     } while (false); \
82     pthread_mutex_unlock(&g_mutex); \
83 }
84 
ArkCreateJsSymbolExtractor(uintptr_t * extractorPtr)85 int DfxArk::ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr)
86 {
87     if (g_arkCreateJsSymbolExtractorFn != nullptr) {
88         return g_arkCreateJsSymbolExtractorFn(extractorPtr);
89     }
90 
91     const char* arkFuncName = "ark_create_js_symbol_extractor";
92     DLSYM_ARK_FUNC(arkFuncName, g_arkCreateJsSymbolExtractorFn)
93 
94     if (g_arkCreateJsSymbolExtractorFn != nullptr) {
95         return g_arkCreateJsSymbolExtractorFn(extractorPtr);
96     }
97     return -1;
98 }
99 
ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr)100 int DfxArk::ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr)
101 {
102     if (g_arkDestoryJsSymbolExtractorFn != nullptr) {
103         return g_arkDestoryJsSymbolExtractorFn(extractorPtr);
104     }
105 
106     const char* arkFuncName = "ark_destory_js_symbol_extractor";
107     DLSYM_ARK_FUNC(arkFuncName, g_arkDestoryJsSymbolExtractorFn)
108 
109     if (g_arkDestoryJsSymbolExtractorFn != nullptr) {
110         return g_arkDestoryJsSymbolExtractorFn(extractorPtr);
111     }
112     return -1;
113 }
114 
ArkCreateLocal()115 int DfxArk::ArkCreateLocal()
116 {
117     if (g_arkCreateLocalFn != nullptr) {
118         return g_arkCreateLocalFn();
119     }
120 
121     const char* arkFuncName = "ark_create_local";
122     DLSYM_ARK_FUNC(arkFuncName, g_arkCreateLocalFn)
123 
124     if (g_arkCreateLocalFn != nullptr) {
125         return g_arkCreateLocalFn();
126     }
127     return -1;
128 }
129 
ArkDestroyLocal()130 int DfxArk::ArkDestroyLocal()
131 {
132     if (g_arkDestroyLocalFn != nullptr) {
133         return g_arkDestroyLocalFn();
134     }
135 
136     const char* arkFuncName = "ark_destroy_local";
137     DLSYM_ARK_FUNC(arkFuncName, g_arkDestroyLocalFn)
138 
139     if (g_arkDestroyLocalFn != nullptr) {
140         return g_arkDestroyLocalFn();
141     }
142     return -1;
143 }
144 
ParseArkFileInfo(uintptr_t byteCodePc,uintptr_t methodid,uintptr_t mapBase,const char * name,uintptr_t extractorPtr,JsFunction * jsFunction)145 int DfxArk::ParseArkFileInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, const char* name,
146     uintptr_t extractorPtr, JsFunction *jsFunction)
147 {
148     if (g_parseArkFileInfoFn != nullptr) {
149         return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction);
150     }
151 
152     const char* arkFuncName = "ark_parse_js_file_info";
153     DLSYM_ARK_FUNC(arkFuncName, g_parseArkFileInfoFn)
154 
155     if (g_parseArkFileInfoFn != nullptr) {
156         return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction);
157     }
158     return -1;
159 }
160 
ParseArkFrameInfoLocal(uintptr_t byteCodePc,uintptr_t methodid,uintptr_t mapBase,uintptr_t offset,JsFunction * jsFunction)161 int DfxArk::ParseArkFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase,
162     uintptr_t offset, JsFunction *jsFunction)
163 {
164     if (g_parseArkFrameInfoLocalFn != nullptr) {
165         return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction);
166     }
167 
168     const char* arkFuncName = "ark_parse_js_frame_info_local";
169     DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoLocalFn)
170 
171     if (g_parseArkFrameInfoLocalFn != nullptr) {
172         return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction);
173     }
174     return -1;
175 }
176 
ParseArkFrameInfo(uintptr_t byteCodePc,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorPtr,JsFunction * jsFunction)177 int DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset,
178     uint8_t *data, uint64_t dataSize, uintptr_t extractorPtr, JsFunction *jsFunction)
179 {
180     return ParseArkFrameInfo(byteCodePc, 0, mapBase, loadOffset, data, dataSize, extractorPtr, jsFunction);
181 }
182 
ParseArkFrameInfo(uintptr_t byteCodePc,uintptr_t methodid,uintptr_t mapBase,uintptr_t loadOffset,uint8_t * data,uint64_t dataSize,uintptr_t extractorPtr,JsFunction * jsFunction)183 int DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, uintptr_t loadOffset,
184     uint8_t *data, uint64_t dataSize, uintptr_t extractorPtr, JsFunction *jsFunction)
185 {
186     if (g_parseArkFrameInfoFn != nullptr) {
187         return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize,
188             extractorPtr, jsFunction);
189     }
190 
191     const char* arkFuncName = "ark_parse_js_frame_info";
192     DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoFn)
193 
194     if (g_parseArkFrameInfoFn != nullptr) {
195         return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize,
196             extractorPtr, jsFunction);
197     }
198     return -1;
199 }
200 
TranslateArkFrameInfo(uint8_t * data,uint64_t dataSize,JsFunction * jsFunction)201 int DfxArk::TranslateArkFrameInfo(uint8_t *data, uint64_t dataSize, JsFunction *jsFunction)
202 {
203     if (g_translateArkFrameInfoFn != nullptr) {
204         return g_translateArkFrameInfoFn(data, dataSize, jsFunction);
205     }
206 
207     const char* arkFuncName = "ark_translate_js_frame_info";
208     DLSYM_ARK_FUNC(arkFuncName, g_translateArkFrameInfoFn)
209 
210     if (g_translateArkFrameInfoFn != nullptr) {
211         return g_translateArkFrameInfoFn(data, dataSize, jsFunction);
212     }
213     return -1;
214 }
215 
StepArkFrame(void * obj,OHOS::HiviewDFX::ReadMemFunc readMemFn,uintptr_t * fp,uintptr_t * sp,uintptr_t * pc,uintptr_t * methodid,bool * isJsFrame)216 int DfxArk::StepArkFrame(void *obj, OHOS::HiviewDFX::ReadMemFunc readMemFn,
217     uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t* methodid, bool *isJsFrame)
218 {
219     if (g_stepArkFn != nullptr) {
220         return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame);
221     }
222 
223     const char* arkFuncName = "step_ark";
224     DLSYM_ARK_FUNC(arkFuncName, g_stepArkFn)
225 
226     if (g_stepArkFn != nullptr) {
227         return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame);
228     }
229     return -1;
230 }
231 
StepArkFrameWithJit(OHOS::HiviewDFX::ArkUnwindParam * arkPrama)232 int DfxArk::StepArkFrameWithJit(OHOS::HiviewDFX::ArkUnwindParam* arkPrama)
233 {
234     if (g_stepArkWithJitFn != nullptr) {
235         return g_stepArkWithJitFn(arkPrama);
236     }
237 
238     const char* const arkFuncName = "step_ark_with_record_jit";
239     DLSYM_ARK_FUNC(arkFuncName, g_stepArkWithJitFn)
240 
241     if (g_stepArkWithJitFn != nullptr) {
242         return g_stepArkWithJitFn(arkPrama);
243     }
244     return -1;
245 }
246 
JitCodeWriteFile(void * ctx,OHOS::HiviewDFX::ReadMemFunc readMemFn,int fd,const uintptr_t * const jitCodeArray,const size_t jitSize)247 int DfxArk::JitCodeWriteFile(void* ctx, OHOS::HiviewDFX::ReadMemFunc readMemFn, int fd,
248     const uintptr_t* const jitCodeArray, const size_t jitSize)
249 {
250     if (g_jitCodeWriteFileFn != nullptr) {
251         return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize);
252     }
253 
254     const char* const arkFuncName = "ark_write_jit_code";
255     DLSYM_ARK_FUNC(arkFuncName, g_jitCodeWriteFileFn)
256 
257     if (g_jitCodeWriteFileFn != nullptr) {
258         return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize);
259     }
260     return -1;
261 }
262 
GetArkNativeFrameInfo(int pid,uintptr_t & pc,uintptr_t & fp,uintptr_t & sp,JsFrame * frames,size_t & size)263 int DfxArk::GetArkNativeFrameInfo(int pid, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp, JsFrame* frames, size_t& size)
264 {
265     if (g_getArkNativeFrameInfoFn != nullptr) {
266         return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size);
267     }
268 
269     const char* arkFuncName = "get_ark_native_frame_info";
270     DLSYM_ARK_FUNC(arkFuncName, g_getArkNativeFrameInfoFn)
271 
272     if (g_getArkNativeFrameInfoFn != nullptr) {
273         return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size);
274     }
275     return -1;
276 }
277 } // namespace HiviewDFX
278 } // namespace OHOS
279