• 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       pidAndIpToSymbolAndFilePathIndex_(SymbolAndFilePathIndex(false)),
22       pidAndipsToCallId_(INVALID_UINT64)
23 {
24 }
~EbpfBase()25 EbpfBase::~EbpfBase()
26 {
27     pidAndipsToCallId_.Clear();
28     pidAndIpToSymbolAndFilePathIndex_.Clear();
29 }
InitEbpfDataParser(EbpfDataReader * reader)30 bool EbpfBase::InitEbpfDataParser(EbpfDataReader* reader)
31 {
32     auto clockId = reader->GetEbpfDataHeader()->header.clock;
33     auto itor = ebpfToTSClockType_.find(clockId);
34     if (itor == ebpfToTSClockType_.end()) {
35         return false;
36     }
37     clockId_ = ebpfToTSClockType_.at(clockId);
38     reader_ = std::move(reader);
39     return true;
40 }
41 
ParseCallStackData(const uint64_t * userIpsAddr,uint16_t count,uint32_t pid,uint64_t callId)42 void EbpfBase::ParseCallStackData(const uint64_t* userIpsAddr, uint16_t count, uint32_t pid, uint64_t callId)
43 {
44     uint64_t depth = 0;
45     for (auto i = count - 1; i >= 0; i--) {
46         if (userIpsAddr[i] > MIN_USER_IP) {
47             auto symbolAndFilePathIndex = GetSymbolAndFilePathIndex(pid, userIpsAddr[i]);
48             auto ipIndex = ConvertToHexTextIndex(userIpsAddr[i]);
49             traceDataCache_->GetEbpfCallStack()->AppendNewData(callId, depth, ipIndex,
50                                                                symbolAndFilePathIndex.symbolIndex,
51                                                                symbolAndFilePathIndex.filePathIndex);
52             depth++;
53         }
54     }
55 }
56 
GetSymbolAndFilePathIndex(uint32_t pid,uint64_t ip)57 SymbolAndFilePathIndex EbpfBase::GetSymbolAndFilePathIndex(uint32_t pid, uint64_t ip)
58 {
59     auto value = pidAndIpToSymbolAndFilePathIndex_.Find(pid, ip);
60     if (value.flag) {
61         return value;
62     }
63     return GetSymbolNameIndexFromElfSym(pid, ip);
64 }
65 
GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader * elfHeaderAddr,uint64_t symVaddr)66 DataIndex EbpfBase::GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader* elfHeaderAddr, uint64_t symVaddr)
67 {
68     uint32_t symbolStart = INVALID_UINT32;
69     auto startValueToSymAddr = reader_->GetElfAddrAndStartValueToSymAddr().Find(elfHeaderAddr);
70     if (!startValueToSymAddr) {
71         return INVALID_UINT64;
72     }
73     auto end = startValueToSymAddr->upper_bound(symVaddr);
74     auto symEntLen = elfHeaderAddr->symEntLen;
75     auto length = std::distance(startValueToSymAddr->begin(), end);
76     if (length > 0) {
77         end--;
78         if (symEntLen == ELF32_SYM) {
79             auto symbolAddr = reinterpret_cast<const Elf32_Sym*>(end->second);
80             if (end->first <= symVaddr && end->first + symbolAddr->st_size >= symVaddr) {
81                 symbolStart = symbolAddr->st_name;
82             }
83         } else {
84             auto symbolAddr = reinterpret_cast<const Elf64_Sym*>(end->second);
85             if (end->first <= symVaddr && end->first + symbolAddr->st_size >= symVaddr) {
86                 symbolStart = symbolAddr->st_name;
87             }
88         }
89     }
90 
91     if (symbolStart == INVALID_UINT32) {
92         return INVALID_UINT64;
93     }
94 
95     // Take out the string according to the subscript
96     auto strTabAddr = reinterpret_cast<const char*>(elfHeaderAddr + 1);
97 
98     if (symbolStart > elfHeaderAddr->strTabLen) {
99         TS_LOGE("symbolStart = %u, elfHeaderAddr->strTabLen = %u", symbolStart, elfHeaderAddr->strTabLen);
100         return INVALID_UINT64;
101     }
102 
103     auto symbolName = reinterpret_cast<const char*>(strTabAddr) + symbolStart;
104     return traceDataCache_->GetDataIndex(symbolName);
105 }
106 
GetSymbolNameIndexFromElfSym(uint32_t pid,uint64_t ip)107 SymbolAndFilePathIndex EbpfBase::GetSymbolNameIndexFromElfSym(uint32_t pid, uint64_t ip)
108 {
109     SymbolAndFilePathIndex symbolAndFilePathIndex(false);
110 
111     auto& pidAndStartAddrToMapsAddr = reader_->GetPidAndStartAddrToMapsAddr();
112     auto startToMapsAddr = pidAndStartAddrToMapsAddr.Find(pid);
113     if (!startToMapsAddr) {
114         symbolAndFilePathIndex.flag = true;
115         pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex);
116         return symbolAndFilePathIndex;
117     }
118 
119     uint64_t vmStart = INVALID_UINT64;
120     uint64_t vmOffset = INVALID_UINT64;
121     auto end = startToMapsAddr->upper_bound(ip);
122     auto length = std::distance(startToMapsAddr->begin(), end);
123     if (length > 0) {
124         end--;
125         if (ip <= end->second->end) {
126             vmStart = end->first;
127             vmOffset = end->second->offset;
128             symbolAndFilePathIndex.filePathIndex =
129                 traceDataCache_->GetDataIndex(reinterpret_cast<const char*>((end->second) + 1));
130         }
131     }
132     symbolAndFilePathIndex.flag = true;
133     if (symbolAndFilePathIndex.filePathIndex == INVALID_INT64) {
134         pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex);
135         return symbolAndFilePathIndex;
136     }
137 
138     auto itor = reader_->GetElfPathIndexToElfAddr().find(symbolAndFilePathIndex.filePathIndex);
139     if (itor == reader_->GetElfPathIndexToElfAddr().end()) {
140         pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex);
141         return symbolAndFilePathIndex;
142     }
143     uint64_t symVaddr = ip - vmStart + vmOffset + itor->second->textVaddr - itor->second->textOffset;
144     auto symbolIndex = GetSymbolNameIndexFromSymVaddr(itor->second, symVaddr);
145     if (symbolIndex != INVALID_UINT64) {
146         symbolAndFilePathIndex.symbolIndex = symbolIndex;
147     }
148     pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex);
149     return symbolAndFilePathIndex;
150 }
151 
ConvertToHexTextIndex(uint64_t number)152 DataIndex EbpfBase::ConvertToHexTextIndex(uint64_t number)
153 {
154     if (number == INVALID_UINT64) {
155         return number;
156     }
157     std::string str = "0x" + base::number(number, base::INTEGER_RADIX_TYPE_HEX);
158     return traceDataCache_->GetDataIndex(str.c_str());
159 }
160 } // namespace TraceStreamer
161 } // namespace SysTuning
162