1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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
16 #include "ebpf_data_reader.h"
17 #include <cinttypes>
18 #include "file_system_data_parser.h"
19 #include "string_help.h"
20
21 namespace SysTuning {
22 namespace TraceStreamer {
23 using namespace SysTuning::base;
24 using namespace SysTuning::EbpfStdtype;
EbpfDataReader(TraceDataCache * dataCache,const TraceStreamerFilters * filter)25 EbpfDataReader::EbpfDataReader(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
26 : EventParserBase(dataCache, filter),
27 ebpfDataHeader_(nullptr),
28 pidAndStartAddrToMapsAddr_(nullptr),
29 elfAddrAndStValueToSymAddr_(nullptr),
30 tracerEventToStrIndex_(INVALID_UINT64),
31 kernelFilePath_(traceDataCache_->GetDataIndex("/proc/kallsyms"))
32 {
33 }
InitEbpfData(const std::deque<uint8_t> & dequeBuffer,uint64_t size)34 bool EbpfDataReader::InitEbpfData(const std::deque<uint8_t>& dequeBuffer, uint64_t size)
35 {
36 buffer_ = std::make_unique<uint8_t[]>(size);
37 std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get());
38
39 startAddr_ = buffer_.get();
40 bufferSize_ = size;
41 unresolvedLen_ = size;
42 if (!InitEbpfHeader() || !ReadEbpfData()) {
43 return false;
44 }
45 return true;
46 }
47
InitEbpfHeader()48 bool EbpfDataReader::InitEbpfHeader()
49 {
50 if (bufferSize_ < EbpfDataHeader::EBPF_DATA_HEADER_SIZE) {
51 TS_LOGE("buffer size less than ebpf data header!!!, bufferSize_ = %" PRIu64 " ", bufferSize_);
52 return false;
53 }
54 ebpfDataHeader_ = reinterpret_cast<EbpfDataHeader*>(startAddr_);
55
56 if (ebpfDataHeader_->header.magic != EbpfDataHeader::HEADER_MAGIC) {
57 TS_LOGE("Get EBPF file header failed! magic = %" PRIx64 "", ebpfDataHeader_->header.magic);
58 return false;
59 }
60 if (ebpfDataHeader_->header.headSize != EbpfDataHeader::EBPF_DATA_HEADER_SIZE) {
61 TS_LOGE("Get ebpf file header failed! headSize = %u", ebpfDataHeader_->header.headSize);
62 return false;
63 }
64 TS_LOGI("EBPF data header : magic = %" PRIu64 ", headSize = %u, clock = %u, cmdline = %s",
65 ebpfDataHeader_->header.magic, ebpfDataHeader_->header.headSize, ebpfDataHeader_->header.clock,
66 ebpfDataHeader_->cmdline);
67 startAddr_ += EbpfDataHeader::EBPF_DATA_HEADER_SIZE;
68 unresolvedLen_ -= EbpfDataHeader::EBPF_DATA_HEADER_SIZE;
69 return true;
70 }
71
EbpfTypeHandle(EbpfTypeAndLength * dataTitle,const uint8_t * startAddr_)72 bool EbpfDataReader::EbpfTypeHandle(EbpfTypeAndLength* dataTitle, const uint8_t* startAddr_)
73 {
74 bool ret = true;
75 switch (dataTitle->type) {
76 case ITEM_EVENT_MAPS: {
77 ret = ReadItemEventMaps(startAddr_, dataTitle->length);
78 break;
79 }
80 case ITEM_SYMBOL_INFO: {
81 ret = ReadItemSymbolInfo(startAddr_, dataTitle->length);
82 break;
83 }
84 case ITEM_EVENT_FS: {
85 ret = ReadItemEventFs(startAddr_, dataTitle->length);
86 break;
87 }
88 case ITEM_EVENT_VM: {
89 ret = ReadItemEventPagedMemory(startAddr_, dataTitle->length);
90 break;
91 }
92 case ITEM_EVENT_BIO: {
93 ret = ReadItemEventBIO(startAddr_, dataTitle->length);
94 break;
95 }
96 case ITEM_EVENT_STR: {
97 ret = ReadItemEventStr(startAddr_, dataTitle->length);
98 break;
99 }
100 case ITEM_EVENT_KENEL_SYMBOL_INFO: {
101 ret = ReaItemKernelSymbolInfo(startAddr_, dataTitle->length);
102 break;
103 }
104 default:
105 TS_LOGI("Do not support EBPF type: %d, length: %d", dataTitle->type, dataTitle->length);
106 }
107 return ret;
108 }
109
ReadEbpfData()110 bool EbpfDataReader::ReadEbpfData()
111 {
112 while (unresolvedLen_ > EBPF_TITLE_SIZE) {
113 EbpfTypeAndLength* dataTitle = reinterpret_cast<EbpfTypeAndLength*>(startAddr_);
114 startAddr_ += EBPF_TITLE_SIZE;
115 unresolvedLen_ -= EBPF_TITLE_SIZE;
116 if (dataTitle->length > unresolvedLen_) {
117 TS_LOGE("Get EBPF data Title failed!");
118 TS_LOGE("type = %x, length = %x", dataTitle->type, dataTitle->length);
119 return false;
120 }
121 if (dataTitle->length == 0) {
122 continue;
123 }
124
125 auto ret = EbpfTypeHandle(dataTitle, startAddr_);
126 if (!ret) {
127 return false;
128 }
129
130 startAddr_ += dataTitle->length;
131 unresolvedLen_ -= dataTitle->length;
132 }
133 return true;
134 }
135
ReadItemEventMaps(const uint8_t * buffer,uint32_t size)136 bool EbpfDataReader::ReadItemEventMaps(const uint8_t* buffer, uint32_t size)
137 {
138 if (size < sizeof(MapsFixedHeader)) {
139 TS_LOGE("get maps addr Failed!!!");
140 return false;
141 }
142 auto procMapsAddr = reinterpret_cast<const MapsFixedHeader*>(buffer);
143 pidAndStartAddrToMapsAddr_.Insert(procMapsAddr->pid, procMapsAddr->start, procMapsAddr);
144 return true;
145 }
146 template <class T>
AddSymbolsToTable(T * firstSymbolAddr,const int size,const ElfEventFixedHeader * elfAddr)147 void EbpfDataReader::AddSymbolsToTable(T* firstSymbolAddr, const int size, const ElfEventFixedHeader* elfAddr)
148 {
149 for (auto i = 0; i < size; i++) {
150 auto symAddr = firstSymbolAddr + i;
151 if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) {
152 elfAddrAndStValueToSymAddr_.Insert(elfAddr, symAddr->st_value, reinterpret_cast<const uint8_t*>(symAddr));
153 }
154 }
155 }
UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader * elfAddr,uint32_t size)156 void EbpfDataReader::UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size)
157 {
158 if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) {
159 TS_LOGE("elf addr size error!!!");
160 return;
161 }
162 auto symEntLen = elfAddr->symEntLen;
163 auto symTabHeadAddr = reinterpret_cast<const uint8_t*>(elfAddr + 1) + elfAddr->strTabLen;
164 if (symEntLen == ELF32_SYM) {
165 AddSymbolsToTable(reinterpret_cast<const Elf32_Sym*>(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr);
166 } else {
167 AddSymbolsToTable(reinterpret_cast<const Elf64_Sym*>(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr);
168 }
169 }
ReadKernelSymAddrMap(const KernelSymbolInfoHeader * elfAddr,uint32_t size)170 void EbpfDataReader::ReadKernelSymAddrMap(const KernelSymbolInfoHeader* elfAddr, uint32_t size)
171 {
172 if (size < sizeof(KernelSymbolInfoHeader) + elfAddr->symTabLen + elfAddr->strTabLen) {
173 TS_LOGE("elf addr size error!!!, size is:%u and the symTabLen is:%u, strTabLen is:%u", size, elfAddr->symTabLen,
174 elfAddr->strTabLen);
175 return;
176 }
177 auto symTabLen = elfAddr->symTabLen;
178 auto sysItemSize = symTabLen / sizeof(KernelSymItem);
179 auto start = reinterpret_cast<const KernelSymItem*>(elfAddr + 1);
180 auto strTab = reinterpret_cast<const char*>(start + sysItemSize);
181 maxKernelAddr_ = elfAddr->vaddrEnd;
182 minKernelAddr_ = elfAddr->vaddrStart;
183 for (uint32_t i = 0; i < sysItemSize; i++) {
184 (void)memset_s(strSymbolName_, MAX_SYMBOL_LENGTH, 0, MAX_SYMBOL_LENGTH);
185 auto item = start + i;
186 if (strncpy_s(strSymbolName_, MAX_SYMBOL_LENGTH, strTab + item->nameOffset, MAX_SYMBOL_LENGTH) < 0) {
187 TS_LOGE("get kernel symbol name error");
188 }
189 AddrDesc desc{item->size, traceDataCache_->dataDict_.GetStringIndex(strSymbolName_)};
190 kernelSymbolMap_.insert(std::make_pair(item->value, desc));
191 }
192 }
193
UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader * elfAddr,uint32_t size)194 void EbpfDataReader::UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size)
195 {
196 if ((elfAddr->fileNameLen > size - sizeof(ElfEventFixedHeader) - elfAddr->strTabLen - elfAddr->symTabLen) ||
197 !elfAddr->fileNameLen) {
198 TS_LOGE("elf filename len is error!!!");
199 return;
200 }
201
202 uint64_t fileNameIndex = INVALID_UINT64;
203 auto fileNameAddr = const_cast<char*>(reinterpret_cast<const char*>(reinterpret_cast<const uint8_t*>(elfAddr + 1) +
204 elfAddr->strTabLen + elfAddr->symTabLen));
205 fileNameAddr[elfAddr->fileNameLen - 1] = '\0';
206 fileNameIndex = traceDataCache_->GetDataIndex(std::string(fileNameAddr));
207 elfPathIndexToElfFixedHeaderAddr_.insert(std::make_pair(fileNameIndex, elfAddr));
208 }
209
ReadItemSymbolInfo(const uint8_t * buffer,uint32_t size)210 bool EbpfDataReader::ReadItemSymbolInfo(const uint8_t* buffer, uint32_t size)
211 {
212 if (size < sizeof(ElfEventFixedHeader)) {
213 TS_LOGE("get symbol addr failed!!!");
214 return false;
215 }
216 auto elfAddr = reinterpret_cast<const ElfEventFixedHeader*>(buffer);
217 UpdateElfAddrAndStValueToSymAddrMap(elfAddr, size);
218 UpdateElfPathIndexToElfAddrMap(elfAddr, size);
219 return true;
220 }
221
ReaItemKernelSymbolInfo(const uint8_t * buffer,uint32_t size)222 bool EbpfDataReader::ReaItemKernelSymbolInfo(const uint8_t* buffer, uint32_t size)
223 {
224 if (size < sizeof(KernelSymbolInfoHeader)) {
225 TS_LOGE("get symbol addr failed!!!");
226 return false;
227 }
228 auto elfAddr = reinterpret_cast<const KernelSymbolInfoHeader*>(buffer);
229 ReadKernelSymAddrMap(elfAddr, size);
230 return true;
231 }
ReadItemEventFs(const uint8_t * buffer,uint32_t size)232 bool EbpfDataReader::ReadItemEventFs(const uint8_t* buffer, uint32_t size)
233 {
234 if (size < sizeof(FsFixedHeader)) {
235 TS_LOGE("get file system event addr failed!!!");
236 return false;
237 }
238 auto fsFixedHeaderAddr = reinterpret_cast<const FsFixedHeader*>(buffer);
239 endTsToFsFixedHeader_.insert(std::make_pair(fsFixedHeaderAddr->endTime, fsFixedHeaderAddr));
240 return true;
241 }
242
ReadItemEventPagedMemory(const uint8_t * buffer,uint32_t size)243 bool EbpfDataReader::ReadItemEventPagedMemory(const uint8_t* buffer, uint32_t size)
244 {
245 if (size < sizeof(PagedMemoryFixedHeader)) {
246 TS_LOGE("get page memory event addr failed!!!");
247 return false;
248 }
249 auto pagedMemoryFixedHeaderAddr = reinterpret_cast<const PagedMemoryFixedHeader*>(buffer);
250 endTsToPagedMemoryFixedHeader_.insert(
251 std::make_pair(pagedMemoryFixedHeaderAddr->endTime, pagedMemoryFixedHeaderAddr));
252 return true;
253 }
254
ReadItemEventBIO(const uint8_t * buffer,uint32_t size)255 bool EbpfDataReader::ReadItemEventBIO(const uint8_t* buffer, uint32_t size)
256 {
257 if (size < sizeof(BIOFixedHeader)) {
258 TS_LOGE("get Block IO event addr failed!!!");
259 return false;
260 }
261 auto bioFixedHeaderAddr = reinterpret_cast<const BIOFixedHeader*>(buffer);
262 endTsToBIOFixedHeader_.insert(std::make_pair(bioFixedHeaderAddr->endTime, bioFixedHeaderAddr));
263 return true;
264 }
265
ReadItemEventStr(const uint8_t * buffer,uint32_t size)266 bool EbpfDataReader::ReadItemEventStr(const uint8_t* buffer, uint32_t size)
267 {
268 if (size < sizeof(StrEventFixedHeader)) {
269 TS_LOGE("get str event addr failed!!!");
270 return false;
271 }
272 auto strFixedHeaderAddr = reinterpret_cast<const StrEventFixedHeader*>(buffer);
273 auto itid =
274 streamFilters_->processFilter_->GetOrCreateThreadWithPid(strFixedHeaderAddr->tid, strFixedHeaderAddr->pid);
275 auto strAddr = const_cast<char*>(reinterpret_cast<const char*>(strFixedHeaderAddr + 1));
276 if ((strFixedHeaderAddr->strLen > size - sizeof(StrEventFixedHeader)) || !strFixedHeaderAddr->strLen) {
277 TS_LOGE("invalid str event, strEventFixedHeader = %zu, strlen = %d, size = %d", sizeof(StrEventFixedHeader),
278 strFixedHeaderAddr->strLen, size);
279 return true;
280 }
281 strAddr[strFixedHeaderAddr->strLen - 1] = '\0';
282 auto strIndex = traceDataCache_->GetDataIndex(strAddr);
283 tracerEventToStrIndex_.Insert(strFixedHeaderAddr->srcTracer, strFixedHeaderAddr->srcType, itid,
284 strFixedHeaderAddr->startTime, strIndex);
285 return true;
286 }
287
GetTracerEventToStrIndexMap()288 QuatraMap<uint32_t, uint32_t, uint32_t, uint64_t, DataIndex>& EbpfDataReader::GetTracerEventToStrIndexMap()
289 {
290 return tracerEventToStrIndex_;
291 }
292
GetSymbolNameIndexFromElfSym(uint64_t ip)293 EbpfSymbolInfo EbpfDataReader::GetSymbolNameIndexFromElfSym(uint64_t ip)
294 {
295 EbpfSymbolInfo ebpfSymbolInfo(false);
296 auto end = kernelSymbolMap_.upper_bound(ip);
297 auto length = std::distance(kernelSymbolMap_.begin(), end);
298 if (length > 0) {
299 end--;
300 // Follow the rules of front closing and rear opening, [start, end)
301 if (ip < end->first + end->second.size) {
302 ebpfSymbolInfo.flag = true;
303 ebpfSymbolInfo.symbolIndex = end->second.name;
304 ebpfSymbolInfo.filePathIndex = kernelFilePath_;
305 } else {
306 TS_LOGD("failed for ip:%" PRIu64 ", kernelip:%" PRIu64 ", size:%" PRIu64 "", ip, end->first,
307 end->second.size);
308 }
309 }
310 if (!ebpfSymbolInfo.flag) {
311 TS_LOGD("failed for ip:%" PRIu64 "", ip);
312 }
313 return ebpfSymbolInfo;
314 }
GetPidAndStartAddrToMapsAddr() const315 const DoubleMap<uint32_t, uint64_t, const MapsFixedHeader*>& EbpfDataReader::GetPidAndStartAddrToMapsAddr() const
316 {
317 return pidAndStartAddrToMapsAddr_;
318 }
319
320 const DoubleMap<const ElfEventFixedHeader*, uint64_t, const uint8_t*>&
GetElfAddrAndStartValueToSymAddr() const321 EbpfDataReader::GetElfAddrAndStartValueToSymAddr() const
322 {
323 return elfAddrAndStValueToSymAddr_;
324 }
325
GetFileSystemEventMap() const326 const std::multimap<uint64_t, const FsFixedHeader*>& EbpfDataReader::GetFileSystemEventMap() const
327 {
328 return endTsToFsFixedHeader_;
329 }
330
GetPagedMemoryMap() const331 const std::multimap<uint64_t, const PagedMemoryFixedHeader*>& EbpfDataReader::GetPagedMemoryMap() const
332 {
333 return endTsToPagedMemoryFixedHeader_;
334 }
335
GetBIOSampleMap() const336 const std::multimap<uint64_t, const BIOFixedHeader*>& EbpfDataReader::GetBIOSampleMap() const
337 {
338 return endTsToBIOFixedHeader_;
339 }
340
GetElfPathIndexToElfAddr() const341 const std::map<DataIndex, const ElfEventFixedHeader*>& EbpfDataReader::GetElfPathIndexToElfAddr() const
342 {
343 return elfPathIndexToElfFixedHeaderAddr_;
344 }
GetEbpfDataHeader() const345 const EbpfDataHeader* EbpfDataReader::GetEbpfDataHeader() const
346 {
347 return const_cast<const EbpfDataHeader*>(ebpfDataHeader_);
348 }
349 } // namespace TraceStreamer
350 } // namespace SysTuning
351