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