xref: /aosp_15_r20/system/extras/simpleperf/dso.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include "dso.h"
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
20*288bf522SAndroid Build Coastguard Worker #include <string.h>
21*288bf522SAndroid Build Coastguard Worker 
22*288bf522SAndroid Build Coastguard Worker #include <algorithm>
23*288bf522SAndroid Build Coastguard Worker #include <limits>
24*288bf522SAndroid Build Coastguard Worker #include <memory>
25*288bf522SAndroid Build Coastguard Worker #include <optional>
26*288bf522SAndroid Build Coastguard Worker #include <string_view>
27*288bf522SAndroid Build Coastguard Worker #include <vector>
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
30*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
31*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker #include "JITDebugReader.h"
34*288bf522SAndroid Build Coastguard Worker #include "environment.h"
35*288bf522SAndroid Build Coastguard Worker #include "kallsyms.h"
36*288bf522SAndroid Build Coastguard Worker #include "read_apk.h"
37*288bf522SAndroid Build Coastguard Worker #include "read_dex_file.h"
38*288bf522SAndroid Build Coastguard Worker #include "read_elf.h"
39*288bf522SAndroid Build Coastguard Worker #include "utils.h"
40*288bf522SAndroid Build Coastguard Worker 
41*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
42*288bf522SAndroid Build Coastguard Worker 
43*288bf522SAndroid Build Coastguard Worker using android::base::EndsWith;
44*288bf522SAndroid Build Coastguard Worker using android::base::StartsWith;
45*288bf522SAndroid Build Coastguard Worker 
46*288bf522SAndroid Build Coastguard Worker namespace simpleperf_dso_impl {
47*288bf522SAndroid Build Coastguard Worker 
RemovePathSeparatorSuffix(const std::string & path)48*288bf522SAndroid Build Coastguard Worker std::string RemovePathSeparatorSuffix(const std::string& path) {
49*288bf522SAndroid Build Coastguard Worker   // Don't remove path separator suffix for '/'.
50*288bf522SAndroid Build Coastguard Worker   if (EndsWith(path, OS_PATH_SEPARATOR) && path.size() > 1u) {
51*288bf522SAndroid Build Coastguard Worker     return path.substr(0, path.size() - 1);
52*288bf522SAndroid Build Coastguard Worker   }
53*288bf522SAndroid Build Coastguard Worker   return path;
54*288bf522SAndroid Build Coastguard Worker }
55*288bf522SAndroid Build Coastguard Worker 
Reset()56*288bf522SAndroid Build Coastguard Worker void DebugElfFileFinder::Reset() {
57*288bf522SAndroid Build Coastguard Worker   allow_mismatched_build_id_ = false;
58*288bf522SAndroid Build Coastguard Worker   vdso_64bit_.clear();
59*288bf522SAndroid Build Coastguard Worker   vdso_32bit_.clear();
60*288bf522SAndroid Build Coastguard Worker   symfs_dir_.clear();
61*288bf522SAndroid Build Coastguard Worker   build_id_to_file_map_.clear();
62*288bf522SAndroid Build Coastguard Worker }
63*288bf522SAndroid Build Coastguard Worker 
SetSymFsDir(const std::string & symfs_dir)64*288bf522SAndroid Build Coastguard Worker bool DebugElfFileFinder::SetSymFsDir(const std::string& symfs_dir) {
65*288bf522SAndroid Build Coastguard Worker   symfs_dir_ = RemovePathSeparatorSuffix(symfs_dir);
66*288bf522SAndroid Build Coastguard Worker   if (!IsDir(symfs_dir_)) {
67*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir_ << "'";
68*288bf522SAndroid Build Coastguard Worker     return false;
69*288bf522SAndroid Build Coastguard Worker   }
70*288bf522SAndroid Build Coastguard Worker   std::string build_id_list_file = symfs_dir_ + OS_PATH_SEPARATOR + "build_id_list";
71*288bf522SAndroid Build Coastguard Worker   std::string build_id_list;
72*288bf522SAndroid Build Coastguard Worker   if (android::base::ReadFileToString(build_id_list_file, &build_id_list)) {
73*288bf522SAndroid Build Coastguard Worker     for (auto& line : android::base::Split(build_id_list, "\n")) {
74*288bf522SAndroid Build Coastguard Worker       std::vector<std::string> items = android::base::Split(line, "=");
75*288bf522SAndroid Build Coastguard Worker       if (items.size() == 2u) {
76*288bf522SAndroid Build Coastguard Worker         build_id_to_file_map_[items[0]] = symfs_dir_ + OS_PATH_SEPARATOR + items[1];
77*288bf522SAndroid Build Coastguard Worker       }
78*288bf522SAndroid Build Coastguard Worker     }
79*288bf522SAndroid Build Coastguard Worker   }
80*288bf522SAndroid Build Coastguard Worker   return true;
81*288bf522SAndroid Build Coastguard Worker }
82*288bf522SAndroid Build Coastguard Worker 
AddSymbolDir(const std::string & symbol_dir)83*288bf522SAndroid Build Coastguard Worker bool DebugElfFileFinder::AddSymbolDir(const std::string& symbol_dir) {
84*288bf522SAndroid Build Coastguard Worker   if (!IsDir(symbol_dir)) {
85*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Invalid symbol dir " << symbol_dir;
86*288bf522SAndroid Build Coastguard Worker     return false;
87*288bf522SAndroid Build Coastguard Worker   }
88*288bf522SAndroid Build Coastguard Worker   std::string dir = RemovePathSeparatorSuffix(symbol_dir);
89*288bf522SAndroid Build Coastguard Worker   CollectBuildIdInDir(dir);
90*288bf522SAndroid Build Coastguard Worker   return true;
91*288bf522SAndroid Build Coastguard Worker }
92*288bf522SAndroid Build Coastguard Worker 
CollectBuildIdInDir(const std::string & dir)93*288bf522SAndroid Build Coastguard Worker void DebugElfFileFinder::CollectBuildIdInDir(const std::string& dir) {
94*288bf522SAndroid Build Coastguard Worker   for (const std::string& entry : GetEntriesInDir(dir)) {
95*288bf522SAndroid Build Coastguard Worker     std::string path = dir + OS_PATH_SEPARATOR + entry;
96*288bf522SAndroid Build Coastguard Worker     if (IsDir(path)) {
97*288bf522SAndroid Build Coastguard Worker       CollectBuildIdInDir(path);
98*288bf522SAndroid Build Coastguard Worker     } else {
99*288bf522SAndroid Build Coastguard Worker       BuildId build_id;
100*288bf522SAndroid Build Coastguard Worker       ElfStatus status;
101*288bf522SAndroid Build Coastguard Worker       auto elf = ElfFile::Open(path, &status);
102*288bf522SAndroid Build Coastguard Worker       if (status == ElfStatus::NO_ERROR) {
103*288bf522SAndroid Build Coastguard Worker         if (elf->GetBuildId(&build_id) == ElfStatus::NO_ERROR) {
104*288bf522SAndroid Build Coastguard Worker           build_id_to_file_map_[build_id.ToString()] = path;
105*288bf522SAndroid Build Coastguard Worker         } else {
106*288bf522SAndroid Build Coastguard Worker           no_build_id_files_.emplace_back(std::move(path));
107*288bf522SAndroid Build Coastguard Worker         }
108*288bf522SAndroid Build Coastguard Worker       }
109*288bf522SAndroid Build Coastguard Worker     }
110*288bf522SAndroid Build Coastguard Worker   }
111*288bf522SAndroid Build Coastguard Worker }
112*288bf522SAndroid Build Coastguard Worker 
SetVdsoFile(const std::string & vdso_file,bool is_64bit)113*288bf522SAndroid Build Coastguard Worker void DebugElfFileFinder::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
114*288bf522SAndroid Build Coastguard Worker   if (is_64bit) {
115*288bf522SAndroid Build Coastguard Worker     vdso_64bit_ = vdso_file;
116*288bf522SAndroid Build Coastguard Worker   } else {
117*288bf522SAndroid Build Coastguard Worker     vdso_32bit_ = vdso_file;
118*288bf522SAndroid Build Coastguard Worker   }
119*288bf522SAndroid Build Coastguard Worker }
120*288bf522SAndroid Build Coastguard Worker 
CheckDebugFilePath(const std::string & path,BuildId & build_id,bool report_build_id_mismatch)121*288bf522SAndroid Build Coastguard Worker bool DebugElfFileFinder::CheckDebugFilePath(const std::string& path, BuildId& build_id,
122*288bf522SAndroid Build Coastguard Worker                                             bool report_build_id_mismatch) {
123*288bf522SAndroid Build Coastguard Worker   ElfStatus status;
124*288bf522SAndroid Build Coastguard Worker   auto elf = ElfFile::Open(path, &status);
125*288bf522SAndroid Build Coastguard Worker   if (!elf) {
126*288bf522SAndroid Build Coastguard Worker     return false;
127*288bf522SAndroid Build Coastguard Worker   }
128*288bf522SAndroid Build Coastguard Worker   BuildId debug_build_id;
129*288bf522SAndroid Build Coastguard Worker   status = elf->GetBuildId(&debug_build_id);
130*288bf522SAndroid Build Coastguard Worker   if (status != ElfStatus::NO_ERROR && status != ElfStatus::NO_BUILD_ID) {
131*288bf522SAndroid Build Coastguard Worker     return false;
132*288bf522SAndroid Build Coastguard Worker   }
133*288bf522SAndroid Build Coastguard Worker 
134*288bf522SAndroid Build Coastguard Worker   if (allow_mismatched_build_id_) {
135*288bf522SAndroid Build Coastguard Worker     return true;
136*288bf522SAndroid Build Coastguard Worker   }
137*288bf522SAndroid Build Coastguard Worker 
138*288bf522SAndroid Build Coastguard Worker   // Native libraries in apks and kernel modules may not have build ids.
139*288bf522SAndroid Build Coastguard Worker   // So build_id and debug_build_id can either be empty, or have the same value.
140*288bf522SAndroid Build Coastguard Worker   bool match = build_id == debug_build_id;
141*288bf522SAndroid Build Coastguard Worker   if (!match && report_build_id_mismatch) {
142*288bf522SAndroid Build Coastguard Worker     LOG(WARNING) << path << " isn't used because of build id mismatch: expected " << build_id
143*288bf522SAndroid Build Coastguard Worker                  << ", real " << debug_build_id;
144*288bf522SAndroid Build Coastguard Worker   }
145*288bf522SAndroid Build Coastguard Worker   return match;
146*288bf522SAndroid Build Coastguard Worker }
147*288bf522SAndroid Build Coastguard Worker 
FindDebugFile(const std::string & dso_path,bool force_64bit,BuildId & build_id)148*288bf522SAndroid Build Coastguard Worker std::string DebugElfFileFinder::FindDebugFile(const std::string& dso_path, bool force_64bit,
149*288bf522SAndroid Build Coastguard Worker                                               BuildId& build_id) {
150*288bf522SAndroid Build Coastguard Worker   if (dso_path == "[vdso]") {
151*288bf522SAndroid Build Coastguard Worker     if (force_64bit && !vdso_64bit_.empty()) {
152*288bf522SAndroid Build Coastguard Worker       return vdso_64bit_;
153*288bf522SAndroid Build Coastguard Worker     } else if (!force_64bit && !vdso_32bit_.empty()) {
154*288bf522SAndroid Build Coastguard Worker       return vdso_32bit_;
155*288bf522SAndroid Build Coastguard Worker     }
156*288bf522SAndroid Build Coastguard Worker   }
157*288bf522SAndroid Build Coastguard Worker   if (build_id.IsEmpty()) {
158*288bf522SAndroid Build Coastguard Worker     // Try reading build id from file if we don't already have one.
159*288bf522SAndroid Build Coastguard Worker     GetBuildIdFromDsoPath(dso_path, &build_id);
160*288bf522SAndroid Build Coastguard Worker   }
161*288bf522SAndroid Build Coastguard Worker 
162*288bf522SAndroid Build Coastguard Worker   // 1. Try build_id_to_file_map.
163*288bf522SAndroid Build Coastguard Worker   if (!build_id_to_file_map_.empty()) {
164*288bf522SAndroid Build Coastguard Worker     if (!build_id.IsEmpty()) {
165*288bf522SAndroid Build Coastguard Worker       auto it = build_id_to_file_map_.find(build_id.ToString());
166*288bf522SAndroid Build Coastguard Worker       if (it != build_id_to_file_map_.end() && CheckDebugFilePath(it->second, build_id, false)) {
167*288bf522SAndroid Build Coastguard Worker         return it->second;
168*288bf522SAndroid Build Coastguard Worker       }
169*288bf522SAndroid Build Coastguard Worker     }
170*288bf522SAndroid Build Coastguard Worker   }
171*288bf522SAndroid Build Coastguard Worker   if (allow_mismatched_build_id_) {
172*288bf522SAndroid Build Coastguard Worker     std::optional<std::string> s = SearchFileMapByPath(dso_path);
173*288bf522SAndroid Build Coastguard Worker     if (s.has_value()) {
174*288bf522SAndroid Build Coastguard Worker       return s.value();
175*288bf522SAndroid Build Coastguard Worker     }
176*288bf522SAndroid Build Coastguard Worker   }
177*288bf522SAndroid Build Coastguard Worker   if (!symfs_dir_.empty()) {
178*288bf522SAndroid Build Coastguard Worker     // 2. Try concatenating symfs_dir and dso_path.
179*288bf522SAndroid Build Coastguard Worker     std::string path = GetPathInSymFsDir(dso_path);
180*288bf522SAndroid Build Coastguard Worker     if (CheckDebugFilePath(path, build_id, true)) {
181*288bf522SAndroid Build Coastguard Worker       return path;
182*288bf522SAndroid Build Coastguard Worker     }
183*288bf522SAndroid Build Coastguard Worker     if (EndsWith(dso_path, ".apk") && IsRegularFile(path)) {
184*288bf522SAndroid Build Coastguard Worker       return path;
185*288bf522SAndroid Build Coastguard Worker     }
186*288bf522SAndroid Build Coastguard Worker     // 3. Try concatenating symfs_dir and basename of dso_path.
187*288bf522SAndroid Build Coastguard Worker     path = symfs_dir_ + OS_PATH_SEPARATOR + android::base::Basename(dso_path);
188*288bf522SAndroid Build Coastguard Worker     if (CheckDebugFilePath(path, build_id, false)) {
189*288bf522SAndroid Build Coastguard Worker       return path;
190*288bf522SAndroid Build Coastguard Worker     }
191*288bf522SAndroid Build Coastguard Worker   }
192*288bf522SAndroid Build Coastguard Worker   // 4. Try concatenating /usr/lib/debug and dso_path.
193*288bf522SAndroid Build Coastguard Worker   // Linux host can store debug shared libraries in /usr/lib/debug.
194*288bf522SAndroid Build Coastguard Worker   if (CheckDebugFilePath("/usr/lib/debug" + dso_path, build_id, false)) {
195*288bf522SAndroid Build Coastguard Worker     return "/usr/lib/debug" + dso_path;
196*288bf522SAndroid Build Coastguard Worker   }
197*288bf522SAndroid Build Coastguard Worker   return dso_path;
198*288bf522SAndroid Build Coastguard Worker }
199*288bf522SAndroid Build Coastguard Worker 
GetPathInSymFsDir(const std::string & path)200*288bf522SAndroid Build Coastguard Worker std::string DebugElfFileFinder::GetPathInSymFsDir(const std::string& path) {
201*288bf522SAndroid Build Coastguard Worker   auto add_symfs_prefix = [&](const std::string& path) {
202*288bf522SAndroid Build Coastguard Worker     if (StartsWith(path, OS_PATH_SEPARATOR)) {
203*288bf522SAndroid Build Coastguard Worker       return symfs_dir_ + path;
204*288bf522SAndroid Build Coastguard Worker     }
205*288bf522SAndroid Build Coastguard Worker     return symfs_dir_ + OS_PATH_SEPARATOR + path;
206*288bf522SAndroid Build Coastguard Worker   };
207*288bf522SAndroid Build Coastguard Worker   if (OS_PATH_SEPARATOR == '/') {
208*288bf522SAndroid Build Coastguard Worker     return add_symfs_prefix(path);
209*288bf522SAndroid Build Coastguard Worker   }
210*288bf522SAndroid Build Coastguard Worker   // Paths in recorded perf.data uses '/' as path separator. When reporting on Windows, it needs
211*288bf522SAndroid Build Coastguard Worker   // to be converted to '\\'.
212*288bf522SAndroid Build Coastguard Worker   auto tuple = SplitUrlInApk(path);
213*288bf522SAndroid Build Coastguard Worker   if (std::get<0>(tuple)) {
214*288bf522SAndroid Build Coastguard Worker     std::string apk_path = std::get<1>(tuple);
215*288bf522SAndroid Build Coastguard Worker     std::string entry_path = std::get<2>(tuple);
216*288bf522SAndroid Build Coastguard Worker     std::replace(apk_path.begin(), apk_path.end(), '/', OS_PATH_SEPARATOR);
217*288bf522SAndroid Build Coastguard Worker     return GetUrlInApk(add_symfs_prefix(apk_path), entry_path);
218*288bf522SAndroid Build Coastguard Worker   }
219*288bf522SAndroid Build Coastguard Worker   std::string elf_path = path;
220*288bf522SAndroid Build Coastguard Worker   std::replace(elf_path.begin(), elf_path.end(), '/', OS_PATH_SEPARATOR);
221*288bf522SAndroid Build Coastguard Worker   return add_symfs_prefix(elf_path);
222*288bf522SAndroid Build Coastguard Worker }
223*288bf522SAndroid Build Coastguard Worker 
SearchFileMapByPath(std::string_view path)224*288bf522SAndroid Build Coastguard Worker std::optional<std::string> DebugElfFileFinder::SearchFileMapByPath(std::string_view path) {
225*288bf522SAndroid Build Coastguard Worker   if (path == "[kernel.kallsyms]") {
226*288bf522SAndroid Build Coastguard Worker     path = "vmlinux";
227*288bf522SAndroid Build Coastguard Worker   }
228*288bf522SAndroid Build Coastguard Worker   std::string_view filename;
229*288bf522SAndroid Build Coastguard Worker   if (size_t pos = path.rfind('/'); pos != path.npos) {
230*288bf522SAndroid Build Coastguard Worker     filename = path.substr(pos + 1);
231*288bf522SAndroid Build Coastguard Worker   } else {
232*288bf522SAndroid Build Coastguard Worker     filename = path;
233*288bf522SAndroid Build Coastguard Worker   }
234*288bf522SAndroid Build Coastguard Worker   std::string best_elf_file;
235*288bf522SAndroid Build Coastguard Worker   size_t best_match_length = 0;
236*288bf522SAndroid Build Coastguard Worker   auto check_file = [&](const std::string& elf_file) {
237*288bf522SAndroid Build Coastguard Worker     if (EndsWith(elf_file, filename)) {
238*288bf522SAndroid Build Coastguard Worker       size_t i = elf_file.size();
239*288bf522SAndroid Build Coastguard Worker       size_t j = path.size();
240*288bf522SAndroid Build Coastguard Worker       while (i > 0 && j > 0 && elf_file[i - 1] == path[j - 1]) {
241*288bf522SAndroid Build Coastguard Worker         i--;
242*288bf522SAndroid Build Coastguard Worker         j--;
243*288bf522SAndroid Build Coastguard Worker       }
244*288bf522SAndroid Build Coastguard Worker       size_t match_length = elf_file.size() - i;
245*288bf522SAndroid Build Coastguard Worker       if (match_length > best_match_length) {
246*288bf522SAndroid Build Coastguard Worker         best_elf_file = elf_file;
247*288bf522SAndroid Build Coastguard Worker         best_match_length = match_length;
248*288bf522SAndroid Build Coastguard Worker       }
249*288bf522SAndroid Build Coastguard Worker     }
250*288bf522SAndroid Build Coastguard Worker   };
251*288bf522SAndroid Build Coastguard Worker 
252*288bf522SAndroid Build Coastguard Worker   for (const auto& p : build_id_to_file_map_) {
253*288bf522SAndroid Build Coastguard Worker     check_file(p.second);
254*288bf522SAndroid Build Coastguard Worker   }
255*288bf522SAndroid Build Coastguard Worker   for (const auto& elf_file : no_build_id_files_) {
256*288bf522SAndroid Build Coastguard Worker     check_file(elf_file);
257*288bf522SAndroid Build Coastguard Worker   }
258*288bf522SAndroid Build Coastguard Worker   if (!best_elf_file.empty()) {
259*288bf522SAndroid Build Coastguard Worker     LOG(INFO) << "Found " << best_elf_file << " for " << path << " by filename";
260*288bf522SAndroid Build Coastguard Worker     return best_elf_file;
261*288bf522SAndroid Build Coastguard Worker   }
262*288bf522SAndroid Build Coastguard Worker   return std::nullopt;
263*288bf522SAndroid Build Coastguard Worker }
264*288bf522SAndroid Build Coastguard Worker 
265*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf_dso_impl
266*288bf522SAndroid Build Coastguard Worker 
267*288bf522SAndroid Build Coastguard Worker static OneTimeFreeAllocator symbol_name_allocator;
268*288bf522SAndroid Build Coastguard Worker 
Symbol(std::string_view name,uint64_t addr,uint64_t len)269*288bf522SAndroid Build Coastguard Worker Symbol::Symbol(std::string_view name, uint64_t addr, uint64_t len)
270*288bf522SAndroid Build Coastguard Worker     : addr(addr),
271*288bf522SAndroid Build Coastguard Worker       len(len),
272*288bf522SAndroid Build Coastguard Worker       name_(symbol_name_allocator.AllocateString(name)),
273*288bf522SAndroid Build Coastguard Worker       demangled_name_(nullptr),
274*288bf522SAndroid Build Coastguard Worker       dump_id_(UINT_MAX) {}
275*288bf522SAndroid Build Coastguard Worker 
DemangledName() const276*288bf522SAndroid Build Coastguard Worker const char* Symbol::DemangledName() const {
277*288bf522SAndroid Build Coastguard Worker   if (demangled_name_ == nullptr) {
278*288bf522SAndroid Build Coastguard Worker     const std::string s = Dso::Demangle(name_);
279*288bf522SAndroid Build Coastguard Worker     SetDemangledName(s);
280*288bf522SAndroid Build Coastguard Worker   }
281*288bf522SAndroid Build Coastguard Worker   return demangled_name_;
282*288bf522SAndroid Build Coastguard Worker }
283*288bf522SAndroid Build Coastguard Worker 
SetDemangledName(std::string_view name) const284*288bf522SAndroid Build Coastguard Worker void Symbol::SetDemangledName(std::string_view name) const {
285*288bf522SAndroid Build Coastguard Worker   if (name == name_) {
286*288bf522SAndroid Build Coastguard Worker     demangled_name_ = name_;
287*288bf522SAndroid Build Coastguard Worker   } else {
288*288bf522SAndroid Build Coastguard Worker     demangled_name_ = symbol_name_allocator.AllocateString(name);
289*288bf522SAndroid Build Coastguard Worker   }
290*288bf522SAndroid Build Coastguard Worker }
291*288bf522SAndroid Build Coastguard Worker 
FunctionName() const292*288bf522SAndroid Build Coastguard Worker std::string_view Symbol::FunctionName() const {
293*288bf522SAndroid Build Coastguard Worker   // Name with signature is like "void ctep.v(cteo, ctgc, ctbn)".
294*288bf522SAndroid Build Coastguard Worker   std::string_view name = DemangledName();
295*288bf522SAndroid Build Coastguard Worker   auto brace_pos = name.find('(');
296*288bf522SAndroid Build Coastguard Worker   if (brace_pos != name.npos) {
297*288bf522SAndroid Build Coastguard Worker     name = name.substr(0, brace_pos);
298*288bf522SAndroid Build Coastguard Worker     auto space_pos = name.rfind(' ');
299*288bf522SAndroid Build Coastguard Worker     if (space_pos != name.npos) {
300*288bf522SAndroid Build Coastguard Worker       name = name.substr(space_pos + 1);
301*288bf522SAndroid Build Coastguard Worker     }
302*288bf522SAndroid Build Coastguard Worker   }
303*288bf522SAndroid Build Coastguard Worker   return name;
304*288bf522SAndroid Build Coastguard Worker }
305*288bf522SAndroid Build Coastguard Worker 
CompareSymbolToAddr(const Symbol & s,uint64_t addr)306*288bf522SAndroid Build Coastguard Worker static bool CompareSymbolToAddr(const Symbol& s, uint64_t addr) {
307*288bf522SAndroid Build Coastguard Worker   return s.addr < addr;
308*288bf522SAndroid Build Coastguard Worker }
309*288bf522SAndroid Build Coastguard Worker 
CompareAddrToSymbol(uint64_t addr,const Symbol & s)310*288bf522SAndroid Build Coastguard Worker static bool CompareAddrToSymbol(uint64_t addr, const Symbol& s) {
311*288bf522SAndroid Build Coastguard Worker   return addr < s.addr;
312*288bf522SAndroid Build Coastguard Worker }
313*288bf522SAndroid Build Coastguard Worker 
314*288bf522SAndroid Build Coastguard Worker bool Dso::demangle_ = true;
315*288bf522SAndroid Build Coastguard Worker std::string Dso::vmlinux_;
316*288bf522SAndroid Build Coastguard Worker std::string Dso::kallsyms_;
317*288bf522SAndroid Build Coastguard Worker std::unordered_map<std::string, BuildId> Dso::build_id_map_;
318*288bf522SAndroid Build Coastguard Worker size_t Dso::dso_count_;
319*288bf522SAndroid Build Coastguard Worker uint32_t Dso::g_dump_id_;
320*288bf522SAndroid Build Coastguard Worker simpleperf_dso_impl::DebugElfFileFinder Dso::debug_elf_file_finder_;
321*288bf522SAndroid Build Coastguard Worker 
SetDemangle(bool demangle)322*288bf522SAndroid Build Coastguard Worker void Dso::SetDemangle(bool demangle) {
323*288bf522SAndroid Build Coastguard Worker   demangle_ = demangle;
324*288bf522SAndroid Build Coastguard Worker }
325*288bf522SAndroid Build Coastguard Worker 
326*288bf522SAndroid Build Coastguard Worker extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
327*288bf522SAndroid Build Coastguard Worker #if defined(__linux__) || defined(__darwin__)
328*288bf522SAndroid Build Coastguard Worker extern "C" char* rustc_demangle(const char* mangled, char* out, size_t* len, int* status);
329*288bf522SAndroid Build Coastguard Worker #endif
330*288bf522SAndroid Build Coastguard Worker 
Demangle(const std::string & name)331*288bf522SAndroid Build Coastguard Worker std::string Dso::Demangle(const std::string& name) {
332*288bf522SAndroid Build Coastguard Worker   if (!demangle_) {
333*288bf522SAndroid Build Coastguard Worker     return name;
334*288bf522SAndroid Build Coastguard Worker   }
335*288bf522SAndroid Build Coastguard Worker   int status;
336*288bf522SAndroid Build Coastguard Worker   bool is_linker_symbol = (name.find(linker_prefix) == 0);
337*288bf522SAndroid Build Coastguard Worker   const char* mangled_str = name.c_str();
338*288bf522SAndroid Build Coastguard Worker   if (is_linker_symbol) {
339*288bf522SAndroid Build Coastguard Worker     mangled_str += linker_prefix.size();
340*288bf522SAndroid Build Coastguard Worker   }
341*288bf522SAndroid Build Coastguard Worker 
342*288bf522SAndroid Build Coastguard Worker   if (mangled_str[0] == '_') {
343*288bf522SAndroid Build Coastguard Worker     char* demangled_name = nullptr;
344*288bf522SAndroid Build Coastguard Worker     int status = -2;  // -2 means name didn't demangle.
345*288bf522SAndroid Build Coastguard Worker     if (mangled_str[1] == 'Z') {
346*288bf522SAndroid Build Coastguard Worker       demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
347*288bf522SAndroid Build Coastguard Worker #if defined(__linux__) || defined(__darwin__)
348*288bf522SAndroid Build Coastguard Worker     } else if (mangled_str[1] == 'R') {
349*288bf522SAndroid Build Coastguard Worker       demangled_name = rustc_demangle(mangled_str, nullptr, nullptr, &status);
350*288bf522SAndroid Build Coastguard Worker #endif
351*288bf522SAndroid Build Coastguard Worker     }
352*288bf522SAndroid Build Coastguard Worker     if (status == 0) {
353*288bf522SAndroid Build Coastguard Worker       // demangled successfully
354*288bf522SAndroid Build Coastguard Worker       std::string result;
355*288bf522SAndroid Build Coastguard Worker       if (is_linker_symbol) {
356*288bf522SAndroid Build Coastguard Worker         result = std::string("[linker]") + demangled_name;
357*288bf522SAndroid Build Coastguard Worker       } else {
358*288bf522SAndroid Build Coastguard Worker         result = demangled_name;
359*288bf522SAndroid Build Coastguard Worker       }
360*288bf522SAndroid Build Coastguard Worker       free(demangled_name);
361*288bf522SAndroid Build Coastguard Worker       return result;
362*288bf522SAndroid Build Coastguard Worker     }
363*288bf522SAndroid Build Coastguard Worker   }
364*288bf522SAndroid Build Coastguard Worker 
365*288bf522SAndroid Build Coastguard Worker   // failed to demangle
366*288bf522SAndroid Build Coastguard Worker   if (is_linker_symbol) {
367*288bf522SAndroid Build Coastguard Worker     return std::string("[linker]") + mangled_str;
368*288bf522SAndroid Build Coastguard Worker   }
369*288bf522SAndroid Build Coastguard Worker   return name;
370*288bf522SAndroid Build Coastguard Worker }
371*288bf522SAndroid Build Coastguard Worker 
SetSymFsDir(const std::string & symfs_dir)372*288bf522SAndroid Build Coastguard Worker bool Dso::SetSymFsDir(const std::string& symfs_dir) {
373*288bf522SAndroid Build Coastguard Worker   return debug_elf_file_finder_.SetSymFsDir(symfs_dir);
374*288bf522SAndroid Build Coastguard Worker }
375*288bf522SAndroid Build Coastguard Worker 
AddSymbolDir(const std::string & symbol_dir)376*288bf522SAndroid Build Coastguard Worker bool Dso::AddSymbolDir(const std::string& symbol_dir) {
377*288bf522SAndroid Build Coastguard Worker   return debug_elf_file_finder_.AddSymbolDir(symbol_dir);
378*288bf522SAndroid Build Coastguard Worker }
379*288bf522SAndroid Build Coastguard Worker 
AllowMismatchedBuildId()380*288bf522SAndroid Build Coastguard Worker void Dso::AllowMismatchedBuildId() {
381*288bf522SAndroid Build Coastguard Worker   return debug_elf_file_finder_.AllowMismatchedBuildId();
382*288bf522SAndroid Build Coastguard Worker }
383*288bf522SAndroid Build Coastguard Worker 
SetVmlinux(const std::string & vmlinux)384*288bf522SAndroid Build Coastguard Worker void Dso::SetVmlinux(const std::string& vmlinux) {
385*288bf522SAndroid Build Coastguard Worker   vmlinux_ = vmlinux;
386*288bf522SAndroid Build Coastguard Worker }
387*288bf522SAndroid Build Coastguard Worker 
SetBuildIds(const std::vector<std::pair<std::string,BuildId>> & build_ids)388*288bf522SAndroid Build Coastguard Worker void Dso::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids) {
389*288bf522SAndroid Build Coastguard Worker   std::unordered_map<std::string, BuildId> map;
390*288bf522SAndroid Build Coastguard Worker   for (auto& pair : build_ids) {
391*288bf522SAndroid Build Coastguard Worker     LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
392*288bf522SAndroid Build Coastguard Worker     map.insert(pair);
393*288bf522SAndroid Build Coastguard Worker   }
394*288bf522SAndroid Build Coastguard Worker   build_id_map_ = std::move(map);
395*288bf522SAndroid Build Coastguard Worker }
396*288bf522SAndroid Build Coastguard Worker 
SetVdsoFile(const std::string & vdso_file,bool is_64bit)397*288bf522SAndroid Build Coastguard Worker void Dso::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
398*288bf522SAndroid Build Coastguard Worker   debug_elf_file_finder_.SetVdsoFile(vdso_file, is_64bit);
399*288bf522SAndroid Build Coastguard Worker }
400*288bf522SAndroid Build Coastguard Worker 
FindExpectedBuildIdForPath(const std::string & path)401*288bf522SAndroid Build Coastguard Worker BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
402*288bf522SAndroid Build Coastguard Worker   auto it = build_id_map_.find(path);
403*288bf522SAndroid Build Coastguard Worker   if (it != build_id_map_.end()) {
404*288bf522SAndroid Build Coastguard Worker     return it->second;
405*288bf522SAndroid Build Coastguard Worker   }
406*288bf522SAndroid Build Coastguard Worker   return BuildId();
407*288bf522SAndroid Build Coastguard Worker }
408*288bf522SAndroid Build Coastguard Worker 
GetExpectedBuildId() const409*288bf522SAndroid Build Coastguard Worker BuildId Dso::GetExpectedBuildId() const {
410*288bf522SAndroid Build Coastguard Worker   return FindExpectedBuildIdForPath(path_);
411*288bf522SAndroid Build Coastguard Worker }
412*288bf522SAndroid Build Coastguard Worker 
Dso(DsoType type,const std::string & path)413*288bf522SAndroid Build Coastguard Worker Dso::Dso(DsoType type, const std::string& path)
414*288bf522SAndroid Build Coastguard Worker     : type_(type),
415*288bf522SAndroid Build Coastguard Worker       path_(path),
416*288bf522SAndroid Build Coastguard Worker       is_loaded_(false),
417*288bf522SAndroid Build Coastguard Worker       dump_id_(UINT_MAX),
418*288bf522SAndroid Build Coastguard Worker       symbol_dump_id_(0),
419*288bf522SAndroid Build Coastguard Worker       symbol_warning_loglevel_(android::base::WARNING) {
420*288bf522SAndroid Build Coastguard Worker   size_t pos = path.find_last_of("/\\");
421*288bf522SAndroid Build Coastguard Worker   if (pos != std::string::npos) {
422*288bf522SAndroid Build Coastguard Worker     file_name_ = path.substr(pos + 1);
423*288bf522SAndroid Build Coastguard Worker   } else {
424*288bf522SAndroid Build Coastguard Worker     file_name_ = path;
425*288bf522SAndroid Build Coastguard Worker   }
426*288bf522SAndroid Build Coastguard Worker   dso_count_++;
427*288bf522SAndroid Build Coastguard Worker }
428*288bf522SAndroid Build Coastguard Worker 
~Dso()429*288bf522SAndroid Build Coastguard Worker Dso::~Dso() {
430*288bf522SAndroid Build Coastguard Worker   if (--dso_count_ == 0) {
431*288bf522SAndroid Build Coastguard Worker     // Clean up global variables when no longer used.
432*288bf522SAndroid Build Coastguard Worker     symbol_name_allocator.Clear();
433*288bf522SAndroid Build Coastguard Worker     demangle_ = true;
434*288bf522SAndroid Build Coastguard Worker     vmlinux_.clear();
435*288bf522SAndroid Build Coastguard Worker     kallsyms_.clear();
436*288bf522SAndroid Build Coastguard Worker     build_id_map_.clear();
437*288bf522SAndroid Build Coastguard Worker     g_dump_id_ = 0;
438*288bf522SAndroid Build Coastguard Worker     debug_elf_file_finder_.Reset();
439*288bf522SAndroid Build Coastguard Worker   }
440*288bf522SAndroid Build Coastguard Worker }
441*288bf522SAndroid Build Coastguard Worker 
CreateDumpId()442*288bf522SAndroid Build Coastguard Worker uint32_t Dso::CreateDumpId() {
443*288bf522SAndroid Build Coastguard Worker   CHECK(!HasDumpId());
444*288bf522SAndroid Build Coastguard Worker   return dump_id_ = g_dump_id_++;
445*288bf522SAndroid Build Coastguard Worker }
446*288bf522SAndroid Build Coastguard Worker 
CreateSymbolDumpId(const Symbol * symbol)447*288bf522SAndroid Build Coastguard Worker uint32_t Dso::CreateSymbolDumpId(const Symbol* symbol) {
448*288bf522SAndroid Build Coastguard Worker   CHECK(!symbol->HasDumpId());
449*288bf522SAndroid Build Coastguard Worker   symbol->dump_id_ = symbol_dump_id_++;
450*288bf522SAndroid Build Coastguard Worker   return symbol->dump_id_;
451*288bf522SAndroid Build Coastguard Worker }
452*288bf522SAndroid Build Coastguard Worker 
IpToFileOffset(uint64_t ip,uint64_t map_start,uint64_t map_pgoff)453*288bf522SAndroid Build Coastguard Worker std::optional<uint64_t> Dso::IpToFileOffset(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) {
454*288bf522SAndroid Build Coastguard Worker   return ip - map_start + map_pgoff;
455*288bf522SAndroid Build Coastguard Worker }
456*288bf522SAndroid Build Coastguard Worker 
FindSymbol(uint64_t vaddr_in_dso)457*288bf522SAndroid Build Coastguard Worker const Symbol* Dso::FindSymbol(uint64_t vaddr_in_dso) {
458*288bf522SAndroid Build Coastguard Worker   if (!is_loaded_) {
459*288bf522SAndroid Build Coastguard Worker     LoadSymbols();
460*288bf522SAndroid Build Coastguard Worker   }
461*288bf522SAndroid Build Coastguard Worker   auto it = std::upper_bound(symbols_.begin(), symbols_.end(), vaddr_in_dso, CompareAddrToSymbol);
462*288bf522SAndroid Build Coastguard Worker   if (it != symbols_.begin()) {
463*288bf522SAndroid Build Coastguard Worker     --it;
464*288bf522SAndroid Build Coastguard Worker     if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) {
465*288bf522SAndroid Build Coastguard Worker       return &*it;
466*288bf522SAndroid Build Coastguard Worker     }
467*288bf522SAndroid Build Coastguard Worker   }
468*288bf522SAndroid Build Coastguard Worker   if (!unknown_symbols_.empty()) {
469*288bf522SAndroid Build Coastguard Worker     auto it = unknown_symbols_.find(vaddr_in_dso);
470*288bf522SAndroid Build Coastguard Worker     if (it != unknown_symbols_.end()) {
471*288bf522SAndroid Build Coastguard Worker       return &it->second;
472*288bf522SAndroid Build Coastguard Worker     }
473*288bf522SAndroid Build Coastguard Worker   }
474*288bf522SAndroid Build Coastguard Worker   return nullptr;
475*288bf522SAndroid Build Coastguard Worker }
476*288bf522SAndroid Build Coastguard Worker 
SetSymbols(std::vector<Symbol> * symbols)477*288bf522SAndroid Build Coastguard Worker void Dso::SetSymbols(std::vector<Symbol>* symbols) {
478*288bf522SAndroid Build Coastguard Worker   symbols_ = std::move(*symbols);
479*288bf522SAndroid Build Coastguard Worker   symbols->clear();
480*288bf522SAndroid Build Coastguard Worker }
481*288bf522SAndroid Build Coastguard Worker 
AddUnknownSymbol(uint64_t vaddr_in_dso,const std::string & name)482*288bf522SAndroid Build Coastguard Worker void Dso::AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name) {
483*288bf522SAndroid Build Coastguard Worker   unknown_symbols_.insert(std::make_pair(vaddr_in_dso, Symbol(name, vaddr_in_dso, 1)));
484*288bf522SAndroid Build Coastguard Worker }
485*288bf522SAndroid Build Coastguard Worker 
IsForJavaMethod() const486*288bf522SAndroid Build Coastguard Worker bool Dso::IsForJavaMethod() const {
487*288bf522SAndroid Build Coastguard Worker   if (type_ == DSO_DEX_FILE) {
488*288bf522SAndroid Build Coastguard Worker     return true;
489*288bf522SAndroid Build Coastguard Worker   }
490*288bf522SAndroid Build Coastguard Worker   if (type_ == DSO_ELF_FILE) {
491*288bf522SAndroid Build Coastguard Worker     if (JITDebugReader::IsPathInJITSymFile(path_)) {
492*288bf522SAndroid Build Coastguard Worker       return true;
493*288bf522SAndroid Build Coastguard Worker     }
494*288bf522SAndroid Build Coastguard Worker     // JITDebugReader in old versions generates symfiles in 'TemporaryFile-XXXXXX'.
495*288bf522SAndroid Build Coastguard Worker     size_t pos = path_.rfind('/');
496*288bf522SAndroid Build Coastguard Worker     pos = (pos == std::string::npos) ? 0 : pos + 1;
497*288bf522SAndroid Build Coastguard Worker     return StartsWith(std::string_view(&path_[pos], path_.size() - pos), "TemporaryFile");
498*288bf522SAndroid Build Coastguard Worker   }
499*288bf522SAndroid Build Coastguard Worker   return false;
500*288bf522SAndroid Build Coastguard Worker }
501*288bf522SAndroid Build Coastguard Worker 
LoadSymbols()502*288bf522SAndroid Build Coastguard Worker void Dso::LoadSymbols() {
503*288bf522SAndroid Build Coastguard Worker   if (!is_loaded_) {
504*288bf522SAndroid Build Coastguard Worker     is_loaded_ = true;
505*288bf522SAndroid Build Coastguard Worker     std::vector<Symbol> symbols = LoadSymbolsImpl();
506*288bf522SAndroid Build Coastguard Worker     if (symbols_.empty()) {
507*288bf522SAndroid Build Coastguard Worker       symbols_ = std::move(symbols);
508*288bf522SAndroid Build Coastguard Worker     } else {
509*288bf522SAndroid Build Coastguard Worker       std::vector<Symbol> merged_symbols;
510*288bf522SAndroid Build Coastguard Worker       std::set_union(symbols_.begin(), symbols_.end(), symbols.begin(), symbols.end(),
511*288bf522SAndroid Build Coastguard Worker                      std::back_inserter(merged_symbols), Symbol::CompareValueByAddr);
512*288bf522SAndroid Build Coastguard Worker       symbols_ = std::move(merged_symbols);
513*288bf522SAndroid Build Coastguard Worker     }
514*288bf522SAndroid Build Coastguard Worker   }
515*288bf522SAndroid Build Coastguard Worker }
516*288bf522SAndroid Build Coastguard Worker 
ReportReadElfSymbolResult(ElfStatus result,const std::string & path,const std::string & debug_file_path,android::base::LogSeverity warning_loglevel=android::base::WARNING)517*288bf522SAndroid Build Coastguard Worker static void ReportReadElfSymbolResult(
518*288bf522SAndroid Build Coastguard Worker     ElfStatus result, const std::string& path, const std::string& debug_file_path,
519*288bf522SAndroid Build Coastguard Worker     android::base::LogSeverity warning_loglevel = android::base::WARNING) {
520*288bf522SAndroid Build Coastguard Worker   if (result == ElfStatus::NO_ERROR) {
521*288bf522SAndroid Build Coastguard Worker     LOG(VERBOSE) << "Read symbols from " << debug_file_path << " successfully";
522*288bf522SAndroid Build Coastguard Worker   } else if (result == ElfStatus::NO_SYMBOL_TABLE) {
523*288bf522SAndroid Build Coastguard Worker     if (path == "[vdso]") {
524*288bf522SAndroid Build Coastguard Worker       // Vdso only contains dynamic symbol table, and we can't change that.
525*288bf522SAndroid Build Coastguard Worker       return;
526*288bf522SAndroid Build Coastguard Worker     }
527*288bf522SAndroid Build Coastguard Worker     // Lacking symbol table isn't considered as an error but worth reporting.
528*288bf522SAndroid Build Coastguard Worker     LOG(warning_loglevel) << debug_file_path << " doesn't contain symbol table";
529*288bf522SAndroid Build Coastguard Worker   } else {
530*288bf522SAndroid Build Coastguard Worker     LOG(warning_loglevel) << "failed to read symbols from " << debug_file_path << ": " << result;
531*288bf522SAndroid Build Coastguard Worker   }
532*288bf522SAndroid Build Coastguard Worker }
533*288bf522SAndroid Build Coastguard Worker 
SortAndFixSymbols(std::vector<Symbol> & symbols)534*288bf522SAndroid Build Coastguard Worker static void SortAndFixSymbols(std::vector<Symbol>& symbols) {
535*288bf522SAndroid Build Coastguard Worker   std::sort(symbols.begin(), symbols.end(), Symbol::CompareValueByAddr);
536*288bf522SAndroid Build Coastguard Worker   Symbol* prev_symbol = nullptr;
537*288bf522SAndroid Build Coastguard Worker   for (auto& symbol : symbols) {
538*288bf522SAndroid Build Coastguard Worker     if (prev_symbol != nullptr && prev_symbol->len == 0) {
539*288bf522SAndroid Build Coastguard Worker       prev_symbol->len = symbol.addr - prev_symbol->addr;
540*288bf522SAndroid Build Coastguard Worker     }
541*288bf522SAndroid Build Coastguard Worker     prev_symbol = &symbol;
542*288bf522SAndroid Build Coastguard Worker   }
543*288bf522SAndroid Build Coastguard Worker }
544*288bf522SAndroid Build Coastguard Worker 
545*288bf522SAndroid Build Coastguard Worker class DexFileDso : public Dso {
546*288bf522SAndroid Build Coastguard Worker  public:
DexFileDso(const std::string & path)547*288bf522SAndroid Build Coastguard Worker   DexFileDso(const std::string& path) : Dso(DSO_DEX_FILE, path) {}
548*288bf522SAndroid Build Coastguard Worker 
AddDexFileOffset(uint64_t dex_file_offset)549*288bf522SAndroid Build Coastguard Worker   void AddDexFileOffset(uint64_t dex_file_offset) override {
550*288bf522SAndroid Build Coastguard Worker     auto it = std::lower_bound(dex_file_offsets_.begin(), dex_file_offsets_.end(), dex_file_offset);
551*288bf522SAndroid Build Coastguard Worker     if (it != dex_file_offsets_.end() && *it == dex_file_offset) {
552*288bf522SAndroid Build Coastguard Worker       return;
553*288bf522SAndroid Build Coastguard Worker     }
554*288bf522SAndroid Build Coastguard Worker     dex_file_offsets_.insert(it, dex_file_offset);
555*288bf522SAndroid Build Coastguard Worker   }
556*288bf522SAndroid Build Coastguard Worker 
DexFileOffsets()557*288bf522SAndroid Build Coastguard Worker   const std::vector<uint64_t>* DexFileOffsets() override { return &dex_file_offsets_; }
558*288bf522SAndroid Build Coastguard Worker 
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t map_pgoff)559*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
560*288bf522SAndroid Build Coastguard Worker     return ip - map_start + map_pgoff;
561*288bf522SAndroid Build Coastguard Worker   }
562*288bf522SAndroid Build Coastguard Worker 
LoadSymbolsImpl()563*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override {
564*288bf522SAndroid Build Coastguard Worker     std::vector<Symbol> symbols;
565*288bf522SAndroid Build Coastguard Worker     if (StartsWith(path_, kDexFileInMemoryPrefix)) {
566*288bf522SAndroid Build Coastguard Worker       // For dex file in memory, the symbols should already be set via SetSymbols().
567*288bf522SAndroid Build Coastguard Worker       return symbols;
568*288bf522SAndroid Build Coastguard Worker     }
569*288bf522SAndroid Build Coastguard Worker 
570*288bf522SAndroid Build Coastguard Worker     const std::string& debug_file_path = GetDebugFilePath();
571*288bf522SAndroid Build Coastguard Worker     auto tuple = SplitUrlInApk(debug_file_path);
572*288bf522SAndroid Build Coastguard Worker     // Symbols of dex files are collected on device. If the dex file doesn't exist, probably
573*288bf522SAndroid Build Coastguard Worker     // we are reporting on host, and there is no need to report warning of missing dex files.
574*288bf522SAndroid Build Coastguard Worker     if (!IsRegularFile(std::get<0>(tuple) ? std::get<1>(tuple) : debug_file_path)) {
575*288bf522SAndroid Build Coastguard Worker       LOG(DEBUG) << "skip reading symbols from non-exist dex_file " << debug_file_path;
576*288bf522SAndroid Build Coastguard Worker       return symbols;
577*288bf522SAndroid Build Coastguard Worker     }
578*288bf522SAndroid Build Coastguard Worker     bool status = false;
579*288bf522SAndroid Build Coastguard Worker     auto symbol_callback = [&](DexFileSymbol* symbol) {
580*288bf522SAndroid Build Coastguard Worker       symbols.emplace_back(symbol->name, symbol->addr, symbol->size);
581*288bf522SAndroid Build Coastguard Worker     };
582*288bf522SAndroid Build Coastguard Worker     if (std::get<0>(tuple)) {
583*288bf522SAndroid Build Coastguard Worker       std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(std::get<1>(tuple));
584*288bf522SAndroid Build Coastguard Worker       ZipEntry entry;
585*288bf522SAndroid Build Coastguard Worker       std::vector<uint8_t> data;
586*288bf522SAndroid Build Coastguard Worker       if (ahelper && ahelper->FindEntry(std::get<2>(tuple), &entry) &&
587*288bf522SAndroid Build Coastguard Worker           ahelper->GetEntryData(entry, &data)) {
588*288bf522SAndroid Build Coastguard Worker         status = ReadSymbolsFromDexFileInMemory(data.data(), data.size(), debug_file_path,
589*288bf522SAndroid Build Coastguard Worker                                                 dex_file_offsets_, symbol_callback);
590*288bf522SAndroid Build Coastguard Worker       }
591*288bf522SAndroid Build Coastguard Worker     } else {
592*288bf522SAndroid Build Coastguard Worker       status = ReadSymbolsFromDexFile(debug_file_path, dex_file_offsets_, symbol_callback);
593*288bf522SAndroid Build Coastguard Worker     }
594*288bf522SAndroid Build Coastguard Worker     if (!status) {
595*288bf522SAndroid Build Coastguard Worker       android::base::LogSeverity level =
596*288bf522SAndroid Build Coastguard Worker           symbols_.empty() ? android::base::WARNING : android::base::DEBUG;
597*288bf522SAndroid Build Coastguard Worker       LOG(level) << "Failed to read symbols from dex_file " << debug_file_path;
598*288bf522SAndroid Build Coastguard Worker       return symbols;
599*288bf522SAndroid Build Coastguard Worker     }
600*288bf522SAndroid Build Coastguard Worker     LOG(VERBOSE) << "Read symbols from dex_file " << debug_file_path << " successfully";
601*288bf522SAndroid Build Coastguard Worker     SortAndFixSymbols(symbols);
602*288bf522SAndroid Build Coastguard Worker     return symbols;
603*288bf522SAndroid Build Coastguard Worker   }
604*288bf522SAndroid Build Coastguard Worker 
605*288bf522SAndroid Build Coastguard Worker  private:
606*288bf522SAndroid Build Coastguard Worker   std::vector<uint64_t> dex_file_offsets_;
607*288bf522SAndroid Build Coastguard Worker };
608*288bf522SAndroid Build Coastguard Worker 
609*288bf522SAndroid Build Coastguard Worker class ElfDso : public Dso {
610*288bf522SAndroid Build Coastguard Worker  public:
ElfDso(const std::string & path,bool force_64bit)611*288bf522SAndroid Build Coastguard Worker   ElfDso(const std::string& path, bool force_64bit)
612*288bf522SAndroid Build Coastguard Worker       : Dso(DSO_ELF_FILE, path), force_64bit_(force_64bit) {}
613*288bf522SAndroid Build Coastguard Worker 
GetReportPath() const614*288bf522SAndroid Build Coastguard Worker   std::string_view GetReportPath() const override {
615*288bf522SAndroid Build Coastguard Worker     if (JITDebugReader::IsPathInJITSymFile(path_)) {
616*288bf522SAndroid Build Coastguard Worker       if (path_.find(kJITAppCacheFile) != path_.npos) {
617*288bf522SAndroid Build Coastguard Worker         return "[JIT app cache]";
618*288bf522SAndroid Build Coastguard Worker       }
619*288bf522SAndroid Build Coastguard Worker       return "[JIT zygote cache]";
620*288bf522SAndroid Build Coastguard Worker     }
621*288bf522SAndroid Build Coastguard Worker     return path_;
622*288bf522SAndroid Build Coastguard Worker   }
623*288bf522SAndroid Build Coastguard Worker 
SetMinExecutableVaddr(uint64_t min_vaddr,uint64_t file_offset)624*288bf522SAndroid Build Coastguard Worker   void SetMinExecutableVaddr(uint64_t min_vaddr, uint64_t file_offset) override {
625*288bf522SAndroid Build Coastguard Worker     min_vaddr_ = min_vaddr;
626*288bf522SAndroid Build Coastguard Worker     file_offset_of_min_vaddr_ = file_offset;
627*288bf522SAndroid Build Coastguard Worker   }
628*288bf522SAndroid Build Coastguard Worker 
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * file_offset)629*288bf522SAndroid Build Coastguard Worker   void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) override {
630*288bf522SAndroid Build Coastguard Worker     if (type_ == DSO_DEX_FILE) {
631*288bf522SAndroid Build Coastguard Worker       return dex_file_dso_->GetMinExecutableVaddr(min_vaddr, file_offset);
632*288bf522SAndroid Build Coastguard Worker     }
633*288bf522SAndroid Build Coastguard Worker     if (min_vaddr_ == uninitialized_value) {
634*288bf522SAndroid Build Coastguard Worker       min_vaddr_ = 0;
635*288bf522SAndroid Build Coastguard Worker       BuildId build_id = GetExpectedBuildId();
636*288bf522SAndroid Build Coastguard Worker 
637*288bf522SAndroid Build Coastguard Worker       ElfStatus status;
638*288bf522SAndroid Build Coastguard Worker       auto elf = ElfFile::Open(GetDebugFilePath(), &build_id, &status);
639*288bf522SAndroid Build Coastguard Worker       if (elf) {
640*288bf522SAndroid Build Coastguard Worker         min_vaddr_ = elf->ReadMinExecutableVaddr(&file_offset_of_min_vaddr_);
641*288bf522SAndroid Build Coastguard Worker       } else {
642*288bf522SAndroid Build Coastguard Worker         // This is likely to be a file wrongly thought of as an ELF file, due to stack unwinding.
643*288bf522SAndroid Build Coastguard Worker         // No need to report it by default.
644*288bf522SAndroid Build Coastguard Worker         LOG(DEBUG) << "failed to read min virtual address of " << GetDebugFilePath() << ": "
645*288bf522SAndroid Build Coastguard Worker                    << status;
646*288bf522SAndroid Build Coastguard Worker       }
647*288bf522SAndroid Build Coastguard Worker     }
648*288bf522SAndroid Build Coastguard Worker     *min_vaddr = min_vaddr_;
649*288bf522SAndroid Build Coastguard Worker     *file_offset = file_offset_of_min_vaddr_;
650*288bf522SAndroid Build Coastguard Worker   }
651*288bf522SAndroid Build Coastguard Worker 
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t map_pgoff)652*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) override {
653*288bf522SAndroid Build Coastguard Worker     if (type_ == DSO_DEX_FILE) {
654*288bf522SAndroid Build Coastguard Worker       return dex_file_dso_->IpToVaddrInFile(ip, map_start, map_pgoff);
655*288bf522SAndroid Build Coastguard Worker     }
656*288bf522SAndroid Build Coastguard Worker     uint64_t min_vaddr;
657*288bf522SAndroid Build Coastguard Worker     uint64_t file_offset_of_min_vaddr;
658*288bf522SAndroid Build Coastguard Worker     GetMinExecutableVaddr(&min_vaddr, &file_offset_of_min_vaddr);
659*288bf522SAndroid Build Coastguard Worker     if (file_offset_of_min_vaddr == uninitialized_value) {
660*288bf522SAndroid Build Coastguard Worker       return ip - map_start + min_vaddr;
661*288bf522SAndroid Build Coastguard Worker     }
662*288bf522SAndroid Build Coastguard Worker     // Apps may make part of the executable segment of a shared library writeable, which can
663*288bf522SAndroid Build Coastguard Worker     // generate multiple executable segments at runtime. So use map_pgoff to calculate
664*288bf522SAndroid Build Coastguard Worker     // vaddr_in_file.
665*288bf522SAndroid Build Coastguard Worker     return ip - map_start + map_pgoff - file_offset_of_min_vaddr + min_vaddr;
666*288bf522SAndroid Build Coastguard Worker   }
667*288bf522SAndroid Build Coastguard Worker 
AddDexFileOffset(uint64_t dex_file_offset)668*288bf522SAndroid Build Coastguard Worker   void AddDexFileOffset(uint64_t dex_file_offset) override {
669*288bf522SAndroid Build Coastguard Worker     if (type_ == DSO_ELF_FILE) {
670*288bf522SAndroid Build Coastguard Worker       // When simpleperf does unwinding while recording, it processes mmap records before reading
671*288bf522SAndroid Build Coastguard Worker       // dex file linked list (via JITDebugReader). To process mmap records, it creates Dso
672*288bf522SAndroid Build Coastguard Worker       // objects of type ELF_FILE. Then after reading dex file linked list, it realizes some
673*288bf522SAndroid Build Coastguard Worker       // ELF_FILE Dso objects should actually be DEX_FILE, because they have dex file offsets.
674*288bf522SAndroid Build Coastguard Worker       // So here converts ELF_FILE Dso into DEX_FILE Dso.
675*288bf522SAndroid Build Coastguard Worker       type_ = DSO_DEX_FILE;
676*288bf522SAndroid Build Coastguard Worker       dex_file_dso_.reset(new DexFileDso(path_));
677*288bf522SAndroid Build Coastguard Worker     }
678*288bf522SAndroid Build Coastguard Worker     dex_file_dso_->AddDexFileOffset(dex_file_offset);
679*288bf522SAndroid Build Coastguard Worker   }
680*288bf522SAndroid Build Coastguard Worker 
DexFileOffsets()681*288bf522SAndroid Build Coastguard Worker   const std::vector<uint64_t>* DexFileOffsets() override {
682*288bf522SAndroid Build Coastguard Worker     return dex_file_dso_ ? dex_file_dso_->DexFileOffsets() : nullptr;
683*288bf522SAndroid Build Coastguard Worker   }
684*288bf522SAndroid Build Coastguard Worker 
685*288bf522SAndroid Build Coastguard Worker  protected:
FindDebugFilePath() const686*288bf522SAndroid Build Coastguard Worker   std::string FindDebugFilePath() const override {
687*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
688*288bf522SAndroid Build Coastguard Worker     return debug_elf_file_finder_.FindDebugFile(path_, force_64bit_, build_id);
689*288bf522SAndroid Build Coastguard Worker   }
690*288bf522SAndroid Build Coastguard Worker 
LoadSymbolsImpl()691*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override {
692*288bf522SAndroid Build Coastguard Worker     if (dex_file_dso_) {
693*288bf522SAndroid Build Coastguard Worker       return dex_file_dso_->LoadSymbolsImpl();
694*288bf522SAndroid Build Coastguard Worker     }
695*288bf522SAndroid Build Coastguard Worker     std::vector<Symbol> symbols;
696*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
697*288bf522SAndroid Build Coastguard Worker     auto symbol_callback = [&](const ElfFileSymbol& symbol) {
698*288bf522SAndroid Build Coastguard Worker       if (symbol.is_func || (symbol.is_label && symbol.is_in_text_section)) {
699*288bf522SAndroid Build Coastguard Worker         symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len);
700*288bf522SAndroid Build Coastguard Worker       }
701*288bf522SAndroid Build Coastguard Worker     };
702*288bf522SAndroid Build Coastguard Worker     ElfStatus status;
703*288bf522SAndroid Build Coastguard Worker     auto elf = ElfFile::Open(GetDebugFilePath(), &build_id, &status);
704*288bf522SAndroid Build Coastguard Worker     if (elf) {
705*288bf522SAndroid Build Coastguard Worker       status = elf->ParseSymbols(symbol_callback);
706*288bf522SAndroid Build Coastguard Worker     }
707*288bf522SAndroid Build Coastguard Worker     android::base::LogSeverity log_level = android::base::WARNING;
708*288bf522SAndroid Build Coastguard Worker     if (!symbols_.empty() || !symbols.empty()) {
709*288bf522SAndroid Build Coastguard Worker       // We already have some symbols when recording.
710*288bf522SAndroid Build Coastguard Worker       log_level = android::base::DEBUG;
711*288bf522SAndroid Build Coastguard Worker     }
712*288bf522SAndroid Build Coastguard Worker     if ((status == ElfStatus::FILE_NOT_FOUND || status == ElfStatus::FILE_MALFORMED) &&
713*288bf522SAndroid Build Coastguard Worker         build_id.IsEmpty()) {
714*288bf522SAndroid Build Coastguard Worker       // This is likely to be a file wrongly thought of as an ELF file, due to stack unwinding.
715*288bf522SAndroid Build Coastguard Worker       log_level = android::base::DEBUG;
716*288bf522SAndroid Build Coastguard Worker     }
717*288bf522SAndroid Build Coastguard Worker     ReportReadElfSymbolResult(status, path_, GetDebugFilePath(), log_level);
718*288bf522SAndroid Build Coastguard Worker     SortAndFixSymbols(symbols);
719*288bf522SAndroid Build Coastguard Worker     return symbols;
720*288bf522SAndroid Build Coastguard Worker   }
721*288bf522SAndroid Build Coastguard Worker 
722*288bf522SAndroid Build Coastguard Worker  private:
723*288bf522SAndroid Build Coastguard Worker   static constexpr uint64_t uninitialized_value = std::numeric_limits<uint64_t>::max();
724*288bf522SAndroid Build Coastguard Worker 
725*288bf522SAndroid Build Coastguard Worker   bool force_64bit_;
726*288bf522SAndroid Build Coastguard Worker   uint64_t min_vaddr_ = uninitialized_value;
727*288bf522SAndroid Build Coastguard Worker   uint64_t file_offset_of_min_vaddr_ = uninitialized_value;
728*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<DexFileDso> dex_file_dso_;
729*288bf522SAndroid Build Coastguard Worker };
730*288bf522SAndroid Build Coastguard Worker 
731*288bf522SAndroid Build Coastguard Worker class KernelDso : public Dso {
732*288bf522SAndroid Build Coastguard Worker  public:
KernelDso(const std::string & path)733*288bf522SAndroid Build Coastguard Worker   KernelDso(const std::string& path) : Dso(DSO_KERNEL, path) {}
734*288bf522SAndroid Build Coastguard Worker 
735*288bf522SAndroid Build Coastguard Worker   // IpToVaddrInFile() and LoadSymbols() must be consistent in fixing addresses changed by kernel
736*288bf522SAndroid Build Coastguard Worker   // address space layout randomization.
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t)737*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override {
738*288bf522SAndroid Build Coastguard Worker     if (map_start != 0 && GetKernelStartAddr() != 0) {
739*288bf522SAndroid Build Coastguard Worker       // Fix kernel addresses changed by kernel address randomization.
740*288bf522SAndroid Build Coastguard Worker       fix_kernel_address_randomization_ = true;
741*288bf522SAndroid Build Coastguard Worker       return ip - map_start + GetKernelStartAddr();
742*288bf522SAndroid Build Coastguard Worker     }
743*288bf522SAndroid Build Coastguard Worker     return ip;
744*288bf522SAndroid Build Coastguard Worker   }
745*288bf522SAndroid Build Coastguard Worker 
IpToFileOffset(uint64_t ip,uint64_t map_start,uint64_t)746*288bf522SAndroid Build Coastguard Worker   std::optional<uint64_t> IpToFileOffset(uint64_t ip, uint64_t map_start, uint64_t) override {
747*288bf522SAndroid Build Coastguard Worker     if (map_start != 0 && GetKernelStartOffset() != 0) {
748*288bf522SAndroid Build Coastguard Worker       return ip - map_start + GetKernelStartOffset();
749*288bf522SAndroid Build Coastguard Worker     }
750*288bf522SAndroid Build Coastguard Worker     return std::nullopt;
751*288bf522SAndroid Build Coastguard Worker   }
752*288bf522SAndroid Build Coastguard Worker 
753*288bf522SAndroid Build Coastguard Worker  protected:
FindDebugFilePath() const754*288bf522SAndroid Build Coastguard Worker   std::string FindDebugFilePath() const override {
755*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
756*288bf522SAndroid Build Coastguard Worker     if (!vmlinux_.empty()) {
757*288bf522SAndroid Build Coastguard Worker       // Use vmlinux as the kernel debug file.
758*288bf522SAndroid Build Coastguard Worker       ElfStatus status;
759*288bf522SAndroid Build Coastguard Worker       if (ElfFile::Open(vmlinux_, &build_id, &status)) {
760*288bf522SAndroid Build Coastguard Worker         return vmlinux_;
761*288bf522SAndroid Build Coastguard Worker       }
762*288bf522SAndroid Build Coastguard Worker     }
763*288bf522SAndroid Build Coastguard Worker     return debug_elf_file_finder_.FindDebugFile(path_, false, build_id);
764*288bf522SAndroid Build Coastguard Worker   }
765*288bf522SAndroid Build Coastguard Worker 
LoadSymbolsImpl()766*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override {
767*288bf522SAndroid Build Coastguard Worker     std::vector<Symbol> symbols;
768*288bf522SAndroid Build Coastguard Worker     ReadSymbolsFromDebugFile(&symbols);
769*288bf522SAndroid Build Coastguard Worker 
770*288bf522SAndroid Build Coastguard Worker     if (symbols.empty() && !kallsyms_.empty()) {
771*288bf522SAndroid Build Coastguard Worker       ReadSymbolsFromKallsyms(kallsyms_, &symbols);
772*288bf522SAndroid Build Coastguard Worker     }
773*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
774*288bf522SAndroid Build Coastguard Worker     if (symbols.empty()) {
775*288bf522SAndroid Build Coastguard Worker       ReadSymbolsFromProc(&symbols);
776*288bf522SAndroid Build Coastguard Worker     }
777*288bf522SAndroid Build Coastguard Worker #endif  // defined(__linux__)
778*288bf522SAndroid Build Coastguard Worker     SortAndFixSymbols(symbols);
779*288bf522SAndroid Build Coastguard Worker     if (!symbols.empty() && symbols.back().len == 0) {
780*288bf522SAndroid Build Coastguard Worker       symbols.back().len = std::numeric_limits<uint64_t>::max() - symbols.back().addr;
781*288bf522SAndroid Build Coastguard Worker     }
782*288bf522SAndroid Build Coastguard Worker     return symbols;
783*288bf522SAndroid Build Coastguard Worker   }
784*288bf522SAndroid Build Coastguard Worker 
785*288bf522SAndroid Build Coastguard Worker  private:
ReadSymbolsFromDebugFile(std::vector<Symbol> * symbols)786*288bf522SAndroid Build Coastguard Worker   void ReadSymbolsFromDebugFile(std::vector<Symbol>* symbols) {
787*288bf522SAndroid Build Coastguard Worker     ElfStatus status;
788*288bf522SAndroid Build Coastguard Worker     auto elf = ElfFile::Open(GetDebugFilePath(), &status);
789*288bf522SAndroid Build Coastguard Worker     if (!elf) {
790*288bf522SAndroid Build Coastguard Worker       return;
791*288bf522SAndroid Build Coastguard Worker     }
792*288bf522SAndroid Build Coastguard Worker 
793*288bf522SAndroid Build Coastguard Worker     if (!fix_kernel_address_randomization_) {
794*288bf522SAndroid Build Coastguard Worker       LOG(WARNING) << "Don't know how to fix addresses changed by kernel address randomization. So "
795*288bf522SAndroid Build Coastguard Worker                       "symbols in "
796*288bf522SAndroid Build Coastguard Worker                    << GetDebugFilePath() << " are not used";
797*288bf522SAndroid Build Coastguard Worker       return;
798*288bf522SAndroid Build Coastguard Worker     }
799*288bf522SAndroid Build Coastguard Worker     // symbols_ are kernel symbols got from /proc/kallsyms while recording. Those symbols are
800*288bf522SAndroid Build Coastguard Worker     // not fixed for kernel address randomization. So clear them to avoid mixing them with
801*288bf522SAndroid Build Coastguard Worker     // symbols in debug_file_path.
802*288bf522SAndroid Build Coastguard Worker     symbols_.clear();
803*288bf522SAndroid Build Coastguard Worker 
804*288bf522SAndroid Build Coastguard Worker     auto symbol_callback = [&](const ElfFileSymbol& symbol) {
805*288bf522SAndroid Build Coastguard Worker       if (symbol.is_func) {
806*288bf522SAndroid Build Coastguard Worker         symbols->emplace_back(symbol.name, symbol.vaddr, symbol.len);
807*288bf522SAndroid Build Coastguard Worker       }
808*288bf522SAndroid Build Coastguard Worker     };
809*288bf522SAndroid Build Coastguard Worker     status = elf->ParseSymbols(symbol_callback);
810*288bf522SAndroid Build Coastguard Worker     ReportReadElfSymbolResult(status, path_, GetDebugFilePath());
811*288bf522SAndroid Build Coastguard Worker   }
812*288bf522SAndroid Build Coastguard Worker 
ReadSymbolsFromKallsyms(std::string & kallsyms,std::vector<Symbol> * symbols)813*288bf522SAndroid Build Coastguard Worker   void ReadSymbolsFromKallsyms(std::string& kallsyms, std::vector<Symbol>* symbols) {
814*288bf522SAndroid Build Coastguard Worker     auto symbol_callback = [&](const KernelSymbol& symbol) {
815*288bf522SAndroid Build Coastguard Worker       if (strchr("TtWw", symbol.type) && symbol.addr != 0u) {
816*288bf522SAndroid Build Coastguard Worker         if (symbol.module == nullptr) {
817*288bf522SAndroid Build Coastguard Worker           symbols->emplace_back(symbol.name, symbol.addr, 0);
818*288bf522SAndroid Build Coastguard Worker         } else {
819*288bf522SAndroid Build Coastguard Worker           std::string name = std::string(symbol.name) + " [" + symbol.module + "]";
820*288bf522SAndroid Build Coastguard Worker           symbols->emplace_back(name, symbol.addr, 0);
821*288bf522SAndroid Build Coastguard Worker         }
822*288bf522SAndroid Build Coastguard Worker       }
823*288bf522SAndroid Build Coastguard Worker       return false;
824*288bf522SAndroid Build Coastguard Worker     };
825*288bf522SAndroid Build Coastguard Worker     ProcessKernelSymbols(kallsyms, symbol_callback);
826*288bf522SAndroid Build Coastguard Worker     if (symbols->empty()) {
827*288bf522SAndroid Build Coastguard Worker       LOG(WARNING) << "Symbol addresses in /proc/kallsyms on device are all zero. "
828*288bf522SAndroid Build Coastguard Worker                       "`echo 0 >/proc/sys/kernel/kptr_restrict` if possible.";
829*288bf522SAndroid Build Coastguard Worker     }
830*288bf522SAndroid Build Coastguard Worker   }
831*288bf522SAndroid Build Coastguard Worker 
832*288bf522SAndroid Build Coastguard Worker #if defined(__linux__)
ReadSymbolsFromProc(std::vector<Symbol> * symbols)833*288bf522SAndroid Build Coastguard Worker   void ReadSymbolsFromProc(std::vector<Symbol>* symbols) {
834*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
835*288bf522SAndroid Build Coastguard Worker     if (!build_id.IsEmpty()) {
836*288bf522SAndroid Build Coastguard Worker       // Try /proc/kallsyms only when asked to do so, or when build id matches.
837*288bf522SAndroid Build Coastguard Worker       // Otherwise, it is likely to use /proc/kallsyms on host for perf.data recorded on device.
838*288bf522SAndroid Build Coastguard Worker       bool can_read_kallsyms = true;
839*288bf522SAndroid Build Coastguard Worker       if (!build_id.IsEmpty()) {
840*288bf522SAndroid Build Coastguard Worker         BuildId real_build_id;
841*288bf522SAndroid Build Coastguard Worker         if (!GetKernelBuildId(&real_build_id) || build_id != real_build_id) {
842*288bf522SAndroid Build Coastguard Worker           LOG(DEBUG) << "failed to read symbols from /proc/kallsyms: Build id mismatch";
843*288bf522SAndroid Build Coastguard Worker           can_read_kallsyms = false;
844*288bf522SAndroid Build Coastguard Worker         }
845*288bf522SAndroid Build Coastguard Worker       }
846*288bf522SAndroid Build Coastguard Worker       if (can_read_kallsyms) {
847*288bf522SAndroid Build Coastguard Worker         std::string kallsyms;
848*288bf522SAndroid Build Coastguard Worker         if (LoadKernelSymbols(&kallsyms)) {
849*288bf522SAndroid Build Coastguard Worker           ReadSymbolsFromKallsyms(kallsyms, symbols);
850*288bf522SAndroid Build Coastguard Worker         }
851*288bf522SAndroid Build Coastguard Worker       }
852*288bf522SAndroid Build Coastguard Worker     }
853*288bf522SAndroid Build Coastguard Worker   }
854*288bf522SAndroid Build Coastguard Worker #endif  // defined(__linux__)
855*288bf522SAndroid Build Coastguard Worker 
GetKernelStartAddr()856*288bf522SAndroid Build Coastguard Worker   uint64_t GetKernelStartAddr() {
857*288bf522SAndroid Build Coastguard Worker     if (!kernel_start_addr_) {
858*288bf522SAndroid Build Coastguard Worker       ParseKernelStartAddr();
859*288bf522SAndroid Build Coastguard Worker     }
860*288bf522SAndroid Build Coastguard Worker     return kernel_start_addr_.value();
861*288bf522SAndroid Build Coastguard Worker   }
862*288bf522SAndroid Build Coastguard Worker 
GetKernelStartOffset()863*288bf522SAndroid Build Coastguard Worker   uint64_t GetKernelStartOffset() {
864*288bf522SAndroid Build Coastguard Worker     if (!kernel_start_file_offset_) {
865*288bf522SAndroid Build Coastguard Worker       ParseKernelStartAddr();
866*288bf522SAndroid Build Coastguard Worker     }
867*288bf522SAndroid Build Coastguard Worker     return kernel_start_file_offset_.value();
868*288bf522SAndroid Build Coastguard Worker   }
869*288bf522SAndroid Build Coastguard Worker 
ParseKernelStartAddr()870*288bf522SAndroid Build Coastguard Worker   void ParseKernelStartAddr() {
871*288bf522SAndroid Build Coastguard Worker     kernel_start_addr_ = 0;
872*288bf522SAndroid Build Coastguard Worker     kernel_start_file_offset_ = 0;
873*288bf522SAndroid Build Coastguard Worker     ElfStatus status;
874*288bf522SAndroid Build Coastguard Worker     if (auto elf = ElfFile::Open(GetDebugFilePath(), &status); elf) {
875*288bf522SAndroid Build Coastguard Worker       for (const auto& section : elf->GetSectionHeader()) {
876*288bf522SAndroid Build Coastguard Worker         if (section.name == ".text") {
877*288bf522SAndroid Build Coastguard Worker           kernel_start_addr_ = section.vaddr;
878*288bf522SAndroid Build Coastguard Worker           kernel_start_file_offset_ = section.file_offset;
879*288bf522SAndroid Build Coastguard Worker           break;
880*288bf522SAndroid Build Coastguard Worker         }
881*288bf522SAndroid Build Coastguard Worker       }
882*288bf522SAndroid Build Coastguard Worker     }
883*288bf522SAndroid Build Coastguard Worker   }
884*288bf522SAndroid Build Coastguard Worker 
885*288bf522SAndroid Build Coastguard Worker   bool fix_kernel_address_randomization_ = false;
886*288bf522SAndroid Build Coastguard Worker   std::optional<uint64_t> kernel_start_addr_;
887*288bf522SAndroid Build Coastguard Worker   std::optional<uint64_t> kernel_start_file_offset_;
888*288bf522SAndroid Build Coastguard Worker };
889*288bf522SAndroid Build Coastguard Worker 
890*288bf522SAndroid Build Coastguard Worker class KernelModuleDso : public Dso {
891*288bf522SAndroid Build Coastguard Worker  public:
KernelModuleDso(const std::string & path,uint64_t memory_start,uint64_t memory_end,Dso * kernel_dso)892*288bf522SAndroid Build Coastguard Worker   KernelModuleDso(const std::string& path, uint64_t memory_start, uint64_t memory_end,
893*288bf522SAndroid Build Coastguard Worker                   Dso* kernel_dso)
894*288bf522SAndroid Build Coastguard Worker       : Dso(DSO_KERNEL_MODULE, path),
895*288bf522SAndroid Build Coastguard Worker         memory_start_(memory_start),
896*288bf522SAndroid Build Coastguard Worker         memory_end_(memory_end),
897*288bf522SAndroid Build Coastguard Worker         kernel_dso_(kernel_dso) {}
898*288bf522SAndroid Build Coastguard Worker 
SetMinExecutableVaddr(uint64_t min_vaddr,uint64_t memory_offset)899*288bf522SAndroid Build Coastguard Worker   void SetMinExecutableVaddr(uint64_t min_vaddr, uint64_t memory_offset) override {
900*288bf522SAndroid Build Coastguard Worker     min_vaddr_ = min_vaddr;
901*288bf522SAndroid Build Coastguard Worker     memory_offset_of_min_vaddr_ = memory_offset;
902*288bf522SAndroid Build Coastguard Worker   }
903*288bf522SAndroid Build Coastguard Worker 
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * memory_offset)904*288bf522SAndroid Build Coastguard Worker   void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* memory_offset) override {
905*288bf522SAndroid Build Coastguard Worker     if (!min_vaddr_) {
906*288bf522SAndroid Build Coastguard Worker       CalculateMinVaddr();
907*288bf522SAndroid Build Coastguard Worker     }
908*288bf522SAndroid Build Coastguard Worker     *min_vaddr = min_vaddr_.value();
909*288bf522SAndroid Build Coastguard Worker     *memory_offset = memory_offset_of_min_vaddr_.value();
910*288bf522SAndroid Build Coastguard Worker   }
911*288bf522SAndroid Build Coastguard Worker 
IpToVaddrInFile(uint64_t ip,uint64_t map_start,uint64_t)912*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t) override {
913*288bf522SAndroid Build Coastguard Worker     uint64_t min_vaddr;
914*288bf522SAndroid Build Coastguard Worker     uint64_t memory_offset;
915*288bf522SAndroid Build Coastguard Worker     GetMinExecutableVaddr(&min_vaddr, &memory_offset);
916*288bf522SAndroid Build Coastguard Worker     return ip - map_start - memory_offset + min_vaddr;
917*288bf522SAndroid Build Coastguard Worker   }
918*288bf522SAndroid Build Coastguard Worker 
919*288bf522SAndroid Build Coastguard Worker  protected:
FindDebugFilePath() const920*288bf522SAndroid Build Coastguard Worker   std::string FindDebugFilePath() const override {
921*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
922*288bf522SAndroid Build Coastguard Worker     return debug_elf_file_finder_.FindDebugFile(path_, false, build_id);
923*288bf522SAndroid Build Coastguard Worker   }
924*288bf522SAndroid Build Coastguard Worker 
LoadSymbolsImpl()925*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override {
926*288bf522SAndroid Build Coastguard Worker     std::vector<Symbol> symbols;
927*288bf522SAndroid Build Coastguard Worker     BuildId build_id = GetExpectedBuildId();
928*288bf522SAndroid Build Coastguard Worker     auto symbol_callback = [&](const ElfFileSymbol& symbol) {
929*288bf522SAndroid Build Coastguard Worker       // We only know how to map ip addrs to symbols in text section.
930*288bf522SAndroid Build Coastguard Worker       if (symbol.is_in_text_section && (symbol.is_label || symbol.is_func)) {
931*288bf522SAndroid Build Coastguard Worker         symbols.emplace_back(symbol.name, symbol.vaddr, symbol.len);
932*288bf522SAndroid Build Coastguard Worker       }
933*288bf522SAndroid Build Coastguard Worker     };
934*288bf522SAndroid Build Coastguard Worker     ElfStatus status;
935*288bf522SAndroid Build Coastguard Worker     auto elf = ElfFile::Open(GetDebugFilePath(), &build_id, &status);
936*288bf522SAndroid Build Coastguard Worker     if (elf) {
937*288bf522SAndroid Build Coastguard Worker       status = elf->ParseSymbols(symbol_callback);
938*288bf522SAndroid Build Coastguard Worker     }
939*288bf522SAndroid Build Coastguard Worker     // Don't warn when a kernel module is missing. As a backup, we read symbols from /proc/kallsyms.
940*288bf522SAndroid Build Coastguard Worker     ReportReadElfSymbolResult(status, path_, GetDebugFilePath(), android::base::DEBUG);
941*288bf522SAndroid Build Coastguard Worker     SortAndFixSymbols(symbols);
942*288bf522SAndroid Build Coastguard Worker     return symbols;
943*288bf522SAndroid Build Coastguard Worker   }
944*288bf522SAndroid Build Coastguard Worker 
945*288bf522SAndroid Build Coastguard Worker  private:
CalculateMinVaddr()946*288bf522SAndroid Build Coastguard Worker   void CalculateMinVaddr() {
947*288bf522SAndroid Build Coastguard Worker     min_vaddr_ = 0;
948*288bf522SAndroid Build Coastguard Worker     memory_offset_of_min_vaddr_ = 0;
949*288bf522SAndroid Build Coastguard Worker 
950*288bf522SAndroid Build Coastguard Worker     // min_vaddr and memory_offset are used to convert an ip addr of a kernel module to its
951*288bf522SAndroid Build Coastguard Worker     // vaddr_in_file, as shown in IpToVaddrInFile(). When the kernel loads a kernel module, it
952*288bf522SAndroid Build Coastguard Worker     // puts ALLOC sections (like .plt, .text.ftrace_trampoline, .text) in memory in order. The
953*288bf522SAndroid Build Coastguard Worker     // text section may not be at the start of the module memory. To do address conversion, we
954*288bf522SAndroid Build Coastguard Worker     // need to know its relative position in the module memory. There are two ways:
955*288bf522SAndroid Build Coastguard Worker     // 1. Read the kernel module file to calculate the relative position of .text section. It
956*288bf522SAndroid Build Coastguard Worker     // is relatively complex and depends on both PLT entries and the kernel version.
957*288bf522SAndroid Build Coastguard Worker     // 2. Find a module symbol in .text section, get its address in memory from /proc/kallsyms,
958*288bf522SAndroid Build Coastguard Worker     // and its vaddr_in_file from the kernel module file. Then other symbols in .text section can
959*288bf522SAndroid Build Coastguard Worker     // be mapped in the same way. Below we use the second method.
960*288bf522SAndroid Build Coastguard Worker 
961*288bf522SAndroid Build Coastguard Worker     if (!IsRegularFile(GetDebugFilePath())) {
962*288bf522SAndroid Build Coastguard Worker       return;
963*288bf522SAndroid Build Coastguard Worker     }
964*288bf522SAndroid Build Coastguard Worker 
965*288bf522SAndroid Build Coastguard Worker     // 1. Select a module symbol in /proc/kallsyms.
966*288bf522SAndroid Build Coastguard Worker     kernel_dso_->LoadSymbols();
967*288bf522SAndroid Build Coastguard Worker     const auto& kernel_symbols = kernel_dso_->GetSymbols();
968*288bf522SAndroid Build Coastguard Worker     auto it = std::lower_bound(kernel_symbols.begin(), kernel_symbols.end(), memory_start_,
969*288bf522SAndroid Build Coastguard Worker                                CompareSymbolToAddr);
970*288bf522SAndroid Build Coastguard Worker     const Symbol* kernel_symbol = nullptr;
971*288bf522SAndroid Build Coastguard Worker     while (it != kernel_symbols.end() && it->addr < memory_end_) {
972*288bf522SAndroid Build Coastguard Worker       if (strlen(it->Name()) > 0 && it->Name()[0] != '$') {
973*288bf522SAndroid Build Coastguard Worker         kernel_symbol = &*it;
974*288bf522SAndroid Build Coastguard Worker         break;
975*288bf522SAndroid Build Coastguard Worker       }
976*288bf522SAndroid Build Coastguard Worker       ++it;
977*288bf522SAndroid Build Coastguard Worker     }
978*288bf522SAndroid Build Coastguard Worker     if (kernel_symbol == nullptr) {
979*288bf522SAndroid Build Coastguard Worker       return;
980*288bf522SAndroid Build Coastguard Worker     }
981*288bf522SAndroid Build Coastguard Worker 
982*288bf522SAndroid Build Coastguard Worker     // 2. Find the symbol in .ko file.
983*288bf522SAndroid Build Coastguard Worker     std::string symbol_name = kernel_symbol->Name();
984*288bf522SAndroid Build Coastguard Worker     if (auto pos = symbol_name.rfind(' '); pos != std::string::npos) {
985*288bf522SAndroid Build Coastguard Worker       symbol_name.resize(pos);
986*288bf522SAndroid Build Coastguard Worker     }
987*288bf522SAndroid Build Coastguard Worker     LoadSymbols();
988*288bf522SAndroid Build Coastguard Worker     for (const auto& symbol : symbols_) {
989*288bf522SAndroid Build Coastguard Worker       if (symbol_name == symbol.Name()) {
990*288bf522SAndroid Build Coastguard Worker         min_vaddr_ = symbol.addr;
991*288bf522SAndroid Build Coastguard Worker         memory_offset_of_min_vaddr_ = kernel_symbol->addr - memory_start_;
992*288bf522SAndroid Build Coastguard Worker         return;
993*288bf522SAndroid Build Coastguard Worker       }
994*288bf522SAndroid Build Coastguard Worker     }
995*288bf522SAndroid Build Coastguard Worker   }
996*288bf522SAndroid Build Coastguard Worker 
997*288bf522SAndroid Build Coastguard Worker   uint64_t memory_start_;
998*288bf522SAndroid Build Coastguard Worker   uint64_t memory_end_;
999*288bf522SAndroid Build Coastguard Worker   Dso* kernel_dso_;
1000*288bf522SAndroid Build Coastguard Worker   std::optional<uint64_t> min_vaddr_;
1001*288bf522SAndroid Build Coastguard Worker   std::optional<uint64_t> memory_offset_of_min_vaddr_;
1002*288bf522SAndroid Build Coastguard Worker };
1003*288bf522SAndroid Build Coastguard Worker 
1004*288bf522SAndroid Build Coastguard Worker class SymbolMapFileDso : public Dso {
1005*288bf522SAndroid Build Coastguard Worker  public:
SymbolMapFileDso(const std::string & path)1006*288bf522SAndroid Build Coastguard Worker   SymbolMapFileDso(const std::string& path) : Dso(DSO_SYMBOL_MAP_FILE, path) {}
1007*288bf522SAndroid Build Coastguard Worker 
IpToVaddrInFile(uint64_t ip,uint64_t,uint64_t)1008*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { return ip; }
1009*288bf522SAndroid Build Coastguard Worker 
1010*288bf522SAndroid Build Coastguard Worker  protected:
LoadSymbolsImpl()1011*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override { return {}; }
1012*288bf522SAndroid Build Coastguard Worker };
1013*288bf522SAndroid Build Coastguard Worker 
1014*288bf522SAndroid Build Coastguard Worker class UnknownDso : public Dso {
1015*288bf522SAndroid Build Coastguard Worker  public:
UnknownDso(const std::string & path)1016*288bf522SAndroid Build Coastguard Worker   UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path) {}
1017*288bf522SAndroid Build Coastguard Worker 
IpToVaddrInFile(uint64_t ip,uint64_t,uint64_t)1018*288bf522SAndroid Build Coastguard Worker   uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { return ip; }
1019*288bf522SAndroid Build Coastguard Worker 
1020*288bf522SAndroid Build Coastguard Worker  protected:
LoadSymbolsImpl()1021*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> LoadSymbolsImpl() override { return std::vector<Symbol>(); }
1022*288bf522SAndroid Build Coastguard Worker };
1023*288bf522SAndroid Build Coastguard Worker 
CreateDso(DsoType dso_type,const std::string & dso_path,bool force_64bit)1024*288bf522SAndroid Build Coastguard Worker std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path,
1025*288bf522SAndroid Build Coastguard Worker                                     bool force_64bit) {
1026*288bf522SAndroid Build Coastguard Worker   switch (dso_type) {
1027*288bf522SAndroid Build Coastguard Worker     case DSO_ELF_FILE:
1028*288bf522SAndroid Build Coastguard Worker       return std::unique_ptr<Dso>(new ElfDso(dso_path, force_64bit));
1029*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL:
1030*288bf522SAndroid Build Coastguard Worker       return std::unique_ptr<Dso>(new KernelDso(dso_path));
1031*288bf522SAndroid Build Coastguard Worker     case DSO_DEX_FILE:
1032*288bf522SAndroid Build Coastguard Worker       return std::unique_ptr<Dso>(new DexFileDso(dso_path));
1033*288bf522SAndroid Build Coastguard Worker     case DSO_SYMBOL_MAP_FILE:
1034*288bf522SAndroid Build Coastguard Worker       return std::unique_ptr<Dso>(new SymbolMapFileDso(dso_path));
1035*288bf522SAndroid Build Coastguard Worker     case DSO_UNKNOWN_FILE:
1036*288bf522SAndroid Build Coastguard Worker       return std::unique_ptr<Dso>(new UnknownDso(dso_path));
1037*288bf522SAndroid Build Coastguard Worker     default:
1038*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "Unexpected dso_type " << static_cast<int>(dso_type);
1039*288bf522SAndroid Build Coastguard Worker       return nullptr;
1040*288bf522SAndroid Build Coastguard Worker   }
1041*288bf522SAndroid Build Coastguard Worker }
1042*288bf522SAndroid Build Coastguard Worker 
CreateDsoWithBuildId(DsoType dso_type,const std::string & dso_path,BuildId & build_id)1043*288bf522SAndroid Build Coastguard Worker std::unique_ptr<Dso> Dso::CreateDsoWithBuildId(DsoType dso_type, const std::string& dso_path,
1044*288bf522SAndroid Build Coastguard Worker                                                BuildId& build_id) {
1045*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<Dso> dso;
1046*288bf522SAndroid Build Coastguard Worker   switch (dso_type) {
1047*288bf522SAndroid Build Coastguard Worker     case DSO_ELF_FILE:
1048*288bf522SAndroid Build Coastguard Worker       dso.reset(new ElfDso(dso_path, false));
1049*288bf522SAndroid Build Coastguard Worker       break;
1050*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL:
1051*288bf522SAndroid Build Coastguard Worker       dso.reset(new KernelDso(dso_path));
1052*288bf522SAndroid Build Coastguard Worker       break;
1053*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL_MODULE:
1054*288bf522SAndroid Build Coastguard Worker       dso.reset(new KernelModuleDso(dso_path, 0, 0, nullptr));
1055*288bf522SAndroid Build Coastguard Worker       break;
1056*288bf522SAndroid Build Coastguard Worker     default:
1057*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "Unexpected dso_type " << static_cast<int>(dso_type);
1058*288bf522SAndroid Build Coastguard Worker       return nullptr;
1059*288bf522SAndroid Build Coastguard Worker   }
1060*288bf522SAndroid Build Coastguard Worker   dso->debug_file_path_ = debug_elf_file_finder_.FindDebugFile(dso_path, false, build_id);
1061*288bf522SAndroid Build Coastguard Worker   return dso;
1062*288bf522SAndroid Build Coastguard Worker }
1063*288bf522SAndroid Build Coastguard Worker 
CreateKernelModuleDso(const std::string & dso_path,uint64_t memory_start,uint64_t memory_end,Dso * kernel_dso)1064*288bf522SAndroid Build Coastguard Worker std::unique_ptr<Dso> Dso::CreateKernelModuleDso(const std::string& dso_path, uint64_t memory_start,
1065*288bf522SAndroid Build Coastguard Worker                                                 uint64_t memory_end, Dso* kernel_dso) {
1066*288bf522SAndroid Build Coastguard Worker   return std::unique_ptr<Dso>(new KernelModuleDso(dso_path, memory_start, memory_end, kernel_dso));
1067*288bf522SAndroid Build Coastguard Worker }
1068*288bf522SAndroid Build Coastguard Worker 
DsoTypeToString(DsoType dso_type)1069*288bf522SAndroid Build Coastguard Worker const char* DsoTypeToString(DsoType dso_type) {
1070*288bf522SAndroid Build Coastguard Worker   switch (dso_type) {
1071*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL:
1072*288bf522SAndroid Build Coastguard Worker       return "dso_kernel";
1073*288bf522SAndroid Build Coastguard Worker     case DSO_KERNEL_MODULE:
1074*288bf522SAndroid Build Coastguard Worker       return "dso_kernel_module";
1075*288bf522SAndroid Build Coastguard Worker     case DSO_ELF_FILE:
1076*288bf522SAndroid Build Coastguard Worker       return "dso_elf_file";
1077*288bf522SAndroid Build Coastguard Worker     case DSO_DEX_FILE:
1078*288bf522SAndroid Build Coastguard Worker       return "dso_dex_file";
1079*288bf522SAndroid Build Coastguard Worker     case DSO_SYMBOL_MAP_FILE:
1080*288bf522SAndroid Build Coastguard Worker       return "dso_symbol_map_file";
1081*288bf522SAndroid Build Coastguard Worker     default:
1082*288bf522SAndroid Build Coastguard Worker       return "unknown";
1083*288bf522SAndroid Build Coastguard Worker   }
1084*288bf522SAndroid Build Coastguard Worker }
1085*288bf522SAndroid Build Coastguard Worker 
GetBuildIdFromDsoPath(const std::string & dso_path,BuildId * build_id)1086*288bf522SAndroid Build Coastguard Worker bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id) {
1087*288bf522SAndroid Build Coastguard Worker   ElfStatus status;
1088*288bf522SAndroid Build Coastguard Worker   auto elf = ElfFile::Open(dso_path, &status);
1089*288bf522SAndroid Build Coastguard Worker   if (status == ElfStatus::NO_ERROR && elf->GetBuildId(build_id) == ElfStatus::NO_ERROR) {
1090*288bf522SAndroid Build Coastguard Worker     return true;
1091*288bf522SAndroid Build Coastguard Worker   }
1092*288bf522SAndroid Build Coastguard Worker   return false;
1093*288bf522SAndroid Build Coastguard Worker }
1094*288bf522SAndroid Build Coastguard Worker 
GetBuildId(const Dso & dso,BuildId & build_id)1095*288bf522SAndroid Build Coastguard Worker bool GetBuildId(const Dso& dso, BuildId& build_id) {
1096*288bf522SAndroid Build Coastguard Worker   if (dso.type() == DSO_KERNEL) {
1097*288bf522SAndroid Build Coastguard Worker     if (GetKernelBuildId(&build_id)) {
1098*288bf522SAndroid Build Coastguard Worker       return true;
1099*288bf522SAndroid Build Coastguard Worker     }
1100*288bf522SAndroid Build Coastguard Worker   } else if (dso.type() == DSO_KERNEL_MODULE) {
1101*288bf522SAndroid Build Coastguard Worker     bool has_build_id = false;
1102*288bf522SAndroid Build Coastguard Worker     if (android::base::EndsWith(dso.Path(), ".ko")) {
1103*288bf522SAndroid Build Coastguard Worker       return GetBuildIdFromDsoPath(dso.Path(), &build_id);
1104*288bf522SAndroid Build Coastguard Worker     }
1105*288bf522SAndroid Build Coastguard Worker     if (const std::string& path = dso.Path();
1106*288bf522SAndroid Build Coastguard Worker         path.size() > 2 && path[0] == '[' && path.back() == ']') {
1107*288bf522SAndroid Build Coastguard Worker       // For kernel modules that we can't find the corresponding file, read build id from /sysfs.
1108*288bf522SAndroid Build Coastguard Worker       return GetModuleBuildId(path.substr(1, path.size() - 2), &build_id);
1109*288bf522SAndroid Build Coastguard Worker     }
1110*288bf522SAndroid Build Coastguard Worker   } else if (dso.type() == DSO_ELF_FILE) {
1111*288bf522SAndroid Build Coastguard Worker     if (dso.Path() == DEFAULT_EXECNAME_FOR_THREAD_MMAP || dso.IsForJavaMethod()) {
1112*288bf522SAndroid Build Coastguard Worker       return false;
1113*288bf522SAndroid Build Coastguard Worker     }
1114*288bf522SAndroid Build Coastguard Worker     if (GetBuildIdFromDsoPath(dso.Path(), &build_id)) {
1115*288bf522SAndroid Build Coastguard Worker       return true;
1116*288bf522SAndroid Build Coastguard Worker     }
1117*288bf522SAndroid Build Coastguard Worker   }
1118*288bf522SAndroid Build Coastguard Worker   return false;
1119*288bf522SAndroid Build Coastguard Worker }
1120*288bf522SAndroid Build Coastguard Worker 
1121*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
1122