blob: 8527797d29198703ddc408c34eca78fa3bad9a8e [file] [log] [blame]
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -07001/*
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
Christopher Ferris5f118512017-09-01 11:17:16 -070017#include <sys/mman.h>
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070018#include <sys/types.h>
19#include <unistd.h>
20
21#include <memory>
Christopher Ferrisbe788d82017-11-27 14:50:38 -080022#include <mutex>
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070023#include <string>
24
Christopher Ferrisd226a512017-07-14 10:37:19 -070025#include <unwindstack/Elf.h>
26#include <unwindstack/MapInfo.h>
27#include <unwindstack/Maps.h>
28#include <unwindstack/Memory.h>
29
30namespace unwindstack {
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070031
Christopher Ferris3f805ac2017-08-30 13:15:19 -070032Memory* 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
Christopher Ferris3f805ac2017-08-30 13:15:19 -070056 uint64_t max_size;
Christopher Ferrisa2f38f12018-10-09 18:49:11 -070057 if (!Elf::GetInfo(memory.get(), &max_size)) {
Christopher Ferris3f805ac2017-08-30 13:15:19 -070058 // Init as if the whole file is an elf.
59 if (memory->Init(name, 0)) {
60 elf_offset = offset;
61 return memory.release();
62 }
63 return nullptr;
64 }
65
66 if (max_size > map_size) {
67 if (memory->Init(name, offset, max_size)) {
68 return memory.release();
69 }
70 // Try to reinit using the default map_size.
71 if (memory->Init(name, offset, map_size)) {
72 return memory.release();
73 }
74 return nullptr;
75 }
76 return memory.release();
77}
78
Christopher Ferris5f118512017-09-01 11:17:16 -070079Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070080 if (end <= start) {
81 return nullptr;
82 }
83
84 elf_offset = 0;
85
Christopher Ferris5f118512017-09-01 11:17:16 -070086 // Fail on device maps.
87 if (flags & MAPS_FLAGS_DEVICE_MAP) {
88 return nullptr;
89 }
90
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070091 // First try and use the file associated with the info.
92 if (!name.empty()) {
Christopher Ferris3f805ac2017-08-30 13:15:19 -070093 Memory* memory = GetFileMemory();
94 if (memory != nullptr) {
95 return memory;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070096 }
97 }
98
Christopher Ferris5f118512017-09-01 11:17:16 -070099 // If the map isn't readable, don't bother trying to read from process memory.
100 if (!(flags & PROT_READ)) {
101 return nullptr;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700102 }
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700103
104 // Need to verify that this elf is valid. It's possible that
105 // only part of the elf file to be mapped into memory is in the executable
106 // map. In this case, there will be another read-only map that includes the
107 // first part of the elf file. This is done if the linker rosegment
108 // option is used.
109 std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
Christopher Ferrisa2f38f12018-10-09 18:49:11 -0700110 if (Elf::IsValidElf(memory.get())) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700111 return memory.release();
112 }
113
114 if (name.empty() || maps_ == nullptr) {
115 return nullptr;
116 }
117
118 // Find the read-only map that has the same name and has an offset closest
119 // to the current offset but less than the offset of the current map.
120 // For shared libraries, there should be a r-x map that has a non-zero
121 // offset and then a r-- map that has a zero offset.
122 // For shared libraries loaded from an apk, there should be a r-x map that
123 // has a non-zero offset and then a r-- map that has a non-zero offset less
124 // than the offset from the r-x map.
125 uint64_t closest_offset = 0;
126 MapInfo* ro_map_info = nullptr;
127 for (auto map_info : *maps_) {
128 if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset &&
129 map_info->offset >= closest_offset) {
130 ro_map_info = map_info;
131 closest_offset = ro_map_info->offset;
132 }
133 }
134
135 if (ro_map_info != nullptr) {
136 // Make sure that relative pc values are corrected properly.
137 elf_offset = offset - closest_offset;
138
139 MemoryRanges* ranges = new MemoryRanges;
140 ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
141 ro_map_info->end - ro_map_info->start, 0));
142 ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
143
144 return ranges;
145 }
146 return nullptr;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700147}
148
Christopher Ferrise8c4ecf2018-10-23 12:04:26 -0700149Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800150 // Make sure no other thread is trying to add the elf to this map.
151 std::lock_guard<std::mutex> guard(mutex_);
152
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800153 if (elf.get() != nullptr) {
154 return elf.get();
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700155 }
156
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800157 bool locked = false;
158 if (Elf::CachingEnabled() && !name.empty()) {
159 Elf::CacheLock();
160 locked = true;
Christopher Ferrisd9575b62018-02-16 13:48:19 -0800161 if (Elf::CacheGet(this)) {
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800162 Elf::CacheUnlock();
163 return elf.get();
164 }
165 }
Christopher Ferrise69f4702017-10-19 16:08:58 -0700166
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800167 Memory* memory = CreateMemory(process_memory);
Christopher Ferrisd9575b62018-02-16 13:48:19 -0800168 if (locked) {
169 if (Elf::CacheAfterCreateMemory(this)) {
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800170 delete memory;
171 Elf::CacheUnlock();
172 return elf.get();
173 }
174 }
175 elf.reset(new Elf(memory));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700176 // If the init fails, keep the elf around as an invalid object so we
177 // don't try to reinit the object.
Christopher Ferrise8c4ecf2018-10-23 12:04:26 -0700178 elf->Init();
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800179
180 if (locked) {
181 Elf::CacheAdd(this);
182 Elf::CacheUnlock();
183 }
184 return elf.get();
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700185}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700186
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800187uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
Christopher Ferrise7b66242017-12-15 11:17:45 -0800188 uint64_t cur_load_bias = load_bias.load();
189 if (cur_load_bias != static_cast<uint64_t>(-1)) {
190 return cur_load_bias;
191 }
192
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800193 {
194 // Make sure no other thread is trying to add the elf to this map.
195 std::lock_guard<std::mutex> guard(mutex_);
196 if (elf != nullptr) {
197 if (elf->valid()) {
Christopher Ferrise7b66242017-12-15 11:17:45 -0800198 cur_load_bias = elf->GetLoadBias();
199 load_bias = cur_load_bias;
200 return cur_load_bias;
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800201 } else {
Christopher Ferrise7b66242017-12-15 11:17:45 -0800202 load_bias = 0;
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800203 return 0;
204 }
205 }
206 }
207
208 // Call lightweight static function that will only read enough of the
209 // elf data to get the load bias.
210 std::unique_ptr<Memory> memory(CreateMemory(process_memory));
Christopher Ferrise7b66242017-12-15 11:17:45 -0800211 cur_load_bias = Elf::GetLoadBias(memory.get());
212 load_bias = cur_load_bias;
213 return cur_load_bias;
Christopher Ferrisb7de5f52017-12-01 21:37:37 -0800214}
215
Christopher Ferrisd226a512017-07-14 10:37:19 -0700216} // namespace unwindstack