• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SetUp()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.
GetOatDumpFilePath(Flavor flavor)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.
Exec(Flavor flavor,Mode mode,const std::vector<std::string> & args,Display display,std::string * error_msg)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__)
TEST_F(OatDumpTest,TestImage)226 TEST_F(OatDumpTest, TestImage) {
227   std::string error_msg;
228   ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
229 }
TEST_F(OatDumpTest,TestImageStatic)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 
TEST_F(OatDumpTest,TestOatImage)236 TEST_F(OatDumpTest, TestOatImage) {
237   std::string error_msg;
238   ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
239 }
TEST_F(OatDumpTest,TestOatImageStatic)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 
TEST_F(OatDumpTest,TestNoDumpVmap)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 }
TEST_F(OatDumpTest,TestNoDumpVmapStatic)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 
TEST_F(OatDumpTest,TestNoDisassemble)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 }
TEST_F(OatDumpTest,TestNoDisassembleStatic)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 
TEST_F(OatDumpTest,TestListClasses)267 TEST_F(OatDumpTest, TestListClasses) {
268   std::string error_msg;
269   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
270 }
TEST_F(OatDumpTest,TestListClassesStatic)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 
TEST_F(OatDumpTest,TestListMethods)277 TEST_F(OatDumpTest, TestListMethods) {
278   std::string error_msg;
279   ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
280 }
TEST_F(OatDumpTest,TestListMethodsStatic)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 
TEST_F(OatDumpTest,TestSymbolize)287 TEST_F(OatDumpTest, TestSymbolize) {
288   std::string error_msg;
289   ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
290 }
TEST_F(OatDumpTest,TestSymbolizeStatic)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