mozglue/linker/ElfLoader.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 ElfLoader_h
michael@0 6 #define ElfLoader_h
michael@0 7
michael@0 8 #include <vector>
michael@0 9 #include <dlfcn.h>
michael@0 10 #include <signal.h>
michael@0 11 #include "mozilla/RefPtr.h"
michael@0 12 #include "Zip.h"
michael@0 13 #include "Elfxx.h"
michael@0 14 #include "Mappable.h"
michael@0 15
michael@0 16 /**
michael@0 17 * dlfcn.h replacement functions
michael@0 18 */
michael@0 19 extern "C" {
michael@0 20 void *__wrap_dlopen(const char *path, int flags);
michael@0 21 const char *__wrap_dlerror(void);
michael@0 22 void *__wrap_dlsym(void *handle, const char *symbol);
michael@0 23 int __wrap_dlclose(void *handle);
michael@0 24
michael@0 25 #ifndef HAVE_DLADDR
michael@0 26 typedef struct {
michael@0 27 const char *dli_fname;
michael@0 28 void *dli_fbase;
michael@0 29 const char *dli_sname;
michael@0 30 void *dli_saddr;
michael@0 31 } Dl_info;
michael@0 32 #endif
michael@0 33 int __wrap_dladdr(void *addr, Dl_info *info);
michael@0 34
michael@0 35 struct dl_phdr_info {
michael@0 36 Elf::Addr dlpi_addr;
michael@0 37 const char *dlpi_name;
michael@0 38 const Elf::Phdr *dlpi_phdr;
michael@0 39 Elf::Half dlpi_phnum;
michael@0 40 };
michael@0 41
michael@0 42 typedef int (*dl_phdr_cb)(struct dl_phdr_info *, size_t, void *);
michael@0 43 int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
michael@0 44
michael@0 45 #ifdef __ARM_EABI__
michael@0 46 const void *__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount);
michael@0 47 #endif
michael@0 48
michael@0 49 /**
michael@0 50 * faulty.lib public API
michael@0 51 */
michael@0 52 MFBT_API size_t
michael@0 53 __dl_get_mappable_length(void *handle);
michael@0 54
michael@0 55 MFBT_API void *
michael@0 56 __dl_mmap(void *handle, void *addr, size_t length, off_t offset);
michael@0 57
michael@0 58 MFBT_API void
michael@0 59 __dl_munmap(void *handle, void *addr, size_t length);
michael@0 60
michael@0 61 MFBT_API bool
michael@0 62 IsSignalHandlingBroken();
michael@0 63
michael@0 64 }
michael@0 65
michael@0 66 /**
michael@0 67 * Specialize RefCounted template for LibHandle. We may get references to
michael@0 68 * LibHandles during the execution of their destructor, so we need
michael@0 69 * RefCounted<LibHandle>::Release to support some reentrancy. See further
michael@0 70 * below.
michael@0 71 */
michael@0 72 class LibHandle;
michael@0 73
michael@0 74 namespace mozilla {
michael@0 75 namespace detail {
michael@0 76
michael@0 77 template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
michael@0 78
michael@0 79 template <> inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted()
michael@0 80 {
michael@0 81 MOZ_ASSERT(refCnt == 0x7fffdead);
michael@0 82 }
michael@0 83
michael@0 84 } /* namespace detail */
michael@0 85 } /* namespace mozilla */
michael@0 86
michael@0 87 /**
michael@0 88 * Abstract class for loaded libraries. Libraries may be loaded through the
michael@0 89 * system linker or this linker, both cases will be derived from this class.
michael@0 90 */
michael@0 91 class LibHandle: public mozilla::AtomicRefCounted<LibHandle>
michael@0 92 {
michael@0 93 public:
michael@0 94 MOZ_DECLARE_REFCOUNTED_TYPENAME(LibHandle)
michael@0 95 /**
michael@0 96 * Constructor. Takes the path of the loaded library and will store a copy
michael@0 97 * of the leaf name.
michael@0 98 */
michael@0 99 LibHandle(const char *path)
michael@0 100 : directRefCnt(0), path(path ? strdup(path) : nullptr), mappable(nullptr) { }
michael@0 101
michael@0 102 /**
michael@0 103 * Destructor.
michael@0 104 */
michael@0 105 virtual ~LibHandle();
michael@0 106
michael@0 107 /**
michael@0 108 * Returns the pointer to the address to which the given symbol resolves
michael@0 109 * inside the library. It is not supposed to resolve the symbol in other
michael@0 110 * libraries, although in practice, it will for system libraries.
michael@0 111 */
michael@0 112 virtual void *GetSymbolPtr(const char *symbol) const = 0;
michael@0 113
michael@0 114 /**
michael@0 115 * Returns whether the given address is part of the virtual address space
michael@0 116 * covered by the loaded library.
michael@0 117 */
michael@0 118 virtual bool Contains(void *addr) const = 0;
michael@0 119
michael@0 120 /**
michael@0 121 * Returns the file name of the library without the containing directory.
michael@0 122 */
michael@0 123 const char *GetName() const;
michael@0 124
michael@0 125 /**
michael@0 126 * Returns the full path of the library, when available. Otherwise, returns
michael@0 127 * the file name.
michael@0 128 */
michael@0 129 const char *GetPath() const
michael@0 130 {
michael@0 131 return path;
michael@0 132 }
michael@0 133
michael@0 134 /**
michael@0 135 * Library handles can be referenced from other library handles or
michael@0 136 * externally (when dlopen()ing using this linker). We need to be
michael@0 137 * able to distinguish between the two kind of referencing for better
michael@0 138 * bookkeeping.
michael@0 139 */
michael@0 140 void AddDirectRef()
michael@0 141 {
michael@0 142 ++directRefCnt;
michael@0 143 mozilla::AtomicRefCounted<LibHandle>::AddRef();
michael@0 144 }
michael@0 145
michael@0 146 /**
michael@0 147 * Releases a direct reference, and returns whether there are any direct
michael@0 148 * references left.
michael@0 149 */
michael@0 150 bool ReleaseDirectRef()
michael@0 151 {
michael@0 152 bool ret = false;
michael@0 153 if (directRefCnt) {
michael@0 154 MOZ_ASSERT(directRefCnt <=
michael@0 155 mozilla::AtomicRefCounted<LibHandle>::refCount());
michael@0 156 if (--directRefCnt)
michael@0 157 ret = true;
michael@0 158 mozilla::AtomicRefCounted<LibHandle>::Release();
michael@0 159 }
michael@0 160 return ret;
michael@0 161 }
michael@0 162
michael@0 163 /**
michael@0 164 * Returns the number of direct references
michael@0 165 */
michael@0 166 MozRefCountType DirectRefCount()
michael@0 167 {
michael@0 168 return directRefCnt;
michael@0 169 }
michael@0 170
michael@0 171 /**
michael@0 172 * Returns the complete size of the file or stream behind the library
michael@0 173 * handle.
michael@0 174 */
michael@0 175 size_t GetMappableLength() const;
michael@0 176
michael@0 177 /**
michael@0 178 * Returns a memory mapping of the file or stream behind the library
michael@0 179 * handle.
michael@0 180 */
michael@0 181 void *MappableMMap(void *addr, size_t length, off_t offset) const;
michael@0 182
michael@0 183 /**
michael@0 184 * Unmaps a memory mapping of the file or stream behind the library
michael@0 185 * handle.
michael@0 186 */
michael@0 187 void MappableMUnmap(void *addr, size_t length) const;
michael@0 188
michael@0 189 #ifdef __ARM_EABI__
michael@0 190 /**
michael@0 191 * Find the address and entry count of the ARM.exidx section
michael@0 192 * associated with the library
michael@0 193 */
michael@0 194 virtual const void *FindExidx(int *pcount) const = 0;
michael@0 195 #endif
michael@0 196
michael@0 197 protected:
michael@0 198 /**
michael@0 199 * Returns a mappable object for use by MappableMMap and related functions.
michael@0 200 */
michael@0 201 virtual Mappable *GetMappable() const = 0;
michael@0 202
michael@0 203 /**
michael@0 204 * Returns whether the handle is a SystemElf or not. (short of a better way
michael@0 205 * to do this without RTTI)
michael@0 206 */
michael@0 207 friend class ElfLoader;
michael@0 208 friend class CustomElf;
michael@0 209 friend class SEGVHandler;
michael@0 210 virtual bool IsSystemElf() const { return false; }
michael@0 211
michael@0 212 private:
michael@0 213 MozRefCountType directRefCnt;
michael@0 214 char *path;
michael@0 215
michael@0 216 /* Mappable object keeping the result of GetMappable() */
michael@0 217 mutable mozilla::RefPtr<Mappable> mappable;
michael@0 218 };
michael@0 219
michael@0 220 /**
michael@0 221 * Specialized RefCounted<LibHandle>::Release. Under normal operation, when
michael@0 222 * refCnt reaches 0, the LibHandle is deleted. Its refCnt is however increased
michael@0 223 * to 1 on normal builds, and 0x7fffdead on debug builds so that the LibHandle
michael@0 224 * can still be referenced while the destructor is executing. The refCnt is
michael@0 225 * allowed to grow > 0x7fffdead, but not to decrease under that value, which
michael@0 226 * would mean too many Releases from within the destructor.
michael@0 227 */
michael@0 228 namespace mozilla {
michael@0 229 namespace detail {
michael@0 230
michael@0 231 template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
michael@0 232 #ifdef DEBUG
michael@0 233 if (refCnt > 0x7fff0000)
michael@0 234 MOZ_ASSERT(refCnt > 0x7fffdead);
michael@0 235 #endif
michael@0 236 MOZ_ASSERT(refCnt > 0);
michael@0 237 if (refCnt > 0) {
michael@0 238 if (0 == --refCnt) {
michael@0 239 #ifdef DEBUG
michael@0 240 refCnt = 0x7fffdead;
michael@0 241 #else
michael@0 242 refCnt = 1;
michael@0 243 #endif
michael@0 244 delete static_cast<const LibHandle*>(this);
michael@0 245 }
michael@0 246 }
michael@0 247 }
michael@0 248
michael@0 249 } /* namespace detail */
michael@0 250 } /* namespace mozilla */
michael@0 251
michael@0 252 /**
michael@0 253 * Class handling libraries loaded by the system linker
michael@0 254 */
michael@0 255 class SystemElf: public LibHandle
michael@0 256 {
michael@0 257 public:
michael@0 258 /**
michael@0 259 * Returns a new SystemElf for the given path. The given flags are passed
michael@0 260 * to dlopen().
michael@0 261 */
michael@0 262 static mozilla::TemporaryRef<LibHandle> Load(const char *path, int flags);
michael@0 263
michael@0 264 /**
michael@0 265 * Inherited from LibHandle
michael@0 266 */
michael@0 267 virtual ~SystemElf();
michael@0 268 virtual void *GetSymbolPtr(const char *symbol) const;
michael@0 269 virtual bool Contains(void *addr) const { return false; /* UNIMPLEMENTED */ }
michael@0 270
michael@0 271 #ifdef __ARM_EABI__
michael@0 272 virtual const void *FindExidx(int *pcount) const;
michael@0 273 #endif
michael@0 274
michael@0 275 protected:
michael@0 276 virtual Mappable *GetMappable() const;
michael@0 277
michael@0 278 /**
michael@0 279 * Returns whether the handle is a SystemElf or not. (short of a better way
michael@0 280 * to do this without RTTI)
michael@0 281 */
michael@0 282 friend class ElfLoader;
michael@0 283 virtual bool IsSystemElf() const { return true; }
michael@0 284
michael@0 285 /**
michael@0 286 * Remove the reference to the system linker handle. This avoids dlclose()
michael@0 287 * being called when the instance is destroyed.
michael@0 288 */
michael@0 289 void Forget()
michael@0 290 {
michael@0 291 dlhandle = nullptr;
michael@0 292 }
michael@0 293
michael@0 294 private:
michael@0 295 /**
michael@0 296 * Private constructor
michael@0 297 */
michael@0 298 SystemElf(const char *path, void *handle)
michael@0 299 : LibHandle(path), dlhandle(handle) { }
michael@0 300
michael@0 301 /* Handle as returned by system dlopen() */
michael@0 302 void *dlhandle;
michael@0 303 };
michael@0 304
michael@0 305 /**
michael@0 306 * The ElfLoader registers its own SIGSEGV handler to handle segmentation
michael@0 307 * faults within the address space of the loaded libraries. It however
michael@0 308 * allows a handler to be set for faults in other places, and redispatches
michael@0 309 * to the handler set through signal() or sigaction().
michael@0 310 */
michael@0 311 class SEGVHandler
michael@0 312 {
michael@0 313 public:
michael@0 314 bool hasRegisteredHandler() {
michael@0 315 return registeredHandler;
michael@0 316 }
michael@0 317
michael@0 318 bool isSignalHandlingBroken() {
michael@0 319 return signalHandlingBroken;
michael@0 320 }
michael@0 321
michael@0 322 protected:
michael@0 323 SEGVHandler();
michael@0 324 ~SEGVHandler();
michael@0 325
michael@0 326 private:
michael@0 327 static int __wrap_sigaction(int signum, const struct sigaction *act,
michael@0 328 struct sigaction *oldact);
michael@0 329
michael@0 330 /**
michael@0 331 * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction.
michael@0 332 */
michael@0 333 struct sigaction action;
michael@0 334
michael@0 335 /**
michael@0 336 * ElfLoader SIGSEGV handler.
michael@0 337 */
michael@0 338 static void handler(int signum, siginfo_t *info, void *context);
michael@0 339
michael@0 340 /**
michael@0 341 * Temporary test handler.
michael@0 342 */
michael@0 343 static void test_handler(int signum, siginfo_t *info, void *context);
michael@0 344
michael@0 345 /**
michael@0 346 * Size of the alternative stack. The printf family requires more than 8KB
michael@0 347 * of stack, and our signal handler may print a few things.
michael@0 348 */
michael@0 349 static const size_t stackSize = 12 * 1024;
michael@0 350
michael@0 351 /**
michael@0 352 * Alternative stack information used before initialization.
michael@0 353 */
michael@0 354 stack_t oldStack;
michael@0 355
michael@0 356 /**
michael@0 357 * Pointer to an alternative stack for signals. Only set if oldStack is
michael@0 358 * not set or not big enough.
michael@0 359 */
michael@0 360 MappedPtr stackPtr;
michael@0 361
michael@0 362 bool registeredHandler;
michael@0 363 bool signalHandlingBroken;
michael@0 364 bool signalHandlingSlow;
michael@0 365 };
michael@0 366
michael@0 367 /**
michael@0 368 * Elf Loader class in charge of loading and bookkeeping libraries.
michael@0 369 */
michael@0 370 class ElfLoader: public SEGVHandler
michael@0 371 {
michael@0 372 public:
michael@0 373 /**
michael@0 374 * The Elf Loader instance
michael@0 375 */
michael@0 376 static ElfLoader Singleton;
michael@0 377
michael@0 378 /**
michael@0 379 * Loads the given library with the given flags. Equivalent to dlopen()
michael@0 380 * The extra "parent" argument optionally gives the handle of the library
michael@0 381 * requesting the given library to be loaded. The loader may look in the
michael@0 382 * directory containing that parent library for the library to load.
michael@0 383 */
michael@0 384 mozilla::TemporaryRef<LibHandle> Load(const char *path, int flags,
michael@0 385 LibHandle *parent = nullptr);
michael@0 386
michael@0 387 /**
michael@0 388 * Returns the handle of the library containing the given address in
michael@0 389 * its virtual address space, i.e. the library handle for which
michael@0 390 * LibHandle::Contains returns true. Its purpose is to allow to
michael@0 391 * implement dladdr().
michael@0 392 */
michael@0 393 mozilla::TemporaryRef<LibHandle> GetHandleByPtr(void *addr);
michael@0 394
michael@0 395 /**
michael@0 396 * Returns a Mappable object for the path. Paths in the form
michael@0 397 * /foo/bar/baz/archive!/directory/lib.so
michael@0 398 * try to load the directory/lib.so in /foo/bar/baz/archive, provided
michael@0 399 * that file is a Zip archive.
michael@0 400 */
michael@0 401 static Mappable *GetMappableFromPath(const char *path);
michael@0 402
michael@0 403 protected:
michael@0 404 /**
michael@0 405 * Registers the given handle. This method is meant to be called by
michael@0 406 * LibHandle subclass creators.
michael@0 407 */
michael@0 408 void Register(LibHandle *handle);
michael@0 409
michael@0 410 /**
michael@0 411 * Forget about the given handle. This method is meant to be called by
michael@0 412 * LibHandle subclass destructors.
michael@0 413 */
michael@0 414 void Forget(LibHandle *handle);
michael@0 415
michael@0 416 /* Last error. Used for dlerror() */
michael@0 417 friend class SystemElf;
michael@0 418 friend const char *__wrap_dlerror(void);
michael@0 419 friend void *__wrap_dlsym(void *handle, const char *symbol);
michael@0 420 friend int __wrap_dlclose(void *handle);
michael@0 421 const char *lastError;
michael@0 422
michael@0 423 private:
michael@0 424 ~ElfLoader();
michael@0 425
michael@0 426 /* Bookkeeping */
michael@0 427 typedef std::vector<LibHandle *> LibHandleList;
michael@0 428 LibHandleList handles;
michael@0 429
michael@0 430 protected:
michael@0 431 friend class CustomElf;
michael@0 432 /**
michael@0 433 * Show some stats about Mappables in CustomElfs. The when argument is to
michael@0 434 * be used by the caller to give an identifier of the when the stats call
michael@0 435 * is made.
michael@0 436 */
michael@0 437 static void stats(const char *when);
michael@0 438
michael@0 439 /* Definition of static destructors as to be used for C++ ABI compatibility */
michael@0 440 typedef void (*Destructor)(void *object);
michael@0 441
michael@0 442 /**
michael@0 443 * C++ ABI makes static initializers register destructors through a specific
michael@0 444 * atexit interface. On glibc/linux systems, the dso_handle is a pointer
michael@0 445 * within a given library. On bionic/android systems, it is an undefined
michael@0 446 * symbol. Making sense of the value is not really important, and all that
michael@0 447 * is really important is that it is different for each loaded library, so
michael@0 448 * that they can be discriminated when shutting down. For convenience, on
michael@0 449 * systems where the dso handle is a symbol, that symbol is resolved to
michael@0 450 * point at corresponding CustomElf.
michael@0 451 *
michael@0 452 * Destructors are registered with __*_atexit with an associated object to
michael@0 453 * be passed as argument when it is called.
michael@0 454 *
michael@0 455 * When __cxa_finalize is called, destructors registered for the given
michael@0 456 * DSO handle are called in the reverse order they were registered.
michael@0 457 */
michael@0 458 #ifdef __ARM_EABI__
michael@0 459 static int __wrap_aeabi_atexit(void *that, Destructor destructor,
michael@0 460 void *dso_handle);
michael@0 461 #else
michael@0 462 static int __wrap_cxa_atexit(Destructor destructor, void *that,
michael@0 463 void *dso_handle);
michael@0 464 #endif
michael@0 465
michael@0 466 static void __wrap_cxa_finalize(void *dso_handle);
michael@0 467
michael@0 468 /**
michael@0 469 * Registered destructor. Keeps track of the destructor function pointer,
michael@0 470 * associated object to call it with, and DSO handle.
michael@0 471 */
michael@0 472 class DestructorCaller {
michael@0 473 public:
michael@0 474 DestructorCaller(Destructor destructor, void *object, void *dso_handle)
michael@0 475 : destructor(destructor), object(object), dso_handle(dso_handle) { }
michael@0 476
michael@0 477 /**
michael@0 478 * Call the destructor function with the associated object.
michael@0 479 * Call only once, see CustomElf::~CustomElf.
michael@0 480 */
michael@0 481 void Call();
michael@0 482
michael@0 483 /**
michael@0 484 * Returns whether the destructor is associated to the given DSO handle
michael@0 485 */
michael@0 486 bool IsForHandle(void *handle) const
michael@0 487 {
michael@0 488 return handle == dso_handle;
michael@0 489 }
michael@0 490
michael@0 491 private:
michael@0 492 Destructor destructor;
michael@0 493 void *object;
michael@0 494 void *dso_handle;
michael@0 495 };
michael@0 496
michael@0 497 private:
michael@0 498 /* Keep track of all registered destructors */
michael@0 499 std::vector<DestructorCaller> destructors;
michael@0 500
michael@0 501 /* Forward declaration, see further below */
michael@0 502 class DebuggerHelper;
michael@0 503 public:
michael@0 504 /* Loaded object descriptor for the debugger interface below*/
michael@0 505 struct link_map {
michael@0 506 /* Base address of the loaded object. */
michael@0 507 const void *l_addr;
michael@0 508 /* File name */
michael@0 509 const char *l_name;
michael@0 510 /* Address of the PT_DYNAMIC segment. */
michael@0 511 const void *l_ld;
michael@0 512
michael@0 513 private:
michael@0 514 friend class ElfLoader::DebuggerHelper;
michael@0 515 /* Double linked list of loaded objects. */
michael@0 516 link_map *l_next, *l_prev;
michael@0 517 };
michael@0 518
michael@0 519 private:
michael@0 520 /* Data structure used by the linker to give details about shared objects it
michael@0 521 * loaded to debuggers. This is normally defined in link.h, but Android
michael@0 522 * headers lack this file. */
michael@0 523 struct r_debug {
michael@0 524 /* Version number of the protocol. */
michael@0 525 int r_version;
michael@0 526
michael@0 527 /* Head of the linked list of loaded objects. */
michael@0 528 link_map *r_map;
michael@0 529
michael@0 530 /* Function to be called when updates to the linked list of loaded objects
michael@0 531 * are going to occur. The function is to be called before and after
michael@0 532 * changes. */
michael@0 533 void (*r_brk)(void);
michael@0 534
michael@0 535 /* Indicates to the debugger what state the linked list of loaded objects
michael@0 536 * is in when the function above is called. */
michael@0 537 enum {
michael@0 538 RT_CONSISTENT, /* Changes are complete */
michael@0 539 RT_ADD, /* Beginning to add a new object */
michael@0 540 RT_DELETE /* Beginning to remove an object */
michael@0 541 } r_state;
michael@0 542 };
michael@0 543
michael@0 544 /* Helper class used to integrate libraries loaded by this linker in
michael@0 545 * r_debug */
michael@0 546 class DebuggerHelper
michael@0 547 {
michael@0 548 public:
michael@0 549 DebuggerHelper();
michael@0 550
michael@0 551 operator bool()
michael@0 552 {
michael@0 553 return dbg;
michael@0 554 }
michael@0 555
michael@0 556 /* Make the debugger aware of a new loaded object */
michael@0 557 void Add(link_map *map);
michael@0 558
michael@0 559 /* Make the debugger aware of the unloading of an object */
michael@0 560 void Remove(link_map *map);
michael@0 561
michael@0 562 /* Iterates over all link_maps */
michael@0 563 class iterator
michael@0 564 {
michael@0 565 public:
michael@0 566 const link_map *operator ->() const
michael@0 567 {
michael@0 568 return item;
michael@0 569 }
michael@0 570
michael@0 571 const link_map &operator ++()
michael@0 572 {
michael@0 573 item = item->l_next;
michael@0 574 return *item;
michael@0 575 }
michael@0 576
michael@0 577 bool operator<(const iterator &other) const
michael@0 578 {
michael@0 579 if (other.item == nullptr)
michael@0 580 return item ? true : false;
michael@0 581 MOZ_CRASH("DebuggerHelper::iterator::operator< called with something else than DebuggerHelper::end()");
michael@0 582 }
michael@0 583 protected:
michael@0 584 friend class DebuggerHelper;
michael@0 585 iterator(const link_map *item): item(item) { }
michael@0 586
michael@0 587 private:
michael@0 588 const link_map *item;
michael@0 589 };
michael@0 590
michael@0 591 iterator begin() const
michael@0 592 {
michael@0 593 return iterator(dbg ? dbg->r_map : nullptr);
michael@0 594 }
michael@0 595
michael@0 596 iterator end() const
michael@0 597 {
michael@0 598 return iterator(nullptr);
michael@0 599 }
michael@0 600
michael@0 601 private:
michael@0 602 r_debug *dbg;
michael@0 603 link_map *firstAdded;
michael@0 604 };
michael@0 605 friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
michael@0 606 DebuggerHelper dbg;
michael@0 607 };
michael@0 608
michael@0 609 #endif /* ElfLoader_h */

mercurial