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