blob: e77d03bae7c525588c74c86199de1fcb05ee6e2a [file] [log] [blame]
Mathieu Chartier19510f02015-05-26 14:44:35 -07001/*
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
Mathieu Chartierdc00f182016-07-14 10:10:44 -070017#include <sstream>
Mathieu Chartier19510f02015-05-26 14:44:35 -070018#include <string>
19#include <vector>
Mathieu Chartier19510f02015-05-26 14:44:35 -070020
Andreas Gampe9186ced2016-12-12 14:28:21 -080021#include "android-base/strings.h"
22
Mathieu Chartier19510f02015-05-26 14:44:35 -070023#include "common_runtime_test.h"
24
Mathieu Chartierdc00f182016-07-14 10:10:44 -070025#include "base/unix_file/fd_file.h"
Mathieu Chartier19510f02015-05-26 14:44:35 -070026#include "runtime/arch/instruction_set.h"
27#include "runtime/gc/heap.h"
28#include "runtime/gc/space/image_space.h"
29#include "runtime/os.h"
30#include "runtime/utils.h"
31#include "utils.h"
32
33#include <sys/types.h>
34#include <unistd.h>
35
36namespace art {
37
38class OatDumpTest : public CommonRuntimeTest {
39 protected:
40 virtual void SetUp() {
41 CommonRuntimeTest::SetUp();
42 core_art_location_ = GetCoreArtLocation();
43 core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
44 }
45
Roland Levillain04147ef2016-09-06 11:09:41 +010046 // Linking flavor.
47 enum Flavor {
48 kDynamic, // oatdump(d)
49 kStatic, // oatdump(d)s
50 };
51
Mathieu Chartier19510f02015-05-26 14:44:35 -070052 // Returns path to the oatdump binary.
Roland Levillain04147ef2016-09-06 11:09:41 +010053 std::string GetOatDumpFilePath(Flavor flavor) {
Mathieu Chartier19510f02015-05-26 14:44:35 -070054 std::string root = GetTestAndroidRoot();
55 root += "/bin/oatdump";
56 if (kIsDebugBuild) {
57 root += "d";
58 }
Roland Levillain04147ef2016-09-06 11:09:41 +010059 if (flavor == kStatic) {
60 root += "s";
61 }
Mathieu Chartier19510f02015-05-26 14:44:35 -070062 return root;
63 }
64
65 enum Mode {
66 kModeOat,
67 kModeArt,
68 kModeSymbolize,
69 };
70
Roland Levillain04147ef2016-09-06 11:09:41 +010071 // Display style.
72 enum Display {
73 kListOnly,
74 kListAndCode
75 };
76
Mathieu Chartier19510f02015-05-26 14:44:35 -070077 // Run the test with custom arguments.
Roland Levillain04147ef2016-09-06 11:09:41 +010078 bool Exec(Flavor flavor,
79 Mode mode,
Mathieu Chartierdc00f182016-07-14 10:10:44 -070080 const std::vector<std::string>& args,
Roland Levillain04147ef2016-09-06 11:09:41 +010081 Display display,
Mathieu Chartierdc00f182016-07-14 10:10:44 -070082 std::string* error_msg) {
Roland Levillain04147ef2016-09-06 11:09:41 +010083 std::string file_path = GetOatDumpFilePath(flavor);
Mathieu Chartier19510f02015-05-26 14:44:35 -070084
85 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
86
Mathieu Chartierdc00f182016-07-14 10:10:44 -070087 // ScratchFile scratch;
Mathieu Chartier19510f02015-05-26 14:44:35 -070088 std::vector<std::string> exec_argv = { file_path };
Mathieu Chartierdc00f182016-07-14 10:10:44 -070089 std::vector<std::string> expected_prefixes;
Mathieu Chartier19510f02015-05-26 14:44:35 -070090 if (mode == kModeSymbolize) {
91 exec_argv.push_back("--symbolize=" + core_oat_location_);
92 exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize");
Mathieu Chartier19510f02015-05-26 14:44:35 -070093 } else {
Mathieu Chartierdc00f182016-07-14 10:10:44 -070094 expected_prefixes.push_back("Dex file data for");
95 expected_prefixes.push_back("Num string ids:");
96 expected_prefixes.push_back("Num field ids:");
97 expected_prefixes.push_back("Num method ids:");
98 expected_prefixes.push_back("LOCATION:");
99 expected_prefixes.push_back("MAGIC:");
100 expected_prefixes.push_back("DEX FILE COUNT:");
Roland Levillain04147ef2016-09-06 11:09:41 +0100101 if (display == kListAndCode) {
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700102 // Code and dex code do not show up if list only.
103 expected_prefixes.push_back("DEX CODE:");
104 expected_prefixes.push_back("CODE:");
105 }
106 if (mode == kModeArt) {
107 exec_argv.push_back("--image=" + core_art_location_);
108 exec_argv.push_back("--instruction-set=" + std::string(
109 GetInstructionSetString(kRuntimeISA)));
110 expected_prefixes.push_back("IMAGE LOCATION:");
111 expected_prefixes.push_back("IMAGE BEGIN:");
112 expected_prefixes.push_back("kDexCaches:");
113 } else {
114 CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat));
115 exec_argv.push_back("--oat-file=" + core_oat_location_);
116 }
Mathieu Chartier19510f02015-05-26 14:44:35 -0700117 }
118 exec_argv.insert(exec_argv.end(), args.begin(), args.end());
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700119
120 bool result = true;
121 // We must set --android-root.
122 int link[2];
123 if (pipe(link) == -1) {
David Sehrda820e92016-08-04 09:41:55 -0700124 *error_msg = strerror(errno);
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700125 return false;
126 }
127
128 const pid_t pid = fork();
129 if (pid == -1) {
David Sehrda820e92016-08-04 09:41:55 -0700130 *error_msg = strerror(errno);
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700131 return false;
132 }
133
134 if (pid == 0) {
135 dup2(link[1], STDOUT_FILENO);
136 close(link[0]);
137 close(link[1]);
David Sehrda820e92016-08-04 09:41:55 -0700138 // change process groups, so we don't get reaped by ProcessManager
139 setpgid(0, 0);
140 // Use execv here rather than art::Exec to avoid blocking on waitpid here.
141 std::vector<char*> argv;
142 for (size_t i = 0; i < exec_argv.size(); ++i) {
143 argv.push_back(const_cast<char*>(exec_argv[i].c_str()));
144 }
145 argv.push_back(nullptr);
146 UNUSED(execv(argv[0], &argv[0]));
Andreas Gampe9186ced2016-12-12 14:28:21 -0800147 const std::string command_line(android::base::Join(exec_argv, ' '));
David Sehrda820e92016-08-04 09:41:55 -0700148 PLOG(ERROR) << "Failed to execv(" << command_line << ")";
149 // _exit to avoid atexit handlers in child.
150 _exit(1);
Mathieu Chartierdc00f182016-07-14 10:10:44 -0700151 } else {
152 close(link[1]);
153 static const size_t kLineMax = 256;
154 char line[kLineMax] = {};
155 size_t line_len = 0;
156 size_t total = 0;
157 std::vector<bool> found(expected_prefixes.size(), false);
158 while (true) {
159 while (true) {
160 size_t spaces = 0;
161 // Trim spaces at the start of the line.
162 for (; spaces < line_len && isspace(line[spaces]); ++spaces) {}
163 if (spaces > 0) {
164 line_len -= spaces;
165 memmove(&line[0], &line[spaces], line_len);
166 }
167 ssize_t bytes_read =
168 TEMP_FAILURE_RETRY(read(link[0], &line[line_len], kLineMax - line_len));
169 if (bytes_read <= 0) {
170 break;
171 }
172 line_len += bytes_read;
173 total += bytes_read;
174 }
175 if (line_len == 0) {
176 break;
177 }
178 // Check contents.
179 for (size_t i = 0; i < expected_prefixes.size(); ++i) {
180 const std::string& expected = expected_prefixes[i];
181 if (!found[i] &&
182 line_len >= expected.length() &&
183 memcmp(line, expected.c_str(), expected.length()) == 0) {
184 found[i] = true;
185 }
186 }
187 // Skip to next line.
188 size_t next_line = 0;
189 for (; next_line + 1 < line_len && line[next_line] != '\n'; ++next_line) {}
190 line_len -= next_line + 1;
191 memmove(&line[0], &line[next_line + 1], line_len);
192 }
193 if (mode == kModeSymbolize) {
194 EXPECT_EQ(total, 0u);
195 } else {
196 EXPECT_GT(total, 0u);
197 }
198 LOG(INFO) << "Processed bytes " << total;
199 close(link[0]);
200 int status = 0;
201 if (waitpid(pid, &status, 0) != -1) {
202 result = (status == 0);
203 }
204
205 for (size_t i = 0; i < expected_prefixes.size(); ++i) {
206 if (!found[i]) {
207 LOG(ERROR) << "Did not find prefix " << expected_prefixes[i];
208 result = false;
209 }
210 }
211 }
212
213 return result;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700214 }
215
216 private:
217 std::string core_art_location_;
218 std::string core_oat_location_;
219};
220
Vladimir Marko7da31702016-03-29 18:42:21 +0100221// Disable tests on arm and mips as they are taking too long to run. b/27824283.
222#if !defined(__arm__) && !defined(__mips__)
Mathieu Chartier19510f02015-05-26 14:44:35 -0700223TEST_F(OatDumpTest, TestImage) {
224 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100225 ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
226}
227TEST_F(OatDumpTest, TestImageStatic) {
228 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
229 std::string error_msg;
230 ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700231}
232
233TEST_F(OatDumpTest, TestOatImage) {
234 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100235 ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
236}
237TEST_F(OatDumpTest, TestOatImageStatic) {
238 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
239 std::string error_msg;
240 ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700241}
242
Mathieu Chartier19510f02015-05-26 14:44:35 -0700243TEST_F(OatDumpTest, TestNoDumpVmap) {
244 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100245 ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
246}
247TEST_F(OatDumpTest, TestNoDumpVmapStatic) {
248 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
249 std::string error_msg;
250 ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700251}
252
253TEST_F(OatDumpTest, TestNoDisassemble) {
254 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100255 ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg))
256 << error_msg;
257}
258TEST_F(OatDumpTest, TestNoDisassembleStatic) {
259 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
260 std::string error_msg;
261 ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700262}
263
264TEST_F(OatDumpTest, TestListClasses) {
265 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100266 ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
267}
268TEST_F(OatDumpTest, TestListClassesStatic) {
269 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
270 std::string error_msg;
271 ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700272}
273
274TEST_F(OatDumpTest, TestListMethods) {
275 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100276 ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
277}
278TEST_F(OatDumpTest, TestListMethodsStatic) {
279 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
280 std::string error_msg;
281 ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700282}
283
284TEST_F(OatDumpTest, TestSymbolize) {
285 std::string error_msg;
Roland Levillain04147ef2016-09-06 11:09:41 +0100286 ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
287}
288TEST_F(OatDumpTest, TestSymbolizeStatic) {
289 TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
290 std::string error_msg;
291 ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
Mathieu Chartier19510f02015-05-26 14:44:35 -0700292}
Nicolas Geoffray973ce7c2016-03-24 09:23:04 +0000293#endif
Mathieu Chartier19510f02015-05-26 14:44:35 -0700294} // namespace art