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             ParseFtraceEvent(*ftraceEvent, evStart, evtSize, parseEventCtx);
136         }
137 
138         cur_ = evEnd;
139         return true;
140     }
141 
142     template <typename T, typename P>  // P: SubEventParser<FtraceEvent>::ParseEventCtx
ParseFtraceEvent(T& ftraceEvent, uint8_t data[], size_t dataSize, P& parseEventCtx)143     bool ParseFtraceEvent(T& ftraceEvent, uint8_t data[], size_t dataSize, P& parseEventCtx)
144     {
145         CHECK_TRUE(
146             dataSize >= parseEventCtx->format.eventSize, false,
147             "FtraceParser::ParseFtraceEvent, dataSize not enough! event name is %s,eventSize is %u, dataSize is %zd",
148             parseEventCtx->format.eventName.c_str(), parseEventCtx->format.eventSize, dataSize);
149 
150         int pid = 0;
151         CHECK_TRUE(ParseFtraceCommonFields(ftraceEvent, data, dataSize, parseEventCtx->format, pid),
152                    false, "parse common fields failed!");
153         if (pid != 0) {
154             int tgid = 0;
155             if (auto it = tgidDict_.find(pid); it != tgidDict_.end()) {
156                 tgid = it->second;
157                 ftraceEvent.set_tgid(tgid);
158             } else {
159                 ParseSavedTgid(FtraceFsOps::GetInstance().GetSavedTgids());
160                 if (auto itm = tgidDict_.find(pid); itm != tgidDict_.end()) {
161                     tgid = itm->second;
162                     ftraceEvent.set_tgid(tgid);
163                 }
164             }
165 
166             std::string comm;
167             if (auto it = commDict_.find(pid); it != commDict_.end()) {
168                 comm = it->second;
169             } else {
170                 if (tgid != 0) {
171                     comm = FtraceFsOps::GetInstance().GetThreadComm(tgid, pid);
172                 } else {
173                     comm = FtraceFsOps::GetInstance().GetProcessComm(pid);
174                 }
175                 if (comm.size() > 0) {
176                     comm.pop_back(); // /proc/xxx/comm end with `\n`
177                     commDict_.insert(std::pair<int32_t, std::string>(pid, comm));
178                 }
179             }
180             if (comm.size() > 0) {
181                 ftraceEvent.set_comm(comm);
182             }
183         }
184 
185         SubEventParser<T>::GetInstance().ParseEvent(ftraceEvent, data, dataSize, parseEventCtx);
186         return true;
187     }
188 
189     template <typename T>
ParseFtraceCommonFields(T& ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat& format, int& pid)190     bool ParseFtraceCommonFields(T& ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat& format, int& pid)
191     {
192         auto& index = format.commonIndex;
193 
194         CHECK_TRUE(IsValidIndex(index.pid), false, "pid index %d invalid!", index.pid);
195         CHECK_TRUE(IsValidIndex(index.type), false, "type index %d invalid!", index.type);
196         CHECK_TRUE(IsValidIndex(index.flags), false, "flags index %d invalid!", index.flags);
197         CHECK_TRUE(IsValidIndex(index.preemt), false, "preemt index %d invalid!", index.preemt);
198 
199         auto& fields = format.commonFields;
200         auto commonFields = ftraceEvent.mutable_common_fields();
201         pid = FtraceFieldParser::ParseIntField<int32_t>(fields, index.pid, data, dataSize);
202         commonFields->set_pid(pid);
203         commonFields->set_type(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.type, data, dataSize));
204         commonFields->set_flags(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.flags, data, dataSize));
205         commonFields->set_preempt_count(FtraceFieldParser::ParseIntField<uint32_t>(fields, index.preemt,
206                                                                                    data, dataSize));
207         return true;
208     }
209 
210     bool ReadInc(uint8_t* start[], uint8_t end[], void* outData, size_t outSize);
211     bool IsValidIndex(int idx);
212 
213 private:
214     DISALLOW_COPY_AND_MOVE(FtraceParser);
215     bool debugOn_ = false;
216     std::regex fixedCharArrayRegex_;
217     std::regex flexDataLocArrayRegex_;
218     PageHeaderFormat pageHeaderFormat_ = {};
219     std::string savedTgidPath_ = "";
220     std::string savedCmdlines_ = "";
221 
222     uint8_t* cur_ = nullptr;
223     uint8_t* page_ = nullptr;      // page start
224     uint8_t* endOfData_ = nullptr; // end of event data
225     uint8_t* endOfPage_ = nullptr; // end of full page
226     uint64_t timestamp_ = 0;
227     PageHeader pageHeader_ = {};
228 
229     std::unordered_map<int32_t, int32_t> tgidDict_ = {};
230     std::unordered_map<int32_t, std::string> commDict_ = {};
231 };
232 FTRACE_NS_END
233 #endif
234