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 #include "dso.h" 18 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include <algorithm> 23 #include <limits> 24 #include <memory> 25 #include <vector> 26 27 #include <android-base/file.h> 28 #include <android-base/logging.h> 29 #include <android-base/strings.h> 30 31 #include "environment.h" 32 #include "read_apk.h" 33 #include "read_dex_file.h" 34 #include "read_elf.h" 35 #include "utils.h" 36 37 namespace simpleperf_dso_impl { 38 39 std::string RemovePathSeparatorSuffix(const std::string& path) { 40 // Don't remove path separator suffix for '/'. 41 if (android::base::EndsWith(path, OS_PATH_SEPARATOR) && path.size() > 1u) { 42 return path.substr(0, path.size() - 1); 43 } 44 return path; 45 } 46 47 void DebugElfFileFinder::Reset() { 48 vdso_64bit_.clear(); 49 vdso_32bit_.clear(); 50 symfs_dir_.clear(); 51 build_id_to_file_map_.clear(); 52 } 53 54 bool DebugElfFileFinder::SetSymFsDir(const std::string& symfs_dir) { 55 symfs_dir_ = RemovePathSeparatorSuffix(symfs_dir); 56 if (!IsDir(symfs_dir_)) { 57 LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir_ << "'"; 58 return false; 59 } 60 std::string build_id_list_file = symfs_dir_ + OS_PATH_SEPARATOR + "build_id_list"; 61 std::string build_id_list; 62 if (android::base::ReadFileToString(build_id_list_file, &build_id_list)) { 63 for (auto& line : android::base::Split(build_id_list, "\n")) { 64 std::vector<std::string> items = android::base::Split(line, "="); 65 if (items.size() == 2u) { 66 build_id_to_file_map_[items[0]] = symfs_dir_ + OS_PATH_SEPARATOR + items[1]; 67 } 68 } 69 } 70 return true; 71 } 72 73 bool DebugElfFileFinder::AddSymbolDir(const std::string& symbol_dir) { 74 if (!IsDir(symbol_dir)) { 75 LOG(ERROR) << "Invalid symbol dir " << symbol_dir; 76 return false; 77 } 78 std::string dir = RemovePathSeparatorSuffix(symbol_dir); 79 CollectBuildIdInDir(dir); 80 return true; 81 } 82 83 void DebugElfFileFinder::CollectBuildIdInDir(const std::string& dir) { 84 for (const std::string& entry : GetEntriesInDir(dir)) { 85 std::string path = dir + OS_PATH_SEPARATOR + entry; 86 if (IsDir(path)) { 87 CollectBuildIdInDir(path); 88 } else { 89 BuildId build_id; 90 if (GetBuildIdFromElfFile(path, &build_id) == ElfStatus::NO_ERROR) { 91 build_id_to_file_map_[build_id.ToString()] = path; 92 } 93 } 94 } 95 } 96 97 void DebugElfFileFinder::SetVdsoFile(const std::string& vdso_file, bool is_64bit) { 98 if (is_64bit) { 99 vdso_64bit_ = vdso_file; 100 } else { 101 vdso_32bit_ = vdso_file; 102 } 103 } 104 105 std::string DebugElfFileFinder::FindDebugFile(const std::string& dso_path, bool force_64bit, 106 BuildId& build_id) { 107 if (dso_path == "[vdso]") { 108 if (force_64bit && !vdso_64bit_.empty()) { 109 return vdso_64bit_; 110 } else if (!force_64bit && !vdso_32bit_.empty()) { 111 return vdso_32bit_; 112 } 113 } 114 if (build_id.IsEmpty()) { 115 // Try reading build id from file if we don't already have one. 116 GetBuildIdFromDsoPath(dso_path, &build_id); 117 } 118 auto check_path = [&](const std::string& path) { 119 BuildId debug_build_id; 120 GetBuildIdFromDsoPath(path, &debug_build_id); 121 if (build_id.IsEmpty()) { 122 // Native libraries in apks may not have build ids. When looking for a debug elf file without 123 // build id (build id is empty), the debug file should exist and also not have build id. 124 return IsRegularFile(path) && debug_build_id.IsEmpty(); 125 } 126 return build_id == debug_build_id; 127 }; 128 129 // 1. Try build_id_to_file_map. 130 if (!build_id_to_file_map_.empty()) { 131 if (!build_id.IsEmpty() || GetBuildIdFromDsoPath(dso_path, &build_id)) { 132 auto it = build_id_to_file_map_.find(build_id.ToString()); 133 if (it != build_id_to_file_map_.end() && check_path(it->second)) { 134 return it->second; 135 } 136 } 137 } 138 if (!symfs_dir_.empty()) { 139 // 2. Try concatenating symfs_dir and dso_path. 140 std::string path = GetPathInSymFsDir(dso_path); 141 if (check_path(path)) { 142 return path; 143 } 144 // 3. Try concatenating symfs_dir and basename of dso_path. 145 path = symfs_dir_ + OS_PATH_SEPARATOR + android::base::Basename(dso_path); 146 if (check_path(path)) { 147 return path; 148 } 149 } 150 // 4. Try concatenating /usr/lib/debug and dso_path. 151 // Linux host can store debug shared libraries in /usr/lib/debug. 152 if (check_path("/usr/lib/debug" + dso_path)) { 153 return "/usr/lib/debug" + dso_path; 154 } 155 return dso_path; 156 } 157 158 std::string DebugElfFileFinder::GetPathInSymFsDir(const std::string& path) { 159 auto add_symfs_prefix = [&](const std::string& path) { 160 if (android::base::StartsWith(path, OS_PATH_SEPARATOR)) { 161 return symfs_dir_ + path; 162 } 163 return symfs_dir_ + OS_PATH_SEPARATOR + path; 164 }; 165 if (OS_PATH_SEPARATOR == '/') { 166 return add_symfs_prefix(path); 167 } 168 // Paths in recorded perf.data uses '/' as path separator. When reporting on Windows, it needs 169 // to be converted to '\\'. 170 auto tuple = SplitUrlInApk(path); 171 if (std::get<0>(tuple)) { 172 std::string apk_path = std::get<1>(tuple); 173 std::string entry_path = std::get<2>(tuple); 174 std::replace(apk_path.begin(), apk_path.end(), '/', OS_PATH_SEPARATOR); 175 return GetUrlInApk(add_symfs_prefix(apk_path), entry_path); 176 } 177 std::string elf_path = path; 178 std::replace(elf_path.begin(), elf_path.end(), '/', OS_PATH_SEPARATOR); 179 return add_symfs_prefix(elf_path); 180 } 181 } // namespace simpleperf_dso_imp 182 183 static OneTimeFreeAllocator symbol_name_allocator; 184 185 Symbol::Symbol(std::string_view name, uint64_t addr, uint64_t len) 186 : addr(addr), 187 len(len), 188 name_(symbol_name_allocator.AllocateString(name)), 189 demangled_name_(nullptr), 190 dump_id_(UINT_MAX) { 191 } 192 193 const char* Symbol::DemangledName() const { 194 if (demangled_name_ == nullptr) { 195 const std::string s = Dso::Demangle(name_); 196 if (s == name_) { 197 demangled_name_ = name_; 198 } else { 199 demangled_name_ = symbol_name_allocator.AllocateString(s); 200 } 201 } 202 return demangled_name_; 203 } 204 205 bool Dso::demangle_ = true; 206 std::string Dso::vmlinux_; 207 std::string Dso::kallsyms_; 208 bool Dso::read_kernel_symbols_from_proc_; 209 std::unordered_map<std::string, BuildId> Dso::build_id_map_; 210 size_t Dso::dso_count_; 211 uint32_t Dso::g_dump_id_; 212 simpleperf_dso_impl::DebugElfFileFinder Dso::debug_elf_file_finder_; 213 214 void Dso::SetDemangle(bool demangle) { demangle_ = demangle; } 215 216 extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, 217 int* status); 218 219 std::string Dso::Demangle(const std::string& name) { 220 if (!demangle_) { 221 return name; 222 } 223 int status; 224 bool is_linker_symbol = (name.find(linker_prefix) == 0); 225 const char* mangled_str = name.c_str(); 226 if (is_linker_symbol) { 227 mangled_str += linker_prefix.size(); 228 } 229 std::string result = name; 230 char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status); 231 if (status == 0) { 232 if (is_linker_symbol) { 233 result = std::string("[linker]") + demangled_name; 234 } else { 235 result = demangled_name; 236 } 237 free(demangled_name); 238 } else if (is_linker_symbol) { 239 result = std::string("[linker]") + mangled_str; 240 } 241 return result; 242 } 243 244 bool Dso::SetSymFsDir(const std::string& symfs_dir) { 245 return debug_elf_file_finder_.SetSymFsDir(symfs_dir); 246 } 247 248 bool Dso::AddSymbolDir(const std::string& symbol_dir) { 249 return debug_elf_file_finder_.AddSymbolDir(symbol_dir); 250 } 251 252 void Dso::SetVmlinux(const std::string& vmlinux) { vmlinux_ = vmlinux; } 253 254 void Dso::SetBuildIds( 255 const std::vector<std::pair<std::string, BuildId>>& build_ids) { 256 std::unordered_map<std::string, BuildId> map; 257 for (auto& pair : build_ids) { 258 LOG(DEBUG) << "build_id_map: " << pair.first << ", " 259 << pair.second.ToString(); 260 map.insert(pair); 261 } 262 build_id_map_ = std::move(map); 263 } 264 265 void Dso::SetVdsoFile(const std::string& vdso_file, bool is_64bit) { 266 debug_elf_file_finder_.SetVdsoFile(vdso_file, is_64bit); 267 } 268 269 BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) { 270 auto it = build_id_map_.find(path); 271 if (it != build_id_map_.end()) { 272 return it->second; 273 } 274 return BuildId(); 275 } 276 277 BuildId Dso::GetExpectedBuildId() { 278 return FindExpectedBuildIdForPath(path_); 279 } 280 281 Dso::Dso(DsoType type, const std::string& path, const std::string& debug_file_path) 282 : type_(type), 283 path_(path), 284 debug_file_path_(debug_file_path), 285 is_loaded_(false), 286 dump_id_(UINT_MAX), 287 symbol_dump_id_(0), 288 symbol_warning_loglevel_(android::base::WARNING) { 289 size_t pos = path.find_last_of("/\\"); 290 if (pos != std::string::npos) { 291 file_name_ = path.substr(pos + 1); 292 } else { 293 file_name_ = path; 294 } 295 dso_count_++; 296 } 297 298 Dso::~Dso() { 299 if (--dso_count_ == 0) { 300 // Clean up global variables when no longer used. 301 symbol_name_allocator.Clear(); 302 demangle_ = true; 303 vmlinux_.clear(); 304 kallsyms_.clear(); 305 read_kernel_symbols_from_proc_ = false; 306 build_id_map_.clear(); 307 g_dump_id_ = 0; 308 debug_elf_file_finder_.Reset(); 309 } 310 } 311 312 uint32_t Dso::CreateDumpId() { 313 CHECK(!HasDumpId()); 314 return dump_id_ = g_dump_id_++; 315 } 316 317 uint32_t Dso::CreateSymbolDumpId(const Symbol* symbol) { 318 CHECK(!symbol->HasDumpId()); 319 symbol->dump_id_ = symbol_dump_id_++; 320 return symbol->dump_id_; 321 } 322 323 const Symbol* Dso::FindSymbol(uint64_t vaddr_in_dso) { 324 if (!is_loaded_) { 325 Load(); 326 } 327 auto it = std::upper_bound(symbols_.begin(), symbols_.end(), 328 Symbol("", vaddr_in_dso, 0), 329 Symbol::CompareValueByAddr); 330 if (it != symbols_.begin()) { 331 --it; 332 if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) { 333 return &*it; 334 } 335 } 336 if (!unknown_symbols_.empty()) { 337 auto it = unknown_symbols_.find(vaddr_in_dso); 338 if (it != unknown_symbols_.end()) { 339 return &it->second; 340 } 341 } 342 return nullptr; 343 } 344 345 void Dso::SetSymbols(std::vector<Symbol>* symbols) { 346 symbols_ = std::move(*symbols); 347 symbols->clear(); 348 } 349 350 void Dso::AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name) { 351 unknown_symbols_.insert(std::make_pair(vaddr_in_dso, Symbol(name, vaddr_in_dso, 1))); 352 } 353 354 bool Dso::IsForJavaMethod() { 355 if (type_ == DSO_DEX_FILE) { 356 return true; 357 } 358 if (type_ == DSO_ELF_FILE) { 359 // JIT symfiles for JITed Java methods are dumped as temporary files, whose name are in format 360 // "TemporaryFile-XXXXXX". 361 size_t pos = path_.rfind('/'); 362 pos = (pos == std::string::npos) ? 0 : pos + 1; 363 return strncmp(&path_[pos], "TemporaryFile", strlen("TemporaryFile")) == 0; 364 } 365 return false; 366 } 367 368 void Dso::Load() { 369 is_loaded_ = true; 370 std::vector<Symbol> symbols = LoadSymbols(); 371 if (symbols_.empty()) { 372 symbols_ = std::move(symbols); 373 } else { 374 std::vector<Symbol> merged_symbols; 375 std::set_union(symbols_.begin(), symbols_.end(), symbols.begin(), symbols.end(), 376 std::back_inserter(merged_symbols), Symbol::CompareValueByAddr); 377 symbols_ = std::move(merged_symbols); 378 } 379 } 380 381 static void ReportReadElfSymbolResult(ElfStatus result, const std::string& path, 382 const std::string& debug_file_path, 383 android::base::LogSeverity warning_loglevel = android::base::WARNING) { 384 if (result == ElfStatus::NO_ERROR) { 385 LOG(VERBOSE) << "Read symbols from " << debug_file_path << " successfully"; 386 } else if (result == ElfStatus::NO_SYMBOL_TABLE) { 387 if (path == "[vdso]") { 388 // Vdso only contains dynamic symbol table, and we can't change that. 389 return; 390 } 391 // Lacking symbol table isn't considered as an error but worth reporting. 392 LOG(warning_loglevel) << debug_file_path << " doesn't contain symbol table"; 393 } else { 394 LOG(warning_loglevel) << "failed to read symbols from " << debug_file_path << ": " << result; 395 } 396 } 397 398 static void SortAndFixSymbols(std::vector<Symbol>& symbols) { 399 std::sort(symbols.begin(), symbols.end(), Symbol::CompareValueByAddr); 400 Symbol* prev_symbol = nullptr; 401 for (auto& symbol : symbols) { 402 if (prev_symbol != nullptr && prev_symbol->len == 0) { 403 prev_symbol->len = symbol.addr - prev_symbol->addr; 404 } 405 prev_symbol = &symbol; 406 } 407 } 408 409 class DexFileDso : public Dso { 410 public: 411 DexFileDso(const std::string& path, const std::string& debug_file_path) 412 : Dso(DSO_DEX_FILE, path, debug_file_path) {} 413 414 void AddDexFileOffset(uint64_t dex_file_offset) override { 415 auto it = std::lower_bound(dex_file_offsets_.begin(), dex_file_offsets_.end(), 416 dex_file_offset); 417 if (it != dex_file_offsets_.end() && *it == dex_file_offset) { 418 return; 419 } 420 dex_file_offsets_.insert(it, dex_file_offset); 421 } 422 423 const std::vector<uint64_t>* DexFileOffsets() override { 424 return &dex_file_offsets_; 425 } 426 427 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override { 428 return ip - map_start + map_pgoff; 429 } 430 431 std::vector<Symbol> LoadSymbols() override { 432 std::vector<Symbol> symbols; 433 std::vector<DexFileSymbol> dex_file_symbols; 434 auto tuple = SplitUrlInApk(debug_file_path_); 435 bool status = false; 436 if (std::get<0>(tuple)) { 437 std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(std::get<1>(tuple)); 438 ZipEntry entry; 439 std::vector<uint8_t> data; 440 if (ahelper && 441 ahelper->FindEntry(std::get<2>(tuple), &entry) && ahelper->GetEntryData(entry, &data)) { 442 status = ReadSymbolsFromDexFileInMemory(data.data(), data.size(), dex_file_offsets_, 443 &dex_file_symbols); 444 } 445 } else { 446 status = ReadSymbolsFromDexFile(debug_file_path_, dex_file_offsets_, &dex_file_symbols); 447 } 448 if (!status) { 449 android::base::LogSeverity level = symbols_.empty() ? android::base::WARNING 450 : android::base::DEBUG; 451 LOG(level) << "Failed to read symbols from " << debug_file_path_; 452 return symbols; 453 } 454 LOG(VERBOSE) << "Read symbols from " << debug_file_path_ << " successfully"; 455 for (auto& symbol : dex_file_symbols) { 456 symbols.emplace_back(symbol.name, symbol.offset, symbol.len); 457 } 458 SortAndFixSymbols(symbols); 459 return symbols; 460 } 461 462 private: 463 std::vector<uint64_t> dex_file_offsets_; 464 }; 465 466 class ElfDso : public Dso { 467 public: 468 ElfDso(const std::string& path, const std::string& debug_file_path) 469 : Dso(DSO_ELF_FILE, path, debug_file_path) {} 470 471 void SetMinExecutableVaddr(uint64_t min_vaddr, uint64_t file_offset) override { 472 min_vaddr_ = min_vaddr; 473 file_offset_of_min_vaddr_ = file_offset; 474 } 475 476 void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) override { 477 if (type_ == DSO_DEX_FILE) { 478 return dex_file_dso_->GetMinExecutableVaddr(min_vaddr, file_offset); 479 } 480 if (min_vaddr_ == uninitialized_value) { 481 min_vaddr_ = 0; 482 BuildId build_id = GetExpectedBuildId(); 483 uint64_t addr; 484 uint64_t offset; 485 ElfStatus result; 486 auto tuple = SplitUrlInApk(debug_file_path_); 487 if (std::get<0>(tuple)) { 488 EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), 489 std::get<2>(tuple)); 490 if (elf == nullptr) { 491 result = ElfStatus::FILE_NOT_FOUND; 492 } else { 493 result = ReadMinExecutableVirtualAddressFromEmbeddedElfFile( 494 elf->filepath(), elf->entry_offset(), elf->entry_size(), build_id, &addr, &offset); 495 } 496 } else { 497 result = ReadMinExecutableVirtualAddressFromElfFile(debug_file_path_, build_id, &addr, 498 &offset); 499 } 500 if (result != ElfStatus::NO_ERROR) { 501 LOG(WARNING) << "failed to read min virtual address of " 502 << GetDebugFilePath() << ": " << result; 503 } else { 504 min_vaddr_ = addr; 505 file_offset_of_min_vaddr_ = offset; 506 } 507 } 508 *min_vaddr = min_vaddr_; 509 *file_offset = file_offset_of_min_vaddr_; 510 } 511 512 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override { 513 if (type_ == DSO_DEX_FILE) { 514 return dex_file_dso_->IpToVaddrInFile(ip, map_start, map_pgoff); 515 } 516 uint64_t min_vaddr; 517 uint64_t file_offset_of_min_vaddr; 518 GetMinExecutableVaddr(&min_vaddr, &file_offset_of_min_vaddr); 519 if (file_offset_of_min_vaddr == uninitialized_value) { 520 return ip - map_start + min_vaddr; 521 } 522 // Apps may make part of the executable segment of a shared library writeable, which can 523 // generate multiple executable segments at runtime. So use map_pgoff to calculate 524 // vaddr_in_file. 525 return ip - map_start + map_pgoff - file_offset_of_min_vaddr + min_vaddr; 526 } 527 528 void AddDexFileOffset(uint64_t dex_file_offset) override { 529 if (type_ == DSO_ELF_FILE) { 530 // When simpleperf does unwinding while recording, it processes mmap records before reading 531 // dex file linked list (via JITDebugReader). To process mmap records, it creates Dso 532 // objects of type ELF_FILE. Then after reading dex file linked list, it realizes some 533 // ELF_FILE Dso objects should actually be DEX_FILE, because they have dex file offsets. 534 // So here converts ELF_FILE Dso into DEX_FILE Dso. 535 type_ = DSO_DEX_FILE; 536 dex_file_dso_.reset(new DexFileDso(path_, path_)); 537 } 538 dex_file_dso_->AddDexFileOffset(dex_file_offset); 539 } 540 541 const std::vector<uint64_t>* DexFileOffsets() override { 542 return dex_file_dso_ ? dex_file_dso_->DexFileOffsets() : nullptr; 543 } 544 545 protected: 546 std::vector<Symbol> LoadSymbols() override { 547 if (dex_file_dso_) { 548 return dex_file_dso_->LoadSymbols(); 549 } 550 std::vector<Symbol> symbols; 551 BuildId build_id = GetExpectedBuildId(); 552 auto symbol_callback = [&](const ElfFileSymbol& symbol) { 553 if (symbol.is_func || (symbol.is_label && symbol.is_in_text_section)) { 554 symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len); 555 } 556 }; 557 ElfStatus status; 558 std::tuple<bool, std::string, std::string> tuple = SplitUrlInApk(debug_file_path_); 559 if (std::get<0>(tuple)) { 560 EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple)); 561 if (elf == nullptr) { 562 status = ElfStatus::FILE_NOT_FOUND; 563 } else { 564 status = ParseSymbolsFromEmbeddedElfFile(elf->filepath(), elf->entry_offset(), 565 elf->entry_size(), build_id, symbol_callback); 566 } 567 } else { 568 status = ParseSymbolsFromElfFile(debug_file_path_, build_id, symbol_callback); 569 } 570 ReportReadElfSymbolResult(status, path_, debug_file_path_, 571 symbols_.empty() ? android::base::WARNING : android::base::DEBUG); 572 SortAndFixSymbols(symbols); 573 return symbols; 574 } 575 576 private: 577 static constexpr uint64_t uninitialized_value = std::numeric_limits<uint64_t>::max(); 578 579 uint64_t min_vaddr_ = uninitialized_value; 580 uint64_t file_offset_of_min_vaddr_ = uninitialized_value; 581 std::unique_ptr<DexFileDso> dex_file_dso_; 582 }; 583 584 class KernelDso : public Dso { 585 public: 586 KernelDso(const std::string& path, const std::string& debug_file_path) 587 : Dso(DSO_KERNEL, path, debug_file_path) {} 588 589 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { 590 return ip; 591 } 592 593 protected: 594 std::vector<Symbol> LoadSymbols() override { 595 std::vector<Symbol> symbols; 596 BuildId build_id = GetExpectedBuildId(); 597 if (!vmlinux_.empty()) { 598 auto symbol_callback = [&](const ElfFileSymbol& symbol) { 599 if (symbol.is_func) { 600 symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len); 601 } 602 }; 603 ElfStatus status = ParseSymbolsFromElfFile(vmlinux_, build_id, symbol_callback); 604 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 652 class 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 657 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override { 658 return ip - map_start; 659 } 660 661 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 }; 670 ElfStatus status = ParseSymbolsFromElfFile(debug_file_path_, build_id, symbol_callback); 671 ReportReadElfSymbolResult(status, path_, debug_file_path_, 672 symbols_.empty() ? android::base::WARNING : android::base::DEBUG); 673 SortAndFixSymbols(symbols); 674 return symbols; 675 } 676 }; 677 678 class UnknownDso : public Dso { 679 public: 680 UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {} 681 682 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { 683 return ip; 684 } 685 686 protected: 687 std::vector<Symbol> LoadSymbols() override { 688 return std::vector<Symbol>(); 689 } 690 }; 691 692 std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path, 693 bool force_64bit) { 694 switch (dso_type) { 695 case DSO_ELF_FILE: { 696 BuildId build_id = FindExpectedBuildIdForPath(dso_path); 697 return std::unique_ptr<Dso>(new ElfDso(dso_path, 698 debug_elf_file_finder_.FindDebugFile(dso_path, force_64bit, build_id))); 699 } 700 case DSO_KERNEL: 701 return std::unique_ptr<Dso>(new KernelDso(dso_path, dso_path)); 702 case DSO_KERNEL_MODULE: 703 return std::unique_ptr<Dso>(new KernelModuleDso(dso_path, dso_path)); 704 case DSO_DEX_FILE: 705 return std::unique_ptr<Dso>(new DexFileDso(dso_path, dso_path)); 706 case DSO_UNKNOWN_FILE: 707 return std::unique_ptr<Dso>(new UnknownDso(dso_path)); 708 default: 709 LOG(FATAL) << "Unexpected dso_type " << static_cast<int>(dso_type); 710 } 711 return nullptr; 712 } 713 714 const char* DsoTypeToString(DsoType dso_type) { 715 switch (dso_type) { 716 case DSO_KERNEL: 717 return "dso_kernel"; 718 case DSO_KERNEL_MODULE: 719 return "dso_kernel_module"; 720 case DSO_ELF_FILE: 721 return "dso_elf_file"; 722 case DSO_DEX_FILE: 723 return "dso_dex_file"; 724 default: 725 return "unknown"; 726 } 727 } 728 729 bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id) { 730 auto tuple = SplitUrlInApk(dso_path); 731 ElfStatus result; 732 if (std::get<0>(tuple)) { 733 EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple)); 734 if (elf == nullptr) { 735 result = ElfStatus::FILE_NOT_FOUND; 736 } else { 737 result = GetBuildIdFromEmbeddedElfFile(elf->filepath(), elf->entry_offset(), 738 elf->entry_size(), build_id); 739 } 740 } else { 741 result = GetBuildIdFromElfFile(dso_path, build_id); 742 } 743 return result == ElfStatus::NO_ERROR; 744 } 745