1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker #ifndef ART_OATDUMP_OATDUMP_TEST_H_ 18*795d594fSAndroid Build Coastguard Worker #define ART_OATDUMP_OATDUMP_TEST_H_ 19*795d594fSAndroid Build Coastguard Worker 20*795d594fSAndroid Build Coastguard Worker #include <sys/types.h> 21*795d594fSAndroid Build Coastguard Worker #include <unistd.h> 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Worker #include <memory> 24*795d594fSAndroid Build Coastguard Worker #include <sstream> 25*795d594fSAndroid Build Coastguard Worker #include <string> 26*795d594fSAndroid Build Coastguard Worker #include <type_traits> 27*795d594fSAndroid Build Coastguard Worker #include <vector> 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h" 30*795d594fSAndroid Build Coastguard Worker #include "base/common_art_test.h" 31*795d594fSAndroid Build Coastguard Worker #include "base/file_utils.h" 32*795d594fSAndroid Build Coastguard Worker #include "base/os.h" 33*795d594fSAndroid Build Coastguard Worker #include "common_runtime_test.h" 34*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h" 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Worker namespace art { 37*795d594fSAndroid Build Coastguard Worker 38*795d594fSAndroid Build Coastguard Worker // Linking flavor. 39*795d594fSAndroid Build Coastguard Worker enum class Flavor { 40*795d594fSAndroid Build Coastguard Worker kDynamic, // oatdump(d), dex2oat(d) 41*795d594fSAndroid Build Coastguard Worker kStatic, // oatdump(d)s, dex2oat(d)s 42*795d594fSAndroid Build Coastguard Worker }; 43*795d594fSAndroid Build Coastguard Worker 44*795d594fSAndroid Build Coastguard Worker class OatDumpTest : public CommonRuntimeTest, public testing::WithParamInterface<Flavor> { 45*795d594fSAndroid Build Coastguard Worker protected: SetUp()46*795d594fSAndroid Build Coastguard Worker virtual void SetUp() { 47*795d594fSAndroid Build Coastguard Worker CommonRuntimeTest::SetUp(); 48*795d594fSAndroid Build Coastguard Worker core_art_location_ = GetCoreArtLocation(); 49*795d594fSAndroid Build Coastguard Worker core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA); 50*795d594fSAndroid Build Coastguard Worker tmp_dir_ = GetScratchDir(); 51*795d594fSAndroid Build Coastguard Worker if (GetParam() == Flavor::kStatic) { 52*795d594fSAndroid Build Coastguard Worker TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS(); 53*795d594fSAndroid Build Coastguard Worker } 54*795d594fSAndroid Build Coastguard Worker 55*795d594fSAndroid Build Coastguard Worker // Prevent boot image inference to ensure consistent test behavior. 56*795d594fSAndroid Build Coastguard Worker unset_bootclasspath_ = std::make_unique<ScopedUnsetEnvironmentVariable>("BOOTCLASSPATH"); 57*795d594fSAndroid Build Coastguard Worker } 58*795d594fSAndroid Build Coastguard Worker TearDown()59*795d594fSAndroid Build Coastguard Worker virtual void TearDown() { 60*795d594fSAndroid Build Coastguard Worker unset_bootclasspath_.reset(); 61*795d594fSAndroid Build Coastguard Worker ClearDirectory(tmp_dir_.c_str(), /*recursive*/ false); 62*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(rmdir(tmp_dir_.c_str()), 0); 63*795d594fSAndroid Build Coastguard Worker CommonRuntimeTest::TearDown(); 64*795d594fSAndroid Build Coastguard Worker } 65*795d594fSAndroid Build Coastguard Worker GetScratchDir()66*795d594fSAndroid Build Coastguard Worker std::string GetScratchDir() const { 67*795d594fSAndroid Build Coastguard Worker // ANDROID_DATA needs to be set 68*795d594fSAndroid Build Coastguard Worker CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")); 69*795d594fSAndroid Build Coastguard Worker std::string dir = getenv("ANDROID_DATA"); 70*795d594fSAndroid Build Coastguard Worker dir += "/oatdump-tmp-dir-XXXXXX"; 71*795d594fSAndroid Build Coastguard Worker if (mkdtemp(&dir[0]) == nullptr) { 72*795d594fSAndroid Build Coastguard Worker PLOG(FATAL) << "mkdtemp(\"" << &dir[0] << "\") failed"; 73*795d594fSAndroid Build Coastguard Worker } 74*795d594fSAndroid Build Coastguard Worker return dir; 75*795d594fSAndroid Build Coastguard Worker } 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker // Returns path to the oatdump/dex2oat/dexdump binary. GetExecutableFilePath(const char * name,bool is_debug,bool is_static,bool bitness)78*795d594fSAndroid Build Coastguard Worker static std::string GetExecutableFilePath(const char* name, 79*795d594fSAndroid Build Coastguard Worker bool is_debug, 80*795d594fSAndroid Build Coastguard Worker bool is_static, 81*795d594fSAndroid Build Coastguard Worker bool bitness) { 82*795d594fSAndroid Build Coastguard Worker std::string path = GetArtBinDir() + '/' + name; 83*795d594fSAndroid Build Coastguard Worker if (is_debug) { 84*795d594fSAndroid Build Coastguard Worker path += 'd'; 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker if (is_static) { 87*795d594fSAndroid Build Coastguard Worker path += 's'; 88*795d594fSAndroid Build Coastguard Worker } 89*795d594fSAndroid Build Coastguard Worker if (bitness) { 90*795d594fSAndroid Build Coastguard Worker path += Is64BitInstructionSet(kRuntimeISA) ? "64" : "32"; 91*795d594fSAndroid Build Coastguard Worker } 92*795d594fSAndroid Build Coastguard Worker return path; 93*795d594fSAndroid Build Coastguard Worker } 94*795d594fSAndroid Build Coastguard Worker GetExecutableFilePath(Flavor flavor,const char * name,bool bitness)95*795d594fSAndroid Build Coastguard Worker static std::string GetExecutableFilePath(Flavor flavor, const char* name, bool bitness) { 96*795d594fSAndroid Build Coastguard Worker return GetExecutableFilePath(name, kIsDebugBuild, flavor == Flavor::kStatic, bitness); 97*795d594fSAndroid Build Coastguard Worker } 98*795d594fSAndroid Build Coastguard Worker 99*795d594fSAndroid Build Coastguard Worker enum Args { 100*795d594fSAndroid Build Coastguard Worker kArgImage = 1 << 0, // --image=<boot-image> 101*795d594fSAndroid Build Coastguard Worker kArgAppImage = 1 << 1, // --app-image=<app-image> 102*795d594fSAndroid Build Coastguard Worker kArgOatBcp = 1 << 2, // --oat-file=<bcp-oat-file> 103*795d594fSAndroid Build Coastguard Worker kArgDexBcp = 1 << 3, // --dex-file=<bcp-dex-file> 104*795d594fSAndroid Build Coastguard Worker kArgOatApp = 1 << 4, // --oat-file=<app-oat-file> 105*795d594fSAndroid Build Coastguard Worker kArgSymbolize = 1 << 5, // --symbolize=<bcp-oat-file> 106*795d594fSAndroid Build Coastguard Worker kArgDexApp = 1 << 6, // --dex-file=<app-dex-file> 107*795d594fSAndroid Build Coastguard Worker kArgMethodAndOffsetAsJson = 1 << 7, // --dump-method-and-offset-only 108*795d594fSAndroid Build Coastguard Worker 109*795d594fSAndroid Build Coastguard Worker // Runtime args. 110*795d594fSAndroid Build Coastguard Worker kArgBcp = 1 << 16, // --runtime-arg -Xbootclasspath:<bcp> 111*795d594fSAndroid Build Coastguard Worker kArgBootImage = 1 << 17, // --boot-image=<boot-image> 112*795d594fSAndroid Build Coastguard Worker kArgIsa = 1 << 18, // --instruction-set=<isa> 113*795d594fSAndroid Build Coastguard Worker }; 114*795d594fSAndroid Build Coastguard Worker 115*795d594fSAndroid Build Coastguard Worker enum Expects { 116*795d594fSAndroid Build Coastguard Worker kExpectImage = 1 << 0, 117*795d594fSAndroid Build Coastguard Worker kExpectOat = 1 << 1, 118*795d594fSAndroid Build Coastguard Worker kExpectCode = 1 << 2, 119*795d594fSAndroid Build Coastguard Worker kExpectBssMappingsForBcp = 1 << 3, 120*795d594fSAndroid Build Coastguard Worker kExpectBssOffsetsForBcp = 1 << 4, 121*795d594fSAndroid Build Coastguard Worker kExpectMethodAndOffsetAsJson = 1 << 5, 122*795d594fSAndroid Build Coastguard Worker }; 123*795d594fSAndroid Build Coastguard Worker GetAppBaseName()124*795d594fSAndroid Build Coastguard Worker static std::string GetAppBaseName() { 125*795d594fSAndroid Build Coastguard Worker // Use ProfileTestMultiDex as it contains references to boot image strings 126*795d594fSAndroid Build Coastguard Worker // that shall use different code for PIC and non-PIC. 127*795d594fSAndroid Build Coastguard Worker return "ProfileTestMultiDex"; 128*795d594fSAndroid Build Coastguard Worker } 129*795d594fSAndroid Build Coastguard Worker GetAppImageName()130*795d594fSAndroid Build Coastguard Worker std::string GetAppImageName() const { return tmp_dir_ + "/" + GetAppBaseName() + ".art"; } 131*795d594fSAndroid Build Coastguard Worker GetAppOdexName()132*795d594fSAndroid Build Coastguard Worker std::string GetAppOdexName() const { return tmp_dir_ + "/" + GetAppBaseName() + ".odex"; } 133*795d594fSAndroid Build Coastguard Worker 134*795d594fSAndroid Build Coastguard Worker ::testing::AssertionResult GenerateAppOdexFile(Flavor flavor, 135*795d594fSAndroid Build Coastguard Worker const std::vector<std::string>& args = {}) const { 136*795d594fSAndroid Build Coastguard Worker std::string dex2oat_path = 137*795d594fSAndroid Build Coastguard Worker GetExecutableFilePath(flavor, "dex2oat", /* bitness= */ kIsTargetBuild); 138*795d594fSAndroid Build Coastguard Worker std::vector<std::string> exec_argv = { 139*795d594fSAndroid Build Coastguard Worker dex2oat_path, 140*795d594fSAndroid Build Coastguard Worker "--runtime-arg", 141*795d594fSAndroid Build Coastguard Worker "-Xms64m", 142*795d594fSAndroid Build Coastguard Worker "--runtime-arg", 143*795d594fSAndroid Build Coastguard Worker "-Xmx64m", 144*795d594fSAndroid Build Coastguard Worker "--runtime-arg", 145*795d594fSAndroid Build Coastguard Worker "-Xnorelocate", 146*795d594fSAndroid Build Coastguard Worker "--runtime-arg", 147*795d594fSAndroid Build Coastguard Worker GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()), 148*795d594fSAndroid Build Coastguard Worker "--runtime-arg", 149*795d594fSAndroid Build Coastguard Worker GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()), 150*795d594fSAndroid Build Coastguard Worker "--boot-image=" + GetCoreArtLocation(), 151*795d594fSAndroid Build Coastguard Worker "--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)), 152*795d594fSAndroid Build Coastguard Worker "--dex-file=" + GetTestDexFileName(GetAppBaseName().c_str()), 153*795d594fSAndroid Build Coastguard Worker "--oat-file=" + GetAppOdexName(), 154*795d594fSAndroid Build Coastguard Worker "--compiler-filter=speed", 155*795d594fSAndroid Build Coastguard Worker }; 156*795d594fSAndroid Build Coastguard Worker exec_argv.insert(exec_argv.end(), args.begin(), args.end()); 157*795d594fSAndroid Build Coastguard Worker 158*795d594fSAndroid Build Coastguard Worker auto post_fork_fn = []() { 159*795d594fSAndroid Build Coastguard Worker setpgid(0, 0); // Change process groups, so we don't get reaped by ProcessManager. 160*795d594fSAndroid Build Coastguard Worker // Ignore setpgid errors. 161*795d594fSAndroid Build Coastguard Worker return setenv("ANDROID_LOG_TAGS", "*:e", 1) == 0; // We're only interested in errors and 162*795d594fSAndroid Build Coastguard Worker // fatal logs. 163*795d594fSAndroid Build Coastguard Worker }; 164*795d594fSAndroid Build Coastguard Worker 165*795d594fSAndroid Build Coastguard Worker std::string error_msg; 166*795d594fSAndroid Build Coastguard Worker ForkAndExecResult res = ForkAndExec(exec_argv, post_fork_fn, &error_msg); 167*795d594fSAndroid Build Coastguard Worker if (res.stage != ForkAndExecResult::kFinished) { 168*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionFailure() << strerror(errno); 169*795d594fSAndroid Build Coastguard Worker } 170*795d594fSAndroid Build Coastguard Worker return res.StandardSuccess() ? ::testing::AssertionSuccess() 171*795d594fSAndroid Build Coastguard Worker : (::testing::AssertionFailure() << error_msg); 172*795d594fSAndroid Build Coastguard Worker } 173*795d594fSAndroid Build Coastguard Worker 174*795d594fSAndroid Build Coastguard Worker // Run the test with custom arguments. 175*795d594fSAndroid Build Coastguard Worker ::testing::AssertionResult Exec(Flavor flavor, 176*795d594fSAndroid Build Coastguard Worker std::underlying_type_t<Args> args, 177*795d594fSAndroid Build Coastguard Worker const std::vector<std::string>& extra_args, 178*795d594fSAndroid Build Coastguard Worker std::underlying_type_t<Expects> expects, 179*795d594fSAndroid Build Coastguard Worker bool expect_failure = false) const { 180*795d594fSAndroid Build Coastguard Worker std::string file_path = GetExecutableFilePath(flavor, "oatdump", /* bitness= */ false); 181*795d594fSAndroid Build Coastguard Worker 182*795d594fSAndroid Build Coastguard Worker if (!OS::FileExists(file_path.c_str())) { 183*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionFailure() << file_path << " should be a valid file path"; 184*795d594fSAndroid Build Coastguard Worker } 185*795d594fSAndroid Build Coastguard Worker 186*795d594fSAndroid Build Coastguard Worker std::vector<std::string> expected_prefixes; 187*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectImage) != 0) { 188*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("IMAGE LOCATION:"); 189*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("IMAGE BEGIN:"); 190*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("kDexCaches:"); 191*795d594fSAndroid Build Coastguard Worker } 192*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectOat) != 0) { 193*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("LOCATION:"); 194*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("MAGIC:"); 195*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("DEX FILE COUNT:"); 196*795d594fSAndroid Build Coastguard Worker } 197*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectCode) != 0) { 198*795d594fSAndroid Build Coastguard Worker // Code and dex code do not show up if list only. 199*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("DEX CODE:"); 200*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("CODE:"); 201*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("StackMap"); 202*795d594fSAndroid Build Coastguard Worker } 203*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectBssMappingsForBcp) != 0) { 204*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("Entries for BCP DexFile"); 205*795d594fSAndroid Build Coastguard Worker } 206*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectBssOffsetsForBcp) != 0) { 207*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back("Offsets for BCP DexFile"); 208*795d594fSAndroid Build Coastguard Worker } 209*795d594fSAndroid Build Coastguard Worker if ((expects & kExpectMethodAndOffsetAsJson) != 0) { 210*795d594fSAndroid Build Coastguard Worker expected_prefixes.push_back( 211*795d594fSAndroid Build Coastguard Worker "{\"method\":\"void java.lang.Object.<init>()\",\"offset\":\"0x"); // actual offset may 212*795d594fSAndroid Build Coastguard Worker // differ between dex 213*795d594fSAndroid Build Coastguard Worker // files 214*795d594fSAndroid Build Coastguard Worker } 215*795d594fSAndroid Build Coastguard Worker 216*795d594fSAndroid Build Coastguard Worker std::vector<std::string> exec_argv = {file_path}; 217*795d594fSAndroid Build Coastguard Worker if ((args & kArgSymbolize) != 0) { 218*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--symbolize=" + core_oat_location_); 219*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--output=" + core_oat_location_ + ".symbolize"); 220*795d594fSAndroid Build Coastguard Worker } 221*795d594fSAndroid Build Coastguard Worker if ((args & kArgBcp) != 0) { 222*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--runtime-arg"); 223*795d594fSAndroid Build Coastguard Worker exec_argv.push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames())); 224*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--runtime-arg"); 225*795d594fSAndroid Build Coastguard Worker exec_argv.push_back( 226*795d594fSAndroid Build Coastguard Worker GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations())); 227*795d594fSAndroid Build Coastguard Worker } 228*795d594fSAndroid Build Coastguard Worker if ((args & kArgIsa) != 0) { 229*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA))); 230*795d594fSAndroid Build Coastguard Worker } 231*795d594fSAndroid Build Coastguard Worker if ((args & kArgBootImage) != 0) { 232*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--boot-image=" + GetCoreArtLocation()); 233*795d594fSAndroid Build Coastguard Worker } 234*795d594fSAndroid Build Coastguard Worker if ((args & kArgImage) != 0) { 235*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--image=" + GetCoreArtLocation()); 236*795d594fSAndroid Build Coastguard Worker } 237*795d594fSAndroid Build Coastguard Worker if ((args & kArgAppImage) != 0) { 238*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--app-image=" + GetAppImageName()); 239*795d594fSAndroid Build Coastguard Worker } 240*795d594fSAndroid Build Coastguard Worker if ((args & kArgOatBcp) != 0) { 241*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--oat-file=" + core_oat_location_); 242*795d594fSAndroid Build Coastguard Worker } 243*795d594fSAndroid Build Coastguard Worker if ((args & kArgDexBcp) != 0) { 244*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--dex-file=" + GetLibCoreDexFileNames()[0]); 245*795d594fSAndroid Build Coastguard Worker } 246*795d594fSAndroid Build Coastguard Worker if ((args & kArgOatApp) != 0) { 247*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--oat-file=" + GetAppOdexName()); 248*795d594fSAndroid Build Coastguard Worker } 249*795d594fSAndroid Build Coastguard Worker if ((args & kArgDexApp) != 0) { 250*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--dex-file=" + GetTestDexFileName(GetAppBaseName().c_str())); 251*795d594fSAndroid Build Coastguard Worker } 252*795d594fSAndroid Build Coastguard Worker if ((args & kArgMethodAndOffsetAsJson) != 0) { 253*795d594fSAndroid Build Coastguard Worker exec_argv.push_back("--dump-method-and-offset-as-json"); 254*795d594fSAndroid Build Coastguard Worker } 255*795d594fSAndroid Build Coastguard Worker exec_argv.insert(exec_argv.end(), extra_args.begin(), extra_args.end()); 256*795d594fSAndroid Build Coastguard Worker 257*795d594fSAndroid Build Coastguard Worker std::vector<bool> found(expected_prefixes.size(), false); 258*795d594fSAndroid Build Coastguard Worker auto line_handle_fn = [&found, &expected_prefixes](const char* line, size_t line_len) { 259*795d594fSAndroid Build Coastguard Worker if (line_len == 0) { 260*795d594fSAndroid Build Coastguard Worker return; 261*795d594fSAndroid Build Coastguard Worker } 262*795d594fSAndroid Build Coastguard Worker // Check contents. 263*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < expected_prefixes.size(); ++i) { 264*795d594fSAndroid Build Coastguard Worker const std::string& expected = expected_prefixes[i]; 265*795d594fSAndroid Build Coastguard Worker if (!found[i] && 266*795d594fSAndroid Build Coastguard Worker line_len >= expected.length() && 267*795d594fSAndroid Build Coastguard Worker memcmp(line, expected.c_str(), expected.length()) == 0) { 268*795d594fSAndroid Build Coastguard Worker found[i] = true; 269*795d594fSAndroid Build Coastguard Worker } 270*795d594fSAndroid Build Coastguard Worker } 271*795d594fSAndroid Build Coastguard Worker }; 272*795d594fSAndroid Build Coastguard Worker 273*795d594fSAndroid Build Coastguard Worker static constexpr size_t kLineMax = 256; 274*795d594fSAndroid Build Coastguard Worker char line[kLineMax] = {}; 275*795d594fSAndroid Build Coastguard Worker size_t line_len = 0; 276*795d594fSAndroid Build Coastguard Worker size_t total = 0; 277*795d594fSAndroid Build Coastguard Worker bool ignore_next_line = false; 278*795d594fSAndroid Build Coastguard Worker std::vector<char> error_buf; // Buffer for debug output on error. Limited to 1M. 279*795d594fSAndroid Build Coastguard Worker auto line_buf_fn = [&](char* buf, size_t len) { 280*795d594fSAndroid Build Coastguard Worker total += len; 281*795d594fSAndroid Build Coastguard Worker 282*795d594fSAndroid Build Coastguard Worker if (len == 0 && line_len > 0 && !ignore_next_line) { 283*795d594fSAndroid Build Coastguard Worker // Everything done, handle leftovers. 284*795d594fSAndroid Build Coastguard Worker line_handle_fn(line, line_len); 285*795d594fSAndroid Build Coastguard Worker } 286*795d594fSAndroid Build Coastguard Worker 287*795d594fSAndroid Build Coastguard Worker if (len > 0) { 288*795d594fSAndroid Build Coastguard Worker size_t pos = error_buf.size(); 289*795d594fSAndroid Build Coastguard Worker if (pos < MB) { 290*795d594fSAndroid Build Coastguard Worker error_buf.insert(error_buf.end(), buf, buf + len); 291*795d594fSAndroid Build Coastguard Worker } 292*795d594fSAndroid Build Coastguard Worker } 293*795d594fSAndroid Build Coastguard Worker 294*795d594fSAndroid Build Coastguard Worker while (len > 0) { 295*795d594fSAndroid Build Coastguard Worker // Copy buf into the free tail of the line buffer, and move input buffer along. 296*795d594fSAndroid Build Coastguard Worker size_t copy = std::min(kLineMax - line_len, len); 297*795d594fSAndroid Build Coastguard Worker memcpy(&line[line_len], buf, copy); 298*795d594fSAndroid Build Coastguard Worker buf += copy; 299*795d594fSAndroid Build Coastguard Worker len -= copy; 300*795d594fSAndroid Build Coastguard Worker 301*795d594fSAndroid Build Coastguard Worker // Skip spaces up to len, return count of removed spaces. Declare a lambda for reuse. 302*795d594fSAndroid Build Coastguard Worker auto trim_space = [&line](size_t len) { 303*795d594fSAndroid Build Coastguard Worker size_t spaces = 0; 304*795d594fSAndroid Build Coastguard Worker for (; spaces < len && isspace(line[spaces]); ++spaces) {} 305*795d594fSAndroid Build Coastguard Worker if (spaces > 0) { 306*795d594fSAndroid Build Coastguard Worker memmove(&line[0], &line[spaces], len - spaces); 307*795d594fSAndroid Build Coastguard Worker } 308*795d594fSAndroid Build Coastguard Worker return spaces; 309*795d594fSAndroid Build Coastguard Worker }; 310*795d594fSAndroid Build Coastguard Worker // There can only be spaces if we freshly started a line. 311*795d594fSAndroid Build Coastguard Worker if (line_len == 0) { 312*795d594fSAndroid Build Coastguard Worker copy -= trim_space(copy); 313*795d594fSAndroid Build Coastguard Worker } 314*795d594fSAndroid Build Coastguard Worker 315*795d594fSAndroid Build Coastguard Worker // Scan for newline characters. 316*795d594fSAndroid Build Coastguard Worker size_t index = line_len; 317*795d594fSAndroid Build Coastguard Worker line_len += copy; 318*795d594fSAndroid Build Coastguard Worker while (index < line_len) { 319*795d594fSAndroid Build Coastguard Worker if (line[index] == '\n') { 320*795d594fSAndroid Build Coastguard Worker // Handle line. 321*795d594fSAndroid Build Coastguard Worker if (!ignore_next_line) { 322*795d594fSAndroid Build Coastguard Worker line_handle_fn(line, index); 323*795d594fSAndroid Build Coastguard Worker } 324*795d594fSAndroid Build Coastguard Worker // Move the rest to the front, but trim leading spaces. 325*795d594fSAndroid Build Coastguard Worker line_len -= index + 1; 326*795d594fSAndroid Build Coastguard Worker memmove(&line[0], &line[index + 1], line_len); 327*795d594fSAndroid Build Coastguard Worker line_len -= trim_space(line_len); 328*795d594fSAndroid Build Coastguard Worker index = 0; 329*795d594fSAndroid Build Coastguard Worker ignore_next_line = false; 330*795d594fSAndroid Build Coastguard Worker } else { 331*795d594fSAndroid Build Coastguard Worker index++; 332*795d594fSAndroid Build Coastguard Worker } 333*795d594fSAndroid Build Coastguard Worker } 334*795d594fSAndroid Build Coastguard Worker 335*795d594fSAndroid Build Coastguard Worker // Handle a full line without newline characters. Ignore the "next" line, as it is the 336*795d594fSAndroid Build Coastguard Worker // tail end of this. 337*795d594fSAndroid Build Coastguard Worker if (line_len == kLineMax) { 338*795d594fSAndroid Build Coastguard Worker if (!ignore_next_line) { 339*795d594fSAndroid Build Coastguard Worker line_handle_fn(line, kLineMax); 340*795d594fSAndroid Build Coastguard Worker } 341*795d594fSAndroid Build Coastguard Worker line_len = 0; 342*795d594fSAndroid Build Coastguard Worker ignore_next_line = true; 343*795d594fSAndroid Build Coastguard Worker } 344*795d594fSAndroid Build Coastguard Worker } 345*795d594fSAndroid Build Coastguard Worker }; 346*795d594fSAndroid Build Coastguard Worker 347*795d594fSAndroid Build Coastguard Worker auto post_fork_fn = []() { 348*795d594fSAndroid Build Coastguard Worker setpgid(0, 0); // Change process groups, so we don't get reaped by ProcessManager. 349*795d594fSAndroid Build Coastguard Worker // Ignore setpgid failures. 350*795d594fSAndroid Build Coastguard Worker return setenv("ANDROID_LOG_TAGS", "*:e", 1) == 0; // We're only interested in errors and 351*795d594fSAndroid Build Coastguard Worker // fatal logs. 352*795d594fSAndroid Build Coastguard Worker }; 353*795d594fSAndroid Build Coastguard Worker 354*795d594fSAndroid Build Coastguard Worker ForkAndExecResult res = ForkAndExec(exec_argv, post_fork_fn, line_buf_fn); 355*795d594fSAndroid Build Coastguard Worker if (res.stage != ForkAndExecResult::kFinished) { 356*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionFailure() << strerror(errno); 357*795d594fSAndroid Build Coastguard Worker } 358*795d594fSAndroid Build Coastguard Worker error_buf.push_back(0); // Make data a C string. 359*795d594fSAndroid Build Coastguard Worker 360*795d594fSAndroid Build Coastguard Worker if (!res.StandardSuccess()) { 361*795d594fSAndroid Build Coastguard Worker if (expect_failure && WIFEXITED(res.status_code)) { 362*795d594fSAndroid Build Coastguard Worker // Avoid crash as valid exit. 363*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionSuccess(); 364*795d594fSAndroid Build Coastguard Worker } 365*795d594fSAndroid Build Coastguard Worker std::ostringstream cmd; 366*795d594fSAndroid Build Coastguard Worker std::copy(exec_argv.begin(), exec_argv.end(), std::ostream_iterator<std::string>(cmd, " ")); 367*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Output: " << error_buf.data(); // Output first as it might be extremely long. 368*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << "Failed command: " << cmd.str(); // Useful to reproduce the failure separately. 369*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionFailure() << "Did not terminate successfully: " << res.status_code; 370*795d594fSAndroid Build Coastguard Worker } else if (expect_failure) { 371*795d594fSAndroid Build Coastguard Worker return ::testing::AssertionFailure() << "Expected failure"; 372*795d594fSAndroid Build Coastguard Worker } 373*795d594fSAndroid Build Coastguard Worker 374*795d594fSAndroid Build Coastguard Worker if ((args & kArgSymbolize) != 0) { 375*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(total, 0u); 376*795d594fSAndroid Build Coastguard Worker } else { 377*795d594fSAndroid Build Coastguard Worker EXPECT_GT(total, 0u); 378*795d594fSAndroid Build Coastguard Worker } 379*795d594fSAndroid Build Coastguard Worker 380*795d594fSAndroid Build Coastguard Worker bool result = true; 381*795d594fSAndroid Build Coastguard Worker std::ostringstream oss; 382*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < expected_prefixes.size(); ++i) { 383*795d594fSAndroid Build Coastguard Worker if (!found[i]) { 384*795d594fSAndroid Build Coastguard Worker oss << "Did not find prefix " << expected_prefixes[i] << std::endl; 385*795d594fSAndroid Build Coastguard Worker result = false; 386*795d594fSAndroid Build Coastguard Worker } 387*795d594fSAndroid Build Coastguard Worker } 388*795d594fSAndroid Build Coastguard Worker if (!result) { 389*795d594fSAndroid Build Coastguard Worker oss << "Processed bytes " << total << ":" << std::endl; 390*795d594fSAndroid Build Coastguard Worker } 391*795d594fSAndroid Build Coastguard Worker 392*795d594fSAndroid Build Coastguard Worker return result ? ::testing::AssertionSuccess() 393*795d594fSAndroid Build Coastguard Worker : (::testing::AssertionFailure() << oss.str() << error_buf.data()); 394*795d594fSAndroid Build Coastguard Worker } 395*795d594fSAndroid Build Coastguard Worker 396*795d594fSAndroid Build Coastguard Worker std::string tmp_dir_; 397*795d594fSAndroid Build Coastguard Worker 398*795d594fSAndroid Build Coastguard Worker private: 399*795d594fSAndroid Build Coastguard Worker std::string core_art_location_; 400*795d594fSAndroid Build Coastguard Worker std::string core_oat_location_; 401*795d594fSAndroid Build Coastguard Worker std::unique_ptr<ScopedUnsetEnvironmentVariable> unset_bootclasspath_; 402*795d594fSAndroid Build Coastguard Worker }; 403*795d594fSAndroid Build Coastguard Worker 404*795d594fSAndroid Build Coastguard Worker } // namespace art 405*795d594fSAndroid Build Coastguard Worker 406*795d594fSAndroid Build Coastguard Worker #endif // ART_OATDUMP_OATDUMP_TEST_H_ 407