1 /* 2 * Copyright (C) 2016 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 #pragma once 18 19 #include <stdint.h> 20 21 #include <atomic> 22 #include <memory> 23 #include <mutex> 24 #include <string> 25 26 #include <unwindstack/Elf.h> 27 #include <unwindstack/SharedString.h> 28 29 namespace unwindstack { 30 31 class MemoryFileAtOffset; 32 33 // Represents virtual memory map (as obtained from /proc/*/maps). 34 // 35 // Note that we have to be surprisingly careful with memory usage here, 36 // since in system-wide profiling this data can take considerable space. 37 // (for example, 400 process * 400 maps * 128 bytes = 20 MB + string data). 38 class MapInfo { 39 public: MapInfo(std::shared_ptr<MapInfo> & prev_map,uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,SharedString name)40 MapInfo(std::shared_ptr<MapInfo>& prev_map, uint64_t start, uint64_t end, uint64_t offset, 41 uint64_t flags, SharedString name) 42 : start_(start), 43 end_(end), 44 offset_(offset), 45 flags_(flags), 46 name_(name), 47 elf_fields_(nullptr), 48 prev_map_(prev_map) {} MapInfo(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,SharedString name)49 MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, SharedString name) 50 : start_(start), 51 end_(end), 52 offset_(offset), 53 flags_(flags), 54 name_(name), 55 elf_fields_(nullptr) {} 56 Create(std::shared_ptr<MapInfo> & prev_map,uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,SharedString name)57 static inline std::shared_ptr<MapInfo> Create(std::shared_ptr<MapInfo>& prev_map, 58 uint64_t start, uint64_t end, uint64_t offset, 59 uint64_t flags, SharedString name) { 60 auto map_info = std::make_shared<MapInfo>(prev_map, start, end, offset, flags, name); 61 if (prev_map) { 62 prev_map->next_map_ = map_info; 63 } 64 return map_info; 65 } Create(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,SharedString name)66 static inline std::shared_ptr<MapInfo> Create(uint64_t start, uint64_t end, uint64_t offset, 67 uint64_t flags, SharedString name) { 68 return std::make_shared<MapInfo>(start, end, offset, flags, name); 69 } 70 71 ~MapInfo(); 72 73 // Cached data for mapped ELF files. 74 // We allocate this structure lazily since there are much fewer ELFs than maps. 75 struct ElfFields { ElfFieldsElfFields76 ElfFields() : load_bias_(UINT64_MAX), build_id_(0) {} 77 78 std::shared_ptr<Elf> elf_; 79 // The offset of the beginning of this mapping to the beginning of the 80 // ELF file. 81 // elf_offset == offset - elf_start_offset. 82 // This value is only non-zero if the offset is non-zero but there is 83 // no elf signature found at that offset. 84 uint64_t elf_offset_ = 0; 85 // This value is the offset into the file of the map in memory that is the 86 // start of the elf. This is not equal to offset when the linker splits 87 // shared libraries into a read-only and read-execute map. 88 uint64_t elf_start_offset_ = 0; 89 90 std::atomic_uint64_t load_bias_; 91 92 // This is a pointer to a new'd std::string. 93 // Using an atomic value means that we don't need to lock and will 94 // make it easier to move to a fine grained lock in the future. 95 std::atomic<SharedString*> build_id_; 96 97 // Set to true if the elf file data is coming from memory. 98 bool memory_backed_elf_ = false; 99 100 // Protect the creation of the elf object. 101 std::mutex elf_mutex_; 102 }; 103 104 // True if the file named by this map is not actually readable and the 105 // elf is using the data in memory. 106 bool ElfFileNotReadable(); 107 108 // This is the previous map with the same name that is not empty and with 109 // a 0 offset. For example, this set of maps: 110 // 1000-2000 r--p 000000 00:00 0 libc.so 111 // 2000-3000 ---p 000000 00:00 0 112 // 3000-4000 r-xp 003000 00:00 0 libc.so 113 // The last map's prev_map would point to the 2000-3000 map, while 114 // GetPrevRealMap() would point to the 1000-2000 map. 115 // NOTE: If a map is encountered that has a non-zero offset, or has a 116 // a name different from the current map, then GetPrevRealMap() 117 // returns nullptr. 118 std::shared_ptr<MapInfo> GetPrevRealMap(); 119 // This is the next map with the same name that is not empty and with 120 // a 0 offset. For the example above, the first map's GetNextRealMap() 121 // would be the 3000-4000 map. 122 // NOTE: If a map is encountered that has a non-zero offset, or has a 123 // a name different from the current map, then GetNextRealMap() 124 // returns nullptr. 125 std::shared_ptr<MapInfo> GetNextRealMap(); 126 127 // This is guaranteed to give out the Elf object associated with the 128 // object. The invariant is that once the Elf object is set under the 129 // lock in a MapInfo object it never changes and is not freed until 130 // the MapInfo object is destructed. GetElfObj()131 inline Elf* GetElfObj() { 132 std::lock_guard<std::mutex> guard(elf_mutex()); 133 return elf().get(); 134 } 135 start()136 inline uint64_t start() const { return start_; } set_start(uint64_t value)137 inline void set_start(uint64_t value) { start_ = value; } 138 end()139 inline uint64_t end() const { return end_; } set_end(uint64_t value)140 inline void set_end(uint64_t value) { end_ = value; } 141 offset()142 inline uint64_t offset() const { return offset_; } set_offset(uint64_t value)143 inline void set_offset(uint64_t value) { offset_ = value; } 144 flags()145 inline uint16_t flags() const { return flags_; } set_flags(uint16_t value)146 inline void set_flags(uint16_t value) { flags_ = value; } 147 name()148 inline SharedString& name() { return name_; } set_name(SharedString & value)149 inline void set_name(SharedString& value) { name_ = value; } set_name(const char * value)150 inline void set_name(const char* value) { name_ = value; } 151 elf()152 inline std::shared_ptr<Elf>& elf() { return GetElfFields().elf_; } set_elf(std::shared_ptr<Elf> & value)153 inline void set_elf(std::shared_ptr<Elf>& value) { GetElfFields().elf_ = value; } set_elf(Elf * value)154 inline void set_elf(Elf* value) { GetElfFields().elf_.reset(value); } 155 elf_offset()156 inline uint64_t elf_offset() { return GetElfFields().elf_offset_; } set_elf_offset(uint64_t value)157 inline void set_elf_offset(uint64_t value) { GetElfFields().elf_offset_ = value; } 158 elf_start_offset()159 inline uint64_t elf_start_offset() { return GetElfFields().elf_start_offset_; } set_elf_start_offset(uint64_t value)160 inline void set_elf_start_offset(uint64_t value) { GetElfFields().elf_start_offset_ = value; } 161 load_bias()162 inline std::atomic_uint64_t& load_bias() { return GetElfFields().load_bias_; } set_load_bias(uint64_t value)163 inline void set_load_bias(uint64_t value) { GetElfFields().load_bias_ = value; } 164 build_id()165 inline std::atomic<SharedString*>& build_id() { return GetElfFields().build_id_; } set_build_id(SharedString * value)166 inline void set_build_id(SharedString* value) { GetElfFields().build_id_ = value; } 167 memory_backed_elf()168 inline bool memory_backed_elf() { return GetElfFields().memory_backed_elf_; } set_memory_backed_elf(bool value)169 inline void set_memory_backed_elf(bool value) { GetElfFields().memory_backed_elf_ = value; } 170 prev_map()171 inline std::shared_ptr<MapInfo> prev_map() const { return prev_map_.lock(); } set_prev_map(std::shared_ptr<MapInfo> & value)172 inline void set_prev_map(std::shared_ptr<MapInfo>& value) { prev_map_ = value; } 173 next_map()174 inline std::shared_ptr<MapInfo> next_map() const { return next_map_.lock(); } set_next_map(std::shared_ptr<MapInfo> & value)175 inline void set_next_map(std::shared_ptr<MapInfo>& value) { next_map_ = value; } 176 177 // This function guarantees it will never return nullptr. 178 Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch); 179 180 // Guaranteed to return the proper value if GetElf() has been called. 181 uint64_t GetLoadBias(); 182 183 // Will get the proper value even if GetElf() hasn't been called. 184 uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory); 185 186 // This returns the name of the map plus the soname if this particular 187 // map represents an elf file that is contained inside of another file. 188 // The format of this soname embedded name is: 189 // file.apk!libutils.so 190 // Otherwise, this function only returns the name of the map. 191 std::string GetFullName(); 192 193 Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory); 194 195 bool GetFunctionName(uint64_t addr, SharedString* name, uint64_t* func_offset); 196 197 // Returns the raw build id read from the elf data. 198 SharedString GetBuildID(); 199 200 // Used internally, and by tests. It sets the value only if it was not already set. 201 SharedString SetBuildID(std::string&& new_build_id); 202 203 // Returns the printable version of the build id (hex dump of raw data). 204 std::string GetPrintableBuildID(); 205 IsBlank()206 inline bool IsBlank() { return offset() == 0 && flags() == 0 && name().empty(); } 207 208 // Returns elf_fields_. It will create the object if it is null. 209 ElfFields& GetElfFields(); 210 211 private: 212 MapInfo(const MapInfo&) = delete; 213 void operator=(const MapInfo&) = delete; 214 215 Memory* GetFileMemory(); 216 bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory); 217 218 // Protect the creation of the elf object. elf_mutex()219 std::mutex& elf_mutex() { return GetElfFields().elf_mutex_; } 220 221 uint64_t start_ = 0; 222 uint64_t end_ = 0; 223 uint64_t offset_ = 0; 224 uint16_t flags_ = 0; 225 SharedString name_; 226 227 std::atomic<ElfFields*> elf_fields_; 228 229 std::weak_ptr<MapInfo> prev_map_; 230 std::weak_ptr<MapInfo> next_map_; 231 }; 232 233 } // namespace unwindstack 234