1 /*
2 *
3 * Copyright 2018, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "symbolizer.h"
19
20 #include <map>
21 #include <memory>
22 #include <unordered_map>
23
24 #include <android-base/logging.h>
25 #include <base/mem_map.h>
26 #include <build_id.h>
27 #include <read_dex_file.h>
28 #include <read_elf.h>
29 #include <vdex_file.h>
30
31 namespace perfprofd {
32
33 namespace {
34
35 struct SimpleperfSymbolizer : public Symbolizer {
36 // For simplicity, we assume non-overlapping symbols.
37 struct Symbol {
Symbolperfprofd::__anon2a2b97bd0111::SimpleperfSymbolizer::Symbol38 Symbol(std::string_view n, uint64_t l) : name(n), length(l) {}
39
40 std::string name;
41 uint64_t length;
42 };
43 using SymbolMap = std::map<uint64_t, Symbol>;
44
Decodeperfprofd::__anon2a2b97bd0111::SimpleperfSymbolizer45 std::string Decode(const std::string& dso, uint64_t address) override {
46 auto it = dsos.find(dso);
47 if (it == dsos.end()) {
48 LoadDso(dso);
49 it = dsos.find(dso);
50 DCHECK(it != dsos.end());
51 }
52
53 const SymbolMap& map = it->second;
54 if (map.empty()) {
55 return "";
56 }
57 auto upper_bound = map.upper_bound(address);
58 if (upper_bound == map.begin()) {
59 // Nope, not in the map.
60 return "";
61 }
62
63 upper_bound--;
64 if (upper_bound->first + upper_bound->second.length > address) {
65 // This element covers the given address, return its name.
66 return upper_bound->second.name;
67 }
68
69 return "";
70 }
71
LoadDsoperfprofd::__anon2a2b97bd0111::SimpleperfSymbolizer72 void LoadDso(const std::string& dso) {
73 // See whether it's an ELF file.
74 {
75 SymbolMap elf_data;
76 auto callback = [&elf_data](const ElfFileSymbol& sym) {
77 if (sym.is_func) {
78 if (sym.len == 0) {
79 LOG(ERROR) << "Symbol size is zero for " << sym.name;
80 }
81 elf_data.emplace(sym.vaddr, Symbol(sym.name, sym.len));
82 }
83 };
84 ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback);
85 if (status == ElfStatus::NO_ERROR) {
86 dsos.emplace(dso, std::move(elf_data));
87 return;
88 }
89 }
90
91 // See whether it's a vdex file.
92 {
93 ::art::MemMap::Init();
94
95 using VdexFile = ::art::VdexFile;
96 std::string error_msg;
97 std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso,
98 /* writable= */ false,
99 /* low_4gb= */ false,
100 /* unquicken= */ false,
101 &error_msg);
102 if (vdex != nullptr) {
103 const uint8_t* cur = nullptr;
104 std::vector<uint64_t> dex_file_offsets;
105 const uint8_t* base = vdex->Begin();
106 for (;;) {
107 cur = vdex->GetNextDexFileData(cur);
108 if (cur == nullptr) {
109 break;
110 }
111 dex_file_offsets.push_back(cur - base);
112 }
113
114 if (!dex_file_offsets.empty()) {
115 std::vector<DexFileSymbol> symbols;
116 if (ReadSymbolsFromDexFile(dso, dex_file_offsets, &symbols)) {
117 SymbolMap vdex_data;
118 for (const DexFileSymbol& symbol : symbols) {
119 vdex_data.emplace(symbol.offset, Symbol(symbol.name, symbol.len));
120 }
121 dsos.emplace(dso, std::move(vdex_data));
122 LOG(INFO) << "Found " << symbols.size() << " dex symbols in " << dso;
123 return;
124 } else {
125 LOG(WARNING) << "Could not read symbols from dex files in " << dso;
126 }
127 } else {
128 LOG(WARNING) << "Could not find dex files for vdex " << dso;
129 dsos.emplace(dso, SymbolMap());
130 }
131 } else {
132 LOG(WARNING) << dso << " is not a vdex: " << error_msg;
133 }
134 }
135
136 // TODO: See whether it's a dex file.
137
138 // OK, give up.
139 LOG(WARNING) << "Could not symbolize " << dso;
140 dsos.emplace(dso, SymbolMap());
141 }
142
GetMinExecutableVAddrperfprofd::__anon2a2b97bd0111::SimpleperfSymbolizer143 bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override {
144 uint64_t file_offset_of_min_vaddr;
145 ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(dso, BuildId(), addr,
146 &file_offset_of_min_vaddr);
147 if (status != ElfStatus::NO_ERROR) {
148 return true;
149 }
150
151 {
152 ::art::MemMap::Init();
153
154 using VdexFile = ::art::VdexFile;
155 std::string error_msg;
156 std::unique_ptr<VdexFile> vdex = VdexFile::Open(dso,
157 /* writable= */ false,
158 /* low_4gb= */ false,
159 /* unquicken= */ false,
160 &error_msg);
161 if (vdex != nullptr) {
162 *addr = 0u;
163 return true;
164 }
165 }
166
167 return false;
168 }
169
170 std::unordered_map<std::string, SymbolMap> dsos;
171 };
172
173 } // namespace
174
CreateELFSymbolizer()175 std::unique_ptr<Symbolizer> CreateELFSymbolizer() {
176 return std::unique_ptr<Symbolizer>(new SimpleperfSymbolizer());
177 }
178
179 } // namespace perfprofd
180