Revert "Revert "Use dlopen to load oat files.""

This reverts commit 7a46b7e235a7c35191cd9ddbab6ca4db0e535da5.

Change-Id: I33439d0e3d7a7e63591a8c7b356e716dcb62bca1
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 189306d..fa041a9 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -439,6 +439,14 @@
                     page_aligned_byte_count, prot, false);
 }
 
+MemMap* MemMap::MapDummy(const char* name, uint8_t* addr, size_t byte_count) {
+  if (byte_count == 0) {
+    return new MemMap(name, nullptr, 0, nullptr, 0, 0, false);
+  }
+  const size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize);
+  return new MemMap(name, addr, byte_count, addr, page_aligned_byte_count, 0, true /* reuse */);
+}
+
 MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, size_t byte_count, int prot, int flags,
                                  int fd, off_t start, bool reuse, const char* filename,
                                  std::string* error_msg) {
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 6023a70..14387ee 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -64,6 +64,12 @@
   static MemMap* MapAnonymous(const char* ashmem_name, uint8_t* addr, size_t byte_count, int prot,
                               bool low_4gb, bool reuse, std::string* error_msg);
 
+  // Create placeholder for a region allocated by direct call to mmap.
+  // This is useful when we do not have control over the code calling mmap,
+  // but when we still want to keep track of it in the list.
+  // The region is not considered to be owned and will not be unmmaped.
+  static MemMap* MapDummy(const char* name, uint8_t* addr, size_t byte_count);
+
   // Map part of a file, taking care of non-page aligned offsets.  The
   // "start" offset is absolute, not relative.
   //
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 6fda790..55a2fbb00 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -21,6 +21,9 @@
 #include <unistd.h>
 
 #include <cstdlib>
+#ifndef __APPLE__
+#include <link.h>  // for dl_iterate_phdr.
+#endif
 #include <sstream>
 
 // dlopen_ext support from bionic.
@@ -35,6 +38,7 @@
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "oat.h"
+#include "mem_map.h"
 #include "mirror/class.h"
 #include "mirror/object-inl.h"
 #include "os.h"
@@ -45,13 +49,13 @@
 namespace art {
 
 // Whether OatFile::Open will try DlOpen() first. Fallback is our own ELF loader.
-static constexpr bool kUseDlopen = false;
+static constexpr bool kUseDlopen = true;
 
 // Whether OatFile::Open will try DlOpen() on the host. On the host we're not linking against
 // bionic, so cannot take advantage of the support for changed semantics (loading the same soname
 // multiple times). However, if/when we switch the above, we likely want to switch this, too,
 // to get test coverage of the code paths.
-static constexpr bool kUseDlopenOnHost = false;
+static constexpr bool kUseDlopenOnHost = true;
 
 // For debugging, Open will print DlOpen error message if set to true.
 static constexpr bool kPrintDlOpenErrorMessage = false;
@@ -210,6 +214,15 @@
 
 bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base,
                      const char* abs_dex_location, std::string* error_msg) {
+#ifdef __APPLE__
+  // The dl_iterate_phdr syscall is missing.  There is similar API on OSX,
+  // but let's fallback to the custom loading code for the time being.
+  UNUSED(elf_filename);
+  UNUSED(requested_base);
+  UNUSED(abs_dex_location);
+  UNUSED(error_msg);
+  return false;
+#else
   std::unique_ptr<char> absolute_path(realpath(elf_filename.c_str(), nullptr));
   if (absolute_path == nullptr) {
     *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
@@ -217,7 +230,7 @@
   }
 #ifdef HAVE_ANDROID_OS
   android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
+  extinfo.flags = ANDROID_DLEXT_FORCE_LOAD | ANDROID_DLEXT_FORCE_FIXED_VADDR;
   dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
 #else
   dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW);
@@ -264,7 +277,27 @@
     bss_end_ += sizeof(uint32_t);
   }
 
+  // Ask the linker where it mmaped the file and notify our mmap wrapper of the regions.
+  struct dl_iterate_context {
+    static int callback(struct dl_phdr_info *info, size_t /* size */, void *data) {
+      auto* context = reinterpret_cast<dl_iterate_context*>(data);
+      if (info->dlpi_name != nullptr && info->dlpi_name == context->so_name) {
+        for (int i = 0; i < info->dlpi_phnum; i++) {
+          if (info->dlpi_phdr[i].p_type == PT_LOAD) {
+            auto vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+            MemMap::MapDummy(info->dlpi_name, vaddr, info->dlpi_phdr[i].p_memsz);
+          }
+        }
+      }
+      return 0;
+    }
+    std::string so_name;
+  } context;
+  context.so_name = elf_filename;
+  dl_iterate_phdr(dl_iterate_context::callback, &context);
+
   return Setup(abs_dex_location, error_msg);
+#endif  // __APPLE__
 }
 
 bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin,
diff --git a/test/137-cfi/run b/test/137-cfi/run
new file mode 100755
index 0000000..78cf2aa
--- /dev/null
+++ b/test/137-cfi/run
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Temporarily disable address space layout randomization (ASLR).
+# This is need on host so that the linker loads core.oat at fixed address.
+export LD_USE_LOAD_BIAS=1
+
+exec ${RUN} "$@"
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 658ba53..a88adc1 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -26,7 +26,7 @@
 public class Main implements Comparator<Main> {
   // Whether to test local unwinding. Libunwind uses linker info to find executables. As we do
   // not dlopen at the moment, this doesn't work, so keep it off for now.
-  public final static boolean TEST_LOCAL_UNWINDING = false;
+  public final static boolean TEST_LOCAL_UNWINDING = true;
 
   // Unwinding another process, modelling debuggerd. This doesn't use the linker, so should work
   // no matter whether we're using dlopen or not.