Home | History | Annotate | Download | only in oatdump
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <sstream>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include "android-base/strings.h"
     22 
     23 #include "common_runtime_test.h"
     24 
     25 #include "base/unix_file/fd_file.h"
     26 #include "runtime/arch/instruction_set.h"
     27 #include "runtime/exec_utils.h"
     28 #include "runtime/gc/heap.h"
     29 #include "runtime/gc/space/image_space.h"
     30 #include "runtime/os.h"
     31 #include "runtime/utils.h"
     32 #include "utils.h"
     33 
     34 #include <sys/types.h>
     35 #include <unistd.h>
     36 
     37 namespace art {
     38 
     39 class OatDumpTest : public CommonRuntimeTest {
     40  protected:
     41   virtual void SetUp() {
     42     CommonRuntimeTest::SetUp();
     43     core_art_location_ = GetCoreArtLocation();
     44     core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
     45   }
     46 
     47   // Linking flavor.
     48   enum Flavor {
     49     kDynamic,  // oatdump(d)
     50     kStatic,   // oatdump(d)s
     51   };
     52 
     53   // Returns path to the oatdump binary.
     54   std::string GetOatDumpFilePath(Flavor flavor) {
     55     std::string root = GetTestAndroidRoot();
     56     root += "/bin/oatdump";
     57     if (kIsDebugBuild) {
     58       root += "d";
     59     }
     60     if (flavor == kStatic) {
     61       root += "s";
     62     }
     63     return root;
     64   }
     65 
     66   enum Mode {
     67     kModeOat,
     68     kModeArt,
     69     kModeSymbolize,
     70   };
     71 
     72   // Display style.
     73   enum Display {
     74     kListOnly,
     75     kListAndCode
     76   };
     77 
     78   // Run the test with custom arguments.
     79   bool Exec(Flavor flavor,
     80             Mode mode,
     81             const std::vector<std::string>& args,
     82             Display display,
     83             std::string* error_msg) {
     84     std::string file_path = GetOatDumpFilePath(flavor);
     85 
     86     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
     87 
     88     // ScratchFile scratch;
     89     std::vector<std::string> exec_argv = { file_path };
     90     std::vector<std::string> expected_prefixes;
     91     if (mode == kModeSymbolize) {
     92       exec_argv.push_back("--symbolize=" + core_oat_location_);
     93       exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize");
     94     } else {
     95       expected_prefixes.push_back("Dex file data for");
     96       expected_prefixes.push_back("Num string ids:");
     97       expected_prefixes.push_back("Num field ids:");
     98       expected_prefixes.push_back("Num method ids:");
     99       expected_prefixes.push_back("LOCATION:");
    100       expected_prefixes.push_back("MAGIC:");
    101       expected_prefixes.push_back("DEX FILE COUNT:");
    102       if (display == kListAndCode) {
    103         // Code and dex code do not show up if list only.
    104         expected_prefixes.push_back("DEX CODE:");
    105         expected_prefixes.push_back("CODE:");
    106         expected_prefixes.push_back("CodeInfoEncoding");
    107         expected_prefixes.push_back("CodeInfoInlineInfo");
    108       }
    109       if (mode == kModeArt) {
    110         exec_argv.push_back("--image=" + core_art_location_);
    111         exec_argv.push_back("--instruction-set=" + std::string(
    112             GetInstructionSetString(kRuntimeISA)));
    113         expected_prefixes.push_back("IMAGE LOCATION:");
    114         expected_prefixes.push_back("IMAGE BEGIN:");
    115         expected_prefixes.push_back("kDexCaches:");
    116       } else {
    117         CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat));
    118         exec_argv.push_back("--oat-file=" + core_oat_location_);
    119       }
    120     }
    121     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
    122 
    123     bool result = true;
    124     // We must set --android-root.
    125     int link[2];
    126     if (pipe(link) == -1) {
    127       *error_msg = strerror(errno);
    128       return false;
    129     }
    130 
    131     const pid_t pid = fork();
    132     if (pid == -1) {
    133       *error_msg = strerror(errno);
    134       return false;
    135     }
    136 
    137     if (pid == 0) {
    138       dup2(link[1], STDOUT_FILENO);
    139       close(link[0]);
    140       close(link[1]);
    141       // change process groups, so we don't get reaped by ProcessManager
    142       setpgid(0, 0);
    143       // Use execv here rather than art::Exec to avoid blocking on waitpid here.
    144       std::vector<char*> argv;
    145       for (size_t i = 0; i < exec_argv.size(); ++i) {
    146         argv.push_back(const_cast<char*>(exec_argv[i].c_str()));
    147       }
    148       argv.push_back(nullptr);
    149       UNUSED(execv(argv[0], &argv[0]));
    150       const std::string command_line(android::base::Join(exec_argv, ' '));
    151       PLOG(ERROR) << "Failed to execv(" << command_line << ")";
    152       // _exit to avoid atexit handlers in child.
    153       _exit(1);
    154     } else {
    155       close(link[1]);
    156       static const size_t kLineMax = 256;
    157       char line[kLineMax] = {};
    158       size_t line_len = 0;
    159       size_t total = 0;
    160       std::vector<bool> found(expected_prefixes.size(), false);
    161       while (true) {
    162         while (true) {
    163           size_t spaces = 0;
    164           // Trim spaces at the start of the line.
    165           for (; spaces < line_len && isspace(line[spaces]); ++spaces) {}
    166           if (spaces > 0) {
    167             line_len -= spaces;
    168             memmove(&line[0], &line[spaces], line_len);
    169           }
    170           ssize_t bytes_read =
    171               TEMP_FAILURE_RETRY(read(link[0], &line[line_len], kLineMax - line_len));
    172           if (bytes_read <= 0) {
    173             break;
    174           }
    175           line_len += bytes_read;
    176           total += bytes_read;
    177         }
    178         if (line_len == 0) {
    179           break;
    180         }
    181         // Check contents.
    182         for (size_t i = 0; i < expected_prefixes.size(); ++i) {
    183           const std::string& expected = expected_prefixes[i];
    184           if (!found[i] &&
    185               line_len >= expected.length() &&
    186               memcmp(line, expected.c_str(), expected.length()) == 0) {
    187             found[i] = true;
    188           }
    189         }
    190         // Skip to next line.
    191         size_t next_line = 0;
    192         for (; next_line + 1 < line_len && line[next_line] != '\n'; ++next_line) {}
    193         line_len -= next_line + 1;
    194         memmove(&line[0], &line[next_line + 1], line_len);
    195       }
    196       if (mode == kModeSymbolize) {
    197         EXPECT_EQ(total, 0u);
    198       } else {
    199         EXPECT_GT(total, 0u);
    200       }
    201       LOG(INFO) << "Processed bytes " << total;
    202       close(link[0]);
    203       int status = 0;
    204       if (waitpid(pid, &status, 0) != -1) {
    205         result = (status == 0);
    206       }
    207 
    208       for (size_t i = 0; i < expected_prefixes.size(); ++i) {
    209         if (!found[i]) {
    210           LOG(ERROR) << "Did not find prefix " << expected_prefixes[i];
    211           result = false;
    212         }
    213       }
    214     }
    215 
    216     return result;
    217   }
    218 
    219  private:
    220   std::string core_art_location_;
    221   std::string core_oat_location_;
    222 };
    223 
    224 // Disable tests on arm and mips as they are taking too long to run. b/27824283.
    225 #if !defined(__arm__) && !defined(__mips__)
    226 TEST_F(OatDumpTest, TestImage) {
    227   std::string error_msg;
    228   ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
    229 }
    230 TEST_F(OatDumpTest, TestImageStatic) {
    231   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    232   std::string error_msg;
    233   ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
    234 }
    235 
    236 TEST_F(OatDumpTest, TestOatImage) {
    237   std::string error_msg;
    238   ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
    239 }
    240 TEST_F(OatDumpTest, TestOatImageStatic) {
    241   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    242   std::string error_msg;
    243   ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
    244 }
    245 
    246 TEST_F(OatDumpTest, TestNoDumpVmap) {
    247   std::string error_msg;
    248   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
    249 }
    250 TEST_F(OatDumpTest, TestNoDumpVmapStatic) {
    251   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    252   std::string error_msg;
    253   ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
    254 }
    255 
    256 TEST_F(OatDumpTest, TestNoDisassemble) {
    257   std::string error_msg;
    258   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg))
    259       << error_msg;
    260 }
    261 TEST_F(OatDumpTest, TestNoDisassembleStatic) {
    262   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    263   std::string error_msg;
    264   ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg)) << error_msg;
    265 }
    266 
    267 TEST_F(OatDumpTest, TestListClasses) {
    268   std::string error_msg;
    269   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
    270 }
    271 TEST_F(OatDumpTest, TestListClassesStatic) {
    272   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    273   std::string error_msg;
    274   ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
    275 }
    276 
    277 TEST_F(OatDumpTest, TestListMethods) {
    278   std::string error_msg;
    279   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
    280 }
    281 TEST_F(OatDumpTest, TestListMethodsStatic) {
    282   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    283   std::string error_msg;
    284   ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
    285 }
    286 
    287 TEST_F(OatDumpTest, TestSymbolize) {
    288   std::string error_msg;
    289   ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
    290 }
    291 TEST_F(OatDumpTest, TestSymbolizeStatic) {
    292   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
    293   std::string error_msg;
    294   ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
    295 }
    296 #endif
    297 }  // namespace art
    298