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