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