103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe/*
203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * Copyright (C) 2014 The Android Open Source Project
303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe *
403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * you may not use this file except in compliance with the License.
603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * You may obtain a copy of the License at
703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe *
803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe *
1003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * Unless required by applicable law or agreed to in writing, software
1103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
1203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * See the License for the specific language governing permissions and
1403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe * limitations under the License.
1503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe */
1603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
1703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_BASE_H_
1803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#define ART_COMPILER_UTILS_ASSEMBLER_TEST_BASE_H_
1903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
2003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#include <cstdio>
2103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#include <cstdlib>
2203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#include <fstream>
2303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#include <iterator>
2403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#include <sys/stat.h>
2503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
2680afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "common_runtime_test.h"  // For ScratchFile
2780afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "utils.h"
2880afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko
2903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampenamespace art {
3003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
3103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe// If you want to take a look at the differences between the ART assembler and GCC, set this flag
3203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe// to true. The disassembled files will then remain in the tmp directory.
3303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampestatic constexpr bool kKeepDisassembledFiles = false;
3403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
3503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe// Use a glocal static variable to keep the same name for all test data. Else we'll just spam the
3603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe// temp directory.
3703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampestatic std::string tmpnam_;
3803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
3903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe// We put this into a class as gtests are self-contained, so this helper needs to be in an h-file.
4003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampeclass AssemblerTestInfrastructure {
4103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe public:
4203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  AssemblerTestInfrastructure(std::string architecture,
4303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string as,
4403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string as_params,
4503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string objdump,
4603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string objdump_params,
4703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string disasm,
4803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              std::string disasm_params,
4903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                              const char* asm_header) :
5003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      architecture_string_(architecture),
5103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      asm_header_(asm_header),
5203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      assembler_cmd_name_(as),
5303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      assembler_parameters_(as_params),
5403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      objdump_cmd_name_(objdump),
5503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      objdump_parameters_(objdump_params),
5603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      disassembler_cmd_name_(disasm),
5703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      disassembler_parameters_(disasm_params) {
5803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Fake a runtime test for ScratchFile
5903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    CommonRuntimeTest::SetUpAndroidData(android_data_);
6003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
6103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
6203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  virtual ~AssemblerTestInfrastructure() {
6303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // We leave temporaries in case this failed so we can debug issues.
6403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    CommonRuntimeTest::TearDownAndroidData(android_data_, false);
6503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    tmpnam_ = "";
6603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
6703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
6803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // This is intended to be run as a test.
6903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool CheckTools() {
70f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::string asm_tool = FindTool(assembler_cmd_name_);
71f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    if (!FileExists(asm_tool)) {
72f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      LOG(ERROR) << "Could not find assembler from " << assembler_cmd_name_;
73f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      LOG(ERROR) << "FindTool returned " << asm_tool;
74f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      FindToolDump(assembler_cmd_name_);
7503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
7603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
7703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    LOG(INFO) << "Chosen assembler command: " << GetAssemblerCommand();
7803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
79f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::string objdump_tool = FindTool(objdump_cmd_name_);
80f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    if (!FileExists(objdump_tool)) {
81f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      LOG(ERROR) << "Could not find objdump from " << objdump_cmd_name_;
82f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      LOG(ERROR) << "FindTool returned " << objdump_tool;
83f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      FindToolDump(objdump_cmd_name_);
8403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
8503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
8603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    LOG(INFO) << "Chosen objdump command: " << GetObjdumpCommand();
8703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
8803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Disassembly is optional.
8903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string disassembler = GetDisassembleCommand();
9003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (disassembler.length() != 0) {
91f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      std::string disassembler_tool = FindTool(disassembler_cmd_name_);
92f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      if (!FileExists(disassembler_tool)) {
93f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe        LOG(ERROR) << "Could not find disassembler from " << disassembler_cmd_name_;
94f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe        LOG(ERROR) << "FindTool returned " << disassembler_tool;
95f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe        FindToolDump(disassembler_cmd_name_);
9603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        return false;
9703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      }
9803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      LOG(INFO) << "Chosen disassemble command: " << GetDisassembleCommand();
9903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    } else {
10003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      LOG(INFO) << "No disassembler given.";
10103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
10203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
10303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return true;
10403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
10503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
10603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Driver() assembles and compares the results. If the results are not equal and we have a
10703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // disassembler, disassemble both and check whether they have the same mnemonics (in which case
10803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // we just warn).
10903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  void Driver(const std::vector<uint8_t>& data, std::string assembly_text, std::string test_name) {
11003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    EXPECT_NE(assembly_text.length(), 0U) << "Empty assembly";
11103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
11203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    NativeAssemblerResult res;
11303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    Compile(assembly_text, &res, test_name);
11403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
11503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    EXPECT_TRUE(res.ok) << res.error_msg;
11603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!res.ok) {
11703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      // No way of continuing.
11803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return;
11903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
12003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
12103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (data == *res.code) {
12203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      Clean(&res);
12303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    } else {
12403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      if (DisassembleBinaries(data, *res.code, test_name)) {
12503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        if (data.size() > res.code->size()) {
12603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe          // Fail this test with a fancy colored warning being printed.
12703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe          EXPECT_TRUE(false) << "Assembly code is not identical, but disassembly of machine code "
12803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe              "is equal: this implies sub-optimal encoding! Our code size=" << data.size() <<
12903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe              ", gcc size=" << res.code->size();
13003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        } else {
13103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe          // Otherwise just print an info message and clean up.
13203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe          LOG(INFO) << "GCC chose a different encoding than ours, but the overall length is the "
13303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe              "same.";
13403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe          Clean(&res);
13503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        }
13603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      } else {
13703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        // This will output the assembly.
13803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        EXPECT_EQ(*res.code, data) << "Outputs (and disassembly) not identical.";
13903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      }
14003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
14103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
14203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
14303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe protected:
14403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Return the host assembler command for this test.
14503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  virtual std::string GetAssemblerCommand() {
14603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Already resolved it once?
14703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (resolved_assembler_cmd_.length() != 0) {
14803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return resolved_assembler_cmd_;
14903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
15003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
15103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string line = FindTool(assembler_cmd_name_);
15203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (line.length() == 0) {
15303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return line;
15403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
15503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
15603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    resolved_assembler_cmd_ = line + assembler_parameters_;
15703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
15803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return resolved_assembler_cmd_;
15903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
16003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
16103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Return the host objdump command for this test.
16203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  virtual std::string GetObjdumpCommand() {
16303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Already resolved it once?
16403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (resolved_objdump_cmd_.length() != 0) {
16503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return resolved_objdump_cmd_;
16603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
16703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
16803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string line = FindTool(objdump_cmd_name_);
16903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (line.length() == 0) {
17003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return line;
17103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
17203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
17303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    resolved_objdump_cmd_ = line + objdump_parameters_;
17403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
17503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return resolved_objdump_cmd_;
17603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
17703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
17803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Return the host disassembler command for this test.
17903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  virtual std::string GetDisassembleCommand() {
18003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Already resolved it once?
18103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (resolved_disassemble_cmd_.length() != 0) {
18203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return resolved_disassemble_cmd_;
18303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
18403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
18503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string line = FindTool(disassembler_cmd_name_);
18603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (line.length() == 0) {
18703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return line;
18803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
18903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
19003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    resolved_disassemble_cmd_ = line + disassembler_parameters_;
19103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
19203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return resolved_disassemble_cmd_;
19303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
19403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
19503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe private:
19603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Structure to store intermediates and results.
19703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  struct NativeAssemblerResult {
19803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool ok;
19903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string error_msg;
20003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string base_name;
20103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::unique_ptr<std::vector<uint8_t>> code;
20203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    uintptr_t length;
20303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  };
20403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
20503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Compile the assembly file from_file to a binary file to_file. Returns true on success.
20603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool Assemble(const char* from_file, const char* to_file, std::string* error_msg) {
20703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool have_assembler = FileExists(FindTool(assembler_cmd_name_));
20803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    EXPECT_TRUE(have_assembler) << "Cannot find assembler:" << GetAssemblerCommand();
20903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!have_assembler) {
21003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
21103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
21203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
21303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::vector<std::string> args;
21403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
21503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Encaspulate the whole command line in a single string passed to
21603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // the shell, so that GetAssemblerCommand() may contain arguments
21703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // in addition to the program name.
21803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(GetAssemblerCommand());
21903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-o");
22003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(to_file);
22103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(from_file);
22203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string cmd = Join(args, ' ');
22303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
22403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.clear();
22503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("/bin/sh");
22603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-c");
22703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(cmd);
22803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
22903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool success = Exec(args, error_msg);
23003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!success) {
231d56376cce54e7df976780ecbd03228f60d276433Nicolas Geoffray      LOG(ERROR) << "Assembler command line:";
23203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      for (std::string arg : args) {
233d56376cce54e7df976780ecbd03228f60d276433Nicolas Geoffray        LOG(ERROR) << arg;
23403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      }
23503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
23603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return success;
23703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
23803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
23903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Runs objdump -h on the binary file and extracts the first line with .text.
24003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Returns "" on failure.
24103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string Objdump(std::string file) {
24203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool have_objdump = FileExists(FindTool(objdump_cmd_name_));
24303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    EXPECT_TRUE(have_objdump) << "Cannot find objdump: " << GetObjdumpCommand();
24403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!have_objdump) {
24503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return "";
24603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
24703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
24803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string error_msg;
24903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::vector<std::string> args;
25003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
25103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Encaspulate the whole command line in a single string passed to
25203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // the shell, so that GetObjdumpCommand() may contain arguments
25303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // in addition to the program name.
25403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(GetObjdumpCommand());
25503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(file);
25603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(">");
25703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(file+".dump");
25803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string cmd = Join(args, ' ');
25903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
26003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.clear();
26103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("/bin/sh");
26203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-c");
26303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(cmd);
26403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
26503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!Exec(args, &error_msg)) {
26603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      EXPECT_TRUE(false) << error_msg;
26703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
26803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
26903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ifstream dump(file+".dump");
27003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
27103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string line;
27203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool found = false;
27303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    while (std::getline(dump, line)) {
27403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      if (line.find(".text") != line.npos) {
27503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        found = true;
27603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe        break;
27703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      }
27803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
27903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
28003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    dump.close();
28103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
28203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (found) {
28303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return line;
28403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    } else {
28503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return "";
28603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
28703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
28803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
28903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Disassemble both binaries and compare the text.
29003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool DisassembleBinaries(const std::vector<uint8_t>& data, const std::vector<uint8_t>& as,
29103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                           std::string test_name) {
29203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string disassembler = GetDisassembleCommand();
29303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (disassembler.length() == 0) {
29403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      LOG(WARNING) << "No dissassembler command.";
29503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
29603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
29703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
29803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string data_name = WriteToFile(data, test_name + ".ass");
29903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string error_msg;
30003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!DisassembleBinary(data_name, &error_msg)) {
30103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      LOG(INFO) << "Error disassembling: " << error_msg;
30203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(data_name.c_str());
30303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
30403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
30503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
30603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string as_name = WriteToFile(as, test_name + ".gcc");
30703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!DisassembleBinary(as_name, &error_msg)) {
30803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      LOG(INFO) << "Error disassembling: " << error_msg;
30903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(data_name.c_str());
31003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove((data_name + ".dis").c_str());
31103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(as_name.c_str());
31203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
31303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
31403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
31503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool result = CompareFiles(data_name + ".dis", as_name + ".dis");
31603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
31703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!kKeepDisassembledFiles) {
31803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(data_name.c_str());
31903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(as_name.c_str());
32003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove((data_name + ".dis").c_str());
32103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove((as_name + ".dis").c_str());
32203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
32303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
32403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return result;
32503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
32603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
32703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool DisassembleBinary(std::string file, std::string* error_msg) {
32803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::vector<std::string> args;
32903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
33003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Encaspulate the whole command line in a single string passed to
33103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // the shell, so that GetDisassembleCommand() may contain arguments
33203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // in addition to the program name.
33303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(GetDisassembleCommand());
33403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(file);
33503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("| sed -n \'/<.data>/,$p\' | sed -e \'s/.*://\'");
33603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(">");
33703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(file+".dis");
33803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string cmd = Join(args, ' ');
33903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
34003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.clear();
34103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("/bin/sh");
34203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-c");
34303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(cmd);
34403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
34503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return Exec(args, error_msg);
34603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
34703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
34803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string WriteToFile(const std::vector<uint8_t>& buffer, std::string test_name) {
34903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string file_name = GetTmpnam() + std::string("---") + test_name;
35003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    const char* data = reinterpret_cast<const char*>(buffer.data());
35103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ofstream s_out(file_name + ".o");
35203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    s_out.write(data, buffer.size());
35303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    s_out.close();
35403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return file_name + ".o";
35503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
35603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
35703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool CompareFiles(std::string f1, std::string f2) {
35803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ifstream f1_in(f1);
35903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ifstream f2_in(f2);
36003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
36103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    bool result = std::equal(std::istreambuf_iterator<char>(f1_in),
36203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                             std::istreambuf_iterator<char>(),
36303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                             std::istreambuf_iterator<char>(f2_in));
36403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
36503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    f1_in.close();
36603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    f2_in.close();
36703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
36803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return result;
36903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
37003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
37103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Compile the given assembly code and extract the binary, if possible. Put result into res.
37203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  bool Compile(std::string assembly_code, NativeAssemblerResult* res, std::string test_name) {
37303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    res->ok = false;
37403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    res->code.reset(nullptr);
37503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
37603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    res->base_name = GetTmpnam() + std::string("---") + test_name;
37703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
37803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // TODO: Lots of error checking.
37903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
38003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ofstream s_out(res->base_name + ".S");
38103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (asm_header_ != nullptr) {
38203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      s_out << asm_header_;
38303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
38403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    s_out << assembly_code;
38503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    s_out.close();
38603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
38703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!Assemble((res->base_name + ".S").c_str(), (res->base_name + ".o").c_str(),
38803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe                  &res->error_msg)) {
38903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      res->error_msg = "Could not compile.";
39003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
39103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
39203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
39303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string odump = Objdump(res->base_name + ".o");
39403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (odump.length() == 0) {
39503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      res->error_msg = "Objdump failed.";
39603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
39703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
39803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
39903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::istringstream iss(odump);
40003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::istream_iterator<std::string> start(iss);
40103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::istream_iterator<std::string> end;
40203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::vector<std::string> tokens(start, end);
40303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
40403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (tokens.size() < OBJDUMP_SECTION_LINE_MIN_TOKENS) {
40503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      res->error_msg = "Objdump output not recognized: too few tokens.";
40603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
40703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
40803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
40903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (tokens[1] != ".text") {
41003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      res->error_msg = "Objdump output not recognized: .text not second token.";
41103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
41203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
41303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
41403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string lengthToken = "0x" + tokens[2];
41503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::istringstream(lengthToken) >> std::hex >> res->length;
41603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
41703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string offsetToken = "0x" + tokens[5];
41803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    uintptr_t offset;
41903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::istringstream(offsetToken) >> std::hex >> offset;
42003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
42103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ifstream obj(res->base_name + ".o");
42203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    obj.seekg(offset);
42303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    res->code.reset(new std::vector<uint8_t>(res->length));
42403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    obj.read(reinterpret_cast<char*>(&(*res->code)[0]), res->length);
42503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    obj.close();
42603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
42703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    res->ok = true;
42803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return true;
42903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
43003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
43103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Remove temporary files.
43203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  void Clean(const NativeAssemblerResult* res) {
43303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::remove((res->base_name + ".S").c_str());
43403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::remove((res->base_name + ".o").c_str());
43503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::remove((res->base_name + ".o.dump").c_str());
43603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
43703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
43803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Check whether file exists. Is used for commands, so strips off any parameters: anything after
43903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // the first space. We skip to the last slash for this, so it should work with directories with
44003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // spaces.
44103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  static bool FileExists(std::string file) {
44203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (file.length() == 0) {
44303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return false;
44403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
44503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
44603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Need to strip any options.
44703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    size_t last_slash = file.find_last_of('/');
44803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (last_slash == std::string::npos) {
44903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      // No slash, start looking at the start.
45003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      last_slash = 0;
45103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
45203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    size_t space_index = file.find(' ', last_slash);
45303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
45403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (space_index == std::string::npos) {
45503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::ifstream infile(file.c_str());
45603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return infile.good();
45703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    } else {
45803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::string copy = file.substr(0, space_index - 1);
45903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
46003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      struct stat buf;
46103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return stat(copy.c_str(), &buf) == 0;
46203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
46303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
46403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
46503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  static std::string GetGCCRootPath() {
46603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return "prebuilts/gcc/linux-x86";
46703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
46803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
46903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  static std::string GetRootPath() {
47003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // 1) Check ANDROID_BUILD_TOP
47103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    char* build_top = getenv("ANDROID_BUILD_TOP");
47203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (build_top != nullptr) {
47303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return std::string(build_top) + "/";
47403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
47503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
47603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // 2) Do cwd
47703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    char temp[1024];
47803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return getcwd(temp, 1024) ? std::string(temp) + "/" : std::string("");
47903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
48003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
48103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string FindTool(std::string tool_name) {
48203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    // Find the current tool. Wild-card pattern is "arch-string*tool-name".
48303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string gcc_path = GetRootPath() + GetGCCRootPath();
48403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::vector<std::string> args;
48503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("find");
48603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(gcc_path);
48703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-name");
48803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(architecture_string_ + "*" + tool_name);
48903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("|");
49003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("sort");
49103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("|");
49203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("tail");
49303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-n");
49403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("1");
49503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string tmp_file = GetTmpnam();
49603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(">");
49703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(tmp_file);
49803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string sh_args = Join(args, ' ');
49903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
50003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.clear();
50103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("/bin/sh");
50203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back("-c");
50303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    args.push_back(sh_args);
50403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
50503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string error_msg;
50603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!Exec(args, &error_msg)) {
50703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      EXPECT_TRUE(false) << error_msg;
508f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      UNREACHABLE();
50903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
51003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
51103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::ifstream in(tmp_file.c_str());
51203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::string line;
51303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (!std::getline(in, line)) {
51403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      in.close();
51503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      std::remove(tmp_file.c_str());
51603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      return "";
51703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
51803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    in.close();
51903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    std::remove(tmp_file.c_str());
52003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return line;
52103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
52203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
5237532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  // Helper for below. If name_predicate is empty, search for all files, otherwise use it for the
5247532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  // "-name" option.
5257532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  static void FindToolDumpPrintout(std::string name_predicate, std::string tmp_file) {
526f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::string gcc_path = GetRootPath() + GetGCCRootPath();
527f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::vector<std::string> args;
528f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back("find");
529f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back(gcc_path);
5307532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    if (!name_predicate.empty()) {
5317532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe      args.push_back("-name");
5327532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe      args.push_back(name_predicate);
5337532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    }
534f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back("|");
535f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back("sort");
536f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back(">");
537f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back(tmp_file);
538f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::string sh_args = Join(args, ' ');
539f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe
540f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.clear();
541f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back("/bin/sh");
542f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back("-c");
543f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    args.push_back(sh_args);
544f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe
545f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::string error_msg;
546f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    if (!Exec(args, &error_msg)) {
547f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      EXPECT_TRUE(false) << error_msg;
548f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe      UNREACHABLE();
549f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    }
550f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe
5517532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    LOG(ERROR) << "FindToolDump: gcc_path=" << gcc_path
5527532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe               << " cmd=" << sh_args;
553f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    std::ifstream in(tmp_file.c_str());
554f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    if (in) {
5557532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe      std::string line;
5567532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe      while (std::getline(in, line)) {
5577532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe        LOG(ERROR) << line;
5587532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe      }
559f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe    }
5607532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    in.close();
5617532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    std::remove(tmp_file.c_str());
5627532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  }
5637532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe
5647532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  // For debug purposes.
5657532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe  void FindToolDump(std::string tool_name) {
5667532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    // Check with the tool name.
5677532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    FindToolDumpPrintout(architecture_string_ + "*" + tool_name, GetTmpnam());
5687532401fbb3602cc6831b5f9a809c0e88d1daa83Andreas Gampe    FindToolDumpPrintout("", GetTmpnam());
569f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe  }
570f3e070675f0a80de8a876689f70eb075d2b42947Andreas Gampe
57103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  // Use a consistent tmpnam, so store it.
57203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string GetTmpnam() {
57303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    if (tmpnam_.length() == 0) {
57403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      ScratchFile tmp;
57503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe      tmpnam_ = tmp.GetFilename() + "asm";
57603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    }
57703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe    return tmpnam_;
57803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  }
57903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
58003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
58103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
58203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string architecture_string_;
58303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  const char* asm_header_;
58403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
58503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string assembler_cmd_name_;
58603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string assembler_parameters_;
58703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
58803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string objdump_cmd_name_;
58903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string objdump_parameters_;
59003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
59103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string disassembler_cmd_name_;
59203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string disassembler_parameters_;
59303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
59403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string resolved_assembler_cmd_;
59503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string resolved_objdump_cmd_;
59603b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string resolved_disassemble_cmd_;
59703b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
59803b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  std::string android_data_;
59903b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
60003b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe  DISALLOW_COPY_AND_ASSIGN(AssemblerTestInfrastructure);
60103b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe};
60203b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
60303b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe}  // namespace art
60403b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe
60503b9ee44362965efec4a4f3d23e978e390fa842fAndreas Gampe#endif  // ART_COMPILER_UTILS_ASSEMBLER_TEST_BASE_H_
606