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