Merge changes I578d36a1,Id17508ab,I385f312b

* changes:
  Create linker_log[_va_list] functions
  Validate defined versions in prelink_image
  Prelink each library only once
diff --git a/linker/Android.bp b/linker/Android.bp
index 3b25d12..8e810d2 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -156,6 +156,7 @@
         "linker_dlwarning.cpp",
         "linker_cfi.cpp",
         "linker_config.cpp",
+        "linker_debug.cpp",
         "linker_gdb_support.cpp",
         "linker_globals.cpp",
         "linker_libc_support.c",
@@ -460,6 +461,7 @@
         // Parts of the linker that we're testing.
         "linker_block_allocator.cpp",
         "linker_config.cpp",
+        "linker_debug.cpp",
         "linker_test_globals.cpp",
         "linker_utils.cpp",
     ],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8b0520a..10833be 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -508,10 +508,7 @@
    */
   if (si_from->has_DT_SYMBOLIC) {
     DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
-    if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
-      return false;
-    }
-
+    s = si_from->find_symbol_by_name(symbol_name, vi);
     if (s != nullptr) {
       *si_found_in = si_from;
     }
@@ -519,15 +516,10 @@
 
   // 1. Look for it in global_group
   if (s == nullptr) {
-    bool error = false;
     global_group.visit([&](soinfo* global_si) {
       DEBUG("%s: looking up %s in %s (from global group)",
           si_from->get_realpath(), name, global_si->get_realpath());
-      if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
-        error = true;
-        return false;
-      }
-
+      s = global_si->find_symbol_by_name(symbol_name, vi);
       if (s != nullptr) {
         *si_found_in = global_si;
         return false;
@@ -535,15 +527,10 @@
 
       return true;
     });
-
-    if (error) {
-      return false;
-    }
   }
 
   // 2. Look for it in the local group
   if (s == nullptr) {
-    bool error = false;
     local_group.visit([&](soinfo* local_si) {
       if (local_si == si_from && si_from->has_DT_SYMBOLIC) {
         // we already did this - skip
@@ -552,11 +539,7 @@
 
       DEBUG("%s: looking up %s in %s (from local group)",
           si_from->get_realpath(), name, local_si->get_realpath());
-      if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
-        error = true;
-        return false;
-      }
-
+      s = local_si->find_symbol_by_name(symbol_name, vi);
       if (s != nullptr) {
         *si_found_in = local_si;
         return false;
@@ -564,10 +547,6 @@
 
       return true;
     });
-
-    if (error) {
-      return false;
-    }
   }
 
   if (s != nullptr) {
@@ -863,11 +842,7 @@
       return kWalkSkip;
     }
 
-    if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
-      result = nullptr;
-      return kWalkStop;
-    }
-
+    result = current_soinfo->find_symbol_by_name(symbol_name, vi);
     if (result != nullptr) {
       *found = current_soinfo;
       return kWalkStop;
@@ -947,10 +922,7 @@
       continue;
     }
 
-    if (!si->find_symbol_by_name(symbol_name, vi, &s)) {
-      return nullptr;
-    }
-
+    s = si->find_symbol_by_name(symbol_name, vi);
     if (s != nullptr) {
       *found = si;
       break;
@@ -2819,25 +2791,38 @@
   return true;
 }
 
-bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym) {
+ElfW(Versym) find_verdef_version_index(const soinfo* si, const version_info* vi) {
   if (vi == nullptr) {
-    *versym = kVersymNotNeeded;
-    return true;
+    return kVersymNotNeeded;
   }
 
-  *versym = kVersymGlobal;
+  ElfW(Versym) result = kVersymGlobal;
 
-  return for_each_verdef(si,
+  if (!for_each_verdef(si,
     [&](size_t, const ElfW(Verdef)* verdef, const ElfW(Verdaux)* verdaux) {
       if (verdef->vd_hash == vi->elf_hash &&
           strcmp(vi->name, si->get_string(verdaux->vda_name)) == 0) {
-        *versym = verdef->vd_ndx;
+        result = verdef->vd_ndx;
         return true;
       }
 
       return false;
     }
-  );
+  )) {
+    // verdef should have already been validated in prelink_image.
+    async_safe_fatal("invalid verdef after prelinking: %s, %s",
+                     si->get_realpath(), linker_get_error_buffer());
+  }
+
+  return result;
+}
+
+// Validate the library's verdef section. On error, returns false and invokes DL_ERR.
+bool validate_verdef_section(const soinfo* si) {
+  return for_each_verdef(si,
+    [&](size_t, const ElfW(Verdef)*, const ElfW(Verdaux)*) {
+      return false;
+    });
 }
 
 bool VersionTracker::init_verdef(const soinfo* si_from) {
@@ -3346,6 +3331,7 @@
 static soinfo_list_t g_empty_list;
 
 bool soinfo::prelink_image() {
+  if (flags_ & FLAG_PRELINKED) return true;
   /* Extract dynamic section */
   ElfW(Word) dynamic_flags = 0;
   phdr_table_get_dynamic_section(phdr, phnum, load_bias, &dynamic, &dynamic_flags);
@@ -3840,6 +3826,12 @@
 
     // Don't call add_dlwarning because a missing DT_SONAME isn't important enough to show in the UI
   }
+
+  // Validate each library's verdef section once, so we don't have to validate
+  // it each time we look up a symbol with a version.
+  if (!validate_verdef_section(this)) return false;
+
+  flags_ |= FLAG_PRELINKED;
   return true;
 }
 
diff --git a/linker/linker.h b/linker/linker.h
index 789640c..16c65a1 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -204,3 +204,5 @@
   size_t reserved_size = 0;
   bool must_use_address = false;
 };
+
+ElfW(Versym) find_verdef_version_index(const soinfo* si, const version_info* vi);
diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp
index 435bb1a..5995013 100644
--- a/linker/linker_cfi.cpp
+++ b/linker/linker_cfi.cpp
@@ -142,8 +142,7 @@
 
 static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) {
   SymbolName name(s);
-  const ElfW(Sym) * sym;
-  if (si->find_symbol_by_name(name, nullptr, &sym) && sym) {
+  if (const ElfW(Sym)* sym = si->find_symbol_by_name(name, nullptr)) {
     return si->resolve_symbol_address(sym);
   }
   return 0;
diff --git a/linker/linker_debug.cpp b/linker/linker_debug.cpp
new file mode 100644
index 0000000..b0aae79
--- /dev/null
+++ b/linker/linker_debug.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "linker_debug.h"
+
+#include <unistd.h>
+
+void linker_log_va_list(int prio __unused, const char* fmt, va_list ap) {
+#if LINKER_DEBUG_TO_LOG
+  async_safe_format_log_va_list(5 - prio, "linker", fmt, ap);
+#else
+  async_safe_format_fd_va_list(STDOUT_FILENO, fmt, ap);
+  write(STDOUT_FILENO, "\n", 1);
+#endif
+}
+
+void linker_log(int prio, const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  linker_log_va_list(prio, fmt, ap);
+  va_end(ap);
+}
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 6031850..738ff6f 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -52,31 +52,33 @@
  * To enable/disable specific debug options, change the defines above
  *********************************************************************/
 
+#include <stdarg.h>
 #include <unistd.h>
 
 #include <async_safe/log.h>
 #include <async_safe/CHECK.h>
 
+#define LINKER_VERBOSITY_PRINT  -1
+#define LINKER_VERBOSITY_INFO   0
+#define LINKER_VERBOSITY_TRACE  1
+#define LINKER_VERBOSITY_DEBUG  2
+
 __LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
 
-#if LINKER_DEBUG_TO_LOG
-#define _PRINTVF(v, x...) \
-    do { \
-      if (g_ld_debug_verbosity > (v)) async_safe_format_log(5-(v), "linker", x); \
-    } while (0)
-#else /* !LINKER_DEBUG_TO_LOG */
-#define _PRINTVF(v, x...) \
-    do { \
-      if (g_ld_debug_verbosity > (v)) { async_safe_format_fd(1, x); write(1, "\n", 1); } \
-    } while (0)
-#endif /* !LINKER_DEBUG_TO_LOG */
+__LIBC_HIDDEN__ void linker_log_va_list(int prio, const char* fmt, va_list ap);
+__LIBC_HIDDEN__ void linker_log(int prio, const char* fmt, ...) __printflike(2, 3);
 
-#define PRINT(x...)          _PRINTVF(-1, x)
-#define INFO(x...)           _PRINTVF(0, x)
-#define TRACE(x...)          _PRINTVF(1, x)
+#define _PRINTVF(v, x...) \
+    do { \
+      if (g_ld_debug_verbosity > (v)) linker_log((v), x); \
+    } while (0)
+
+#define PRINT(x...)          _PRINTVF(LINKER_VERBOSITY_PRINT, x)
+#define INFO(x...)           _PRINTVF(LINKER_VERBOSITY_INFO, x)
+#define TRACE(x...)          _PRINTVF(LINKER_VERBOSITY_TRACE, x)
 
 #if TRACE_DEBUG
-#define DEBUG(x...)          _PRINTVF(2, "DEBUG: " x)
+#define DEBUG(x...)          _PRINTVF(LINKER_VERBOSITY_DEBUG, "DEBUG: " x)
 #else /* !TRACE_DEBUG */
 #define DEBUG(x...)          do {} while (0)
 #endif /* TRACE_DEBUG */
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 04aa27b..8efc9fe 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -36,6 +36,7 @@
 
 #include <async_safe/log.h>
 
+#include "linker.h"
 #include "linker_config.h"
 #include "linker_debug.h"
 #include "linker_globals.h"
@@ -43,7 +44,6 @@
 #include "linker_utils.h"
 
 // TODO(dimitry): These functions are currently located in linker.cpp - find a better place for it
-bool find_verdef_version_index(const soinfo* si, const version_info* vi, ElfW(Versym)* versym);
 ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr);
 int get_application_target_sdk_version();
 
@@ -135,22 +135,6 @@
   return 0;
 }
 
-bool soinfo::find_symbol_by_name(SymbolName& symbol_name,
-                                 const version_info* vi,
-                                 const ElfW(Sym)** symbol) const {
-  uint32_t symbol_index;
-  bool success =
-      is_gnu_hash() ?
-      gnu_lookup(symbol_name, vi, &symbol_index) :
-      elf_lookup(symbol_name, vi, &symbol_index);
-
-  if (success) {
-    *symbol = symbol_index == 0 ? nullptr : symtab_ + symbol_index;
-  }
-
-  return success;
-}
-
 static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
   if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
       ELF_ST_BIND(s->st_info) == STB_WEAK) {
@@ -177,9 +161,12 @@
       verneed == (*verdef & ~kVersymHiddenBit);
 }
 
-bool soinfo::gnu_lookup(SymbolName& symbol_name,
-                        const version_info* vi,
-                        uint32_t* symbol_index) const {
+const ElfW(Sym)* soinfo::find_symbol_by_name(SymbolName& symbol_name,
+                                             const version_info* vi) const {
+  return is_gnu_hash() ? gnu_lookup(symbol_name, vi) : elf_lookup(symbol_name, vi);
+}
+
+const ElfW(Sym)* soinfo::gnu_lookup(SymbolName& symbol_name, const version_info* vi) const {
   uint32_t hash = symbol_name.gnu_hash();
   uint32_t h2 = hash >> gnu_shift2_;
 
@@ -187,8 +174,6 @@
   uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
   ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];
 
-  *symbol_index = 0;
-
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
       symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
@@ -197,7 +182,7 @@
     TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
         symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
-    return true;
+    return nullptr;
   }
 
   // bloom test says "probably yes"...
@@ -207,7 +192,7 @@
     TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
         symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
-    return true;
+    return nullptr;
   }
 
   // lookup versym for the version definition in this library
@@ -216,10 +201,7 @@
   // which implies that the default version can be accepted; the second case results in
   // verneed = 1 (kVersymGlobal) and implies that we should ignore versioned symbols
   // for this library and consider only *global* ones.
-  ElfW(Versym) verneed = 0;
-  if (!find_verdef_version_index(this, vi, &verneed)) {
-    return false;
-  }
+  const ElfW(Versym) verneed = find_verdef_version_index(this, vi);
 
   do {
     ElfW(Sym)* s = symtab_ + n;
@@ -235,30 +217,24 @@
       TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
           symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
           static_cast<size_t>(s->st_size));
-      *symbol_index = n;
-      return true;
+      return symtab_ + n;
     }
   } while ((gnu_chain_[n++] & 1) == 0);
 
   TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
              symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
 
-  return true;
+  return nullptr;
 }
 
-bool soinfo::elf_lookup(SymbolName& symbol_name,
-                        const version_info* vi,
-                        uint32_t* symbol_index) const {
+const ElfW(Sym)* soinfo::elf_lookup(SymbolName& symbol_name, const version_info* vi) const {
   uint32_t hash = symbol_name.elf_hash();
 
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
              symbol_name.get_name(), get_realpath(),
              reinterpret_cast<void*>(base), hash, hash % nbucket_);
 
-  ElfW(Versym) verneed = 0;
-  if (!find_verdef_version_index(this, vi, &verneed)) {
-    return false;
-  }
+  const ElfW(Versym) verneed = find_verdef_version_index(this, vi);
 
   for (uint32_t n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
     ElfW(Sym)* s = symtab_ + n;
@@ -276,8 +252,7 @@
                  symbol_name.get_name(), get_realpath(),
                  reinterpret_cast<void*>(s->st_value),
                  static_cast<size_t>(s->st_size));
-      *symbol_index = n;
-      return true;
+      return symtab_ + n;
     }
   }
 
@@ -285,8 +260,7 @@
              symbol_name.get_name(), get_realpath(),
              reinterpret_cast<void*>(base), hash, hash % nbucket_);
 
-  *symbol_index = 0;
-  return true;
+  return nullptr;
 }
 
 ElfW(Sym)* soinfo::find_symbol_by_address(const void* addr) {
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index dd3817c..9ae17ea 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -63,6 +63,7 @@
                                          // destructor associated with this
                                          // soinfo is executed and this flag is
                                          // unset.
+#define FLAG_PRELINKED        0x00000400 // prelink_image has successfully processed this soinfo
 #define FLAG_NEW_SOINFO       0x40000000 // new soinfo format
 
 #define SOINFO_VERSION 5
@@ -242,9 +243,7 @@
 
   soinfo_list_t& get_parents();
 
-  bool find_symbol_by_name(SymbolName& symbol_name,
-                           const version_info* vi,
-                           const ElfW(Sym)** symbol) const;
+  const ElfW(Sym)* find_symbol_by_name(SymbolName& symbol_name, const version_info* vi) const;
 
   ElfW(Sym)* find_symbol_by_address(const void* addr);
   ElfW(Addr) resolve_symbol_address(const ElfW(Sym)* s) const;
@@ -309,10 +308,10 @@
   bool is_image_linked() const;
   void set_image_linked();
 
-  bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
-  ElfW(Sym)* elf_addr_lookup(const void* addr);
-  bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
+  const ElfW(Sym)* gnu_lookup(SymbolName& symbol_name, const version_info* vi) const;
+  const ElfW(Sym)* elf_lookup(SymbolName& symbol_name, const version_info* vi) const;
   ElfW(Sym)* gnu_addr_lookup(const void* addr);
+  ElfW(Sym)* elf_addr_lookup(const void* addr);
 
   bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
                            const char* sym_name, const version_info** vi);