• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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