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 }