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