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
RemovePathSeparatorSuffix(const std::string & path)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
Reset()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
SetSymFsDir(const std::string & symfs_dir)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
AddSymbolDir(const std::string & symbol_dir)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
CollectBuildIdInDir(const std::string & dir)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
SetVdsoFile(const std::string & vdso_file,bool is_64bit)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
FindDebugFile(const std::string & dso_path,bool force_64bit,BuildId & build_id)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
GetPathInSymFsDir(const std::string & path)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
Symbol(std::string_view name,uint64_t addr,uint64_t len)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
DemangledName() const193 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
SetDemangle(bool demangle)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
Demangle(const std::string & name)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
SetSymFsDir(const std::string & symfs_dir)244 bool Dso::SetSymFsDir(const std::string& symfs_dir) {
245 return debug_elf_file_finder_.SetSymFsDir(symfs_dir);
246 }
247
AddSymbolDir(const std::string & symbol_dir)248 bool Dso::AddSymbolDir(const std::string& symbol_dir) {
249 return debug_elf_file_finder_.AddSymbolDir(symbol_dir);
250 }
251
SetVmlinux(const std::string & vmlinux)252 void Dso::SetVmlinux(const std::string& vmlinux) { vmlinux_ = vmlinux; }
253
SetBuildIds(const std::vector<std::pair<std::string,BuildId>> & build_ids)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
SetVdsoFile(const std::string & vdso_file,bool is_64bit)265 void Dso::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
266 debug_elf_file_finder_.SetVdsoFile(vdso_file, is_64bit);
267 }
268
FindExpectedBuildIdForPath(const std::string & path)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
GetExpectedBuildId()277 BuildId Dso::GetExpectedBuildId() {
278 return FindExpectedBuildIdForPath(path_);
279 }
280
Dso(DsoType type,const std::string & path,const std::string & debug_file_path)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
~Dso()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
CreateDumpId()312 uint32_t Dso::CreateDumpId() {
313 CHECK(!HasDumpId());
314 return dump_id_ = g_dump_id_++;
315 }
316
CreateSymbolDumpId(const Symbol * symbol)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
FindSymbol(uint64_t vaddr_in_dso)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
SetSymbols(std::vector<Symbol> * symbols)345 void Dso::SetSymbols(std::vector<Symbol>* symbols) {
346 symbols_ = std::move(*symbols);
347 symbols->clear();
348 }
349
AddUnknownSymbol(uint64_t vaddr_in_dso,const std::string & name)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
IsForJavaMethod()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
Load()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
ReportReadElfSymbolResult(ElfStatus result,const std::string & path,const std::string & debug_file_path,android::base::LogSeverity warning_loglevel=android::base::WARNING)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
SortAndFixSymbols(std::vector<Symbol> & symbols)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:
DexFileDso(const std::string & path,const std::string & debug_file_path)411 DexFileDso(const std::string& path, const std::string& debug_file_path)
412 : Dso(DSO_DEX_FILE, path, debug_file_path) {}
413
AddDexFileOffset(uint64_t dex_file_offset)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
DexFileOffsets()423 const std::vector<uint64_t>* DexFileOffsets() override {
424 return &dex_file_offsets_;
425 }
426
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t map_pgoff)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
LoadSymbols()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:
ElfDso(const std::string & path,const std::string & debug_file_path)468 ElfDso(const std::string& path, const std::string& debug_file_path)
469 : Dso(DSO_ELF_FILE, path, debug_file_path) {}
470
SetMinExecutableVaddr(uint64_t min_vaddr,uint64_t file_offset)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
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * file_offset)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
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t map_pgoff)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
AddDexFileOffset(uint64_t dex_file_offset)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
DexFileOffsets()541 const std::vector<uint64_t>* DexFileOffsets() override {
542 return dex_file_dso_ ? dex_file_dso_->DexFileOffsets() : nullptr;
543 }
544
545 protected:
LoadSymbols()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:
KernelDso(const std::string & path,const std::string & debug_file_path)586 KernelDso(const std::string& path, const std::string& debug_file_path)
587 : Dso(DSO_KERNEL, path, debug_file_path) {}
588
IpToVaddrInFile(uint64_t ip,uint64_t,uint64_t)589 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
590 return ip;
591 }
592
593 protected:
LoadSymbols()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:
ReadSymbolsFromKallsyms(std::string & kallsyms)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:
KernelModuleDso(const std::string & path,const std::string & debug_file_path)654 KernelModuleDso(const std::string& path, const std::string& debug_file_path)
655 : Dso(DSO_KERNEL_MODULE, path, debug_file_path) {}
656
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t)657 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override {
658 return ip - map_start;
659 }
660
661 protected:
LoadSymbols()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:
UnknownDso(const std::string & path)680 UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {}
681
IpToVaddrInFile(uint64_t ip,uint64_t,uint64_t)682 uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override {
683 return ip;
684 }
685
686 protected:
LoadSymbols()687 std::vector<Symbol> LoadSymbols() override {
688 return std::vector<Symbol>();
689 }
690 };
691
CreateDso(DsoType dso_type,const std::string & dso_path,bool force_64bit)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
DsoTypeToString(DsoType dso_type)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
GetBuildIdFromDsoPath(const std::string & dso_path,BuildId * build_id)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