1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 <cstring>
22 #include <fcntl.h>
23 #include <fstream>
24 #include <regex>
25 #include <sstream>
26 #include <unistd.h>
27 
28 #include "common.h"
29 #include "file_utils.h"
30 #include "securec.h"
31 #include "string_utils.h"
32 
33 #ifdef HILOG_DEBUG
34 #undef HILOG_DEBUG
35 #endif
36 
37 #define HILOG_DEBUG(LOG_CORE, fmt, ...) \
38     if (debugOn_) { \
39         PROFILER_LOG_INFO(LOG_CORE, ":DEBUG: " fmt, ##__VA_ARGS__); \
40     }
41 
42 namespace {
43 using namespace OHOS::Developtools::Profiler;
44 constexpr unsigned RB_MISSED_EVENTS = (1uL << 31); // Flag when events were overwritten
45 constexpr unsigned RB_MISSED_STORED = (1 << 30);   // Missed count stored at end
46 constexpr unsigned RB_MISSED_FLAGS = (RB_MISSED_EVENTS | RB_MISSED_STORED);
47 
48 constexpr unsigned COL_IDX_NAME = 0;
49 constexpr unsigned COL_IDX_VALUE = 1;
50 
51 constexpr unsigned TS_EXT_SHIFT = 27;
52 constexpr uint32_t INT_MAX_LEN = 10;
53 
GetTimestampIncrements(uint64_t ext)54 inline uint64_t GetTimestampIncrements(uint64_t ext)
55 {
56     return ext << TS_EXT_SHIFT;
57 }
58 } // namespace
59 
60 FTRACE_NS_BEGIN
FtraceParser()61 FtraceParser::FtraceParser()
62 {
63     PROFILER_LOG_INFO(LOG_CORE, "FtraceParser create!");
64 }
65 
Init()66 bool FtraceParser::Init()
67 {
68     fixedCharArrayRegex_ = std::regex(R"(char \w+\[\d+\])");
69     flexDataLocArrayRegex_ = std::regex(R"(__data_loc [a-zA-Z_0-9 ]+\[\] \w+)");
70     if (FtraceFsOps::GetInstance().IsHmKernel()) {
71         return true;
72     }
73     std::string printkFormats = FtraceFsOps::GetInstance().GetPrintkFormats();
74     CHECK_TRUE(printkFormats.size() > 0, false, "read printk_formats failed!");
75     CHECK_TRUE(PrintkFormatsParser::GetInstance().Parse(printkFormats), false, "parse printk_formats failed");
76 
77     std::string formatDesc = FtraceFsOps::GetInstance().GetPageHeaderFormat();
78     CHECK_TRUE(formatDesc.size() > 0, false, "read header_page failed!");
79     return ParseHeaderPageFormat(formatDesc);
80 }
81 
~FtraceParser()82 FtraceParser::~FtraceParser()
83 {
84     PROFILER_LOG_INFO(LOG_CORE, "FtraceParser destroy!");
85 }
86 
SetupEvent(const std::string& type, const std::string& name)87 bool FtraceParser::SetupEvent(const std::string& type, const std::string& name)
88 {
89     if (!SubEventParser<FtraceEvent>::GetInstance().IsSupport(name)) {
90         // no sub event parser found for event, so no need to parse format file
91         return false;
92     }
93 
94     EventFormat format;
95     format.eventType = type;
96     format.eventName = name;
97     std::string desc = FtraceFsOps::GetInstance().GetEventDataFormat(type, name);
98     if (desc != "") {
99         CHECK_TRUE(ParseEventFormat(desc.data(), format), false, "parse %s/%s/format failed!",
100             type.c_str(), name.c_str());
101         CHECK_TRUE(SubEventParser<FtraceEvent>::GetInstance().SetupEvent(format),
102             false, "setup %s/%s failed!", type.c_str(), name.c_str());
103         CHECK_TRUE(SubEventParser<ProtoEncoder::FtraceEvent>::GetInstance().SetupEvent(format),
104             false, "setup pbzero %s/%s failed!", type.c_str(), name.c_str());
105     }
106     return true;
107 }
108 
ParseHeaderPageFormat(const std::string& formatDesc)109 bool FtraceParser::ParseHeaderPageFormat(const std::string& formatDesc)
110 {
111     EventFormat format = {};
112     CHECK_TRUE(ParseEventFormat(formatDesc, format), false, "parse events/header_page failed!");
113 
114     bool commitFound = false;
115     for (auto& field : format.fields) {
116         if (field.name == "timestamp") {
117             pageHeaderFormat_.timestamp = field;
118         } else if (field.name == "commit") {
119             pageHeaderFormat_.commit = field;
120             commitFound = true;
121         } else if (field.name == "overwrite") {
122             pageHeaderFormat_.overwrite = field;
123         }
124     }
125 
126     CHECK_TRUE(commitFound, false, "commit field not found!");
127     return true;
128 }
129 
GetHeaderPageCommitSize(void)130 int FtraceParser::GetHeaderPageCommitSize(void)
131 {
132     // return the size value of commit field read from events/header_page
133     return pageHeaderFormat_.commit.size;
134 }
135 
ParseEventFormat(const std::string& formatDesc, EventFormat& format)136 bool FtraceParser::ParseEventFormat(const std::string& formatDesc, EventFormat& format)
137 {
138     std::string idLinePrefix = "ID:";
139     std::string fieldLinePrefix = "field:";
140     std::string printFmtLinePrefix = "print fmt:";
141 
142     std::string line;
143     std::stringstream sin(formatDesc);
144     while (getline(sin, line)) {
145         line = StringUtils::Strip(line);
146         if (line.empty()) {
147             continue;
148         } else if (StringUtils::StartsWith(line, fieldLinePrefix)) {
149             ParseFieldFormat(line, format);
150         } else if (StringUtils::StartsWith(line, idLinePrefix)) {
151             auto idStr = line.substr(idLinePrefix.size() + 1);
152             format.eventId = static_cast<uint32_t>(atoi(idStr.c_str()));
153         }
154     }
155     CHECK_TRUE(format.fields.size() > 0, false, "ParseEventFormat failed!");
156     size_t lastFiledIndex = format.fields.size() > 1 ? format.fields.size() - 1 : 0;
157     format.eventSize = format.fields[lastFiledIndex].offset + format.fields[lastFiledIndex].size;
158     return true;
159 }
160 
SplitNameFromTypeName(const std::string& typeName)161 static std::string SplitNameFromTypeName(const std::string& typeName)
162 {
163     std::string name;
164     if (typeName.size() > 0) { // split type and name
165         auto posT0 = typeName.rfind(" ");
166         std::string rightHalf = typeName.substr(posT0 + 1);
167         size_t dataIndex = rightHalf.size() > 1 ? rightHalf.size() - 1 : 0;
168         if (rightHalf[dataIndex] != ']') {
169             name = rightHalf;
170         } else {
171             std::string::size_type postT1 = rightHalf.rfind('[');
172             if (postT1 == std::string::npos) {
173                 return "";
174             }
175             name = rightHalf.substr(0, postT1);
176         }
177     }
178     return name;
179 }
180 
EraseNameFromTypeName(const std::string& typeName, const std::string& name)181 static std::string EraseNameFromTypeName(const std::string& typeName, const std::string& name)
182 {
183     std::string type;
184     if (name.size() > 0) { // erase name part from typeName
185         type = typeName;
186         auto pos = type.find(name);
187         type.replace(pos, name.size(), "");
188         type = StringUtils::Strip(type);
189     }
190     return type;
191 }
192 
ParseCommonFiledIndex(CommonFiledIndex& commonIndex, const std::string& name, int index)193 static void ParseCommonFiledIndex(CommonFiledIndex& commonIndex, const std::string& name, int index)
194 {
195     if (name == "common_type") {
196         commonIndex.type = index;
197     } else if (name == "common_flags") {
198         commonIndex.flags = index;
199     } else if (name == "common_preempt_count") {
200         commonIndex.preemt = index;
201     } else if (name == "common_pid") {
202         commonIndex.pid = index;
203     }
204 }
205 
ParseFieldFormat(const std::string& fieldLine, EventFormat& format)206 bool FtraceParser::ParseFieldFormat(const std::string& fieldLine, EventFormat& format)
207 {
208     FieldFormat fieldInfo;
209     std::string typeName;
210     std::string offsetStr;
211     std::string sizeStr;
212     std::string signedStr;
213 
214     for (auto& part : StringUtils::Split(fieldLine, ";")) {
215         auto cols = StringUtils::Split(StringUtils::Strip(part), ":");
216         if (cols.size() < COL_IDX_VALUE) {
217             continue;
218         }
219         const auto& key = cols[COL_IDX_NAME];
220         if (key == "field") {
221             typeName = cols[COL_IDX_VALUE];
222         } else if (key == "offset") {
223             offsetStr = cols[COL_IDX_VALUE];
224         } else if (key == "size") {
225             sizeStr = cols[COL_IDX_VALUE];
226         } else if (key == "signed") {
227             signedStr = cols[COL_IDX_VALUE];
228         }
229     }
230 
231     std::string name = SplitNameFromTypeName(typeName);
232     std::string type = EraseNameFromTypeName(typeName, name); // for field type
233     fieldInfo.name = name;
234     fieldInfo.typeName = typeName;
235     fieldInfo.offset = atoi(offsetStr.c_str());
236     fieldInfo.size = atoi(sizeStr.c_str());
237     fieldInfo.isSigned = atoi(signedStr.c_str());
238 
239     ParseFieldType(type, fieldInfo);
240     ParseProtoType(fieldInfo);
241 
242     if (StringUtils::StartsWith(name, "common_")) {
243         ParseCommonFiledIndex(format.commonIndex, name, static_cast<int>(format.commonFields.size()));
244         format.commonFields.push_back(fieldInfo);
245     } else {
246         format.fields.push_back(fieldInfo);
247     }
248     return true;
249 }
250 
ParseSepcialIntType(FieldFormat& field, const std::string& type, const std::string& typeName)251 static bool ParseSepcialIntType(FieldFormat& field, const std::string& type, const std::string& typeName)
252 {
253     if (type == "bool") {
254         field.filedType = FIELD_TYPE_BOOL;
255         return true;
256     }
257 
258     if (type == "ino_t" || type == "i_ino") {
259         if (field.size == sizeof(uint32_t)) {
260             field.filedType = FIELD_TYPE_INODE32;
261             return true;
262         } else if (field.size == sizeof(uint64_t)) {
263             field.filedType = FIELD_TYPE_INODE64;
264             return true;
265         }
266     }
267 
268     if (type == "dev_t") {
269         if (field.size == sizeof(uint32_t)) {
270             field.filedType = FIELD_TYPE_DEVID32;
271             return true;
272         } else if (field.size == sizeof(uint64_t)) {
273             field.filedType = FIELD_TYPE_DEVID64;
274             return true;
275         }
276     }
277 
278     // Pids (as in 'sched_switch').
279     if (type == "pid_t") {
280         field.filedType = FIELD_TYPE_PID32;
281         return true;
282     }
283 
284     if ((typeName.find("common_pid") != std::string::npos)) {
285         field.filedType = FIELD_TYPE_COMMONPID32;
286         return true;
287     }
288     return false;
289 }
290 
ParseCommonIntType(FieldFormat& field, bool sign)291 static bool ParseCommonIntType(FieldFormat& field, bool sign)
292 {
293     switch (field.size) {
294         case sizeof(int8_t):
295             field.filedType = sign ? FIELD_TYPE_INT8 : FIELD_TYPE_UINT8;
296             return true;
297         case sizeof(int16_t):
298             field.filedType = sign ? FIELD_TYPE_INT16 : FIELD_TYPE_UINT16;
299             return true;
300         case sizeof(int32_t):
301             field.filedType = sign ? FIELD_TYPE_INT32 : FIELD_TYPE_UINT32;
302             return true;
303         case sizeof(int64_t):
304             field.filedType = sign ? FIELD_TYPE_INT64 : FIELD_TYPE_UINT64;
305             return true;
306         default:
307             break;
308     }
309     return false;
310 }
311 
ParseKernelAddrField(FieldFormat& field, const std::string& type)312 static bool ParseKernelAddrField(FieldFormat& field, const std::string& type)
313 {
314     if (type == "void*" || type == "void *") {
315         if (field.size == sizeof(uint64_t)) { // 64-bit kernel addresses
316             field.filedType = FIELD_TYPE_SYMADDR64;
317             return true;
318         } else if (field.size == sizeof(uint32_t)) { // 32-bit kernel addresses
319             field.filedType = FIELD_TYPE_SYMADDR32;
320             return true;
321         }
322     }
323     return false;
324 }
325 
ParseFieldType(const std::string& type, FieldFormat& field)326 bool FtraceParser::ParseFieldType(const std::string& type, FieldFormat& field)
327 {
328     const std::string& typeName = field.typeName;
329     // Fixed size C char arrary, likes "char a[LEN]"
330     if (std::regex_match(typeName, fixedCharArrayRegex_)) {
331         field.filedType = FIELD_TYPE_FIXEDCSTRING;
332         return true;
333     }
334 
335     // for flex array with __data_loc mark, likes: __data_loc char[] name; __data_loc __u8[] buf;
336     if (std::regex_match(typeName, flexDataLocArrayRegex_)) {
337         CHECK_TRUE(field.size == sizeof(uint32_t), false, "__data_loc %s, size: %hu", typeName.c_str(), field.size);
338         field.filedType = FIELD_TYPE_DATALOC;
339         return true;
340     }
341 
342     if ((typeName.find("char[]") != std::string::npos) || (typeName.find("char *") != std::string::npos)) {
343         field.filedType = FIELD_TYPE_STRINGPTR;
344         return true;
345     }
346 
347     // Variable length strings: "char foo" + size: 0 (as in 'print').
348     if ((type == "char" || type == "char []") && field.size == 0) {
349         field.filedType = FIELD_TYPE_CSTRING;
350         return true;
351     }
352 
353     // 64-bit kernel addresses
354     if (ParseKernelAddrField(field, type)) {
355         return true;
356     }
357 
358     if (ParseSepcialIntType(field, type, typeName)) {
359         return true;
360     }
361 
362     // int uint:
363     if (ParseCommonIntType(field, field.isSigned)) {
364         return true;
365     }
366     return false;
367 }
368 
ParseProtoType(FieldFormat& field)369 void FtraceParser::ParseProtoType(FieldFormat& field)
370 {
371     switch (field.filedType) {
372         case FIELD_TYPE_CSTRING:
373         case FIELD_TYPE_FIXEDCSTRING:
374         case FIELD_TYPE_STRINGPTR:
375         case FIELD_TYPE_DATALOC:
376             field.protoType = PROTO_TYPE_STRING;
377             break;
378         case FIELD_TYPE_INT8:
379         case FIELD_TYPE_INT16:
380         case FIELD_TYPE_INT32:
381         case FIELD_TYPE_PID32:
382         case FIELD_TYPE_COMMONPID32:
383             field.protoType = PROTO_TYPE_INT32;
384             break;
385         case FIELD_TYPE_INT64:
386             field.protoType = PROTO_TYPE_INT64;
387             break;
388         case FIELD_TYPE_UINT8:
389         case FIELD_TYPE_UINT16:
390         case FIELD_TYPE_UINT32:
391         case FIELD_TYPE_BOOL:
392         case FIELD_TYPE_DEVID32:
393         case FIELD_TYPE_SYMADDR32:
394             field.protoType = PROTO_TYPE_UINT32;
395             break;
396         case FIELD_TYPE_DEVID64:
397         case FIELD_TYPE_UINT64:
398         case FIELD_TYPE_INODE32:
399         case FIELD_TYPE_INODE64:
400         case FIELD_TYPE_SYMADDR64:
401             field.protoType = PROTO_TYPE_UINT64;
402             break;
403         case FIELD_TYPE_INVALID:
404             field.protoType = PROTO_TYPE_UNKNOWN;
405             break;
406         default:
407             break;
408     }
409 }
410 
ParsePerCpuStatus(PerCpuStats& stats, const std::string& perCpuStats)411 bool FtraceParser::ParsePerCpuStatus(PerCpuStats& stats, const std::string& perCpuStats)
412 {
413     std::string line;
414     std::stringstream input(perCpuStats);
415 
416     int count = 0;
417     while (getline(input, line, '\n')) {
418         std::string sep = ": ";
419         size_t pos = line.rfind(sep);
420         if (pos == std::string::npos) {
421             continue;
422         }
423         std::stringstream ss(line.substr(pos + sep.size()));
424         std::string name = line.substr(0, pos);
425         if (name == "entries") {
426             ss >> stats.entries;
427             count++;
428         } else if (name == "overrun") {
429             ss >> stats.overrun;
430             count++;
431         } else if (name == "commit overrun") {
432             ss >> stats.commitOverrun;
433             count++;
434         } else if (name == "bytes") {
435             ss >> stats.bytes;
436             count++;
437         } else if (name == "oldest event ts") {
438             ss >> stats.oldestEventTs;
439             count++;
440         } else if (name == "now ts") {
441             ss >> stats.nowTs;
442             count++;
443         } else if (name == "dropped events") {
444             ss >> stats.droppedEvents;
445             count++;
446         } else if (name == "read events") {
447             ss >> stats.readEvents;
448             count++;
449         }
450     }
451     return count > 0;
452 }
453 
454 // parse kernel ring buffer page header data
ParsePageHeader()455 bool FtraceParser::ParsePageHeader()
456 {
457     // read time stamp
458     uint64_t timestamp = 0;
459     CHECK_TRUE(ReadInc(&cur_, endOfPage_, &timestamp, sizeof(timestamp)), false, "read timestamp from page failed!");
460     pageHeader_.timestamp = timestamp;
461 
462     // read data size and overwriten flags
463     uint64_t commit = 0;
464     const int commitSize = GetHeaderPageCommitSize(); // 8B on 64bit device, 4B on 32bit device
465     CHECK_TRUE(ReadInc(&cur_, endOfPage_, &commit, commitSize), false, "read commit to page header failed!");
466 
467     // refers kernel function ring_buffer_page_len:
468     pageHeader_.size = (commit & ~RB_MISSED_FLAGS);
469     pageHeader_.overwrite = (commit & RB_MISSED_EVENTS);
470 
471     pageHeader_.startpos = cur_;
472     pageHeader_.endpos = cur_ + pageHeader_.size;
473     return true;
474 }
475 
476 // parse /sys/kernel/debug/tracing/saved_tgids
477 // refers kernel function saved_tgids_show
ParseSavedTgid(const std::string& savedTgid)478 bool FtraceParser::ParseSavedTgid(const std::string& savedTgid)
479 {
480     int32_t pid = 0;
481     int32_t tgid = 0;
482     std::stringstream sin(savedTgid);
483     // kernel format code with: "%d %d\n"
484     while (sin >> pid >> tgid) {
485         tgidDict_[pid] = tgid;
486     }
487 
488     if (tgidDict_.size() == 0) {
489         PROFILER_LOG_WARN(LOG_CORE, "ParseSavedTgid: parsed tigds: %zu", tgidDict_.size());
490     }
491     return true;
492 }
493 
494 // parse /sys/kernel/debug/tracing/saved_cmdlines
495 // refers kernel function saved_cmdlines_show
ParseSavedCmdlines(const std::string& savedCmdlines)496 bool FtraceParser::ParseSavedCmdlines(const std::string& savedCmdlines)
497 {
498     bool retval = false;
499     int32_t pid;
500     std::string comm;
501     std::string line;
502     std::stringstream sin(savedCmdlines);
503     while (std::getline(sin, line)) {
504         // kernel format with: "%d %s\n"
505         auto pos = line.find(' ');
506         if (pos != std::string::npos && pos < INT_MAX_LEN) {
507             auto pidStr = line.substr(0, pos);
508             pid = COMMON::IsNumeric(pidStr) ? std::stoi(pidStr) : 0;
509             comm = line.substr(pos + 1);
510             commDict_[pid] = comm;
511             retval = true;
512         }
513     }
514 
515     if (commDict_.size() == 0) {
516         PROFILER_LOG_WARN(LOG_CORE, "ParseSavedCmdlines: parsed cmdlines: %zu", commDict_.size());
517     }
518     return retval;
519 }
520 
ParsePaddingData(const FtraceEventHeader& eventHeader)521 bool FtraceParser::ParsePaddingData(const FtraceEventHeader& eventHeader)
522 {
523     if (eventHeader.timeDelta == 0) {
524         return false;
525     }
526     uint32_t paddingLength;
527     CHECK_TRUE(ReadInc(&cur_, endOfData_, &paddingLength, sizeof(paddingLength)), false, "read padding len failed!");
528 
529     // skip padding data
530     cur_ += paddingLength;
531     return true;
532 }
533 
ParseTimeExtend(const FtraceEventHeader& eventHeader)534 bool FtraceParser::ParseTimeExtend(const FtraceEventHeader& eventHeader)
535 {
536     uint32_t deltaExt = 0;
537     CHECK_TRUE(ReadInc(&cur_, endOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
538 
539     timestamp_ += GetTimestampIncrements(deltaExt);
540     PROFILER_LOG_INFO(LOG_CORE, "ParseTimeExtend: update ts with %u to %" PRIu64, deltaExt, timestamp_);
541     return true;
542 }
543 
ParseTimeStamp(const FtraceEventHeader& eventHeader)544 bool FtraceParser::ParseTimeStamp(const FtraceEventHeader& eventHeader)
545 {
546     uint32_t deltaExt = 0;
547     CHECK_TRUE(ReadInc(&cur_, endOfData_, &deltaExt, sizeof(deltaExt)), false, "read time delta failed!");
548 
549     // refers kernel function rb_update_write_stamp in ring_buffer.c
550     timestamp_ = eventHeader.timeDelta + GetTimestampIncrements(deltaExt);
551     PROFILER_LOG_INFO(LOG_CORE, "ParseTimeStamp: update ts with %u to %" PRIu64, deltaExt, timestamp_);
552     return true;
553 }
554 
ReadInc(uint8_t* start[], uint8_t end[], void* outData, size_t outSize)555 bool FtraceParser::ReadInc(uint8_t* start[], uint8_t end[], void* outData, size_t outSize)
556 {
557     if ((end - *start) < static_cast<ptrdiff_t>(outSize)) {
558         return false;
559     }
560     CHECK_TRUE(memcpy_s(outData, outSize, *start, outSize) == EOK, false,
561                "read %zu bytes from memory region FAILED", outSize);
562     *start += outSize;
563     return true;
564 }
565 
IsValidIndex(int idx)566 bool FtraceParser::IsValidIndex(int idx)
567 {
568     return idx != CommonFiledIndex::INVALID_IDX;
569 }
570 
SetDebugOn(bool value)571 void FtraceParser::SetDebugOn(bool value)
572 {
573     debugOn_ = value;
574     PROFILER_LOG_INFO(LOG_CORE, "debugOption: %s", debugOn_ ? "true" : "false");
575 }
576 FTRACE_NS_END
577