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