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 #include "bpf_event_receiver.h"
17
18 #include <chrono>
19
20 using namespace std::chrono_literals;
21
22 static constexpr int DOUBLE = 2;
23
DoWork()24 void BPFEventReceiver::DoWork()
25 {
26 for (__u32 cnt = MAX_BUSY_LOOPS; cnt != 0; --cnt) {
27 if (buf_->GetDataSize()) {
28 break;
29 }
30 }
31 if (buf_->GetDataSize() == 0) {
32 std::unique_lock lk {mtx_};
33 cond_.wait(lk, [this]()->bool {return this->stop_ || this->buf_->GetDataSize();});
34 if (stop_) {
35 return;
36 }
37 }
38
39 while (buf_->GetDataSize() != 0) {
40 __u32 tracer {0};
41 if (buf_->Peek(&tracer) == 0) {
42 switch (tracer) {
43 case FSTRACE: {
44 ReceiveFSTraceEvent();
45 continue;
46 }
47 case PFTRACE: {
48 ReceivePFTraceEvent();
49 continue;
50 }
51 case BIOTRACE: {
52 ReceiveBIOTraceEvent();
53 continue;
54 }
55 case STRTRACE: {
56 ReceiveSTRTraceEvent();
57 continue;
58 }
59 case DLOPEN_TRACE: {
60 ReceiveDlopenTraceEvent();
61 continue;
62 }
63 default: {
64 DiscardEvent();
65 continue;
66 }
67 }
68 } else {
69 HHLOGE(true, "failed to peek the tracer type");
70 return;
71 }
72 }
73 }
74
ReceiveFSTraceEvent()75 void BPFEventReceiver::ReceiveFSTraceEvent()
76 {
77 struct fstrace_cmplt_event_t cmplt_event {};
78 size_t dataSize = buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
79 if (dataSize != sizeof(cmplt_event)) {
80 HHLOGE(true, "imcomplete fstrace event data receiveed");
81 return;
82 }
83 WriteEventMaps(cmplt_event.tgid);
84 auto file = file_.lock();
85 if (file == nullptr) {
86 HHLOGE(true, "failed to receive fstrace event: hiebpf data file closed");
87 return;
88 }
89 __u32 tlvItemSize = GetFSTraceTLVItemSize(cmplt_event);
90 void *dest = file->Reserve(tlvItemSize);
91 if (dest == nullptr) {
92 HHLOGE(true, "failed to reserve space for fstrace event tlv item");
93 return;
94 }
95 if (EncodeFSTraceEvent(&cmplt_event, dest, tlvItemSize) != 0) {
96 HHLOGE(true, "failed to encode fstrace event");
97 file->Discard(dest);
98 return;
99 }
100 file->Submit(dest);
101 }
102
ReceivePFTraceEvent()103 void BPFEventReceiver::ReceivePFTraceEvent()
104 {
105 struct pftrace_cmplt_event_t cmplt_event {};
106 buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
107 WriteEventMaps(cmplt_event.tgid);
108 auto file = file_.lock();
109 if (file == nullptr) {
110 HHLOGE(true, "failed to receive pftrace event: hiebpf data file closed");
111 return;
112 }
113 __u32 tlvItemSize = GetPFTraceTLVItemSize(cmplt_event);
114 void *dest = file->Reserve(tlvItemSize);
115 if (dest == nullptr) {
116 HHLOGE(true, "failed to reserve space for pftrace event tlv item");
117 return;
118 }
119 if (EncodePFTraceEvent(&cmplt_event, dest, tlvItemSize) != 0) {
120 HHLOGE(true, "failed to encode pftrace event");
121 file->Discard(dest);
122 return;
123 }
124 file->Submit(dest);
125 }
126
ReceiveBIOTraceEvent()127 void BPFEventReceiver::ReceiveBIOTraceEvent()
128 {
129 struct biotrace_cmplt_event_t cmplt_event {};
130 buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
131 auto file = file_.lock();
132 if (file == nullptr) {
133 HHLOGE(true, "failed to receive biotrace event: hiebpf data file closed");
134 return;
135 }
136 __u32 tlvItemSize = GetBIOTraceTLVItemSize(cmplt_event);
137 void *dest = file->Reserve(tlvItemSize);
138 if (dest == nullptr) {
139 HHLOGE(true, "failed to reserve space for biotrace event tlv item");
140 return;
141 }
142 if (EncodeBIOTraceEvent(&cmplt_event, dest, tlvItemSize) != 0) {
143 HHLOGE(true, "failed to encode biotrace event");
144 file->Discard(dest);
145 return;
146 }
147 file->Submit(dest);
148 }
149
ReceiveSTRTraceEvent()150 void BPFEventReceiver::ReceiveSTRTraceEvent()
151 {
152 struct strtrace_cmplt_event_t cmplt_event {};
153 buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
154 if (cmplt_event.len == 0) {
155 return;
156 }
157 auto file = file_.lock();
158 if (file == nullptr) {
159 HHLOGE(true, "failed to receive strtrace event: hiebpf data file closed");
160 return;
161 }
162 __u32 tlvItemSize = GetSTRTraceTLVItemSize(cmplt_event);
163 void *dest = file->Reserve(tlvItemSize);
164 if (dest == nullptr) {
165 HHLOGE(true, "failed to reserve space for strtrace event tlv item");
166 return;
167 }
168 if (EncodeSTRTraceEvent(&cmplt_event, dest, tlvItemSize) != 0) {
169 HHLOGE(true, "failed to encode strtrace event");
170 file->Discard(dest);
171 return;
172 }
173 file->Submit(dest);
174 }
175
ReceiveDlopenTraceEvent()176 void BPFEventReceiver::ReceiveDlopenTraceEvent()
177 {
178 struct dlopen_trace_start_event_t cmplt_event {};
179 buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
180 mapsInfo_.RemovePid(cmplt_event.tgid);
181 }
182
WriteEventMaps(uint32_t pid)183 void BPFEventReceiver::WriteEventMaps(uint32_t pid)
184 {
185 if (mapsInfo_.IsCached(pid)) {
186 return;
187 }
188 using OHOS::Developtools::Hiebpf::MapsInfo;
189 std::vector<MapsInfo::MapsItem> mapsItems;
190 mapsInfo_.GetMaps(pid, mapsItems);
191 auto file = file_.lock();
192 for (auto &item : mapsItems) {
193 size_t size = sizeof(FixedMapTLVItem) + item.fileName_.size() + 1;
194 void *dest = file->Reserve(size);
195 if (dest == nullptr) {
196 HHLOGE(true, "failed to reserve space for strtrace event tlv item");
197 continue;
198 }
199 FixedMapTLVItem *mapItem = static_cast<FixedMapTLVItem *>(dest);
200 mapItem->type = MAPSTRACE;
201 mapItem->len = size - sizeof(uint32_t) * DOUBLE;
202 mapItem->start = item.start_;
203 mapItem->end = item.end_;
204 mapItem->offset = item.offset_;
205 mapItem->pid = item.pid_;
206 mapItem->fileNameLen = item.fileName_.size() + 1;
207 char* tmp = static_cast<char*>(dest);
208 char* fileName = tmp + sizeof(FixedMapTLVItem);
209 (void)strncpy_s(fileName, mapItem->fileNameLen, item.fileName_.c_str(), item.fileName_.size());
210 file->Submit(dest);
211 WriteSymbolInfo(item.fileName_);
212 }
213 mapsInfo_.CachePid(pid);
214 }
215
WriteSymbolInfo(const std::string & fileName)216 void BPFEventReceiver::WriteSymbolInfo(const std::string &fileName)
217 {
218 if (elfSymbolInfo_.IsCached(fileName)) {
219 return;
220 }
221 using OHOS::Developtools::Hiebpf::ElfSymbolInfo;
222 ElfSymbolInfo::ElfSymbolTable symbolInfo;
223 if (elfSymbolInfo_.GetSymbolTable(fileName, symbolInfo)) {
224 auto file = file_.lock();
225 size_t size = sizeof(FixedSymbolTLVItem) + symbolInfo.strTable_.size() + symbolInfo.symTable_.size()
226 + symbolInfo.fileName_.size() + 1;
227 void *dest = file->Reserve(size);
228 if (dest == nullptr) {
229 HHLOGE(true, "file reserve failed");
230 return;
231 }
232 FixedSymbolTLVItem *sym = static_cast<FixedSymbolTLVItem *>(dest);
233 sym->type = SYMBOLTRACE;
234 sym->len = size - sizeof(uint32_t) * DOUBLE;
235 sym->textVaddr = symbolInfo.textVaddr_;
236 sym->textOffset = symbolInfo.textOffset_;
237 sym->strTabLen = symbolInfo.strTable_.size();
238 sym->symTabLen = symbolInfo.symTable_.size();
239 sym->fileNameLen = symbolInfo.fileName_.size() + 1;
240 sym->symEntLen = symbolInfo.symEntSize_;
241 char* tmp = static_cast<char*>(dest);
242 size_t pos = 0;
243 pos += sizeof(FixedSymbolTLVItem);
244 if (memcpy_s(tmp + pos, size - pos, symbolInfo.strTable_.data(), sym->strTabLen) != EOK) {
245 HHLOGE(true, "memcpy_s failed");
246 return;
247 }
248 pos += sym->strTabLen;
249 if (memcpy_s(tmp + pos, size - pos, symbolInfo.symTable_.data(), sym->symTabLen) != EOK) {
250 HHLOGE(true, "memcpy_s failed");
251 return;
252 }
253 pos += sym->symTabLen;
254 if (memcpy_s(tmp + pos, size - pos, symbolInfo.fileName_.c_str(), symbolInfo.fileName_.size()) != EOK) {
255 HHLOGE(true, "memcpy_s failed");
256 return;
257 }
258 file->Submit(dest);
259 }
260 elfSymbolInfo_.CacheFileName(fileName);
261 }
262
ReverseStr(char * left,char * right)263 void BPFEventReceiver::ReverseStr(char* left, char* right)
264 {
265 while (left < right) {
266 char tmp = 0;
267 tmp = *left;
268 *left = *right;
269 *right = tmp;
270 left++;
271 right--;
272 }
273 }
274
DiscardEvent()275 void BPFEventReceiver::DiscardEvent()
276 {
277 struct strtrace_cmplt_event_t cmplt_event {};
278 buf_->Get((char*)&cmplt_event, sizeof(cmplt_event));
279 HHLOGE(true, "unkown tracer type = %u, event data will be discarded", cmplt_event.tracer);
280 }
281
EncodeFSTraceEvent(const struct fstrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)282 int BPFEventReceiver::EncodeFSTraceEvent(
283 const struct fstrace_cmplt_event_t *cmplt_event,
284 void* tlvItem,
285 const size_t itemLen)
286 {
287 struct FixedFSTraceTLVItem *item = static_cast<struct FixedFSTraceTLVItem *>(tlvItem);
288 item->tracer_ = FSTRACE;
289 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
290 item->pid_ = cmplt_event->tgid;
291 item->tid_ = cmplt_event->pid;
292 CHECK_TRUE(strncpy_s(item->tracerName_, MAX_TRACER_NAME_LEN,
293 gTracerTable[FSTRACE].c_str(), gTracerTable[FSTRACE].size()) == EOK,
294 -1, "failed to copy fstrace tracer name");
295 item->stime_ = cmplt_event->start_event.stime;
296 item->ctime_ = cmplt_event->ctime;
297 item->retval_ = cmplt_event->retval;
298 item->nips_ = static_cast<uint16_t>(cmplt_event->nips);
299 item->type_ = static_cast<uint16_t>(cmplt_event->start_event.type);
300 CHECK_TRUE(strncpy_s(item->typeName_, MAX_TYPE_NAME_LEN,
301 gFSTraceTypeTable[item->type_].c_str(),
302 gFSTraceTypeTable[item->type_].size() == EOK),
303 -1, "failed to copy fstrace type name");
304 CHECK_TRUE(ConvertFSTraceArgsToArray(item->args_, &cmplt_event->start_event) == 0, -1,
305 "failed to convert fstrace event args");
306 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->comm, MAX_COMM_LEN);
307 if (item->nips_ != 0) {
308 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
309 sizeof(struct FixedFSTraceTLVItem))), item->nips_ * sizeof(__u64),
310 cmplt_event->ips, item->nips_ * sizeof(__u64));
311 if (ret != EOK) {
312 return -1;
313 }
314 }
315 return 0;
316 }
317
EncodePFTraceEvent(const struct pftrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)318 int BPFEventReceiver::EncodePFTraceEvent(
319 const struct pftrace_cmplt_event_t *cmplt_event,
320 void* tlvItem,
321 const size_t itemLen)
322 {
323 struct FixedPFTraceTLVItem *item = static_cast<struct FixedPFTraceTLVItem *>(tlvItem);
324 item->tracer_ = PFTRACE;
325 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
326 item->pid_ = cmplt_event->tgid;
327 item->tid_ = cmplt_event->pid;
328 CHECK_TRUE(strncpy_s(item->tracerName_, MAX_TRACER_NAME_LEN,
329 gTracerTable[PFTRACE].c_str(), gTracerTable[PFTRACE].size() == EOK),
330 -1, "failed to copy pftrace tracer name");
331 item->stime_ = cmplt_event->start_event.stime;
332 item->ctime_ = cmplt_event->ctime;
333 item->addr_ = cmplt_event->start_event.addr;
334 item->size_ = cmplt_event->size;
335 item->nips_ = static_cast<uint16_t>(cmplt_event->nips);
336 item->type_ = static_cast<uint16_t>(cmplt_event->start_event.type);
337 CHECK_TRUE(strncpy_s(item->typeName_,
338 MAX_TYPE_NAME_LEN,
339 gPFTraceTypeTable[item->type_].c_str(),
340 gPFTraceTypeTable[item->type_].size()) == EOK,
341 -1, "failed to copy pftrace type name");
342 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->comm, MAX_COMM_LEN);
343 if (item->nips_ != 0) {
344 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
345 sizeof(struct FixedPFTraceTLVItem))), item->nips_ * sizeof(__u64),
346 cmplt_event->ips, item->nips_ * sizeof(__u64));
347 if (ret != EOK) {
348 return -1;
349 }
350 }
351 return 0;
352 }
353
EncodeBIOTraceEvent(const struct biotrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)354 int BPFEventReceiver::EncodeBIOTraceEvent(
355 const struct biotrace_cmplt_event_t *cmplt_event,
356 void* tlvItem,
357 const size_t itemLen)
358 {
359 struct FixedBIOTraceTLVItem *item = static_cast<struct FixedBIOTraceTLVItem *>(tlvItem);
360 item->tracer_ = BIOTRACE;
361 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
362 item->pid_ = cmplt_event->start_event.tgid;
363 item->tid_ = cmplt_event->start_event.pid;
364 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->start_event.comm, MAX_COMM_LEN);
365 item->stime_ = cmplt_event->start_event.stime;
366 item->ctime_ = cmplt_event->ctime;
367 item->prio_ = cmplt_event->prio;
368 item->size_ = cmplt_event->start_event.size;
369 item->blkcnt_ = cmplt_event->blkcnt;
370 item->nips_ = cmplt_event->nips;
371 item->type_ = cmplt_event->start_event.type;
372 CHECK_TRUE(strncpy_s(item->typeName_,
373 MAX_TYPE_NAME_LEN,
374 gBIOTraceTypeTable[item->type_].c_str(),
375 gBIOTraceTypeTable[item->type_].size()) == EOK,
376 -1, "failed to copy BIOstrace type name");
377 if (item->nips_ != 0) {
378 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
379 sizeof(struct FixedBIOTraceTLVItem))), item->nips_ * sizeof(__u64),
380 cmplt_event->ips, item->nips_ * sizeof(__u64));
381 if (ret != EOK) {
382 return -1;
383 }
384 }
385 return 0;
386 }
387
EncodeSTRTraceEvent(const struct strtrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)388 int BPFEventReceiver::EncodeSTRTraceEvent(
389 const struct strtrace_cmplt_event_t *cmplt_event,
390 void* tlvItem,
391 const size_t itemLen)
392 {
393 struct FixedSTRTraceTLVItem *item = static_cast<struct FixedSTRTraceTLVItem *>(tlvItem);
394 item->tracer_ = STRTRACE;
395 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
396 item->pid_ = cmplt_event->tgid;
397 item->tid_ = cmplt_event->pid;
398 item->stime_ = cmplt_event->start_event.stime;
399 item->srcTracer_ = cmplt_event->start_event.stracer;
400 item->srcType_ = cmplt_event->start_event.type;
401 item->strLen_ = cmplt_event->len;
402 if (item->strLen_ and item->strLen_ <= MAX_FILENAME_LEN) {
403 char *filename = static_cast<char*>(tlvItem);
404 filename += sizeof(struct FixedSTRTraceTLVItem);
405 CHECK_TRUE(strncpy_s(filename, MAX_FILENAME_LEN, cmplt_event->filename, item->strLen_) == EOK, -1,
406 "failed to copy cmplt_event file name");
407 if (item->srcTracer_ == BIOTRACE || (item->srcTracer_ == FSTRACE && item->srcType_ == SYS_CLOSE)) {
408 ReverseStr(filename, filename + item->strLen_ - 2); // 2: last 2 chars
409 char* start = filename;
410 while (*start != '\0') {
411 char* end = start;
412 while (*end != '/' && *end != '\0') {
413 end++;
414 }
415 ReverseStr(start, end - 1);
416 if (*end != '\0') {
417 start = end + 1;
418 } else {
419 start = end;
420 }
421 }
422 }
423 }
424 return 0;
425 }
426