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 "file_system_data_parser.h"
18 #include "string_help.h"
19 #include <cinttypes>
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
ReadEbpfData()72 bool EbpfDataReader::ReadEbpfData()
73 {
74 while (unresolvedLen_ > EBPF_TITLE_SIZE) {
75 EbpfTypeAndLength* dataTitle = reinterpret_cast<EbpfTypeAndLength*>(startAddr_);
76 startAddr_ += EBPF_TITLE_SIZE;
77 unresolvedLen_ -= EBPF_TITLE_SIZE;
78 if (dataTitle->length > unresolvedLen_) {
79 TS_LOGE("Get EBPF data Title failed!");
80 TS_LOGE("type = %x, length = %x", dataTitle->type, dataTitle->length);
81 return false;
82 }
83 if (dataTitle->length == 0) {
84 continue;
85 }
86
87 bool ret = true;
88 switch (dataTitle->type) {
89 case ITEM_EVENT_MAPS: {
90 ret = ReadItemEventMaps(startAddr_, dataTitle->length);
91 break;
92 }
93 case ITEM_SYMBOL_INFO: {
94 ret = ReadItemSymbolInfo(startAddr_, dataTitle->length);
95 break;
96 }
97 case ITEM_EVENT_FS: {
98 ret = ReadItemEventFs(startAddr_, dataTitle->length);
99 break;
100 }
101 case ITEM_EVENT_VM: {
102 ret = ReadItemEventPagedMemory(startAddr_, dataTitle->length);
103 break;
104 }
105 case ITEM_EVENT_BIO: {
106 ret = ReadItemEventBIO(startAddr_, dataTitle->length);
107 break;
108 }
109 case ITEM_EVENT_STR: {
110 ret = ReadItemEventStr(startAddr_, dataTitle->length);
111 break;
112 }
113 case ITEM_EVENT_KENEL_SYMBOL_INFO: {
114 ret = ReaItemKernelSymbolInfo(startAddr_, dataTitle->length);
115 break;
116 }
117 default:
118 TS_LOGI("Do not support EBPF type: %d, length: %d", dataTitle->type, dataTitle->length);
119 }
120 if (!ret) {
121 return false;
122 }
123 startAddr_ += dataTitle->length;
124 unresolvedLen_ -= dataTitle->length;
125 }
126 return true;
127 }
128
ReadItemEventMaps(const uint8_t * buffer,uint32_t size)129 bool EbpfDataReader::ReadItemEventMaps(const uint8_t* buffer, uint32_t size)
130 {
131 if (size < sizeof(MapsFixedHeader)) {
132 TS_LOGE("get maps addr Failed!!!");
133 return false;
134 }
135 auto procMapsAddr = reinterpret_cast<const MapsFixedHeader*>(buffer);
136 pidAndStartAddrToMapsAddr_.Insert(procMapsAddr->pid, procMapsAddr->start, procMapsAddr);
137 #if WITH_EBPF_HELP
138 if ((procMapsAddr->fileNameLen > size - sizeof(MapsFixedHeader)) || !procMapsAddr->fileNameLen) {
139 TS_LOGE("maps fileNameLen error!!!");
140 return false;
141 }
142 auto fileNameAddr = const_cast<char*>(reinterpret_cast<const char*>(procMapsAddr + 1));
143 fileNameAddr[procMapsAddr->fileNameLen - 1] = '\0';
144 auto fileNameIndex = traceDataCache_->GetDataIndex(fileNameAddr);
145
146 // add proc Maps Data
147 traceDataCache_->GetEbpfProcessMaps()->AppendNewData(procMapsAddr->start, procMapsAddr->end, procMapsAddr->offset,
148 procMapsAddr->pid, procMapsAddr->fileNameLen, fileNameIndex);
149 #endif
150 return true;
151 }
152 template <class T>
AddSymbolsToTable(T * firstSymbolAddr,const int size,const ElfEventFixedHeader * elfAddr)153 void EbpfDataReader::AddSymbolsToTable(T* firstSymbolAddr, const int size, const ElfEventFixedHeader* elfAddr)
154 {
155 for (auto i = 0; i < size; i++) {
156 auto symAddr = firstSymbolAddr + i;
157 if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) {
158 elfAddrAndStValueToSymAddr_.Insert(elfAddr, symAddr->st_value, reinterpret_cast<const uint8_t*>(symAddr));
159 }
160 }
161 }
UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader * elfAddr,uint32_t size)162 void EbpfDataReader::UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size)
163 {
164 if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) {
165 TS_LOGE("elf addr size error!!!");
166 return;
167 }
168 auto symEntLen = elfAddr->symEntLen;
169 auto symTabHeadAddr = reinterpret_cast<const uint8_t*>(elfAddr + 1) + elfAddr->strTabLen;
170 if (symEntLen == ELF32_SYM) {
171 AddSymbolsToTable(reinterpret_cast<const Elf32_Sym*>(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr);
172 } else {
173 AddSymbolsToTable(reinterpret_cast<const Elf64_Sym*>(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr);
174 }
175 }
ReadKernelSymAddrMap(const KernelSymbolInfoHeader * elfAddr,uint32_t size)176 void EbpfDataReader::ReadKernelSymAddrMap(const KernelSymbolInfoHeader* elfAddr, uint32_t size)
177 {
178 if (size < sizeof(KernelSymbolInfoHeader) + elfAddr->symTabLen + elfAddr->strTabLen) {
179 TS_LOGE("elf addr size error!!!, size is:%u and the symTabLen is:%u, strTabLen is:%u", size, elfAddr->symTabLen,
180 elfAddr->strTabLen);
181 return;
182 }
183 auto symTabLen = elfAddr->symTabLen;
184 auto sysItemSize = symTabLen / sizeof(KernelSymItem);
185 auto start = reinterpret_cast<const KernelSymItem*>(elfAddr + 1);
186 auto strTab = reinterpret_cast<const char*>(start + sysItemSize);
187 maxKernelAddr_ = elfAddr->vaddrEnd;
188 minKernelAddr_ = elfAddr->vaddrStart;
189 for (uint32_t i = 0; i < sysItemSize; i++) {
190 (void)memset_s(strSymbolName_, MAX_SYMBOL_LENGTH, 0, MAX_SYMBOL_LENGTH);
191 auto item = start + i;
192 if (strncpy_s(strSymbolName_, MAX_SYMBOL_LENGTH, strTab + item->nameOffset, MAX_SYMBOL_LENGTH) < 0) {
193 TS_LOGE("get kernel symbol name error");
194 }
195 AddrDesc desc{item->size, traceDataCache_->dataDict_.GetStringIndex(strSymbolName_)};
196 kernelSymbolMap_.insert(std::make_pair(item->value, desc));
197 }
198 }
199
UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader * elfAddr,uint32_t size)200 void EbpfDataReader::UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size)
201 {
202 if ((elfAddr->fileNameLen > size - sizeof(ElfEventFixedHeader) - elfAddr->strTabLen - elfAddr->symTabLen) ||
203 !elfAddr->fileNameLen) {
204 TS_LOGE("elf filename len is error!!!");
205 return;
206 }
207
208 uint64_t fileNameIndex = INVALID_UINT64;
209 auto fileNameAddr = const_cast<char*>(reinterpret_cast<const char*>(reinterpret_cast<const uint8_t*>(elfAddr + 1) +
210 elfAddr->strTabLen + elfAddr->symTabLen));
211 fileNameAddr[elfAddr->fileNameLen - 1] = '\0';
212 fileNameIndex = traceDataCache_->GetDataIndex(std::string(fileNameAddr));
213 elfPathIndexToElfFixedHeaderAddr_.insert(std::make_pair(fileNameIndex, elfAddr));
214
215 #if WITH_EBPF_HELP
216 // add Elf symbol Data
217 traceDataCache_->GetEbpfElf()->AppendNewData(elfId_, elfAddr->textVaddr, elfAddr->textOffset, elfAddr->strTabLen,
218 elfAddr->symTabLen, elfAddr->fileNameLen, elfAddr->symEntLen,
219 fileNameIndex);
220 #endif
221 }
222
223 #if WITH_EBPF_HELP
224 template <class T>
AppendSymbolsToTable(T * firstSymbolAddr,const int size)225 void EbpfDataReader::AppendSymbolsToTable(T* firstSymbolAddr, const int size)
226 {
227 for (auto i = 0; i < size; i++) {
228 auto symAddr = firstSymbolAddr + i;
229 if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) {
230 traceDataCache_->GetEbpfElfSymbol()->AppendNewData(elfId_, symAddr->st_name, symAddr->st_value,
231 symAddr->st_size);
232 }
233 }
234 }
UpdateEbpfElfSymbolTable(const ElfEventFixedHeader * elfAddr,uint32_t size)235 void EbpfDataReader::UpdateEbpfElfSymbolTable(const ElfEventFixedHeader* elfAddr, uint32_t size)
236 {
237 if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) {
238 TS_LOGE("elf addr size error!!!");
239 return;
240 }
241 auto symEntLen = elfAddr->symEntLen;
242 if (symEntLen == ELF32_SYM) {
243 AppendSymbolsToTable(
244 reinterpret_cast<const Elf32_Sym*>(reinterpret_cast<const uint8_t*>(elfAddr + 1) + elfAddr->strTabLen),
245 elfAddr->symTabLen / symEntLen);
246 } else {
247 AppendSymbolsToTable(
248 reinterpret_cast<const Elf64_Sym*>(reinterpret_cast<const uint8_t*>(elfAddr + 1) + elfAddr->strTabLen),
249 elfAddr->symTabLen / symEntLen);
250 }
251 }
252 #endif
253
ReadItemSymbolInfo(const uint8_t * buffer,uint32_t size)254 bool EbpfDataReader::ReadItemSymbolInfo(const uint8_t* buffer, uint32_t size)
255 {
256 if (size < sizeof(ElfEventFixedHeader)) {
257 TS_LOGE("get symbol addr failed!!!");
258 return false;
259 }
260 auto elfAddr = reinterpret_cast<const ElfEventFixedHeader*>(buffer);
261 UpdateElfAddrAndStValueToSymAddrMap(elfAddr, size);
262 UpdateElfPathIndexToElfAddrMap(elfAddr, size);
263 #if WITH_EBPF_HELP
264 UpdateEbpfElfSymbolTable(elfAddr, size);
265 elfId_++;
266 #endif
267 return true;
268 }
269
ReaItemKernelSymbolInfo(const uint8_t * buffer,uint32_t size)270 bool EbpfDataReader::ReaItemKernelSymbolInfo(const uint8_t* buffer, uint32_t size)
271 {
272 if (size < sizeof(KernelSymbolInfoHeader)) {
273 TS_LOGE("get symbol addr failed!!!");
274 return false;
275 }
276 auto elfAddr = reinterpret_cast<const KernelSymbolInfoHeader*>(buffer);
277 ReadKernelSymAddrMap(elfAddr, size);
278 return true;
279 }
ReadItemEventFs(const uint8_t * buffer,uint32_t size)280 bool EbpfDataReader::ReadItemEventFs(const uint8_t* buffer, uint32_t size)
281 {
282 if (size < sizeof(FsFixedHeader)) {
283 TS_LOGE("get file system event addr failed!!!");
284 return false;
285 }
286 auto fsFixedHeaderAddr = reinterpret_cast<const FsFixedHeader*>(buffer);
287 endTsToFsFixedHeader_.insert(std::make_pair(fsFixedHeaderAddr->endTime, fsFixedHeaderAddr));
288 return true;
289 }
290
ReadItemEventPagedMemory(const uint8_t * buffer,uint32_t size)291 bool EbpfDataReader::ReadItemEventPagedMemory(const uint8_t* buffer, uint32_t size)
292 {
293 if (size < sizeof(PagedMemoryFixedHeader)) {
294 TS_LOGE("get page memory event addr failed!!!");
295 return false;
296 }
297 auto pagedMemoryFixedHeaderAddr = reinterpret_cast<const PagedMemoryFixedHeader*>(buffer);
298 endTsToPagedMemoryFixedHeader_.insert(
299 std::make_pair(pagedMemoryFixedHeaderAddr->endTime, pagedMemoryFixedHeaderAddr));
300 return true;
301 }
302
ReadItemEventBIO(const uint8_t * buffer,uint32_t size)303 bool EbpfDataReader::ReadItemEventBIO(const uint8_t* buffer, uint32_t size)
304 {
305 if (size < sizeof(BIOFixedHeader)) {
306 TS_LOGE("get Block IO event addr failed!!!");
307 return false;
308 }
309 auto bioFixedHeaderAddr = reinterpret_cast<const BIOFixedHeader*>(buffer);
310 endTsToBIOFixedHeader_.insert(std::make_pair(bioFixedHeaderAddr->endTime, bioFixedHeaderAddr));
311 return true;
312 }
313
ReadItemEventStr(const uint8_t * buffer,uint32_t size)314 bool EbpfDataReader::ReadItemEventStr(const uint8_t* buffer, uint32_t size)
315 {
316 if (size < sizeof(StrEventFixedHeader)) {
317 TS_LOGE("get str event addr failed!!!");
318 return false;
319 }
320 auto strFixedHeaderAddr = reinterpret_cast<const StrEventFixedHeader*>(buffer);
321 auto itid =
322 streamFilters_->processFilter_->GetOrCreateThreadWithPid(strFixedHeaderAddr->tid, strFixedHeaderAddr->pid);
323 auto strAddr = const_cast<char*>(reinterpret_cast<const char*>(strFixedHeaderAddr + 1));
324 if ((strFixedHeaderAddr->strLen > size - sizeof(StrEventFixedHeader)) || !strFixedHeaderAddr->strLen) {
325 TS_LOGE("invalid str event, strEventFixedHeader = %zu, strlen = %d, size = %d", sizeof(StrEventFixedHeader),
326 strFixedHeaderAddr->strLen, size);
327 return true;
328 }
329 strAddr[strFixedHeaderAddr->strLen - 1] = '\0';
330 auto strIndex = traceDataCache_->GetDataIndex(strAddr);
331 tracerEventToStrIndex_.Insert(strFixedHeaderAddr->srcTracer, strFixedHeaderAddr->srcType, itid,
332 strFixedHeaderAddr->startTime, strIndex);
333 return true;
334 }
335
GetTracerEventToStrIndexMap()336 QuatraMap<uint32_t, uint32_t, uint32_t, uint64_t, DataIndex>& EbpfDataReader::GetTracerEventToStrIndexMap()
337 {
338 return tracerEventToStrIndex_;
339 }
340
GetSymbolNameIndexFromElfSym(uint64_t ip)341 SymbolAndFilePathIndex EbpfDataReader::GetSymbolNameIndexFromElfSym(uint64_t ip)
342 {
343 SymbolAndFilePathIndex symbolAndFilePathIndex(false);
344 auto end = kernelSymbolMap_.upper_bound(ip);
345 auto length = std::distance(kernelSymbolMap_.begin(), end);
346 if (length > 0) {
347 end--;
348 // Follow the rules of front closing and rear opening, [start, end)
349 if (ip < end->first + end->second.size) {
350 symbolAndFilePathIndex.flag = true;
351 symbolAndFilePathIndex.symbolIndex = end->second.name;
352 symbolAndFilePathIndex.filePathIndex = kernelFilePath_;
353 } else {
354 TS_LOGD("failed for ip:%lu, kernelip:%lu, size:%lu", ip, end->first, end->second.size);
355 }
356 }
357 if (!symbolAndFilePathIndex.flag) {
358 TS_LOGD("failed for ip:%lu", ip);
359 }
360 return symbolAndFilePathIndex;
361 }
GetPidAndStartAddrToMapsAddr() const362 const DoubleMap<uint32_t, uint64_t, const MapsFixedHeader*>& EbpfDataReader::GetPidAndStartAddrToMapsAddr() const
363 {
364 return pidAndStartAddrToMapsAddr_;
365 }
366
367 const DoubleMap<const ElfEventFixedHeader*, uint64_t, const uint8_t*>&
GetElfAddrAndStartValueToSymAddr() const368 EbpfDataReader::GetElfAddrAndStartValueToSymAddr() const
369 {
370 return elfAddrAndStValueToSymAddr_;
371 }
372
GetFileSystemEventMap() const373 const std::multimap<uint64_t, const FsFixedHeader*>& EbpfDataReader::GetFileSystemEventMap() const
374 {
375 return endTsToFsFixedHeader_;
376 }
377
GetPagedMemoryMap() const378 const std::multimap<uint64_t, const PagedMemoryFixedHeader*>& EbpfDataReader::GetPagedMemoryMap() const
379 {
380 return endTsToPagedMemoryFixedHeader_;
381 }
382
GetBIOSampleMap() const383 const std::multimap<uint64_t, const BIOFixedHeader*>& EbpfDataReader::GetBIOSampleMap() const
384 {
385 return endTsToBIOFixedHeader_;
386 }
387
GetElfPathIndexToElfAddr() const388 const std::map<DataIndex, const ElfEventFixedHeader*>& EbpfDataReader::GetElfPathIndexToElfAddr() const
389 {
390 return elfPathIndexToElfFixedHeaderAddr_;
391 }
GetEbpfDataHeader() const392 const EbpfDataHeader* EbpfDataReader::GetEbpfDataHeader() const
393 {
394 return const_cast<const EbpfDataHeader*>(ebpfDataHeader_);
395 }
396 } // namespace TraceStreamer
397 } // namespace SysTuning
398