• 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 <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