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_, ×tamp, 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