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
16#include "faultloggerdunwinder_fuzzer.h"
17
18#include <cstddef>
19#include <cstdint>
20
21#include "dfx_ark.h"
22#include "dfx_config.h"
23#include "dfx_hap.h"
24#include "dfx_regs.h"
25#include "dfx_xz_utils.h"
26#include "dwarf_op.h"
27#include "faultloggerd_fuzzertest_common.h"
28#include "thread_context.h"
29#include "unwinder.h"
30
31namespace OHOS {
32namespace HiviewDFX {
33const int FAULTLOGGER_FUZZTEST_MAX_STRING_LENGTH = 50;
34
35void TestDfxConfig()
36{
37    DfxConfig::GetConfig();
38}
39
40void TestGetArkNativeFrameInfo(const uint8_t* data, size_t size)
41{
42    int pid;
43    uintptr_t pc;
44    uintptr_t fp;
45    uintptr_t sp;
46    int offsetTotalLength = sizeof(pid) + sizeof(pc) + sizeof(fp) + sizeof(sp);
47    if (offsetTotalLength > size) {
48        return;
49    }
50
51    STREAM_TO_VALUEINFO(data, pid);
52    STREAM_TO_VALUEINFO(data, pc);
53    STREAM_TO_VALUEINFO(data, fp);
54    STREAM_TO_VALUEINFO(data, sp);
55
56    const size_t jSFRAME_MAX = 64;
57    JsFrame jsFrames[jSFRAME_MAX];
58
59    DfxArk::GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrames, size);
60}
61
62void TestStepArkFrame(const uint8_t* data, size_t size)
63{
64    uintptr_t pc;
65    uintptr_t fp;
66    uintptr_t sp;
67    uintptr_t methodid;
68    int offsetTotalLength = sizeof(pc) + sizeof(fp) + sizeof(sp) + sizeof(methodid);
69    if (offsetTotalLength > size) {
70        return;
71    }
72
73    STREAM_TO_VALUEINFO(data, pc);
74    STREAM_TO_VALUEINFO(data, fp);
75    STREAM_TO_VALUEINFO(data, sp);
76    STREAM_TO_VALUEINFO(data, methodid);
77    bool isJsFrame = methodid % 2;
78
79    DfxMemory dfxMemory;
80    DfxArk::StepArkFrame(&dfxMemory, &(Unwinder::AccessMem), &fp, &sp, &pc, &methodid, &isJsFrame);
81}
82
83void TestStepArkFrameWithJit(const uint8_t* data, size_t size)
84{
85    uintptr_t fp;
86    uintptr_t pc;
87    uintptr_t sp;
88    uintptr_t methodid;
89    int offsetTotalLength = sizeof(pc) + sizeof(fp) + sizeof(sp) + sizeof(methodid);
90    if (offsetTotalLength > size) {
91        return;
92    }
93
94    STREAM_TO_VALUEINFO(data, pc);
95    STREAM_TO_VALUEINFO(data, fp);
96    STREAM_TO_VALUEINFO(data, sp);
97    STREAM_TO_VALUEINFO(data, methodid);
98    bool isJsFrame = methodid % 2;
99
100    std::vector<uintptr_t> jitCache_ = {};
101    DfxMemory dfxMemory;
102    ArkUnwindParam arkParam(&dfxMemory, &(Unwinder::AccessMem), &fp, &sp, &pc, &methodid, &isJsFrame, jitCache_);
103    DfxArk::StepArkFrameWithJit(&arkParam);
104}
105
106void TestJitCodeWriteFile(const uint8_t* data, size_t size)
107{
108    int fd;
109    uintptr_t jitCacheData;
110    int offsetTotalLength = sizeof(fd) + sizeof(jitCacheData);
111    if (offsetTotalLength > size) {
112        return;
113    }
114
115    STREAM_TO_VALUEINFO(data, fd);
116    STREAM_TO_VALUEINFO(data, jitCacheData);
117
118    std::vector<uintptr_t> jitCache = {};
119    jitCache.push_back(jitCacheData);
120    DfxMemory dfxMemory;
121    DfxArk::JitCodeWriteFile(&dfxMemory, &(Unwinder::AccessMem), fd, jitCache.data(), jitCache.size());
122}
123
124void TestParseArkFrameInfoLocal(const uint8_t* data, size_t size)
125{
126    uintptr_t pc;
127    uintptr_t funcOffset;
128    uintptr_t mapBegin;
129    uintptr_t offset;
130    int offsetTotalLength = sizeof(pc) + sizeof(funcOffset) + sizeof(mapBegin) + sizeof(offset);
131    if (offsetTotalLength > size) {
132        return;
133    }
134
135    STREAM_TO_VALUEINFO(data, pc);
136    STREAM_TO_VALUEINFO(data, funcOffset);
137    STREAM_TO_VALUEINFO(data, mapBegin);
138    STREAM_TO_VALUEINFO(data, offset);
139
140    JsFunction jsFunction;
141    DfxArk::ParseArkFrameInfoLocal(static_cast<uintptr_t>(pc), static_cast<uintptr_t>(funcOffset),
142                                   static_cast<uintptr_t>(mapBegin), static_cast<uintptr_t>(offset), &jsFunction);
143}
144
145void TestArkCreateJsSymbolExtractor(const uint8_t* data, size_t size)
146{
147    uintptr_t extractorPtr;
148    if (size < sizeof(extractorPtr)) {
149        return;
150    }
151
152    STREAM_TO_VALUEINFO(data, extractorPtr);
153
154    DfxArk::ArkCreateJsSymbolExtractor(&extractorPtr);
155}
156
157void TestArkDestoryJsSymbolExtractor(const uint8_t* data, size_t size)
158{
159    uintptr_t extractorPtr;
160    if (size < sizeof(extractorPtr)) {
161        return;
162    }
163
164    STREAM_TO_VALUEINFO(data, extractorPtr);
165
166    DfxArk::ArkDestoryJsSymbolExtractor(extractorPtr);
167}
168
169void TestDfxArk(const uint8_t* data, size_t size)
170{
171    TestGetArkNativeFrameInfo(data, size);
172    TestStepArkFrame(data, size);
173    TestStepArkFrameWithJit(data, size);
174    TestJitCodeWriteFile(data, size);
175    TestParseArkFrameInfoLocal(data, size);
176    TestArkCreateJsSymbolExtractor(data, size);
177}
178
179void TestDfxHap(const uint8_t* data, size_t size)
180{
181    pid_t pid;
182    uint64_t pc;
183    uintptr_t methodid;
184    uintptr_t offset;
185    unsigned int offsetTotalLength = sizeof(pid) + sizeof(pc) + sizeof(methodid) + sizeof(offset);
186    if (offsetTotalLength > size) {
187        return;
188    }
189
190    STREAM_TO_VALUEINFO(data, pid);
191    STREAM_TO_VALUEINFO(data, pc);
192    STREAM_TO_VALUEINFO(data, methodid);
193    STREAM_TO_VALUEINFO(data, offset);
194
195    auto map = std::make_shared<DfxMap>();
196    JsFunction jsFunction;
197    DfxHap dfxHap;
198    dfxHap.ParseHapInfo(pid, pc, methodid, map, &jsFunction);
199}
200
201#if defined(__aarch64__)
202void TestSetFromFpMiniRegs(const uint8_t* data, size_t size)
203{
204    uintptr_t regs;
205    if (size < sizeof(regs)) {
206        return;
207    }
208
209    STREAM_TO_VALUEINFO(data, regs);
210
211    auto dfxregs = std::make_shared<DfxRegsArm64>();
212    dfxregs->SetFromFpMiniRegs(&regs, size);
213}
214#endif
215
216#if defined(__aarch64__)
217void TestSetFromQutMiniRegs(const uint8_t* data, size_t size)
218{
219    uintptr_t regs;
220    if (size < sizeof(regs)) {
221        return;
222    }
223
224    STREAM_TO_VALUEINFO(data, regs);
225
226    auto dfxregs = std::make_shared<DfxRegsArm64>();
227    dfxregs->SetFromQutMiniRegs(&regs, size);
228}
229#endif
230
231#if defined(__aarch64__)
232void TestDfxRegsArm64(const uint8_t* data, size_t size)
233{
234    TestSetFromFpMiniRegs(data, size);
235    TestSetFromQutMiniRegs(data, size);
236}
237#endif
238
239void TestThreadContext(const uint8_t* data, size_t size)
240{
241    int32_t tid;
242    uintptr_t stackBottom;
243    uintptr_t stackTop;
244    unsigned int offsetTotalLength = sizeof(tid) + sizeof(stackBottom) + sizeof(stackTop);
245    if (offsetTotalLength > size) {
246        return;
247    }
248
249    STREAM_TO_VALUEINFO(data, tid);
250    STREAM_TO_VALUEINFO(data, stackBottom);
251    STREAM_TO_VALUEINFO(data, stackTop);
252
253    LocalThreadContext& context = LocalThreadContext::GetInstance();
254    context.GetStackRange(tid, stackBottom, stackTop);
255    context.CollectThreadContext(tid);
256    context.GetThreadContext(tid);
257    context.ReleaseThread(tid);
258}
259
260void TestDfxInstrStatistic(const uint8_t* data, size_t size)
261{
262    uint32_t type;
263    uint64_t val;
264    uint64_t errInfo;
265    unsigned int offsetTotalLength = sizeof(type) + sizeof(val) + sizeof(errInfo) +
266                                     FAULTLOGGER_FUZZTEST_MAX_STRING_LENGTH;
267    if (offsetTotalLength > size) {
268        return;
269    }
270
271    STREAM_TO_VALUEINFO(data, type);
272    type = type % 10; // 10 : get the last digit of the number
273    STREAM_TO_VALUEINFO(data, val);
274    STREAM_TO_VALUEINFO(data, errInfo);
275
276    std::string soName(reinterpret_cast<const char*>(data), FAULTLOGGER_FUZZTEST_MAX_STRING_LENGTH);
277    data += FAULTLOGGER_FUZZTEST_MAX_STRING_LENGTH;
278
279    InstrStatisticType statisticType;
280    if (type == 0) {
281        statisticType = InstrStatisticType::InstructionEntriesArmExidx;
282    } else {
283        statisticType = InstrStatisticType::UnsupportedArmExidx;
284    }
285    DfxInstrStatistic& statistic = DfxInstrStatistic::GetInstance();
286    statistic.SetCurrentStatLib(soName);
287    statistic.AddInstrStatistic(statisticType, val, errInfo);
288    std::vector<std::pair<uint32_t, uint32_t>> result;
289    statistic.DumpInstrStatResult(result);
290}
291
292void TestDfxXzUtils(const uint8_t* data, size_t size)
293{
294    uint8_t src;
295    if (size < sizeof(src)) {
296        return;
297    }
298
299    STREAM_TO_VALUEINFO(data, src);
300
301    std::shared_ptr<std::vector<uint8_t>> out;
302    XzDecompress(&src, size, out);
303}
304
305void FaultloggerdUnwinderTest(const uint8_t* data, size_t size)
306{
307    TestDfxConfig();
308    TestDfxArk(data, size);
309    TestDfxHap(data, size);
310#if defined(__aarch64__)
311    TestDfxRegsArm64(data, size);
312#endif
313    TestThreadContext(data, size);
314    TestDfxInstrStatistic(data, size);
315    TestDfxXzUtils(data, size);
316    sleep(1);
317}
318} // namespace HiviewDFX
319} // namespace OHOS
320
321/* Fuzzer entry point */
322extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
323{
324    if (data == nullptr || size == 0) {
325        return 0;
326    }
327
328    /* Run your code on data */
329    OHOS::HiviewDFX::FaultloggerdUnwinderTest(data, size);
330    return 0;
331}
332