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