Fix unused DT entry warnings.

 DT_STRSZ Implement strtab boundary checks
 DT_FLAGS_1 Warn if flags other than DF_1_NOW|DF_1_GLOBAL are set

Bug: 17552334
Bug: 18186310

(cherry picked from commit 6cdeb5234d7f4523fe9d83974f265d80f10512a6)

Change-Id: I7ffc7bc600798308a77ad949a644949b64250ae2
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3073109..9e26cf8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -417,14 +417,13 @@
 
 static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
   ElfW(Sym)* symtab = si->symtab;
-  const char* strtab = si->strtab;
 
   TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p %x %zd",
              name, si->name, reinterpret_cast<void*>(si->base), hash, hash % si->nbucket);
 
   for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
     ElfW(Sym)* s = symtab + n;
-    if (strcmp(strtab + s->st_name, name)) continue;
+    if (strcmp(si->get_string(s->st_name), name)) continue;
 
     // only concern ourselves with global and weak symbol definitions
     switch (ELF_ST_BIND(s->st_info)) {
@@ -776,7 +775,7 @@
 static void for_each_dt_needed(const soinfo* si, F action) {
   for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
     if (d->d_tag == DT_NEEDED) {
-      action(si->strtab + d->d_un.d_val);
+      action(si->get_string(d->d_un.d_val));
     }
   }
 }
@@ -1103,7 +1102,7 @@
     soinfo* lsi = nullptr;
 
     if (sym != 0) {
-      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+      sym_name = get_string(symtab[sym].st_name);
       s = soinfo_do_lookup(this, sym_name, &lsi);
       if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
@@ -1381,7 +1380,7 @@
     soinfo* lsi = nullptr;
 
     if (sym != 0) {
-      sym_name = reinterpret_cast<const char*>(strtab + symtab[sym].st_name);
+      sym_name = get_string(symtab[sym].st_name);
       s = soinfo_do_lookup(this, sym_name, &lsi);
       if (s == nullptr) {
         // We only allow an undefined symbol if this is a weak reference...
@@ -1599,7 +1598,7 @@
   got = si->plt_got + local_gotno;
   for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
     // This is an undefined reference... try to locate it.
-    const char* sym_name = si->strtab + sym->st_name;
+    const char* sym_name = si->get_string(sym->st_name);
     soinfo* lsi = nullptr;
     ElfW(Sym)* s = soinfo_do_lookup(si, sym_name, &lsi);
     if (s == nullptr) {
@@ -1801,6 +1800,14 @@
   return static_cast<ElfW(Addr)>(s->st_value + load_bias);
 }
 
+const char* soinfo::get_string(ElfW(Word) index) const {
+  if (has_min_version(1) && (index >= strtab_size)) {
+    __libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d", name, strtab_size, index);
+  }
+
+  return strtab + index;
+}
+
 /* Force any of the closed stdin, stdout and stderr to be associated with
    /dev/null. */
 static int nullify_closed_stdio() {
@@ -1909,6 +1916,9 @@
       case DT_STRTAB:
         strtab = reinterpret_cast<const char*>(load_bias + d->d_un.d_ptr);
         break;
+      case DT_STRSZ:
+        strtab_size = d->d_un.d_val;
+        break;
       case DT_SYMTAB:
         symtab = reinterpret_cast<ElfW(Sym)*>(load_bias + d->d_un.d_ptr);
         break;
@@ -2062,6 +2072,16 @@
           has_DT_SYMBOLIC = true;
         }
         break;
+      case DT_FLAGS_1:
+        if ((d->d_un.d_val & DF_1_GLOBAL) != 0) {
+          rtld_flags |= RTLD_GLOBAL;
+        }
+        // TODO: Implement other flags
+
+        if ((d->d_un.d_val & ~(DF_1_NOW | DF_1_GLOBAL)) != 0) {
+          DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
+        }
+        break;
 #if defined(__mips__)
       case DT_STRSZ:
         break;
@@ -2093,7 +2113,7 @@
 
       default:
         if (!relocating_linker) {
-          DEBUG("%s: unused DT entry: type %p arg %p", name,
+          DL_WARN("%s: unused DT entry: type %p arg %p", name,
               reinterpret_cast<void*>(d->d_tag), reinterpret_cast<void*>(d->d_un.d_val));
         }
         break;