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 #ifndef SIMPLE_PERF_DSO_H_
18 #define SIMPLE_PERF_DSO_H_
19 
20 #include <memory>
21 #include <string>
22 #include <unordered_map>
23 #include <vector>
24 
25 #include <android-base/file.h>
26 #include <android-base/logging.h>
27 
28 #include "build_id.h"
29 #include "read_elf.h"
30 
31 
32 namespace simpleperf_dso_impl {
33 
34 // Find elf files with symbol table and debug information.
35 class DebugElfFileFinder {
36  public:
37   void Reset();
38   bool SetSymFsDir(const std::string& symfs_dir);
39   bool AddSymbolDir(const std::string& symbol_dir);
40   void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
41   std::string FindDebugFile(const std::string& dso_path, bool force_64bit,
42                             BuildId& build_id);
43   // Only for testing
44   std::string GetPathInSymFsDir(const std::string& path);
45 
46  private:
47   void CollectBuildIdInDir(const std::string& dir);
48 
49   std::string vdso_64bit_;
50   std::string vdso_32bit_;
51   std::string symfs_dir_;
52   std::unordered_map<std::string, std::string> build_id_to_file_map_;
53 };
54 
55 }  // namespace simpleperf_dso_impl
56 
57 struct Symbol {
58   uint64_t addr;
59   // TODO: make len uint32_t.
60   uint64_t len;
61 
62   Symbol(std::string_view name, uint64_t addr, uint64_t len);
NameSymbol63   const char* Name() const { return name_; }
64 
65   const char* DemangledName() const;
66 
HasDumpIdSymbol67   bool HasDumpId() const {
68     return dump_id_ != UINT_MAX;
69   }
70 
GetDumpIdSymbol71   bool GetDumpId(uint32_t* pdump_id) const {
72     if (!HasDumpId()) {
73       return false;
74     }
75     *pdump_id = dump_id_;
76     return true;
77   }
78 
CompareByDumpIdSymbol79   static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) {
80     uint32_t id1 = UINT_MAX;
81     s1->GetDumpId(&id1);
82     uint32_t id2 = UINT_MAX;
83     s2->GetDumpId(&id2);
84     return id1 < id2;
85   }
86 
CompareByAddrSymbol87   static bool CompareByAddr(const Symbol* s1, const Symbol* s2) {
88     return s1->addr < s2->addr;
89   }
90 
CompareValueByAddrSymbol91   static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) {
92     return s1.addr < s2.addr;
93   }
94 
95  private:
96   const char* name_;
97   mutable const char* demangled_name_;
98   mutable uint32_t dump_id_;
99 
100   friend class Dso;
101 };
102 
103 enum DsoType {
104   DSO_KERNEL,
105   DSO_KERNEL_MODULE,
106   DSO_ELF_FILE,
107   DSO_DEX_FILE,  // For files containing dex files, like .vdex files.
108   DSO_UNKNOWN_FILE,
109 };
110 
111 struct KernelSymbol;
112 struct ElfFileSymbol;
113 
114 class Dso {
115  public:
116   static void SetDemangle(bool demangle);
117   static std::string Demangle(const std::string& name);
118   // SymFsDir is used to provide an alternative root directory looking for files with symbols.
119   // For example, if we are searching symbols for /system/lib/libc.so and SymFsDir is /data/symbols,
120   // then we will also search file /data/symbols/system/lib/libc.so.
121   static bool SetSymFsDir(const std::string& symfs_dir);
122   // SymbolDir is used to add a directory containing files with symbols. Each file under it will
123   // be searched recursively to build a build_id_map.
124   static bool AddSymbolDir(const std::string& symbol_dir);
125   static void SetVmlinux(const std::string& vmlinux);
SetKallsyms(std::string kallsyms)126   static void SetKallsyms(std::string kallsyms) {
127     if (!kallsyms.empty()) {
128       kallsyms_ = std::move(kallsyms);
129     }
130   }
ReadKernelSymbolsFromProc()131   static void ReadKernelSymbolsFromProc() {
132     read_kernel_symbols_from_proc_ = true;
133   }
134   static void SetBuildIds(
135       const std::vector<std::pair<std::string, BuildId>>& build_ids);
136   static BuildId FindExpectedBuildIdForPath(const std::string& path);
137   static void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
138 
139   static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path,
140                                         bool force_64bit = false);
141 
142   virtual ~Dso();
143 
type()144   DsoType type() const { return type_; }
145 
146   // Return the path recorded in perf.data.
Path()147   const std::string& Path() const { return path_; }
148   // Return the path containing symbol table and debug information.
GetDebugFilePath()149   const std::string& GetDebugFilePath() const { return debug_file_path_; }
150   // Return the file name without directory info.
FileName()151   const std::string& FileName() const { return file_name_; }
152 
HasDumpId()153   bool HasDumpId() {
154     return dump_id_ != UINT_MAX;
155   }
156 
GetDumpId(uint32_t * pdump_id)157   bool GetDumpId(uint32_t* pdump_id) {
158     if (!HasDumpId()) {
159       return false;
160     }
161     *pdump_id = dump_id_;
162     return true;
163   }
164 
165   uint32_t CreateDumpId();
166   uint32_t CreateSymbolDumpId(const Symbol* symbol);
167 
SetMinExecutableVaddr(uint64_t,uint64_t)168   virtual void SetMinExecutableVaddr(uint64_t, uint64_t) {}
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * file_offset)169   virtual void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) {
170     *min_vaddr = 0;
171     *file_offset = 0;
172   }
AddDexFileOffset(uint64_t)173   virtual void AddDexFileOffset(uint64_t) {}
DexFileOffsets()174   virtual const std::vector<uint64_t>* DexFileOffsets() { return nullptr; }
175 
176   virtual uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) = 0;
177 
178   const Symbol* FindSymbol(uint64_t vaddr_in_dso);
179 
GetSymbols()180   const std::vector<Symbol>& GetSymbols() { return symbols_; }
181   void SetSymbols(std::vector<Symbol>* symbols);
182 
183   // Create a symbol for a virtual address which can't find a corresponding
184   // symbol in symbol table.
185   void AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name);
186   bool IsForJavaMethod();
187 
188  protected:
189   static bool demangle_;
190   static std::string vmlinux_;
191   static std::string kallsyms_;
192   static bool read_kernel_symbols_from_proc_;
193   static std::unordered_map<std::string, BuildId> build_id_map_;
194   static size_t dso_count_;
195   static uint32_t g_dump_id_;
196   static simpleperf_dso_impl::DebugElfFileFinder debug_elf_file_finder_;
197 
198   Dso(DsoType type, const std::string& path, const std::string& debug_file_path);
199   BuildId GetExpectedBuildId();
200 
201   void Load();
202   virtual std::vector<Symbol> LoadSymbols() = 0;
203 
204   DsoType type_;
205   // path of the shared library used by the profiled program
206   const std::string path_;
207   // path of the shared library having symbol table and debug information
208   // It is the same as path_, or has the same build id as path_.
209   std::string debug_file_path_;
210   // File name of the shared library, got by removing directories in path_.
211   std::string file_name_;
212   std::vector<Symbol> symbols_;
213   // unknown symbols are like [libc.so+0x1234].
214   std::unordered_map<uint64_t, Symbol> unknown_symbols_;
215   bool is_loaded_;
216   // Used to identify current dso if it needs to be dumped.
217   uint32_t dump_id_;
218   // Used to assign dump_id for symbols in current dso.
219   uint32_t symbol_dump_id_;
220   android::base::LogSeverity symbol_warning_loglevel_;
221 };
222 
223 const char* DsoTypeToString(DsoType dso_type);
224 bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id);
225 
226 #endif  // SIMPLE_PERF_DSO_H_
227