/* * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ebpf_data_reader.h" #include #include "file_system_data_parser.h" #include "string_help.h" namespace SysTuning { namespace TraceStreamer { using namespace SysTuning::base; using namespace SysTuning::EbpfStdtype; EbpfDataReader::EbpfDataReader(TraceDataCache *dataCache, const TraceStreamerFilters *filter) : EventParserBase(dataCache, filter), ebpfDataHeader_(nullptr), pidAndStartAddrToMapsAddr_(nullptr), elfAddrAndStValueToSymAddr_(nullptr), tracerEventToStrIndex_(INVALID_UINT64), kernelFilePath_(traceDataCache_->GetDataIndex("/proc/kallsyms")) { } bool EbpfDataReader::InitEbpfData(const std::deque &dequeBuffer, uint64_t size) { buffer_ = std::make_unique(size); std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get()); startAddr_ = buffer_.get(); bufferSize_ = size; unresolvedLen_ = size; if (!InitEbpfHeader() || !ReadEbpfData()) { return false; } return true; } bool EbpfDataReader::InitEbpfHeader() { if (bufferSize_ < EbpfDataHeader::EBPF_DATA_HEADER_SIZE) { TS_LOGE("buffer size less than ebpf data header!!!, bufferSize_ = %" PRIu64 " ", bufferSize_); return false; } ebpfDataHeader_ = reinterpret_cast(startAddr_); if (ebpfDataHeader_->header.magic != EbpfDataHeader::HEADER_MAGIC) { TS_LOGE("Get EBPF file header failed! magic = %" PRIx64 "", ebpfDataHeader_->header.magic); return false; } if (ebpfDataHeader_->header.headSize != EbpfDataHeader::EBPF_DATA_HEADER_SIZE) { TS_LOGE("Get ebpf file header failed! headSize = %u", ebpfDataHeader_->header.headSize); return false; } TS_LOGI("EBPF data header : magic = %" PRIu64 ", headSize = %u, clock = %u, cmdline = %s", ebpfDataHeader_->header.magic, ebpfDataHeader_->header.headSize, ebpfDataHeader_->header.clock, ebpfDataHeader_->cmdline); startAddr_ += EbpfDataHeader::EBPF_DATA_HEADER_SIZE; unresolvedLen_ -= EbpfDataHeader::EBPF_DATA_HEADER_SIZE; return true; } bool EbpfDataReader::EbpfTypeHandle(EbpfTypeAndLength *dataTitle, const uint8_t *startAddr) { bool ret = true; switch (dataTitle->type) { case ITEM_EVENT_MAPS: { ret = ReadItemEventMaps(startAddr, dataTitle->length); break; } case ITEM_SYMBOL_INFO: { ret = ReadItemSymbolInfo(startAddr, dataTitle->length); break; } case ITEM_EVENT_FS: { ret = ReadItemEventFs(startAddr, dataTitle->length); break; } case ITEM_EVENT_VM: { ret = ReadItemEventPagedMemory(startAddr, dataTitle->length); break; } case ITEM_EVENT_BIO: { ret = ReadItemEventBIO(startAddr, dataTitle->length); break; } case ITEM_EVENT_STR: { ret = ReadItemEventStr(startAddr, dataTitle->length); break; } case ITEM_EVENT_KENEL_SYMBOL_INFO: { ret = ReaItemKernelSymbolInfo(startAddr, dataTitle->length); break; } default: TS_LOGI("Do not support EBPF type: %d, length: %d", dataTitle->type, dataTitle->length); } return ret; } bool EbpfDataReader::ReadEbpfData() { while (unresolvedLen_ > EBPF_TITLE_SIZE) { EbpfTypeAndLength *dataTitle = reinterpret_cast(startAddr_); startAddr_ += EBPF_TITLE_SIZE; unresolvedLen_ -= EBPF_TITLE_SIZE; if (dataTitle->length > unresolvedLen_) { TS_LOGE("Get EBPF data Title failed!"); TS_LOGE("type = %x, length = %x", dataTitle->type, dataTitle->length); return false; } if (dataTitle->length == 0) { continue; } auto ret = EbpfTypeHandle(dataTitle, startAddr_); if (!ret) { return false; } startAddr_ += dataTitle->length; unresolvedLen_ -= dataTitle->length; } return true; } bool EbpfDataReader::ReadItemEventMaps(const uint8_t *buffer, uint32_t size) { if (size < sizeof(MapsFixedHeader)) { TS_LOGE("get maps addr Failed!!!"); return false; } auto procMapsAddr = reinterpret_cast(buffer); pidAndStartAddrToMapsAddr_.Insert(procMapsAddr->pid, procMapsAddr->start, procMapsAddr); return true; } template void EbpfDataReader::AddSymbolsToTable(T *firstSymbolAddr, const int size, const ElfEventFixedHeader *elfAddr) { for (auto i = 0; i < size; i++) { auto symAddr = firstSymbolAddr + i; if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) { elfAddrAndStValueToSymAddr_.Insert(elfAddr, symAddr->st_value, reinterpret_cast(symAddr)); } } } void EbpfDataReader::UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader *elfAddr, uint32_t size) { if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) { TS_LOGE("elf addr size error!!!"); return; } auto symEntLen = elfAddr->symEntLen; auto symTabHeadAddr = reinterpret_cast(elfAddr + 1) + elfAddr->strTabLen; if (symEntLen == ELF32_SYM) { AddSymbolsToTable(reinterpret_cast(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr); } else { AddSymbolsToTable(reinterpret_cast(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr); } } void EbpfDataReader::ReadKernelSymAddrMap(const KernelSymbolInfoHeader *elfAddr, uint32_t size) { if (size < sizeof(KernelSymbolInfoHeader) + elfAddr->symTabLen + elfAddr->strTabLen) { TS_LOGE("elf addr size error!!!, size is:%u and the symTabLen is:%u, strTabLen is:%u", size, elfAddr->symTabLen, elfAddr->strTabLen); return; } auto symTabLen = elfAddr->symTabLen; auto sysItemSize = symTabLen / sizeof(KernelSymItem); auto start = reinterpret_cast(elfAddr + 1); auto strTab = reinterpret_cast(start + sysItemSize); maxKernelAddr_ = elfAddr->vaddrEnd; minKernelAddr_ = elfAddr->vaddrStart; for (uint32_t i = 0; i < sysItemSize; i++) { (void)memset_s(strSymbolName_, maxSymbolLength, 0, maxSymbolLength); auto item = start + i; if (strncpy_s(strSymbolName_, maxSymbolLength, strTab + item->nameOffset, maxSymbolLength) < 0) { TS_LOGE("get kernel symbol name error"); } AddrDesc desc{item->size, traceDataCache_->dataDict_.GetStringIndex(strSymbolName_)}; kernelSymbolMap_.insert(std::make_pair(item->value, desc)); } } void EbpfDataReader::UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader *elfAddr, uint32_t size) { if ((elfAddr->fileNameLen > size - sizeof(ElfEventFixedHeader) - elfAddr->strTabLen - elfAddr->symTabLen) || !elfAddr->fileNameLen) { TS_LOGE("elf filename len is error!!!"); return; } uint64_t fileNameIndex = INVALID_UINT64; auto fileNameAddr = const_cast(reinterpret_cast( reinterpret_cast(elfAddr + 1) + elfAddr->strTabLen + elfAddr->symTabLen)); fileNameAddr[elfAddr->fileNameLen - 1] = '\0'; fileNameIndex = traceDataCache_->GetDataIndex(std::string(fileNameAddr)); elfPathIndexToElfFixedHeaderAddr_.insert(std::make_pair(fileNameIndex, elfAddr)); } bool EbpfDataReader::ReadItemSymbolInfo(const uint8_t *buffer, uint32_t size) { if (size < sizeof(ElfEventFixedHeader)) { TS_LOGE("get symbol addr failed!!!"); return false; } auto elfAddr = reinterpret_cast(buffer); UpdateElfAddrAndStValueToSymAddrMap(elfAddr, size); UpdateElfPathIndexToElfAddrMap(elfAddr, size); return true; } bool EbpfDataReader::ReaItemKernelSymbolInfo(const uint8_t *buffer, uint32_t size) { if (size < sizeof(KernelSymbolInfoHeader)) { TS_LOGE("get symbol addr failed!!!"); return false; } auto elfAddr = reinterpret_cast(buffer); ReadKernelSymAddrMap(elfAddr, size); return true; } bool EbpfDataReader::ReadItemEventFs(const uint8_t *buffer, uint32_t size) { if (size < sizeof(FsFixedHeader)) { TS_LOGE("get file system event addr failed!!!"); return false; } auto fsFixedHeaderAddr = reinterpret_cast(buffer); endTsToFsFixedHeader_.insert(std::make_pair(fsFixedHeaderAddr->endTime, fsFixedHeaderAddr)); return true; } bool EbpfDataReader::ReadItemEventPagedMemory(const uint8_t *buffer, uint32_t size) { if (size < sizeof(PagedMemoryFixedHeader)) { TS_LOGE("get page memory event addr failed!!!"); return false; } auto pagedMemoryFixedHeaderAddr = reinterpret_cast(buffer); endTsToPagedMemoryFixedHeader_.insert( std::make_pair(pagedMemoryFixedHeaderAddr->endTime, pagedMemoryFixedHeaderAddr)); return true; } bool EbpfDataReader::ReadItemEventBIO(const uint8_t *buffer, uint32_t size) { if (size < sizeof(BIOFixedHeader)) { TS_LOGE("get Block IO event addr failed!!!"); return false; } auto bioFixedHeaderAddr = reinterpret_cast(buffer); endTsToBIOFixedHeader_.insert(std::make_pair(bioFixedHeaderAddr->endTime, bioFixedHeaderAddr)); return true; } bool EbpfDataReader::ReadItemEventStr(const uint8_t *buffer, uint32_t size) { if (size < sizeof(StrEventFixedHeader)) { TS_LOGE("get str event addr failed!!!"); return false; } auto strFixedHeaderAddr = reinterpret_cast(buffer); auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(strFixedHeaderAddr->tid, strFixedHeaderAddr->pid); auto strAddr = const_cast(reinterpret_cast(strFixedHeaderAddr + 1)); if ((strFixedHeaderAddr->strLen > size - sizeof(StrEventFixedHeader)) || !strFixedHeaderAddr->strLen) { TS_LOGE("invalid str event, strEventFixedHeader = %zu, strlen = %d, size = %d", sizeof(StrEventFixedHeader), strFixedHeaderAddr->strLen, size); return true; } strAddr[strFixedHeaderAddr->strLen - 1] = '\0'; auto strIndex = traceDataCache_->GetDataIndex(strAddr); tracerEventToStrIndex_.Insert(strFixedHeaderAddr->srcTracer, strFixedHeaderAddr->srcType, itid, strFixedHeaderAddr->startTime, strIndex); return true; } QuatraMap &EbpfDataReader::GetTracerEventToStrIndexMap() { return tracerEventToStrIndex_; } EbpfSymbolInfo EbpfDataReader::GetSymbolNameIndexFromElfSym(uint64_t ip) { EbpfSymbolInfo ebpfSymbolInfo(false); auto end = kernelSymbolMap_.upper_bound(ip); auto length = std::distance(kernelSymbolMap_.begin(), end); if (length > 0) { end--; // Follow the rules of front closing and rear opening, [start, end) if (ip < end->first + end->second.size) { ebpfSymbolInfo.flag = true; ebpfSymbolInfo.symbolIndex = end->second.name; ebpfSymbolInfo.filePathIndex = kernelFilePath_; } else { TS_LOGD("failed for ip:%" PRIu64 ", kernelip:%" PRIu64 ", size:%" PRIu64 "", ip, end->first, end->second.size); } } if (!ebpfSymbolInfo.flag) { TS_LOGD("failed for ip:%" PRIu64 "", ip); } return ebpfSymbolInfo; } const DoubleMap &EbpfDataReader::GetPidAndStartAddrToMapsAddr() const { return pidAndStartAddrToMapsAddr_; } const EbpfDataReader::ElfDoubleMap &EbpfDataReader::GetElfAddrAndStartValueToSymAddr() const { return elfAddrAndStValueToSymAddr_; } const std::multimap &EbpfDataReader::GetFileSystemEventMap() const { return endTsToFsFixedHeader_; } const std::multimap &EbpfDataReader::GetPagedMemoryMap() const { return endTsToPagedMemoryFixedHeader_; } const std::multimap &EbpfDataReader::GetBIOSampleMap() const { return endTsToBIOFixedHeader_; } const std::map &EbpfDataReader::GetElfPathIndexToElfAddr() const { return elfPathIndexToElfFixedHeaderAddr_; } const EbpfDataHeader *EbpfDataReader::GetEbpfDataHeader() const { return const_cast(ebpfDataHeader_); } } // namespace TraceStreamer } // namespace SysTuning