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 #include <gtest/gtest.h>
16
17 #include <cstdio>
18 #include <dlfcn.h>
19 #include <cstdint>
20
21 #include "dfx_ark.h"
22 #include "dfx_log.h"
23
24 using namespace testing;
25 using namespace testing::ext;
26 using namespace std;
27
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace {
31 const char ARK_LIB_NAME[] = "libark_jsruntime.so";
32
33 void* g_handle = nullptr;
34 pthread_mutex_t g_mutex;
35 int (*g_getArkNativeFrameInfoFn)(int, uintptr_t*, uintptr_t*, uintptr_t*, JsFrame*, size_t&);
36 int (*g_stepArkFn)(void*, OHOS::HiviewDFX::ReadMemFunc, uintptr_t*, uintptr_t*, uintptr_t*, uintptr_t*, bool*);
37 int (*g_stepArkWithJitFn)(OHOS::HiviewDFX::ArkUnwindParam*);
38 int (*g_jitCodeWriteFileFn)(void*, OHOS::HiviewDFX::ReadMemFunc, int, const uintptr_t* const, const size_t);
39 int (*g_parseArkFileInfoFn)(uintptr_t, uintptr_t, uintptr_t, const char*, uintptr_t, JsFunction*);
40 int (*g_parseArkFrameInfoLocalFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, JsFunction*);
41 int (*g_parseArkFrameInfoFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uint8_t*, uint64_t, uintptr_t, JsFunction*);
42 int (*g_arkCreateJsSymbolExtractorFn)(uintptr_t*);
43 int (*g_arkDestoryJsSymbolExtractorFn)(uintptr_t);
44 int (*g_arkDestoryLocalFn)();
45 using RustDemangleFn = char*(*)(const char *);
46 RustDemangleFn g_rustDemangleFn = nullptr;
47
GetLibArkHandle()48 bool GetLibArkHandle()
49 {
50 if (g_handle != nullptr) {
51 return true;
52 }
53 g_handle = dlopen(ARK_LIB_NAME, RTLD_LAZY);
54 if (g_handle == nullptr) {
55 DFXLOGU("Failed to load library(%{public}s).", dlerror());
56 return false;
57 }
58 return true;
59 }
60 } // namespace
61
62 #define DLSYM_ARK_FUNC(FuncName, DlsymFuncName) { \
63 pthread_mutex_lock(&g_mutex); \
64 do { \
65 if (!GetLibArkHandle()) { \
66 break; \
67 } \
68 *reinterpret_cast<void**>(&(DlsymFuncName)) = dlsym(g_handle, (FuncName)); \
69 } while (false); \
70 pthread_mutex_unlock(&g_mutex); \
71 }
72
73 class ArkTest : public testing::Test {
74 public:
SetUpTestCase()75 static void SetUpTestCase() {}
TearDownTestCase()76 static void TearDownTestCase() {}
SetUp()77 void SetUp() {}
TearDown()78 void TearDown() {}
79 };
80
81 /**
82 * @tc.name: ArkTest001
83 * @tc.desc: test ArkCreateJsSymbolExtractor functions
84 * @tc.type: FUNC
85 */
HWTEST_F(ArkTest, ArkTest001, TestSize.Level2)86 HWTEST_F(ArkTest, ArkTest001, TestSize.Level2)
87 {
88 GTEST_LOG_(INFO) << "ArkTest001: start.";
89 uintptr_t zero = 0;
90 uintptr_t* extractorPtr = &zero;
91 const char* arkFuncName = "ark_create_js_symbol_extractor";
92 DLSYM_ARK_FUNC(arkFuncName, g_arkCreateJsSymbolExtractorFn)
93 ASSERT_NE(g_arkCreateJsSymbolExtractorFn, nullptr);
94 g_arkCreateJsSymbolExtractorFn(extractorPtr);
95 g_arkCreateJsSymbolExtractorFn = nullptr;
96 GTEST_LOG_(INFO) << "ArkTest001: end.";
97 }
98
99 /**
100 * @tc.name: ArkTest002
101 * @tc.desc: test ArkDestoryJsSymbolExtractor functions
102 * @tc.type: FUNC
103 */
HWTEST_F(ArkTest, ArkTest002, TestSize.Level2)104 HWTEST_F(ArkTest, ArkTest002, TestSize.Level2)
105 {
106 GTEST_LOG_(INFO) << "ArkTest002: start.";
107 uintptr_t extractorPtr = 0;
108 const char* arkFuncName = "ark_destory_js_symbol_extractor";
109 DLSYM_ARK_FUNC(arkFuncName, g_arkDestoryJsSymbolExtractorFn)
110 ASSERT_NE(g_arkDestoryJsSymbolExtractorFn, nullptr);
111 g_arkDestoryJsSymbolExtractorFn(extractorPtr);
112 g_arkDestoryJsSymbolExtractorFn = nullptr;
113 GTEST_LOG_(INFO) << "ArkTest002: end.";
114 }
115
116 /**
117 * @tc.name: ArkTest003
118 * @tc.desc: test ParseArkFileInfo functions
119 * @tc.type: FUNC
120 */
HWTEST_F(ArkTest, ArkTest003, TestSize.Level2)121 HWTEST_F(ArkTest, ArkTest003, TestSize.Level2)
122 {
123 GTEST_LOG_(INFO) << "ArkTest003: start.";
124 uintptr_t byteCodePc = 0;
125 uintptr_t methodid = 0;
126 uintptr_t mapBase = 0;
127 const char* name = nullptr;
128 uintptr_t extractorPtr = 0;
129 JsFunction *jsFunction = nullptr;
130 const char* arkFuncName = "ark_parse_js_file_info";
131 DLSYM_ARK_FUNC(arkFuncName, g_parseArkFileInfoFn)
132 ASSERT_NE(g_parseArkFileInfoFn, nullptr);
133 g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction);
134 g_parseArkFileInfoFn = nullptr;
135 GTEST_LOG_(INFO) << "ArkTest003: end.";
136 }
137
138 /**
139 * @tc.name: ArkTest004
140 * @tc.desc: test ParseArkFrameInfoLocal functions
141 * @tc.type: FUNC
142 */
HWTEST_F(ArkTest, ArkTest004, TestSize.Level2)143 HWTEST_F(ArkTest, ArkTest004, TestSize.Level2)
144 {
145 GTEST_LOG_(INFO) << "ArkTest004: start.";
146 uintptr_t byteCodePc = 0;
147 uintptr_t methodid = 0;
148 uintptr_t mapBase = 0;
149 uintptr_t offset = 0;
150 JsFunction *jsFunction = nullptr;
151 const char* arkFuncName = "ark_parse_js_frame_info_local";
152 DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoLocalFn)
153 ASSERT_NE(g_parseArkFrameInfoLocalFn, nullptr);
154 g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction);
155 g_parseArkFrameInfoLocalFn = nullptr;
156 GTEST_LOG_(INFO) << "ArkTest004: end.";
157 }
158
159 /**
160 * @tc.name: ArkTest005
161 * @tc.desc: test ParseArkFrameInfo functions
162 * @tc.type: FUNC
163 */
HWTEST_F(ArkTest, ArkTest005, TestSize.Level2)164 HWTEST_F(ArkTest, ArkTest005, TestSize.Level2)
165 {
166 GTEST_LOG_(INFO) << "ArkTest005: start.";
167 uintptr_t byteCodePc = 0;
168 uintptr_t methodid = 0;
169 uintptr_t mapBase = 0;
170 uintptr_t loadOffset = 0;
171 uint8_t *data = nullptr;
172 uint64_t dataSize = 0;
173 uintptr_t extractorPtr = 0;
174 JsFunction *jsFunction = nullptr;
175 const char* arkFuncName = "ark_parse_js_frame_info";
176 DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoFn)
177 ASSERT_NE(g_parseArkFrameInfoFn, nullptr);
178 g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize, extractorPtr, jsFunction);
179 g_parseArkFrameInfoFn = nullptr;
180 GTEST_LOG_(INFO) << "ArkTest005: end.";
181 }
182
183 /**
184 * @tc.name: ArkTest006
185 * @tc.desc: test StepArkFrame functions
186 * @tc.type: FUNC
187 */
HWTEST_F(ArkTest, ArkTest006, TestSize.Level2)188 HWTEST_F(ArkTest, ArkTest006, TestSize.Level2)
189 {
190 GTEST_LOG_(INFO) << "ArkTest006: start.";
191 pid_t pid = fork();
192 if (pid == 0) {
193 uintptr_t zero = 0;
194 void *obj = nullptr;
195 OHOS::HiviewDFX::ReadMemFunc readMemFn = nullptr;
196 uintptr_t *fp = &zero;
197 uintptr_t *sp = &zero;
198 uintptr_t *pc = &zero;
199 uintptr_t* methodid = &zero;
200 bool *isJsFrame = nullptr;
201 const char* arkFuncName = "step_ark";
202 DLSYM_ARK_FUNC(arkFuncName, g_stepArkFn)
203 ASSERT_NE(g_stepArkFn, nullptr);
204 g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame);
205 g_stepArkFn = nullptr;
206 ASSERT_NE(g_handle, nullptr);
207 const char* arkFuncName1 = "ark_destory_local";
208 pthread_mutex_lock(&g_mutex);
209 *reinterpret_cast<void**>(&(g_arkDestoryLocalFn)) = dlsym(g_handle, arkFuncName1);
210 pthread_mutex_unlock(&g_mutex);
211 ASSERT_NE(g_arkDestoryLocalFn, nullptr);
212 g_arkDestoryLocalFn();
213 g_arkDestoryLocalFn = nullptr;
214 exit(0);
215 }
216 int status;
217 bool isSuccess = waitpid(pid, &status, 0) != -1;
218 if (!isSuccess) {
219 ASSERT_FALSE(isSuccess);
220 return;
221 }
222
223 int exitCode = -1;
224 if (WIFEXITED(status)) {
225 exitCode = WEXITSTATUS(status);
226 printf("Exit status was %d\n", exitCode);
227 }
228 ASSERT_EQ(exitCode, 0);
229 GTEST_LOG_(INFO) << "ArkTest006: end.";
230 }
231
232 /**
233 * @tc.name: ArkTest007
234 * @tc.desc: test StepArkFrameWithJit functions
235 * @tc.type: FUNC
236 */
HWTEST_F(ArkTest, ArkTest007, TestSize.Level2)237 HWTEST_F(ArkTest, ArkTest007, TestSize.Level2)
238 {
239 GTEST_LOG_(INFO) << "ArkTest007: start.";
240 uintptr_t zero = 0;
241 void *ctx = &zero;
242 ReadMemFunc readMem = nullptr;
243 uintptr_t *fp = &zero;
244 uintptr_t *sp = &zero;
245 uintptr_t *pc = &zero;
246 uintptr_t *methodId = &zero;
247 bool *isJsFrame = nullptr;
248 std::vector<uintptr_t> vec;
249 std::vector<uintptr_t>& jitCache = vec;
250 OHOS::HiviewDFX::ArkUnwindParam ark(ctx, readMem, fp, sp, pc, methodId, isJsFrame, jitCache);
251 OHOS::HiviewDFX::ArkUnwindParam* arkPrama = &ark;
252 const char* const arkFuncName = "step_ark_with_record_jit";
253 DLSYM_ARK_FUNC(arkFuncName, g_stepArkWithJitFn)
254 ASSERT_NE(g_stepArkWithJitFn, nullptr);
255 g_stepArkWithJitFn(arkPrama);
256 g_stepArkWithJitFn = nullptr;
257 GTEST_LOG_(INFO) << "ArkTest007: end.";
258 }
259
260 /**
261 * @tc.name: ArkTest008
262 * @tc.desc: test JitCodeWriteFile functions
263 * @tc.type: FUNC
264 */
HWTEST_F(ArkTest, ArkTest008, TestSize.Level2)265 HWTEST_F(ArkTest, ArkTest008, TestSize.Level2)
266 {
267 GTEST_LOG_(INFO) << "ArkTest008: start.";
268 void* ctx = nullptr;
269 OHOS::HiviewDFX::ReadMemFunc readMemFn = nullptr;
270 int fd = -1;
271 const uintptr_t* const jitCodeArray = nullptr;
272 const size_t jitSize = 0;
273 const char* const arkFuncName = "ark_write_jit_code";
274 DLSYM_ARK_FUNC(arkFuncName, g_jitCodeWriteFileFn)
275 ASSERT_NE(g_jitCodeWriteFileFn, nullptr);
276 g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize);
277 g_jitCodeWriteFileFn = nullptr;
278 GTEST_LOG_(INFO) << "ArkTest008: end.";
279 }
280
281 /**
282 * @tc.name: ArkTest009
283 * @tc.desc: test GetArkNativeFrameInfo functions
284 * @tc.type: FUNC
285 */
HWTEST_F(ArkTest, ArkTest009, TestSize.Level2)286 HWTEST_F(ArkTest, ArkTest009, TestSize.Level2)
287 {
288 GTEST_LOG_(INFO) << "ArkTest009: start.";
289 int pid = 0;
290 uintptr_t zero = 0;
291 uintptr_t& pc = zero;
292 uintptr_t& fp = zero;
293 uintptr_t& sp = zero;
294 JsFrame* frames = nullptr;
295 size_t& size = zero;
296 const char* arkFuncName = "get_ark_native_frame_info";
297 DLSYM_ARK_FUNC(arkFuncName, g_getArkNativeFrameInfoFn)
298 ASSERT_NE(g_getArkNativeFrameInfoFn, nullptr);
299 g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size);
300 g_getArkNativeFrameInfoFn = nullptr;
301 GTEST_LOG_(INFO) << "ArkTest009: end.";
302 }
303
304 /**
305 * @tc.name: ArkTest010
306 * @tc.desc: test rustc_demangle functions
307 * @tc.type: FUNC
308 */
HWTEST_F(ArkTest, ArkTest010, TestSize.Level2)309 HWTEST_F(ArkTest, ArkTest010, TestSize.Level2)
310 {
311 GTEST_LOG_(INFO) << "ArkTest010: start.";
312 void* handle = dlopen("librustc_demangle.z.so", RTLD_LAZY | RTLD_NODELETE);
313 ASSERT_TRUE(handle) << "Failed to dlopen librustc_demangle";
314 g_rustDemangleFn = (RustDemangleFn)dlsym(handle, "rustc_demangle");
315 ASSERT_TRUE(g_rustDemangleFn) << "Failed to dlsym rustc_demangle";
316 std::string reason = "reason";
317 const char *bufStr = reason.c_str();
318 g_rustDemangleFn(bufStr);
319 g_rustDemangleFn = nullptr;
320 GTEST_LOG_(INFO) << "ArkTest010: end.";
321 }
322 }
323 }