• 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 
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     bool ParseSavedCmdlines(const std::string& savedCmdlines);
86 
87     void SetDebugOn(bool value);
88 
HmParseFtraceEvent(T & ftraceEvent,uint8_t data[],size_t dataSize,P & parseEventCtx)89     template <typename T, typename P> bool HmParseFtraceEvent(T& ftraceEvent, uint8_t data[],
90             size_t dataSize, P& parseEventCtx)
91     {
92         return ParseFtraceEvent(ftraceEvent, data, dataSize, parseEventCtx);
93     }
94 
95 private:
96     int GetHeaderPageCommitSize(void);
97     bool ParseHeaderPageFormat(const std::string& formatDesc);
98     bool ParseEventFormat(const std::string& formatDesc, EventFormat& format);
99     bool ParseFieldFormat(const std::string& fieldLine, EventFormat& format);
100     bool ParseFieldType(const std::string& type, FieldFormat& field);
101     static void ParseProtoType(FieldFormat& field);
102 
103     bool ParsePageHeader();
104 
105     // parse different page types
106     bool ParsePaddingData(const FtraceEventHeader& eventHeader);
107     bool ParseTimeExtend(const FtraceEventHeader& eventHeader);
108     bool ParseTimeStamp(const FtraceEventHeader& eventHeader);
109 
110     template <typename T, typename E>
ParseDataRecord(const FtraceEventHeader & eventHeader,T & ftraceCpuDetailMsg,E * event)111     bool ParseDataRecord(const FtraceEventHeader& eventHeader, T& ftraceCpuDetailMsg, E* event)
112     {
113         uint32_t evtSize = 0;
114         // refers comments of kernel function rb_event_data_length:
115         if (eventHeader.typeLen) {
116             evtSize = sizeof(eventHeader.array[0]) * eventHeader.typeLen;
117         } else {
118             CHECK_TRUE(ReadInc(&cur_, endOfData_, &evtSize, sizeof(evtSize)), false, "read event size failed!");
119             if (evtSize < sizeof(uint32_t)) {
120                 return false;
121             }
122             evtSize -= sizeof(uint32_t); // array[0] is length, array[1...array[0]] is event data
123         }
124 
125         uint8_t* evStart = cur_;
126         uint8_t* evEnd = cur_ + evtSize;
127         uint16_t evId = 0;
128         CHECK_TRUE(ReadInc(&cur_, evEnd, &evId, sizeof(evId)), false, "read event ID failed!");
129 
130         uint32_t eventId = evId;
131         auto* parseEventCtx = SubEventParser<E>::GetInstance().GetParseEventCtx(eventId);
132         if (parseEventCtx != nullptr) {
133             auto* ftraceEvent = ftraceCpuDetailMsg.add_event();
134             ftraceEvent->set_timestamp(timestamp_);
135             parseEventCtx->format.osVersion = osVersion_;
136             ParseFtraceEvent(*ftraceEvent, evStart, evtSize, parseEventCtx);
137         }
138 
139         cur_ = evEnd;
140         return true;
141     }
142 
143     template <typename T, typename P>  // P: SubEventParser<FtraceEvent>::ParseEventCtx
ParseFtraceEvent(T & ftraceEvent,uint8_t data[],size_t dataSize,P & parseEventCtx)144     bool ParseFtraceEvent(T& ftraceEvent, uint8_t data[], size_t dataSize, P& parseEventCtx)
145     {
146         CHECK_TRUE(
147             dataSize >= parseEventCtx->format.eventSize, false,
148             "FtraceParser::ParseFtraceEvent, dataSize not enough! event name is %s,eventSize is %u, dataSize is %zd",
149             parseEventCtx->format.eventName.c_str(), parseEventCtx->format.eventSize, dataSize);
150 
151         int pid = 0;
152         CHECK_TRUE(ParseFtraceCommonFields(ftraceEvent, data, dataSize, parseEventCtx->format, pid),
153                    false, "parse common fields failed!");
154         if (pid != 0) {
155             int tgid = 0;
156             if (auto it = tgidDict_.find(pid); it != tgidDict_.end()) {
157                 tgid = it->second;
158                 ftraceEvent.set_tgid(tgid);
159             } else {
160                 ParseSavedTgid(FtraceFsOps::GetInstance().GetSavedTgids());
161                 if (auto itm = tgidDict_.find(pid); itm != tgidDict_.end()) {
162                     tgid = itm->second;
163                     ftraceEvent.set_tgid(tgid);
164                 }
165             }
166 
167             std::string comm;
168             if (auto it = commDict_.find(pid); it != commDict_.end()) {
169                 comm = it->second;
170             } else {
171                 if (tgid != 0) {
172                     comm = FtraceFsOps::GetInstance().GetThreadComm(tgid, pid);
173                 } else {
174                     comm = FtraceFsOps::GetInstance().GetProcessComm(pid);
175                 }
176                 if (comm.size() > 0) {
177                     comm.pop_back(); // /proc/xxx/comm end with `\n`
178                     commDict_.insert(std::pair<int32_t, std::string>(pid, comm));
179                 }
180             }
181             if (comm.size() > 0) {
182                 ftraceEvent.set_comm(comm);
183             }
184         }
185 
186         SubEventParser<T>::GetInstance().ParseEvent(ftraceEvent, data, dataSize, parseEventCtx);
187         return true;
188     }
189 
190     template <typename T>
ParseFtraceCommonFields(T & ftraceEvent,uint8_t data[],size_t dataSize,const EventFormat & format,int & pid)191     bool ParseFtraceCommonFields(T& ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat& format, int& pid)
192     {
193         auto& index = format.commonIndex;
194 
195         CHECK_TRUE(IsValidIndex(index.pid), false, "pid index %d invalid!", index.pid);
196         CHECK_TRUE(IsValidIndex(index.type), false, "type index %d invalid!", index.type);
197         CHECK_TRUE(IsValidIndex(index.flags), false, "flags index %d invalid!", index.flags);
198         CHECK_TRUE(IsValidIndex(index.preemt), false, "preemt index %d invalid!", index.preemt);
199 
200         auto& fields = format.commonFields;
201         auto commonFields = ftraceEvent.mutable_common_fields();
202         pid = FtraceFieldParser::ParseIntField<int32_t>(fields, index.pid, data, dataSize);
203         commonFields->set_pid(pid);
204         commonFields->set_type(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.type, data, dataSize));
205         commonFields->set_flags(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.flags, data, dataSize));
206         commonFields->set_preempt_count(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.preemt,
207                                                                                    data, dataSize));
208         return true;
209     }
210 
211     bool ReadInc(uint8_t* start[], uint8_t end[], void* outData, size_t outSize);
212     bool IsValidIndex(int idx);
213 
214 private:
215     DISALLOW_COPY_AND_MOVE(FtraceParser);
216     bool debugOn_ = false;
217     std::regex fixedCharArrayRegex_;
218     std::regex flexDataLocArrayRegex_;
219     PageHeaderFormat pageHeaderFormat_ = {};
220     std::string savedTgidPath_ = "";
221     std::string savedCmdlines_ = "";
222 
223     uint8_t* cur_ = nullptr;
224     uint8_t* page_ = nullptr;      // page start
225     uint8_t* endOfData_ = nullptr; // end of event data
226     uint8_t* endOfPage_ = nullptr; // end of full page
227     uint64_t timestamp_ = 0;
228     std::string osVersion_ = "";
229     PageHeader pageHeader_ = {};
230 
231     std::unordered_map<int32_t, int32_t> tgidDict_ = {};
232     std::unordered_map<int32_t, std::string> commDict_ = {};
233 };
234 FTRACE_NS_END
235 #endif
236