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