Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(465)

Side by Side Diff: third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove findbugs issues. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crazy_linker_proc_maps.h"
6
7 #include <inttypes.h>
8 #include <limits.h>
9
10 #include "elf_traits.h"
11 #include "crazy_linker_debug.h"
12 #include "crazy_linker_line_reader.h"
13 #include "crazy_linker_util.h"
14 #include "crazy_linker_system.h"
15
16 namespace crazy {
17
18 namespace {
19
20 // Decompose the components of a /proc/$PID/maps file into multiple
21 // components. |line| should be the address of a zero-terminated line
22 // of input. On success, returns true and sets |*entry|, false otherwise.
23 //
24 // IMPORTANT: On success, |entry->path| will point into the input line,
25 // the caller will have to copy the string into a different location if
26 // it needs to persist it.
27 bool ParseProcMapsLine(const char* line,
28 const char* line_end,
29 ProcMaps::Entry* entry) {
30 // Example input lines on a 64-bit system, one cannot assume that
31 // everything is properly sized.
32 //
33 // 00400000-0040b000 r-xp 00000000 08:01 6570708 /b in/cat
34 // 0060a000-0060b000 r--p 0000a000 08:01 6570708 /b in/cat
35 // 0060b000-0060c000 rw-p 0000b000 08:01 6570708 /b in/cat
36 // 01dd0000-01df1000 rw-p 00000000 00:00 0 [h eap]
37 // 7f4b8d4d7000-7f4b8e22a000 r--p 00000000 08:01 38666648 /u sr/lib/locale/locale-archive
38 // 7f4b8e22a000-7f4b8e3df000 r-xp 00000000 08:01 28836281 /l ib/x86_64-linux-gnu/libc-2.15.so
39 // 7f4b8e3df000-7f4b8e5de000 ---p 001b5000 08:01 28836281 /l ib/x86_64-linux-gnu/libc-2.15.so
40 // 7f4b8e5de000-7f4b8e5e2000 r--p 001b4000 08:01 28836281 /l ib/x86_64-linux-gnu/libc-2.15.so
41 // 7f4b8e5e2000-7f4b8e5e4000 rw-p 001b8000 08:01 28836281 /l ib/x86_64-linux-gnu/libc-2.15.so
42 const char* p = line;
43 for (int token = 0; token < 7; ++token) {
44 char separator = (token == 0) ? '-' : ' ';
45 // skip leading token separators first.
46 while (p < line_end && *p == separator)
47 p++;
48
49 // find start and end of current token, and compute start of
50 // next search.
51 const char* tok_start = p;
52 const char* tok_end = static_cast<const char*>(
53 memchr(p, separator, line_end - p));
54 if (!tok_end) {
55 tok_end = line_end;
56 p = line_end;
57 } else {
58 p = tok_end + 1;
59 }
60
61 if (tok_end == tok_start) {
62 if (token == 6) {
63 // empty token can happen for index 6, when there is no path
64 // element on the line. This corresponds to anonymous memory
65 // mapped segments.
66 entry->path = NULL;
67 entry->path_len = 0;
68 break;
69 }
70 return false;
71 }
72
73 switch (token) {
74 case 0: // vma_start
75 entry->vma_start = static_cast<size_t>(
76 strtoumax(tok_start, NULL, 16));
77 break;
78
79 case 1: // vma_end
80 entry->vma_end = static_cast<size_t>(
81 strtoumax(tok_start, NULL, 16));
82 break;
83
84 case 2: // protection bits
85 {
86 int flags = 0;
87 for (const char* t = tok_start; t < tok_end; ++t) {
88 if (*t == 'r')
89 flags |= PROT_READ;
90 if (*t == 'w')
91 flags |= PROT_WRITE;
92 if (*t == 'x')
93 flags |= PROT_EXEC;
94 }
95 entry->prot_flags = flags;
96 }
97 break;
98
99 case 3: // page offset
100 entry->load_offset = static_cast<size_t>(
101 strtoumax(tok_start, NULL, 16)) * PAGE_SIZE;
102 break;
103
104 case 6: // path
105 // Get rid of trailing newlines, if any.
106 while (tok_end > tok_start && tok_end[-1] == '\n')
107 tok_end--;
108 entry->path = tok_start;
109 entry->path_len = tok_end - tok_start;
110 break;
111
112 default: // ignore all other tokens.
113 ;
114 }
115 }
116 return true;
117 }
118
119 } // namespace
120
121 // Internal implementation of ProcMaps class.
122 class ProcMapsInternal {
123 public:
124 ProcMapsInternal()
125 : index_(0), entries_() {
126 }
127
128 ~ProcMapsInternal() {
129 Reset();
130 }
131
132 bool Open(const char* path) {
133 Reset();
134 LineReader reader(path);
135 index_ = 0;
136 while (reader.GetNextLine()) {
137 ProcMaps::Entry entry;
138 memset(&entry, 0, sizeof(entry));
139 if (!ParseProcMapsLine(reader.line(),
140 reader.line() + reader.length(),
141 &entry)) {
142 // Ignore broken lines.
143 continue;
144 }
145
146 // Reallocate path.
147 const char* old_path = entry.path;
148 if (old_path) {
149 char* new_path = static_cast<char*>(::malloc(entry.path_len + 1));
150 ::memcpy(new_path, old_path, entry.path_len);
151 new_path[entry.path_len] = '\0';
152 entry.path = const_cast<const char*>(new_path);
153 }
154
155 entries_.PushBack(entry);
156 }
157 return true;
158 }
159
160 void Rewind() {
161 index_ = 0;
162 }
163
164 bool GetNextEntry(ProcMaps::Entry* entry) {
165 if (index_ >= entries_.GetCount())
166 return false;
167
168 *entry = entries_[index_++];
169 return true;
170 }
171
172 private:
173 void Reset() {
174 for (size_t n = 0; n < entries_.GetCount(); ++n) {
175 ProcMaps::Entry& entry = entries_[n];
176 ::free(const_cast<char*>(entry.path));
177 }
178 entries_.Resize(0);
179 }
180
181 size_t index_;
182 Vector<ProcMaps::Entry> entries_;
183 };
184
185 ProcMaps::ProcMaps() {
186 internal_ = new ProcMapsInternal();
187 (void) internal_->Open("/proc/self/maps");
188 }
189
190 ProcMaps::ProcMaps(pid_t pid) {
191 internal_ = new ProcMapsInternal();
192 char maps_file[32];
193 snprintf(maps_file, sizeof maps_file, "/proc/%u/maps", pid);
194 (void) internal_->Open(maps_file);
195 }
196
197 ProcMaps::~ProcMaps() {
198 delete internal_;
199 }
200
201 void ProcMaps::Rewind() {
202 internal_->Rewind();
203 }
204
205 bool ProcMaps::GetNextEntry(Entry* entry) {
206 return internal_->GetNextEntry(entry);
207 }
208
209 int ProcMaps::GetProtectionFlagsForAddress(void* address) {
210 size_t vma_addr = reinterpret_cast<size_t>(address);
211 internal_->Rewind();
212 ProcMaps::Entry entry;
213 while (internal_->GetNextEntry(&entry)) {
214 if (entry.vma_start <= vma_addr && vma_addr < entry.vma_end)
215 return entry.prot_flags;
216 }
217 return 0;
218 }
219
220 bool FindElfBinaryForAddress(void* address,
221 uintptr_t* load_address,
222 char* path_buffer,
223 size_t path_buffer_len) {
224 ProcMaps self_maps;
225 ProcMaps::Entry entry;
226
227 uintptr_t addr = reinterpret_cast<uintptr_t>(address);
228
229 while (self_maps.GetNextEntry(&entry)) {
230 if (entry.vma_start <= addr && addr < entry.vma_end) {
231 *load_address = entry.vma_start;
232 if (!entry.path) {
233 LOG("Could not find ELF binary path!?\n");
234 return false;
235 }
236 if (entry.path_len >= path_buffer_len) {
237 LOG("ELF binary path too long: '%s'\n", entry.path);
238 return false;
239 }
240 memcpy(path_buffer, entry.path, entry.path_len);
241 path_buffer[entry.path_len] = '\0';
242 return true;
243 }
244 }
245 return false;
246 }
247
248 // Returns the current protection bit flags for the page holding a given
249 // address. Returns true on success, or false if the address is not mapped.
250 bool FindProtectionFlagsForAddress(void* address, int* prot_flags) {
251 ProcMaps self_maps;
252 ProcMaps::Entry entry;
253
254 uintptr_t addr = reinterpret_cast<uintptr_t>(address);
255
256 while (self_maps.GetNextEntry(&entry)) {
257 if (entry.vma_start <= addr && addr < entry.vma_end) {
258 *prot_flags = entry.prot_flags;
259 return true;
260 }
261 }
262 return false;
263 }
264
265 bool FindLoadAddressForFile(const char* file_name,
266 uintptr_t* load_address,
267 uintptr_t* load_offset) {
268 size_t file_name_len = strlen(file_name);
269 bool is_base_name = (strchr(file_name, '/') == NULL);
270 ProcMaps self_maps;
271 ProcMaps::Entry entry;
272
273 while (self_maps.GetNextEntry(&entry)) {
274 // Skip vDSO et al.
275 if (entry.path_len == 0 || entry.path[0] == '[')
276 continue;
277
278 const char* entry_name = entry.path;
279 size_t entry_len = entry.path_len;
280
281 if (is_base_name) {
282 const char* p = reinterpret_cast<const char*>(
283 ::memrchr(entry.path, '/', entry.path_len));
284 if (p) {
285 entry_name = p + 1;
286 entry_len = entry.path_len - (p - entry.path) - 1;
287 }
288 }
289
290 if (file_name_len == entry_len &&
291 !memcmp(file_name, entry_name, entry_len)) {
292 *load_address = entry.vma_start;
293 *load_offset = entry.load_offset;
294 return true;
295 }
296 }
297
298 return false;
299 }
300
301 } // namespace crazy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698