/src/perfetto/buildtools/android-unwinding/libunwindstack/MapInfo.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2017 The Android Open Source Project |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include <stdint.h> |
18 | | #include <sys/mman.h> |
19 | | #include <sys/types.h> |
20 | | #include <unistd.h> |
21 | | |
22 | | #include <memory> |
23 | | #include <mutex> |
24 | | #include <string> |
25 | | |
26 | | #include <android-base/strings.h> |
27 | | |
28 | | #include <unwindstack/Elf.h> |
29 | | #include <unwindstack/MapInfo.h> |
30 | | #include <unwindstack/Maps.h> |
31 | | #include <unwindstack/Memory.h> |
32 | | |
33 | | #include "MemoryFileAtOffset.h" |
34 | | #include "MemoryRange.h" |
35 | | |
36 | | namespace unwindstack { |
37 | | |
38 | 0 | bool MapInfo::ElfFileNotReadable() { |
39 | 0 | const std::string& map_name = name(); |
40 | 0 | return memory_backed_elf() && !map_name.empty() && map_name[0] != '[' && |
41 | 0 | !android::base::StartsWith(map_name, "/memfd:"); |
42 | 0 | } |
43 | | |
44 | 5.23k | std::shared_ptr<MapInfo> MapInfo::GetPrevRealMap() { |
45 | 5.23k | if (name().empty()) { |
46 | 0 | return nullptr; |
47 | 0 | } |
48 | | |
49 | 5.23k | for (auto prev = prev_map(); prev != nullptr; prev = prev->prev_map()) { |
50 | 5.23k | if (!prev->IsBlank()) { |
51 | 5.23k | if (prev->name() == name()) { |
52 | 0 | return prev; |
53 | 0 | } |
54 | 5.23k | return nullptr; |
55 | 5.23k | } |
56 | 5.23k | } |
57 | 0 | return nullptr; |
58 | 5.23k | } |
59 | | |
60 | 5.55k | std::shared_ptr<MapInfo> MapInfo::GetNextRealMap() { |
61 | 5.55k | if (name().empty()) { |
62 | 0 | return nullptr; |
63 | 0 | } |
64 | | |
65 | 5.55k | for (auto next = next_map(); next != nullptr; next = next->next_map()) { |
66 | 0 | if (!next->IsBlank()) { |
67 | 0 | if (next->name() == name()) { |
68 | 0 | return next; |
69 | 0 | } |
70 | 0 | return nullptr; |
71 | 0 | } |
72 | 0 | } |
73 | 5.55k | return nullptr; |
74 | 5.55k | } |
75 | | |
76 | 0 | bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) { |
77 | | // One last attempt, see if the previous map is read-only with the |
78 | | // same name and stretches across this map. |
79 | 0 | auto prev_real_map = GetPrevRealMap(); |
80 | 0 | if (prev_real_map == nullptr || prev_real_map->flags() != PROT_READ || |
81 | 0 | prev_real_map->offset() >= offset()) { |
82 | 0 | return false; |
83 | 0 | } |
84 | | |
85 | 0 | uint64_t map_size = end() - prev_real_map->end(); |
86 | 0 | if (!memory->Init(name(), prev_real_map->offset(), map_size)) { |
87 | 0 | return false; |
88 | 0 | } |
89 | | |
90 | 0 | uint64_t max_size; |
91 | 0 | if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) { |
92 | 0 | return false; |
93 | 0 | } |
94 | | |
95 | 0 | if (!memory->Init(name(), prev_real_map->offset(), max_size)) { |
96 | 0 | return false; |
97 | 0 | } |
98 | | |
99 | 0 | set_elf_offset(offset() - prev_real_map->offset()); |
100 | 0 | set_elf_start_offset(prev_real_map->offset()); |
101 | 0 | return true; |
102 | 0 | } |
103 | | |
104 | 5.59k | std::shared_ptr<Memory> MapInfo::CreateFileMemory() { |
105 | | // Fail on device maps. |
106 | 5.59k | if (flags() & MAPS_FLAGS_DEVICE_MAP) { |
107 | 0 | return nullptr; |
108 | 0 | } |
109 | | |
110 | 5.59k | auto file_memory = std::make_shared<MemoryFileAtOffset>(); |
111 | 5.59k | if (offset() == 0) { |
112 | 5.59k | if (file_memory->Init(name(), 0)) { |
113 | 0 | return file_memory; |
114 | 0 | } |
115 | 5.59k | return nullptr; |
116 | 5.59k | } |
117 | | |
118 | | // These are the possibilities when the offset is non-zero. |
119 | | // - There is an elf file embedded in a file, and the offset is the |
120 | | // the start of the elf in the file. |
121 | | // - There is an elf file embedded in a file, and the offset is the |
122 | | // the start of the executable part of the file. The actual start |
123 | | // of the elf is in the read-only segment preceeding this map. |
124 | | // - The whole file is an elf file, and the offset needs to be saved. |
125 | | // |
126 | | // Map in just the part of the file for the map. If this is not |
127 | | // a valid elf, then reinit as if the whole file is an elf file. |
128 | | // If the offset is a valid elf, then determine the size of the map |
129 | | // and reinit to that size. This is needed because the dynamic linker |
130 | | // only maps in a portion of the original elf, and never the symbol |
131 | | // file data. |
132 | | // |
133 | | // For maps with MAPS_FLAGS_JIT_SYMFILE_MAP, the map range is for a JIT function, |
134 | | // which can be smaller than elf header size. So make sure map_size is large enough |
135 | | // to read elf header. |
136 | 0 | uint64_t map_size = std::max<uint64_t>(end() - start(), sizeof(ElfTypes64::Ehdr)); |
137 | 0 | if (!file_memory->Init(name(), offset(), map_size)) { |
138 | 0 | return nullptr; |
139 | 0 | } |
140 | | |
141 | | // Check if the start of this map is an embedded elf. |
142 | 0 | uint64_t max_size = 0; |
143 | 0 | if (Elf::GetInfo(file_memory.get(), &max_size)) { |
144 | 0 | set_elf_start_offset(offset()); |
145 | 0 | if (max_size > map_size) { |
146 | 0 | if (file_memory->Init(name(), offset(), max_size)) { |
147 | 0 | return file_memory; |
148 | 0 | } |
149 | | // Try to reinit using the default map_size. |
150 | 0 | if (file_memory->Init(name(), offset(), map_size)) { |
151 | 0 | return file_memory; |
152 | 0 | } |
153 | 0 | set_elf_start_offset(0); |
154 | 0 | return nullptr; |
155 | 0 | } |
156 | 0 | return file_memory; |
157 | 0 | } |
158 | | |
159 | | // No elf at offset, try to init as if the whole file is an elf. |
160 | 0 | if (file_memory->Init(name(), 0) && Elf::IsValidElf(file_memory.get())) { |
161 | 0 | set_elf_offset(offset()); |
162 | 0 | return file_memory; |
163 | 0 | } |
164 | | |
165 | | // See if the map previous to this one contains a read-only map |
166 | | // that represents the real start of the elf data. |
167 | 0 | if (InitFileMemoryFromPreviousReadOnlyMap(file_memory.get())) { |
168 | 0 | return file_memory; |
169 | 0 | } |
170 | | |
171 | | // Failed to find elf at start of file or at read-only map, return |
172 | | // file object from the current map. |
173 | 0 | if (file_memory->Init(name(), offset(), map_size)) { |
174 | 0 | return file_memory; |
175 | 0 | } |
176 | 0 | return nullptr; |
177 | 0 | } |
178 | | |
179 | 5.59k | std::shared_ptr<Memory> MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { |
180 | 5.59k | if (end() <= start()) { |
181 | 0 | return nullptr; |
182 | 0 | } |
183 | | |
184 | 5.59k | set_elf_offset(0); |
185 | | |
186 | | // Fail on device maps. |
187 | 5.59k | if (flags() & MAPS_FLAGS_DEVICE_MAP) { |
188 | 0 | return nullptr; |
189 | 0 | } |
190 | | |
191 | | // First try and use the file associated with the info. |
192 | 5.59k | if (!name().empty()) { |
193 | 5.59k | auto memory = CreateFileMemory(); |
194 | 5.59k | if (memory != nullptr) { |
195 | 0 | return memory; |
196 | 0 | } |
197 | 5.59k | } |
198 | | |
199 | 5.59k | if (process_memory == nullptr) { |
200 | 0 | return nullptr; |
201 | 0 | } |
202 | | |
203 | 5.59k | set_memory_backed_elf(true); |
204 | | |
205 | | // Need to verify that this elf is valid. It's possible that |
206 | | // only part of the elf file to be mapped into memory is in the executable |
207 | | // map. In this case, there will be another read-only map that includes the |
208 | | // first part of the elf file. This is done if the linker rosegment |
209 | | // option is used. |
210 | 5.59k | std::shared_ptr<Memory> memory_range( |
211 | 5.59k | new MemoryRange(process_memory, start(), end() - start(), 0)); |
212 | 5.59k | if (Elf::IsValidElf(memory_range.get())) { |
213 | 5.55k | set_elf_start_offset(offset()); |
214 | | |
215 | 5.55k | auto next_real_map = GetNextRealMap(); |
216 | | |
217 | | // Might need to peek at the next map to create a memory object that |
218 | | // includes that map too. |
219 | 5.55k | if (offset() != 0 || next_real_map == nullptr || offset() >= next_real_map->offset()) { |
220 | 5.55k | return memory_range; |
221 | 5.55k | } |
222 | | |
223 | | // There is a possibility that the elf object has already been created |
224 | | // in the next map. Since this should be a very uncommon path, just |
225 | | // redo the work. If this happens, the elf for this map will eventually |
226 | | // be discarded. |
227 | 0 | MemoryRanges* ranges = new MemoryRanges; |
228 | 0 | std::shared_ptr<Memory> memory_ranges(ranges); |
229 | 0 | ranges->Insert(new MemoryRange(process_memory, start(), end() - start(), 0)); |
230 | 0 | ranges->Insert(new MemoryRange(process_memory, next_real_map->start(), |
231 | 0 | next_real_map->end() - next_real_map->start(), |
232 | 0 | next_real_map->offset() - offset())); |
233 | |
|
234 | 0 | return memory_ranges; |
235 | 5.55k | } |
236 | | |
237 | 40 | auto prev_real_map = GetPrevRealMap(); |
238 | | |
239 | | // Find the read-only map by looking at the previous map. The linker |
240 | | // doesn't guarantee that this invariant will always be true. However, |
241 | | // if that changes, there is likely something else that will change and |
242 | | // break something. |
243 | 40 | if (offset() == 0 || prev_real_map == nullptr || prev_real_map->offset() >= offset()) { |
244 | 40 | set_memory_backed_elf(false); |
245 | 40 | return nullptr; |
246 | 40 | } |
247 | | |
248 | | // Make sure that relative pc values are corrected properly. |
249 | 0 | set_elf_offset(offset() - prev_real_map->offset()); |
250 | | // Use this as the elf start offset, otherwise, you always get offsets into |
251 | | // the r-x section, which is not quite the right information. |
252 | 0 | set_elf_start_offset(prev_real_map->offset()); |
253 | |
|
254 | 0 | MemoryRanges* ranges = new MemoryRanges; |
255 | 0 | std::shared_ptr<Memory> memory_ranges(ranges); |
256 | 0 | if (!ranges->Insert(new MemoryRange(process_memory, prev_real_map->start(), |
257 | 0 | prev_real_map->end() - prev_real_map->start(), 0))) { |
258 | 0 | return nullptr; |
259 | 0 | } |
260 | 0 | if (!ranges->Insert(new MemoryRange(process_memory, start(), end() - start(), elf_offset()))) { |
261 | 0 | return nullptr; |
262 | 0 | } |
263 | 0 | return memory_ranges; |
264 | 0 | } |
265 | | |
266 | | class ScopedElfCacheLock { |
267 | | public: |
268 | 5.59k | ScopedElfCacheLock() { |
269 | 5.59k | if (Elf::CachingEnabled()) Elf::CacheLock(); |
270 | 5.59k | } |
271 | 5.59k | ~ScopedElfCacheLock() { |
272 | 5.59k | if (Elf::CachingEnabled()) Elf::CacheUnlock(); |
273 | 5.59k | } |
274 | | }; |
275 | | |
276 | 6.89k | Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) { |
277 | | // Make sure no other thread is trying to add the elf to this map. |
278 | 6.89k | std::lock_guard<std::mutex> guard(elf_mutex()); |
279 | | |
280 | 6.89k | if (elf().get() != nullptr) { |
281 | 1.29k | return elf().get(); |
282 | 1.29k | } |
283 | | |
284 | 5.59k | ScopedElfCacheLock elf_cache_lock; |
285 | 5.59k | if (Elf::CachingEnabled() && !name().empty()) { |
286 | 0 | if (Elf::CacheGet(this)) { |
287 | 0 | return elf().get(); |
288 | 0 | } |
289 | 0 | } |
290 | | |
291 | 5.59k | auto elf_memory = CreateMemory(process_memory); |
292 | 5.59k | elf().reset(new Elf(elf_memory)); |
293 | | // If the init fails, keep the elf around as an invalid object so we |
294 | | // don't try to reinit the object. |
295 | 5.59k | elf()->Init(); |
296 | 5.59k | if (elf()->valid() && expected_arch != elf()->arch()) { |
297 | | // Make the elf invalid, mismatch between arch and expected arch. |
298 | 353 | elf()->Invalidate(); |
299 | 353 | } |
300 | | |
301 | 5.59k | if (!elf()->valid()) { |
302 | 403 | set_elf_start_offset(offset()); |
303 | 5.19k | } else if (auto prev_real_map = GetPrevRealMap(); prev_real_map != nullptr && |
304 | 0 | prev_real_map->flags() == PROT_READ && |
305 | 0 | prev_real_map->offset() < offset()) { |
306 | | // If there is a read-only map then a read-execute map that represents the |
307 | | // same elf object, make sure the previous map is using the same elf |
308 | | // object if it hasn't already been set. Locking this should not result |
309 | | // in a deadlock as long as the invariant that the code only ever tries |
310 | | // to lock the previous real map holds true. |
311 | 0 | std::lock_guard<std::mutex> guard(prev_real_map->elf_mutex()); |
312 | 0 | if (prev_real_map->elf() == nullptr) { |
313 | | // Need to verify if the map is the previous read-only map. |
314 | 0 | prev_real_map->set_elf(elf()); |
315 | 0 | prev_real_map->set_memory_backed_elf(memory_backed_elf()); |
316 | 0 | prev_real_map->set_elf_start_offset(elf_start_offset()); |
317 | 0 | prev_real_map->set_elf_offset(prev_real_map->offset() - elf_start_offset()); |
318 | 0 | } else if (prev_real_map->elf_start_offset() == elf_start_offset()) { |
319 | | // Discard this elf, and use the elf from the previous map instead. |
320 | 0 | set_elf(prev_real_map->elf()); |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | // Cache the elf only after all of the above checks since we might |
325 | | // discard the original elf we created. |
326 | 5.59k | if (Elf::CachingEnabled()) { |
327 | 0 | Elf::CacheAdd(this); |
328 | 0 | } |
329 | 5.59k | return elf().get(); |
330 | 5.59k | } |
331 | | |
332 | 0 | bool MapInfo::GetFunctionName(uint64_t addr, SharedString* name, uint64_t* func_offset) { |
333 | 0 | { |
334 | | // Make sure no other thread is trying to update this elf object. |
335 | 0 | std::lock_guard<std::mutex> guard(elf_mutex()); |
336 | 0 | if (elf() == nullptr) { |
337 | 0 | return false; |
338 | 0 | } |
339 | 0 | } |
340 | | // No longer need the lock, once the elf object is created, it is not deleted |
341 | | // until this object is deleted. |
342 | 0 | return elf()->GetFunctionName(addr, name, func_offset); |
343 | 0 | } |
344 | | |
345 | 0 | uint64_t MapInfo::GetLoadBias() { |
346 | 0 | uint64_t cur_load_bias = load_bias().load(); |
347 | 0 | if (cur_load_bias != UINT64_MAX) { |
348 | 0 | return cur_load_bias; |
349 | 0 | } |
350 | | |
351 | 0 | Elf* elf_obj = GetElfObj(); |
352 | 0 | if (elf_obj == nullptr) { |
353 | 0 | return UINT64_MAX; |
354 | 0 | } |
355 | | |
356 | 0 | if (elf_obj->valid()) { |
357 | 0 | cur_load_bias = elf_obj->GetLoadBias(); |
358 | 0 | set_load_bias(cur_load_bias); |
359 | 0 | return cur_load_bias; |
360 | 0 | } |
361 | | |
362 | 0 | set_load_bias(0); |
363 | 0 | return 0; |
364 | 0 | } |
365 | | |
366 | 0 | uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) { |
367 | 0 | uint64_t cur_load_bias = GetLoadBias(); |
368 | 0 | if (cur_load_bias != UINT64_MAX) { |
369 | 0 | return cur_load_bias; |
370 | 0 | } |
371 | | |
372 | | // Call lightweight static function that will only read enough of the |
373 | | // elf data to get the load bias. |
374 | 0 | auto memory = CreateMemory(process_memory); |
375 | 0 | cur_load_bias = Elf::GetLoadBias(memory.get()); |
376 | 0 | set_load_bias(cur_load_bias); |
377 | 0 | return cur_load_bias; |
378 | 0 | } |
379 | | |
380 | 736k | MapInfo::~MapInfo() { |
381 | 736k | ElfFields* elf_fields = elf_fields_.load(); |
382 | 736k | if (elf_fields != nullptr) { |
383 | 5.59k | delete elf_fields->build_id_.load(); |
384 | 5.59k | delete elf_fields; |
385 | 5.59k | } |
386 | 736k | } |
387 | | |
388 | 0 | std::string MapInfo::GetFullName() { |
389 | 0 | Elf* elf_obj = GetElfObj(); |
390 | 0 | if (elf_obj == nullptr || elf_start_offset() == 0 || name().empty()) { |
391 | 0 | return name(); |
392 | 0 | } |
393 | | |
394 | 0 | std::string soname = elf_obj->GetSoname(); |
395 | 0 | if (soname.empty()) { |
396 | 0 | return name(); |
397 | 0 | } |
398 | | |
399 | 0 | std::string full_name(name()); |
400 | 0 | full_name += '!'; |
401 | 0 | full_name += soname; |
402 | 0 | return full_name; |
403 | 0 | } |
404 | | |
405 | 4.36k | SharedString MapInfo::GetBuildID() { |
406 | 4.36k | SharedString* id = build_id().load(); |
407 | 4.36k | if (id != nullptr) { |
408 | 748 | return *id; |
409 | 748 | } |
410 | | |
411 | | // No need to lock, at worst if multiple threads do this at the same |
412 | | // time it should be detected and only one thread should win and |
413 | | // save the data. |
414 | | |
415 | 3.61k | std::string result; |
416 | 3.61k | Elf* elf_obj = GetElfObj(); |
417 | 3.61k | if (elf_obj != nullptr) { |
418 | 3.61k | result = elf_obj->GetBuildID(); |
419 | 3.61k | } else { |
420 | | // This will only work if we can get the file associated with this memory. |
421 | | // If this is only available in memory, then the section name information |
422 | | // is not present and we will not be able to find the build id info. |
423 | 0 | auto file_memory = CreateFileMemory(); |
424 | 0 | if (file_memory != nullptr) { |
425 | 0 | result = Elf::GetBuildID(file_memory.get()); |
426 | 0 | } |
427 | 0 | } |
428 | 3.61k | return SetBuildID(std::move(result)); |
429 | 4.36k | } |
430 | | |
431 | 3.61k | SharedString MapInfo::SetBuildID(std::string&& new_build_id) { |
432 | 3.61k | std::unique_ptr<SharedString> new_build_id_ptr(new SharedString(std::move(new_build_id))); |
433 | 3.61k | SharedString* expected_id = nullptr; |
434 | | // Strong version since we need to reliably return the stored pointer. |
435 | 3.61k | if (build_id().compare_exchange_strong(expected_id, new_build_id_ptr.get())) { |
436 | | // Value saved, so make sure the memory is not freed. |
437 | 3.61k | return *new_build_id_ptr.release(); |
438 | 3.61k | } else { |
439 | | // The expected value is set to the stored value on failure. |
440 | 0 | return *expected_id; |
441 | 0 | } |
442 | 3.61k | } |
443 | | |
444 | 88.2k | MapInfo::ElfFields& MapInfo::GetElfFields() { |
445 | 88.2k | ElfFields* elf_fields = elf_fields_.load(std::memory_order_acquire); |
446 | 88.2k | if (elf_fields != nullptr) { |
447 | 82.6k | return *elf_fields; |
448 | 82.6k | } |
449 | | // Allocate and initialize the field in thread-safe way. |
450 | 5.59k | std::unique_ptr<ElfFields> desired(new ElfFields()); |
451 | 5.59k | ElfFields* expected = nullptr; |
452 | | // Strong version is reliable. Weak version might randomly return false. |
453 | 5.59k | if (elf_fields_.compare_exchange_strong(expected, desired.get())) { |
454 | 5.59k | return *desired.release(); // Success: we transferred the pointer ownership to the field. |
455 | 5.59k | } else { |
456 | 0 | return *expected; // Failure: 'expected' is updated to the value set by the other thread. |
457 | 0 | } |
458 | 5.59k | } |
459 | | |
460 | 0 | std::string MapInfo::GetPrintableBuildID() { |
461 | 0 | std::string raw_build_id = GetBuildID(); |
462 | 0 | return Elf::GetPrintableBuildID(raw_build_id); |
463 | 0 | } |
464 | | |
465 | | } // namespace unwindstack |