Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef SIMPLE_PERF_DSO_H_ |
| 18 | #define SIMPLE_PERF_DSO_H_ |
| 19 | |
| 20 | #include <memory> |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 21 | #include <string> |
Yabin Cui | 638c558 | 2015-07-01 16:16:57 -0700 | [diff] [blame] | 22 | #include <unordered_map> |
| 23 | #include <vector> |
| 24 | |
Mark Salyzyn | 499a017 | 2018-11-12 12:58:06 -0800 | [diff] [blame] | 25 | #include <android-base/file.h> |
Yabin Cui | e466d4d | 2017-08-11 17:03:07 -0700 | [diff] [blame] | 26 | #include <android-base/logging.h> |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 27 | |
Yabin Cui | 638c558 | 2015-07-01 16:16:57 -0700 | [diff] [blame] | 28 | #include "build_id.h" |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 29 | #include "read_elf.h" |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 30 | |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 31 | |
| 32 | namespace simpleperf_dso_impl { |
| 33 | |
| 34 | // Find elf files with symbol table and debug information. |
| 35 | class DebugElfFileFinder { |
| 36 | public: |
| 37 | void Reset(); |
| 38 | bool SetSymFsDir(const std::string& symfs_dir); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 39 | bool AddSymbolDir(const std::string& symbol_dir); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 40 | void SetVdsoFile(const std::string& vdso_file, bool is_64bit); |
| 41 | std::string FindDebugFile(const std::string& dso_path, bool force_64bit, |
| 42 | BuildId& build_id); |
Yabin Cui | 1b9b1c1 | 2018-10-29 14:23:48 -0700 | [diff] [blame] | 43 | // Only for testing |
| 44 | std::string GetPathInSymFsDir(const std::string& path); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 45 | |
| 46 | private: |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 47 | void CollectBuildIdInDir(const std::string& dir); |
| 48 | |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 49 | std::string vdso_64bit_; |
| 50 | std::string vdso_32bit_; |
| 51 | std::string symfs_dir_; |
| 52 | std::unordered_map<std::string, std::string> build_id_to_file_map_; |
| 53 | }; |
| 54 | |
| 55 | } // namespace simpleperf_dso_impl |
| 56 | |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 57 | struct Symbol { |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 58 | uint64_t addr; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 59 | // TODO: make len uint32_t. |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 60 | uint64_t len; |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 61 | |
Martin Stjernholm | 7c27cc2 | 2018-11-28 00:46:00 +0000 | [diff] [blame] | 62 | Symbol(std::string_view name, uint64_t addr, uint64_t len); |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 63 | const char* Name() const { return name_; } |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 64 | |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 65 | const char* DemangledName() const; |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 66 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 67 | bool HasDumpId() const { |
| 68 | return dump_id_ != UINT_MAX; |
| 69 | } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 70 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 71 | bool GetDumpId(uint32_t* pdump_id) const { |
| 72 | if (!HasDumpId()) { |
| 73 | return false; |
| 74 | } |
| 75 | *pdump_id = dump_id_; |
| 76 | return true; |
| 77 | } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 78 | |
Yabin Cui | aba7e29 | 2016-11-11 14:53:52 -0800 | [diff] [blame] | 79 | static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) { |
| 80 | uint32_t id1 = UINT_MAX; |
| 81 | s1->GetDumpId(&id1); |
| 82 | uint32_t id2 = UINT_MAX; |
| 83 | s2->GetDumpId(&id2); |
| 84 | return id1 < id2; |
| 85 | } |
| 86 | |
| 87 | static bool CompareByAddr(const Symbol* s1, const Symbol* s2) { |
| 88 | return s1->addr < s2->addr; |
| 89 | } |
| 90 | |
| 91 | static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) { |
| 92 | return s1.addr < s2.addr; |
| 93 | } |
| 94 | |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 95 | private: |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 96 | const char* name_; |
| 97 | mutable const char* demangled_name_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 98 | mutable uint32_t dump_id_; |
| 99 | |
| 100 | friend class Dso; |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 101 | }; |
| 102 | |
Yabin Cui | ba50c4b | 2015-07-21 11:24:48 -0700 | [diff] [blame] | 103 | enum DsoType { |
| 104 | DSO_KERNEL, |
| 105 | DSO_KERNEL_MODULE, |
| 106 | DSO_ELF_FILE, |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 107 | DSO_DEX_FILE, // For files containing dex files, like .vdex files. |
Yabin Cui | c36ea8b | 2018-04-16 18:21:40 -0700 | [diff] [blame] | 108 | DSO_UNKNOWN_FILE, |
Yabin Cui | ba50c4b | 2015-07-21 11:24:48 -0700 | [diff] [blame] | 109 | }; |
| 110 | |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 111 | struct KernelSymbol; |
| 112 | struct ElfFileSymbol; |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 113 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 114 | class Dso { |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 115 | public: |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 116 | static void SetDemangle(bool demangle); |
| 117 | static std::string Demangle(const std::string& name); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 118 | // SymFsDir is used to provide an alternative root directory looking for files with symbols. |
| 119 | // For example, if we are searching symbols for /system/lib/libc.so and SymFsDir is /data/symbols, |
| 120 | // then we will also search file /data/symbols/system/lib/libc.so. |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 121 | static bool SetSymFsDir(const std::string& symfs_dir); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 122 | // SymbolDir is used to add a directory containing files with symbols. Each file under it will |
| 123 | // be searched recursively to build a build_id_map. |
| 124 | static bool AddSymbolDir(const std::string& symbol_dir); |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 125 | static void SetVmlinux(const std::string& vmlinux); |
Yabin Cui | b421297 | 2016-05-25 14:08:05 -0700 | [diff] [blame] | 126 | static void SetKallsyms(std::string kallsyms) { |
| 127 | if (!kallsyms.empty()) { |
| 128 | kallsyms_ = std::move(kallsyms); |
| 129 | } |
| 130 | } |
Yabin Cui | a939245 | 2017-01-12 18:07:27 -0800 | [diff] [blame] | 131 | static void ReadKernelSymbolsFromProc() { |
| 132 | read_kernel_symbols_from_proc_ = true; |
| 133 | } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 134 | static void SetBuildIds( |
| 135 | const std::vector<std::pair<std::string, BuildId>>& build_ids); |
Yabin Cui | 52c6369 | 2016-11-28 17:28:08 -0800 | [diff] [blame] | 136 | static BuildId FindExpectedBuildIdForPath(const std::string& path); |
Yabin Cui | c68e66d | 2018-03-07 15:47:15 -0800 | [diff] [blame] | 137 | static void SetVdsoFile(const std::string& vdso_file, bool is_64bit); |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 138 | |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 139 | static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path, |
| 140 | bool force_64bit = false); |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 141 | |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 142 | virtual ~Dso(); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 143 | |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 144 | DsoType type() const { return type_; } |
| 145 | |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 146 | // Return the path recorded in perf.data. |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 147 | const std::string& Path() const { return path_; } |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 148 | // Return the path containing symbol table and debug information. |
| 149 | const std::string& GetDebugFilePath() const { return debug_file_path_; } |
Yabin Cui | 15475e6 | 2016-07-14 13:26:19 -0700 | [diff] [blame] | 150 | // Return the file name without directory info. |
| 151 | const std::string& FileName() const { return file_name_; } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 152 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 153 | bool HasDumpId() { |
| 154 | return dump_id_ != UINT_MAX; |
| 155 | } |
| 156 | |
| 157 | bool GetDumpId(uint32_t* pdump_id) { |
| 158 | if (!HasDumpId()) { |
| 159 | return false; |
| 160 | } |
| 161 | *pdump_id = dump_id_; |
| 162 | return true; |
| 163 | } |
| 164 | |
| 165 | uint32_t CreateDumpId(); |
| 166 | uint32_t CreateSymbolDumpId(const Symbol* symbol); |
Yabin Cui | 78fddd1 | 2016-10-24 14:09:26 -0700 | [diff] [blame] | 167 | |
Yabin Cui | db2c493 | 2019-02-07 15:06:42 -0800 | [diff] [blame] | 168 | virtual void SetMinExecutableVaddr(uint64_t, uint64_t) {} |
| 169 | virtual void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) { |
| 170 | *min_vaddr = 0; |
| 171 | *file_offset = 0; |
| 172 | } |
Yabin Cui | dd401b3 | 2018-04-11 11:17:06 -0700 | [diff] [blame] | 173 | virtual void AddDexFileOffset(uint64_t) {} |
| 174 | virtual const std::vector<uint64_t>* DexFileOffsets() { return nullptr; } |
Yabin Cui | 547c60e | 2015-10-12 16:56:05 -0700 | [diff] [blame] | 175 | |
Yabin Cui | db2c493 | 2019-02-07 15:06:42 -0800 | [diff] [blame] | 176 | virtual uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) = 0; |
| 177 | |
Yabin Cui | 547c60e | 2015-10-12 16:56:05 -0700 | [diff] [blame] | 178 | const Symbol* FindSymbol(uint64_t vaddr_in_dso); |
Yabin Cui | c5b4a31 | 2016-10-24 13:38:38 -0700 | [diff] [blame] | 179 | |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 180 | const std::vector<Symbol>& GetSymbols() { return symbols_; } |
Yabin Cui | c5b4a31 | 2016-10-24 13:38:38 -0700 | [diff] [blame] | 181 | void SetSymbols(std::vector<Symbol>* symbols); |
| 182 | |
| 183 | // Create a symbol for a virtual address which can't find a corresponding |
| 184 | // symbol in symbol table. |
| 185 | void AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name); |
Yabin Cui | 10bbd84 | 2018-08-13 17:42:25 -0700 | [diff] [blame] | 186 | bool IsForJavaMethod(); |
Yabin Cui | b378355 | 2015-06-11 11:15:42 -0700 | [diff] [blame] | 187 | |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 188 | protected: |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 189 | static bool demangle_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 190 | static std::string vmlinux_; |
Yabin Cui | b421297 | 2016-05-25 14:08:05 -0700 | [diff] [blame] | 191 | static std::string kallsyms_; |
Yabin Cui | a939245 | 2017-01-12 18:07:27 -0800 | [diff] [blame] | 192 | static bool read_kernel_symbols_from_proc_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 193 | static std::unordered_map<std::string, BuildId> build_id_map_; |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 194 | static size_t dso_count_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 195 | static uint32_t g_dump_id_; |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 196 | static simpleperf_dso_impl::DebugElfFileFinder debug_elf_file_finder_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 197 | |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 198 | Dso(DsoType type, const std::string& path, const std::string& debug_file_path); |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 199 | BuildId GetExpectedBuildId(); |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 200 | |
| 201 | void Load(); |
| 202 | virtual std::vector<Symbol> LoadSymbols() = 0; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 203 | |
Yabin Cui | dd401b3 | 2018-04-11 11:17:06 -0700 | [diff] [blame] | 204 | DsoType type_; |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 205 | // path of the shared library used by the profiled program |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 206 | const std::string path_; |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 207 | // path of the shared library having symbol table and debug information |
| 208 | // It is the same as path_, or has the same build id as path_. |
| 209 | std::string debug_file_path_; |
Yabin Cui | 15475e6 | 2016-07-14 13:26:19 -0700 | [diff] [blame] | 210 | // File name of the shared library, got by removing directories in path_. |
| 211 | std::string file_name_; |
Yabin Cui | c5b4a31 | 2016-10-24 13:38:38 -0700 | [diff] [blame] | 212 | std::vector<Symbol> symbols_; |
| 213 | // unknown symbols are like [libc.so+0x1234]. |
| 214 | std::unordered_map<uint64_t, Symbol> unknown_symbols_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 215 | bool is_loaded_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 216 | // Used to identify current dso if it needs to be dumped. |
| 217 | uint32_t dump_id_; |
| 218 | // Used to assign dump_id for symbols in current dso. |
| 219 | uint32_t symbol_dump_id_; |
Yabin Cui | e466d4d | 2017-08-11 17:03:07 -0700 | [diff] [blame] | 220 | android::base::LogSeverity symbol_warning_loglevel_; |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 221 | }; |
| 222 | |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 223 | const char* DsoTypeToString(DsoType dso_type); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 224 | bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id); |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 225 | |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 226 | #endif // SIMPLE_PERF_DSO_H_ |