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