• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android-base/stringprintf.h>
26 
27 #include <unwindstack/Elf.h>
28 #include <unwindstack/MapInfo.h>
29 #include <unwindstack/Maps.h>
30 #include <unwindstack/Memory.h>
31 
32 namespace unwindstack {
33 
InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset * memory)34 bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
35   // One last attempt, see if the previous map is read-only with the
36   // same name and stretches across this map.
37   if (prev_map == nullptr || prev_map->flags != PROT_READ) {
38     return false;
39   }
40 
41   uint64_t map_size = end - prev_map->end;
42   if (!memory->Init(name, prev_map->offset, map_size)) {
43     return false;
44   }
45 
46   uint64_t max_size;
47   if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
48     return false;
49   }
50 
51   if (!memory->Init(name, prev_map->offset, max_size)) {
52     return false;
53   }
54 
55   elf_offset = offset - prev_map->offset;
56   elf_start_offset = prev_map->offset;
57   return true;
58 }
59 
GetFileMemory()60 Memory* MapInfo::GetFileMemory() {
61   std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
62   if (offset == 0) {
63     if (memory->Init(name, 0)) {
64       return memory.release();
65     }
66     return nullptr;
67   }
68 
69   // These are the possibilities when the offset is non-zero.
70   // - There is an elf file embedded in a file, and the offset is the
71   //   the start of the elf in the file.
72   // - There is an elf file embedded in a file, and the offset is the
73   //   the start of the executable part of the file. The actual start
74   //   of the elf is in the read-only segment preceeding this map.
75   // - The whole file is an elf file, and the offset needs to be saved.
76   //
77   // Map in just the part of the file for the map. If this is not
78   // a valid elf, then reinit as if the whole file is an elf file.
79   // If the offset is a valid elf, then determine the size of the map
80   // and reinit to that size. This is needed because the dynamic linker
81   // only maps in a portion of the original elf, and never the symbol
82   // file data.
83   uint64_t map_size = end - start;
84   if (!memory->Init(name, offset, map_size)) {
85     return nullptr;
86   }
87 
88   // Check if the start of this map is an embedded elf.
89   uint64_t max_size = 0;
90   if (Elf::GetInfo(memory.get(), &max_size)) {
91     elf_start_offset = offset;
92     if (max_size > map_size) {
93       if (memory->Init(name, offset, max_size)) {
94         return memory.release();
95       }
96       // Try to reinit using the default map_size.
97       if (memory->Init(name, offset, map_size)) {
98         return memory.release();
99       }
100       elf_start_offset = 0;
101       return nullptr;
102     }
103     return memory.release();
104   }
105 
106   // No elf at offset, try to init as if the whole file is an elf.
107   if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
108     elf_offset = offset;
109     // Need to check how to set the elf start offset. If this map is not
110     // the r-x map of a r-- map, then use the real offset value. Otherwise,
111     // use 0.
112     if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ ||
113         prev_map->name != name) {
114       elf_start_offset = offset;
115     }
116     return memory.release();
117   }
118 
119   // See if the map previous to this one contains a read-only map
120   // that represents the real start of the elf data.
121   if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) {
122     return memory.release();
123   }
124 
125   // Failed to find elf at start of file or at read-only map, return
126   // file object from the current map.
127   if (memory->Init(name, offset, map_size)) {
128     return memory.release();
129   }
130   return nullptr;
131 }
132 
CreateMemory(const std::shared_ptr<Memory> & process_memory)133 Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
134   if (end <= start) {
135     return nullptr;
136   }
137 
138   elf_offset = 0;
139 
140   // Fail on device maps.
141   if (flags & MAPS_FLAGS_DEVICE_MAP) {
142     return nullptr;
143   }
144 
145   // First try and use the file associated with the info.
146   if (!name.empty()) {
147     Memory* memory = GetFileMemory();
148     if (memory != nullptr) {
149       return memory;
150     }
151   }
152 
153   if (process_memory == nullptr) {
154     return nullptr;
155   }
156 
157   // Need to verify that this elf is valid. It's possible that
158   // only part of the elf file to be mapped into memory is in the executable
159   // map. In this case, there will be another read-only map that includes the
160   // first part of the elf file. This is done if the linker rosegment
161   // option is used.
162   std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
163   if (Elf::IsValidElf(memory.get())) {
164     memory_backed_elf = true;
165     return memory.release();
166   }
167 
168   // Find the read-only map by looking at the previous map. The linker
169   // doesn't guarantee that this invariant will always be true. However,
170   // if that changes, there is likely something else that will change and
171   // break something.
172   if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
173       prev_map->offset >= offset) {
174     return nullptr;
175   }
176 
177   // Make sure that relative pc values are corrected properly.
178   elf_offset = offset - prev_map->offset;
179   // Use this as the elf start offset, otherwise, you always get offsets into
180   // the r-x section, which is not quite the right information.
181   elf_start_offset = prev_map->offset;
182 
183   MemoryRanges* ranges = new MemoryRanges;
184   ranges->Insert(
185       new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
186   ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
187 
188   memory_backed_elf = true;
189   return ranges;
190 }
191 
GetElf(const std::shared_ptr<Memory> & process_memory,ArchEnum expected_arch)192 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
193   {
194     // Make sure no other thread is trying to add the elf to this map.
195     std::lock_guard<std::mutex> guard(mutex_);
196 
197     if (elf.get() != nullptr) {
198       return elf.get();
199     }
200 
201     bool locked = false;
202     if (Elf::CachingEnabled() && !name.empty()) {
203       Elf::CacheLock();
204       locked = true;
205       if (Elf::CacheGet(this)) {
206         Elf::CacheUnlock();
207         return elf.get();
208       }
209     }
210 
211     Memory* memory = CreateMemory(process_memory);
212     if (locked) {
213       if (Elf::CacheAfterCreateMemory(this)) {
214         delete memory;
215         Elf::CacheUnlock();
216         return elf.get();
217       }
218     }
219     elf.reset(new Elf(memory));
220     // If the init fails, keep the elf around as an invalid object so we
221     // don't try to reinit the object.
222     elf->Init();
223     if (elf->valid() && expected_arch != elf->arch()) {
224       // Make the elf invalid, mismatch between arch and expected arch.
225       elf->Invalidate();
226     }
227 
228     if (locked) {
229       Elf::CacheAdd(this);
230       Elf::CacheUnlock();
231     }
232   }
233 
234   // If there is a read-only map then a read-execute map that represents the
235   // same elf object, make sure the previous map is using the same elf
236   // object if it hasn't already been set.
237   if (prev_map != nullptr && elf_start_offset != offset && prev_map->offset == elf_start_offset &&
238       prev_map->name == name) {
239     std::lock_guard<std::mutex> guard(prev_map->mutex_);
240     if (prev_map->elf.get() == nullptr) {
241       prev_map->elf = elf;
242       prev_map->memory_backed_elf = memory_backed_elf;
243     }
244   }
245   return elf.get();
246 }
247 
GetFunctionName(uint64_t addr,std::string * name,uint64_t * func_offset)248 bool MapInfo::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
249   {
250     // Make sure no other thread is trying to update this elf object.
251     std::lock_guard<std::mutex> guard(mutex_);
252     if (elf == nullptr) {
253       return false;
254     }
255   }
256   // No longer need the lock, once the elf object is created, it is not deleted
257   // until this object is deleted.
258   return elf->GetFunctionName(addr, name, func_offset);
259 }
260 
GetLoadBias(const std::shared_ptr<Memory> & process_memory)261 uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
262   uint64_t cur_load_bias = load_bias.load();
263   if (cur_load_bias != static_cast<uint64_t>(-1)) {
264     return cur_load_bias;
265   }
266 
267   {
268     // Make sure no other thread is trying to add the elf to this map.
269     std::lock_guard<std::mutex> guard(mutex_);
270     if (elf != nullptr) {
271       if (elf->valid()) {
272         cur_load_bias = elf->GetLoadBias();
273         load_bias = cur_load_bias;
274         return cur_load_bias;
275       } else {
276         load_bias = 0;
277         return 0;
278       }
279     }
280   }
281 
282   // Call lightweight static function that will only read enough of the
283   // elf data to get the load bias.
284   std::unique_ptr<Memory> memory(CreateMemory(process_memory));
285   cur_load_bias = Elf::GetLoadBias(memory.get());
286   load_bias = cur_load_bias;
287   return cur_load_bias;
288 }
289 
~MapInfo()290 MapInfo::~MapInfo() {
291   uintptr_t id = build_id.load();
292   if (id != 0) {
293     delete reinterpret_cast<std::string*>(id);
294   }
295 }
296 
GetBuildID()297 std::string MapInfo::GetBuildID() {
298   uintptr_t id = build_id.load();
299   if (build_id != 0) {
300     return *reinterpret_cast<std::string*>(id);
301   }
302 
303   // No need to lock, at worst if multiple threads do this at the same
304   // time it should be detected and only one thread should win and
305   // save the data.
306   std::unique_ptr<std::string> cur_build_id(new std::string);
307 
308   // Now need to see if the elf object exists.
309   // Make sure no other thread is trying to add the elf to this map.
310   mutex_.lock();
311   Elf* elf_obj = elf.get();
312   mutex_.unlock();
313   if (elf_obj != nullptr) {
314     *cur_build_id = elf_obj->GetBuildID();
315   } else {
316     // This will only work if we can get the file associated with this memory.
317     // If this is only available in memory, then the section name information
318     // is not present and we will not be able to find the build id info.
319     std::unique_ptr<Memory> memory(GetFileMemory());
320     if (memory != nullptr) {
321       *cur_build_id = Elf::GetBuildID(memory.get());
322     }
323   }
324 
325   id = reinterpret_cast<uintptr_t>(cur_build_id.get());
326   uintptr_t expected_id = 0;
327   if (build_id.compare_exchange_weak(expected_id, id)) {
328     // Value saved, so make sure the memory is not freed.
329     cur_build_id.release();
330   }
331   return *reinterpret_cast<std::string*>(id);
332 }
333 
GetPrintableBuildID()334 std::string MapInfo::GetPrintableBuildID() {
335   std::string raw_build_id = GetBuildID();
336   if (raw_build_id.empty()) {
337     return "";
338   }
339   std::string printable_build_id;
340   for (const char& c : raw_build_id) {
341     // Use %hhx to avoid sign extension on abis that have signed chars.
342     printable_build_id += android::base::StringPrintf("%02hhx", c);
343   }
344   return printable_build_id;
345 }
346 
347 }  // namespace unwindstack
348