• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 #include "ebpf_base.h"
16 
17 namespace SysTuning {
18 namespace TraceStreamer {
EbpfBase(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)19 EbpfBase::EbpfBase(TraceDataCache *dataCache, const TraceStreamerFilters *ctx)
20     : EventParserBase(dataCache, ctx),
21       pidAndIpToEbpfSymbolInfo_(EbpfSymbolInfo(false)),
22       filePathIndexAndStValueToSymAddr_(nullptr),
23       pidAndipsToCallId_(INVALID_UINT32)
24 {
25 }
~EbpfBase()26 EbpfBase::~EbpfBase()
27 {
28     pidAndipsToCallId_.Clear();
29     pidAndIpToEbpfSymbolInfo_.Clear();
30     filePathIndexToPidAndIpMap_.clear();
31     filePathIndexAndStValueToSymAddr_.Clear();
32 }
InitEbpfDataParser(EbpfDataReader * reader)33 bool EbpfBase::InitEbpfDataParser(EbpfDataReader *reader)
34 {
35     auto clockId = reader->GetEbpfDataHeader()->header.clock;
36     auto itor = ebpfToTSClockType_.find(clockId);
37     if (itor == ebpfToTSClockType_.end()) {
38         return false;
39     }
40     clockId_ = ebpfToTSClockType_.at(clockId);
41     reader_ = std::move(reader);
42     return true;
43 }
44 
ParseCallStackData(const uint64_t * userIpsAddr,uint16_t count,uint32_t pid,uint32_t callId)45 void EbpfBase::ParseCallStackData(const uint64_t *userIpsAddr, uint16_t count, uint32_t pid, uint32_t callId)
46 {
47     uint32_t depth = 0;
48     for (auto i = count - 1; i >= 0; i--) {
49         if (userIpsAddr[i] <= MIN_USER_IP) {
50             continue;
51         }
52         auto ebpfSymbolInfo = GetEbpfSymbolInfo(pid, userIpsAddr[i]);
53         auto ipIndex = ConvertToHexTextIndex(userIpsAddr[i]);
54         ipStrIndexToIpMap_.insert(std::make_pair(ipIndex, userIpsAddr[i]));
55         EbpfCallStackDataRow ebpfCallStackDataRow = {
56             callId, depth++, ipIndex, ebpfSymbolInfo.symbolIndex, ebpfSymbolInfo.filePathIndex, ebpfSymbolInfo.vaddr};
57         auto row = traceDataCache_->GetEbpfCallStack()->AppendNewData(ebpfCallStackDataRow);
58         if (ebpfSymbolInfo.filePathIndex == INVALID_UINT64) {
59             continue;
60         }
61         if (filePathIndexToCallStackRowMap_.count(ebpfSymbolInfo.filePathIndex) == 0) {
62             auto rows = std::make_shared<std::set<size_t>>();
63             rows->insert(row);
64             filePathIndexToCallStackRowMap_[ebpfSymbolInfo.filePathIndex] = rows;
65         } else {
66             filePathIndexToCallStackRowMap_[ebpfSymbolInfo.filePathIndex]->insert(row);
67         }
68     }
69     // Only one successful insertion is required, without considering repeated insertion failures
70     callIdToPid_.insert(std::make_pair(callId, pid));
71 }
72 
GetEbpfSymbolInfo(uint32_t pid,uint64_t ip)73 EbpfSymbolInfo EbpfBase::GetEbpfSymbolInfo(uint32_t pid, uint64_t ip)
74 {
75     auto value = pidAndIpToEbpfSymbolInfo_.Find(pid, ip);
76     if (value.flag) {
77         return value;
78     }
79     return GetSymbolNameIndexFromElfSym(pid, ip);
80 }
81 
GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader * elfHeaderAddr,uint64_t symVaddr)82 DataIndex EbpfBase::GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader *elfHeaderAddr, uint64_t symVaddr)
83 {
84     uint32_t symbolStart = INVALID_UINT32;
85     auto startValueToSymAddr = reader_->GetElfAddrAndStartValueToSymAddr().Find(elfHeaderAddr);
86     if (!startValueToSymAddr) {
87         return INVALID_UINT64;
88     }
89     auto end = startValueToSymAddr->upper_bound(symVaddr);
90     auto symEntLen = elfHeaderAddr->symEntLen;
91     auto length = std::distance(startValueToSymAddr->begin(), end);
92     if (length > 0) {
93         end--;
94         if (symEntLen == ELF32_SYM) {
95             GetSymbolStartIndex(reinterpret_cast<const Elf32_Sym *>(end->second), symbolStart, symVaddr);
96         } else {
97             GetSymbolStartIndex(reinterpret_cast<const Elf64_Sym *>(end->second), symbolStart, symVaddr);
98         }
99     }
100     if (symbolStart == INVALID_UINT32) {
101         return INVALID_UINT64;
102     }
103     // Take out the string according to the subscript
104     auto strTabAddr = reinterpret_cast<const char *>(elfHeaderAddr + 1);
105     if (symbolStart > elfHeaderAddr->strTabLen) {
106         TS_LOGE("symbolStart = %u, elfHeaderAddr->strTabLen = %u", symbolStart, elfHeaderAddr->strTabLen);
107         return INVALID_UINT64;
108     }
109     auto mangle = reinterpret_cast<const char *>(strTabAddr) + symbolStart;
110     auto demangle = GetDemangleSymbolIndex(mangle);
111     auto index = traceDataCache_->GetDataIndex(demangle);
112     if (demangle != mangle) {
113         free(demangle);
114     }
115     return index;
116 }
UpdateFilePathIndexToPidAndIpMap(DataIndex filePathIndex,uint32_t pid,uint64_t ip)117 void EbpfBase::UpdateFilePathIndexToPidAndIpMap(DataIndex filePathIndex, uint32_t pid, uint64_t ip)
118 {
119     auto itor = filePathIndexToPidAndIpMap_.find(filePathIndex);
120     if (itor != filePathIndexToPidAndIpMap_.end()) {
121         itor->second->insert(std::make_tuple(pid, ip));
122     } else {
123         auto pidAndIpSet = std::make_shared<std::set<std::tuple<uint32_t, uint64_t>>>();
124         pidAndIpSet->insert(std::make_tuple(pid, ip));
125         filePathIndexToPidAndIpMap_.insert(std::make_pair(filePathIndex, pidAndIpSet));
126     }
127 }
128 
129 template <typename StartToMapsAddr>
GetSymbolSave(EbpfSymbolInfo & ebpfSymbolInfo,StartToMapsAddr & startToMapsAddr,uint32_t pid,uint64_t ip)130 void EbpfBase::GetSymbolSave(EbpfSymbolInfo &ebpfSymbolInfo,
131                              StartToMapsAddr &startToMapsAddr,
132                              uint32_t pid,
133                              uint64_t ip)
134 {
135     // Obtain symbol information based on the given IP value and store the relevant information in the EbpfSymbolInfo
136     // object
137     uint64_t vmStart = INVALID_UINT64;
138     uint64_t vmOffset = INVALID_UINT64;
139     auto end = startToMapsAddr->upper_bound(ip);
140     auto length = std::distance(startToMapsAddr->begin(), end);
141     if (length > 0) {
142         end--;
143         // Follow the rules of front closing and rear opening, [start, end)
144         if (ip < end->second->end) {
145             vmStart = end->first;
146             vmOffset = end->second->offset;
147             ebpfSymbolInfo.filePathIndex =
148                 traceDataCache_->GetDataIndex(reinterpret_cast<const char *>((end->second) + 1));
149         }
150     }
151     ebpfSymbolInfo.flag = true;
152     if (ebpfSymbolInfo.filePathIndex == INVALID_INT64) {
153         pidAndIpToEbpfSymbolInfo_.Insert(pid, ip, ebpfSymbolInfo);
154         UpdateFilePathIndexToPidAndIpMap(ebpfSymbolInfo.filePathIndex, pid, ip);
155         return;
156     }
157 
158     auto itor = reader_->GetElfPathIndexToElfAddr().find(ebpfSymbolInfo.filePathIndex);
159     if (itor == reader_->GetElfPathIndexToElfAddr().end()) {
160         pidAndIpToEbpfSymbolInfo_.Insert(pid, ip, ebpfSymbolInfo);
161         UpdateFilePathIndexToPidAndIpMap(ebpfSymbolInfo.filePathIndex, pid, ip);
162         return;
163     }
164     uint64_t symVaddr = ip - vmStart + vmOffset + itor->second->textVaddr - itor->second->textOffset;
165     ebpfSymbolInfo.vaddr = symVaddr;
166     auto symbolIndex = GetSymbolNameIndexFromSymVaddr(itor->second, symVaddr);
167     if (symbolIndex != INVALID_UINT64) {
168         ebpfSymbolInfo.symbolIndex = symbolIndex;
169     }
170     pidAndIpToEbpfSymbolInfo_.Insert(pid, ip, ebpfSymbolInfo);
171     UpdateFilePathIndexToPidAndIpMap(ebpfSymbolInfo.filePathIndex, pid, ip);
172     return;
173 }
174 
GetSymbolNameIndexFromElfSym(uint32_t pid,uint64_t ip)175 EbpfSymbolInfo EbpfBase::GetSymbolNameIndexFromElfSym(uint32_t pid, uint64_t ip)
176 {
177     EbpfSymbolInfo ebpfSymbolInfo(false);
178     // Follow the rules of front closing and rear opening, [start, end)
179     if (ip < reader_->maxKernelAddr_ && ip >= reader_->minKernelAddr_) {
180         ebpfSymbolInfo = reader_->GetSymbolNameIndexFromElfSym(ip);
181         pidAndIpToEbpfSymbolInfo_.Insert(pid, ip, ebpfSymbolInfo);
182         UpdateFilePathIndexToPidAndIpMap(ebpfSymbolInfo.filePathIndex, pid, ip);
183         return ebpfSymbolInfo;
184     }
185 
186     auto &pidAndStartAddrToMapsAddr = reader_->GetPidAndStartAddrToMapsAddr();
187     auto startToMapsAddr = pidAndStartAddrToMapsAddr.Find(pid);
188     if (!startToMapsAddr) {
189         ebpfSymbolInfo.flag = true;
190         pidAndIpToEbpfSymbolInfo_.Insert(pid, ip, ebpfSymbolInfo);
191         UpdateFilePathIndexToPidAndIpMap(ebpfSymbolInfo.filePathIndex, pid, ip);
192         return ebpfSymbolInfo;
193     }
194 
195     GetSymbolSave(ebpfSymbolInfo, startToMapsAddr, pid, ip);
196     return ebpfSymbolInfo;
197 }
198 
ConvertToHexTextIndex(uint64_t number)199 DataIndex EbpfBase::ConvertToHexTextIndex(uint64_t number)
200 {
201     if (number == INVALID_UINT64) {
202         return number;
203     }
204     std::string str = "0x" + base::number(number, base::INTEGER_RADIX_TYPE_HEX);
205     return traceDataCache_->GetDataIndex(str.c_str());
206 }
207 template <class T>
UpdateFilePathIndexAndStValueToSymAddrMap(T * firstSymbolAddr,const int size,uint32_t filePathIndex)208 void EbpfBase::UpdateFilePathIndexAndStValueToSymAddrMap(T *firstSymbolAddr, const int size, uint32_t filePathIndex)
209 {
210     for (auto i = 0; i < size; i++) {
211         auto symAddr = firstSymbolAddr + i;
212         if ((symAddr->st_info & STT_FUNC) && (symAddr->st_value)) {
213             filePathIndexAndStValueToSymAddr_.Insert(filePathIndex, symAddr->st_value,
214                                                      reinterpret_cast<const uint8_t *>(symAddr));
215         }
216     }
217 }
EBPFReloadElfSymbolTable(const std::vector<std::unique_ptr<SymbolsFile>> & symbolsFiles)218 bool EbpfBase::EBPFReloadElfSymbolTable(const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles)
219 {
220     auto ebpfCallStackDate = traceDataCache_->GetEbpfCallStack();
221     auto size = ebpfCallStackDate->Size();
222     auto filePathIndexs = ebpfCallStackDate->FilePathIds();
223     auto vaddrs = ebpfCallStackDate->Vaddrs();
224     for (const auto &symbolsFile : symbolsFiles) {
225         std::shared_ptr<std::set<size_t>> rows = nullptr;
226         for (const auto &item : filePathIndexToCallStackRowMap_) {
227             auto originFilePath = traceDataCache_->GetDataFromDict(item.first);
228             if (EndWith(originFilePath, symbolsFile->filePath_)) {
229                 rows = item.second;
230                 break;
231             }
232         }
233         if (rows == nullptr) {
234             continue;
235         }
236         for (auto row : *rows) {
237             auto dfxSymbol = symbolsFile->GetSymbolWithVaddr(vaddrs[row]);
238             if (dfxSymbol.IsValid()) {
239                 auto symbolIndex = traceDataCache_->GetDataIndex(dfxSymbol.GetName());
240                 ebpfCallStackDate->UpdateEbpfSymbolInfo(row, symbolIndex);
241             }
242         }
243     }
244     return true;
245 }
246 
247 template <class T>
GetSymbolStartIndex(T * elfSym,uint32_t & symbolStart,uint64_t symVaddr)248 void EbpfBase::GetSymbolStartIndex(T *elfSym, uint32_t &symbolStart, uint64_t symVaddr)
249 {
250     if (elfSym->st_value + elfSym->st_size >= symVaddr) {
251         symbolStart = elfSym->st_name;
252     }
253 }
254 } // namespace TraceStreamer
255 } // namespace SysTuning
256