1 /*
2 * Copyright (c) 2021 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 * Description: FtraceParser class implements
16 */
17 #include "ftrace_parser.h"
18
19 #include <algorithm>
20 #include <cerrno>
21 #include <cinttypes>
22 #include <cstring>
23 #include <fcntl.h>
24 #include <fstream>
25 #include <regex>
26 #include <sstream>
27 #include <unistd.h>
28
29 #include "file_utils.h"
30 #include "ftrace_fs_ops.h"
31 #include "logging.h"
32 #include "printk_formats_parser.h"
33 #include "securec.h"
34 #include "string_utils.h"
35 #include "sub_event_parser.h"
36
37 #ifdef HILOG_DEBUG
38 #undef HILOG_DEBUG
39 #endif
40
41 #define HILOG_DEBUG(LOG_CORE, fmt, ...) \
42 if (debugOn_) { \
43 HILOG_INFO(LOG_CORE, ":DEBUG: " fmt, ##__VA_ARGS__); \
44 }
45
46 namespace {
47 constexpr unsigned RB_MISSED_EVENTS = (1uL << 31); // Flag when events were overwritten
48 constexpr unsigned RB_MISSED_STORED = (1 << 30); // Missed count stored at end
49 constexpr unsigned RB_MISSED_FLAGS = (RB_MISSED_EVENTS | RB_MISSED_STORED);
50
51 constexpr unsigned COL_IDX_NAME = 0;
52 constexpr unsigned COL_IDX_VALUE = 1;
53
54 constexpr unsigned TS_EXT_SHIFT = 27;
55
GetTimestampIncrements(uint64_t ext)56 inline uint64_t GetTimestampIncrements(uint64_t ext)
57 {
58 return ext << TS_EXT_SHIFT;
59 }
60
ReadInc(uint8_t * start[],const uint8_t end[],void * outData,size_t outSize)61 bool ReadInc(uint8_t* start[], const uint8_t end[], void* outData, size_t outSize)
62 {
63 if ((end - *start) < static_cast<ptrdiff_t>(outSize)) {
64 return false;
65 }
66 if (memcpy_s(outData, outSize, *start, outSize) != EOK) {
67 HILOG_ERROR(LOG_CORE, "read %zu bytes from memory FAILED", outSize);
68 return false;
69 }
70 *start += outSize;
71 return true;
72 }
73 } // namespace
74
75 FTRACE_NS_BEGIN
FtraceParser()76 FtraceParser::FtraceParser()
77 {
78 HILOG_INFO(LOG_CORE, "FtraceParser create!");
79 }
80
Init()81 bool FtraceParser::Init()
82 {
83 fixedCharArrayRegex_ = std::regex(R"(char \w+\[\d+\])");
84 flexDataLocArrayRegex_ = std::regex(R"(__data_loc [a-zA-Z_0-9 ]+\[\] \w+)");
85
86 std::string printkFormats = FtraceFsOps::GetInstance().GetPrintkFormats();
87 CHECK_TRUE(printkFormats.size() > 0, false, "read printk_formats failed!");
88 CHECK_TRUE(PrintkFormatsParser::GetInstance().Parse(printkFormats), false, "parse printk_formats failed");
89
90 std::string formatDesc = FtraceFsOps::GetInstance().GetPageHeaderFormat();
91 CHECK_TRUE(formatDesc.size() > 0, false, "read header_page failed!");
92 return ParseHeaderPageFormat(formatDesc);
93 }
94
~FtraceParser()95 FtraceParser::~FtraceParser()
96 {
97 HILOG_INFO(LOG_CORE, "FtraceParser destroy!");
98 }
99
SetupEvent(const std::string & type,const std::string & name)100 bool FtraceParser::SetupEvent(const std::string& type, const std::string& name)
101 {
102 if (!SubEventParser::GetInstance().IsSupport(name)) {
103 // no sub event parser found for event, so no need to parse format file
104 return false;
105 }
106
107 EventFormat format;
108 format.eventType = type;
109 format.eventName = name;
110 std::string desc = FtraceFsOps::GetInstance().GetEventDataFormat(type, name);
111 CHECK_TRUE(ParseEventFormat(desc.data(), format), false, "parse %s/%s/format failed!", type.c_str(), name.c_str());
112 CHECK_TRUE(SubEventParser::GetInstance().SetupEvent(format), false, "setup %s/%s failed!", type.c_str(),
113 name.c_str());
114
115 return true;
116 }
117
ParseHeaderPageFormat(const std::string & formatDesc)118 bool FtraceParser::ParseHeaderPageFormat(const std::string& formatDesc)
119 {
120 EventFormat format = {};
121 CHECK_TRUE(ParseEventFormat(formatDesc, format), false, "parse events/header_page failed!");
122
123 bool commitFound = false;
124 for (auto& field : format.fields) {
125 if (field.name == "timestamp") {
126 pageHeaderFormat_.timestamp = field;
127 } else if (field.name == "commit") {
128 pageHeaderFormat_.commit = field;
129 commitFound = true;
130 } else if (field.name == "overwrite") {
131 pageHeaderFormat_.overwrite = field;
132 }
133 }
134
135 HILOG_INFO(LOG_CORE, "page header info:");
136 PrintFieldInfo(pageHeaderFormat_.timestamp);
137 PrintFieldInfo(pageHeaderFormat_.commit);
138 PrintFieldInfo(pageHeaderFormat_.overwrite);
139 CHECK_TRUE(commitFound, false, "commit field not found!");
140 return true;
141 }
142
GetHeaderPageCommitSize(void)143 int FtraceParser::GetHeaderPageCommitSize(void)
144 {
145 // return the size value of commit field read from events/header_page
146 return pageHeaderFormat_.commit.size;
147 }
148
ParseEventFormat(const std::string & formatDesc,EventFormat & format)149 bool FtraceParser::ParseEventFormat(const std::string& formatDesc, EventFormat& format)
150 {
151 std::string idLinePrefix = "ID:";
152 std::string fieldLinePrefix = "field:";
153 std::string printFmtLinePrefix = "print fmt:";
154
155 std::string line;
156 std::stringstream sin(formatDesc);
157 while (getline(sin, line)) {
158 line = StringUtils::Strip(line);
159 if (line.empty()) {
160 continue;
161 } else if (StringUtils::StartsWith(line, fieldLinePrefix)) {
162 ParseFieldFormat(line, format);
163 } else if (StringUtils::StartsWith(line, idLinePrefix)) {
164 auto idStr = line.substr(idLinePrefix.size() + 1);
165 format.eventId = static_cast<uint32_t>(atoi(idStr.c_str()));
166 }
167 }
168
169 CHECK_TRUE(format.fields.size() > 0, false, "ParseEventFormat from %s failed!", formatDesc.c_str());
170 int lastFiledIndex = format.fields.size() - 1;
171 format.eventSize = format.fields[lastFiledIndex].offset + format.fields[lastFiledIndex].size;
172 return true;
173 }
174
GetName(const std::map<int,std::string> & nameMap,int type)175 static std::string GetName(const std::map<int, std::string>& nameMap, int type)
176 {
177 auto it = nameMap.find(type);
178 if (it != nameMap.end()) {
179 return it->second;
180 }
181 return "";
182 }
183
GetFieldTypeName(EventFieldType type)184 static std::string GetFieldTypeName(EventFieldType type)
185 {
186 static std::map<int, std::string> toNames = {
187 #define VALUE_NAME(x) {x, #x}
188 VALUE_NAME(FIELD_TYPE_INVALID), VALUE_NAME(FIELD_TYPE_BOOL), VALUE_NAME(FIELD_TYPE_INT8),
189 VALUE_NAME(FIELD_TYPE_UINT8), VALUE_NAME(FIELD_TYPE_INT16), VALUE_NAME(FIELD_TYPE_UINT16),
190 VALUE_NAME(FIELD_TYPE_INT32), VALUE_NAME(FIELD_TYPE_UINT32), VALUE_NAME(FIELD_TYPE_INT64),
191 VALUE_NAME(FIELD_TYPE_UINT64), VALUE_NAME(FIELD_TYPE_FIXEDCSTRING), VALUE_NAME(FIELD_TYPE_CSTRING),
192 VALUE_NAME(FIELD_TYPE_STRINGPTR), VALUE_NAME(FIELD_TYPE_INODE32), VALUE_NAME(FIELD_TYPE_INODE64),
193 VALUE_NAME(FIELD_TYPE_PID32), VALUE_NAME(FIELD_TYPE_COMMONPID32), VALUE_NAME(FIELD_TYPE_DEVID32),
194 VALUE_NAME(FIELD_TYPE_DEVID64), VALUE_NAME(FIELD_TYPE_DATALOC), VALUE_NAME(FIELD_TYPE_SYMADDR32),
195 VALUE_NAME(FIELD_TYPE_SYMADDR64),
196 #undef VALUE_NAME
197 };
198 return GetName(toNames, type);
199 }
200
GetProtoTypeName(ProtoFieldType type)201 static std::string GetProtoTypeName(ProtoFieldType type)
202 {
203 static std::map<int, std::string> toNames = {
204 #define VALUE_NAME(x) {x, #x}
205 VALUE_NAME(PROTO_TYPE_UNKNOWN), VALUE_NAME(PROTO_TYPE_DOUBLE), VALUE_NAME(PROTO_TYPE_FLOAT),
206 VALUE_NAME(PROTO_TYPE_INT64), VALUE_NAME(PROTO_TYPE_UINT64), VALUE_NAME(PROTO_TYPE_INT32),
207 VALUE_NAME(PROTO_TYPE_FIXED64), VALUE_NAME(PROTO_TYPE_FIXED32), VALUE_NAME(PROTO_TYPE_BOOL),
208 VALUE_NAME(PROTO_TYPE_STRING), VALUE_NAME(PROTO_TYPE_GROUP), VALUE_NAME(PROTO_TYPE_MESSAGE),
209 VALUE_NAME(PROTO_TYPE_BYTES), VALUE_NAME(PROTO_TYPE_UINT32), VALUE_NAME(PROTO_TYPE_ENUM),
210 VALUE_NAME(PROTO_TYPE_SFIXED32), VALUE_NAME(PROTO_TYPE_SFIXED64), VALUE_NAME(PROTO_TYPE_SINT32),
211 VALUE_NAME(PROTO_TYPE_SINT64), VALUE_NAME(PROTO_TYPE_MAX),
212 #undef VALUE_NAME
213 };
214 return GetName(toNames, type);
215 }
216
PrintFieldInfo(const FieldFormat & info)217 void FtraceParser::PrintFieldInfo(const FieldFormat& info)
218 {
219 UNUSED_PARAMETER(GetProtoTypeName);
220 UNUSED_PARAMETER(GetFieldTypeName);
221 HILOG_DEBUG(LOG_CORE,
222 "FieldFormat { offset: %u, size:%u, sign: %u fieldType: %s, protoType:%s, typeName: %s, name: %s}",
223 info.offset, info.size, info.isSigned, GetFieldTypeName(info.filedType).c_str(),
224 GetProtoTypeName(info.protoType).c_str(), info.typeName.c_str(), info.name.c_str());
225 }
226
SplitNameFromTypeName(const std::string & typeName)227 static std::string SplitNameFromTypeName(const std::string& typeName)
228 {
229 std::string name;
230 if (typeName.size() > 0) { // split type and name
231 auto posT0 = typeName.rfind(" ");
232 std::string rightHalf = typeName.substr(posT0 + 1);
233 if (rightHalf[rightHalf.size() - 1] != ']') {
234 name = rightHalf;
235 } else {
236 std::string::size_type postT1 = rightHalf.rfind('[');
237 if (postT1 == std::string::npos) {
238 return "";
239 }
240 name = rightHalf.substr(0, postT1);
241 }
242 }
243 return name;
244 }
245
EraseNameFromTypeName(const std::string & typeName,const std::string & name)246 static std::string EraseNameFromTypeName(const std::string& typeName, const std::string& name)
247 {
248 std::string type;
249 if (name.size() > 0) { // erase name part from typeName
250 type = typeName;
251 auto pos = type.find(name);
252 type.replace(pos, name.size(), "");
253 type = StringUtils::Strip(type);
254 }
255 return type;
256 }
257
ParseCommonFiledIndex(CommonFiledIndex & commonIndex,const std::string & name,int index)258 static void ParseCommonFiledIndex(CommonFiledIndex& commonIndex, const std::string& name, int index)
259 {
260 if (name == "common_type") {
261 commonIndex.type = index;
262 } else if (name == "common_flags") {
263 commonIndex.flags = index;
264 } else if (name == "common_preempt_count") {
265 commonIndex.preemt = index;
266 } else if (name == "common_pid") {
267 commonIndex.pid = index;
268 }
269 }
270
ParseFieldFormat(const std::string & fieldLine,EventFormat & format)271 bool FtraceParser::ParseFieldFormat(const std::string& fieldLine, EventFormat& format)
272 {
273 FieldFormat fieldInfo;
274 std::string typeName;
275 std::string offsetStr;
276 std::string sizeStr;
277 std::string signedStr;
278
279 for (auto& part : StringUtils::Split(fieldLine, ";")) {
280 auto cols = StringUtils::Split(StringUtils::Strip(part), ":");
281 if (cols.size() < COL_IDX_VALUE) {
282 continue;
283 }
284 const auto& key = cols[COL_IDX_NAME];
285 if (key == "field") {
286 typeName = cols[COL_IDX_VALUE];
287 } else if (key == "offset") {
288 offsetStr = cols[COL_IDX_VALUE];
289 } else if (key == "size") {
290 sizeStr = cols[COL_IDX_VALUE];
291 } else if (key == "signed") {
292 signedStr = cols[COL_IDX_VALUE];
293 }
294 }
295
296 std::string name = SplitNameFromTypeName(typeName);
297 std::string type = EraseNameFromTypeName(typeName, name); // for field type
298 fieldInfo.name = name;
299 fieldInfo.typeName = typeName;
300 fieldInfo.offset = atoi(offsetStr.c_str());
301 fieldInfo.size = atoi(sizeStr.c_str());
302 fieldInfo.isSigned = atoi(signedStr.c_str());
303
304 ParseFieldType(type, fieldInfo);
305 ParseProtoType(fieldInfo);
306
307 if (StringUtils::StartsWith(name, "common_")) {
308 ParseCommonFiledIndex(format.commonIndex, name, static_cast<int>(format.commonFields.size()));
309 format.commonFields.push_back(fieldInfo);
310 } else {
311 format.fields.push_back(fieldInfo);
312 }
313 return true;
314 }
315
ParseSepcialIntType(FieldFormat & field,const std::string & type,const std::string & typeName)316 static bool ParseSepcialIntType(FieldFormat& field, const std::string& type, const std::string& typeName)
317 {
318 if (type == "bool") {
319 field.filedType = FIELD_TYPE_BOOL;
320 return true;
321 }
322
323 if (type == "ino_t" || type == "i_ino") {
324 if (field.size == sizeof(uint32_t)) {
325 field.filedType = FIELD_TYPE_INODE32;
326 return true;
327 } else if (field.size == sizeof(uint64_t)) {
328 field.filedType = FIELD_TYPE_INODE64;
329 return true;
330 }
331 }
332
333 if (type == "dev_t") {
334 if (field.size == sizeof(uint32_t)) {
335 field.filedType = FIELD_TYPE_DEVID32;
336 return true;
337 } else if (field.size == sizeof(uint64_t)) {
338 field.filedType = FIELD_TYPE_DEVID64;
339 return true;
340 }
341 }
342
343 // Pids (as in 'sched_switch').
344 if (type == "pid_t") {
345 field.filedType = FIELD_TYPE_PID32;
346 return true;
347 }
348
349 if ((typeName.find("common_pid") != std::string::npos)) {
350 field.filedType = FIELD_TYPE_COMMONPID32;
351 return true;
352 }
353 return false;
354 }
355
ParseCommonIntType(FieldFormat & field,bool sign)356 static bool ParseCommonIntType(FieldFormat& field, bool sign)
357 {
358 switch (field.size) {
359 case sizeof(int8_t):
360 field.filedType = sign ? FIELD_TYPE_INT8 : FIELD_TYPE_UINT8;
361 return true;
362 case sizeof(int16_t):
363 field.filedType = sign ? FIELD_TYPE_INT16 : FIELD_TYPE_UINT16;
364 return true;
365 case sizeof(int32_t):
366 field.filedType = sign ? FIELD_TYPE_INT32 : FIELD_TYPE_UINT32;
367 return true;
368 case sizeof(int64_t):
369 field.filedType = sign ? FIELD_TYPE_INT64 : FIELD_TYPE_UINT64;
370 return true;
371 default:
372 break;
373 }
374 return false;
375 }
376
ParseKernelAddrField(FieldFormat & field,const std::string & type)377 static bool ParseKernelAddrField(FieldFormat& field, const std::string& type)
378 {
379 if (type == "void*" || type == "void *") {
380 if (field.size == sizeof(uint64_t)) { // 64-bit kernel addresses
381 field.filedType = FIELD_TYPE_SYMADDR64;
382 return true;
383 } else if (field.size == sizeof(uint32_t)) { // 32-bit kernel addresses
384 field.filedType = FIELD_TYPE_SYMADDR32;
385 return true;
386 }
387 }
388 return false;
389 }
390
ParseFieldType(const std::string & type,FieldFormat & field)391 bool FtraceParser::ParseFieldType(const std::string& type, FieldFormat& field)
392 {
393 const std::string& typeName = field.typeName;
394 // Fixed size C char arrary, likes "char a[LEN]"
395 if (std::regex_match(typeName, fixedCharArrayRegex_)) {
396 field.filedType = FIELD_TYPE_FIXEDCSTRING;
397 return true;
398 }
399
400 // for flex array with __data_loc mark, likes: __data_loc char[] name; __data_loc __u8[] buf;
401 if (std::regex_match(typeName, flexDataLocArrayRegex_)) {
402 CHECK_TRUE(field.size == sizeof(uint32_t), false, "__data_loc %s, size: %hu", typeName.c_str(), field.size);
403 field.filedType = FIELD_TYPE_DATALOC;
404 return true;
405 }
406
407 if ((typeName.find("char[]") != std::string::npos) || (typeName.find("char *") != std::string::npos)) {
408 field.filedType = FIELD_TYPE_STRINGPTR;
409 return true;
410 }
411
412 // Variable length strings: "char foo" + size: 0 (as in 'print').
413 if ((type == "char" || type == "char []") && field.size == 0) {
414 field.filedType = FIELD_TYPE_CSTRING;
415 return true;
416 }
417
418 // 64-bit kernel addresses
419 if (ParseKernelAddrField(field, type)) {
420 return true;
421 }
422
423 if (ParseSepcialIntType(field, type, typeName)) {
424 return true;
425 }
426
427 // int uint:
428 if (ParseCommonIntType(field, field.isSigned)) {
429 return true;
430 }
431 return false;
432 }
433
ParseProtoType(FieldFormat & field)434 void FtraceParser::ParseProtoType(FieldFormat& field)
435 {
436 switch (field.filedType) {
437 case FIELD_TYPE_CSTRING:
438 case FIELD_TYPE_FIXEDCSTRING:
439 case FIELD_TYPE_STRINGPTR:
440 case FIELD_TYPE_DATALOC:
441 field.protoType = PROTO_TYPE_STRING;
442 break;
443 case FIELD_TYPE_INT8:
444 case FIELD_TYPE_INT16:
445 case FIELD_TYPE_INT32:
446 case FIELD_TYPE_PID32:
447 case FIELD_TYPE_COMMONPID32:
448 field.protoType = PROTO_TYPE_INT32;
449 break;
450 case FIELD_TYPE_INT64:
451 field.protoType = PROTO_TYPE_INT64;
452 break;
453 case FIELD_TYPE_UINT8:
454 case FIELD_TYPE_UINT16:
455 case FIELD_TYPE_UINT32:
456 case FIELD_TYPE_BOOL:
457 case FIELD_TYPE_DEVID32:
458 case FIELD_TYPE_SYMADDR32:
459 field.protoType = PROTO_TYPE_UINT32;
460 break;
461 case FIELD_TYPE_DEVID64:
462 case FIELD_TYPE_UINT64:
463 case FIELD_TYPE_INODE32:
464 case FIELD_TYPE_INODE64:
465 case FIELD_TYPE_SYMADDR64:
466 field.protoType = PROTO_TYPE_UINT64;
467 break;
468 case FIELD_TYPE_INVALID:
469 field.protoType = PROTO_TYPE_UNKNOWN;
470 break;
471 default:
472 break;
473 }
474 }
475
ParsePerCpuStatus(PerCpuStats & stats,const std::string & perCpuStats)476 bool FtraceParser::ParsePerCpuStatus(PerCpuStats& stats, const std::string& perCpuStats)
477 {
478 std::string line;
479 std::stringstream input(perCpuStats);
480
481 int count = 0;
482 while (getline(input, line, '\n')) {
483 std::string sep = ": ";
484 size_t pos = line.rfind(sep);
485 if (pos == std::string::npos) {
486 continue;
487 }
488 std::stringstream ss(line.substr(pos + sep.size()));
489 std::string name = line.substr(0, pos);
490 if (name == "entries") {
491 ss >> stats.entries;
492 count++;
493 } else if (name == "overrun") {
494 ss >> stats.overrun;
495 count++;
496 } else if (name == "commit overrun") {
497 ss >> stats.commitOverrun;
498 count++;
499 } else if (name == "bytes") {
500 ss >> stats.bytes;
501 count++;
502 } else if (name == "oldest event ts") {
503 ss >> stats.oldestEventTs;
504 count++;
505 } else if (name == "now ts") {
506 ss >> stats.nowTs;
507 count++;
508 } else if (name == "dropped events") {
509 ss >> stats.droppedEvents;
510 count++;
511 } else if (name == "read events") {
512 ss >> stats.readEvents;
513 count++;
514 }
515 }
516 return count > 0;
517 }
518
519 // parse kernel ring buffer page header data
ParsePageHeader()520 bool FtraceParser::ParsePageHeader()
521 {
522 // read time stamp
523 uint64_t timestamp = 0;
524 CHECK_TRUE(ReadInc(&cur_, endOfPage_, ×tamp, sizeof(timestamp)), false, "read timestamp from page failed!");
525 pageHeader_.timestamp = timestamp;
526
527 // read data size and overwriten flags
528 uint64_t commit = 0;
529 const int commitSize = GetHeaderPageCommitSize(); // 8B on 64bit device, 4B on 32bit device
530 CHECK_TRUE(ReadInc(&cur_, endOfPage_, &commit, commitSize), false, "read commit to page header failed!");
531
532 // refers kernel function ring_buffer_page_len:
533 pageHeader_.size = (commit & ~RB_MISSED_FLAGS);
534 pageHeader_.overwrite = (commit & RB_MISSED_EVENTS);
535
536 pageHeader_.startpos = cur_;
537 pageHeader_.endpos = cur_ + pageHeader_.size;
538 return true;
539 }
540
541 // parse /sys/kernel/debug/tracing/saved_tgids
542 // refers kernel function saved_tgids_show
ParseSavedTgid(const std::string & savedTgid)543 bool FtraceParser::ParseSavedTgid(const std::string& savedTgid)
544 {
545 int32_t pid = 0;
546 int32_t tgid = 0;
547 std::stringstream sin(savedTgid);
548 // kernel format code with: "%d %d\n"
549 while (sin >> pid >> tgid) {
550 tgidDict_[pid] = tgid;
551 }
552
553 if (tgidDict_.size() == 0) {
554 HILOG_WARN(LOG_CORE, "ParseSavedTgid: parsed tigds: %zu", tgidDict_.size());
555 }
556 return true;
557 }
558
559 // parse /sys/kernel/debug/tracing/saved_cmdlines
560 // refers kernel function saved_cmdlines_show
ParseSavedCmdlines(const std::string & savedCmdlines)561 bool FtraceParser::ParseSavedCmdlines(const std::string& savedCmdlines)
562 {
563 bool retval = false;
564 int32_t pid;
565 std::string comm;
566 std::string line;
567 std::stringstream sin(savedCmdlines);
568 while (std::getline(sin, line)) {
569 // kernel format with: "%d %s\n"
570 auto pos = line.find(' ');
571 if (pos != std::string::npos) {
572 pid = std::stoi(line.substr(0, pos));
573 comm = line.substr(pos + 1);
574 commDict_[pid] = comm;
575 retval = true;
576 }
577 }
578
579 if (commDict_.size() == 0) {
580 HILOG_WARN(LOG_CORE, "ParseSavedCmdlines: parsed cmdlines: %zu", commDict_.size());
581 }
582 return retval;
583 }
584
ParsePaddingData(const FtraceEventHeader & eventHeader)585 bool FtraceParser::ParsePaddingData(const FtraceEventHeader& eventHeader)
586 {
587 if (eventHeader.timeDelta == 0) {
588 return false;
589 }
590 uint32_t paddingLength;
591 CHECK_TRUE(ReadInc(&cur_, endOfData_, &paddingLength, sizeof(paddingLength)), false, "read padding len failed!");
592
593 // skip padding data
594 cur_ += paddingLength;
595 return true;
596 }
597
ParseTimeExtend(const FtraceEventHeader & eventHeader)598 bool FtraceParser::ParseTimeExtend(const FtraceEventHeader& eventHeader)
599 {
600 uint32_t deltaExt = 0;
601 CHECK_TRUE(ReadInc(&cur_, endOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
602
603 timestamp_ += GetTimestampIncrements(deltaExt);
604 HILOG_INFO(LOG_CORE, "ParseTimeExtend: update ts with %u to %" PRIu64, deltaExt, timestamp_);
605 return true;
606 }
607
ParseTimeStamp(const FtraceEventHeader & eventHeader)608 bool FtraceParser::ParseTimeStamp(const FtraceEventHeader& eventHeader)
609 {
610 uint32_t deltaExt = 0;
611 CHECK_TRUE(ReadInc(&cur_, endOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
612
613 // refers kernel function rb_update_write_stamp in ring_buffer.c
614 timestamp_ = eventHeader.timeDelta + GetTimestampIncrements(deltaExt);
615 HILOG_INFO(LOG_CORE, "ParseTimeStamp: update ts with %u to %" PRIu64, deltaExt, timestamp_);
616 return true;
617 }
618
ParseDataRecord(const FtraceEventHeader & eventHeader,FtraceCpuDetailMsg & cpuMsg)619 bool FtraceParser::ParseDataRecord(const FtraceEventHeader& eventHeader, FtraceCpuDetailMsg& cpuMsg)
620 {
621 uint32_t evtSize = 0;
622 // refers comments of kernel function rb_event_data_length:
623 if (eventHeader.typeLen) {
624 evtSize = sizeof(eventHeader.array[0]) * eventHeader.typeLen;
625 } else {
626 CHECK_TRUE(ReadInc(&cur_, endOfData_, &evtSize, sizeof(evtSize)), false, "read event size failed!");
627 if (evtSize < sizeof(uint32_t)) {
628 return false;
629 }
630 evtSize -= sizeof(uint32_t); // array[0] is length, array[1...array[0]] is event data
631 }
632 HILOG_DEBUG(LOG_CORE, "ParseDataRecord: parse %u bytes of event data...", evtSize);
633
634 uint8_t* evStart = cur_;
635 uint8_t* evEnd = cur_ + evtSize;
636 uint16_t evId = 0;
637 CHECK_TRUE(ReadInc(&cur_, evEnd, &evId, sizeof(evId)), false, "read event ID failed!");
638
639 uint32_t eventId = evId;
640 SubEventParser::ParseEventCtx* parseEventCtx = SubEventParser::GetInstance().GetParseEventCtx(eventId);
641 if (parseEventCtx == nullptr) {
642 HILOG_DEBUG(LOG_CORE, "event %u not supported!", eventId);
643 } else {
644 HILOG_DEBUG(LOG_CORE, "ParseDataRecord: eventId = %u, name = %s",
645 eventId, parseEventCtx->format.eventName.c_str());
646 auto ftraceEvent = cpuMsg.add_event();
647 ftraceEvent->set_timestamp(timestamp_);
648 ParseFtraceEvent(*ftraceEvent, evStart, evtSize, parseEventCtx);
649 }
650 cur_ = evEnd;
651 return true;
652 }
653
ParsePage(FtraceCpuDetailMsg & cpuMsg,uint8_t page[],size_t size)654 bool FtraceParser::ParsePage(FtraceCpuDetailMsg& cpuMsg, uint8_t page[], size_t size)
655 {
656 cur_ = page;
657 page_ = page;
658 endOfPage_ = page + size;
659
660 ParsePageHeader();
661 HILOG_DEBUG(LOG_CORE, "ParsePage: %" PRIu64 " bytes event data in page!", pageHeader_.size);
662 cpuMsg.set_overwrite(pageHeader_.overwrite);
663
664 timestamp_ = pageHeader_.timestamp;
665 endOfData_ = pageHeader_.endpos;
666 while (cur_ < pageHeader_.endpos) {
667 FtraceEventHeader eventHeader = {};
668 CHECK_TRUE(ReadInc(&cur_, endOfData_, &eventHeader, sizeof(FtraceEventHeader)), false,
669 "read EventHeader fail!");
670
671 timestamp_ += eventHeader.timeDelta;
672
673 bool retval = false;
674 switch (eventHeader.typeLen) {
675 case BUFFER_TYPE_PADDING:
676 retval = ParsePaddingData(eventHeader);
677 CHECK_TRUE(retval, false, "parse PADDING data failed!");
678 break;
679 case BUFFER_TYPE_TIME_EXTEND:
680 retval = ParseTimeExtend(eventHeader);
681 CHECK_TRUE(retval, false, "parse TIME_EXTEND failed!");
682 break;
683 case BUFFER_TYPE_TIME_STAMP:
684 retval = ParseTimeStamp(eventHeader);
685 CHECK_TRUE(retval, false, "parse TIME_STAMP failed!");
686 break;
687 default:
688 retval = ParseDataRecord(eventHeader, cpuMsg);
689 CHECK_TRUE(retval, false, "parse record data failed!");
690 break;
691 }
692 HILOG_DEBUG(LOG_CORE, "parsed %ld bytes of page data.", static_cast<long>(cur_ - page_));
693 }
694 return true;
695 }
696
IsValidIndex(int idx)697 static bool IsValidIndex(int idx)
698 {
699 return idx != CommonFiledIndex::INVALID_IDX;
700 }
701
ParseFtraceCommonFields(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format)702 bool FtraceParser::ParseFtraceCommonFields(FtraceEvent& ftraceEvent,
703 uint8_t data[],
704 size_t dataSize,
705 const EventFormat& format)
706 {
707 auto& index = format.commonIndex;
708
709 CHECK_TRUE(IsValidIndex(index.pid), false, "pid index %d invalid!", index.pid);
710 CHECK_TRUE(IsValidIndex(index.type), false, "type index %d invalid!", index.type);
711 CHECK_TRUE(IsValidIndex(index.flags), false, "flags index %d invalid!", index.flags);
712 CHECK_TRUE(IsValidIndex(index.preemt), false, "preemt index %d invalid!", index.preemt);
713
714 auto commonFields = ftraceEvent.mutable_common_fields();
715 commonFields->set_pid(FtraceFieldParser::ParseIntField<int32_t>(format.commonFields, index.pid, data, dataSize));
716 commonFields->set_type(FtraceFieldParser::ParseIntField<uint32_t>(format.commonFields, index.type, data, dataSize));
717 commonFields->set_flags(
718 FtraceFieldParser::ParseIntField<uint32_t>(format.commonFields, index.flags, data, dataSize));
719 commonFields->set_preempt_count(
720 FtraceFieldParser::ParseIntField<uint32_t>(format.commonFields, index.preemt, data, dataSize));
721 return true;
722 }
723
ParseFtraceEvent(FtraceEvent & ftraceEvent,uint8_t data[],size_t dataSize,const SubEventParser::ParseEventCtx * parseEventCtx)724 bool FtraceParser::ParseFtraceEvent(FtraceEvent& ftraceEvent,
725 uint8_t data[],
726 size_t dataSize,
727 const SubEventParser::ParseEventCtx* parseEventCtx)
728 {
729 CHECK_TRUE(dataSize >= parseEventCtx->format.eventSize, false,
730 "FtraceParser::ParseFtraceEvent, dataSize not enough!");
731 CHECK_TRUE(ParseFtraceCommonFields(ftraceEvent, data, dataSize, parseEventCtx->format), false,
732 "parse common fields failed!");
733
734 int pid = ftraceEvent.common_fields().pid();
735 if (pid != 0) {
736 int tgid = 0;
737 if (auto it = tgidDict_.find(pid); it != tgidDict_.end()) {
738 tgid = it->second;
739 ftraceEvent.set_tgid(tgid);
740 } else {
741 ParseSavedTgid(FtraceFsOps::GetInstance().GetSavedTgids());
742 if (auto itm = tgidDict_.find(pid); itm != tgidDict_.end()) {
743 tgid = itm->second;
744 ftraceEvent.set_tgid(tgid);
745 }
746 }
747
748 std::string comm;
749 if (auto it = commDict_.find(pid); it != commDict_.end()) {
750 comm = it->second;
751 } else {
752 if (tgid != 0) {
753 comm = FtraceFsOps::GetInstance().GetThreadComm(tgid, pid);
754 } else {
755 comm = FtraceFsOps::GetInstance().GetProcessComm(pid);
756 }
757 if (comm.size() > 0) {
758 comm.pop_back(); // /proc/xxx/comm end with `\n`
759 commDict_.insert(std::pair<int32_t, std::string>(pid, comm));
760 }
761 }
762 if (comm.size() > 0) {
763 ftraceEvent.set_comm(comm);
764 }
765
766 HILOG_DEBUG(LOG_CORE, "pid = %5d, tgid = %5d, comm = %16s, event = %s", pid, tgid, comm.c_str(),
767 parseEventCtx->format.eventName.c_str());
768 }
769
770 SubEventParser::GetInstance().ParseEvent(ftraceEvent, data, dataSize, parseEventCtx);
771 return true;
772 }
773
SetDebugOn(bool value)774 void FtraceParser::SetDebugOn(bool value)
775 {
776 debugOn_ = value;
777 HILOG_INFO(LOG_CORE, "debugOption: %s", debugOn_ ? "true" : "false");
778 }
779 FTRACE_NS_END
780