mozglue/linker/Utils.h

branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
equal deleted inserted replaced
-1:000000000000 0:6890861894d6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #ifndef Utils_h
6 #define Utils_h
7
8 #include <stdint.h>
9 #include <stddef.h>
10 #include <sys/mman.h>
11 #include <unistd.h>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Scoped.h"
14
15 /**
16 * On architectures that are little endian and that support unaligned reads,
17 * we can use direct type, but on others, we want to have a special class
18 * to handle conversion and alignment issues.
19 */
20 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__))
21 typedef uint16_t le_uint16;
22 typedef uint32_t le_uint32;
23 #else
24
25 /**
26 * Template that allows to find an unsigned int type from a (computed) bit size
27 */
28 template <int s> struct UInt { };
29 template <> struct UInt<16> { typedef uint16_t Type; };
30 template <> struct UInt<32> { typedef uint32_t Type; };
31
32 /**
33 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing
34 * conversion from little endian and avoiding alignment issues.
35 */
36 template <typename T>
37 class le_to_cpu
38 {
39 public:
40 typedef typename UInt<16 * sizeof(T)>::Type Type;
41
42 operator Type() const
43 {
44 return (b << (sizeof(T) * 8)) | a;
45 }
46
47 const le_to_cpu& operator =(const Type &v)
48 {
49 a = v & ((1 << (sizeof(T) * 8)) - 1);
50 b = v >> (sizeof(T) * 8);
51 return *this;
52 }
53
54 le_to_cpu() { }
55 le_to_cpu(const Type &v)
56 {
57 operator =(v);
58 }
59
60 const le_to_cpu& operator +=(const Type &v)
61 {
62 return operator =(operator Type() + v);
63 }
64
65 const le_to_cpu& operator ++(int)
66 {
67 return operator =(operator Type() + 1);
68 }
69
70 private:
71 T a, b;
72 };
73
74 /**
75 * Type definitions
76 */
77 typedef le_to_cpu<unsigned char> le_uint16;
78 typedef le_to_cpu<le_uint16> le_uint32;
79 #endif
80
81
82 /**
83 * AutoCloseFD is a RAII wrapper for POSIX file descriptors
84 */
85 struct AutoCloseFDTraits
86 {
87 typedef int type;
88 static int empty() { return -1; }
89 static void release(int fd) { if (fd != -1) close(fd); }
90 };
91 typedef mozilla::Scoped<AutoCloseFDTraits> AutoCloseFD;
92
93 /**
94 * AutoCloseFILE is a RAII wrapper for POSIX streams
95 */
96 struct AutoCloseFILETraits
97 {
98 typedef FILE *type;
99 static FILE *empty() { return nullptr; }
100 static void release(FILE *f) { if (f) fclose(f); }
101 };
102 typedef mozilla::Scoped<AutoCloseFILETraits> AutoCloseFILE;
103
104 /**
105 * Page alignment helpers
106 */
107 static inline size_t PageSize()
108 {
109 return 4096;
110 }
111
112 static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment)
113 {
114 return ptr & ~(alignment - 1);
115 }
116
117 template <typename T>
118 static inline T *AlignedPtr(T *ptr, size_t alignment)
119 {
120 return reinterpret_cast<T *>(
121 AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
122 }
123
124 template <typename T>
125 static inline T PageAlignedPtr(T ptr)
126 {
127 return AlignedPtr(ptr, PageSize());
128 }
129
130 static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment)
131 {
132 return AlignedPtr(ptr + alignment - 1, alignment);
133 }
134
135 template <typename T>
136 static inline T *AlignedEndPtr(T *ptr, size_t alignment)
137 {
138 return reinterpret_cast<T *>(
139 AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
140 }
141
142 template <typename T>
143 static inline T PageAlignedEndPtr(T ptr)
144 {
145 return AlignedEndPtr(ptr, PageSize());
146 }
147
148 static inline size_t AlignedSize(size_t size, size_t alignment)
149 {
150 return (size + alignment - 1) & ~(alignment - 1);
151 }
152
153 static inline size_t PageAlignedSize(size_t size)
154 {
155 return AlignedSize(size, PageSize());
156 }
157
158 static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment)
159 {
160 return ptr % alignment == 0;
161 }
162
163 template <typename T>
164 static inline bool IsAlignedPtr(T *ptr, size_t alignment)
165 {
166 return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment);
167 }
168
169 template <typename T>
170 static inline bool IsPageAlignedPtr(T ptr)
171 {
172 return IsAlignedPtr(ptr, PageSize());
173 }
174
175 static inline bool IsAlignedSize(size_t size, size_t alignment)
176 {
177 return size % alignment == 0;
178 }
179
180 static inline bool IsPageAlignedSize(size_t size)
181 {
182 return IsAlignedSize(size, PageSize());
183 }
184
185 static inline size_t PageNumber(size_t size)
186 {
187 return (size + PageSize() - 1) / PageSize();
188 }
189
190 /**
191 * MemoryRange stores a pointer, size pair.
192 */
193 class MemoryRange
194 {
195 public:
196 MemoryRange(void *buf, size_t length): buf(buf), length(length) { }
197
198 void Assign(void *b, size_t len) {
199 buf = b;
200 length = len;
201 }
202
203 void Assign(const MemoryRange& other) {
204 buf = other.buf;
205 length = other.length;
206 }
207
208 void *get() const
209 {
210 return buf;
211 }
212
213 operator void *() const
214 {
215 return buf;
216 }
217
218 operator unsigned char *() const
219 {
220 return reinterpret_cast<unsigned char *>(buf);
221 }
222
223 bool operator ==(void *ptr) const {
224 return buf == ptr;
225 }
226
227 bool operator ==(unsigned char *ptr) const {
228 return buf == ptr;
229 }
230
231 void *operator +(off_t offset) const
232 {
233 return reinterpret_cast<char *>(buf) + offset;
234 }
235
236 /**
237 * Returns whether the given address is within the mapped range
238 */
239 bool Contains(void *ptr) const
240 {
241 return (ptr >= buf) && (ptr < reinterpret_cast<char *>(buf) + length);
242 }
243
244 /**
245 * Returns the length of the mapped range
246 */
247 size_t GetLength() const
248 {
249 return length;
250 }
251
252 static MemoryRange mmap(void *addr, size_t length, int prot, int flags,
253 int fd, off_t offset) {
254 return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length);
255 }
256
257 private:
258 void *buf;
259 size_t length;
260 };
261
262 /**
263 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
264 * a simple void * or unsigned char *.
265 *
266 * It is defined as a derivative of a template that allows to use a
267 * different unmapping strategy.
268 */
269 template <typename T>
270 class GenericMappedPtr: public MemoryRange
271 {
272 public:
273 GenericMappedPtr(void *buf, size_t length): MemoryRange(buf, length) { }
274 GenericMappedPtr(const MemoryRange& other): MemoryRange(other) { }
275 GenericMappedPtr(): MemoryRange(MAP_FAILED, 0) { }
276
277 void Assign(void *b, size_t len) {
278 if (get() != MAP_FAILED)
279 static_cast<T *>(this)->munmap(get(), GetLength());
280 MemoryRange::Assign(b, len);
281 }
282
283 void Assign(const MemoryRange& other) {
284 Assign(other.get(), other.GetLength());
285 }
286
287 ~GenericMappedPtr()
288 {
289 if (get() != MAP_FAILED)
290 static_cast<T *>(this)->munmap(get(), GetLength());
291 }
292
293 };
294
295 struct MappedPtr: public GenericMappedPtr<MappedPtr>
296 {
297 MappedPtr(void *buf, size_t length)
298 : GenericMappedPtr<MappedPtr>(buf, length) { }
299 MappedPtr(const MemoryRange& other)
300 : GenericMappedPtr<MappedPtr>(other) { }
301 MappedPtr(): GenericMappedPtr<MappedPtr>() { }
302
303 private:
304 friend class GenericMappedPtr<MappedPtr>;
305 void munmap(void *buf, size_t length)
306 {
307 ::munmap(buf, length);
308 }
309 };
310
311 /**
312 * UnsizedArray is a way to access raw arrays of data in memory.
313 *
314 * struct S { ... };
315 * UnsizedArray<S> a(buf);
316 * UnsizedArray<S> b; b.Init(buf);
317 *
318 * This is roughly equivalent to
319 * const S *a = reinterpret_cast<const S *>(buf);
320 * const S *b = nullptr; b = reinterpret_cast<const S *>(buf);
321 *
322 * An UnsizedArray has no known length, and it's up to the caller to make
323 * sure the accessed memory is mapped and makes sense.
324 */
325 template <typename T>
326 class UnsizedArray
327 {
328 public:
329 typedef size_t idx_t;
330
331 /**
332 * Constructors and Initializers
333 */
334 UnsizedArray(): contents(nullptr) { }
335 UnsizedArray(const void *buf): contents(reinterpret_cast<const T *>(buf)) { }
336
337 void Init(const void *buf)
338 {
339 MOZ_ASSERT(contents == nullptr);
340 contents = reinterpret_cast<const T *>(buf);
341 }
342
343 /**
344 * Returns the nth element of the array
345 */
346 const T &operator[](const idx_t index) const
347 {
348 MOZ_ASSERT(contents);
349 return contents[index];
350 }
351
352 operator const T *() const
353 {
354 return contents;
355 }
356 /**
357 * Returns whether the array points somewhere
358 */
359 operator bool() const
360 {
361 return contents != nullptr;
362 }
363 private:
364 const T *contents;
365 };
366
367 /**
368 * Array, like UnsizedArray, is a way to access raw arrays of data in memory.
369 * Unlike UnsizedArray, it has a known length, and is enumerable with an
370 * iterator.
371 *
372 * struct S { ... };
373 * Array<S> a(buf, len);
374 * UnsizedArray<S> b; b.Init(buf, len);
375 *
376 * In the above examples, len is the number of elements in the array. It is
377 * also possible to initialize an Array with the buffer size:
378 *
379 * Array<S> c; c.InitSize(buf, size);
380 *
381 * It is also possible to initialize an Array in two steps, only providing
382 * one data at a time:
383 *
384 * Array<S> d;
385 * d.Init(buf);
386 * d.Init(len); // or d.InitSize(size);
387 *
388 */
389 template <typename T>
390 class Array: public UnsizedArray<T>
391 {
392 public:
393 typedef typename UnsizedArray<T>::idx_t idx_t;
394
395 /**
396 * Constructors and Initializers
397 */
398 Array(): UnsizedArray<T>(), length(0) { }
399 Array(const void *buf, const idx_t length)
400 : UnsizedArray<T>(buf), length(length) { }
401
402 void Init(const void *buf)
403 {
404 UnsizedArray<T>::Init(buf);
405 }
406
407 void Init(const idx_t len)
408 {
409 MOZ_ASSERT(length == 0);
410 length = len;
411 }
412
413 void InitSize(const idx_t size)
414 {
415 Init(size / sizeof(T));
416 }
417
418 void Init(const void *buf, const idx_t len)
419 {
420 UnsizedArray<T>::Init(buf);
421 Init(len);
422 }
423
424 void InitSize(const void *buf, const idx_t size)
425 {
426 UnsizedArray<T>::Init(buf);
427 InitSize(size);
428 }
429
430 /**
431 * Returns the nth element of the array
432 */
433 const T &operator[](const idx_t index) const
434 {
435 MOZ_ASSERT(index < length);
436 MOZ_ASSERT(operator bool());
437 return UnsizedArray<T>::operator[](index);
438 }
439
440 /**
441 * Returns the number of elements in the array
442 */
443 idx_t numElements() const
444 {
445 return length;
446 }
447
448 /**
449 * Returns whether the array points somewhere and has at least one element.
450 */
451 operator bool() const
452 {
453 return (length > 0) && UnsizedArray<T>::operator bool();
454 }
455
456 /**
457 * Iterator for an Array. Use is similar to that of STL const_iterators:
458 *
459 * struct S { ... };
460 * Array<S> a(buf, len);
461 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
462 * // Do something with *it.
463 * }
464 */
465 class iterator
466 {
467 public:
468 iterator(): item(nullptr) { }
469
470 const T &operator *() const
471 {
472 return *item;
473 }
474
475 const T *operator ->() const
476 {
477 return item;
478 }
479
480 iterator &operator ++()
481 {
482 ++item;
483 return *this;
484 }
485
486 bool operator<(const iterator &other) const
487 {
488 return item < other.item;
489 }
490 protected:
491 friend class Array<T>;
492 iterator(const T &item): item(&item) { }
493
494 private:
495 const T *item;
496 };
497
498 /**
499 * Returns an iterator pointing at the beginning of the Array
500 */
501 iterator begin() const {
502 if (length)
503 return iterator(UnsizedArray<T>::operator[](0));
504 return iterator();
505 }
506
507 /**
508 * Returns an iterator pointing past the end of the Array
509 */
510 iterator end() const {
511 if (length)
512 return iterator(UnsizedArray<T>::operator[](length));
513 return iterator();
514 }
515
516 /**
517 * Reverse iterator for an Array. Use is similar to that of STL
518 * const_reverse_iterators:
519 *
520 * struct S { ... };
521 * Array<S> a(buf, len);
522 * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) {
523 * // Do something with *it.
524 * }
525 */
526 class reverse_iterator
527 {
528 public:
529 reverse_iterator(): item(nullptr) { }
530
531 const T &operator *() const
532 {
533 const T *tmp = item;
534 return *--tmp;
535 }
536
537 const T *operator ->() const
538 {
539 return &operator*();
540 }
541
542 reverse_iterator &operator ++()
543 {
544 --item;
545 return *this;
546 }
547
548 bool operator<(const reverse_iterator &other) const
549 {
550 return item > other.item;
551 }
552 protected:
553 friend class Array<T>;
554 reverse_iterator(const T &item): item(&item) { }
555
556 private:
557 const T *item;
558 };
559
560 /**
561 * Returns a reverse iterator pointing at the end of the Array
562 */
563 reverse_iterator rbegin() const {
564 if (length)
565 return reverse_iterator(UnsizedArray<T>::operator[](length));
566 return reverse_iterator();
567 }
568
569 /**
570 * Returns a reverse iterator pointing past the beginning of the Array
571 */
572 reverse_iterator rend() const {
573 if (length)
574 return reverse_iterator(UnsizedArray<T>::operator[](0));
575 return reverse_iterator();
576 }
577 private:
578 idx_t length;
579 };
580
581 /**
582 * Transforms a pointer-to-function to a pointer-to-object pointing at the
583 * same address.
584 */
585 template <typename T>
586 void *FunctionPtr(T func)
587 {
588 union {
589 void *ptr;
590 T func;
591 } f;
592 f.func = func;
593 return f.ptr;
594 }
595
596 #endif /* Utils_h */
597

mercurial