blob: d8096ca6b8a2a57de888bad9c01499af109b2365 [file] [log] [blame]
Yabin Cuiec12ed92015-06-08 10:38:10 -07001/*
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#include "dso.h"
18
Yabin Cuib3783552015-06-11 11:15:42 -070019#include <stdlib.h>
Yabin Cuicc2e59e2015-08-21 14:23:43 -070020#include <string.h>
Yabin Cuic8485602015-08-20 15:04:39 -070021
Yabin Cuicc2e59e2015-08-21 14:23:43 -070022#include <algorithm>
Yabin Cuic8485602015-08-20 15:04:39 -070023#include <limits>
Yabin Cuidd401b32018-04-11 11:17:06 -070024#include <memory>
Yabin Cuicc2e59e2015-08-21 14:23:43 -070025#include <vector>
Yabin Cuic8485602015-08-20 15:04:39 -070026
Yabin Cuib4212972016-05-25 14:08:05 -070027#include <android-base/file.h>
Elliott Hughes66dd09e2015-12-04 14:00:57 -080028#include <android-base/logging.h>
Yabin Cui40b70ff2018-04-09 14:06:08 -070029#include <android-base/strings.h>
Yabin Cuic8485602015-08-20 15:04:39 -070030
Yabin Cuiec12ed92015-06-08 10:38:10 -070031#include "environment.h"
Yabin Cuib1a885b2016-02-14 19:18:02 -080032#include "read_apk.h"
Yabin Cui516a87c2018-03-26 17:34:00 -070033#include "read_dex_file.h"
Yabin Cuiec12ed92015-06-08 10:38:10 -070034#include "read_elf.h"
Yabin Cuib3783552015-06-11 11:15:42 -070035#include "utils.h"
Yabin Cuiec12ed92015-06-08 10:38:10 -070036
Yabin Cui3a880452020-06-29 16:37:31 -070037using namespace simpleperf;
38
Yabin Cui40b70ff2018-04-09 14:06:08 -070039namespace simpleperf_dso_impl {
40
Yabin Cui1b9b1c12018-10-29 14:23:48 -070041std::string RemovePathSeparatorSuffix(const std::string& path) {
42 // Don't remove path separator suffix for '/'.
43 if (android::base::EndsWith(path, OS_PATH_SEPARATOR) && path.size() > 1u) {
44 return path.substr(0, path.size() - 1);
45 }
46 return path;
47}
48
Yabin Cui40b70ff2018-04-09 14:06:08 -070049void DebugElfFileFinder::Reset() {
50 vdso_64bit_.clear();
51 vdso_32bit_.clear();
52 symfs_dir_.clear();
53 build_id_to_file_map_.clear();
54}
55
56bool DebugElfFileFinder::SetSymFsDir(const std::string& symfs_dir) {
Yabin Cui1b9b1c12018-10-29 14:23:48 -070057 symfs_dir_ = RemovePathSeparatorSuffix(symfs_dir);
58 if (!IsDir(symfs_dir_)) {
59 LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir_ << "'";
60 return false;
Yabin Cui40b70ff2018-04-09 14:06:08 -070061 }
Yabin Cui1b9b1c12018-10-29 14:23:48 -070062 std::string build_id_list_file = symfs_dir_ + OS_PATH_SEPARATOR + "build_id_list";
Yabin Cui40b70ff2018-04-09 14:06:08 -070063 std::string build_id_list;
64 if (android::base::ReadFileToString(build_id_list_file, &build_id_list)) {
65 for (auto& line : android::base::Split(build_id_list, "\n")) {
Yabin Cui2969a9e2018-04-19 17:06:24 -070066 std::vector<std::string> items = android::base::Split(line, "=");
Yabin Cui40b70ff2018-04-09 14:06:08 -070067 if (items.size() == 2u) {
Yabin Cui1b9b1c12018-10-29 14:23:48 -070068 build_id_to_file_map_[items[0]] = symfs_dir_ + OS_PATH_SEPARATOR + items[1];
Yabin Cui40b70ff2018-04-09 14:06:08 -070069 }
70 }
71 }
72 return true;
73}
74
Yabin Cui3939b9d2018-07-20 17:12:13 -070075bool DebugElfFileFinder::AddSymbolDir(const std::string& symbol_dir) {
76 if (!IsDir(symbol_dir)) {
77 LOG(ERROR) << "Invalid symbol dir " << symbol_dir;
78 return false;
79 }
Yabin Cui1b9b1c12018-10-29 14:23:48 -070080 std::string dir = RemovePathSeparatorSuffix(symbol_dir);
Yabin Cui3939b9d2018-07-20 17:12:13 -070081 CollectBuildIdInDir(dir);
82 return true;
83}
84
85void DebugElfFileFinder::CollectBuildIdInDir(const std::string& dir) {
86 for (const std::string& entry : GetEntriesInDir(dir)) {
Yabin Cui1b9b1c12018-10-29 14:23:48 -070087 std::string path = dir + OS_PATH_SEPARATOR + entry;
Yabin Cui3939b9d2018-07-20 17:12:13 -070088 if (IsDir(path)) {
89 CollectBuildIdInDir(path);
90 } else {
91 BuildId build_id;
Yabin Cui3a880452020-06-29 16:37:31 -070092 ElfStatus status;
93 auto elf = ElfFile::Open(path, &status);
94 if (status == ElfStatus::NO_ERROR && elf->GetBuildId(&build_id) == ElfStatus::NO_ERROR) {
Yabin Cui3939b9d2018-07-20 17:12:13 -070095 build_id_to_file_map_[build_id.ToString()] = path;
96 }
97 }
98 }
99}
100
Yabin Cui40b70ff2018-04-09 14:06:08 -0700101void DebugElfFileFinder::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
102 if (is_64bit) {
103 vdso_64bit_ = vdso_file;
104 } else {
105 vdso_32bit_ = vdso_file;
106 }
107}
108
109std::string DebugElfFileFinder::FindDebugFile(const std::string& dso_path, bool force_64bit,
110 BuildId& build_id) {
111 if (dso_path == "[vdso]") {
112 if (force_64bit && !vdso_64bit_.empty()) {
113 return vdso_64bit_;
114 } else if (!force_64bit && !vdso_32bit_.empty()) {
115 return vdso_32bit_;
116 }
Yabin Cui3939b9d2018-07-20 17:12:13 -0700117 }
Yabin Cuid347bb42019-11-14 15:24:07 -0800118 if (build_id.IsEmpty()) {
119 // Try reading build id from file if we don't already have one.
120 GetBuildIdFromDsoPath(dso_path, &build_id);
121 }
Yabin Cui3939b9d2018-07-20 17:12:13 -0700122 auto check_path = [&](const std::string& path) {
123 BuildId debug_build_id;
Yabin Cuid347bb42019-11-14 15:24:07 -0800124 GetBuildIdFromDsoPath(path, &debug_build_id);
125 if (build_id.IsEmpty()) {
126 // Native libraries in apks may not have build ids. When looking for a debug elf file without
127 // build id (build id is empty), the debug file should exist and also not have build id.
128 return IsRegularFile(path) && debug_build_id.IsEmpty();
Yabin Cui3939b9d2018-07-20 17:12:13 -0700129 }
Yabin Cuid347bb42019-11-14 15:24:07 -0800130 return build_id == debug_build_id;
Yabin Cui3939b9d2018-07-20 17:12:13 -0700131 };
132
Yabin Cui5d269c72019-05-31 15:30:17 -0700133 // 1. Try build_id_to_file_map.
134 if (!build_id_to_file_map_.empty()) {
135 if (!build_id.IsEmpty() || GetBuildIdFromDsoPath(dso_path, &build_id)) {
136 auto it = build_id_to_file_map_.find(build_id.ToString());
137 if (it != build_id_to_file_map_.end() && check_path(it->second)) {
138 return it->second;
139 }
140 }
141 }
Yabin Cui1b9b1c12018-10-29 14:23:48 -0700142 if (!symfs_dir_.empty()) {
Yabin Cuia4496ad2019-11-18 16:40:28 -0800143 // 2. Try concatenating symfs_dir and dso_path.
Yabin Cui1b9b1c12018-10-29 14:23:48 -0700144 std::string path = GetPathInSymFsDir(dso_path);
145 if (check_path(path)) {
146 return path;
147 }
Yabin Cuia4496ad2019-11-18 16:40:28 -0800148 // 3. Try concatenating symfs_dir and basename of dso_path.
149 path = symfs_dir_ + OS_PATH_SEPARATOR + android::base::Basename(dso_path);
150 if (check_path(path)) {
151 return path;
152 }
Yabin Cui3939b9d2018-07-20 17:12:13 -0700153 }
Yabin Cuia4496ad2019-11-18 16:40:28 -0800154 // 4. Try concatenating /usr/lib/debug and dso_path.
Yabin Cui3939b9d2018-07-20 17:12:13 -0700155 // Linux host can store debug shared libraries in /usr/lib/debug.
156 if (check_path("/usr/lib/debug" + dso_path)) {
157 return "/usr/lib/debug" + dso_path;
158 }
Yabin Cui40b70ff2018-04-09 14:06:08 -0700159 return dso_path;
160}
Yabin Cui1b9b1c12018-10-29 14:23:48 -0700161
162std::string DebugElfFileFinder::GetPathInSymFsDir(const std::string& path) {
163 auto add_symfs_prefix = [&](const std::string& path) {
164 if (android::base::StartsWith(path, OS_PATH_SEPARATOR)) {
165 return symfs_dir_ + path;
166 }
167 return symfs_dir_ + OS_PATH_SEPARATOR + path;
168 };
169 if (OS_PATH_SEPARATOR == '/') {
170 return add_symfs_prefix(path);
171 }
172 // Paths in recorded perf.data uses '/' as path separator. When reporting on Windows, it needs
173 // to be converted to '\\'.
174 auto tuple = SplitUrlInApk(path);
175 if (std::get<0>(tuple)) {
176 std::string apk_path = std::get<1>(tuple);
177 std::string entry_path = std::get<2>(tuple);
178 std::replace(apk_path.begin(), apk_path.end(), '/', OS_PATH_SEPARATOR);
179 return GetUrlInApk(add_symfs_prefix(apk_path), entry_path);
180 }
181 std::string elf_path = path;
182 std::replace(elf_path.begin(), elf_path.end(), '/', OS_PATH_SEPARATOR);
183 return add_symfs_prefix(elf_path);
184}
Yabin Cui40b70ff2018-04-09 14:06:08 -0700185} // namespace simpleperf_dso_imp
186
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700187static OneTimeFreeAllocator symbol_name_allocator;
188
Martin Stjernholm7c27cc22018-11-28 00:46:00 +0000189Symbol::Symbol(std::string_view name, uint64_t addr, uint64_t len)
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700190 : addr(addr),
191 len(len),
192 name_(symbol_name_allocator.AllocateString(name)),
Yabin Cui767dd172016-06-02 21:02:43 -0700193 demangled_name_(nullptr),
Yabin Cui516a87c2018-03-26 17:34:00 -0700194 dump_id_(UINT_MAX) {
195}
Yabin Cuib10a8fb2015-08-18 16:32:18 -0700196
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700197const char* Symbol::DemangledName() const {
198 if (demangled_name_ == nullptr) {
199 const std::string s = Dso::Demangle(name_);
200 if (s == name_) {
201 demangled_name_ = name_;
202 } else {
203 demangled_name_ = symbol_name_allocator.AllocateString(s);
204 }
205 }
206 return demangled_name_;
Yabin Cuiec12ed92015-06-08 10:38:10 -0700207}
208
Yabin Cuic8485602015-08-20 15:04:39 -0700209bool Dso::demangle_ = true;
Yabin Cuic8485602015-08-20 15:04:39 -0700210std::string Dso::vmlinux_;
Yabin Cuib4212972016-05-25 14:08:05 -0700211std::string Dso::kallsyms_;
Yabin Cuia9392452017-01-12 18:07:27 -0800212bool Dso::read_kernel_symbols_from_proc_;
Yabin Cuic8485602015-08-20 15:04:39 -0700213std::unordered_map<std::string, BuildId> Dso::build_id_map_;
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700214size_t Dso::dso_count_;
Yabin Cui16501ff2016-10-19 15:06:29 -0700215uint32_t Dso::g_dump_id_;
Yabin Cui40b70ff2018-04-09 14:06:08 -0700216simpleperf_dso_impl::DebugElfFileFinder Dso::debug_elf_file_finder_;
Yabin Cuiba50c4b2015-07-21 11:24:48 -0700217
Yabin Cui767dd172016-06-02 21:02:43 -0700218void Dso::SetDemangle(bool demangle) { demangle_ = demangle; }
Yabin Cuib3783552015-06-11 11:15:42 -0700219
Yabin Cui767dd172016-06-02 21:02:43 -0700220extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n,
221 int* status);
Yabin Cuib10a8fb2015-08-18 16:32:18 -0700222
Yabin Cuic8485602015-08-20 15:04:39 -0700223std::string Dso::Demangle(const std::string& name) {
Yabin Cuib10a8fb2015-08-18 16:32:18 -0700224 if (!demangle_) {
225 return name;
226 }
227 int status;
228 bool is_linker_symbol = (name.find(linker_prefix) == 0);
229 const char* mangled_str = name.c_str();
230 if (is_linker_symbol) {
231 mangled_str += linker_prefix.size();
232 }
233 std::string result = name;
234 char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
235 if (status == 0) {
236 if (is_linker_symbol) {
237 result = std::string("[linker]") + demangled_name;
238 } else {
239 result = demangled_name;
240 }
241 free(demangled_name);
242 } else if (is_linker_symbol) {
243 result = std::string("[linker]") + mangled_str;
244 }
245 return result;
246}
247
Yabin Cuic8485602015-08-20 15:04:39 -0700248bool Dso::SetSymFsDir(const std::string& symfs_dir) {
Yabin Cui40b70ff2018-04-09 14:06:08 -0700249 return debug_elf_file_finder_.SetSymFsDir(symfs_dir);
Yabin Cuic8485602015-08-20 15:04:39 -0700250}
251
Yabin Cui3939b9d2018-07-20 17:12:13 -0700252bool Dso::AddSymbolDir(const std::string& symbol_dir) {
253 return debug_elf_file_finder_.AddSymbolDir(symbol_dir);
254}
255
Yabin Cui767dd172016-06-02 21:02:43 -0700256void Dso::SetVmlinux(const std::string& vmlinux) { vmlinux_ = vmlinux; }
Yabin Cuic8485602015-08-20 15:04:39 -0700257
Yabin Cui767dd172016-06-02 21:02:43 -0700258void Dso::SetBuildIds(
259 const std::vector<std::pair<std::string, BuildId>>& build_ids) {
Yabin Cuic8485602015-08-20 15:04:39 -0700260 std::unordered_map<std::string, BuildId> map;
261 for (auto& pair : build_ids) {
Yabin Cui767dd172016-06-02 21:02:43 -0700262 LOG(DEBUG) << "build_id_map: " << pair.first << ", "
263 << pair.second.ToString();
Yabin Cuic8485602015-08-20 15:04:39 -0700264 map.insert(pair);
265 }
266 build_id_map_ = std::move(map);
267}
268
Yabin Cuic68e66d2018-03-07 15:47:15 -0800269void Dso::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
Yabin Cui40b70ff2018-04-09 14:06:08 -0700270 debug_elf_file_finder_.SetVdsoFile(vdso_file, is_64bit);
Yabin Cui63a1c3d2017-05-19 12:57:44 -0700271}
272
Yabin Cui52c63692016-11-28 17:28:08 -0800273BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
274 auto it = build_id_map_.find(path);
Yabin Cuic8485602015-08-20 15:04:39 -0700275 if (it != build_id_map_.end()) {
276 return it->second;
277 }
278 return BuildId();
279}
280
Yabin Cui52c63692016-11-28 17:28:08 -0800281BuildId Dso::GetExpectedBuildId() {
282 return FindExpectedBuildIdForPath(path_);
283}
284
Yabin Cui516a87c2018-03-26 17:34:00 -0700285Dso::Dso(DsoType type, const std::string& path, const std::string& debug_file_path)
Yabin Cui767dd172016-06-02 21:02:43 -0700286 : type_(type),
Yabin Cui767dd172016-06-02 21:02:43 -0700287 path_(path),
Yabin Cui516a87c2018-03-26 17:34:00 -0700288 debug_file_path_(debug_file_path),
Yabin Cui767dd172016-06-02 21:02:43 -0700289 is_loaded_(false),
Yabin Cui16501ff2016-10-19 15:06:29 -0700290 dump_id_(UINT_MAX),
Yabin Cuie466d4d2017-08-11 17:03:07 -0700291 symbol_dump_id_(0),
292 symbol_warning_loglevel_(android::base::WARNING) {
Yabin Cui15475e62016-07-14 13:26:19 -0700293 size_t pos = path.find_last_of("/\\");
294 if (pos != std::string::npos) {
295 file_name_ = path.substr(pos + 1);
296 } else {
297 file_name_ = path;
298 }
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700299 dso_count_++;
Yabin Cuic8485602015-08-20 15:04:39 -0700300}
301
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700302Dso::~Dso() {
303 if (--dso_count_ == 0) {
Yabin Cuib4212972016-05-25 14:08:05 -0700304 // Clean up global variables when no longer used.
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700305 symbol_name_allocator.Clear();
Yabin Cuib4212972016-05-25 14:08:05 -0700306 demangle_ = true;
Yabin Cuib4212972016-05-25 14:08:05 -0700307 vmlinux_.clear();
308 kallsyms_.clear();
Yabin Cuia9392452017-01-12 18:07:27 -0800309 read_kernel_symbols_from_proc_ = false;
Yabin Cuib4212972016-05-25 14:08:05 -0700310 build_id_map_.clear();
Yabin Cui16501ff2016-10-19 15:06:29 -0700311 g_dump_id_ = 0;
Yabin Cui40b70ff2018-04-09 14:06:08 -0700312 debug_elf_file_finder_.Reset();
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700313 }
314}
315
Yabin Cui16501ff2016-10-19 15:06:29 -0700316uint32_t Dso::CreateDumpId() {
317 CHECK(!HasDumpId());
318 return dump_id_ = g_dump_id_++;
319}
320
321uint32_t Dso::CreateSymbolDumpId(const Symbol* symbol) {
322 CHECK(!symbol->HasDumpId());
323 symbol->dump_id_ = symbol_dump_id_++;
324 return symbol->dump_id_;
325}
326
Yabin Cui547c60e2015-10-12 16:56:05 -0700327const Symbol* Dso::FindSymbol(uint64_t vaddr_in_dso) {
Yabin Cuic8485602015-08-20 15:04:39 -0700328 if (!is_loaded_) {
Yabin Cuic5b4a312016-10-24 13:38:38 -0700329 Load();
330 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700331 auto it = std::upper_bound(symbols_.begin(), symbols_.end(),
332 Symbol("", vaddr_in_dso, 0),
333 Symbol::CompareValueByAddr);
334 if (it != symbols_.begin()) {
335 --it;
336 if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) {
337 return &*it;
Yabin Cuic8485602015-08-20 15:04:39 -0700338 }
339 }
Yabin Cuic5b4a312016-10-24 13:38:38 -0700340 if (!unknown_symbols_.empty()) {
341 auto it = unknown_symbols_.find(vaddr_in_dso);
342 if (it != unknown_symbols_.end()) {
343 return &it->second;
Yabin Cuic8485602015-08-20 15:04:39 -0700344 }
345 }
346 return nullptr;
347}
348
Yabin Cuic5b4a312016-10-24 13:38:38 -0700349void Dso::SetSymbols(std::vector<Symbol>* symbols) {
350 symbols_ = std::move(*symbols);
351 symbols->clear();
352}
353
354void Dso::AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name) {
355 unknown_symbols_.insert(std::make_pair(vaddr_in_dso, Symbol(name, vaddr_in_dso, 1)));
356}
357
Yabin Cui10bbd842018-08-13 17:42:25 -0700358bool Dso::IsForJavaMethod() {
359 if (type_ == DSO_DEX_FILE) {
360 return true;
361 }
362 if (type_ == DSO_ELF_FILE) {
363 // JIT symfiles for JITed Java methods are dumped as temporary files, whose name are in format
364 // "TemporaryFile-XXXXXX".
365 size_t pos = path_.rfind('/');
366 pos = (pos == std::string::npos) ? 0 : pos + 1;
367 return strncmp(&path_[pos], "TemporaryFile", strlen("TemporaryFile")) == 0;
368 }
369 return false;
370}
371
Yabin Cuic5b4a312016-10-24 13:38:38 -0700372void Dso::Load() {
373 is_loaded_ = true;
Yabin Cui516a87c2018-03-26 17:34:00 -0700374 std::vector<Symbol> symbols = LoadSymbols();
375 if (symbols_.empty()) {
376 symbols_ = std::move(symbols);
Yabin Cuidec43c12016-07-29 16:40:40 -0700377 } else {
Yabin Cui516a87c2018-03-26 17:34:00 -0700378 std::vector<Symbol> merged_symbols;
379 std::set_union(symbols_.begin(), symbols_.end(), symbols.begin(), symbols.end(),
380 std::back_inserter(merged_symbols), Symbol::CompareValueByAddr);
381 symbols_ = std::move(merged_symbols);
Yabin Cuic8485602015-08-20 15:04:39 -0700382 }
Yabin Cuiba50c4b2015-07-21 11:24:48 -0700383}
384
Yabin Cui516a87c2018-03-26 17:34:00 -0700385static void ReportReadElfSymbolResult(ElfStatus result, const std::string& path,
386 const std::string& debug_file_path,
387 android::base::LogSeverity warning_loglevel = android::base::WARNING) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700388 if (result == ElfStatus::NO_ERROR) {
Yabin Cui516a87c2018-03-26 17:34:00 -0700389 LOG(VERBOSE) << "Read symbols from " << debug_file_path << " successfully";
Yabin Cuidec43c12016-07-29 16:40:40 -0700390 } else if (result == ElfStatus::NO_SYMBOL_TABLE) {
Yabin Cui516a87c2018-03-26 17:34:00 -0700391 if (path == "[vdso]") {
Yabin Cui63a1c3d2017-05-19 12:57:44 -0700392 // Vdso only contains dynamic symbol table, and we can't change that.
Yabin Cui516a87c2018-03-26 17:34:00 -0700393 return;
Yabin Cui63a1c3d2017-05-19 12:57:44 -0700394 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700395 // Lacking symbol table isn't considered as an error but worth reporting.
Yabin Cui516a87c2018-03-26 17:34:00 -0700396 LOG(warning_loglevel) << debug_file_path << " doesn't contain symbol table";
Yabin Cuidec43c12016-07-29 16:40:40 -0700397 } else {
Yabin Cui516a87c2018-03-26 17:34:00 -0700398 LOG(warning_loglevel) << "failed to read symbols from " << debug_file_path << ": " << result;
Yabin Cuidec43c12016-07-29 16:40:40 -0700399 }
400}
401
Yabin Cui516a87c2018-03-26 17:34:00 -0700402static void SortAndFixSymbols(std::vector<Symbol>& symbols) {
403 std::sort(symbols.begin(), symbols.end(), Symbol::CompareValueByAddr);
Yabin Cuic8485602015-08-20 15:04:39 -0700404 Symbol* prev_symbol = nullptr;
Yabin Cui516a87c2018-03-26 17:34:00 -0700405 for (auto& symbol : symbols) {
Yabin Cuic8485602015-08-20 15:04:39 -0700406 if (prev_symbol != nullptr && prev_symbol->len == 0) {
Yabin Cuicc2e59e2015-08-21 14:23:43 -0700407 prev_symbol->len = symbol.addr - prev_symbol->addr;
Yabin Cuic8485602015-08-20 15:04:39 -0700408 }
Yabin Cui3d4aa262017-11-01 15:58:55 -0700409 prev_symbol = &symbol;
Yabin Cui638c5582015-07-01 16:16:57 -0700410 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700411}
412
Yabin Cuidd401b32018-04-11 11:17:06 -0700413class DexFileDso : public Dso {
414 public:
415 DexFileDso(const std::string& path, const std::string& debug_file_path)
416 : Dso(DSO_DEX_FILE, path, debug_file_path) {}
417
418 void AddDexFileOffset(uint64_t dex_file_offset) override {
Yabin Cuic8571d42018-06-06 11:20:39 -0700419 auto it = std::lower_bound(dex_file_offsets_.begin(), dex_file_offsets_.end(),
420 dex_file_offset);
421 if (it != dex_file_offsets_.end() && *it == dex_file_offset) {
422 return;
423 }
424 dex_file_offsets_.insert(it, dex_file_offset);
Yabin Cuidd401b32018-04-11 11:17:06 -0700425 }
426
427 const std::vector<uint64_t>* DexFileOffsets() override {
428 return &dex_file_offsets_;
429 }
430
Yabin Cuidb2c4932019-02-07 15:06:42 -0800431 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
432 return ip - map_start + map_pgoff;
433 }
434
Yabin Cuidd401b32018-04-11 11:17:06 -0700435 std::vector<Symbol> LoadSymbols() override {
436 std::vector<Symbol> symbols;
437 std::vector<DexFileSymbol> dex_file_symbols;
Yabin Cui2a53ff32018-05-21 17:37:00 -0700438 auto tuple = SplitUrlInApk(debug_file_path_);
439 bool status = false;
440 if (std::get<0>(tuple)) {
441 std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(std::get<1>(tuple));
442 ZipEntry entry;
443 std::vector<uint8_t> data;
Yabin Cui15749e02018-05-30 16:37:06 -0700444 if (ahelper &&
445 ahelper->FindEntry(std::get<2>(tuple), &entry) && ahelper->GetEntryData(entry, &data)) {
Yabin Cui2a53ff32018-05-21 17:37:00 -0700446 status = ReadSymbolsFromDexFileInMemory(data.data(), data.size(), dex_file_offsets_,
447 &dex_file_symbols);
448 }
449 } else {
450 status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, &dex_file_symbols);
451 }
452 if (!status) {
Yabin Cuidd401b32018-04-11 11:17:06 -0700453 android::base::LogSeverity level = symbols_.empty() ? android::base::WARNING
454 : android::base::DEBUG;
455 LOG(level) << "Failed to read symbols from " << debug_file_path_;
456 return symbols;
457 }
458 LOG(VERBOSE) << "Read symbols from " << debug_file_path_ << " successfully";
459 for (auto& symbol : dex_file_symbols) {
460 symbols.emplace_back(symbol.name, symbol.offset, symbol.len);
461 }
462 SortAndFixSymbols(symbols);
463 return symbols;
464 }
465
466 private:
467 std::vector<uint64_t> dex_file_offsets_;
468};
469
Yabin Cui516a87c2018-03-26 17:34:00 -0700470class ElfDso : public Dso {
471 public:
472 ElfDso(const std::string& path, const std::string& debug_file_path)
Yabin Cuidb2c4932019-02-07 15:06:42 -0800473 : Dso(DSO_ELF_FILE, path, debug_file_path) {}
Yabin Cui516a87c2018-03-26 17:34:00 -0700474
Yabin Cuidb2c4932019-02-07 15:06:42 -0800475 void SetMinExecutableVaddr(uint64_t min_vaddr, uint64_t file_offset) override {
476 min_vaddr_ = min_vaddr;
477 file_offset_of_min_vaddr_ = file_offset;
Yabin Cuic8485602015-08-20 15:04:39 -0700478 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700479
Yabin Cuidb2c4932019-02-07 15:06:42 -0800480 void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) override {
481 if (type_ == DSO_DEX_FILE) {
482 return dex_file_dso_->GetMinExecutableVaddr(min_vaddr, file_offset);
483 }
484 if (min_vaddr_ == uninitialized_value) {
485 min_vaddr_ = 0;
486 BuildId build_id = GetExpectedBuildId();
487 uint64_t addr;
488 uint64_t offset;
489 ElfStatus result;
490 auto tuple = SplitUrlInApk(debug_file_path_);
491 if (std::get<0>(tuple)) {
492 EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple),
493 std::get<2>(tuple));
494 if (elf == nullptr) {
495 result = ElfStatus::FILE_NOT_FOUND;
496 } else {
497 result = ReadMinExecutableVirtualAddressFromEmbeddedElfFile(
498 elf->filepath(), elf->entry_offset(), elf->entry_size(), build_id, &addr, &offset);
499 }
500 } else {
501 result = ReadMinExecutableVirtualAddressFromElfFile(debug_file_path_, build_id, &addr,
502 &offset);
503 }
504 if (result != ElfStatus::NO_ERROR) {
505 LOG(WARNING) << "failed to read min virtual address of "
506 << GetDebugFilePath() << ": " << result;
507 } else {
508 min_vaddr_ = addr;
509 file_offset_of_min_vaddr_ = offset;
510 }
511 }
512 *min_vaddr = min_vaddr_;
513 *file_offset = file_offset_of_min_vaddr_;
514 }
515
516 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
517 if (type_ == DSO_DEX_FILE) {
518 return dex_file_dso_->IpToVaddrInFile(ip, map_start, map_pgoff);
519 }
520 uint64_t min_vaddr;
521 uint64_t file_offset_of_min_vaddr;
522 GetMinExecutableVaddr(&min_vaddr, &file_offset_of_min_vaddr);
523 if (file_offset_of_min_vaddr == uninitialized_value) {
524 return ip - map_start + min_vaddr;
525 }
526 // Apps may make part of the executable segment of a shared library writeable, which can
527 // generate multiple executable segments at runtime. So use map_pgoff to calculate
528 // vaddr_in_file.
529 return ip - map_start + map_pgoff - file_offset_of_min_vaddr + min_vaddr;
Yabin Cui516a87c2018-03-26 17:34:00 -0700530 }
531
Yabin Cuidd401b32018-04-11 11:17:06 -0700532 void AddDexFileOffset(uint64_t dex_file_offset) override {
533 if (type_ == DSO_ELF_FILE) {
534 // When simpleperf does unwinding while recording, it processes mmap records before reading
535 // dex file linked list (via JITDebugReader). To process mmap records, it creates Dso
536 // objects of type ELF_FILE. Then after reading dex file linked list, it realizes some
537 // ELF_FILE Dso objects should actually be DEX_FILE, because they have dex file offsets.
538 // So here converts ELF_FILE Dso into DEX_FILE Dso.
539 type_ = DSO_DEX_FILE;
540 dex_file_dso_.reset(new DexFileDso(path_, path_));
541 }
542 dex_file_dso_->AddDexFileOffset(dex_file_offset);
543 }
544
545 const std::vector<uint64_t>* DexFileOffsets() override {
546 return dex_file_dso_ ? dex_file_dso_->DexFileOffsets() : nullptr;
547 }
548
Yabin Cui516a87c2018-03-26 17:34:00 -0700549 protected:
550 std::vector<Symbol> LoadSymbols() override {
Yabin Cuidd401b32018-04-11 11:17:06 -0700551 if (dex_file_dso_) {
552 return dex_file_dso_->LoadSymbols();
553 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700554 std::vector<Symbol> symbols;
555 BuildId build_id = GetExpectedBuildId();
556 auto symbol_callback = [&](const ElfFileSymbol& symbol) {
557 if (symbol.is_func || (symbol.is_label && symbol.is_in_text_section)) {
558 symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len);
559 }
560 };
561 ElfStatus status;
Yabin Cui01947032020-06-30 14:36:46 -0700562 auto elf = ElfFile::Open(debug_file_path_, &build_id, &status);
563 if (elf) {
564 status = elf->ParseSymbols(symbol_callback);
Yabin Cui516a87c2018-03-26 17:34:00 -0700565 }
566 ReportReadElfSymbolResult(status, path_, debug_file_path_,
567 symbols_.empty() ? android::base::WARNING : android::base::DEBUG);
568 SortAndFixSymbols(symbols);
569 return symbols;
570 }
571
572 private:
Yabin Cuidb2c4932019-02-07 15:06:42 -0800573 static constexpr uint64_t uninitialized_value = std::numeric_limits<uint64_t>::max();
574
575 uint64_t min_vaddr_ = uninitialized_value;
576 uint64_t file_offset_of_min_vaddr_ = uninitialized_value;
Yabin Cuidd401b32018-04-11 11:17:06 -0700577 std::unique_ptr<DexFileDso> dex_file_dso_;
Yabin Cui516a87c2018-03-26 17:34:00 -0700578};
579
580class KernelDso : public Dso {
581 public:
582 KernelDso(const std::string& path, const std::string& debug_file_path)
583 : Dso(DSO_KERNEL, path, debug_file_path) {}
584
Yabin Cuidb2c4932019-02-07 15:06:42 -0800585 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
586 return ip;
587 }
588
Yabin Cui516a87c2018-03-26 17:34:00 -0700589 protected:
590 std::vector<Symbol> LoadSymbols() override {
591 std::vector<Symbol> symbols;
592 BuildId build_id = GetExpectedBuildId();
593 if (!vmlinux_.empty()) {
594 auto symbol_callback = [&](const ElfFileSymbol& symbol) {
595 if (symbol.is_func) {
596 symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len);
597 }
598 };
Yabin Cui01947032020-06-30 14:36:46 -0700599 ElfStatus status;
600 auto elf = ElfFile::Open(vmlinux_, &build_id, &status);
601 if (elf) {
602 status = elf->ParseSymbols(symbol_callback);
603 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700604 ReportReadElfSymbolResult(status, path_, vmlinux_);
605 } else if (!kallsyms_.empty()) {
606 symbols = ReadSymbolsFromKallsyms(kallsyms_);
607 } else if (read_kernel_symbols_from_proc_ || !build_id.IsEmpty()) {
608 // Try /proc/kallsyms only when asked to do so, or when build id matches.
609 // Otherwise, it is likely to use /proc/kallsyms on host for perf.data recorded on device.
610 bool can_read_kallsyms = true;
611 if (!build_id.IsEmpty()) {
612 BuildId real_build_id;
613 if (!GetKernelBuildId(&real_build_id) || build_id != real_build_id) {
614 LOG(DEBUG) << "failed to read symbols from /proc/kallsyms: Build id mismatch";
615 can_read_kallsyms = false;
616 }
617 }
618 if (can_read_kallsyms) {
619 std::string kallsyms;
620 if (!android::base::ReadFileToString("/proc/kallsyms", &kallsyms)) {
621 LOG(DEBUG) << "failed to read /proc/kallsyms";
622 } else {
623 symbols = ReadSymbolsFromKallsyms(kallsyms);
624 }
625 }
626 }
627 SortAndFixSymbols(symbols);
628 if (!symbols.empty()) {
629 symbols.back().len = std::numeric_limits<uint64_t>::max() - symbols.back().addr;
630 }
631 return symbols;
632 }
633
634 private:
635 std::vector<Symbol> ReadSymbolsFromKallsyms(std::string& kallsyms) {
636 std::vector<Symbol> symbols;
637 auto symbol_callback = [&](const KernelSymbol& symbol) {
638 if (strchr("TtWw", symbol.type) && symbol.addr != 0u) {
639 symbols.emplace_back(symbol.name, symbol.addr, 0);
640 }
641 return false;
642 };
643 ProcessKernelSymbols(kallsyms, symbol_callback);
644 if (symbols.empty()) {
645 LOG(WARNING) << "Symbol addresses in /proc/kallsyms on device are all zero. "
646 "`echo 0 >/proc/sys/kernel/kptr_restrict` if possible.";
647 }
648 return symbols;
649 }
650};
651
652class KernelModuleDso : public Dso {
653 public:
654 KernelModuleDso(const std::string& path, const std::string& debug_file_path)
655 : Dso(DSO_KERNEL_MODULE, path, debug_file_path) {}
656
Yabin Cuidb2c4932019-02-07 15:06:42 -0800657 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override {
658 return ip - map_start;
659 }
660
Yabin Cui516a87c2018-03-26 17:34:00 -0700661 protected:
662 std::vector<Symbol> LoadSymbols() override {
663 std::vector<Symbol> symbols;
664 BuildId build_id = GetExpectedBuildId();
665 auto symbol_callback = [&](const ElfFileSymbol& symbol) {
666 if (symbol.is_func || symbol.is_in_text_section) {
667 symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len);
668 }
669 };
Yabin Cui01947032020-06-30 14:36:46 -0700670 ElfStatus status;
671 auto elf = ElfFile::Open(debug_file_path_, &build_id, &status);
672 if (elf) {
673 status = elf->ParseSymbols(symbol_callback);
674 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700675 ReportReadElfSymbolResult(status, path_, debug_file_path_,
676 symbols_.empty() ? android::base::WARNING : android::base::DEBUG);
677 SortAndFixSymbols(symbols);
678 return symbols;
679 }
680};
681
Yabin Cuic36ea8b2018-04-16 18:21:40 -0700682class UnknownDso : public Dso {
683 public:
684 UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {}
685
Yabin Cuidb2c4932019-02-07 15:06:42 -0800686 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
687 return ip;
688 }
689
Yabin Cuic36ea8b2018-04-16 18:21:40 -0700690 protected:
691 std::vector<Symbol> LoadSymbols() override {
692 return std::vector<Symbol>();
693 }
694};
695
Yabin Cui516a87c2018-03-26 17:34:00 -0700696std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path,
697 bool force_64bit) {
Yabin Cui516a87c2018-03-26 17:34:00 -0700698 switch (dso_type) {
Yabin Cui40b70ff2018-04-09 14:06:08 -0700699 case DSO_ELF_FILE: {
700 BuildId build_id = FindExpectedBuildIdForPath(dso_path);
701 return std::unique_ptr<Dso>(new ElfDso(dso_path,
702 debug_elf_file_finder_.FindDebugFile(dso_path, force_64bit, build_id)));
703 }
Yabin Cui516a87c2018-03-26 17:34:00 -0700704 case DSO_KERNEL:
705 return std::unique_ptr<Dso>(new KernelDso(dso_path, dso_path));
706 case DSO_KERNEL_MODULE:
Yabin Cui40b70ff2018-04-09 14:06:08 -0700707 return std::unique_ptr<Dso>(new KernelModuleDso(dso_path, dso_path));
Yabin Cui516a87c2018-03-26 17:34:00 -0700708 case DSO_DEX_FILE:
Yabin Cui40b70ff2018-04-09 14:06:08 -0700709 return std::unique_ptr<Dso>(new DexFileDso(dso_path, dso_path));
Yabin Cuic36ea8b2018-04-16 18:21:40 -0700710 case DSO_UNKNOWN_FILE:
711 return std::unique_ptr<Dso>(new UnknownDso(dso_path));
Yabin Cui516a87c2018-03-26 17:34:00 -0700712 default:
713 LOG(FATAL) << "Unexpected dso_type " << static_cast<int>(dso_type);
714 }
715 return nullptr;
716}
717
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700718std::unique_ptr<Dso> Dso::CreateElfDsoWithBuildId(const std::string& dso_path, BuildId& build_id) {
719 return std::unique_ptr<Dso>(
720 new ElfDso(dso_path, debug_elf_file_finder_.FindDebugFile(dso_path, false, build_id)));
721}
722
Yabin Cui767dd172016-06-02 21:02:43 -0700723const char* DsoTypeToString(DsoType dso_type) {
724 switch (dso_type) {
725 case DSO_KERNEL:
726 return "dso_kernel";
727 case DSO_KERNEL_MODULE:
728 return "dso_kernel_module";
729 case DSO_ELF_FILE:
730 return "dso_elf_file";
Yabin Cui516a87c2018-03-26 17:34:00 -0700731 case DSO_DEX_FILE:
732 return "dso_dex_file";
Yabin Cui767dd172016-06-02 21:02:43 -0700733 default:
734 return "unknown";
735 }
736}
Yabin Cui40b70ff2018-04-09 14:06:08 -0700737
738bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id) {
Yabin Cui3a880452020-06-29 16:37:31 -0700739 ElfStatus status;
740 auto elf = ElfFile::Open(dso_path, &status);
741 if (status == ElfStatus::NO_ERROR && elf->GetBuildId(build_id) == ElfStatus::NO_ERROR) {
742 return true;
Yabin Cui40b70ff2018-04-09 14:06:08 -0700743 }
Yabin Cui3a880452020-06-29 16:37:31 -0700744 return false;
Yabin Cui40b70ff2018-04-09 14:06:08 -0700745}