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 §ionVaddr, [[maybe_unused]] uint64_t §ionSize, 256 [[maybe_unused]] uint64_t §ionFileOffset) 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