mozglue/linker/Utils.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial