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