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