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