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 <sys/mman.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 21 #include <memory> 22 #include <mutex> 23 #include <string> 24 25 #include <unwindstack/Elf.h> 26 #include <unwindstack/MapInfo.h> 27 #include <unwindstack/Maps.h> 28 #include <unwindstack/Memory.h> 29 30 namespace unwindstack { 31 32 Memory* MapInfo::GetFileMemory() { 33 std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset); 34 if (offset == 0) { 35 if (memory->Init(name, 0)) { 36 return memory.release(); 37 } 38 return nullptr; 39 } 40 41 // There are two possibilities when the offset is non-zero. 42 // - There is an elf file embedded in a file. 43 // - The whole file is an elf file, and the offset needs to be saved. 44 // 45 // Map in just the part of the file for the map. If this is not 46 // a valid elf, then reinit as if the whole file is an elf file. 47 // If the offset is a valid elf, then determine the size of the map 48 // and reinit to that size. This is needed because the dynamic linker 49 // only maps in a portion of the original elf, and never the symbol 50 // file data. 51 uint64_t map_size = end - start; 52 if (!memory->Init(name, offset, map_size)) { 53 return nullptr; 54 } 55 56 bool valid; 57 uint64_t max_size; 58 Elf::GetInfo(memory.get(), &valid, &max_size); 59 if (!valid) { 60 // Init as if the whole file is an elf. 61 if (memory->Init(name, 0)) { 62 elf_offset = offset; 63 return memory.release(); 64 } 65 return nullptr; 66 } 67 68 if (max_size > map_size) { 69 if (memory->Init(name, offset, max_size)) { 70 return memory.release(); 71 } 72 // Try to reinit using the default map_size. 73 if (memory->Init(name, offset, map_size)) { 74 return memory.release(); 75 } 76 return nullptr; 77 } 78 return memory.release(); 79 } 80 81 Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { 82 if (end <= start) { 83 return nullptr; 84 } 85 86 elf_offset = 0; 87 88 // Fail on device maps. 89 if (flags & MAPS_FLAGS_DEVICE_MAP) { 90 return nullptr; 91 } 92 93 // First try and use the file associated with the info. 94 if (!name.empty()) { 95 Memory* memory = GetFileMemory(); 96 if (memory != nullptr) { 97 return memory; 98 } 99 } 100 101 // If the map isn't readable, don't bother trying to read from process memory. 102 if (!(flags & PROT_READ)) { 103 return nullptr; 104 } 105 return new MemoryRange(process_memory, start, end - start, 0); 106 } 107 108 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) { 109 // Make sure no other thread is trying to add the elf to this map. 110 std::lock_guard<std::mutex> guard(mutex_); 111 112 if (elf.get() != nullptr) { 113 return elf.get(); 114 } 115 116 bool locked = false; 117 if (Elf::CachingEnabled() && !name.empty()) { 118 Elf::CacheLock(); 119 locked = true; 120 if (Elf::CacheGet(this)) { 121 Elf::CacheUnlock(); 122 return elf.get(); 123 } 124 } 125 126 Memory* memory = CreateMemory(process_memory); 127 if (locked) { 128 if (Elf::CacheAfterCreateMemory(this)) { 129 delete memory; 130 Elf::CacheUnlock(); 131 return elf.get(); 132 } 133 } 134 elf.reset(new Elf(memory)); 135 // If the init fails, keep the elf around as an invalid object so we 136 // don't try to reinit the object. 137 elf->Init(init_gnu_debugdata); 138 139 if (locked) { 140 Elf::CacheAdd(this); 141 Elf::CacheUnlock(); 142 } 143 return elf.get(); 144 } 145 146 uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) { 147 uint64_t cur_load_bias = load_bias.load(); 148 if (cur_load_bias != static_cast<uint64_t>(-1)) { 149 return cur_load_bias; 150 } 151 152 { 153 // Make sure no other thread is trying to add the elf to this map. 154 std::lock_guard<std::mutex> guard(mutex_); 155 if (elf != nullptr) { 156 if (elf->valid()) { 157 cur_load_bias = elf->GetLoadBias(); 158 load_bias = cur_load_bias; 159 return cur_load_bias; 160 } else { 161 load_bias = 0; 162 return 0; 163 } 164 } 165 } 166 167 // Call lightweight static function that will only read enough of the 168 // elf data to get the load bias. 169 std::unique_ptr<Memory> memory(CreateMemory(process_memory)); 170 cur_load_bias = Elf::GetLoadBias(memory.get()); 171 load_bias = cur_load_bias; 172 return cur_load_bias; 173 } 174 175 } // namespace unwindstack 176