1 /* 2 * Copyright (c) 2022 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 #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 43 struct 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 60 struct 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 77 struct 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 93 struct 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 106 struct 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 116 struct 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 127 class BPFEventReceiver { 128 public: MakeShared(const std::weak_ptr<HiebpfDataFile> & file)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 ~BPFEventReceiver()141 ~BPFEventReceiver() 142 { 143 if (not stop_) { 144 stop_ = true; 145 } 146 if (workLoop_.joinable()) { 147 workLoop_.join(); 148 } 149 } 150 Put(void * data,const size_t dataSize)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 Start()164 inline int Start() 165 { 166 workLoop_ = std::thread(&BPFEventReceiver::WorkLoop, this); 167 return 0; 168 } 169 Stop()170 inline void Stop() 171 { 172 if (Running()) { 173 stop_ = true; 174 NotifyOne(); 175 } 176 if (workLoop_.joinable()) { 177 workLoop_.join(); 178 } 179 } 180 Running()181 inline bool Running() const 182 { 183 return (not stop_); 184 } 185 186 private: 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); ConvertFSTraceArgsToArray(__u64 * args,const struct fstrace_start_event_t * start_event)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 GetFSTraceTLVItemSize(const struct fstrace_cmplt_event_t & cmplt_event)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 GetPFTraceTLVItemSize(const struct pftrace_cmplt_event_t & cmplt_event)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 GetBIOTraceTLVItemSize(const struct biotrace_cmplt_event_t & cmplt_event)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 GetSTRTraceTLVItemSize(const struct strtrace_cmplt_event_t & cmplt_event)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 WorkLoop()257 inline void WorkLoop() 258 { 259 while (not stop_) { 260 DoWork(); 261 } 262 } 263 BPFEventReceiver(const std::weak_ptr<HiebpfDataFile> & file)264 inline BPFEventReceiver(const std::weak_ptr<HiebpfDataFile> &file) : file_ {file} {} 265 NotifyOne()266 inline void NotifyOne() 267 { 268 cond_.notify_one(); 269 } 270 InitBuffer()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