Move GetAndroidToolsDir to common location.

Move the code which looks for the prebuilts directory
to CommonRuntimeTest and add test for it.

Change-Id: Id804de31c466656957fdd4b6a470f80a00477aed
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 7283710..8c61871 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -171,6 +171,7 @@
   runtime/oat_file_test.cc \
   runtime/oat_file_assistant_test.cc \
   runtime/parsed_options_test.cc \
+  runtime/prebuilt_tools_test.cc \
   runtime/reference_table_test.cc \
   runtime/thread_pool_test.cc \
   runtime/transaction_test.cc \
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index dd5e0c2..5a97c3b 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -55,36 +55,6 @@
     expected_lines_.push_back(ExpectedLine {substr, next, at_file, at_line});
   }
 
-  static std::string GetObjdumpPath() {
-    const char* android_build_top = getenv("ANDROID_BUILD_TOP");
-    if (android_build_top != nullptr) {
-      std::string host_prebuilts = std::string(android_build_top) +
-                                   "/prebuilts/gcc/linux-x86/host/";
-      // Read the content of the directory.
-      std::set<std::string> entries;
-      DIR* dir = opendir(host_prebuilts.c_str());
-      if (dir != nullptr) {
-        struct dirent* entry;
-        while ((entry = readdir(dir)) != nullptr) {
-          if (strstr(entry->d_name, "linux-glibc")) {
-            entries.insert(host_prebuilts + entry->d_name);
-          }
-        }
-        closedir(dir);
-      }
-      // Strings are sorted so the last one should be the most recent version.
-      if (!entries.empty()) {
-        std::string path = *entries.rbegin() + "/x86_64-linux/bin/objdump";
-        struct stat st;
-        if (stat(path.c_str(), &st) == 0) {
-          return path;  // File exists.
-        }
-      }
-    }
-    ADD_FAILURE() << "Can not find prebuild objdump.";
-    return "objdump";  // Use the system objdump as fallback.
-  }
-
   // Pretty-print the generated DWARF data using objdump.
   template<typename Elf_Word, typename Elf_Sword, typename Elf_Addr, typename Elf_Dyn,
            typename Elf_Sym, typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr>
@@ -130,8 +100,8 @@
 
     // Read the elf file back using objdump.
     std::vector<std::string> lines;
-    std::string cmd = GetObjdumpPath();
-    cmd = cmd + " " + args + " " + file.GetFilename() + " 2>&1";
+    std::string cmd = GetAndroidHostToolsDir();
+    cmd = cmd + "objdump " + args + " " + file.GetFilename() + " 2>&1";
     FILE* output = popen(cmd.data(), "r");
     char buffer[1024];
     const char* line;
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index a171e59..772fa9a 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -43,8 +43,6 @@
 static constexpr bool kPrintResults = false;
 #endif
 
-static const char* TOOL_PREFIX = "arm-linux-androideabi-";
-
 void SetAndroidData() {
   const char* data = getenv("ANDROID_DATA");
   if (data == nullptr) {
@@ -65,87 +63,6 @@
   return *s1 - *s2;
 }
 
-std::string GetAndroidToolsDir() {
-  std::string root;
-  const char* android_build_top = getenv("ANDROID_BUILD_TOP");
-  if (android_build_top != nullptr) {
-    root += android_build_top;
-  } else {
-    // Not set by build server, so default to current directory
-    char* cwd = getcwd(nullptr, 0);
-    setenv("ANDROID_BUILD_TOP", cwd, 1);
-    root += cwd;
-    free(cwd);
-  }
-
-  // Look for "prebuilts"
-  std::string toolsdir = root;
-  struct stat st;
-  while (toolsdir != "") {
-    std::string prebuilts = toolsdir + "/prebuilts";
-    if (stat(prebuilts.c_str(), &st) == 0) {
-       // Found prebuilts.
-       toolsdir += "/prebuilts/gcc/linux-x86/arm";
-       break;
-    }
-    // Not present, move up one dir.
-    size_t slash = toolsdir.rfind('/');
-    if (slash == std::string::npos) {
-      toolsdir = "";
-    } else {
-      toolsdir = toolsdir.substr(0, slash-1);
-    }
-  }
-  bool statok = stat(toolsdir.c_str(), &st) == 0;
-  if (!statok) {
-    return "";      // Use path.
-  }
-
-  DIR* dir = opendir(toolsdir.c_str());
-  if (dir == nullptr) {
-    return "";      // Use path.
-  }
-
-  struct dirent* entry;
-  std::string founddir;
-  double maxversion  = 0;
-
-  // Find the latest version of the arm-eabi tools (biggest version number).
-  // Suffix on toolsdir will be something like "arm-eabi-4.8"
-  while ((entry = readdir(dir)) != nullptr) {
-    std::string subdir = toolsdir + std::string("/") + std::string(entry->d_name);
-    size_t eabi = subdir.find(TOOL_PREFIX);
-    if (eabi != std::string::npos) {
-      // Check if "bin/{as,objcopy,objdump}" exist under this folder.
-      struct stat exec_st;
-      std::string exec_path;
-      exec_path = subdir + "/bin/" + TOOL_PREFIX + "as";
-      if (stat(exec_path.c_str(), &exec_st) != 0)
-        continue;
-      exec_path = subdir + "/bin/" + TOOL_PREFIX + "objcopy";
-      if (stat(exec_path.c_str(), &exec_st) != 0)
-        continue;
-      exec_path = subdir + "/bin/" + TOOL_PREFIX + "objdump";
-      if (stat(exec_path.c_str(), &exec_st) != 0)
-        continue;
-
-      std::string suffix = subdir.substr(eabi + strlen(TOOL_PREFIX));
-      double version = strtod(suffix.c_str(), nullptr);
-      if (version > maxversion) {
-        maxversion = version;
-        founddir = subdir;
-      }
-    }
-  }
-  closedir(dir);
-  bool found = founddir != "";
-  if (!found) {
-    return "";      // Use path.
-  }
-
-  return founddir + "/bin/";
-}
-
 void dump(std::vector<uint8_t>& code, const char* testname) {
   // This will only work on the host.  There is no as, objcopy or objdump on the
   // device.
@@ -155,7 +72,7 @@
 
   if (!results_ok) {
     setup_results();
-    toolsdir = GetAndroidToolsDir();
+    toolsdir = CommonRuntimeTest::GetAndroidTargetToolsDir(kThumb2);
     SetAndroidData();
     results_ok = true;
   }
@@ -187,19 +104,18 @@
   char cmd[1024];
 
   // Assemble the .S
-  snprintf(cmd, sizeof(cmd), "%s%sas %s -o %s.o", toolsdir.c_str(), TOOL_PREFIX, filename, filename);
+  snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
   system(cmd);
 
   // Remove the $d symbols to prevent the disassembler dumping the instructions
   // as .word
-  snprintf(cmd, sizeof(cmd), "%s%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), TOOL_PREFIX,
-    filename, filename);
+  snprintf(cmd, sizeof(cmd), "%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), filename, filename);
   system(cmd);
 
   // Disassemble.
 
-  snprintf(cmd, sizeof(cmd), "%s%sobjdump -d %s.oo | grep '^  *[0-9a-f][0-9a-f]*:'",
-    toolsdir.c_str(), TOOL_PREFIX, filename);
+  snprintf(cmd, sizeof(cmd), "%sobjdump -d %s.oo | grep '^  *[0-9a-f][0-9a-f]*:'",
+    toolsdir.c_str(), filename);
   if (kPrintResults) {
     // Print the results only, don't check. This is used to generate new output for inserting
     // into the .inc file.
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 60b7fa2..e17b885 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -16,6 +16,7 @@
 
 #include "common_runtime_test.h"
 
+#include <cstdio>
 #include <dirent.h>
 #include <dlfcn.h>
 #include <fcntl.h>
@@ -188,6 +189,82 @@
   }
 }
 
+// Helper - find directory with the following format:
+// ${ANDROID_BUILD_TOP}/${subdir1}/${subdir2}-${version}/${subdir3}/bin/
+static std::string GetAndroidToolsDir(const std::string& subdir1,
+                                      const std::string& subdir2,
+                                      const std::string& subdir3) {
+  std::string root;
+  const char* android_build_top = getenv("ANDROID_BUILD_TOP");
+  if (android_build_top != nullptr) {
+    root = android_build_top;
+  } else {
+    // Not set by build server, so default to current directory
+    char* cwd = getcwd(nullptr, 0);
+    setenv("ANDROID_BUILD_TOP", cwd, 1);
+    root = cwd;
+    free(cwd);
+  }
+
+  std::string toolsdir = root + "/" + subdir1;
+  std::string founddir;
+  DIR* dir;
+  if ((dir = opendir(toolsdir.c_str())) != nullptr) {
+    float maxversion = 0;
+    struct dirent* entry;
+    while ((entry = readdir(dir)) != nullptr) {
+      std::string format = subdir2 + "-%f";
+      float version;
+      if (std::sscanf(entry->d_name, format.c_str(), &version) == 1) {
+        if (version > maxversion) {
+          maxversion = version;
+          founddir = toolsdir + "/" + entry->d_name + "/" + subdir3 + "/bin/";
+        }
+      }
+    }
+    closedir(dir);
+  }
+
+  if (founddir.empty()) {
+    ADD_FAILURE() << "Can not find Android tools directory.";
+  }
+  return founddir;
+}
+
+std::string CommonRuntimeTest::GetAndroidHostToolsDir() {
+  return GetAndroidToolsDir("prebuilts/gcc/linux-x86/host",
+                            "x86_64-linux-glibc2.15",
+                            "x86_64-linux");
+}
+
+std::string CommonRuntimeTest::GetAndroidTargetToolsDir(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return GetAndroidToolsDir("prebuilts/gcc/linux-x86/arm",
+                                "arm-linux-androideabi",
+                                "arm-linux-androideabi");
+    case kArm64:
+      return GetAndroidToolsDir("prebuilts/gcc/linux-x86/aarch64",
+                                "aarch64-linux-android",
+                                "aarch64-linux-android");
+    case kX86:
+    case kX86_64:
+      return GetAndroidToolsDir("prebuilts/gcc/linux-x86/x86",
+                                "x86_64-linux-android",
+                                "x86_64-linux-android");
+    case kMips:
+    case kMips64:
+      return GetAndroidToolsDir("prebuilts/gcc/linux-x86/mips",
+                                "mips64el-linux-android",
+                                "mips64el-linux-android");
+    case kNone:
+      break;
+  }
+  ADD_FAILURE() << "Invalid isa " << isa;
+  return "";
+}
+
 std::string CommonRuntimeTest::GetCoreArtLocation() {
   return GetCoreFileLocation("art");
 }
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 5fbc2ee..9917378 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -22,6 +22,7 @@
 
 #include <string>
 
+#include "arch/instruction_set.h"
 #include "base/mutex.h"
 #include "globals.h"
 #include "os.h"
@@ -79,6 +80,12 @@
   // Gets the path of the libcore dex file.
   static std::string GetLibCoreDexFileName();
 
+  // Returns bin directory which contains host's prebuild tools.
+  static std::string GetAndroidHostToolsDir();
+
+  // Returns bin directory which contains target's prebuild tools.
+  static std::string GetAndroidTargetToolsDir(InstructionSet isa);
+
  protected:
   static bool IsHost() {
     return !kIsTargetBuild;
diff --git a/runtime/prebuilt_tools_test.cc b/runtime/prebuilt_tools_test.cc
new file mode 100644
index 0000000..453c0da
--- /dev/null
+++ b/runtime/prebuilt_tools_test.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "common_runtime_test.h"
+
+#include <cstdio>
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+// Run the tests only on host.
+#ifndef HAVE_ANDROID_OS
+
+class PrebuiltToolsTest : public CommonRuntimeTest {
+};
+
+static void CheckToolsExist(const std::string& tools_dir) {
+  const char* tools[] { "as", "objcopy", "objdump" };  // NOLINT
+  for (const char* tool : tools) {
+    struct stat exec_st;
+    std::string exec_path = tools_dir + tool;
+    if (stat(exec_path.c_str(), &exec_st) != 0) {
+      ADD_FAILURE() << "Can not find " << tool << " in " << tools_dir;
+    }
+  }
+}
+
+TEST_F(PrebuiltToolsTest, CheckHostTools) {
+  std::string tools_dir = GetAndroidHostToolsDir();
+  if (tools_dir.empty()) {
+    ADD_FAILURE() << "Can not find Android tools directory for host";
+  } else {
+    CheckToolsExist(tools_dir);
+  }
+}
+
+TEST_F(PrebuiltToolsTest, CheckTargetTools) {
+  InstructionSet isas[] = { kArm, kArm64, kThumb2, kX86, kX86_64, kMips, kMips64 };  // NOLINT
+  for (InstructionSet isa : isas) {
+    std::string tools_dir = GetAndroidTargetToolsDir(isa);
+    if (tools_dir.empty()) {
+      ADD_FAILURE() << "Can not find Android tools directory for " << isa;
+    } else {
+      CheckToolsExist(tools_dir);
+    }
+  }
+}
+
+#endif  // HAVE_ANDROID_OS
+
+}  // namespace art