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
16 #include "offline_symbolization_filter.h"
17 #include <cinttypes>
18
19 namespace SysTuning {
20 namespace TraceStreamer {
OfflineSymbolizationFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)21 OfflineSymbolizationFilter::OfflineSymbolizationFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
22 : FilterBase(dataCache, filter),
23 filePathIdAndStValueToSymAddr_(nullptr),
24 symbolTablePtrAndStValueToSymAddr_(nullptr),
25 ipidToStartAddrToMapsInfoMap_(nullptr),
26 ipidToIpToFrameInfo_(nullptr),
27 ipidTofilePathIdToSymbolTableMap_(nullptr)
28 {
29 }
OfflineSymbolization(const std::shared_ptr<std::vector<uint64_t>> ips)30 std::shared_ptr<std::vector<std::shared_ptr<FrameInfo>>> OfflineSymbolizationFilter::OfflineSymbolization(
31 const std::shared_ptr<std::vector<uint64_t>> ips)
32 {
33 auto ipid = ips->back();
34 auto result = std::make_shared<std::vector<std::shared_ptr<FrameInfo>>>();
35 for (auto itor = ips->begin(); (itor + 1) != ips->end(); itor++) {
36 auto frameInfo = OfflineSymbolizationByIp(ipid, *itor);
37 // If the IP in the middle of the call stack cannot be symbolized, the remaining IP is discarded
38 if (!frameInfo) {
39 break;
40 }
41 result->emplace_back(frameInfo);
42 }
43 return result;
44 }
45 template <class T>
GetSymbolStartMaybeUpdateFrameInfo(T * elfSym,uint32_t & symbolStart,uint64_t symVaddr,uint64_t ip,FrameInfo * frameInfo)46 void OfflineSymbolizationFilter::GetSymbolStartMaybeUpdateFrameInfo(T* elfSym,
47 uint32_t& symbolStart,
48 uint64_t symVaddr,
49 uint64_t ip,
50 FrameInfo* frameInfo)
51 {
52 if (elfSym->st_value + elfSym->st_size >= symVaddr) {
53 symbolStart = elfSym->st_name;
54 if (frameInfo) {
55 frameInfo->offset_ = elfSym->st_value != 0 ? elfSym->st_value : ip;
56 frameInfo->symbolOffset_ = symVaddr - elfSym->st_value;
57 }
58 }
59 }
60
FillFrameInfo(const std::shared_ptr<FrameInfo> & frameInfo,uint64_t ip,uint64_t ipid)61 bool OfflineSymbolizationFilter::FillFrameInfo(const std::shared_ptr<FrameInfo>& frameInfo, uint64_t ip, uint64_t ipid)
62 {
63 frameInfo->ip_ = ip;
64 auto startAddrToMapsInfoItor = ipidToStartAddrToMapsInfoMap_.Find(ipid);
65 TS_CHECK_TRUE(startAddrToMapsInfoItor != nullptr, false,
66 "ipidToStartAddrToMapsInfoMap_ can't find the ipid(%" PRIu64 ")", ipid);
67 auto endItor = startAddrToMapsInfoItor->upper_bound(ip);
68 int64_t length = std::distance(startAddrToMapsInfoItor->begin(), endItor);
69 if (length > 0) {
70 endItor--;
71 // Follow the rules of front closing and rear opening, [start, end)
72 if (ip < endItor->second->end()) {
73 vmStart_ = endItor->second->start();
74 vmOffset_ = endItor->second->offset();
75 frameInfo->filePathId_ = endItor->second->file_path_id();
76 }
77 }
78 if (frameInfo->filePathId_ == INVALID_UINT32) {
79 // find matching MapsInfo failed!!!
80 TS_LOGI("find matching Maps Info failed, ip = %" PRIu64 ", length=%" PRId64 "", ip, length);
81 return false;
82 }
83 return true;
84 }
CalcSymInfo(uint64_t ipid,uint64_t ip,uint32_t & symbolStart,std::shared_ptr<FrameInfo> & frameInfo,std::shared_ptr<ProtoReader::SymbolTable_Reader> & symbolTable)85 bool OfflineSymbolizationFilter::CalcSymInfo(uint64_t ipid,
86 uint64_t ip,
87 uint32_t& symbolStart,
88 std::shared_ptr<FrameInfo>& frameInfo,
89 std::shared_ptr<ProtoReader::SymbolTable_Reader>& symbolTable)
90 {
91 // calculate symVaddr = ip - vmStart + vmOffset + phdrVaddr - phdrOffset
92 uint64_t symVaddr =
93 ip - vmStart_ + vmOffset_ + symbolTable->text_exec_vaddr() - symbolTable->text_exec_vaddr_file_offset();
94 frameInfo->symVaddr_ = symVaddr;
95 // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size.
96 auto symEntLen = symbolTable->sym_entry_size();
97 auto startValueToSymAddrMap = symbolTablePtrAndStValueToSymAddr_.Find(symbolTable);
98 if (!startValueToSymAddrMap) {
99 // find matching SymbolTable failed, but symVaddr is availiable
100 ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
101 // find symbolTable failed!!!
102 TS_LOGD("find symbolTalbe failed!!!");
103 return false;
104 }
105 // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size. then you can get st_name
106 auto end = startValueToSymAddrMap->upper_bound(symVaddr);
107 auto length = std::distance(startValueToSymAddrMap->begin(), end);
108 if (length > 0) {
109 end--;
110 if (symEntLen == ELF32_SYM) {
111 GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf32_Sym*>(end->second), symbolStart, symVaddr,
112 ip, frameInfo.get());
113 } else {
114 GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf64_Sym*>(end->second), symbolStart, symVaddr,
115 ip, frameInfo.get());
116 }
117 }
118 if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->str_table().Size()) {
119 // find symbolStart failed, but some data is availiable.
120 frameInfo->offset_ = ip;
121 frameInfo->symbolOffset_ = 0;
122 ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
123 TS_LOGD("symbolStart is %u invaliable!!!", symbolStart);
124 return false;
125 }
126 return true;
127 }
OfflineSymbolizationByIp(uint64_t ipid,uint64_t ip)128 std::shared_ptr<FrameInfo> OfflineSymbolizationFilter::OfflineSymbolizationByIp(uint64_t ipid, uint64_t ip)
129 {
130 if (isSingleProcData_) {
131 ipid = SINGLE_PROC_IPID;
132 }
133 auto frameInfoPtr = ipidToIpToFrameInfo_.Find(ipid, ip);
134 if (frameInfoPtr != nullptr) {
135 return frameInfoPtr;
136 }
137 vmStart_ = INVALID_UINT64;
138 vmOffset_ = INVALID_UINT64;
139 // start symbolization
140 std::shared_ptr<FrameInfo> frameInfo = std::make_shared<FrameInfo>();
141 if (!FillFrameInfo(frameInfo, ip, ipid)) {
142 if (ip & usefulIpMask_) {
143 return frameInfo;
144 }
145 return nullptr;
146 }
147 // find SymbolTable by filePathId
148 auto symbolTable = ipidTofilePathIdToSymbolTableMap_.Find(ipid, frameInfo->filePathId_);
149 if (symbolTable == nullptr) {
150 // find matching SymbolTable failed, but filePathId is availiable
151 ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
152 TS_LOGD("find matching filePathId failed, ipid = %" PRIu64 ", ip = %" PRIu64 ", filePathId = %u", ipid, ip,
153 frameInfo->filePathId_);
154 return frameInfo;
155 }
156 uint32_t symbolStart = INVALID_UINT32;
157 if (!CalcSymInfo(ipid, ip, symbolStart, frameInfo, symbolTable)) {
158 return frameInfo;
159 }
160 auto mangle = reinterpret_cast<const char*>(symbolTable->str_table().Data() + symbolStart);
161 auto demangle = base::GetDemangleSymbolIndex(mangle);
162 frameInfo->symbolIndex_ = traceDataCache_->GetDataIndex(demangle);
163 if (demangle != mangle) {
164 free(demangle);
165 }
166 ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
167 return frameInfo;
168 }
OfflineSymbolizationByVaddr(uint64_t symVaddr,DataIndex filePathIndex)169 DataIndex OfflineSymbolizationFilter::OfflineSymbolizationByVaddr(uint64_t symVaddr, DataIndex filePathIndex)
170 {
171 auto& symbolTable = filePathIdToImportSymbolTableMap_.at(filePathIndex);
172 // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size.
173 auto symEntLen = symbolTable->symEntSize;
174 auto startValueToSymAddrMap = filePathIdAndStValueToSymAddr_.Find(filePathIndex);
175 if (!startValueToSymAddrMap) {
176 return INVALID_DATAINDEX;
177 }
178 // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size. then you can get st_name
179 auto end = startValueToSymAddrMap->upper_bound(symVaddr);
180 auto length = std::distance(startValueToSymAddrMap->begin(), end);
181 uint32_t symbolStart = INVALID_UINT32;
182 if (length > 0) {
183 end--;
184 if (symEntLen == ELF32_SYM) {
185 GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf32_Sym*>(end->second), symbolStart, symVaddr,
186 0, nullptr);
187 } else {
188 GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf64_Sym*>(end->second), symbolStart, symVaddr,
189 0, nullptr);
190 }
191 }
192 if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->strTable.size()) {
193 TS_LOGD("symbolStart is : %u invaliable!!!", symbolStart);
194 return INVALID_DATAINDEX;
195 }
196 auto mangle = symbolTable->strTable.c_str() + symbolStart;
197 auto demangle = base::GetDemangleSymbolIndex(mangle);
198 auto index = traceDataCache_->GetDataIndex(demangle);
199 if (demangle != mangle) {
200 free(demangle);
201 }
202 return index;
203 }
204 } // namespace TraceStreamer
205 } // namespace SysTuning
206