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 #ifndef _LIBUNWINDSTACK_MAP_INFO_H
18 #define _LIBUNWINDSTACK_MAP_INFO_H
19 
20 #include <stdint.h>
21 
22 #include <atomic>
23 #include <memory>
24 #include <mutex>
25 #include <string>
26 
27 #include <unwindstack/Elf.h>
28 #include <unwindstack/SharedString.h>
29 
30 namespace unwindstack {
31 
32 class MemoryFileAtOffset;
33 
34 // Represents virtual memory map (as obtained from /proc/*/maps).
35 //
36 // Note that we have to be surprisingly careful with memory usage here,
37 // since in system-wide profiling this data can take considerable space.
38 // (for example, 400 process * 400 maps * 128 bytes = 20 MB + string data).
39 class MapInfo {
40  public:
MapInfo(MapInfo * prev_map,MapInfo * prev_real_map,uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,SharedString name)41   MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
42           uint64_t flags, SharedString name)
43       : start_(start),
44         end_(end),
45         offset_(offset),
46         flags_(flags),
47         name_(name),
48         elf_fields_(nullptr),
49         prev_map_(prev_map),
50         prev_real_map_(prev_real_map) {
51     if (prev_real_map != nullptr) prev_real_map->next_real_map_ = this;
52   }
53   ~MapInfo();
54 
55   // Cached data for mapped ELF files.
56   // We allocate this structure lazily since there are much fewer ELFs than maps.
57   struct ElfFields {
ElfFieldsElfFields58     ElfFields() : load_bias_(INT64_MAX), build_id_(0) {}
59 
60     std::shared_ptr<Elf> elf_;
61     // The offset of the beginning of this mapping to the beginning of the
62     // ELF file.
63     // elf_offset == offset - elf_start_offset.
64     // This value is only non-zero if the offset is non-zero but there is
65     // no elf signature found at that offset.
66     uint64_t elf_offset_ = 0;
67     // This value is the offset into the file of the map in memory that is the
68     // start of the elf. This is not equal to offset when the linker splits
69     // shared libraries into a read-only and read-execute map.
70     uint64_t elf_start_offset_ = 0;
71 
72     std::atomic_int64_t load_bias_;
73 
74     // This is a pointer to a new'd std::string.
75     // Using an atomic value means that we don't need to lock and will
76     // make it easier to move to a fine grained lock in the future.
77     std::atomic<SharedString*> build_id_;
78 
79     // Set to true if the elf file data is coming from memory.
80     bool memory_backed_elf_ = false;
81 
82     // Protect the creation of the elf object.
83     std::mutex elf_mutex_;
84   };
85 
start()86   inline uint64_t start() const { return start_; }
set_start(uint64_t value)87   inline void set_start(uint64_t value) { start_ = value; }
88 
end()89   inline uint64_t end() const { return end_; }
set_end(uint64_t value)90   inline void set_end(uint64_t value) { end_ = value; }
91 
offset()92   inline uint64_t offset() const { return offset_; }
set_offset(uint64_t value)93   inline void set_offset(uint64_t value) { offset_ = value; }
94 
flags()95   inline uint16_t flags() const { return flags_; }
set_flags(uint16_t value)96   inline void set_flags(uint16_t value) { flags_ = value; }
97 
name()98   inline SharedString& name() { return name_; }
set_name(SharedString & value)99   inline void set_name(SharedString& value) { name_ = value; }
set_name(const char * value)100   inline void set_name(const char* value) { name_ = value; }
101 
elf()102   inline std::shared_ptr<Elf>& elf() { return GetElfFields().elf_; }
set_elf(std::shared_ptr<Elf> & value)103   inline void set_elf(std::shared_ptr<Elf>& value) { GetElfFields().elf_ = value; }
set_elf(Elf * value)104   inline void set_elf(Elf* value) { GetElfFields().elf_.reset(value); }
105 
elf_offset()106   inline uint64_t elf_offset() { return GetElfFields().elf_offset_; }
set_elf_offset(uint64_t value)107   inline void set_elf_offset(uint64_t value) { GetElfFields().elf_offset_ = value; }
108 
elf_start_offset()109   inline uint64_t elf_start_offset() { return GetElfFields().elf_start_offset_; }
set_elf_start_offset(uint64_t value)110   inline void set_elf_start_offset(uint64_t value) { GetElfFields().elf_start_offset_ = value; }
111 
load_bias()112   inline std::atomic_int64_t& load_bias() { return GetElfFields().load_bias_; }
set_load_bias(int64_t value)113   inline void set_load_bias(int64_t value) { GetElfFields().load_bias_ = value; }
114 
build_id()115   inline std::atomic<SharedString*>& build_id() { return GetElfFields().build_id_; }
set_build_id(SharedString * value)116   inline void set_build_id(SharedString* value) { GetElfFields().build_id_ = value; }
117 
memory_backed_elf()118   inline bool memory_backed_elf() { return GetElfFields().memory_backed_elf_; }
set_memory_backed_elf(bool value)119   inline void set_memory_backed_elf(bool value) { GetElfFields().memory_backed_elf_ = value; }
120 
prev_map()121   inline MapInfo* prev_map() const { return prev_map_; }
set_prev_map(MapInfo * value)122   inline void set_prev_map(MapInfo* value) { prev_map_ = value; }
123 
prev_real_map()124   inline MapInfo* prev_real_map() const { return prev_real_map_; }
set_prev_real_map(MapInfo * value)125   inline void set_prev_real_map(MapInfo* value) { prev_real_map_ = value; }
126 
next_real_map()127   inline MapInfo* next_real_map() const { return next_real_map_; }
set_next_real_map(MapInfo * value)128   inline void set_next_real_map(MapInfo* value) { next_real_map_ = value; }
129 
130   // This function guarantees it will never return nullptr.
131   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
132 
133   uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
134 
135   Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
136 
137   bool GetFunctionName(uint64_t addr, SharedString* name, uint64_t* func_offset);
138 
139   // Returns the raw build id read from the elf data.
140   SharedString GetBuildID();
141 
142   // Used internally, and by tests. It sets the value only if it was not already set.
143   SharedString SetBuildID(std::string&& new_build_id);
144 
145   // Returns the printable version of the build id (hex dump of raw data).
146   std::string GetPrintableBuildID();
147 
IsBlank()148   inline bool IsBlank() { return offset() == 0 && flags() == 0 && name().empty(); }
149 
150   // Returns elf_fields_. It will create the object if it is null.
151   ElfFields& GetElfFields();
152 
153  private:
154   MapInfo(const MapInfo&) = delete;
155   void operator=(const MapInfo&) = delete;
156 
157   Memory* GetFileMemory();
158   bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory);
159 
160   // Protect the creation of the elf object.
elf_mutex()161   std::mutex& elf_mutex() { return GetElfFields().elf_mutex_; }
162 
163   uint64_t start_ = 0;
164   uint64_t end_ = 0;
165   uint64_t offset_ = 0;
166   uint16_t flags_ = 0;
167   SharedString name_;
168 
169   std::atomic<ElfFields*> elf_fields_;
170 
171   MapInfo* prev_map_ = nullptr;
172   // This is the previous map that is not empty with a 0 offset. For
173   // example, this set of maps:
174   //  1000-2000  r--p 000000 00:00 0 libc.so
175   //  2000-3000  ---p 000000 00:00 0 libc.so
176   //  3000-4000  r-xp 003000 00:00 0 libc.so
177   // The last map's prev_map would point to the 2000-3000 map, while the
178   // prev_real_map would point to the 1000-2000 map.
179   MapInfo* prev_real_map_ = nullptr;
180 
181   // Same as above but set to point to the next map.
182   MapInfo* next_real_map_ = nullptr;
183 };
184 
185 }  // namespace unwindstack
186 
187 #endif  // _LIBUNWINDSTACK_MAP_INFO_H
188