1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_ark.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <algorithm>
19800b99b8Sopenharmony_ci#include <cstdio>
20800b99b8Sopenharmony_ci#include <cstdlib>
21800b99b8Sopenharmony_ci#include <dlfcn.h>
22800b99b8Sopenharmony_ci#include <pthread.h>
23800b99b8Sopenharmony_ci
24800b99b8Sopenharmony_ci#include "dfx_define.h"
25800b99b8Sopenharmony_ci#include "dfx_log.h"
26800b99b8Sopenharmony_ci#include "string_util.h"
27800b99b8Sopenharmony_ci
28800b99b8Sopenharmony_cinamespace OHOS {
29800b99b8Sopenharmony_cinamespace HiviewDFX {
30800b99b8Sopenharmony_cinamespace {
31800b99b8Sopenharmony_ci#undef LOG_DOMAIN
32800b99b8Sopenharmony_ci#undef LOG_TAG
33800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
34800b99b8Sopenharmony_ci#define LOG_TAG "DfxArk"
35800b99b8Sopenharmony_ci
36800b99b8Sopenharmony_ciconst char ARK_LIB_NAME[] = "libark_jsruntime.so";
37800b99b8Sopenharmony_ci
38800b99b8Sopenharmony_civoid* g_handle = nullptr;
39800b99b8Sopenharmony_cipthread_mutex_t g_mutex;
40800b99b8Sopenharmony_ciint (*g_getArkNativeFrameInfoFn)(int, uintptr_t*, uintptr_t*, uintptr_t*, JsFrame*, size_t&);
41800b99b8Sopenharmony_ciint (*g_stepArkFn)(void*, OHOS::HiviewDFX::ReadMemFunc, uintptr_t*, uintptr_t*, uintptr_t*, uintptr_t*, bool*);
42800b99b8Sopenharmony_ciint (*g_stepArkWithJitFn)(OHOS::HiviewDFX::ArkUnwindParam*);
43800b99b8Sopenharmony_ciint (*g_jitCodeWriteFileFn)(void*, OHOS::HiviewDFX::ReadMemFunc, int, const uintptr_t* const, const size_t);
44800b99b8Sopenharmony_ciint (*g_parseArkFileInfoFn)(uintptr_t, uintptr_t, uintptr_t, const char*, uintptr_t, JsFunction*);
45800b99b8Sopenharmony_ciint (*g_parseArkFrameInfoLocalFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, JsFunction*);
46800b99b8Sopenharmony_ciint (*g_parseArkFrameInfoFn)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uint8_t*, uint64_t, uintptr_t, JsFunction*);
47800b99b8Sopenharmony_ciint (*g_translateArkFrameInfoFn)(uint8_t*, uint64_t, JsFunction*);
48800b99b8Sopenharmony_ciint (*g_arkCreateJsSymbolExtractorFn)(uintptr_t*);
49800b99b8Sopenharmony_ciint (*g_arkDestoryJsSymbolExtractorFn)(uintptr_t);
50800b99b8Sopenharmony_ciint (*g_arkDestoryLocalFn)();
51800b99b8Sopenharmony_ci
52800b99b8Sopenharmony_cibool GetLibArkHandle()
53800b99b8Sopenharmony_ci{
54800b99b8Sopenharmony_ci    if (g_handle != nullptr) {
55800b99b8Sopenharmony_ci        return true;
56800b99b8Sopenharmony_ci    }
57800b99b8Sopenharmony_ci    g_handle = dlopen(ARK_LIB_NAME, RTLD_LAZY);
58800b99b8Sopenharmony_ci    if (g_handle == nullptr) {
59800b99b8Sopenharmony_ci        DFXLOGU("Failed to load library(%{public}s).", dlerror());
60800b99b8Sopenharmony_ci        return false;
61800b99b8Sopenharmony_ci    }
62800b99b8Sopenharmony_ci    return true;
63800b99b8Sopenharmony_ci}
64800b99b8Sopenharmony_ci}
65800b99b8Sopenharmony_ci
66800b99b8Sopenharmony_ci#define DLSYM_ARK_FUNC(funcName, dlsymFuncName) { \
67800b99b8Sopenharmony_ci    pthread_mutex_lock(&g_mutex); \
68800b99b8Sopenharmony_ci    do { \
69800b99b8Sopenharmony_ci        if ((dlsymFuncName) != nullptr) { \
70800b99b8Sopenharmony_ci            break; \
71800b99b8Sopenharmony_ci        } \
72800b99b8Sopenharmony_ci        if (!GetLibArkHandle()) { \
73800b99b8Sopenharmony_ci            break; \
74800b99b8Sopenharmony_ci        } \
75800b99b8Sopenharmony_ci        (dlsymFuncName) = reinterpret_cast<decltype(dlsymFuncName)>(dlsym(g_handle, (funcName))); \
76800b99b8Sopenharmony_ci        if ((dlsymFuncName) == nullptr) { \
77800b99b8Sopenharmony_ci            DFXLOGE("Failed to dlsym(%{public}s), error: %{public}s", (funcName), dlerror()); \
78800b99b8Sopenharmony_ci            break; \
79800b99b8Sopenharmony_ci        } \
80800b99b8Sopenharmony_ci    } while (false); \
81800b99b8Sopenharmony_ci    pthread_mutex_unlock(&g_mutex); \
82800b99b8Sopenharmony_ci}
83800b99b8Sopenharmony_ci
84800b99b8Sopenharmony_ciint DfxArk::ArkCreateJsSymbolExtractor(uintptr_t* extractorPtr)
85800b99b8Sopenharmony_ci{
86800b99b8Sopenharmony_ci    if (g_arkCreateJsSymbolExtractorFn != nullptr) {
87800b99b8Sopenharmony_ci        return g_arkCreateJsSymbolExtractorFn(extractorPtr);
88800b99b8Sopenharmony_ci    }
89800b99b8Sopenharmony_ci
90800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_create_js_symbol_extractor";
91800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_arkCreateJsSymbolExtractorFn)
92800b99b8Sopenharmony_ci
93800b99b8Sopenharmony_ci    if (g_arkCreateJsSymbolExtractorFn != nullptr) {
94800b99b8Sopenharmony_ci        return g_arkCreateJsSymbolExtractorFn(extractorPtr);
95800b99b8Sopenharmony_ci    }
96800b99b8Sopenharmony_ci    return -1;
97800b99b8Sopenharmony_ci}
98800b99b8Sopenharmony_ci
99800b99b8Sopenharmony_ciint DfxArk::ArkDestoryJsSymbolExtractor(uintptr_t extractorPtr)
100800b99b8Sopenharmony_ci{
101800b99b8Sopenharmony_ci    if (g_arkDestoryJsSymbolExtractorFn != nullptr) {
102800b99b8Sopenharmony_ci        return g_arkDestoryJsSymbolExtractorFn(extractorPtr);
103800b99b8Sopenharmony_ci    }
104800b99b8Sopenharmony_ci
105800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_destory_js_symbol_extractor";
106800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_arkDestoryJsSymbolExtractorFn)
107800b99b8Sopenharmony_ci
108800b99b8Sopenharmony_ci    if (g_arkDestoryJsSymbolExtractorFn != nullptr) {
109800b99b8Sopenharmony_ci        return g_arkDestoryJsSymbolExtractorFn(extractorPtr);
110800b99b8Sopenharmony_ci    }
111800b99b8Sopenharmony_ci    return -1;
112800b99b8Sopenharmony_ci}
113800b99b8Sopenharmony_ci
114800b99b8Sopenharmony_ciint DfxArk::ArkDestoryLocal()
115800b99b8Sopenharmony_ci{
116800b99b8Sopenharmony_ci    if (g_arkDestoryLocalFn != nullptr) {
117800b99b8Sopenharmony_ci        return g_arkDestoryLocalFn();
118800b99b8Sopenharmony_ci    }
119800b99b8Sopenharmony_ci
120800b99b8Sopenharmony_ci    if (g_handle == nullptr) {
121800b99b8Sopenharmony_ci        return -1;
122800b99b8Sopenharmony_ci    }
123800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_destory_local";
124800b99b8Sopenharmony_ci    pthread_mutex_lock(&g_mutex);
125800b99b8Sopenharmony_ci    if (g_arkDestoryLocalFn != nullptr) {
126800b99b8Sopenharmony_ci        pthread_mutex_unlock(&g_mutex);
127800b99b8Sopenharmony_ci        return g_arkDestoryLocalFn();
128800b99b8Sopenharmony_ci    }
129800b99b8Sopenharmony_ci    g_arkDestoryLocalFn = reinterpret_cast<decltype(g_arkDestoryLocalFn)>(dlsym(g_handle, arkFuncName));
130800b99b8Sopenharmony_ci    pthread_mutex_unlock(&g_mutex);
131800b99b8Sopenharmony_ci    if (g_arkDestoryLocalFn != nullptr) {
132800b99b8Sopenharmony_ci        return g_arkDestoryLocalFn();
133800b99b8Sopenharmony_ci    }
134800b99b8Sopenharmony_ci    return -1;
135800b99b8Sopenharmony_ci}
136800b99b8Sopenharmony_ci
137800b99b8Sopenharmony_ciint DfxArk::ParseArkFileInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, const char* name,
138800b99b8Sopenharmony_ci    uintptr_t extractorPtr, JsFunction *jsFunction)
139800b99b8Sopenharmony_ci{
140800b99b8Sopenharmony_ci    if (g_parseArkFileInfoFn != nullptr) {
141800b99b8Sopenharmony_ci        return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction);
142800b99b8Sopenharmony_ci    }
143800b99b8Sopenharmony_ci
144800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_parse_js_file_info";
145800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_parseArkFileInfoFn)
146800b99b8Sopenharmony_ci
147800b99b8Sopenharmony_ci    if (g_parseArkFileInfoFn != nullptr) {
148800b99b8Sopenharmony_ci        return g_parseArkFileInfoFn(byteCodePc, methodid, mapBase, name, extractorPtr, jsFunction);
149800b99b8Sopenharmony_ci    }
150800b99b8Sopenharmony_ci    return -1;
151800b99b8Sopenharmony_ci}
152800b99b8Sopenharmony_ci
153800b99b8Sopenharmony_ciint DfxArk::ParseArkFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase,
154800b99b8Sopenharmony_ci    uintptr_t offset, JsFunction *jsFunction)
155800b99b8Sopenharmony_ci{
156800b99b8Sopenharmony_ci    if (g_parseArkFrameInfoLocalFn != nullptr) {
157800b99b8Sopenharmony_ci        return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction);
158800b99b8Sopenharmony_ci    }
159800b99b8Sopenharmony_ci
160800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_parse_js_frame_info_local";
161800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoLocalFn)
162800b99b8Sopenharmony_ci
163800b99b8Sopenharmony_ci    if (g_parseArkFrameInfoLocalFn != nullptr) {
164800b99b8Sopenharmony_ci        return g_parseArkFrameInfoLocalFn(byteCodePc, methodid, mapBase, offset, jsFunction);
165800b99b8Sopenharmony_ci    }
166800b99b8Sopenharmony_ci    return -1;
167800b99b8Sopenharmony_ci}
168800b99b8Sopenharmony_ci
169800b99b8Sopenharmony_ciint DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset,
170800b99b8Sopenharmony_ci    uint8_t *data, uint64_t dataSize, uintptr_t extractorPtr, JsFunction *jsFunction)
171800b99b8Sopenharmony_ci{
172800b99b8Sopenharmony_ci    return ParseArkFrameInfo(byteCodePc, 0, mapBase, loadOffset, data, dataSize, extractorPtr, jsFunction);
173800b99b8Sopenharmony_ci}
174800b99b8Sopenharmony_ci
175800b99b8Sopenharmony_ciint DfxArk::ParseArkFrameInfo(uintptr_t byteCodePc, uintptr_t methodid, uintptr_t mapBase, uintptr_t loadOffset,
176800b99b8Sopenharmony_ci    uint8_t *data, uint64_t dataSize, uintptr_t extractorPtr, JsFunction *jsFunction)
177800b99b8Sopenharmony_ci{
178800b99b8Sopenharmony_ci    if (g_parseArkFrameInfoFn != nullptr) {
179800b99b8Sopenharmony_ci        return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize,
180800b99b8Sopenharmony_ci            extractorPtr, jsFunction);
181800b99b8Sopenharmony_ci    }
182800b99b8Sopenharmony_ci
183800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_parse_js_frame_info";
184800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_parseArkFrameInfoFn)
185800b99b8Sopenharmony_ci
186800b99b8Sopenharmony_ci    if (g_parseArkFrameInfoFn != nullptr) {
187800b99b8Sopenharmony_ci        return g_parseArkFrameInfoFn(byteCodePc, methodid, mapBase, loadOffset, data, dataSize,
188800b99b8Sopenharmony_ci            extractorPtr, jsFunction);
189800b99b8Sopenharmony_ci    }
190800b99b8Sopenharmony_ci    return -1;
191800b99b8Sopenharmony_ci}
192800b99b8Sopenharmony_ci
193800b99b8Sopenharmony_ciint DfxArk::TranslateArkFrameInfo(uint8_t *data, uint64_t dataSize, JsFunction *jsFunction)
194800b99b8Sopenharmony_ci{
195800b99b8Sopenharmony_ci    if (g_translateArkFrameInfoFn != nullptr) {
196800b99b8Sopenharmony_ci        return g_translateArkFrameInfoFn(data, dataSize, jsFunction);
197800b99b8Sopenharmony_ci    }
198800b99b8Sopenharmony_ci
199800b99b8Sopenharmony_ci    const char* arkFuncName = "ark_translate_js_frame_info";
200800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_translateArkFrameInfoFn)
201800b99b8Sopenharmony_ci
202800b99b8Sopenharmony_ci    if (g_translateArkFrameInfoFn != nullptr) {
203800b99b8Sopenharmony_ci        return g_translateArkFrameInfoFn(data, dataSize, jsFunction);
204800b99b8Sopenharmony_ci    }
205800b99b8Sopenharmony_ci    return -1;
206800b99b8Sopenharmony_ci}
207800b99b8Sopenharmony_ci
208800b99b8Sopenharmony_ciint DfxArk::StepArkFrame(void *obj, OHOS::HiviewDFX::ReadMemFunc readMemFn,
209800b99b8Sopenharmony_ci    uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t* methodid, bool *isJsFrame)
210800b99b8Sopenharmony_ci{
211800b99b8Sopenharmony_ci    if (g_stepArkFn != nullptr) {
212800b99b8Sopenharmony_ci        return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame);
213800b99b8Sopenharmony_ci    }
214800b99b8Sopenharmony_ci
215800b99b8Sopenharmony_ci    const char* arkFuncName = "step_ark";
216800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_stepArkFn)
217800b99b8Sopenharmony_ci
218800b99b8Sopenharmony_ci    if (g_stepArkFn != nullptr) {
219800b99b8Sopenharmony_ci        return g_stepArkFn(obj, readMemFn, fp, sp, pc, methodid, isJsFrame);
220800b99b8Sopenharmony_ci    }
221800b99b8Sopenharmony_ci    return -1;
222800b99b8Sopenharmony_ci}
223800b99b8Sopenharmony_ci
224800b99b8Sopenharmony_ciint DfxArk::StepArkFrameWithJit(OHOS::HiviewDFX::ArkUnwindParam* arkPrama)
225800b99b8Sopenharmony_ci{
226800b99b8Sopenharmony_ci    if (g_stepArkWithJitFn != nullptr) {
227800b99b8Sopenharmony_ci        return g_stepArkWithJitFn(arkPrama);
228800b99b8Sopenharmony_ci    }
229800b99b8Sopenharmony_ci
230800b99b8Sopenharmony_ci    const char* const arkFuncName = "step_ark_with_record_jit";
231800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_stepArkWithJitFn)
232800b99b8Sopenharmony_ci
233800b99b8Sopenharmony_ci    if (g_stepArkWithJitFn != nullptr) {
234800b99b8Sopenharmony_ci        return g_stepArkWithJitFn(arkPrama);
235800b99b8Sopenharmony_ci    }
236800b99b8Sopenharmony_ci    return -1;
237800b99b8Sopenharmony_ci}
238800b99b8Sopenharmony_ci
239800b99b8Sopenharmony_ciint DfxArk::JitCodeWriteFile(void* ctx, OHOS::HiviewDFX::ReadMemFunc readMemFn, int fd,
240800b99b8Sopenharmony_ci    const uintptr_t* const jitCodeArray, const size_t jitSize)
241800b99b8Sopenharmony_ci{
242800b99b8Sopenharmony_ci    if (g_jitCodeWriteFileFn != nullptr) {
243800b99b8Sopenharmony_ci        return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize);
244800b99b8Sopenharmony_ci    }
245800b99b8Sopenharmony_ci
246800b99b8Sopenharmony_ci    const char* const arkFuncName = "ark_write_jit_code";
247800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_jitCodeWriteFileFn)
248800b99b8Sopenharmony_ci
249800b99b8Sopenharmony_ci    if (g_jitCodeWriteFileFn != nullptr) {
250800b99b8Sopenharmony_ci        return g_jitCodeWriteFileFn(ctx, readMemFn, fd, jitCodeArray, jitSize);
251800b99b8Sopenharmony_ci    }
252800b99b8Sopenharmony_ci    return -1;
253800b99b8Sopenharmony_ci}
254800b99b8Sopenharmony_ci
255800b99b8Sopenharmony_ciint DfxArk::GetArkNativeFrameInfo(int pid, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp, JsFrame* frames, size_t& size)
256800b99b8Sopenharmony_ci{
257800b99b8Sopenharmony_ci    if (g_getArkNativeFrameInfoFn != nullptr) {
258800b99b8Sopenharmony_ci        return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size);
259800b99b8Sopenharmony_ci    }
260800b99b8Sopenharmony_ci
261800b99b8Sopenharmony_ci    const char* arkFuncName = "get_ark_native_frame_info";
262800b99b8Sopenharmony_ci    DLSYM_ARK_FUNC(arkFuncName, g_getArkNativeFrameInfoFn)
263800b99b8Sopenharmony_ci
264800b99b8Sopenharmony_ci    if (g_getArkNativeFrameInfoFn != nullptr) {
265800b99b8Sopenharmony_ci        return g_getArkNativeFrameInfoFn(pid, &pc, &fp, &sp, frames, size);
266800b99b8Sopenharmony_ci    }
267800b99b8Sopenharmony_ci    return -1;
268800b99b8Sopenharmony_ci}
269800b99b8Sopenharmony_ci} // namespace HiviewDFX
270800b99b8Sopenharmony_ci} // namespace OHOS
271