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