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
24using namespace testing;
25using namespace testing::ext;
26using namespace std;
27
28namespace OHOS {
29namespace HiviewDFX {
30namespace {
31const char ARK_LIB_NAME[] = "libark_jsruntime.so";
32
33void* g_handle = nullptr;
34pthread_mutex_t g_mutex;
35int (*g_getArkNativeFrameInfoFn)(int, uintptr_t*, uintptr_t*, uintptr_t*, JsFrame*, size_t&);
36int (*g_stepArkFn)(void*, OHOS::HiviewDFX::ReadMemFunc, uintptr_t*, uintptr_t*, uintptr_t*, uintptr_t*, bool*);
37int (*g_stepArkWithJitFn)(OHOS::HiviewDFX::ArkUnwindParam*);
38int (*g_jitCodeWriteFileFn)(void*, OHOS::HiviewDFX::ReadMemFunc, int, const uintptr_t* const, const size_t);
39int (*g_parseArkFileInfoFn)(uintptr_t, uintptr_t, uintptr_t, const char*, uintptr_t, JsFunction*);
40int (*g_parseArkFrameInfoLocalFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, JsFunction*);
41int (*g_parseArkFrameInfoFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uint8_t*, uint64_t, uintptr_t, JsFunction*);
42int (*g_arkCreateJsSymbolExtractorFn)(uintptr_t*);
43int (*g_arkDestoryJsSymbolExtractorFn)(uintptr_t);
44int (*g_arkDestoryLocalFn)();
45using RustDemangleFn = char*(*)(const char *);
46RustDemangleFn g_rustDemangleFn = nullptr;
47
48bool 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
73class ArkTest : public testing::Test {
74public:
75    static void SetUpTestCase() {}
76    static void TearDownTestCase() {}
77    void SetUp() {}
78    void TearDown() {}
79};
80
81/**
82 * @tc.name: ArkTest001
83 * @tc.desc: test ArkCreateJsSymbolExtractor functions
84 * @tc.type: FUNC
85 */
86HWTEST_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 */
104HWTEST_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 */
121HWTEST_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 */
143HWTEST_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 */
164HWTEST_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 */
188HWTEST_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 */
237HWTEST_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 */
265HWTEST_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 */
286HWTEST_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 */
309HWTEST_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}