blob: 48e9eb59647f1c48f845389698f717b6560aaf1c [file] [log] [blame]
Vladimir Marko1352f132017-04-28 15:28:29 +01001/*
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#ifndef ART_OATDUMP_OATDUMP_TEST_H_
18#define ART_OATDUMP_OATDUMP_TEST_H_
19
20#include <sstream>
21#include <string>
22#include <vector>
23
24#include "android-base/strings.h"
25
26#include "common_runtime_test.h"
27
28#include "base/unix_file/fd_file.h"
29#include "runtime/arch/instruction_set.h"
30#include "runtime/exec_utils.h"
31#include "runtime/gc/heap.h"
32#include "runtime/gc/space/image_space.h"
33#include "runtime/os.h"
34#include "runtime/utils.h"
35#include "utils.h"
36
37#include <sys/types.h>
38#include <unistd.h>
39
40namespace art {
41
42class OatDumpTest : public CommonRuntimeTest {
43 protected:
44 virtual void SetUp() {
45 CommonRuntimeTest::SetUp();
46 core_art_location_ = GetCoreArtLocation();
47 core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
48 }
49
50 // Linking flavor.
51 enum Flavor {
52 kDynamic, // oatdump(d)
53 kStatic, // oatdump(d)s
54 };
55
56 // Returns path to the oatdump binary.
57 std::string GetOatDumpFilePath(Flavor flavor) {
58 std::string root = GetTestAndroidRoot();
59 root += "/bin/oatdump";
60 if (kIsDebugBuild) {
61 root += "d";
62 }
63 if (flavor == kStatic) {
64 root += "s";
65 }
66 return root;
67 }
68
69 enum Mode {
70 kModeOat,
71 kModeArt,
72 kModeSymbolize,
73 };
74
75 // Display style.
76 enum Display {
77 kListOnly,
78 kListAndCode
79 };
80
81 // Run the test with custom arguments.
82 bool Exec(Flavor flavor,
83 Mode mode,
84 const std::vector<std::string>& args,
85 Display display,
86 std::string* error_msg) {
87 std::string file_path = GetOatDumpFilePath(flavor);
88
89 EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
90
91 // ScratchFile scratch;
92 std::vector<std::string> exec_argv = { file_path };
93 std::vector<std::string> expected_prefixes;
94 if (mode == kModeSymbolize) {
95 exec_argv.push_back("--symbolize=" + core_oat_location_);
96 exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize");
97 } else {
98 expected_prefixes.push_back("Dex file data for");
99 expected_prefixes.push_back("Num string ids:");
100 expected_prefixes.push_back("Num field ids:");
101 expected_prefixes.push_back("Num method ids:");
102 expected_prefixes.push_back("LOCATION:");
103 expected_prefixes.push_back("MAGIC:");
104 expected_prefixes.push_back("DEX FILE COUNT:");
105 if (display == kListAndCode) {
106 // Code and dex code do not show up if list only.
107 expected_prefixes.push_back("DEX CODE:");
108 expected_prefixes.push_back("CODE:");
109 expected_prefixes.push_back("CodeInfoEncoding");
110 expected_prefixes.push_back("CodeInfoInlineInfo");
111 }
112 if (mode == kModeArt) {
113 exec_argv.push_back("--image=" + core_art_location_);
114 exec_argv.push_back("--instruction-set=" + std::string(
115 GetInstructionSetString(kRuntimeISA)));
116 expected_prefixes.push_back("IMAGE LOCATION:");
117 expected_prefixes.push_back("IMAGE BEGIN:");
118 expected_prefixes.push_back("kDexCaches:");
119 } else {
120 CHECK_EQ(static_cast<size_t>(mode), static_cast<size_t>(kModeOat));
121 exec_argv.push_back("--oat-file=" + core_oat_location_);
122 }
123 }
124 exec_argv.insert(exec_argv.end(), args.begin(), args.end());
125
126 bool result = true;
127 // We must set --android-root.
128 int link[2];
129 if (pipe(link) == -1) {
130 *error_msg = strerror(errno);
131 return false;
132 }
133
134 const pid_t pid = fork();
135 if (pid == -1) {
136 *error_msg = strerror(errno);
137 return false;
138 }
139
140 if (pid == 0) {
141 dup2(link[1], STDOUT_FILENO);
142 close(link[0]);
143 close(link[1]);
144 // change process groups, so we don't get reaped by ProcessManager
145 setpgid(0, 0);
146 // Use execv here rather than art::Exec to avoid blocking on waitpid here.
147 std::vector<char*> argv;
148 for (size_t i = 0; i < exec_argv.size(); ++i) {
149 argv.push_back(const_cast<char*>(exec_argv[i].c_str()));
150 }
151 argv.push_back(nullptr);
152 UNUSED(execv(argv[0], &argv[0]));
153 const std::string command_line(android::base::Join(exec_argv, ' '));
154 PLOG(ERROR) << "Failed to execv(" << command_line << ")";
155 // _exit to avoid atexit handlers in child.
156 _exit(1);
157 } else {
158 close(link[1]);
159 static const size_t kLineMax = 256;
160 char line[kLineMax] = {};
161 size_t line_len = 0;
162 size_t total = 0;
163 std::vector<bool> found(expected_prefixes.size(), false);
164 while (true) {
165 while (true) {
166 size_t spaces = 0;
167 // Trim spaces at the start of the line.
168 for (; spaces < line_len && isspace(line[spaces]); ++spaces) {}
169 if (spaces > 0) {
170 line_len -= spaces;
171 memmove(&line[0], &line[spaces], line_len);
172 }
173 ssize_t bytes_read =
174 TEMP_FAILURE_RETRY(read(link[0], &line[line_len], kLineMax - line_len));
175 if (bytes_read <= 0) {
176 break;
177 }
178 line_len += bytes_read;
179 total += bytes_read;
180 }
181 if (line_len == 0) {
182 break;
183 }
184 // Check contents.
185 for (size_t i = 0; i < expected_prefixes.size(); ++i) {
186 const std::string& expected = expected_prefixes[i];
187 if (!found[i] &&
188 line_len >= expected.length() &&
189 memcmp(line, expected.c_str(), expected.length()) == 0) {
190 found[i] = true;
191 }
192 }
193 // Skip to next line.
194 size_t next_line = 0;
195 for (; next_line + 1 < line_len && line[next_line] != '\n'; ++next_line) {}
196 line_len -= next_line + 1;
197 memmove(&line[0], &line[next_line + 1], line_len);
198 }
199 if (mode == kModeSymbolize) {
200 EXPECT_EQ(total, 0u);
201 } else {
202 EXPECT_GT(total, 0u);
203 }
204 LOG(INFO) << "Processed bytes " << total;
205 close(link[0]);
206 int status = 0;
207 if (waitpid(pid, &status, 0) != -1) {
208 result = (status == 0);
209 }
210
211 for (size_t i = 0; i < expected_prefixes.size(); ++i) {
212 if (!found[i]) {
213 LOG(ERROR) << "Did not find prefix " << expected_prefixes[i];
214 result = false;
215 }
216 }
217 }
218
219 return result;
220 }
221
222 private:
223 std::string core_art_location_;
224 std::string core_oat_location_;
225};
226
227} // namespace art
228
229#endif // ART_OATDUMP_OATDUMP_TEST_H_