• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 }
30 
31 template <class T>
GetSymbolStartMaybeUpdateFrameInfo(T * elfSym,uint32_t & symbolStart,uint64_t symVaddr,uint64_t ip,FrameInfo * frameInfo)32 void OfflineSymbolizationFilter::GetSymbolStartMaybeUpdateFrameInfo(T *elfSym,
33                                                                     uint32_t &symbolStart,
34                                                                     uint64_t symVaddr,
35                                                                     uint64_t ip,
36                                                                     FrameInfo *frameInfo)
37 {
38     if (elfSym->st_value + elfSym->st_size >= symVaddr) {
39         symbolStart = elfSym->st_name;
40         if (frameInfo) {
41             frameInfo->offset_ = elfSym->st_value != 0 ? elfSym->st_value : ip;
42             frameInfo->symbolOffset_ = symVaddr - elfSym->st_value;
43         }
44     }
45 }
46 
FillFrameInfo(const std::shared_ptr<FrameInfo> & frameInfo,uint64_t ip,uint64_t ipid)47 bool OfflineSymbolizationFilter::FillFrameInfo(const std::shared_ptr<FrameInfo> &frameInfo, uint64_t ip, uint64_t ipid)
48 {
49     frameInfo->ip_ = ip;
50     auto startAddrToMapsInfoItor = ipidToStartAddrToMapsInfoMap_.Find(ipid);
51     TS_CHECK_TRUE(startAddrToMapsInfoItor != nullptr, false,
52                   "ipidToStartAddrToMapsInfoMap_ can't find the ipid(%" PRIu64 ")", ipid);
53     auto endItor = startAddrToMapsInfoItor->upper_bound(ip);
54     int64_t length = std::distance(startAddrToMapsInfoItor->begin(), endItor);
55     if (length > 0) {
56         endItor--;
57         // Follow the rules of front closing and rear opening, [start, end)
58         if (ip < endItor->second->end()) {
59             vmStart_ = endItor->second->start();
60             vmOffset_ = endItor->second->offset();
61             frameInfo->filePathId_ = endItor->second->file_path_id();
62         }
63     }
64     if (frameInfo->filePathId_ == INVALID_UINT32) {
65         // find matching MapsInfo failed!!!
66         TS_LOGI("find matching Maps Info failed, ip = %" PRIu64 ", length=%" PRId64 "", ip, length);
67         return false;
68     }
69     return true;
70 }
CalcSymInfo(uint64_t ipid,uint64_t ip,uint32_t & symbolStart,std::shared_ptr<FrameInfo> & frameInfo,std::shared_ptr<ProtoReader::SymbolTable_Reader> & symbolTable)71 bool OfflineSymbolizationFilter::CalcSymInfo(uint64_t ipid,
72                                              uint64_t ip,
73                                              uint32_t &symbolStart,
74                                              std::shared_ptr<FrameInfo> &frameInfo,
75                                              std::shared_ptr<ProtoReader::SymbolTable_Reader> &symbolTable)
76 {
77     // calculate symVaddr = ip - vmStart + vmOffset + phdrVaddr - phdrOffset
78     uint64_t symVaddr =
79         ip - vmStart_ + vmOffset_ + symbolTable->text_exec_vaddr() - symbolTable->text_exec_vaddr_file_offset();
80     frameInfo->symVaddr_ = symVaddr;
81     // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size.
82     auto symEntLen = symbolTable->sym_entry_size();
83     auto startValueToSymAddrMap = symbolTablePtrAndStValueToSymAddr_.Find(symbolTable);
84     if (!startValueToSymAddrMap) {
85         // find matching SymbolTable failed, but symVaddr is availiable
86         ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
87         // find symbolTable failed!!!
88         TS_LOGD("find symbolTalbe failed!!!");
89         return false;
90     }
91     // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size.  then you can get st_name
92     auto end = startValueToSymAddrMap->upper_bound(symVaddr);
93     auto length = std::distance(startValueToSymAddrMap->begin(), end);
94     if (length > 0) {
95         end--;
96         if (symEntLen == ELF32_SYM) {
97             GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf32_Sym *>(end->second), symbolStart, symVaddr,
98                                                ip, frameInfo.get());
99         } else {
100             GetSymbolStartMaybeUpdateFrameInfo(reinterpret_cast<const Elf64_Sym *>(end->second), symbolStart, symVaddr,
101                                                ip, frameInfo.get());
102         }
103     }
104     if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->str_table().Size()) {
105         // find symbolStart failed, but some data is availiable.
106         frameInfo->offset_ = ip;
107         frameInfo->symbolOffset_ = 0;
108         ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
109         TS_LOGD("symbolStart is %u invaliable!!!", symbolStart);
110         return false;
111     }
112     return true;
113 }
OfflineSymbolizationByIp(uint64_t ipid,uint64_t ip)114 std::shared_ptr<FrameInfo> OfflineSymbolizationFilter::OfflineSymbolizationByIp(uint64_t ipid, uint64_t ip)
115 {
116     if (isSingleProcData_) {
117         ipid = SINGLE_PROC_IPID;
118     }
119     auto frameInfoPtr = ipidToIpToFrameInfo_.Find(ipid, ip);
120     if (frameInfoPtr != nullptr) {
121         return frameInfoPtr;
122     }
123     vmStart_ = INVALID_UINT64;
124     vmOffset_ = INVALID_UINT64;
125     // start symbolization
126     std::shared_ptr<FrameInfo> frameInfo = std::make_shared<FrameInfo>();
127     if (!FillFrameInfo(frameInfo, ip, ipid)) {
128         if (ip) {
129             return frameInfo;
130         }
131         return nullptr;
132     }
133     // find SymbolTable by filePathId
134     auto symbolTable = ipidTofilePathIdToSymbolTableMap_.Find(ipid, frameInfo->filePathId_);
135     if (symbolTable == nullptr) {
136         // find matching SymbolTable failed, but filePathId is availiable
137         ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
138         TS_LOGD("find matching filePathId failed, ipid = %" PRIu64 ", ip = %" PRIu64 ", filePathId = %u", ipid, ip,
139                 frameInfo->filePathId_);
140         return frameInfo;
141     }
142     uint32_t symbolStart = INVALID_UINT32;
143     if (!CalcSymInfo(ipid, ip, symbolStart, frameInfo, symbolTable)) {
144         return frameInfo;
145     }
146     auto mangle = reinterpret_cast<const char *>(symbolTable->str_table().Data() + symbolStart);
147     auto demangle = base::GetDemangleSymbolIndex(mangle);
148     frameInfo->symbolIndex_ = traceDataCache_->GetDataIndex(demangle);
149     if (demangle != mangle) {
150         free(demangle);
151     }
152     ipidToIpToFrameInfo_.Insert(ipid, ip, frameInfo);
153     return frameInfo;
154 }
155 } // namespace TraceStreamer
156 } // namespace SysTuning
157