1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mozglue/linker/Utils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,597 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef Utils_h 1.9 +#define Utils_h 1.10 + 1.11 +#include <stdint.h> 1.12 +#include <stddef.h> 1.13 +#include <sys/mman.h> 1.14 +#include <unistd.h> 1.15 +#include "mozilla/Assertions.h" 1.16 +#include "mozilla/Scoped.h" 1.17 + 1.18 +/** 1.19 + * On architectures that are little endian and that support unaligned reads, 1.20 + * we can use direct type, but on others, we want to have a special class 1.21 + * to handle conversion and alignment issues. 1.22 + */ 1.23 +#if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__)) 1.24 +typedef uint16_t le_uint16; 1.25 +typedef uint32_t le_uint32; 1.26 +#else 1.27 + 1.28 +/** 1.29 + * Template that allows to find an unsigned int type from a (computed) bit size 1.30 + */ 1.31 +template <int s> struct UInt { }; 1.32 +template <> struct UInt<16> { typedef uint16_t Type; }; 1.33 +template <> struct UInt<32> { typedef uint32_t Type; }; 1.34 + 1.35 +/** 1.36 + * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing 1.37 + * conversion from little endian and avoiding alignment issues. 1.38 + */ 1.39 +template <typename T> 1.40 +class le_to_cpu 1.41 +{ 1.42 +public: 1.43 + typedef typename UInt<16 * sizeof(T)>::Type Type; 1.44 + 1.45 + operator Type() const 1.46 + { 1.47 + return (b << (sizeof(T) * 8)) | a; 1.48 + } 1.49 + 1.50 + const le_to_cpu& operator =(const Type &v) 1.51 + { 1.52 + a = v & ((1 << (sizeof(T) * 8)) - 1); 1.53 + b = v >> (sizeof(T) * 8); 1.54 + return *this; 1.55 + } 1.56 + 1.57 + le_to_cpu() { } 1.58 + le_to_cpu(const Type &v) 1.59 + { 1.60 + operator =(v); 1.61 + } 1.62 + 1.63 + const le_to_cpu& operator +=(const Type &v) 1.64 + { 1.65 + return operator =(operator Type() + v); 1.66 + } 1.67 + 1.68 + const le_to_cpu& operator ++(int) 1.69 + { 1.70 + return operator =(operator Type() + 1); 1.71 + } 1.72 + 1.73 +private: 1.74 + T a, b; 1.75 +}; 1.76 + 1.77 +/** 1.78 + * Type definitions 1.79 + */ 1.80 +typedef le_to_cpu<unsigned char> le_uint16; 1.81 +typedef le_to_cpu<le_uint16> le_uint32; 1.82 +#endif 1.83 + 1.84 + 1.85 +/** 1.86 + * AutoCloseFD is a RAII wrapper for POSIX file descriptors 1.87 + */ 1.88 +struct AutoCloseFDTraits 1.89 +{ 1.90 + typedef int type; 1.91 + static int empty() { return -1; } 1.92 + static void release(int fd) { if (fd != -1) close(fd); } 1.93 +}; 1.94 +typedef mozilla::Scoped<AutoCloseFDTraits> AutoCloseFD; 1.95 + 1.96 +/** 1.97 + * AutoCloseFILE is a RAII wrapper for POSIX streams 1.98 + */ 1.99 +struct AutoCloseFILETraits 1.100 +{ 1.101 + typedef FILE *type; 1.102 + static FILE *empty() { return nullptr; } 1.103 + static void release(FILE *f) { if (f) fclose(f); } 1.104 +}; 1.105 +typedef mozilla::Scoped<AutoCloseFILETraits> AutoCloseFILE; 1.106 + 1.107 +/** 1.108 + * Page alignment helpers 1.109 + */ 1.110 +static inline size_t PageSize() 1.111 +{ 1.112 + return 4096; 1.113 +} 1.114 + 1.115 +static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment) 1.116 +{ 1.117 + return ptr & ~(alignment - 1); 1.118 +} 1.119 + 1.120 +template <typename T> 1.121 +static inline T *AlignedPtr(T *ptr, size_t alignment) 1.122 +{ 1.123 + return reinterpret_cast<T *>( 1.124 + AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); 1.125 +} 1.126 + 1.127 +template <typename T> 1.128 +static inline T PageAlignedPtr(T ptr) 1.129 +{ 1.130 + return AlignedPtr(ptr, PageSize()); 1.131 +} 1.132 + 1.133 +static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment) 1.134 +{ 1.135 + return AlignedPtr(ptr + alignment - 1, alignment); 1.136 +} 1.137 + 1.138 +template <typename T> 1.139 +static inline T *AlignedEndPtr(T *ptr, size_t alignment) 1.140 +{ 1.141 + return reinterpret_cast<T *>( 1.142 + AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); 1.143 +} 1.144 + 1.145 +template <typename T> 1.146 +static inline T PageAlignedEndPtr(T ptr) 1.147 +{ 1.148 + return AlignedEndPtr(ptr, PageSize()); 1.149 +} 1.150 + 1.151 +static inline size_t AlignedSize(size_t size, size_t alignment) 1.152 +{ 1.153 + return (size + alignment - 1) & ~(alignment - 1); 1.154 +} 1.155 + 1.156 +static inline size_t PageAlignedSize(size_t size) 1.157 +{ 1.158 + return AlignedSize(size, PageSize()); 1.159 +} 1.160 + 1.161 +static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment) 1.162 +{ 1.163 + return ptr % alignment == 0; 1.164 +} 1.165 + 1.166 +template <typename T> 1.167 +static inline bool IsAlignedPtr(T *ptr, size_t alignment) 1.168 +{ 1.169 + return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment); 1.170 +} 1.171 + 1.172 +template <typename T> 1.173 +static inline bool IsPageAlignedPtr(T ptr) 1.174 +{ 1.175 + return IsAlignedPtr(ptr, PageSize()); 1.176 +} 1.177 + 1.178 +static inline bool IsAlignedSize(size_t size, size_t alignment) 1.179 +{ 1.180 + return size % alignment == 0; 1.181 +} 1.182 + 1.183 +static inline bool IsPageAlignedSize(size_t size) 1.184 +{ 1.185 + return IsAlignedSize(size, PageSize()); 1.186 +} 1.187 + 1.188 +static inline size_t PageNumber(size_t size) 1.189 +{ 1.190 + return (size + PageSize() - 1) / PageSize(); 1.191 +} 1.192 + 1.193 +/** 1.194 + * MemoryRange stores a pointer, size pair. 1.195 + */ 1.196 +class MemoryRange 1.197 +{ 1.198 +public: 1.199 + MemoryRange(void *buf, size_t length): buf(buf), length(length) { } 1.200 + 1.201 + void Assign(void *b, size_t len) { 1.202 + buf = b; 1.203 + length = len; 1.204 + } 1.205 + 1.206 + void Assign(const MemoryRange& other) { 1.207 + buf = other.buf; 1.208 + length = other.length; 1.209 + } 1.210 + 1.211 + void *get() const 1.212 + { 1.213 + return buf; 1.214 + } 1.215 + 1.216 + operator void *() const 1.217 + { 1.218 + return buf; 1.219 + } 1.220 + 1.221 + operator unsigned char *() const 1.222 + { 1.223 + return reinterpret_cast<unsigned char *>(buf); 1.224 + } 1.225 + 1.226 + bool operator ==(void *ptr) const { 1.227 + return buf == ptr; 1.228 + } 1.229 + 1.230 + bool operator ==(unsigned char *ptr) const { 1.231 + return buf == ptr; 1.232 + } 1.233 + 1.234 + void *operator +(off_t offset) const 1.235 + { 1.236 + return reinterpret_cast<char *>(buf) + offset; 1.237 + } 1.238 + 1.239 + /** 1.240 + * Returns whether the given address is within the mapped range 1.241 + */ 1.242 + bool Contains(void *ptr) const 1.243 + { 1.244 + return (ptr >= buf) && (ptr < reinterpret_cast<char *>(buf) + length); 1.245 + } 1.246 + 1.247 + /** 1.248 + * Returns the length of the mapped range 1.249 + */ 1.250 + size_t GetLength() const 1.251 + { 1.252 + return length; 1.253 + } 1.254 + 1.255 + static MemoryRange mmap(void *addr, size_t length, int prot, int flags, 1.256 + int fd, off_t offset) { 1.257 + return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length); 1.258 + } 1.259 + 1.260 +private: 1.261 + void *buf; 1.262 + size_t length; 1.263 +}; 1.264 + 1.265 +/** 1.266 + * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as 1.267 + * a simple void * or unsigned char *. 1.268 + * 1.269 + * It is defined as a derivative of a template that allows to use a 1.270 + * different unmapping strategy. 1.271 + */ 1.272 +template <typename T> 1.273 +class GenericMappedPtr: public MemoryRange 1.274 +{ 1.275 +public: 1.276 + GenericMappedPtr(void *buf, size_t length): MemoryRange(buf, length) { } 1.277 + GenericMappedPtr(const MemoryRange& other): MemoryRange(other) { } 1.278 + GenericMappedPtr(): MemoryRange(MAP_FAILED, 0) { } 1.279 + 1.280 + void Assign(void *b, size_t len) { 1.281 + if (get() != MAP_FAILED) 1.282 + static_cast<T *>(this)->munmap(get(), GetLength()); 1.283 + MemoryRange::Assign(b, len); 1.284 + } 1.285 + 1.286 + void Assign(const MemoryRange& other) { 1.287 + Assign(other.get(), other.GetLength()); 1.288 + } 1.289 + 1.290 + ~GenericMappedPtr() 1.291 + { 1.292 + if (get() != MAP_FAILED) 1.293 + static_cast<T *>(this)->munmap(get(), GetLength()); 1.294 + } 1.295 + 1.296 +}; 1.297 + 1.298 +struct MappedPtr: public GenericMappedPtr<MappedPtr> 1.299 +{ 1.300 + MappedPtr(void *buf, size_t length) 1.301 + : GenericMappedPtr<MappedPtr>(buf, length) { } 1.302 + MappedPtr(const MemoryRange& other) 1.303 + : GenericMappedPtr<MappedPtr>(other) { } 1.304 + MappedPtr(): GenericMappedPtr<MappedPtr>() { } 1.305 + 1.306 +private: 1.307 + friend class GenericMappedPtr<MappedPtr>; 1.308 + void munmap(void *buf, size_t length) 1.309 + { 1.310 + ::munmap(buf, length); 1.311 + } 1.312 +}; 1.313 + 1.314 +/** 1.315 + * UnsizedArray is a way to access raw arrays of data in memory. 1.316 + * 1.317 + * struct S { ... }; 1.318 + * UnsizedArray<S> a(buf); 1.319 + * UnsizedArray<S> b; b.Init(buf); 1.320 + * 1.321 + * This is roughly equivalent to 1.322 + * const S *a = reinterpret_cast<const S *>(buf); 1.323 + * const S *b = nullptr; b = reinterpret_cast<const S *>(buf); 1.324 + * 1.325 + * An UnsizedArray has no known length, and it's up to the caller to make 1.326 + * sure the accessed memory is mapped and makes sense. 1.327 + */ 1.328 +template <typename T> 1.329 +class UnsizedArray 1.330 +{ 1.331 +public: 1.332 + typedef size_t idx_t; 1.333 + 1.334 + /** 1.335 + * Constructors and Initializers 1.336 + */ 1.337 + UnsizedArray(): contents(nullptr) { } 1.338 + UnsizedArray(const void *buf): contents(reinterpret_cast<const T *>(buf)) { } 1.339 + 1.340 + void Init(const void *buf) 1.341 + { 1.342 + MOZ_ASSERT(contents == nullptr); 1.343 + contents = reinterpret_cast<const T *>(buf); 1.344 + } 1.345 + 1.346 + /** 1.347 + * Returns the nth element of the array 1.348 + */ 1.349 + const T &operator[](const idx_t index) const 1.350 + { 1.351 + MOZ_ASSERT(contents); 1.352 + return contents[index]; 1.353 + } 1.354 + 1.355 + operator const T *() const 1.356 + { 1.357 + return contents; 1.358 + } 1.359 + /** 1.360 + * Returns whether the array points somewhere 1.361 + */ 1.362 + operator bool() const 1.363 + { 1.364 + return contents != nullptr; 1.365 + } 1.366 +private: 1.367 + const T *contents; 1.368 +}; 1.369 + 1.370 +/** 1.371 + * Array, like UnsizedArray, is a way to access raw arrays of data in memory. 1.372 + * Unlike UnsizedArray, it has a known length, and is enumerable with an 1.373 + * iterator. 1.374 + * 1.375 + * struct S { ... }; 1.376 + * Array<S> a(buf, len); 1.377 + * UnsizedArray<S> b; b.Init(buf, len); 1.378 + * 1.379 + * In the above examples, len is the number of elements in the array. It is 1.380 + * also possible to initialize an Array with the buffer size: 1.381 + * 1.382 + * Array<S> c; c.InitSize(buf, size); 1.383 + * 1.384 + * It is also possible to initialize an Array in two steps, only providing 1.385 + * one data at a time: 1.386 + * 1.387 + * Array<S> d; 1.388 + * d.Init(buf); 1.389 + * d.Init(len); // or d.InitSize(size); 1.390 + * 1.391 + */ 1.392 +template <typename T> 1.393 +class Array: public UnsizedArray<T> 1.394 +{ 1.395 +public: 1.396 + typedef typename UnsizedArray<T>::idx_t idx_t; 1.397 + 1.398 + /** 1.399 + * Constructors and Initializers 1.400 + */ 1.401 + Array(): UnsizedArray<T>(), length(0) { } 1.402 + Array(const void *buf, const idx_t length) 1.403 + : UnsizedArray<T>(buf), length(length) { } 1.404 + 1.405 + void Init(const void *buf) 1.406 + { 1.407 + UnsizedArray<T>::Init(buf); 1.408 + } 1.409 + 1.410 + void Init(const idx_t len) 1.411 + { 1.412 + MOZ_ASSERT(length == 0); 1.413 + length = len; 1.414 + } 1.415 + 1.416 + void InitSize(const idx_t size) 1.417 + { 1.418 + Init(size / sizeof(T)); 1.419 + } 1.420 + 1.421 + void Init(const void *buf, const idx_t len) 1.422 + { 1.423 + UnsizedArray<T>::Init(buf); 1.424 + Init(len); 1.425 + } 1.426 + 1.427 + void InitSize(const void *buf, const idx_t size) 1.428 + { 1.429 + UnsizedArray<T>::Init(buf); 1.430 + InitSize(size); 1.431 + } 1.432 + 1.433 + /** 1.434 + * Returns the nth element of the array 1.435 + */ 1.436 + const T &operator[](const idx_t index) const 1.437 + { 1.438 + MOZ_ASSERT(index < length); 1.439 + MOZ_ASSERT(operator bool()); 1.440 + return UnsizedArray<T>::operator[](index); 1.441 + } 1.442 + 1.443 + /** 1.444 + * Returns the number of elements in the array 1.445 + */ 1.446 + idx_t numElements() const 1.447 + { 1.448 + return length; 1.449 + } 1.450 + 1.451 + /** 1.452 + * Returns whether the array points somewhere and has at least one element. 1.453 + */ 1.454 + operator bool() const 1.455 + { 1.456 + return (length > 0) && UnsizedArray<T>::operator bool(); 1.457 + } 1.458 + 1.459 + /** 1.460 + * Iterator for an Array. Use is similar to that of STL const_iterators: 1.461 + * 1.462 + * struct S { ... }; 1.463 + * Array<S> a(buf, len); 1.464 + * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) { 1.465 + * // Do something with *it. 1.466 + * } 1.467 + */ 1.468 + class iterator 1.469 + { 1.470 + public: 1.471 + iterator(): item(nullptr) { } 1.472 + 1.473 + const T &operator *() const 1.474 + { 1.475 + return *item; 1.476 + } 1.477 + 1.478 + const T *operator ->() const 1.479 + { 1.480 + return item; 1.481 + } 1.482 + 1.483 + iterator &operator ++() 1.484 + { 1.485 + ++item; 1.486 + return *this; 1.487 + } 1.488 + 1.489 + bool operator<(const iterator &other) const 1.490 + { 1.491 + return item < other.item; 1.492 + } 1.493 + protected: 1.494 + friend class Array<T>; 1.495 + iterator(const T &item): item(&item) { } 1.496 + 1.497 + private: 1.498 + const T *item; 1.499 + }; 1.500 + 1.501 + /** 1.502 + * Returns an iterator pointing at the beginning of the Array 1.503 + */ 1.504 + iterator begin() const { 1.505 + if (length) 1.506 + return iterator(UnsizedArray<T>::operator[](0)); 1.507 + return iterator(); 1.508 + } 1.509 + 1.510 + /** 1.511 + * Returns an iterator pointing past the end of the Array 1.512 + */ 1.513 + iterator end() const { 1.514 + if (length) 1.515 + return iterator(UnsizedArray<T>::operator[](length)); 1.516 + return iterator(); 1.517 + } 1.518 + 1.519 + /** 1.520 + * Reverse iterator for an Array. Use is similar to that of STL 1.521 + * const_reverse_iterators: 1.522 + * 1.523 + * struct S { ... }; 1.524 + * Array<S> a(buf, len); 1.525 + * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) { 1.526 + * // Do something with *it. 1.527 + * } 1.528 + */ 1.529 + class reverse_iterator 1.530 + { 1.531 + public: 1.532 + reverse_iterator(): item(nullptr) { } 1.533 + 1.534 + const T &operator *() const 1.535 + { 1.536 + const T *tmp = item; 1.537 + return *--tmp; 1.538 + } 1.539 + 1.540 + const T *operator ->() const 1.541 + { 1.542 + return &operator*(); 1.543 + } 1.544 + 1.545 + reverse_iterator &operator ++() 1.546 + { 1.547 + --item; 1.548 + return *this; 1.549 + } 1.550 + 1.551 + bool operator<(const reverse_iterator &other) const 1.552 + { 1.553 + return item > other.item; 1.554 + } 1.555 + protected: 1.556 + friend class Array<T>; 1.557 + reverse_iterator(const T &item): item(&item) { } 1.558 + 1.559 + private: 1.560 + const T *item; 1.561 + }; 1.562 + 1.563 + /** 1.564 + * Returns a reverse iterator pointing at the end of the Array 1.565 + */ 1.566 + reverse_iterator rbegin() const { 1.567 + if (length) 1.568 + return reverse_iterator(UnsizedArray<T>::operator[](length)); 1.569 + return reverse_iterator(); 1.570 + } 1.571 + 1.572 + /** 1.573 + * Returns a reverse iterator pointing past the beginning of the Array 1.574 + */ 1.575 + reverse_iterator rend() const { 1.576 + if (length) 1.577 + return reverse_iterator(UnsizedArray<T>::operator[](0)); 1.578 + return reverse_iterator(); 1.579 + } 1.580 +private: 1.581 + idx_t length; 1.582 +}; 1.583 + 1.584 +/** 1.585 + * Transforms a pointer-to-function to a pointer-to-object pointing at the 1.586 + * same address. 1.587 + */ 1.588 +template <typename T> 1.589 +void *FunctionPtr(T func) 1.590 +{ 1.591 + union { 1.592 + void *ptr; 1.593 + T func; 1.594 + } f; 1.595 + f.func = func; 1.596 + return f.ptr; 1.597 +} 1.598 + 1.599 +#endif /* Utils_h */ 1.600 +