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