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