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 }