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