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