Home | History | Annotate | Download | only in libunwindstack
      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