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