xref: /aosp_15_r20/system/unwinding/libunwindstack/Maps.cpp (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 #include <errno.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <fcntl.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <inttypes.h>
20*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <stdio.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <string.h>
23*eb293b8fSAndroid Build Coastguard Worker #include <sys/mman.h>
24*eb293b8fSAndroid Build Coastguard Worker #include <sys/types.h>
25*eb293b8fSAndroid Build Coastguard Worker #include <unistd.h>
26*eb293b8fSAndroid Build Coastguard Worker 
27*eb293b8fSAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
28*eb293b8fSAndroid Build Coastguard Worker #include <procinfo/process_map.h>
29*eb293b8fSAndroid Build Coastguard Worker 
30*eb293b8fSAndroid Build Coastguard Worker #include <algorithm>
31*eb293b8fSAndroid Build Coastguard Worker #include <cctype>
32*eb293b8fSAndroid Build Coastguard Worker #include <memory>
33*eb293b8fSAndroid Build Coastguard Worker #include <string>
34*eb293b8fSAndroid Build Coastguard Worker #include <vector>
35*eb293b8fSAndroid Build Coastguard Worker 
36*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Elf.h>
37*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Maps.h>
38*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
39*eb293b8fSAndroid Build Coastguard Worker 
40*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
41*eb293b8fSAndroid Build Coastguard Worker 
Find(uint64_t pc)42*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<MapInfo> Maps::Find(uint64_t pc) {
43*eb293b8fSAndroid Build Coastguard Worker   if (maps_.empty()) {
44*eb293b8fSAndroid Build Coastguard Worker     return nullptr;
45*eb293b8fSAndroid Build Coastguard Worker   }
46*eb293b8fSAndroid Build Coastguard Worker   size_t first = 0;
47*eb293b8fSAndroid Build Coastguard Worker   size_t last = maps_.size();
48*eb293b8fSAndroid Build Coastguard Worker   while (first < last) {
49*eb293b8fSAndroid Build Coastguard Worker     size_t index = (first + last) / 2;
50*eb293b8fSAndroid Build Coastguard Worker     const auto& cur = maps_[index];
51*eb293b8fSAndroid Build Coastguard Worker     if (pc >= cur->start() && pc < cur->end()) {
52*eb293b8fSAndroid Build Coastguard Worker       return cur;
53*eb293b8fSAndroid Build Coastguard Worker     } else if (pc < cur->start()) {
54*eb293b8fSAndroid Build Coastguard Worker       last = index;
55*eb293b8fSAndroid Build Coastguard Worker     } else {
56*eb293b8fSAndroid Build Coastguard Worker       first = index + 1;
57*eb293b8fSAndroid Build Coastguard Worker     }
58*eb293b8fSAndroid Build Coastguard Worker   }
59*eb293b8fSAndroid Build Coastguard Worker   return nullptr;
60*eb293b8fSAndroid Build Coastguard Worker }
61*eb293b8fSAndroid Build Coastguard Worker 
Parse()62*eb293b8fSAndroid Build Coastguard Worker bool Maps::Parse() {
63*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> prev_map;
64*eb293b8fSAndroid Build Coastguard Worker   return android::procinfo::ReadMapFile(GetMapsFile(),
65*eb293b8fSAndroid Build Coastguard Worker                       [&](const android::procinfo::MapInfo& mapinfo) {
66*eb293b8fSAndroid Build Coastguard Worker     // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
67*eb293b8fSAndroid Build Coastguard Worker     auto flags = mapinfo.flags;
68*eb293b8fSAndroid Build Coastguard Worker     if (strncmp(mapinfo.name.c_str(), "/dev/", 5) == 0 &&
69*eb293b8fSAndroid Build Coastguard Worker         strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) {
70*eb293b8fSAndroid Build Coastguard Worker       flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
71*eb293b8fSAndroid Build Coastguard Worker     }
72*eb293b8fSAndroid Build Coastguard Worker     maps_.emplace_back(
73*eb293b8fSAndroid Build Coastguard Worker         MapInfo::Create(prev_map, mapinfo.start, mapinfo.end, mapinfo.pgoff, flags, mapinfo.name));
74*eb293b8fSAndroid Build Coastguard Worker     prev_map = maps_.back();
75*eb293b8fSAndroid Build Coastguard Worker   });
76*eb293b8fSAndroid Build Coastguard Worker }
77*eb293b8fSAndroid Build Coastguard Worker 
Add(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,const std::string & name)78*eb293b8fSAndroid Build Coastguard Worker void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
79*eb293b8fSAndroid Build Coastguard Worker                const std::string& name) {
80*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> prev_map(maps_.empty() ? nullptr : maps_.back());
81*eb293b8fSAndroid Build Coastguard Worker   auto map_info = MapInfo::Create(prev_map, start, end, offset, flags, name);
82*eb293b8fSAndroid Build Coastguard Worker   maps_.emplace_back(std::move(map_info));
83*eb293b8fSAndroid Build Coastguard Worker }
84*eb293b8fSAndroid Build Coastguard Worker 
Add(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,const std::string & name,uint64_t load_bias)85*eb293b8fSAndroid Build Coastguard Worker void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
86*eb293b8fSAndroid Build Coastguard Worker                const std::string& name, uint64_t load_bias) {
87*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> prev_map(maps_.empty() ? nullptr : maps_.back());
88*eb293b8fSAndroid Build Coastguard Worker   auto map_info = MapInfo::Create(prev_map, start, end, offset, flags, name);
89*eb293b8fSAndroid Build Coastguard Worker   map_info->set_load_bias(load_bias);
90*eb293b8fSAndroid Build Coastguard Worker   maps_.emplace_back(std::move(map_info));
91*eb293b8fSAndroid Build Coastguard Worker }
92*eb293b8fSAndroid Build Coastguard Worker 
Sort()93*eb293b8fSAndroid Build Coastguard Worker void Maps::Sort() {
94*eb293b8fSAndroid Build Coastguard Worker   if (maps_.empty()) {
95*eb293b8fSAndroid Build Coastguard Worker     return;
96*eb293b8fSAndroid Build Coastguard Worker   }
97*eb293b8fSAndroid Build Coastguard Worker 
98*eb293b8fSAndroid Build Coastguard Worker   std::sort(maps_.begin(), maps_.end(),
99*eb293b8fSAndroid Build Coastguard Worker             [](const std::shared_ptr<MapInfo>& a, const std::shared_ptr<MapInfo>& b) {
100*eb293b8fSAndroid Build Coastguard Worker               return a->start() < b->start();
101*eb293b8fSAndroid Build Coastguard Worker             });
102*eb293b8fSAndroid Build Coastguard Worker 
103*eb293b8fSAndroid Build Coastguard Worker   // Set prev_map and next_map on the info objects.
104*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> prev_map;
105*eb293b8fSAndroid Build Coastguard Worker   // Set the last next_map to nullptr.
106*eb293b8fSAndroid Build Coastguard Worker   maps_.back()->set_next_map(prev_map);
107*eb293b8fSAndroid Build Coastguard Worker   for (auto& map_info : maps_) {
108*eb293b8fSAndroid Build Coastguard Worker     map_info->set_prev_map(prev_map);
109*eb293b8fSAndroid Build Coastguard Worker     if (prev_map) {
110*eb293b8fSAndroid Build Coastguard Worker       prev_map->set_next_map(map_info);
111*eb293b8fSAndroid Build Coastguard Worker     }
112*eb293b8fSAndroid Build Coastguard Worker     prev_map = map_info;
113*eb293b8fSAndroid Build Coastguard Worker   }
114*eb293b8fSAndroid Build Coastguard Worker }
115*eb293b8fSAndroid Build Coastguard Worker 
Parse()116*eb293b8fSAndroid Build Coastguard Worker bool BufferMaps::Parse() {
117*eb293b8fSAndroid Build Coastguard Worker   std::string content(buffer_);
118*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> prev_map;
119*eb293b8fSAndroid Build Coastguard Worker   return android::procinfo::ReadMapFileContent(
120*eb293b8fSAndroid Build Coastguard Worker       &content[0], [&](const android::procinfo::MapInfo& mapinfo) {
121*eb293b8fSAndroid Build Coastguard Worker         // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
122*eb293b8fSAndroid Build Coastguard Worker         auto flags = mapinfo.flags;
123*eb293b8fSAndroid Build Coastguard Worker         if (strncmp(mapinfo.name.c_str(), "/dev/", 5) == 0 &&
124*eb293b8fSAndroid Build Coastguard Worker             strncmp(mapinfo.name.c_str() + 5, "ashmem/", 7) != 0) {
125*eb293b8fSAndroid Build Coastguard Worker           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
126*eb293b8fSAndroid Build Coastguard Worker         }
127*eb293b8fSAndroid Build Coastguard Worker         maps_.emplace_back(MapInfo::Create(prev_map, mapinfo.start, mapinfo.end, mapinfo.pgoff,
128*eb293b8fSAndroid Build Coastguard Worker                                            flags, mapinfo.name));
129*eb293b8fSAndroid Build Coastguard Worker         prev_map = maps_.back();
130*eb293b8fSAndroid Build Coastguard Worker       });
131*eb293b8fSAndroid Build Coastguard Worker }
132*eb293b8fSAndroid Build Coastguard Worker 
GetMapsFile() const133*eb293b8fSAndroid Build Coastguard Worker const std::string RemoteMaps::GetMapsFile() const {
134*eb293b8fSAndroid Build Coastguard Worker   return "/proc/" + std::to_string(pid_) + "/maps";
135*eb293b8fSAndroid Build Coastguard Worker }
136*eb293b8fSAndroid Build Coastguard Worker 
GetMapsFile() const137*eb293b8fSAndroid Build Coastguard Worker const std::string LocalUpdatableMaps::GetMapsFile() const {
138*eb293b8fSAndroid Build Coastguard Worker   return "/proc/self/maps";
139*eb293b8fSAndroid Build Coastguard Worker }
140*eb293b8fSAndroid Build Coastguard Worker 
LocalUpdatableMaps()141*eb293b8fSAndroid Build Coastguard Worker LocalUpdatableMaps::LocalUpdatableMaps() : Maps() {
142*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_init(&maps_rwlock_, nullptr);
143*eb293b8fSAndroid Build Coastguard Worker }
144*eb293b8fSAndroid Build Coastguard Worker 
Find(uint64_t pc)145*eb293b8fSAndroid Build Coastguard Worker std::shared_ptr<MapInfo> LocalUpdatableMaps::Find(uint64_t pc) {
146*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_rdlock(&maps_rwlock_);
147*eb293b8fSAndroid Build Coastguard Worker   std::shared_ptr<MapInfo> map_info = Maps::Find(pc);
148*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_unlock(&maps_rwlock_);
149*eb293b8fSAndroid Build Coastguard Worker 
150*eb293b8fSAndroid Build Coastguard Worker   if (map_info == nullptr) {
151*eb293b8fSAndroid Build Coastguard Worker     pthread_rwlock_wrlock(&maps_rwlock_);
152*eb293b8fSAndroid Build Coastguard Worker     // This is guaranteed not to invalidate any previous MapInfo objects so
153*eb293b8fSAndroid Build Coastguard Worker     // we don't need to worry about any MapInfo* values already in use.
154*eb293b8fSAndroid Build Coastguard Worker     if (Reparse()) {
155*eb293b8fSAndroid Build Coastguard Worker       map_info = Maps::Find(pc);
156*eb293b8fSAndroid Build Coastguard Worker     }
157*eb293b8fSAndroid Build Coastguard Worker     pthread_rwlock_unlock(&maps_rwlock_);
158*eb293b8fSAndroid Build Coastguard Worker   }
159*eb293b8fSAndroid Build Coastguard Worker 
160*eb293b8fSAndroid Build Coastguard Worker   return map_info;
161*eb293b8fSAndroid Build Coastguard Worker }
162*eb293b8fSAndroid Build Coastguard Worker 
Parse()163*eb293b8fSAndroid Build Coastguard Worker bool LocalUpdatableMaps::Parse() {
164*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_wrlock(&maps_rwlock_);
165*eb293b8fSAndroid Build Coastguard Worker   bool parsed = Maps::Parse();
166*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_unlock(&maps_rwlock_);
167*eb293b8fSAndroid Build Coastguard Worker   return parsed;
168*eb293b8fSAndroid Build Coastguard Worker }
169*eb293b8fSAndroid Build Coastguard Worker 
ForEachMapInfo(std::function<bool (MapInfo *)> const & find_var)170*eb293b8fSAndroid Build Coastguard Worker void LocalUpdatableMaps::ForEachMapInfo(std::function<bool(MapInfo*)> const& find_var) {
171*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_rdlock(&maps_rwlock_);
172*eb293b8fSAndroid Build Coastguard Worker   for (const auto& info : maps_) {
173*eb293b8fSAndroid Build Coastguard Worker     if (!find_var(info.get())) break;
174*eb293b8fSAndroid Build Coastguard Worker   }
175*eb293b8fSAndroid Build Coastguard Worker   pthread_rwlock_unlock(&maps_rwlock_);
176*eb293b8fSAndroid Build Coastguard Worker }
177*eb293b8fSAndroid Build Coastguard Worker 
Reparse(bool * any_changed)178*eb293b8fSAndroid Build Coastguard Worker bool LocalUpdatableMaps::Reparse(/*out*/ bool* any_changed) {
179*eb293b8fSAndroid Build Coastguard Worker   // New maps will be added at the end without deleting the old ones.
180*eb293b8fSAndroid Build Coastguard Worker   size_t last_map_idx = maps_.size();
181*eb293b8fSAndroid Build Coastguard Worker   if (!Maps::Parse()) {
182*eb293b8fSAndroid Build Coastguard Worker     maps_.resize(last_map_idx);
183*eb293b8fSAndroid Build Coastguard Worker     return false;
184*eb293b8fSAndroid Build Coastguard Worker   }
185*eb293b8fSAndroid Build Coastguard Worker 
186*eb293b8fSAndroid Build Coastguard Worker   size_t search_map_idx = 0;
187*eb293b8fSAndroid Build Coastguard Worker   size_t num_deleted_old_entries = 0;
188*eb293b8fSAndroid Build Coastguard Worker   size_t num_deleted_new_entries = 0;
189*eb293b8fSAndroid Build Coastguard Worker   for (size_t new_map_idx = last_map_idx; new_map_idx < maps_.size(); new_map_idx++) {
190*eb293b8fSAndroid Build Coastguard Worker     auto& new_map_info = maps_[new_map_idx];
191*eb293b8fSAndroid Build Coastguard Worker     uint64_t start = new_map_info->start();
192*eb293b8fSAndroid Build Coastguard Worker     uint64_t end = new_map_info->end();
193*eb293b8fSAndroid Build Coastguard Worker     uint64_t flags = new_map_info->flags();
194*eb293b8fSAndroid Build Coastguard Worker     const SharedString& name = new_map_info->name();
195*eb293b8fSAndroid Build Coastguard Worker     for (size_t old_map_idx = search_map_idx; old_map_idx < last_map_idx; old_map_idx++) {
196*eb293b8fSAndroid Build Coastguard Worker       auto& info = maps_[old_map_idx];
197*eb293b8fSAndroid Build Coastguard Worker       if (start == info->start() && end == info->end() && flags == info->flags() &&
198*eb293b8fSAndroid Build Coastguard Worker           name == info->name()) {
199*eb293b8fSAndroid Build Coastguard Worker         search_map_idx = old_map_idx + 1;
200*eb293b8fSAndroid Build Coastguard Worker         // Since we are throwing away a map from the new list, need to
201*eb293b8fSAndroid Build Coastguard Worker         // adjust the next/prev pointers in the old map entry.
202*eb293b8fSAndroid Build Coastguard Worker         auto prev = new_map_info->prev_map();
203*eb293b8fSAndroid Build Coastguard Worker         auto next = new_map_info->next_map();
204*eb293b8fSAndroid Build Coastguard Worker         info->set_prev_map(prev);
205*eb293b8fSAndroid Build Coastguard Worker         info->set_next_map(next);
206*eb293b8fSAndroid Build Coastguard Worker 
207*eb293b8fSAndroid Build Coastguard Worker         // Fix up the pointers in the prev and next entries.
208*eb293b8fSAndroid Build Coastguard Worker         if (prev != nullptr) {
209*eb293b8fSAndroid Build Coastguard Worker           prev->set_next_map(info);
210*eb293b8fSAndroid Build Coastguard Worker         }
211*eb293b8fSAndroid Build Coastguard Worker         if (next != nullptr) {
212*eb293b8fSAndroid Build Coastguard Worker           next->set_prev_map(info);
213*eb293b8fSAndroid Build Coastguard Worker         }
214*eb293b8fSAndroid Build Coastguard Worker 
215*eb293b8fSAndroid Build Coastguard Worker         maps_[new_map_idx] = nullptr;
216*eb293b8fSAndroid Build Coastguard Worker         num_deleted_new_entries++;
217*eb293b8fSAndroid Build Coastguard Worker         break;
218*eb293b8fSAndroid Build Coastguard Worker       } else if (info->start() > start) {
219*eb293b8fSAndroid Build Coastguard Worker         // Stop, there isn't going to be a match.
220*eb293b8fSAndroid Build Coastguard Worker         search_map_idx = old_map_idx;
221*eb293b8fSAndroid Build Coastguard Worker         break;
222*eb293b8fSAndroid Build Coastguard Worker       }
223*eb293b8fSAndroid Build Coastguard Worker 
224*eb293b8fSAndroid Build Coastguard Worker       // Never delete these maps, they may be in use. The assumption is
225*eb293b8fSAndroid Build Coastguard Worker       // that there will only every be a handful of these so waiting
226*eb293b8fSAndroid Build Coastguard Worker       // to destroy them is not too expensive.
227*eb293b8fSAndroid Build Coastguard Worker       // Since these are all shared_ptrs, we can just remove the references.
228*eb293b8fSAndroid Build Coastguard Worker       // Any code still holding on to the pointer, will still have a
229*eb293b8fSAndroid Build Coastguard Worker       // valid pointer after this.
230*eb293b8fSAndroid Build Coastguard Worker       search_map_idx = old_map_idx + 1;
231*eb293b8fSAndroid Build Coastguard Worker       maps_[old_map_idx] = nullptr;
232*eb293b8fSAndroid Build Coastguard Worker       num_deleted_old_entries++;
233*eb293b8fSAndroid Build Coastguard Worker     }
234*eb293b8fSAndroid Build Coastguard Worker     if (search_map_idx >= last_map_idx) {
235*eb293b8fSAndroid Build Coastguard Worker       break;
236*eb293b8fSAndroid Build Coastguard Worker     }
237*eb293b8fSAndroid Build Coastguard Worker   }
238*eb293b8fSAndroid Build Coastguard Worker 
239*eb293b8fSAndroid Build Coastguard Worker   for (size_t i = search_map_idx; i < last_map_idx; i++) {
240*eb293b8fSAndroid Build Coastguard Worker     maps_[i] = nullptr;
241*eb293b8fSAndroid Build Coastguard Worker     num_deleted_old_entries++;
242*eb293b8fSAndroid Build Coastguard Worker   }
243*eb293b8fSAndroid Build Coastguard Worker 
244*eb293b8fSAndroid Build Coastguard Worker   // Sort all of the values such that the nullptrs wind up at the end, then
245*eb293b8fSAndroid Build Coastguard Worker   // resize them away.
246*eb293b8fSAndroid Build Coastguard Worker   std::sort(maps_.begin(), maps_.end(), [](const auto& a, const auto& b) {
247*eb293b8fSAndroid Build Coastguard Worker     if (a == nullptr) {
248*eb293b8fSAndroid Build Coastguard Worker       return false;
249*eb293b8fSAndroid Build Coastguard Worker     } else if (b == nullptr) {
250*eb293b8fSAndroid Build Coastguard Worker       return true;
251*eb293b8fSAndroid Build Coastguard Worker     }
252*eb293b8fSAndroid Build Coastguard Worker     return a->start() < b->start();
253*eb293b8fSAndroid Build Coastguard Worker   });
254*eb293b8fSAndroid Build Coastguard Worker   maps_.resize(maps_.size() - num_deleted_old_entries - num_deleted_new_entries);
255*eb293b8fSAndroid Build Coastguard Worker 
256*eb293b8fSAndroid Build Coastguard Worker   if (any_changed != nullptr) {
257*eb293b8fSAndroid Build Coastguard Worker     *any_changed = num_deleted_old_entries != 0 || maps_.size() != last_map_idx;
258*eb293b8fSAndroid Build Coastguard Worker   }
259*eb293b8fSAndroid Build Coastguard Worker 
260*eb293b8fSAndroid Build Coastguard Worker   return true;
261*eb293b8fSAndroid Build Coastguard Worker }
262*eb293b8fSAndroid Build Coastguard Worker 
263*eb293b8fSAndroid Build Coastguard Worker }  // namespace unwindstack
264