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 <vector>
25 
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28 
29 #include "environment.h"
30 #include "read_apk.h"
31 #include "read_elf.h"
32 #include "utils.h"
33 
34 static OneTimeFreeAllocator symbol_name_allocator;
35 
Symbol(const std::string & name,uint64_t addr,uint64_t len)36 Symbol::Symbol(const std::string& name, uint64_t addr, uint64_t len)
37     : addr(addr),
38       len(len),
39       name_(symbol_name_allocator.AllocateString(name)),
40       demangled_name_(nullptr),
41       dump_id_(UINT_MAX) {}
42 
DemangledName() const43 const char* Symbol::DemangledName() const {
44   if (demangled_name_ == nullptr) {
45     const std::string s = Dso::Demangle(name_);
46     if (s == name_) {
47       demangled_name_ = name_;
48     } else {
49       demangled_name_ = symbol_name_allocator.AllocateString(s);
50     }
51   }
52   return demangled_name_;
53 }
54 
55 bool Dso::demangle_ = true;
56 std::string Dso::symfs_dir_;
57 std::string Dso::vmlinux_;
58 std::string Dso::kallsyms_;
59 bool Dso::read_kernel_symbols_from_proc_;
60 std::unordered_map<std::string, BuildId> Dso::build_id_map_;
61 size_t Dso::dso_count_;
62 uint32_t Dso::g_dump_id_;
63 
SetDemangle(bool demangle)64 void Dso::SetDemangle(bool demangle) { demangle_ = demangle; }
65 
66 extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n,
67                                 int* status);
68 
Demangle(const std::string & name)69 std::string Dso::Demangle(const std::string& name) {
70   if (!demangle_) {
71     return name;
72   }
73   int status;
74   bool is_linker_symbol = (name.find(linker_prefix) == 0);
75   const char* mangled_str = name.c_str();
76   if (is_linker_symbol) {
77     mangled_str += linker_prefix.size();
78   }
79   std::string result = name;
80   char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
81   if (status == 0) {
82     if (is_linker_symbol) {
83       result = std::string("[linker]") + demangled_name;
84     } else {
85       result = demangled_name;
86     }
87     free(demangled_name);
88   } else if (is_linker_symbol) {
89     result = std::string("[linker]") + mangled_str;
90   }
91   return result;
92 }
93 
SetSymFsDir(const std::string & symfs_dir)94 bool Dso::SetSymFsDir(const std::string& symfs_dir) {
95   std::string dirname = symfs_dir;
96   if (!dirname.empty()) {
97     if (dirname.back() != '/') {
98       dirname.push_back('/');
99     }
100     if (!IsDir(symfs_dir)) {
101       LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
102       return false;
103     }
104   }
105   symfs_dir_ = dirname;
106   return true;
107 }
108 
SetVmlinux(const std::string & vmlinux)109 void Dso::SetVmlinux(const std::string& vmlinux) { vmlinux_ = vmlinux; }
110 
SetBuildIds(const std::vector<std::pair<std::string,BuildId>> & build_ids)111 void Dso::SetBuildIds(
112     const std::vector<std::pair<std::string, BuildId>>& build_ids) {
113   std::unordered_map<std::string, BuildId> map;
114   for (auto& pair : build_ids) {
115     LOG(DEBUG) << "build_id_map: " << pair.first << ", "
116                << pair.second.ToString();
117     map.insert(pair);
118   }
119   build_id_map_ = std::move(map);
120 }
121 
FindExpectedBuildIdForPath(const std::string & path)122 BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
123   auto it = build_id_map_.find(path);
124   if (it != build_id_map_.end()) {
125     return it->second;
126   }
127   return BuildId();
128 }
129 
GetExpectedBuildId()130 BuildId Dso::GetExpectedBuildId() {
131   return FindExpectedBuildIdForPath(path_);
132 }
133 
CreateDso(DsoType dso_type,const std::string & dso_path)134 std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type,
135                                     const std::string& dso_path) {
136   return std::unique_ptr<Dso>(new Dso(dso_type, dso_path));
137 }
138 
Dso(DsoType type,const std::string & path)139 Dso::Dso(DsoType type, const std::string& path)
140     : type_(type),
141       path_(path),
142       debug_file_path_(path),
143       min_vaddr_(std::numeric_limits<uint64_t>::max()),
144       is_loaded_(false),
145       dump_id_(UINT_MAX),
146       symbol_dump_id_(0) {
147   if (type_ == DSO_KERNEL) {
148     min_vaddr_ = 0;
149   }
150   // Check if file matching path_ exists in symfs directory before using it as
151   // debug_file_path_.
152   if (!symfs_dir_.empty()) {
153     std::string path_in_symfs = symfs_dir_ + path_;
154     std::tuple<bool, std::string, std::string> tuple =
155         SplitUrlInApk(path_in_symfs);
156     std::string file_path =
157         std::get<0>(tuple) ? std::get<1>(tuple) : path_in_symfs;
158     if (IsRegularFile(file_path)) {
159       debug_file_path_ = path_in_symfs;
160     }
161   }
162   size_t pos = path.find_last_of("/\\");
163   if (pos != std::string::npos) {
164     file_name_ = path.substr(pos + 1);
165   } else {
166     file_name_ = path;
167   }
168   dso_count_++;
169 }
170 
~Dso()171 Dso::~Dso() {
172   if (--dso_count_ == 0) {
173     // Clean up global variables when no longer used.
174     symbol_name_allocator.Clear();
175     demangle_ = true;
176     symfs_dir_.clear();
177     vmlinux_.clear();
178     kallsyms_.clear();
179     read_kernel_symbols_from_proc_ = false;
180     build_id_map_.clear();
181     g_dump_id_ = 0;
182   }
183 }
184 
CreateDumpId()185 uint32_t Dso::CreateDumpId() {
186   CHECK(!HasDumpId());
187   return dump_id_ = g_dump_id_++;
188 }
189 
CreateSymbolDumpId(const Symbol * symbol)190 uint32_t Dso::CreateSymbolDumpId(const Symbol* symbol) {
191   CHECK(!symbol->HasDumpId());
192   symbol->dump_id_ = symbol_dump_id_++;
193   return symbol->dump_id_;
194 }
195 
FindSymbol(uint64_t vaddr_in_dso)196 const Symbol* Dso::FindSymbol(uint64_t vaddr_in_dso) {
197   if (!is_loaded_) {
198     Load();
199   }
200   if (!symbols_.empty()) {
201     auto it = std::upper_bound(symbols_.begin(), symbols_.end(),
202                                Symbol("", vaddr_in_dso, 0),
203                                Symbol::CompareValueByAddr);
204     if (it != symbols_.begin()) {
205       --it;
206       if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) {
207         return &*it;
208       }
209     }
210   }
211   if (!unknown_symbols_.empty()) {
212     auto it = unknown_symbols_.find(vaddr_in_dso);
213     if (it != unknown_symbols_.end()) {
214       return &it->second;
215     }
216   }
217   return nullptr;
218 }
219 
GetSymbols()220 const std::vector<Symbol>& Dso::GetSymbols() {
221   if (!is_loaded_) {
222     Load();
223   }
224   return symbols_;
225 }
226 
SetSymbols(std::vector<Symbol> * symbols)227 void Dso::SetSymbols(std::vector<Symbol>* symbols) {
228   symbols_ = std::move(*symbols);
229   symbols->clear();
230 }
231 
AddUnknownSymbol(uint64_t vaddr_in_dso,const std::string & name)232 void Dso::AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name) {
233   unknown_symbols_.insert(std::make_pair(vaddr_in_dso, Symbol(name, vaddr_in_dso, 1)));
234 }
235 
MinVirtualAddress()236 uint64_t Dso::MinVirtualAddress() {
237   if (min_vaddr_ == std::numeric_limits<uint64_t>::max()) {
238     min_vaddr_ = 0;
239     if (type_ == DSO_ELF_FILE) {
240       BuildId build_id = GetExpectedBuildId();
241 
242       uint64_t addr;
243       ElfStatus result = ReadMinExecutableVirtualAddressFromElfFile(
244           GetDebugFilePath(), build_id, &addr);
245       if (result != ElfStatus::NO_ERROR) {
246         LOG(WARNING) << "failed to read min virtual address of "
247                      << GetDebugFilePath() << ": " << result;
248       } else {
249         min_vaddr_ = addr;
250       }
251     }
252   }
253   return min_vaddr_;
254 }
255 
MergeSortedSymbols(const std::vector<Symbol> & s1,const std::vector<Symbol> & s2)256 static std::vector<Symbol> MergeSortedSymbols(const std::vector<Symbol>& s1,
257                                               const std::vector<Symbol>& s2) {
258   std::vector<Symbol> result;
259   std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), std::back_inserter(result),
260                  Symbol::CompareValueByAddr);
261   return result;
262 }
263 
Load()264 void Dso::Load() {
265   is_loaded_ = true;
266   std::vector<Symbol> dumped_symbols;
267   if (!symbols_.empty()) {
268     // If symbols has been read from file feature section of perf.data, move it to
269     // dumped_symbols,  so later we can merge them with symbols read from file system.
270     dumped_symbols = std::move(symbols_);
271     symbols_.clear();
272   }
273   bool result = false;
274   switch (type_) {
275     case DSO_KERNEL:
276       result = LoadKernel();
277       break;
278     case DSO_KERNEL_MODULE:
279       result = LoadKernelModule();
280       break;
281     case DSO_ELF_FILE: {
282       if (std::get<0>(SplitUrlInApk(path_))) {
283         result = LoadEmbeddedElfFile();
284       } else {
285         result = LoadElfFile();
286       }
287       break;
288     }
289   }
290   if (result) {
291     std::sort(symbols_.begin(), symbols_.end(), Symbol::CompareValueByAddr);
292     FixupSymbolLength();
293   } else {
294     symbols_.clear();
295   }
296 
297   if (symbols_.empty()) {
298     symbols_ = std::move(dumped_symbols);
299   } else if (!dumped_symbols.empty()) {
300     symbols_ = MergeSortedSymbols(symbols_, dumped_symbols);
301   }
302 
303   if (symbols_.empty()) {
304     LOG(DEBUG) << "failed to load dso: " << path_;
305   }
306 }
307 
IsKernelFunctionSymbol(const KernelSymbol & symbol)308 static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
309   return (symbol.type == 'T' || symbol.type == 't' || symbol.type == 'W' ||
310           symbol.type == 'w');
311 }
312 
KernelSymbolCallback(const KernelSymbol & kernel_symbol,std::vector<Symbol> * symbols)313 static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol,
314                                  std::vector<Symbol>* symbols) {
315   if (IsKernelFunctionSymbol(kernel_symbol)) {
316     symbols->emplace_back(Symbol(kernel_symbol.name, kernel_symbol.addr, 0));
317   }
318   return false;
319 }
320 
VmlinuxSymbolCallback(const ElfFileSymbol & elf_symbol,std::vector<Symbol> * symbols)321 static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol,
322                                   std::vector<Symbol>* symbols) {
323   if (elf_symbol.is_func) {
324     symbols->emplace_back(
325         Symbol(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len));
326   }
327 }
328 
CheckReadSymbolResult(ElfStatus result,const std::string & filename)329 bool CheckReadSymbolResult(ElfStatus result, const std::string& filename) {
330   if (result == ElfStatus::NO_ERROR) {
331     LOG(VERBOSE) << "Read symbols from " << filename << " successfully";
332     return true;
333   } else if (result == ElfStatus::NO_SYMBOL_TABLE) {
334     // Lacking symbol table isn't considered as an error but worth reporting.
335     LOG(WARNING) << filename << " doesn't contain symbol table";
336     return true;
337   } else {
338     LOG(WARNING) << "failed to read symbols from " << filename
339                  << ": " << result;
340     return false;
341   }
342 }
343 
LoadKernel()344 bool Dso::LoadKernel() {
345   BuildId build_id = GetExpectedBuildId();
346   if (!vmlinux_.empty()) {
347     ElfStatus result = ParseSymbolsFromElfFile(vmlinux_, build_id,
348         std::bind(VmlinuxSymbolCallback, std::placeholders::_1, &symbols_));
349     return CheckReadSymbolResult(result, vmlinux_);
350   } else if (!kallsyms_.empty()) {
351     ProcessKernelSymbols(kallsyms_, std::bind(&KernelSymbolCallback,
352                                               std::placeholders::_1, &symbols_));
353     bool all_zero = true;
354     for (const auto& symbol : symbols_) {
355       if (symbol.addr != 0) {
356         all_zero = false;
357         break;
358       }
359     }
360     if (all_zero) {
361       LOG(WARNING)
362           << "Symbol addresses in /proc/kallsyms on device are all zero. "
363              "`echo 0 >/proc/sys/kernel/kptr_restrict` if possible.";
364       symbols_.clear();
365       return false;
366     }
367   } else if (read_kernel_symbols_from_proc_ || !build_id.IsEmpty()) {
368     // Try /proc/kallsyms only when asked to do so, or when build id matches.
369     // Otherwise, it is likely to use /proc/kallsyms on host for perf.data recorded on device.
370     if (!build_id.IsEmpty()) {
371       BuildId real_build_id;
372       if (!GetKernelBuildId(&real_build_id)) {
373         return false;
374       }
375       bool match = (build_id == real_build_id);
376       if (!match) {
377         LOG(WARNING) << "failed to read symbols from /proc/kallsyms: Build id "
378                      << "mismatch";
379         return false;
380       }
381     }
382 
383     std::string kallsyms;
384     if (!android::base::ReadFileToString("/proc/kallsyms", &kallsyms)) {
385       LOG(DEBUG) << "failed to read /proc/kallsyms";
386       return false;
387     }
388     ProcessKernelSymbols(kallsyms, std::bind(&KernelSymbolCallback,
389                                              std::placeholders::_1, &symbols_));
390     bool all_zero = true;
391     for (const auto& symbol : symbols_) {
392       if (symbol.addr != 0) {
393         all_zero = false;
394         break;
395       }
396     }
397     if (all_zero) {
398       LOG(WARNING) << "Symbol addresses in /proc/kallsyms are all zero. "
399                       "`echo 0 >/proc/sys/kernel/kptr_restrict` if possible.";
400       symbols_.clear();
401       return false;
402     }
403   }
404   return true;
405 }
406 
ElfFileSymbolCallback(const ElfFileSymbol & elf_symbol,bool (* filter)(const ElfFileSymbol &),std::vector<Symbol> * symbols)407 static void ElfFileSymbolCallback(const ElfFileSymbol& elf_symbol,
408                                   bool (*filter)(const ElfFileSymbol&),
409                                   std::vector<Symbol>* symbols) {
410   if (filter(elf_symbol)) {
411     symbols->emplace_back(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len);
412   }
413 }
414 
SymbolFilterForKernelModule(const ElfFileSymbol & elf_symbol)415 static bool SymbolFilterForKernelModule(const ElfFileSymbol& elf_symbol) {
416   // TODO: Parse symbol outside of .text section.
417   return (elf_symbol.is_func && elf_symbol.is_in_text_section);
418 }
419 
LoadKernelModule()420 bool Dso::LoadKernelModule() {
421   BuildId build_id = GetExpectedBuildId();
422   ElfStatus result = ParseSymbolsFromElfFile(GetDebugFilePath(), build_id,
423       std::bind(ElfFileSymbolCallback, std::placeholders::_1,
424                 SymbolFilterForKernelModule, &symbols_));
425   return CheckReadSymbolResult(result, GetDebugFilePath());
426 }
427 
SymbolFilterForDso(const ElfFileSymbol & elf_symbol)428 static bool SymbolFilterForDso(const ElfFileSymbol& elf_symbol) {
429   return elf_symbol.is_func ||
430          (elf_symbol.is_label && elf_symbol.is_in_text_section);
431 }
432 
LoadElfFile()433 bool Dso::LoadElfFile() {
434   BuildId build_id = GetExpectedBuildId();
435 
436   if (symfs_dir_.empty()) {
437     // Linux host can store debug shared libraries in /usr/lib/debug.
438     ElfStatus result = ParseSymbolsFromElfFile(
439         "/usr/lib/debug" + path_, build_id,
440         std::bind(ElfFileSymbolCallback, std::placeholders::_1,
441                   SymbolFilterForDso, &symbols_));
442     if (result == ElfStatus::NO_ERROR) {
443       return CheckReadSymbolResult(result, "/usr/lib/debug" + path_);
444     }
445   }
446   // TODO: load std::vector<Symbol> directly from ParseSymbolsFromElfFile
447   // instead of needing to call a callback function for each symbol.
448   ElfStatus result = ParseSymbolsFromElfFile(
449       GetDebugFilePath(), build_id,
450       std::bind(ElfFileSymbolCallback, std::placeholders::_1,
451                 SymbolFilterForDso, &symbols_));
452   return CheckReadSymbolResult(result, GetDebugFilePath());
453 }
454 
LoadEmbeddedElfFile()455 bool Dso::LoadEmbeddedElfFile() {
456   BuildId build_id = GetExpectedBuildId();
457   auto tuple = SplitUrlInApk(GetDebugFilePath());
458   CHECK(std::get<0>(tuple));
459   ElfStatus result = ParseSymbolsFromApkFile(
460       std::get<1>(tuple), std::get<2>(tuple), build_id,
461       std::bind(ElfFileSymbolCallback, std::placeholders::_1,
462                 SymbolFilterForDso, &symbols_));
463   return CheckReadSymbolResult(result, GetDebugFilePath());
464 }
465 
FixupSymbolLength()466 void Dso::FixupSymbolLength() {
467   Symbol* prev_symbol = nullptr;
468   for (auto& symbol : symbols_) {
469     if (prev_symbol != nullptr && prev_symbol->len == 0) {
470       prev_symbol->len = symbol.addr - prev_symbol->addr;
471     }
472     prev_symbol = const_cast<Symbol*>(&symbol);
473   }
474   if (prev_symbol != nullptr && prev_symbol->len == 0) {
475     prev_symbol->len = std::numeric_limits<uint64_t>::max() - prev_symbol->addr;
476   }
477 }
478 
DsoTypeToString(DsoType dso_type)479 const char* DsoTypeToString(DsoType dso_type) {
480   switch (dso_type) {
481     case DSO_KERNEL:
482       return "dso_kernel";
483     case DSO_KERNEL_MODULE:
484       return "dso_kernel_module";
485     case DSO_ELF_FILE:
486       return "dso_elf_file";
487     default:
488       return "unknown";
489   }
490 }
491