Merge "Implement lookup by DT_SONAME"
This commit is contained in:
		@@ -248,6 +248,7 @@ soinfo* get_libdl_info() {
 | 
			
		||||
    __libdl_info.ref_count_ = 1;
 | 
			
		||||
    __libdl_info.strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
 | 
			
		||||
    __libdl_info.local_group_root_ = &__libdl_info;
 | 
			
		||||
    __libdl_info.soname_ = "libdl.so";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return &__libdl_info;
 | 
			
		||||
 
 | 
			
		||||
@@ -78,19 +78,6 @@
 | 
			
		||||
#undef ELF_ST_TYPE
 | 
			
		||||
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
 | 
			
		||||
 | 
			
		||||
#if defined(__LP64__)
 | 
			
		||||
#define SEARCH_NAME(x) x
 | 
			
		||||
#else
 | 
			
		||||
// Nvidia drivers are relying on the bug:
 | 
			
		||||
// http://code.google.com/p/android/issues/detail?id=6670
 | 
			
		||||
// so we continue to use base-name lookup for lp32
 | 
			
		||||
static const char* get_base_name(const char* name) {
 | 
			
		||||
  const char* bname = strrchr(name, '/');
 | 
			
		||||
  return bname ? bname + 1 : name;
 | 
			
		||||
}
 | 
			
		||||
#define SEARCH_NAME(x) get_base_name(x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
 | 
			
		||||
 | 
			
		||||
static LinkerTypeAllocator<soinfo> g_soinfo_allocator;
 | 
			
		||||
@@ -1029,7 +1016,7 @@ static soinfo* load_library(LoadTaskList& load_tasks,
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags);
 | 
			
		||||
  soinfo* si = soinfo_alloc(name, &file_stat, file_offset, rtld_flags);
 | 
			
		||||
  if (si == nullptr) {
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
@@ -1051,10 +1038,15 @@ static soinfo* load_library(LoadTaskList& load_tasks,
 | 
			
		||||
  return si;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static soinfo *find_loaded_library_by_name(const char* name) {
 | 
			
		||||
  const char* search_name = SEARCH_NAME(name);
 | 
			
		||||
static soinfo *find_loaded_library_by_soname(const char* name) {
 | 
			
		||||
  // Ignore filename with path.
 | 
			
		||||
  if (strchr(name, '/') != nullptr) {
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (soinfo* si = solist; si != nullptr; si = si->next) {
 | 
			
		||||
    if (!strcmp(search_name, si->name)) {
 | 
			
		||||
    const char* soname = si->get_soname();
 | 
			
		||||
    if (soname != nullptr && (strcmp(name, soname) == 0)) {
 | 
			
		||||
      return si;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -1062,13 +1054,12 @@ static soinfo *find_loaded_library_by_name(const char* name) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
 | 
			
		||||
 | 
			
		||||
  soinfo* si = find_loaded_library_by_name(name);
 | 
			
		||||
  soinfo* si = find_loaded_library_by_soname(name);
 | 
			
		||||
 | 
			
		||||
  // Library might still be loaded, the accurate detection
 | 
			
		||||
  // of this fact is done by load_library.
 | 
			
		||||
  if (si == nullptr) {
 | 
			
		||||
    TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
 | 
			
		||||
    TRACE("[ '%s' has not been found by soname.  Trying harder...]", name);
 | 
			
		||||
    si = load_library(load_tasks, name, rtld_flags, extinfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -1832,6 +1823,7 @@ uint32_t soinfo::get_dt_flags_1() const {
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
 | 
			
		||||
  if (has_min_version(1)) {
 | 
			
		||||
    if ((dt_flags_1 & DF_1_GLOBAL) != 0) {
 | 
			
		||||
@@ -1846,6 +1838,14 @@ void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* soinfo::get_soname() {
 | 
			
		||||
  if (has_min_version(2)) {
 | 
			
		||||
    return soname_;
 | 
			
		||||
  } else {
 | 
			
		||||
    return name;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is a return on get_children()/get_parents() if
 | 
			
		||||
// 'this->flags' does not have FLAG_NEW_SOINFO set.
 | 
			
		||||
static soinfo::soinfo_list_t g_empty_list;
 | 
			
		||||
@@ -2012,14 +2012,17 @@ bool soinfo::prelink_image() {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Extract useful information from dynamic section.
 | 
			
		||||
  // Note that: "Except for the DT_NULL element at the end of the array,
 | 
			
		||||
  // and the relative order of DT_NEEDED elements, entries may appear in any order."
 | 
			
		||||
  //
 | 
			
		||||
  // source: http://www.sco.com/developers/gabi/1998-04-29/ch5.dynamic.html
 | 
			
		||||
  uint32_t needed_count = 0;
 | 
			
		||||
  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
 | 
			
		||||
    DEBUG("d = %p, d[0](tag) = %p d[1](val) = %p",
 | 
			
		||||
          d, reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
 | 
			
		||||
    switch (d->d_tag) {
 | 
			
		||||
      case DT_SONAME:
 | 
			
		||||
        // TODO: glibc dynamic linker uses this name for
 | 
			
		||||
        // initial library lookup; consider doing the same here.
 | 
			
		||||
        // this is parsed after we have strtab initialized (see below).
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case DT_HASH:
 | 
			
		||||
@@ -2342,6 +2345,14 @@ bool soinfo::prelink_image() {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // second pass - parse entries relying on strtab
 | 
			
		||||
  for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
 | 
			
		||||
    if (d->d_tag == DT_SONAME) {
 | 
			
		||||
      soname_ = get_string(d->d_un.d_val);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
 | 
			
		||||
        reinterpret_cast<void*>(base), strtab_, symtab_);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,7 @@
 | 
			
		||||
 | 
			
		||||
#define SUPPORTED_DT_FLAGS_1 (DF_1_NOW | DF_1_GLOBAL | DF_1_NODELETE)
 | 
			
		||||
 | 
			
		||||
#define SOINFO_VERSION 1
 | 
			
		||||
#define SOINFO_VERSION 2
 | 
			
		||||
 | 
			
		||||
#define SOINFO_NAME_LEN 128
 | 
			
		||||
 | 
			
		||||
@@ -278,6 +278,8 @@ struct soinfo {
 | 
			
		||||
 | 
			
		||||
  soinfo* get_local_group_root() const;
 | 
			
		||||
 | 
			
		||||
  const char* get_soname();
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  ElfW(Sym)* elf_lookup(SymbolName& symbol_name);
 | 
			
		||||
  ElfW(Sym)* elf_addr_lookup(const void* addr);
 | 
			
		||||
@@ -322,6 +324,8 @@ struct soinfo {
 | 
			
		||||
  uint8_t* android_relocs_;
 | 
			
		||||
  size_t android_relocs_size_;
 | 
			
		||||
 | 
			
		||||
  const char* soname_;
 | 
			
		||||
 | 
			
		||||
  friend soinfo* get_libdl_info();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,32 @@ TEST(dlfcn, dlopen_noload) {
 | 
			
		||||
  ASSERT_EQ(0, dlclose(handle2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(dlfcn, dlopen_by_soname) {
 | 
			
		||||
  static const char* soname = "libdlext_test_soname.so";
 | 
			
		||||
  static const char* filename = "libdlext_test_different_soname.so";
 | 
			
		||||
  // 1. Make sure there is no library with soname in default search path
 | 
			
		||||
  void* handle = dlopen(soname, RTLD_NOW);
 | 
			
		||||
  ASSERT_TRUE(handle == nullptr);
 | 
			
		||||
 | 
			
		||||
  // 2. Load a library using filename
 | 
			
		||||
  handle = dlopen(filename, RTLD_NOW);
 | 
			
		||||
  ASSERT_TRUE(handle != nullptr) << dlerror();
 | 
			
		||||
 | 
			
		||||
  // 3. Find library by soname
 | 
			
		||||
  void* handle_soname = dlopen(soname, RTLD_NOW | RTLD_NOLOAD);
 | 
			
		||||
  ASSERT_TRUE(handle_soname != nullptr) << dlerror();
 | 
			
		||||
  ASSERT_EQ(handle, handle_soname);
 | 
			
		||||
 | 
			
		||||
  // 4. RTLD_NOLOAD should still work with filename
 | 
			
		||||
  void* handle_filename = dlopen(filename, RTLD_NOW | RTLD_NOLOAD);
 | 
			
		||||
  ASSERT_TRUE(handle_filename != nullptr) << dlerror();
 | 
			
		||||
  ASSERT_EQ(handle, handle_filename);
 | 
			
		||||
 | 
			
		||||
  dlclose(handle_filename);
 | 
			
		||||
  dlclose(handle_soname);
 | 
			
		||||
  dlclose(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ifuncs are only supported on intel and arm64 for now
 | 
			
		||||
#if defined (__aarch64__) || defined(__i386__) || defined(__x86_64__)
 | 
			
		||||
TEST(dlfcn, ifunc) {
 | 
			
		||||
 
 | 
			
		||||
@@ -117,6 +117,17 @@ build_type := target
 | 
			
		||||
build_target := SHARED_LIBRARY
 | 
			
		||||
include $(TEST_PATH)/Android.build.mk
 | 
			
		||||
 | 
			
		||||
# ----------------------------------------------------------------------------
 | 
			
		||||
# Library with soname which does not match filename
 | 
			
		||||
# ----------------------------------------------------------------------------
 | 
			
		||||
libdlext_test_different_soname_src_files := \
 | 
			
		||||
    dlext_test_library.cpp \
 | 
			
		||||
 | 
			
		||||
module := libdlext_test_different_soname
 | 
			
		||||
module_tag := optional
 | 
			
		||||
libdlext_test_different_soname_ldflags := -Wl,-soname=libdlext_test_soname.so
 | 
			
		||||
include $(LOCAL_PATH)/Android.build.testlib.mk
 | 
			
		||||
 | 
			
		||||
# -----------------------------------------------------------------------------
 | 
			
		||||
# Library used by dlext tests - zipped and aligned
 | 
			
		||||
# -----------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user