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