• 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 #ifndef HIPERF_SYMBOLS_H
17 #define HIPERF_SYMBOLS_H
18 
19 #include <cinttypes>
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23 #include <gtest/gtest.h>
24 #include "perf_file_format.h"
25 #include "utilities.h"
26 
27 namespace OHOS {
28 namespace Developtools {
29 namespace NativeDaemon {
30 constexpr const char KERNEL_MMAP_NAME[] = "[kernel.kallsyms]";
31 constexpr const char KERNEL_MODULES_EXT_NAME[] = ".ko";
32 constexpr const char KERNEL_ELF_NAME[] = "vmlinux";
33 constexpr const char MMAP_ANONYMOUS_NAME[] = "[anon]";
34 constexpr const char MMAP_ANONYMOUS_OHOS_NAME[] = "//anon";
35 
36 const std::string NOTE_GNU_BUILD_ID = ".note.gnu.build-id";
37 const std::string EH_FRAME_HR = ".eh_frame_hdr";
38 const std::string EH_FRAME = ".eh_frame";
39 const std::string ARM_EXIDX = ".ARM.exidx";
40 const std::string SYMTAB = ".symtab";
41 const std::string DYNSYM = ".dynsym";
42 
43 const int MAX_SYMBOLS_TYPE_NAME_LEN = 10;
44 
45 struct Symbol {
46     uint64_t vaddr_ = 0;
47     uint64_t ipVaddr_ = 0;
48     uint64_t offset_ = 0;
49     uint64_t len_ = 0;
50     int32_t index_ = -1;
51     std::string name_ = "";
52     std::string module_ = "";      // maybe empty
53     std::string demangle_ = "";    // demangle string
54     mutable bool matched_ = false; // if some callstack match this
55     int32_t hit_ = 0;
56 
SymbolSymbol57     Symbol(uint64_t vaddr, uint64_t len, const std::string name, const std::string module)
58         : vaddr_(vaddr),
59           ipVaddr_(vaddr),
60           offset_(ipVaddr_ - vaddr_),
61           len_(len),
62           name_(name),
63           module_(module) {};
SymbolSymbol64     Symbol(uint64_t vaddr, const std::string name, const std::string module)
65         : Symbol(vaddr, 0, name, module) {};
SymbolSymbol66     Symbol(uint64_t addr = 0) : Symbol(addr, std::string(), std::string()) {};
67 
sameSymbol68     bool same(const Symbol &b) const
69     {
70         return (vaddr_ == b.vaddr_ and demangle_ == b.demangle_);
71     }
72 
73     bool operator==(const Symbol &b) const
74     {
75         return same(b);
76     }
77 
78     bool operator!=(const Symbol &b) const
79     {
80         return !same(b);
81     }
82 
isValidSymbol83     bool isValid() const
84     {
85         return !module_.empty();
86     }
87 
MatchedSymbol88     void Matched() const
89     {
90         matched_ = true;
91     }
92 
setIpVAddressSymbol93     void setIpVAddress(uint64_t vaddr)
94     {
95         ipVaddr_ = vaddr;
96         offset_ = ipVaddr_ - vaddr_;
97     }
98 
GetNameSymbol99     std::string GetName() const
100     {
101         return demangle_.empty() ? name_ : demangle_;
102     }
103 
GetNameOrModuleVaddrSymbol104     std::string GetNameOrModuleVaddr(const std::string &comm) const
105     {
106         if (!demangle_.empty()) {
107             return demangle_;
108         } else if (!name_.empty()) {
109             return name_;
110         } else {
111             std::stringstream sstream;
112             sstream << (module_.empty() ? comm : module_) << "+0x" << std::hex << ipVaddr_;
113             return sstream.str();
114         }
115     }
116 
NameSymbol117     std::string Name() const
118     {
119         std::stringstream sstream;
120         if (!demangle_.empty()) {
121             sstream << demangle_;
122         } else {
123             sstream << name_;
124         }
125         if (ipVaddr_ > vaddr_) {
126             sstream << "(+0x" << std::hex << (ipVaddr_ - vaddr_) << ")";
127         } else if (ipVaddr_ < vaddr_) {
128             sstream << "(-0x" << std::hex << (vaddr_ - ipVaddr_) << ") should not happend.";
129         }
130         return sstream.str();
131     };
132 
AddrSymbol133     std::string Addr() const
134     {
135         std::stringstream sstream;
136         sstream << "0x" << std::setfill('0') << std::setw(sizeof(ipVaddr_) * BYTE_PRINT_WIDTH)
137                 << std::hex << ipVaddr_;
138         return sstream.str();
139     };
LenSymbol140     std::string Len() const
141     {
142         std::stringstream sstream;
143         sstream << std::setfill('0') << std::setw(sizeof(len_)) << len_;
144         return sstream.str();
145     };
ToStringSymbol146     std::string ToString() const
147     {
148         std::stringstream sstream;
149         sstream << Addr() << " " << Name();
150         return sstream.str();
151     };
ToDebugStringSymbol152     std::string ToDebugString() const
153     {
154         std::stringstream sstream;
155         sstream << Addr() << "|";
156         sstream << Len() << "|";
157         sstream << demangle_ << "|";
158         sstream << name_ << "|";
159         sstream << (matched_ ? "matched" : "");
160 
161         return sstream.str();
162     };
163 
containSymbol164     bool contain(uint64_t addr) const
165     {
166         if (len_ == 0) {
167             return vaddr_ <= addr;
168         } else {
169             return vaddr_ <= addr and (vaddr_ + len_) > addr;
170         }
171     }
172 
173     // The range [first, last) must be partitioned with respect to the expression !(value < element)
174     // or !comp(value, element)
ValueLessThanElemSymbol175     static bool ValueLessThanElem(uint64_t vaddr, const Symbol &a)
176     {
177         return vaddr < a.vaddr_;
178     }
CompareLTSymbol179     static bool CompareLT(const Symbol &a, const Symbol &b)
180     {
181         return a.vaddr_ < b.vaddr_; // we should use vaddr to sort
182     };
183 };
184 
185 enum SymbolsFileType {
186     SYMBOL_KERNEL_FILE,
187     SYMBOL_KERNEL_MODULE_FILE,
188     SYMBOL_ELF_FILE,
189     SYMBOL_JAVA_FILE,
190     SYMBOL_JS_FILE,
191     SYMBOL_UNKNOW_FILE,
192 };
193 
194 class SymbolsFile {
195 public:
196     SymbolsFileType symbolFileType_;
197     std::string filePath_ = "";
198 
199     // [14] .text             PROGBITS         00000000002c5000  000c5000
200     // min exec addr , general it point to .text
201     // we make a default value for min compare
202     static const uint64_t maxVaddr = std::numeric_limits<uint64_t>::max();
203 
204     uint64_t textExecVaddr_ = maxVaddr;
205     uint64_t textExecVaddrFileOffset_ = 0;
206     uint64_t textExecVaddrRange_ = maxVaddr;
207 
SymbolsFile(SymbolsFileType symbolType,const std::string path)208     SymbolsFile(SymbolsFileType symbolType, const std::string path)
209         : symbolFileType_(symbolType), filePath_(path) {};
210     virtual ~SymbolsFile();
211 
212     // create the symbols file object
213     static std::unique_ptr<SymbolsFile> CreateSymbolsFile(SymbolsFileType = SYMBOL_UNKNOW_FILE,
214         const std::string symbolFilePath = std::string());
215     static std::unique_ptr<SymbolsFile> CreateSymbolsFile(const std::string &symbolFilePath);
216 
217     // set symbols path
setSymbolsFilePath(const std::string & symbolsSearchPath)218     bool setSymbolsFilePath(const std::string &symbolsSearchPath)
219     {
220         std::vector<std::string> symbolsSearchPaths = {symbolsSearchPath};
221         return setSymbolsFilePath(symbolsSearchPaths);
222     };
223     bool setSymbolsFilePath(const std::vector<std::string> &);
224 
225     // load symbol from file
226     virtual bool LoadSymbols([[maybe_unused]] const std::string &symbolFilePath = std::string())
227     {
228         HLOGV("virtual dummy function called");
229         loaded_ = true;
230         return false;
231     };
232 
233     // get the build if from symbols
234     const std::string GetBuildId() const;
235 
236     // get the symbols vector
237     const std::vector<Symbol> &GetSymbols();
238 
239     // get vaddr(in symbol) from ip(real addr , after mmap reloc)
240     virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const;
241 
242     // get symbols from vaddr
243     const Symbol GetSymbolWithVaddr(uint64_t vaddr) const;
244 
245     // read the .text section and .eh_frame section (RO) memory from elf mmap
246     // unwind use this to check the DWARF and so on
ReadRoMemory(uint64_t,uint8_t *,size_t)247     virtual size_t ReadRoMemory(uint64_t, uint8_t *, size_t) const
248     {
249         HLOGV("virtual dummy function called");
250         return 0; // default not support
251     }
252 
253     // get the section info , like .ARM.exidx
GetSectionInfo(const std::string & name,uint64_t & sectionVaddr,uint64_t & sectionSize,uint64_t & sectionFileOffset)254     virtual bool GetSectionInfo([[maybe_unused]] const std::string &name,
255         [[maybe_unused]] uint64_t &sectionVaddr, [[maybe_unused]] uint64_t &sectionSize,
256         [[maybe_unused]] uint64_t &sectionFileOffset) const
257     {
258         HLOGV("virtual dummy function called");
259         return false;
260     }
261 #ifndef __arm__
262     // get hdr info for unwind , need provide the fde table location and entry count
GetHDRSectionInfo(uint64_t & ehFrameHdrElfOffset,uint64_t & fdeTableElfOffset,uint64_t & fdeTableSize)263     virtual bool GetHDRSectionInfo([[maybe_unused]] uint64_t &ehFrameHdrElfOffset,
264         [[maybe_unused]] uint64_t &fdeTableElfOffset, [[maybe_unused]] uint64_t &fdeTableSize) const
265     {
266         HLOGV("virtual dummy function called");
267         return false;
268     }
269 #endif
270     // load from symbols from the perf.data format
271     static std::unique_ptr<SymbolsFile> LoadSymbolsFromSaved(const SymbolFileStruct &);
272     // save the symbols to perf.data format
273     const SymbolFileStruct exportSymbolToFileFormat(bool onlyMatched = true);
274 
Loaded()275     bool Loaded()
276     {
277         return loaded_;
278     }
279 
280 protected:
281     bool loaded_ = false;
282     const std::string FindSymbolFile(const std::vector<std::string> &,
283         std::string symboleFilePath = std::string()) const;
284 
285     std::string SearchReadableFile(const std::vector<std::string> &searchPaths,
286         const std::string &filePath) const;
287     bool UpdateBuildIdIfMatch(std::string buildId);
288     std::string buildId_;
289     std::vector<std::string> symbolsFileSearchPaths_;
290     std::vector<Symbol> symbols_ {};
291     void AdjustSymbols();
292     bool CheckPathReadable(const std::string &path) const;
293 
294     FRIEND_TEST(SymbolsTest, FindSymbolFile);
295     FRIEND_TEST(SymbolsTest, UpdateBuildIdIfMatch);
296     FRIEND_TEST(SymbolsTest, exportSymbolToFileFormat);
297     FRIEND_TEST(SymbolsTest, exportSymbolToFileFormatMatched);
298     friend class VirtualRuntimeTest;
299 };
300 
301 class CCompareSymbolsFile {
302 public:
operator()303     bool operator() (const std::unique_ptr<SymbolsFile>& left, const std::unique_ptr<SymbolsFile>& right) const
304     {
305         return left->filePath_ < right->filePath_;
306     }
307 };
308 } // namespace NativeDaemon
309 } // namespace Developtools
310 } // namespace OHOS
311 #endif