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