blob: 8ee18746e3c6d8a08d8bd4d4205e6329653f91fe [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "common/dlfcn_injection.h"
#include <irt_syscalls.h>
#include <private/dl_dst_lib.h>
#include <private/inject_arc_linker_hooks.h>
#include <sys/mman.h>
#include <string>
#include "base/containers/hash_tables.h"
#include "base/strings/string_split.h"
#include "common/alog.h"
#include "common/android_static_libraries.h"
#include "common/ndk_support/arm_syscall.h"
#include "common/ndk_support/mmap.h"
#include "common/wrapped_functions.h"
namespace arc {
namespace {
// A map from wrapped symbol names to their function pointers.
typedef base::hash_map<std::string, void*> SymbolMap; // NOLINT
SymbolMap* g_wrapped_symbol_map;
// Names of Android's libraries which we statically link to the main nexe.
typedef base::hash_set<std::string> LibraryNameSet; // NOLINT
LibraryNameSet* g_android_library_names;
// For mmap/munmap, we use --wrap to use posix_translation based
// implementation. We need to convert IRT ABI to libc ABI.
int __nacl_irt_mmap_posix_translation(void** addr, size_t len, int prot,
int flags, int fd, nacl_abi_off_t off) {
// This is __wrap_mmap call so we will kick posix_translation.
void* result = mmap(*addr, len, prot, flags, fd, off);
if (result == MAP_FAILED)
return errno;
*addr = result;
return 0;
}
int __nacl_irt_munmap_posix_translation(void* addr, size_t len) {
// This is __wrap_munmap call so we will kick posix_translation.
int result = munmap(addr, len);
if (result < 0)
return errno;
return 0;
}
} // namespace
void InitDlfcnInjection() {
g_wrapped_symbol_map = new SymbolMap();
for (WrappedFunction* p = kWrappedFunctions; p->name; p++) {
if (!g_wrapped_symbol_map->insert(
std::make_pair(p->name, reinterpret_cast<void*>(p->func))).second)
LOG_ALWAYS_FATAL("Duplicated symbol: %s", p->name);
}
g_android_library_names = new LibraryNameSet();
for (const char** p = kAndroidStaticLibraries; *p; p++) {
// Append ".so" as their shared object versions will be queried.
const char* kSoSuffix = ".so";
if (!g_android_library_names->insert(std::string(*p) + kSoSuffix).second)
LOG_ALWAYS_FATAL("Duplicated library name: %s", *p);
}
#if defined(USE_NDK_DIRECT_EXECUTION)
// Syscall numbers (e.g., __NR_mmap) depend on CPU. As we need to
// handle syscalls called by NDK with ARM's syscall numbers instead
// of host's, we inject the syscall function for ARM.
(*g_wrapped_symbol_map)["syscall"] =
reinterpret_cast<void*>(&RunArmLibcSyscall);
// See src/common/ndk_support/mmap.h for detail.
(*g_wrapped_symbol_map)["mmap"] =
reinterpret_cast<void*>(&MmapForNdk);
(*g_wrapped_symbol_map)["mprotect"] =
reinterpret_cast<void*>(&MprotectForNdk);
#endif
// Inject the custom symbol resolver and posix_translation based
// file operations to the Bionic loader. After we inject the
// posix_translation based file functions, we use munmap and close
// based on posix_translation in dlclose. This is safe as we call
// InitDlfcnInjection before the first dlopen is called, and we do
// not dlclose DT_NEEDED ELF objects.
//
// Note that we have already set up IRT hooks in InitIRTHooks, so
// __nacl_irt_close, __nacl_irt_open, __nacl_irt_read, and
// __nacl_irt_write here are not the original IRT functions, but
// ARC's customized versions which call __wrap_*.
__arc_linker_hooks hooks = {
ResolveWrappedSymbol,
IsStaticallyLinkedSharedObject,
__nacl_irt_close,
__nacl_irt_mmap_posix_translation,
__nacl_irt_munmap_posix_translation,
__nacl_irt_open,
__nacl_irt_read,
__nacl_irt_write,
};
__inject_arc_linker_hooks(&hooks);
}
void* ResolveWrappedSymbol(const char* symbol) {
SymbolMap::const_iterator found = g_wrapped_symbol_map->find(symbol);
return found != g_wrapped_symbol_map->end() ? found->second : NULL;
}
int IsStaticallyLinkedSharedObject(const char* filename) {
LibraryNameSet::const_iterator found =
g_android_library_names->find(filename);
return found != g_android_library_names->end();
}
} // namespace arc