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 #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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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 = reinterpret_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 = reinterpret_cast<char*>(dest);
242 size_t pos = 0;
243 if (sizeof(FixedSymbolTLVItem) + sym->strTabLen + sym->symTabLen > size) {
244 HHLOGE(true, "invalid symbol info");
245 return;
246 }
247 pos += sizeof(FixedSymbolTLVItem);
248 if (memcpy_s(tmp + pos, size - pos, symbolInfo.strTable_.data(), sym->strTabLen) != EOK) {
249 HHLOGE(true, "memcpy_s failed");
250 return;
251 }
252 pos += sym->strTabLen;
253 if (memcpy_s(tmp + pos, size - pos, symbolInfo.symTable_.data(), sym->symTabLen) != EOK) {
254 HHLOGE(true, "memcpy_s failed");
255 return;
256 }
257 pos += sym->symTabLen;
258 if (memcpy_s(tmp + pos, size - pos, symbolInfo.fileName_.c_str(), symbolInfo.fileName_.size()) != EOK) {
259 HHLOGE(true, "memcpy_s failed");
260 return;
261 }
262 file->Submit(dest);
263 }
264 elfSymbolInfo_.CacheFileName(fileName);
265 }
266
ReverseStr(char * left,char * right)267 void BPFEventReceiver::ReverseStr(char* left, char* right)
268 {
269 while (left < right) {
270 char tmp = 0;
271 tmp = *left;
272 *left = *right;
273 *right = tmp;
274 left++;
275 right--;
276 }
277 }
278
DiscardEvent()279 void BPFEventReceiver::DiscardEvent()
280 {
281 struct strtrace_cmplt_event_t cmplt_event {};
282 buf_->Get(reinterpret_cast<char*>(&cmplt_event), sizeof(cmplt_event));
283 HHLOGE(true, "unkown tracer type = %u, event data will be discarded", cmplt_event.tracer);
284 }
285
EncodeFSTraceEvent(const struct fstrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)286 int BPFEventReceiver::EncodeFSTraceEvent(
287 const struct fstrace_cmplt_event_t *cmplt_event,
288 void* tlvItem,
289 const size_t itemLen)
290 {
291 struct FixedFSTraceTLVItem *item = static_cast<struct FixedFSTraceTLVItem *>(tlvItem);
292 item->tracer_ = FSTRACE;
293 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
294 item->pid_ = cmplt_event->tgid;
295 item->tid_ = cmplt_event->pid;
296 CHECK_TRUE(strncpy_s(item->tracerName_, MAX_TRACER_NAME_LEN,
297 gTracerTable[FSTRACE].c_str(), gTracerTable[FSTRACE].size()) == EOK,
298 -1, "failed to copy fstrace tracer name");
299 item->stime_ = cmplt_event->start_event.stime;
300 item->ctime_ = cmplt_event->ctime;
301 item->retval_ = cmplt_event->retval;
302 item->nips_ = static_cast<uint16_t>(cmplt_event->nips);
303 item->type_ = static_cast<uint16_t>(cmplt_event->start_event.type);
304 CHECK_TRUE(strncpy_s(item->typeName_, MAX_TYPE_NAME_LEN,
305 gFSTraceTypeTable[item->type_].c_str(),
306 gFSTraceTypeTable[item->type_].size()) == EOK,
307 -1, "failed to copy fstrace type name");
308 CHECK_TRUE(ConvertFSTraceArgsToArray(item->args_, &cmplt_event->start_event) == 0, -1,
309 "failed to convert fstrace event args");
310 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->comm, MAX_COMM_LEN);
311 if (item->nips_ != 0) {
312 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
313 sizeof(struct FixedFSTraceTLVItem))), item->nips_ * sizeof(__u64),
314 cmplt_event->ips, item->nips_ * sizeof(__u64));
315 if (ret != EOK) {
316 return -1;
317 }
318 }
319 return 0;
320 }
321
EncodePFTraceEvent(const struct pftrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)322 int BPFEventReceiver::EncodePFTraceEvent(
323 const struct pftrace_cmplt_event_t *cmplt_event,
324 void* tlvItem,
325 const size_t itemLen)
326 {
327 struct FixedPFTraceTLVItem *item = static_cast<struct FixedPFTraceTLVItem *>(tlvItem);
328 item->tracer_ = PFTRACE;
329 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
330 item->pid_ = cmplt_event->tgid;
331 item->tid_ = cmplt_event->pid;
332 CHECK_TRUE(strncpy_s(item->tracerName_, MAX_TRACER_NAME_LEN,
333 gTracerTable[PFTRACE].c_str(), gTracerTable[PFTRACE].size()) == EOK,
334 -1, "failed to copy pftrace tracer name");
335 item->stime_ = cmplt_event->start_event.stime;
336 item->ctime_ = cmplt_event->ctime;
337 item->addr_ = cmplt_event->start_event.addr;
338 item->size_ = cmplt_event->size;
339 item->nips_ = static_cast<uint16_t>(cmplt_event->nips);
340 item->type_ = static_cast<uint16_t>(cmplt_event->start_event.type);
341 CHECK_TRUE(strncpy_s(item->typeName_,
342 MAX_TYPE_NAME_LEN,
343 gPFTraceTypeTable[item->type_].c_str(),
344 gPFTraceTypeTable[item->type_].size()) == EOK,
345 -1, "failed to copy pftrace type name");
346 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->comm, MAX_COMM_LEN);
347 if (item->nips_ != 0) {
348 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
349 sizeof(struct FixedPFTraceTLVItem))), item->nips_ * sizeof(__u64),
350 cmplt_event->ips, item->nips_ * sizeof(__u64));
351 if (ret != EOK) {
352 return -1;
353 }
354 }
355 return 0;
356 }
357
EncodeBIOTraceEvent(const struct biotrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)358 int BPFEventReceiver::EncodeBIOTraceEvent(
359 const struct biotrace_cmplt_event_t *cmplt_event,
360 void* tlvItem,
361 const size_t itemLen)
362 {
363 struct FixedBIOTraceTLVItem *item = static_cast<struct FixedBIOTraceTLVItem *>(tlvItem);
364 item->tracer_ = BIOTRACE;
365 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
366 item->pid_ = cmplt_event->start_event.tgid;
367 item->tid_ = cmplt_event->start_event.pid;
368 (void)memcpy_s(item->comm_, MAX_COMM_LEN, cmplt_event->start_event.comm, MAX_COMM_LEN);
369 item->stime_ = cmplt_event->start_event.stime;
370 item->ctime_ = cmplt_event->ctime;
371 item->prio_ = cmplt_event->prio;
372 item->size_ = cmplt_event->start_event.size;
373 item->blkcnt_ = cmplt_event->blkcnt;
374 item->nips_ = cmplt_event->nips;
375 item->type_ = cmplt_event->start_event.type;
376 CHECK_TRUE(strncpy_s(item->typeName_,
377 MAX_TYPE_NAME_LEN,
378 gBIOTraceTypeTable[item->type_].c_str(),
379 gBIOTraceTypeTable[item->type_].size()) == EOK,
380 -1, "failed to copy BIOstrace type name");
381 if (item->nips_ != 0) {
382 int ret = memcpy_s(reinterpret_cast<__u64*>((reinterpret_cast<char *>(item) +
383 sizeof(struct FixedBIOTraceTLVItem))), item->nips_ * sizeof(__u64),
384 cmplt_event->ips, item->nips_ * sizeof(__u64));
385 if (ret != EOK) {
386 return -1;
387 }
388 }
389 return 0;
390 }
391
EncodeSTRTraceEvent(const struct strtrace_cmplt_event_t * cmplt_event,void * tlvItem,const size_t itemLen)392 int BPFEventReceiver::EncodeSTRTraceEvent(
393 const struct strtrace_cmplt_event_t *cmplt_event,
394 void* tlvItem,
395 const size_t itemLen)
396 {
397 struct FixedSTRTraceTLVItem *item = static_cast<struct FixedSTRTraceTLVItem *>(tlvItem);
398 item->tracer_ = STRTRACE;
399 item->itemLen_ = itemLen - sizeof(uint32_t) * DOUBLE;
400 item->pid_ = cmplt_event->tgid;
401 item->tid_ = cmplt_event->pid;
402 item->stime_ = cmplt_event->start_event.stime;
403 item->srcTracer_ = cmplt_event->start_event.stracer;
404 item->srcType_ = cmplt_event->start_event.type;
405 item->strLen_ = cmplt_event->len;
406 if (item->strLen_ && item->strLen_ <= MAX_FILENAME_LEN) {
407 char *filename = reinterpret_cast<char*>(tlvItem);
408 filename += sizeof(struct FixedSTRTraceTLVItem);
409 CHECK_TRUE(strncpy_s(filename, MAX_FILENAME_LEN, cmplt_event->filename, item->strLen_) == EOK, -1,
410 "failed to copy cmplt_event file name");
411 if (item->srcTracer_ == BIOTRACE || (item->srcTracer_ == FSTRACE && item->srcType_ == SYS_CLOSE)) {
412 ReverseStr(filename, filename + item->strLen_ - 2); // 2: last 2 chars
413 char* start = filename;
414 while (*start != '\0') {
415 char* end = start;
416 while (*end != '/' && *end != '\0') {
417 end++;
418 }
419 ReverseStr(start, end - 1);
420 if (*end != '\0') {
421 start = end + 1;
422 } else {
423 start = end;
424 }
425 }
426 }
427 }
428 return 0;
429 }
430