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