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