123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <memory>
- #include <mutex>
- #include <string>
- #include <android-base/stringprintf.h>
- #include <unwindstack/Elf.h>
- #include <unwindstack/MapInfo.h>
- #include <unwindstack/Maps.h>
- #include <unwindstack/Memory.h>
- namespace unwindstack {
- bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
- // One last attempt, see if the previous map is read-only with the
- // same name and stretches across this map.
- if (prev_map == nullptr || prev_map->flags != PROT_READ) {
- return false;
- }
- uint64_t map_size = end - prev_map->end;
- if (!memory->Init(name, prev_map->offset, map_size)) {
- return false;
- }
- uint64_t max_size;
- if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
- return false;
- }
- if (!memory->Init(name, prev_map->offset, max_size)) {
- return false;
- }
- elf_offset = offset - prev_map->offset;
- elf_start_offset = prev_map->offset;
- return true;
- }
- Memory* MapInfo::GetFileMemory() {
- std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
- if (offset == 0) {
- if (memory->Init(name, 0)) {
- return memory.release();
- }
- return nullptr;
- }
- // These are the possibilities when the offset is non-zero.
- // - There is an elf file embedded in a file, and the offset is the
- // the start of the elf in the file.
- // - There is an elf file embedded in a file, and the offset is the
- // the start of the executable part of the file. The actual start
- // of the elf is in the read-only segment preceeding this map.
- // - The whole file is an elf file, and the offset needs to be saved.
- //
- // Map in just the part of the file for the map. If this is not
- // a valid elf, then reinit as if the whole file is an elf file.
- // If the offset is a valid elf, then determine the size of the map
- // and reinit to that size. This is needed because the dynamic linker
- // only maps in a portion of the original elf, and never the symbol
- // file data.
- uint64_t map_size = end - start;
- if (!memory->Init(name, offset, map_size)) {
- return nullptr;
- }
- // Check if the start of this map is an embedded elf.
- uint64_t max_size = 0;
- if (Elf::GetInfo(memory.get(), &max_size)) {
- elf_start_offset = offset;
- if (max_size > map_size) {
- if (memory->Init(name, offset, max_size)) {
- return memory.release();
- }
- // Try to reinit using the default map_size.
- if (memory->Init(name, offset, map_size)) {
- return memory.release();
- }
- elf_start_offset = 0;
- return nullptr;
- }
- return memory.release();
- }
- // No elf at offset, try to init as if the whole file is an elf.
- if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
- elf_offset = offset;
- // Need to check how to set the elf start offset. If this map is not
- // the r-x map of a r-- map, then use the real offset value. Otherwise,
- // use 0.
- if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ ||
- prev_map->name != name) {
- elf_start_offset = offset;
- }
- return memory.release();
- }
- // See if the map previous to this one contains a read-only map
- // that represents the real start of the elf data.
- if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) {
- return memory.release();
- }
- // Failed to find elf at start of file or at read-only map, return
- // file object from the current map.
- if (memory->Init(name, offset, map_size)) {
- return memory.release();
- }
- return nullptr;
- }
- Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
- if (end <= start) {
- return nullptr;
- }
- elf_offset = 0;
- // Fail on device maps.
- if (flags & MAPS_FLAGS_DEVICE_MAP) {
- return nullptr;
- }
- // First try and use the file associated with the info.
- if (!name.empty()) {
- Memory* memory = GetFileMemory();
- if (memory != nullptr) {
- return memory;
- }
- }
- if (process_memory == nullptr) {
- return nullptr;
- }
- // Need to verify that this elf is valid. It's possible that
- // only part of the elf file to be mapped into memory is in the executable
- // map. In this case, there will be another read-only map that includes the
- // first part of the elf file. This is done if the linker rosegment
- // option is used.
- std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
- if (Elf::IsValidElf(memory.get())) {
- memory_backed_elf = true;
- return memory.release();
- }
- // Find the read-only map by looking at the previous map. The linker
- // doesn't guarantee that this invariant will always be true. However,
- // if that changes, there is likely something else that will change and
- // break something.
- if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
- prev_map->offset >= offset) {
- return nullptr;
- }
- // Make sure that relative pc values are corrected properly.
- elf_offset = offset - prev_map->offset;
- // Use this as the elf start offset, otherwise, you always get offsets into
- // the r-x section, which is not quite the right information.
- elf_start_offset = prev_map->offset;
- MemoryRanges* ranges = new MemoryRanges;
- ranges->Insert(
- new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
- ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
- memory_backed_elf = true;
- return ranges;
- }
- Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
- {
- // Make sure no other thread is trying to add the elf to this map.
- std::lock_guard<std::mutex> guard(mutex_);
- if (elf.get() != nullptr) {
- return elf.get();
- }
- bool locked = false;
- if (Elf::CachingEnabled() && !name.empty()) {
- Elf::CacheLock();
- locked = true;
- if (Elf::CacheGet(this)) {
- Elf::CacheUnlock();
- return elf.get();
- }
- }
- Memory* memory = CreateMemory(process_memory);
- if (locked) {
- if (Elf::CacheAfterCreateMemory(this)) {
- delete memory;
- Elf::CacheUnlock();
- return elf.get();
- }
- }
- elf.reset(new Elf(memory));
- // If the init fails, keep the elf around as an invalid object so we
- // don't try to reinit the object.
- elf->Init();
- if (elf->valid() && expected_arch != elf->arch()) {
- // Make the elf invalid, mismatch between arch and expected arch.
- elf->Invalidate();
- }
- if (locked) {
- Elf::CacheAdd(this);
- Elf::CacheUnlock();
- }
- }
- // If there is a read-only map then a read-execute map that represents the
- // same elf object, make sure the previous map is using the same elf
- // object if it hasn't already been set.
- if (prev_map != nullptr && elf_start_offset != offset && prev_map->offset == elf_start_offset &&
- prev_map->name == name) {
- std::lock_guard<std::mutex> guard(prev_map->mutex_);
- if (prev_map->elf.get() == nullptr) {
- prev_map->elf = elf;
- prev_map->memory_backed_elf = memory_backed_elf;
- }
- }
- return elf.get();
- }
- bool MapInfo::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- {
- // Make sure no other thread is trying to update this elf object.
- std::lock_guard<std::mutex> guard(mutex_);
- if (elf == nullptr) {
- return false;
- }
- }
- // No longer need the lock, once the elf object is created, it is not deleted
- // until this object is deleted.
- return elf->GetFunctionName(addr, name, func_offset);
- }
- uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
- uint64_t cur_load_bias = load_bias.load();
- if (cur_load_bias != static_cast<uint64_t>(-1)) {
- return cur_load_bias;
- }
- {
- // Make sure no other thread is trying to add the elf to this map.
- std::lock_guard<std::mutex> guard(mutex_);
- if (elf != nullptr) {
- if (elf->valid()) {
- cur_load_bias = elf->GetLoadBias();
- load_bias = cur_load_bias;
- return cur_load_bias;
- } else {
- load_bias = 0;
- return 0;
- }
- }
- }
- // Call lightweight static function that will only read enough of the
- // elf data to get the load bias.
- std::unique_ptr<Memory> memory(CreateMemory(process_memory));
- cur_load_bias = Elf::GetLoadBias(memory.get());
- load_bias = cur_load_bias;
- return cur_load_bias;
- }
- MapInfo::~MapInfo() {
- uintptr_t id = build_id.load();
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- }
- }
- std::string MapInfo::GetBuildID() {
- uintptr_t id = build_id.load();
- if (build_id != 0) {
- return *reinterpret_cast<std::string*>(id);
- }
- // No need to lock, at worst if multiple threads do this at the same
- // time it should be detected and only one thread should win and
- // save the data.
- std::unique_ptr<std::string> cur_build_id(new std::string);
- // Now need to see if the elf object exists.
- // Make sure no other thread is trying to add the elf to this map.
- mutex_.lock();
- Elf* elf_obj = elf.get();
- mutex_.unlock();
- if (elf_obj != nullptr) {
- *cur_build_id = elf_obj->GetBuildID();
- } else {
- // This will only work if we can get the file associated with this memory.
- // If this is only available in memory, then the section name information
- // is not present and we will not be able to find the build id info.
- std::unique_ptr<Memory> memory(GetFileMemory());
- if (memory != nullptr) {
- *cur_build_id = Elf::GetBuildID(memory.get());
- }
- }
- id = reinterpret_cast<uintptr_t>(cur_build_id.get());
- uintptr_t expected_id = 0;
- if (build_id.compare_exchange_weak(expected_id, id)) {
- // Value saved, so make sure the memory is not freed.
- cur_build_id.release();
- }
- return *reinterpret_cast<std::string*>(id);
- }
- std::string MapInfo::GetPrintableBuildID() {
- std::string raw_build_id = GetBuildID();
- if (raw_build_id.empty()) {
- return "";
- }
- std::string printable_build_id;
- for (const char& c : raw_build_id) {
- // Use %hhx to avoid sign extension on abis that have signed chars.
- printable_build_id += android::base::StringPrintf("%02hhx", c);
- }
- return printable_build_id;
- }
- } // namespace unwindstack
|