• 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  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 #include "ebpf_converter.h"
16 
17 #include <algorithm>
18 #include <cstring>
19 #include <cxxabi.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <iostream>
23 #include <unistd.h>
24 #include <memory>
25 #include <securec.h>
26 
27 #define CHK(expr) \
28     do { \
29         if (!(expr)) { \
30             std::cout << __FUNCTION__ << ": "; \
31             std::cout <<  __LINE__ << ", "; \
32             std::cout << "read data failed" << std::endl; \
33             return; \
34         } \
35     } while (0)
36 
37 namespace OHOS {
38 namespace EBPF_TOOLS {
39 namespace {
40 constexpr uint8_t HEADER_MAGIC = 8;
41 constexpr uint8_t ARGS_NUM = 4;
42 constexpr uint8_t SYM_ENT_LEN_64 = 24;
43 constexpr uint8_t SYM_ENT_LEN_32 = 16;
44 constexpr uint8_t STT_FUNC = 2;
45 constexpr uint8_t EVENT_FS_FIXED_SIZE = 64;
46 constexpr uint8_t EVENT_MAPS_FIXED_SIZE = 36;
47 constexpr uint8_t EVENT_SYM_FIXED_SIZE = 36;
48 constexpr uint8_t EVENT_MEM_FIXED_SIZE = 88;
49 constexpr uint8_t EVENT_STR_FIXED_SIZE = 40;
50 constexpr uint8_t EVENT_BIO_FIXED_SIZE = 88;
51 } // namespace
EbpfConverter(const std::string & inputPath,const std::string & outPath)52 EbpfConverter::EbpfConverter(const std::string& inputPath, const std::string& outPath)
53     : inputPath_(inputPath), outputPath_(outPath) {}
54 
StartParsing()55 void EbpfConverter::StartParsing()
56 {
57     if (access(inputPath_.c_str(), R_OK) != 0) {
58         std::cout << "the input file path is invalid" << std::endl;
59         return;
60     }
61     fd_ = open(inputPath_.c_str(), O_RDONLY);
62     if (fd_ == -1) {
63         std::cout << "open " << inputPath_ << " failed" << std::endl;
64         return;
65     }
66     char magic[HEADER_MAGIC + 1];
67     (void)memset_s(magic, sizeof(magic), 0, sizeof(magic));
68     CHK(Read(reinterpret_cast<void*>(&magic), sizeof(magic) - 1));
69     outData_ << "magic: " << magic << '\n';
70     HeaderDataItem header = {};
71     CHK(Read(reinterpret_cast<void*>(&header), sizeof(header)));
72     outData_  << "headSize: " << header.headSize << '\n' << "version: " << header.version << '\n'
73         << "clock: " << header.clock << '\n' << "cmdLineLen: " << header.cmdLineLen;
74 
75     char cmdline[header.cmdLineLen + 1];
76     if (header.cmdLineLen > 0) {
77         CHK(Read(reinterpret_cast<void*>(cmdline), sizeof(cmdline) - 1));
78         outData_ << "\ncmdline: " << cmdline << '\n';
79     }
80     fileSize_ = lseek(fd_, header.headSize, SEEK_SET);
81 
82     FILE *file = fopen(outputPath_.c_str(), "w");
83     if (file == nullptr) {
84         std::cout << "create " << outputPath_ << " failed" << std::endl;
85         return;
86     }
87 
88     while (true) {
89         uint32_t type = 0;
90         if (read(fd_, reinterpret_cast<void*>(&type), sizeof(type)) <= 0) {
91             break;
92         }
93         switch (type) {
94             case MAPSTRACE: {
95                 EventMapsParsing();
96                 break;
97             }
98             case SYMBOLTRACE: {
99                 SymbolInfoParsing();
100                 break;
101             }
102             case FSTRACE: {
103                 EventFsParsing();
104                 break;
105             }
106             case PFTRACE: {
107                 EventMemParsing();
108                 break;
109             }
110             case BIOTRACE: {
111                 EventBIOParsing();
112                 break;
113             }
114             case STRTRACE: {
115                 EventStrParsing();
116                 break;
117             }
118             default: {
119                 std::cout << "Invalid type: " << type << std::endl;
120                 close(fd_);
121                 fd_ = -1;
122                 fileSize_ = 0;
123                 fclose(file);
124                 return;
125             }
126         }
127     }
128     close(fd_);
129     fd_ = -1;
130     fileSize_ = 0;
131     std::cout << "Data read successfully, output..." << std::endl;
132     size_t len = outData_.str().size();
133     if (fwrite(outData_.str().c_str(), 1, len, file) != len) {
134         std::cout << "write data failed" << std::endl;
135         fclose(file);
136         return;
137     }
138     fclose(file);
139     std::cout << "Data parsing success..." << std::endl;
140 }
141 
Read(void * buffer,size_t size)142 bool EbpfConverter::Read(void* buffer, size_t size)
143 {
144     ssize_t ret = read(fd_, buffer, size);
145     if (ret <= 0) {
146         close(fd_);
147         fd_ = -1;
148         fileSize_ = 0;
149         return false;
150     }
151     return true;
152 }
153 
EventFsParsing()154 void EbpfConverter::EventFsParsing()
155 {
156     lseek(fd_, fileSize_, SEEK_SET);
157     EventFs efs = {};
158     CHK(Read(reinterpret_cast<void*>(&efs), EVENT_FS_FIXED_SIZE));
159     uint64_t args[ARGS_NUM] = { 0 };
160     CHK(Read(reinterpret_cast<void*>(args), sizeof(args)));
161     efs.args = std::vector<uint64_t>(args, args + ARGS_NUM);
162     CHK(Read(reinterpret_cast<void*>(&efs.comm), sizeof(efs.comm)));
163     uint64_t userIPs[efs.nrUserIPs];
164     if (efs.nrUserIPs > 0) {
165         CHK(Read(reinterpret_cast<void*>(userIPs), sizeof(userIPs)));
166         efs.userIPs = std::vector<uint64_t>(userIPs, userIPs + efs.nrUserIPs);
167     }
168     fileSize_ = lseek(fd_, 0, SEEK_CUR);
169 
170     outData_ << "\nEventFs:\n"
171         << "  type: " << efs.tag << '\n'
172         << "  len: " << efs.len << '\n'
173         << "  pid: " << efs.pid << '\n'
174         << "  tid: " << efs.tid << '\n'
175         << "  tracerName: " << efs.tracerName << '\n'
176         << "  start: " << efs.start << '\n'
177         << "  end: " << efs.end << '\n'
178         << "  typeName: " << efs.typeName << '\n'
179         << "  ret: " << efs.ret << '\n'
180         << "  nrUserIPs: " << efs.nrUserIPs << '\n'
181         << "  type: " << efs.type << '\n'
182         << "  args: ";
183     for (const auto &arg : efs.args) {
184         outData_ << arg << ", ";
185     }
186 
187     outData_ << "\n  userIPs:\n";
188     for (const auto &ip : efs.userIPs) {
189         if (ip == 0) {
190             continue;
191         }
192         outData_ << "    0x" << std::hex << ip << std::dec << ":";
193         auto itm = GetSymbolInfo(efs.pid, ip);
194         outData_ << "\n      vAddr_: 0x" << std::hex << vAddr_[ip] << std::dec << '\n';
195         for (const auto &sym : itm.second) {
196             outData_ << "      symbol: " << sym << '\n';
197         }
198         outData_ << "      fileName: " << itm.first << '\n';
199     }
200     outData_ << "  comm: " << std::string(efs.comm) << '\n';
201 }
202 
EventMapsParsing()203 void EbpfConverter::EventMapsParsing()
204 {
205     lseek(fd_, fileSize_, SEEK_SET);
206     EventMaps maps = {};
207     CHK(Read(reinterpret_cast<void*>(&maps), EVENT_MAPS_FIXED_SIZE));
208     char fileName[maps.fileNameLen + 1];
209     (void)memset_s(fileName, sizeof(fileName), 0, sizeof(fileName));
210     if (maps.fileNameLen > 0) {
211         CHK(Read(reinterpret_cast<void*>(fileName), sizeof(fileName) - 1));
212         maps.fileName = fileName;
213     }
214     auto iter = maps_.find(maps.pid);
215     if (iter == maps_.end()) {
216         maps_[maps.pid] = std::vector<EventMaps>({ maps });
217     } else {
218         iter->second.push_back(maps);
219     }
220     fileSize_ = lseek(fd_, 0, SEEK_CUR);
221 
222     // put output
223     outData_ << "\nEventMaps:\n"
224         << "  type: " << maps.type << '\n'
225         << "  len: " << maps.len << '\n'
226         << "  start: 0x" << std::hex << maps.start << std::dec << '\n'
227         << "  end: 0x" << std::hex << maps.end << std::dec << '\n'
228         << "  offset: 0x" << std::hex << maps.offset << std::dec << '\n'
229         << "  pid: " << maps.pid << '\n'
230         << "  fileNameLen: " << maps.fileNameLen << '\n'
231         << "  fileName: " << maps.fileName << '\n';
232 }
233 
SymbolInfoParsing()234 void EbpfConverter::SymbolInfoParsing()
235 {
236     lseek(fd_, fileSize_, SEEK_SET);
237     uint64_t strAddr = 0;
238     uint64_t symAddr = 0;
239     SymbolInfo info = {};
240     CHK(Read(reinterpret_cast<void*>(&info), EVENT_SYM_FIXED_SIZE));
241 
242     info.strTab = new char[info.strTabLen + 1];
243     if (memset_s(info.strTab, info.strTabLen + 1, 0, info.strTabLen + 1) != EOK) {
244         std::cout << "memset string table failed" << std::endl;
245         return;
246     }
247     if (info.strTabLen > 0) {
248         auto ret = lseek(fd_, 0, SEEK_CUR);
249         if (ret >= 0) {
250             strAddr = (uint64_t)ret;
251         }
252         CHK(Read(reinterpret_cast<void*>(info.strTab), info.strTabLen));
253     }
254     info.symTab = new char[info.symTabLen + 1];
255     if (memset_s(info.symTab, info.symTabLen + 1, 0, info.symTabLen + 1) != EOK) {
256         std::cout << "memset symbol table failed" << std::endl;
257         return;
258     }
259     if (info.symTabLen > 0) {
260         auto ret = lseek(fd_, 0, SEEK_CUR);
261         if (ret >= 0) {
262             symAddr = (uint64_t)ret;
263         }
264         CHK(Read(reinterpret_cast<void*>(info.symTab), info.symTabLen));
265     }
266     char fileName[info.fileNameSize + 1];
267     (void)memset_s(fileName, sizeof(fileName), 0, sizeof(fileName));
268     if (info.fileNameSize > 0) {
269         CHK(Read(reinterpret_cast<void*>(&fileName), sizeof(fileName) - 1));
270         info.fileName = fileName;
271     }
272     record_[std::string(fileName)] = Record(fileName, symAddr, strAddr);
273     symbolInfo_[fileName] = info;
274     fileSize_ = lseek(fd_, 0, SEEK_CUR);
275 
276     // put output
277     outData_ << "\nSymbolInfo:\n"
278             << "  tag: " << info.type << '\n'
279             << "  len: " << info.len << '\n'
280             << "  textVaddr: 0x" << std::hex << info.textVaddr << std::dec << '\n'
281             << "  textOffset: 0x" << std::hex << info.textOffset << std::dec << '\n'
282             << "  strTabLen: 0x" << std::hex << info.strTabLen << std::dec <<'\n'
283             << "  symTabLen: 0x" << std::hex << info.symTabLen << std::dec << '\n'
284             << "  fileNameSize: " << info.fileNameSize << '\n'
285             << "  fileName: " << info.fileName << '\n'
286             << "  strTabAddr: 0x" << std::hex << record_[info.fileName].strTabAddr << std::dec << '\n'
287             << "  symTabAddr: 0x" << std::hex << record_[info.fileName].symTabAddr << std::dec << '\n';
288 }
289 
EventMemParsing()290 void EbpfConverter::EventMemParsing()
291 {
292     lseek(fd_, fileSize_, SEEK_SET);
293     EventMem mem = {};
294     CHK(Read(reinterpret_cast<void*>(&mem), EVENT_MEM_FIXED_SIZE));
295     uint64_t userIPs[mem.nips];
296     if (mem.nips > 0) {
297         CHK(Read(reinterpret_cast<void*>(&userIPs), sizeof(userIPs)));
298         mem.userIPs = std::vector<uint64_t>(userIPs, userIPs + mem.nips);
299     }
300     fileSize_ = lseek(fd_, 0, SEEK_CUR);
301 
302     outData_ << "\nEventMem:\n"
303         << "  tag: " << mem.tag << '\n'
304         << "  len: " << mem.len << '\n'
305         << "  pid: " << mem.pid << '\n'
306         << "  tid: " << mem.tid << '\n'
307         << "  tagName: " << mem.tagName << '\n'
308         << "  start: " << mem.start << '\n'
309         << "  end: " << mem.end << '\n'
310         << "  typeName: " << mem.typeName << '\n'
311         << "  addr: " << mem.addr << '\n'
312         << "  size: " << mem.size << '\n'
313         << "  nips: " << mem.nips << '\n'
314         << "  type: " << mem.type << '\n'
315         << "  comm: " << mem.comm << '\n'
316         << "  userIPs:\n";
317     for (const auto &ip : mem.userIPs) {
318         if (ip == 0) {
319             continue;
320         }
321         outData_ << "    0x" << std::hex << ip << std::dec << ":";
322         auto itm = GetSymbolInfo(mem.pid, ip);
323         outData_ << "\n      vAddr_: 0x" << std::hex << vAddr_[ip] << std::dec << '\n';
324         for (const auto &sym : itm.second) {
325             outData_ << "      symbol: " << sym << '\n';
326         }
327         outData_ << "      fileName: " << itm.first << '\n';
328     }
329 }
330 
EventStrParsing()331 void EbpfConverter::EventStrParsing()
332 {
333     lseek(fd_, fileSize_, SEEK_SET);
334     EventStr str = {};
335     CHK(Read(reinterpret_cast<void*>(&str), EVENT_STR_FIXED_SIZE));
336     char fileName[str.strLen + 1];
337     if (str.strLen > 0) {
338         CHK(Read(reinterpret_cast<void*>(&fileName), sizeof(fileName) - 1));
339         str.fileName = fileName;
340     }
341     str_.push_back(str);
342     int32_t newPos = static_cast<int32_t>(str.len - 32 - str.strLen);
343     fileSize_ = lseek(fd_, lseek(fd_, 0, SEEK_CUR) + newPos, SEEK_SET);
344 
345     outData_ << "\nEventStr:\n"
346         << "  tag: " << str.tag << '\n'
347         << "  len: " << str.len << '\n'
348         << "  pid: " << str.pid << '\n'
349         << "  tid: " << str.tid << '\n'
350         << "  start: " << str.start << '\n'
351         << "  srcTracer: " << str.srcTracer << '\n'
352         << "  srcType: " << str.srcType << '\n'
353         << "  strLen: " << str.strLen << '\n'
354         << "  fileName: " << str.fileName << '\n';
355 }
356 
EventBIOParsing()357 void EbpfConverter::EventBIOParsing()
358 {
359     lseek(fd_, fileSize_, SEEK_SET);
360     EventBIO bio = {};
361     CHK(Read(reinterpret_cast<void*>(&bio), EVENT_BIO_FIXED_SIZE));
362     uint64_t userIPs[bio.nips];
363     if (bio.nips > 0) {
364         CHK(Read(reinterpret_cast<void*>(userIPs), sizeof(userIPs)));
365         bio.userIPs = std::vector<uint64_t>(userIPs, userIPs + bio.nips);
366     }
367     fileSize_ = lseek(fd_, 0, SEEK_CUR);
368 
369     outData_ << "\nEventBIO:\n"
370         << "  tag: " << bio.tag << '\n'
371         << "  len: " << bio.len << '\n'
372         << "  pid: " << bio.pid << '\n'
373         << "  tid: " << bio.tid << '\n'
374         << "  comm: " << bio.comm << '\n'
375         << "  start: " << bio.start << '\n'
376         << "  end: " << bio.end << '\n'
377         << "  prio: " << bio.prio << '\n'
378         << "  size: " << bio.size << '\n'
379         << "  type: " << bio.type << '\n'
380         << "  typeName: " << bio.typeName << '\n';
381 
382     for (const auto &ip : bio.userIPs) {
383         if (ip == 0) {
384             continue;
385         }
386         outData_ << "    0x" << std::hex << ip << std::dec << ":";
387         auto itm = GetSymbolInfo(bio.pid, ip);
388         outData_ << "\n      vAddr_: 0x" << std::hex << vAddr_[ip] << std::dec << '\n';
389         for (const auto &sym : itm.second) {
390             outData_ << "      symbol: " << sym << '\n';
391         }
392         outData_ << "      fileName: " << itm.first << '\n';
393     }
394 }
395 
GetSymbolInfo(uint64_t pid,uint64_t ip)396 std::pair<std::string, std::vector<std::string>> EbpfConverter::GetSymbolInfo(uint64_t pid, uint64_t ip)
397 {
398     auto mapIter = maps_.find(pid);
399     if (mapIter == maps_.end()) {
400         return std::pair<std::string, std::vector<std::string>>();
401     }
402 
403     std::string fileName;
404     uint64_t start = 0;
405     uint32_t offset = 0;
406     std::any_of(mapIter->second.begin(), mapIter->second.end(), [&](const EventMaps &maps) {
407         if (ip >= maps.start && ip <= maps.end) {
408             fileName = maps.fileName;
409             start = maps.start;
410             offset = maps.offset;
411             return true;
412         }
413         return false;
414     });
415     if (fileName.empty()) {
416         return std::pair<std::string, std::vector<std::string>>();
417     }
418 
419     auto symItem = symbolInfo_.find(fileName);
420     if (symItem == symbolInfo_.end()) {
421         return std::pair<std::string, std::vector<std::string>>();
422     }
423     uint64_t vaddr = ip - start + offset - symItem->second.textOffset + symItem->second.textVaddr;
424     vAddr_[ip] = vaddr;
425     std::pair<std::string, std::vector<std::string>> symbolInfos;
426     symbolInfos.first = fileName;
427     if (symItem->second.symEntlen == SYM_ENT_LEN_64) {
428         uint32_t count = 0;
429         while (count < symItem->second.symTabLen) {
430             Elf64_Sym sym;
431             if (memcpy_s(&sym, sizeof(sym), symItem->second.symTab + count, SYM_ENT_LEN_64) != EOK) {
432                 std::cout << "copy symTab failed" << std::endl;
433                 return std::pair<std::string, std::vector<std::string>>();
434             }
435             if (vaddr >= sym.st_value &&
436                 vaddr <= sym.st_value + sym.st_size &&
437                 (sym.st_info & STT_FUNC) &&
438                 sym.st_value != 0) {
439                 char *ret = abi::__cxa_demangle(static_cast<char *>(symItem->second.strTab + sym.st_name),
440                                                 nullptr, nullptr, nullptr);
441                 ret == nullptr ? symbolInfos.second.push_back(std::string(symItem->second.strTab + sym.st_name))
442                     : symbolInfos.second.push_back(std::string(ret));
443             }
444             count += SYM_ENT_LEN_64;
445         }
446     } else if (symItem->second.symEntlen == SYM_ENT_LEN_32) {
447         uint32_t count = 0;
448         while (count < symItem->second.symTabLen) {
449             Elf32_Sym sym;
450             if (memcpy_s(&sym, sizeof(sym), symItem->second.strTab + count, SYM_ENT_LEN_32) != EOK) {
451                 std::cout << "copy symTab failed" << std::endl;
452                 return std::pair<std::string, std::vector<std::string>>();
453             }
454             if (vaddr >= sym.st_value &&
455                 vaddr <= sym.st_value + sym.st_size &&
456                 (sym.st_info & STT_FUNC) &&
457                 sym.st_value != 0) {
458                 char *ret = abi::__cxa_demangle(symItem->second.strTab + sym.st_name, nullptr, nullptr, nullptr);
459                 ret == nullptr ? symbolInfos.second.push_back(std::string(symItem->second.strTab + sym.st_name))
460                     : symbolInfos.second.push_back(std::string(ret));
461             }
462             count += SYM_ENT_LEN_32;
463         }
464     } else {
465         std::cout << "Invalid symEntlen" << std::endl;
466     }
467     return symbolInfos;
468 }
469 } // EBPF_TOOLS
470 } // OHOS
471 
main(int32_t argc,char * argv[])472 int32_t main(int32_t argc, char* argv[])
473 {
474     std::ios::sync_with_stdio(false);
475     std::cin.tie(nullptr);
476     struct option long_options[] = {
477         {"input", required_argument, nullptr, 'i'},
478         {"out", required_argument, nullptr, 'o'},
479         {"help", no_argument, nullptr, 'h'},
480         {0, 0, 0, 0}
481     };
482     int32_t opt;
483     std::string inputPath, outputPath;
484     while ((opt = getopt_long(argc, argv, "i:o:h", long_options, nullptr)) != -1) {
485         switch (opt) {
486             case 'i': {
487                 inputPath = optarg;
488                 continue;
489             }
490             case 'o': {
491                 outputPath = optarg;
492                 continue;
493             }
494             case 'h': {
495                 std::cout << "    --input" << "  " << "-i" << "  :" << "input file name" << std::endl;
496                 std::cout << "    --out" << "    " << "-o" << "  :" << "out file name" << std::endl;
497                 break;
498             }
499             default: {
500                 std::cout << "Parameter error" << std::endl;
501                 break;
502             }
503         }
504     }
505     OHOS::EBPF_TOOLS::EbpfConverter ec(inputPath, outputPath);
506     ec.StartParsing();
507     return 0;
508 }