• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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