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 | 7078c67 | 2020-11-10 16:24:12 -0800 | [diff] [blame] | 21 | #include <optional> |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 22 | #include <string> |
Yabin Cui | e32ed2b | 2020-07-23 15:30:14 -0700 | [diff] [blame] | 23 | #include <string_view> |
Yabin Cui | 638c558 | 2015-07-01 16:16:57 -0700 | [diff] [blame] | 24 | #include <unordered_map> |
| 25 | #include <vector> |
| 26 | |
Mark Salyzyn | 499a017 | 2018-11-12 12:58:06 -0800 | [diff] [blame] | 27 | #include <android-base/file.h> |
Yabin Cui | e466d4d | 2017-08-11 17:03:07 -0700 | [diff] [blame] | 28 | #include <android-base/logging.h> |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 29 | |
Yabin Cui | 638c558 | 2015-07-01 16:16:57 -0700 | [diff] [blame] | 30 | #include "build_id.h" |
Thiébaud Weksteen | e7e750e | 2020-11-19 15:07:46 +0100 | [diff] [blame] | 31 | #include "kallsyms.h" |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 32 | #include "read_elf.h" |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 33 | |
Yabin Cui | faa7b92 | 2021-01-11 17:35:57 -0800 | [diff] [blame] | 34 | namespace simpleperf { |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 35 | namespace simpleperf_dso_impl { |
| 36 | |
| 37 | // Find elf files with symbol table and debug information. |
| 38 | class DebugElfFileFinder { |
| 39 | public: |
| 40 | void Reset(); |
| 41 | bool SetSymFsDir(const std::string& symfs_dir); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 42 | bool AddSymbolDir(const std::string& symbol_dir); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 43 | void SetVdsoFile(const std::string& vdso_file, bool is_64bit); |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 44 | std::string FindDebugFile(const std::string& dso_path, bool force_64bit, BuildId& build_id); |
Yabin Cui | 1b9b1c1 | 2018-10-29 14:23:48 -0700 | [diff] [blame] | 45 | // Only for testing |
| 46 | std::string GetPathInSymFsDir(const std::string& path); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 47 | |
| 48 | private: |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 49 | void CollectBuildIdInDir(const std::string& dir); |
| 50 | |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 51 | std::string vdso_64bit_; |
| 52 | std::string vdso_32bit_; |
| 53 | std::string symfs_dir_; |
| 54 | std::unordered_map<std::string, std::string> build_id_to_file_map_; |
| 55 | }; |
| 56 | |
| 57 | } // namespace simpleperf_dso_impl |
| 58 | |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 59 | struct Symbol { |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 60 | uint64_t addr; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 61 | // TODO: make len uint32_t. |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 62 | uint64_t len; |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 63 | |
Martin Stjernholm | 7c27cc2 | 2018-11-28 00:46:00 +0000 | [diff] [blame] | 64 | Symbol(std::string_view name, uint64_t addr, uint64_t len); |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 65 | const char* Name() const { return name_; } |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 66 | |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 67 | const char* DemangledName() const; |
Yabin Cui | 40eef9e | 2021-04-13 13:08:31 -0700 | [diff] [blame] | 68 | void SetDemangledName(std::string_view name) const; |
Yabin Cui | 1e16b20 | 2021-08-16 13:37:35 -0700 | [diff] [blame] | 69 | // Return function name without signature. |
Yabin Cui | fef9514 | 2021-08-19 10:51:00 -0700 | [diff] [blame] | 70 | std::string_view FunctionName() const; |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 71 | |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 72 | bool HasDumpId() const { return dump_id_ != UINT_MAX; } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 73 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 74 | bool GetDumpId(uint32_t* pdump_id) const { |
| 75 | if (!HasDumpId()) { |
| 76 | return false; |
| 77 | } |
| 78 | *pdump_id = dump_id_; |
| 79 | return true; |
| 80 | } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 81 | |
Yabin Cui | aba7e29 | 2016-11-11 14:53:52 -0800 | [diff] [blame] | 82 | static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) { |
| 83 | uint32_t id1 = UINT_MAX; |
| 84 | s1->GetDumpId(&id1); |
| 85 | uint32_t id2 = UINT_MAX; |
| 86 | s2->GetDumpId(&id2); |
| 87 | return id1 < id2; |
| 88 | } |
| 89 | |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 90 | static bool CompareByAddr(const Symbol* s1, const Symbol* s2) { return s1->addr < s2->addr; } |
Yabin Cui | aba7e29 | 2016-11-11 14:53:52 -0800 | [diff] [blame] | 91 | |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 92 | static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) { return s1.addr < s2.addr; } |
Yabin Cui | aba7e29 | 2016-11-11 14:53:52 -0800 | [diff] [blame] | 93 | |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 94 | private: |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 95 | const char* name_; |
| 96 | mutable const char* demangled_name_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 97 | mutable uint32_t dump_id_; |
| 98 | |
| 99 | friend class Dso; |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 100 | }; |
| 101 | |
Yabin Cui | ba50c4b | 2015-07-21 11:24:48 -0700 | [diff] [blame] | 102 | enum DsoType { |
| 103 | DSO_KERNEL, |
| 104 | DSO_KERNEL_MODULE, |
| 105 | DSO_ELF_FILE, |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 106 | DSO_DEX_FILE, // For files containing dex files, like .vdex files. |
Evgeny Eltsin | 91dbae0 | 2020-08-27 15:46:09 +0200 | [diff] [blame] | 107 | DSO_SYMBOL_MAP_FILE, |
Yabin Cui | c36ea8b | 2018-04-16 18:21:40 -0700 | [diff] [blame] | 108 | DSO_UNKNOWN_FILE, |
Yabin Cui | 8d005de | 2020-10-21 13:48:53 -0700 | [diff] [blame] | 109 | // DSO_UNKNOWN_FILE is written to the file feature section in recording files. Changing its value |
| 110 | // may cause compatibility issue. So put new DsoTypes below. |
Yabin Cui | ba50c4b | 2015-07-21 11:24:48 -0700 | [diff] [blame] | 111 | }; |
| 112 | |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 113 | class Dso { |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 114 | public: |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 115 | static void SetDemangle(bool demangle); |
| 116 | static std::string Demangle(const std::string& name); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 117 | // SymFsDir is used to provide an alternative root directory looking for files with symbols. |
| 118 | // For example, if we are searching symbols for /system/lib/libc.so and SymFsDir is /data/symbols, |
| 119 | // then we will also search file /data/symbols/system/lib/libc.so. |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 120 | static bool SetSymFsDir(const std::string& symfs_dir); |
Yabin Cui | 3939b9d | 2018-07-20 17:12:13 -0700 | [diff] [blame] | 121 | // SymbolDir is used to add a directory containing files with symbols. Each file under it will |
| 122 | // be searched recursively to build a build_id_map. |
| 123 | static bool AddSymbolDir(const std::string& symbol_dir); |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 124 | static void SetVmlinux(const std::string& vmlinux); |
Yabin Cui | b421297 | 2016-05-25 14:08:05 -0700 | [diff] [blame] | 125 | static void SetKallsyms(std::string kallsyms) { |
| 126 | if (!kallsyms.empty()) { |
| 127 | kallsyms_ = std::move(kallsyms); |
| 128 | } |
| 129 | } |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 130 | static void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids); |
Yabin Cui | 52c6369 | 2016-11-28 17:28:08 -0800 | [diff] [blame] | 131 | static BuildId FindExpectedBuildIdForPath(const std::string& path); |
Yabin Cui | c68e66d | 2018-03-07 15:47:15 -0800 | [diff] [blame] | 132 | static void SetVdsoFile(const std::string& vdso_file, bool is_64bit); |
Yabin Cui | b10a8fb | 2015-08-18 16:32:18 -0700 | [diff] [blame] | 133 | |
Yabin Cui | 63a1c3d | 2017-05-19 12:57:44 -0700 | [diff] [blame] | 134 | static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path, |
| 135 | bool force_64bit = false); |
Yabin Cui | 16f41ff | 2021-03-23 14:58:25 -0700 | [diff] [blame] | 136 | static std::unique_ptr<Dso> CreateDsoWithBuildId(DsoType dso_type, const std::string& dso_path, |
| 137 | BuildId& build_id); |
Yabin Cui | f3da1ed | 2020-11-25 15:37:38 -0800 | [diff] [blame] | 138 | static std::unique_ptr<Dso> CreateKernelModuleDso(const std::string& dso_path, |
| 139 | uint64_t memory_start, uint64_t memory_end, |
| 140 | Dso* kernel_dso); |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 141 | virtual ~Dso(); |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 142 | |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 143 | DsoType type() const { return type_; } |
| 144 | |
Yabin Cui | 3c8c213 | 2015-08-13 20:30:20 -0700 | [diff] [blame] | 145 | // Return the path recorded in perf.data. |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 146 | const std::string& Path() const { return path_; } |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 147 | // Return the path containing symbol table and debug information. |
Yabin Cui | 11424c4 | 2022-03-10 16:04:04 -0800 | [diff] [blame] | 148 | const std::string& GetDebugFilePath() const { |
| 149 | if (!debug_file_path_.has_value()) { |
| 150 | debug_file_path_ = FindDebugFilePath(); |
| 151 | } |
| 152 | return debug_file_path_.value(); |
| 153 | } |
| 154 | |
Yabin Cui | e32ed2b | 2020-07-23 15:30:14 -0700 | [diff] [blame] | 155 | // Return the path beautified for reporting. |
| 156 | virtual std::string_view GetReportPath() const { return Path(); } |
Yabin Cui | 15475e6 | 2016-07-14 13:26:19 -0700 | [diff] [blame] | 157 | // Return the file name without directory info. |
| 158 | const std::string& FileName() const { return file_name_; } |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 159 | |
Thiébaud Weksteen | 4848ee0 | 2020-10-23 16:06:59 +0200 | [diff] [blame] | 160 | bool HasDumpId() { return dump_id_ != UINT_MAX; } |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 161 | |
| 162 | bool GetDumpId(uint32_t* pdump_id) { |
| 163 | if (!HasDumpId()) { |
| 164 | return false; |
| 165 | } |
| 166 | *pdump_id = dump_id_; |
| 167 | return true; |
| 168 | } |
| 169 | |
| 170 | uint32_t CreateDumpId(); |
| 171 | uint32_t CreateSymbolDumpId(const Symbol* symbol); |
Yabin Cui | 78fddd1 | 2016-10-24 14:09:26 -0700 | [diff] [blame] | 172 | |
Yabin Cui | db2c493 | 2019-02-07 15:06:42 -0800 | [diff] [blame] | 173 | virtual void SetMinExecutableVaddr(uint64_t, uint64_t) {} |
| 174 | virtual void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) { |
| 175 | *min_vaddr = 0; |
| 176 | *file_offset = 0; |
| 177 | } |
Yabin Cui | dd401b3 | 2018-04-11 11:17:06 -0700 | [diff] [blame] | 178 | virtual void AddDexFileOffset(uint64_t) {} |
| 179 | virtual const std::vector<uint64_t>* DexFileOffsets() { return nullptr; } |
Yabin Cui | 547c60e | 2015-10-12 16:56:05 -0700 | [diff] [blame] | 180 | |
Yabin Cui | db2c493 | 2019-02-07 15:06:42 -0800 | [diff] [blame] | 181 | virtual uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) = 0; |
Yabin Cui | 7078c67 | 2020-11-10 16:24:12 -0800 | [diff] [blame] | 182 | virtual std::optional<uint64_t> IpToFileOffset(uint64_t ip, uint64_t map_start, |
| 183 | uint64_t map_pgoff); |
Yabin Cui | db2c493 | 2019-02-07 15:06:42 -0800 | [diff] [blame] | 184 | |
Yabin Cui | 547c60e | 2015-10-12 16:56:05 -0700 | [diff] [blame] | 185 | const Symbol* FindSymbol(uint64_t vaddr_in_dso); |
Yabin Cui | f3da1ed | 2020-11-25 15:37:38 -0800 | [diff] [blame] | 186 | void LoadSymbols(); |
Yabin Cui | ac4b249 | 2020-12-09 16:27:57 -0800 | [diff] [blame] | 187 | const std::vector<Symbol>& GetSymbols() const { return symbols_; } |
Yabin Cui | c5b4a31 | 2016-10-24 13:38:38 -0700 | [diff] [blame] | 188 | void SetSymbols(std::vector<Symbol>* symbols); |
| 189 | |
| 190 | // Create a symbol for a virtual address which can't find a corresponding |
| 191 | // symbol in symbol table. |
| 192 | void AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name); |
Yabin Cui | ac4b249 | 2020-12-09 16:27:57 -0800 | [diff] [blame] | 193 | bool IsForJavaMethod() const; |
Yabin Cui | b378355 | 2015-06-11 11:15:42 -0700 | [diff] [blame] | 194 | |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 195 | protected: |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 196 | static bool demangle_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 197 | static std::string vmlinux_; |
Yabin Cui | b421297 | 2016-05-25 14:08:05 -0700 | [diff] [blame] | 198 | static std::string kallsyms_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 199 | static std::unordered_map<std::string, BuildId> build_id_map_; |
Yabin Cui | cc2e59e | 2015-08-21 14:23:43 -0700 | [diff] [blame] | 200 | static size_t dso_count_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 201 | static uint32_t g_dump_id_; |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 202 | static simpleperf_dso_impl::DebugElfFileFinder debug_elf_file_finder_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 203 | |
Yabin Cui | 11424c4 | 2022-03-10 16:04:04 -0800 | [diff] [blame] | 204 | Dso(DsoType type, const std::string& path); |
| 205 | BuildId GetExpectedBuildId() const; |
Yabin Cui | 516a87c | 2018-03-26 17:34:00 -0700 | [diff] [blame] | 206 | |
Yabin Cui | 11424c4 | 2022-03-10 16:04:04 -0800 | [diff] [blame] | 207 | virtual std::string FindDebugFilePath() const { return path_; } |
Yabin Cui | f3da1ed | 2020-11-25 15:37:38 -0800 | [diff] [blame] | 208 | virtual std::vector<Symbol> LoadSymbolsImpl() = 0; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 209 | |
Yabin Cui | dd401b3 | 2018-04-11 11:17:06 -0700 | [diff] [blame] | 210 | DsoType type_; |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 211 | // path of the shared library used by the profiled program |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 212 | const std::string path_; |
Yabin Cui | eec606c | 2016-07-07 13:53:33 -0700 | [diff] [blame] | 213 | // path of the shared library having symbol table and debug information |
| 214 | // It is the same as path_, or has the same build id as path_. |
Yabin Cui | 11424c4 | 2022-03-10 16:04:04 -0800 | [diff] [blame] | 215 | mutable std::optional<std::string> debug_file_path_; |
Yabin Cui | 15475e6 | 2016-07-14 13:26:19 -0700 | [diff] [blame] | 216 | // File name of the shared library, got by removing directories in path_. |
| 217 | std::string file_name_; |
Yabin Cui | c5b4a31 | 2016-10-24 13:38:38 -0700 | [diff] [blame] | 218 | std::vector<Symbol> symbols_; |
| 219 | // unknown symbols are like [libc.so+0x1234]. |
| 220 | std::unordered_map<uint64_t, Symbol> unknown_symbols_; |
Yabin Cui | c848560 | 2015-08-20 15:04:39 -0700 | [diff] [blame] | 221 | bool is_loaded_; |
Yabin Cui | 16501ff | 2016-10-19 15:06:29 -0700 | [diff] [blame] | 222 | // Used to identify current dso if it needs to be dumped. |
| 223 | uint32_t dump_id_; |
| 224 | // Used to assign dump_id for symbols in current dso. |
| 225 | uint32_t symbol_dump_id_; |
Yabin Cui | e466d4d | 2017-08-11 17:03:07 -0700 | [diff] [blame] | 226 | android::base::LogSeverity symbol_warning_loglevel_; |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 227 | }; |
| 228 | |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 229 | const char* DsoTypeToString(DsoType dso_type); |
Yabin Cui | 40b70ff | 2018-04-09 14:06:08 -0700 | [diff] [blame] | 230 | bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id); |
Yabin Cui | 767dd17 | 2016-06-02 21:02:43 -0700 | [diff] [blame] | 231 | |
Yabin Cui | faa7b92 | 2021-01-11 17:35:57 -0800 | [diff] [blame] | 232 | } // namespace simpleperf |
| 233 | |
Yabin Cui | ec12ed9 | 2015-06-08 10:38:10 -0700 | [diff] [blame] | 234 | #endif // SIMPLE_PERF_DSO_H_ |