summaryrefslogtreecommitdiffstats
path: root/mozglue/interposers/InterposerHelper.h
blob: fddc05a163bb91f3cc6a43922c0552ab966be15b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef InterposerHelper_h
#define InterposerHelper_h

#include <type_traits>

#ifdef MOZ_LINKER
#  include "Linker.h"
#else
#  include <dlfcn.h>
#endif

#include "mozilla/Assertions.h"

template <typename T>
static inline T dlsym_wrapper(void* aHandle, const char* aName) {
#ifdef MOZ_LINKER
  return reinterpret_cast<T>(__wrap_dlsym(aHandle, aName));
#else
  return reinterpret_cast<T>(dlsym(aHandle, aName));
#endif  // MOZ_LINKER
}

static inline void* dlopen_wrapper(const char* aPath, int flags) {
#ifdef MOZ_LINKER
  return __wrap_dlopen(aPath, flags);
#else
  return dlopen(aPath, flags);
#endif  // MOZ_LINKER
}

template <typename T>
static T get_real_symbol(const char* aName, T aReplacementSymbol) {
  // T can only be a function pointer
  static_assert(std::is_function<typename std::remove_pointer<T>::type>::value);

  // Find the corresponding function in the linked libraries
  T real_symbol = dlsym_wrapper<T>(RTLD_NEXT, aName);

#if defined(ANDROID)
  if (real_symbol == nullptr) {
    // On old versions of Android the application runtime links in libc before
    // we get a chance to link libmozglue, so its symbols don't appear when
    // resolving them with RTLD_NEXT. This behavior differ between the
    // different versions of Android so we'll just look for them directly into
    // libc.so. Note that this won't work if we're trying to interpose
    // functions that are in other libraries, but hopefully we'll never have
    // to do that.
    void* handle = dlopen_wrapper("libc.so", RTLD_LAZY);

    if (handle) {
      real_symbol = dlsym_wrapper<T>(handle, aName);
    }
  }
#endif

  if (real_symbol == nullptr) {
    MOZ_CRASH_UNSAFE_PRINTF(
        "%s() interposition failed but the interposer function is "
        "still being called, this won't work!",
        aName);
  }

  if (real_symbol == aReplacementSymbol) {
    MOZ_CRASH_UNSAFE_PRINTF(
        "We could not obtain the real %s(). Calling the symbol we "
        "got would make us enter an infinite loop so stop here instead.",
        aName);
  }

  return real_symbol;
}

#define GET_REAL_SYMBOL(name) get_real_symbol(#name, name)

#endif  // InterposerHelper_h