1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
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#ifndef BPF_EVENT_RECEIVER_H
17#define BPF_EVENT_RECEIVER_H
18
19#include <memory>
20#include <thread>
21#include <mutex>
22#include <condition_variable>
23
24
25#include "type_headers.h"
26#include "ringbuffer.h"
27#include "hiebpf_data_file.h"
28#include "hhlog.h"
29#include "hiebpf.skel.h"
30#include "bpf.h"
31#include "fstrace_args_converter.h"
32#include "maps_info.h"
33#include "elf_symbol_info.h"
34#include <iostream>
35
36
37#define FSTRACE_MAX_ARGS    4
38#define MAX_TRACER_NAME_LEN 8
39#define MAX_TYPE_NAME_LEN   16
40#define MAX_BUSY_LOOPS      1000
41#define PADDING(nbytes)     char reserve_[nbytes]
42
43struct FixedFSTraceTLVItem {
44    __u32 tracer_;
45    __u32 itemLen_;
46    __u32 pid_;
47    __u32 tid_;
48    char tracerName_[MAX_TRACER_NAME_LEN]; // MAX_TRACER_NAME_LEN = 8 bytes, which is 64 bits
49    __u64 stime_;
50    __u64 ctime_;
51    char typeName_[MAX_TYPE_NAME_LEN];      // MAX_TYPE_NAME_LEN = 16 bytes, which is 128 bits
52    int32_t  retval_;
53    uint16_t nips_;
54    uint16_t type_;
55    __u64 args_[FSTRACE_MAX_ARGS];
56    char comm_[MAX_COMM_LEN];           // MAX_COMM_LEN = 16 bytes, which 128 bits
57    /* the above members have been carefully aligned */
58};
59
60struct FixedPFTraceTLVItem {
61    __u32 tracer_;
62    __u32 itemLen_;
63    __u32 pid_;
64    __u32 tid_;
65    char tracerName_[MAX_TRACER_NAME_LEN];
66    __u64 stime_;
67    __u64 ctime_;
68    char typeName_[MAX_TYPE_NAME_LEN];
69    __u64 addr_;
70    __u32 size_;
71    uint16_t nips_;
72    uint16_t type_;
73    char comm_[MAX_COMM_LEN];
74    /* the above members have been carefully aligned */
75};
76
77struct FixedBIOTraceTLVItem {
78    __u32 tracer_;
79    __u32 itemLen_;
80    __u32 pid_;
81    __u32 tid_;
82    char comm_[MAX_COMM_LEN];
83    __u64 stime_;
84    __u64 ctime_;
85    __u32 prio_;
86    __u32 size_;
87    __u64 blkcnt_;
88    __u32 nips_;
89    __u32 type_;
90    char typeName_[MAX_TYPE_NAME_LEN];
91};
92
93struct FixedSTRTraceTLVItem {
94    __u32 tracer_;
95    __u32 itemLen_;
96    __u32 pid_;
97    __u32 tid_;
98    __u64 stime_;
99    __u32 srcTracer_;
100    __u32 srcType_;
101    __u32 strLen_;
102    PADDING(sizeof(__u32));
103    /* the above members have been carefully aligned */
104};
105
106struct FixedMapTLVItem {
107    uint32_t type = 0;
108    uint32_t len = 0;
109    uint64_t start = 0;
110    uint64_t end = 0;
111    uint32_t offset = 0;
112    uint32_t pid = 0;
113    uint32_t fileNameLen = 0;
114}__attribute__((packed));
115
116struct FixedSymbolTLVItem {
117    uint32_t type = 0;
118    uint32_t len = 0;
119    uint64_t textVaddr = 0;
120    uint32_t textOffset = 0;
121    uint32_t strTabLen = 0;
122    uint32_t symTabLen = 0;
123    uint32_t fileNameLen = 0;
124    uint32_t symEntLen = 0;
125}__attribute__((packed));
126
127class BPFEventReceiver {
128public:
129    static inline std::shared_ptr<BPFEventReceiver> MakeShared(const std::weak_ptr<HiebpfDataFile> &file)
130    {
131        std::shared_ptr<BPFEventReceiver> obj {new(std::nothrow) BPFEventReceiver {file}};
132        if (obj == nullptr) {
133            return nullptr;
134        }
135        if (obj->InitBuffer() != 0) {
136            return nullptr;
137        }
138        return obj;
139    }
140
141    ~BPFEventReceiver()
142    {
143        if (not stop_) {
144            stop_ = true;
145        }
146        if (workLoop_.joinable()) {
147            workLoop_.join();
148        }
149    }
150
151    inline int Put(void *data, const size_t dataSize)
152    {
153        HHLOGF((data == nullptr or dataSize == 0), "invalid arguments: this should never happen");
154        HHLOGF(buf_ == nullptr, "receiver has no buffer: this should never happen");
155        int ret {-1};
156        ret = buf_->Put((const char*)data, dataSize);
157        if (ret == static_cast<int>(dataSize)) {
158            NotifyOne();
159        }
160        HHLOGF((0 <= ret and ret < static_cast<int>(dataSize)), "incomplete data received: this should never happen");
161        return ret;
162    }
163
164    inline int Start()
165    {
166        workLoop_ = std::thread([this] { this->WorkLoop(); });
167        return 0;
168    }
169
170    inline void Stop()
171    {
172        if (Running()) {
173            stop_ = true;
174            NotifyOne();
175        }
176        if (workLoop_.joinable()) {
177            workLoop_.join();
178        }
179    }
180
181    inline bool Running() const
182    {
183        return (not stop_);
184    }
185
186private:
187    enum MemAlign:std::size_t {
188        ALIGNMENT_BYTES = 8,
189        ALIGNMENT_MASK = 7,
190    };
191    void DoWork();
192    void ReceiveFSTraceEvent();
193    void ReceivePFTraceEvent();
194    void ReceiveBIOTraceEvent();
195    void ReceiveSTRTraceEvent();
196    void ReceiveDlopenTraceEvent();
197    void WriteEventMaps(uint32_t pid);
198    void WriteSymbolInfo(const std::string &fileName);
199    void ReverseStr(char* left, char* right);
200    void DiscardEvent();
201    int EncodeFSTraceEvent(
202        const struct fstrace_cmplt_event_t *cmplt_event,
203        void* tlvItem,
204        const size_t itemLen);
205    int EncodePFTraceEvent(
206        const struct pftrace_cmplt_event_t *cmplt_event,
207        void* tlvItem,
208        const size_t itemLen);
209    int EncodeBIOTraceEvent(
210        const struct biotrace_cmplt_event_t *cmplt_event,
211        void* tlvItem,
212        const size_t itemLen);
213    int EncodeSTRTraceEvent(
214        const struct strtrace_cmplt_event_t *cmplt_event,
215        void* tlvItem,
216        const size_t itemLen);
217    int ConvertFSTraceArgsToArray(__u64 *args, const struct fstrace_start_event_t *start_event)
218    {
219        int (*fn) (__u64*, const struct fstrace_start_event_t *) = g_argsConverterTable[start_event->type];
220        if (fn) {
221            return fn(args, start_event);
222        }
223        HHLOGE(true, "invalid converter for type = %u", start_event->type);
224        return -1;
225    }
226
227    inline __u32 GetFSTraceTLVItemSize(const struct fstrace_cmplt_event_t &cmplt_event)
228    {
229        __u32 size {sizeof(struct FixedFSTraceTLVItem)};
230        size += cmplt_event.nips * sizeof(__u64);
231        return size;
232    }
233
234    inline __u32 GetPFTraceTLVItemSize(const struct pftrace_cmplt_event_t &cmplt_event)
235    {
236        __u32 size {sizeof(struct FixedPFTraceTLVItem)};
237        size += cmplt_event.nips * sizeof(__u64);
238        return size;
239    }
240
241    inline __u32 GetBIOTraceTLVItemSize(const struct biotrace_cmplt_event_t &cmplt_event)
242    {
243        __u32 size {sizeof(struct FixedBIOTraceTLVItem)};
244        size += cmplt_event.nips * sizeof(__u64);
245        return size;
246    }
247
248    inline __u32 GetSTRTraceTLVItemSize(const struct strtrace_cmplt_event_t &cmplt_event)
249    {
250        __u32 size {sizeof(FixedSTRTraceTLVItem)};
251        size += cmplt_event.len;
252        size &= ~ALIGNMENT_MASK;
253        size += alignBytes_;
254        return size;
255    }
256
257    inline void WorkLoop()
258    {
259        while (not stop_) {
260            DoWork();
261        }
262    }
263
264    inline BPFEventReceiver(const std::weak_ptr<HiebpfDataFile> &file) : file_ {file} {}
265
266    inline void NotifyOne()
267    {
268        cond_.notify_one();
269    }
270
271    inline int InitBuffer()
272    {
273        constexpr std::size_t bufSize {1 << 20};
274        constexpr enum RingBuffer::MemAlignShift memAlign {RingBuffer::MemAlignShift::W_ALIGN_SHIFT};
275        buf_ = std::make_unique<RingBuffer>(bufSize, memAlign);
276        if (buf_ == nullptr or (not (*buf_))) {
277            return -1;
278        }
279        return 0;
280    }
281
282    std::vector<std::string> gTracerTable {
283        "maptrace",
284        "symtrace",
285        "fstrace",
286        "pftrace",
287        "biotrace",
288        "strtrace",
289    };
290
291    std::vector<std::string> gFSTraceTypeTable {
292        "",
293        "openat2",
294        "read",
295        "write",
296        "pread64",
297        "pwrite64",
298        "readv",
299        "writev",
300        "preadv",
301        "pwritev",
302        "close",
303    };
304
305    std::vector<std::string> gPFTraceTypeTable {
306        "",
307        "FILE_BACKED_IN",
308        "PAGE_CACHE_HIT",
309        "SWAP_FROM_ZRAM",
310        "SWAP_FROM_DISK",
311        "ZERO_FILL_PAGE",
312        "FAKE_ZERO_PAGE",
313        "COPY_ON_WRITE",
314        "MAX_EVENT_TYPE",
315    };
316
317    std::vector<std::string> gBIOTraceTypeTable {
318        "",
319        "DATA_READ",
320        "DATA_WRITE",
321        "METADATA_READ",
322        "METADATA_WRITE",
323        "PAGE_IN",
324        "PAGE_OUT",
325    };
326
327    const std::size_t alignBytes_ {ALIGNMENT_BYTES};
328    bool stop_ {false};
329    std::mutex  mtx_ {};
330    std::condition_variable cond_ {};
331    std::thread workLoop_ {};
332    std::unique_ptr<RingBuffer> buf_ {nullptr};
333    std::weak_ptr<HiebpfDataFile> file_ {};
334    OHOS::Developtools::Hiebpf::MapsInfo mapsInfo_;
335    OHOS::Developtools::Hiebpf::ElfSymbolInfo elfSymbolInfo_;
336};
337#endif