• 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 define
16  */
17 #ifndef FTRACE_EVENT_CONTAINER_H
18 #define FTRACE_EVENT_CONTAINER_H
19 #include <cinttypes>
20 #include <memory>
21 #include <regex>
22 #include <string>
23 #include <vector>
24 #include <unordered_set>
25 #include "logging.h"
26 #include "ftrace_common_type.h"
27 #include "ftrace_field_parser.h"
28 #include "ftrace_fs_ops.h"
29 #include "printk_formats_parser.h"
30 #include "sub_event_parser.h"
31 
32 FTRACE_NS_BEGIN
33 class FtraceParser {
34 public:
35     FtraceParser();
36     ~FtraceParser();
37 
38     bool Init();
39     bool SetupEvent(const std::string& type, const std::string& name);
40 
41     bool ParsePerCpuStatus(PerCpuStats& stats, const std::string& perCpuStats);
42 
ParsePage(T & ftraceCpuDetailMsg,uint8_t page[],size_t size,E * ftraceEvent)43     template <typename T, typename E> bool ParsePage(T& ftraceCpuDetailMsg, uint8_t page[], size_t size, E* ftraceEvent)
44     {
45         cur_ = page;
46         page_ = page;
47         endOfPage_ = page + size;
48 
49         CHECK_TRUE(ParsePageHeader(), false, "parse page header fail!");
50         ftraceCpuDetailMsg.set_overwrite(pageHeader_.overwrite);
51 
52         timestamp_ = pageHeader_.timestamp;
53         endOfData_ = pageHeader_.endpos;
54         while (cur_ < pageHeader_.endpos) {
55             FtraceEventHeader eventHeader = {};
56             CHECK_TRUE(ReadInc(&cur_, endOfData_, &eventHeader, sizeof(FtraceEventHeader)), false,
57                        "read EventHeader fail!");
58 
59             timestamp_ += eventHeader.timeDelta;
60 
61             bool retval = false;
62             switch (eventHeader.typeLen) {
63                 case BUFFER_TYPE_PADDING:
64                     retval = ParsePaddingData(eventHeader);
65                     CHECK_TRUE(retval, false, "parse PADDING data failed!");
66                     break;
67                 case BUFFER_TYPE_TIME_EXTEND:
68                     retval = ParseTimeExtend(eventHeader);
69                     CHECK_TRUE(retval, false, "parse TIME_EXTEND failed!");
70                     break;
71                 case BUFFER_TYPE_TIME_STAMP:
72                     retval = ParseTimeStamp(eventHeader);
73                     CHECK_TRUE(retval, false, "parse TIME_STAMP failed!");
74                     break;
75                 default:
76                     retval = ParseDataRecord(eventHeader, ftraceCpuDetailMsg, ftraceEvent);
77                     CHECK_TRUE(retval, false, "parse record data failed!");
78                     break;
79             }
80         }
81         return true;
82     }
83 
84     bool ParseSavedTgid(const std::string& savedTgid);
85     void ParseTargetedSavedTgid(const std::string& savedTgid, int targetPid);
86     bool ParseSavedCmdlines(const std::string& savedCmdlines);
87 
88     void SetDebugOn(bool value);
89 
HmParseFtraceEvent(T & ftraceEvent,uint8_t data[],size_t dataSize,P & parseEventCtx)90     template <typename T, typename P> bool HmParseFtraceEvent(T& ftraceEvent, uint8_t data[],
91             size_t dataSize, P& parseEventCtx)
92     {
93         return ParseFtraceEvent(ftraceEvent, data, dataSize, parseEventCtx);
94     }
95 
ParseTidGid()96     void ParseTidGid()
97     {
98         ParseSavedTgid(FtraceFsOps::GetInstance().GetSavedTgids());
99     }
100 
101 private:
102     int GetHeaderPageCommitSize(void);
103     bool ParseHeaderPageFormat(const std::string& formatDesc);
104     bool ParseEventFormat(const std::string& formatDesc, EventFormat& format);
105     bool ParseFieldFormat(const std::string& fieldLine, EventFormat& format);
106     bool ParseFieldType(const std::string& type, FieldFormat& field);
107     static void ParseProtoType(FieldFormat& field);
108 
109     bool ParsePageHeader();
110 
111     // parse different page types
112     bool ParsePaddingData(const FtraceEventHeader& eventHeader);
113     bool ParseTimeExtend(const FtraceEventHeader& eventHeader);
114     bool ParseTimeStamp(const FtraceEventHeader& eventHeader);
115 
116     template <typename T, typename E>
ParseDataRecord(const FtraceEventHeader & eventHeader,T & ftraceCpuDetailMsg,E * event)117     bool ParseDataRecord(const FtraceEventHeader& eventHeader, T& ftraceCpuDetailMsg, E* event)
118     {
119         uint32_t evtSize = 0;
120         // refers comments of kernel function rb_event_data_length:
121         if (eventHeader.typeLen) {
122             evtSize = sizeof(eventHeader.array[0]) * eventHeader.typeLen;
123         } else {
124             CHECK_TRUE(ReadInc(&cur_, endOfData_, &evtSize, sizeof(evtSize)), false, "read event size failed!");
125             if (evtSize < sizeof(uint32_t)) {
126                 return false;
127             }
128             evtSize -= sizeof(uint32_t); // array[0] is length, array[1...array[0]] is event data
129         }
130 
131         uint8_t* evStart = cur_;
132         uint8_t* evEnd = cur_ + evtSize;
133         uint16_t evId = 0;
134         CHECK_TRUE(ReadInc(&cur_, evEnd, &evId, sizeof(evId)), false, "read event ID failed!");
135 
136         uint32_t eventId = evId;
137         auto* parseEventCtx = SubEventParser<E>::GetInstance().GetParseEventCtx(eventId);
138         if (parseEventCtx != nullptr) {
139             auto* ftraceEvent = ftraceCpuDetailMsg.add_event();
140             ftraceEvent->set_timestamp(timestamp_);
141             parseEventCtx->format.osVersion = osVersion_;
142             ParseFtraceEvent(*ftraceEvent, evStart, evtSize, parseEventCtx);
143         }
144 
145         cur_ = evEnd;
146         return true;
147     }
148 
149     template <typename T, typename P>  // P: SubEventParser<FtraceEvent>::ParseEventCtx
ParseFtraceEvent(T & ftraceEvent,uint8_t data[],size_t dataSize,P & parseEventCtx)150     bool ParseFtraceEvent(T& ftraceEvent, uint8_t data[], size_t dataSize, P& parseEventCtx)
151     {
152         CHECK_TRUE(
153             dataSize >= parseEventCtx->format.eventSize, false,
154             "FtraceParser::ParseFtraceEvent, dataSize not enough! event name is %s,eventSize is %u, dataSize is %zd",
155             parseEventCtx->format.eventName.c_str(), parseEventCtx->format.eventSize, dataSize);
156 
157         int pid = 0;
158         CHECK_TRUE(ParseFtraceCommonFields(ftraceEvent, data, dataSize, parseEventCtx->format, pid),
159                    false, "parse common fields failed!");
160         if (pid != 0) {
161             int tgid = 0;
162             if (tgidDict_.count(pid) > 0) {
163                 tgid = tgidDict_[pid];
164             } else {
165                 int tgid = FtraceFsOps::GetInstance().GetTgidFromStatus(pid);
166                 if (tgid == -1) {
167                     tgid = 0;
168                     ParseTargetedSavedTgid(FtraceFsOps::GetInstance().GetSavedTgids(), pid);
169                     auto itm = tgidDict_.find(pid);
170                     if (itm != tgidDict_.end()) {
171                         tgid = itm->second;
172                     }
173                 } else {
174                     tgidDict_[pid] = tgid;
175                 }
176             }
177             ftraceEvent.set_tgid(tgid);
178             std::string comm;
179             if (auto it = commDict_.find(pid); it != commDict_.end()) {
180                 comm = it->second;
181             } else {
182                 if (tgid != 0) {
183                     comm = FtraceFsOps::GetInstance().GetThreadComm(tgid, pid);
184                 } else {
185                     comm = FtraceFsOps::GetInstance().GetProcessComm(pid);
186                 }
187                 if (comm.size() > 0) {
188                     comm.pop_back(); // /proc/xxx/comm end with `\n`
189                     commDict_.insert(std::pair<int32_t, std::string>(pid, comm));
190                 }
191             }
192             if (comm.size() > 0) {
193                 ftraceEvent.set_comm(comm);
194             }
195         }
196 
197         SubEventParser<T>::GetInstance().ParseEvent(ftraceEvent, data, dataSize, parseEventCtx);
198         return true;
199     }
200 
201     template <typename T>
ParseFtraceCommonFields(T & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format,int & pid)202     bool ParseFtraceCommonFields(T& ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat& format, int& pid)
203     {
204         auto& index = format.commonIndex;
205 
206         CHECK_TRUE(IsValidIndex(index.pid), false, "pid index %d invalid!", index.pid);
207         CHECK_TRUE(IsValidIndex(index.type), false, "type index %d invalid!", index.type);
208         CHECK_TRUE(IsValidIndex(index.flags), false, "flags index %d invalid!", index.flags);
209         CHECK_TRUE(IsValidIndex(index.preemt), false, "preemt index %d invalid!", index.preemt);
210 
211         auto& fields = format.commonFields;
212         auto commonFields = ftraceEvent.mutable_common_fields();
213         pid = FtraceFieldParser::ParseIntField<int32_t>(fields, index.pid, data, dataSize);
214         commonFields->set_pid(pid);
215         commonFields->set_type(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.type, data, dataSize));
216         commonFields->set_flags(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.flags, data, dataSize));
217         commonFields->set_preempt_count(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.preemt,
218                                                                                    data, dataSize));
219         return true;
220     }
221 
222     bool ReadInc(uint8_t* start[], uint8_t end[], void* outData, size_t outSize);
223     bool IsValidIndex(int idx);
224 
225 private:
226     DISALLOW_COPY_AND_MOVE(FtraceParser);
227     bool debugOn_ = false;
228     std::regex fixedCharArrayRegex_;
229     std::regex flexDataLocArrayRegex_;
230     PageHeaderFormat pageHeaderFormat_ = {};
231     std::string savedTgidPath_ = "";
232     std::string savedCmdlines_ = "";
233 
234     uint8_t* cur_ = nullptr;
235     uint8_t* page_ = nullptr;      // page start
236     uint8_t* endOfData_ = nullptr; // end of event data
237     uint8_t* endOfPage_ = nullptr; // end of full page
238     uint64_t timestamp_ = 0;
239     std::string osVersion_ = "";
240     PageHeader pageHeader_ = {};
241 
242     std::unordered_map<int32_t, int32_t> tgidDict_ = {};
243     std::unordered_map<int32_t, std::string> commDict_ = {};
244 };
245 FTRACE_NS_END
246 #endif
247