From 83e9ba3bd788c7c28f270e2269e593b94ca95b41 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 25 Jul 2013 09:10:32 -0700 Subject: More pnacl-llc cleanups. Focus on nacl_file and its interface with pnacl-llc.cpp; nacl_file as a name no longer makes sense, and neither do the comments describing it - so rename it. Also cleanup the interface a bit, and use more LLVM-y stuff instead of new data types. BUG=None R=dschuff@chromium.org, jfb@chromium.org Review URL: https://codereview.chromium.org/20186002 --- tools/pnacl-llc/CMakeLists.txt | 3 +- tools/pnacl-llc/SRPCStreamer.cpp | 7 +- tools/pnacl-llc/SRPCStreamer.h | 7 +- tools/pnacl-llc/nacl_file.cpp | 393 --------------------------------------- tools/pnacl-llc/pnacl-llc.cpp | 20 +- tools/pnacl-llc/srpc_main.cpp | 364 ++++++++++++++++++++++++++++++++++++ 6 files changed, 377 insertions(+), 417 deletions(-) delete mode 100644 tools/pnacl-llc/nacl_file.cpp create mode 100644 tools/pnacl-llc/srpc_main.cpp (limited to 'tools') diff --git a/tools/pnacl-llc/CMakeLists.txt b/tools/pnacl-llc/CMakeLists.txt index 9e53a28aff..a3ac2712b8 100644 --- a/tools/pnacl-llc/CMakeLists.txt +++ b/tools/pnacl-llc/CMakeLists.txt @@ -2,8 +2,7 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader naclbitreader irreader asmparser naclanalysis) add_llvm_tool(pnacl-llc -# This file provides wrappers to lseek(2), read(2), etc. - nacl_file.cpp + srpc_main.cpp SRPCStreamer.cpp pnacl-llc.cpp ) diff --git a/tools/pnacl-llc/SRPCStreamer.cpp b/tools/pnacl-llc/SRPCStreamer.cpp index c41650c89a..e6546aef5f 100644 --- a/tools/pnacl-llc/SRPCStreamer.cpp +++ b/tools/pnacl-llc/SRPCStreamer.cpp @@ -6,11 +6,6 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// - #if defined(__native_client__) #define DEBUG_TYPE "bitcode-stream" #include "SRPCStreamer.h" @@ -139,4 +134,4 @@ int SRPCStreamer::streamEnd(std::string *ErrMsg) { return Error; } -#endif +#endif // __native_client__ diff --git a/tools/pnacl-llc/SRPCStreamer.h b/tools/pnacl-llc/SRPCStreamer.h index 4c1c6737e6..805552be1f 100644 --- a/tools/pnacl-llc/SRPCStreamer.h +++ b/tools/pnacl-llc/SRPCStreamer.h @@ -1,4 +1,4 @@ -//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===// +//===-- SRPCStreamer.h - Stream bitcode over SRPC ------------------------===// // // The LLVM Compiler Infrastructure // @@ -6,11 +6,6 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// - #ifndef SRPCSTREAMER_H #define SRPCSTREAMER_H diff --git a/tools/pnacl-llc/nacl_file.cpp b/tools/pnacl-llc/nacl_file.cpp deleted file mode 100644 index 44b347a499..0000000000 --- a/tools/pnacl-llc/nacl_file.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* Copyright 2012 The Native Client Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can - * be found in the LICENSE file. - * - * This file provides wrappers to open() to use pre-opened file descriptors - * for the input bitcode and the output file. - * - * It also has the SRPC interfaces, but that should probably be refactored - * into a separate file. - */ - -#if defined(__native_client__) - -#include -#include -#include -#include -// Headers which are not properly part of the SDK are included by their -// path in the nacl tree -#include "native_client/src/shared/srpc/nacl_srpc.h" -#ifdef __pnacl__ -#include "native_client/src/untrusted/nacl/pnacl.h" -#endif -#include "SRPCStreamer.h" - -#include -#include -#include - -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/system_error.h" - - -using std::string; -using std::map; - -#define printerr(...) fprintf(stderr, __VA_ARGS__) - -#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) - -namespace { - -typedef std::vector string_vector; - -// The filename used internally for looking up the bitcode file. -char kBitcodeFilename[] = "pnacl.pexe"; -// The filename used internally for looking up the object code file. -char kObjectFilename[] = "pnacl.o"; -// Object which manages streaming bitcode over SRPC and threading. -SRPCStreamer *srpc_streamer; -// FD of the object file. -int object_file_fd; - -} // namespace - -//TODO(dschuff): a little more elegant interface into llc than this? -extern llvm::DataStreamer* NaClBitcodeStreamer; - -extern int llc_main(int argc, char **argv); - -int GetObjectFileFD() { - return object_file_fd; -} - -namespace { - -int DoTranslate(string_vector* cmd_line_vec, int object_fd) { - if (cmd_line_vec == NULL) { - return 1; - } - object_file_fd = object_fd; - // Make an argv array from the input vector. - size_t argc = cmd_line_vec->size(); - char** argv = new char*[argc]; - for (size_t i = 0; i < argc; ++i) { - // llc_main will not mutate the command line, so this is safe. - argv[i] = const_cast((*cmd_line_vec)[i].c_str()); - } - argv[argc] = NULL; - // Call main. - return llc_main(static_cast(argc), argv); -} - -string_vector* CommandLineFromArgz(char* str, size_t str_len) { - char* entry = str; - string_vector* vec = new string_vector; - while (entry != NULL) { - vec->push_back(entry); - entry = argz_next(str, str_len, entry); - } - return vec; -} - -void AddFixedArguments(string_vector* vec) { - // Add fixed arguments to the command line. These specify the bitcode - // and object code filenames, removing them from the contract with the - // coordinator. - vec->push_back(kBitcodeFilename); - vec->push_back("-o"); - vec->push_back(kObjectFilename); -} - -bool AddDefaultCPU(string_vector* vec) { -#if defined (__pnacl__) - switch (__builtin_nacl_target_arch()) { - case PnaclTargetArchitectureX86_32: { - vec->push_back("-mcpu=pentium4"); - break; - } - case PnaclTargetArchitectureX86_64: { - vec->push_back("-mcpu=core2"); - break; - } - case PnaclTargetArchitectureARM_32: { - vec->push_back("-mcpu=cortex-a9"); - break; - } - default: - printerr("no target architecture match.\n"); - return false; - } -// Some cases for building this with nacl-gcc. -#elif defined (__i386__) - vec->push_back("-mcpu=pentium4"); -#elif defined (__x86_64__) - vec->push_back("-mcpu=core2"); -#elif defined (__arm__) - vec->push_back("-mcpu=cortex-a9"); -#error "Unknown architecture" -#endif - return true; -} - -bool HasCPUOverride(string_vector* vec) { - std::string mcpu = std::string("-mcpu="); - size_t len = mcpu.length(); - for (size_t i = 0; i < vec->size(); ++i) { - std::string prefix = (*vec)[i].substr(0, len); - if (prefix.compare(mcpu) == 0) - return true; - } - return false; -} - -string_vector* GetDefaultCommandLine() { - string_vector* command_line = new string_vector; - size_t i; - // First, those common to all architectures. - static const char* common_args[] = { "pnacl_translator", - "-filetype=obj" }; - for (i = 0; i < ARRAY_SIZE(common_args); ++i) { - command_line->push_back(common_args[i]); - } - // Then those particular to a platform. - static const char* llc_args_x8632[] = { "-mtriple=i686-none-nacl-gnu", - NULL }; - static const char* llc_args_x8664[] = { "-mtriple=x86_64-none-nacl-gnu", - NULL }; - static const char* llc_args_arm[] = { "-mtriple=armv7a-none-nacl-gnueabi", - "-arm-reserve-r9", - "-sfi-disable-cp", - "-sfi-store", - "-sfi-load", - "-sfi-stack", - "-sfi-branch", - "-sfi-data", - "-mattr=+neon", - "-no-inline-jumptables", - "-float-abi=hard", - NULL }; - - const char **llc_args = NULL; -#if defined (__pnacl__) - switch (__builtin_nacl_target_arch()) { - case PnaclTargetArchitectureX86_32: { - llc_args = llc_args_x8632; - break; - } - case PnaclTargetArchitectureX86_64: { - llc_args = llc_args_x8664; - break; - } - case PnaclTargetArchitectureARM_32: { - llc_args = llc_args_arm; - break; - } - default: - printerr("no target architecture match.\n"); - delete command_line; - return NULL; - } -// Some cases for building this with nacl-gcc. -#elif defined (__i386__) - llc_args = llc_args_x8632; -#elif defined (__x86_64__) - llc_args = llc_args_x8664; -#elif defined (__arm__) - llc_args = llc_args_arm; -#else -#error "Unknown architecture" -#endif - for (i = 0; llc_args[i] != NULL; i++) command_line->push_back(llc_args[i]); - return command_line; -} - -// Data passed from main thread to compile thread. -// Takes ownership of the commandline vector. -class StreamingThreadData { - public: - StreamingThreadData(int object_fd, string_vector* cmd_line_vec) : - object_fd_(object_fd), cmd_line_vec_(cmd_line_vec) {} - int ObjectFD() const { return object_fd_; } - string_vector* CmdLineVec() const { return cmd_line_vec_.get(); } - const int object_fd_; - const llvm::OwningPtr cmd_line_vec_; -}; - -void *run_streamed(void *arg) { - StreamingThreadData* data = reinterpret_cast(arg); - data->CmdLineVec()->push_back("-streaming-bitcode"); - if (DoTranslate(data->CmdLineVec(), data->ObjectFD()) != 0) { - printerr("DoTranslate failed.\n"); - srpc_streamer->setError(); - return NULL; - } - delete data; - return NULL; -} - -// Actually do the work for stream initialization. -void do_stream_init(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done, - string_vector* command_line_vec) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - srpc_streamer = new SRPCStreamer(); - std::string StrError; - StreamingThreadData* thread_data = new StreamingThreadData( - in_args[0]->u.hval, command_line_vec); - NaClBitcodeStreamer = srpc_streamer->init(run_streamed, - reinterpret_cast(thread_data), - &StrError); - if (NaClBitcodeStreamer) { - rpc->result = NACL_SRPC_RESULT_OK; - out_args[0]->arrays.str = strdup("no error"); - } else { - out_args[0]->arrays.str = strdup(StrError.c_str()); - } -} - -// Invoked by the StreamInit RPC to initialize bitcode streaming over SRPC. -// Under the hood it forks a new thread at starts the llc_main, which sets -// up the compilation and blocks when it tries to start reading the bitcode. -// Input arg is a file descriptor to write the output object file to. -// Returns a string, containing an error message if the call fails. -void stream_init(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - // cmd_line_vec allocated by GetDefaultCommandLine() is freed by the - // translation thread in run_streamed() - string_vector* cmd_line_vec = GetDefaultCommandLine(); - if (!cmd_line_vec || !AddDefaultCPU(cmd_line_vec)) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - out_args[0]->arrays.str = strdup("Failed to get default commandline."); - return; - } - AddFixedArguments(cmd_line_vec); - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by StreamInitWithCommandLine RPC. Same as stream_init, but -// provides a command line to use instead of the default. -void stream_init_with_command_line(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - char* command_line = in_args[1]->arrays.carr; - size_t command_line_len = in_args[1]->u.count; - string_vector* cmd_line_vec = - CommandLineFromArgz(command_line, command_line_len); - AddFixedArguments(cmd_line_vec); - // cmd_line_vec is freed by the translation thread in run_streamed - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by StreamInitWithOverrides RPC. Same as stream_init, but -// provides commandline flag overrides (appended to the default). -void stream_init_with_overrides(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - string_vector* cmd_line_vec = GetDefaultCommandLine(); - if (!cmd_line_vec) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - out_args[0]->arrays.str = strdup("Failed to get default commandline."); - return; - } - AddFixedArguments(cmd_line_vec); - - char* command_line = in_args[1]->arrays.carr; - size_t command_line_len = in_args[1]->u.count; - llvm::OwningPtr extra_vec( - CommandLineFromArgz(command_line, command_line_len)); - cmd_line_vec->insert(cmd_line_vec->end(), - extra_vec->begin(), extra_vec->end()); - // Make sure some -mcpu override exists for now to prevent - // auto-cpu feature detection from triggering instructions that - // we do not validate yet. - if (!HasCPUOverride(extra_vec.get())) { - AddDefaultCPU(cmd_line_vec); - } - extra_vec.reset(NULL); - // cmd_line_vec is freed by the translation thread in run_streamed. - do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); -} - -// Invoked by the StreamChunk RPC. Receives a chunk of the bitcode and -// buffers it for later retrieval by the compilation thread. -void stream_chunk(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - size_t len = in_args[0]->u.count; - unsigned char *bytes = reinterpret_cast( - in_args[0]->arrays.carr); - if (srpc_streamer->gotChunk(bytes, len) != len) { - return; - } - rpc->result = NACL_SRPC_RESULT_OK; -} - -// Invoked by the StreamEnd RPC. Waits until the compilation finishes, -// then returns. Returns an int indicating whether the bitcode is a -// shared library, a string with the soname, a string with dependencies, -// and a string which contains an error message if applicable. -void stream_end(NaClSrpcRpc *rpc, - NaClSrpcArg **in_args, - NaClSrpcArg **out_args, - NaClSrpcClosure *done) { - NaClSrpcClosureRunner runner(done); - rpc->result = NACL_SRPC_RESULT_APP_ERROR; - std::string StrError; - if (srpc_streamer->streamEnd(&StrError)) { - out_args[3]->arrays.str = strdup(StrError.c_str()); - return; - } - // TODO(eliben): We don't really use shared libraries now. At some - // point this should be cleaned up from SRPC as well. - out_args[0]->u.ival = false; - // SRPC deletes the strings returned when the closure is invoked. - // Therefore we need to use strdup. - out_args[1]->arrays.str = strdup(""); - out_args[2]->arrays.str = strdup(""); - rpc->result = NACL_SRPC_RESULT_OK; -} - -const struct NaClSrpcHandlerDesc srpc_methods[] = { - // Protocol for streaming: - // (StreamInit(obj_fd) -> error_str | - // StreamInitWIthCommandLine(obj_fd, escaped_cmdline) -> error_str) - // StreamChunk(data) + - // StreamEnd() -> (is_shared_lib,soname,dependencies,error_str) - { "StreamInit:h:s", stream_init }, - { "StreamInitWithCommandLine:hC:s:", stream_init_with_command_line }, - { "StreamInitWithOverrides:hC:s:", stream_init_with_overrides }, - { "StreamChunk:C:", stream_chunk }, - { "StreamEnd::isss", stream_end }, - { NULL, NULL }, -}; - -} // namespace - -int -main() { - if (!NaClSrpcModuleInit()) { - return 1; - } - - if (!NaClSrpcAcceptClientConnection(srpc_methods)) { - return 1; - } - NaClSrpcModuleFini(); - return 0; -} - -#endif diff --git a/tools/pnacl-llc/pnacl-llc.cpp b/tools/pnacl-llc/pnacl-llc.cpp index 17d3db865a..31d546ab3e 100644 --- a/tools/pnacl-llc/pnacl-llc.cpp +++ b/tools/pnacl-llc/pnacl-llc.cpp @@ -49,8 +49,9 @@ using namespace llvm; // sandboxed translator (from pnacl-llc.pexe to pnacl-llc.nexe). In this mode // it uses SRPC operations instead of direct OS intefaces. #if defined(__native_client__) -int GetObjectFileFD(); -DataStreamer* NaClBitcodeStreamer; +int srpc_main(int argc, char **argv); +int getObjectFileFD(); +DataStreamer *getNaClBitcodeStreamer(); #endif cl::opt @@ -274,7 +275,7 @@ static int compileModule(StringRef ProgramName, LLVMContext &Context) { std::string StrError; M.reset(getNaClStreamedBitcodeModule( std::string(""), - NaClBitcodeStreamer, Context, &StrError)); + getNaClBitcodeStreamer(), Context, &StrError)); if (!StrError.empty()) Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError); } else { @@ -434,7 +435,7 @@ static int compileModule(StringRef ProgramName, LLVMContext &Context) { { #if defined(__native_client__) - raw_fd_ostream ROS(GetObjectFileFD(), true); + raw_fd_ostream ROS(getObjectFileFD(), true); ROS.SetBufferSize(1 << 20); formatted_raw_ostream FOS(ROS); #else @@ -476,11 +477,10 @@ static int compileModule(StringRef ProgramName, LLVMContext &Context) { return 0; } -#if !defined(__native_client__) -int -main (int argc, char **argv) { - return llc_main(argc, argv); -} +int main(int argc, char **argv) { +#if defined(__native_client__) + return srpc_main(argc, argv); #else -// main() is in nacl_file.cpp. + return llc_main(argc, argv); #endif // __native_client__ +} diff --git a/tools/pnacl-llc/srpc_main.cpp b/tools/pnacl-llc/srpc_main.cpp new file mode 100644 index 0000000000..bd97bc8c5b --- /dev/null +++ b/tools/pnacl-llc/srpc_main.cpp @@ -0,0 +1,364 @@ +//===-- srpc_main.cpp - PNaCl sandboxed translator invocation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Main invocation of the sandboxed translator through SRPC. +// +//===----------------------------------------------------------------------===// + +#if defined(__native_client__) + +// Headers which are not properly part of the SDK are included by their +// path in the NaCl tree. +#include "native_client/src/shared/srpc/nacl_srpc.h" +#ifdef __pnacl__ +#include "native_client/src/untrusted/nacl/pnacl.h" +#endif // __pnacl__ + +#include "SRPCStreamer.h" + +#include +#include +#include +#include + +#include + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/system_error.h" + +using namespace llvm; +using namespace llvm::opt; +using std::string; + +// Imported from pnacl-llc.cpp +extern int llc_main(int argc, char **argv); + +namespace { + +// The filename used internally for looking up the bitcode file. +const char kBitcodeFilename[] = "pnacl.pexe"; +// The filename used internally for looking up the object code file. +const char kObjectFilename[] = "pnacl.o"; +// Object which manages streaming bitcode over SRPC and threading. +SRPCStreamer *srpc_streamer; +// FD of the object file. +int object_file_fd; + +DataStreamer *NaClBitcodeStreamer; + +int DoTranslate(ArgStringList *CmdLineArgs, int object_fd) { + if (CmdLineArgs == NULL) { + return 1; + } + object_file_fd = object_fd; + // Make an argv array from the input vector. + size_t argc = CmdLineArgs->size(); + char **argv = new char *[argc]; + for (size_t i = 0; i < argc; ++i) { + // llc_main will not mutate the command line, so this is safe. + argv[i] = const_cast((*CmdLineArgs)[i]); + } + argv[argc] = NULL; + // Call main. + return llc_main(static_cast(argc), argv); +} + +ArgStringList *CommandLineFromArgz(char *str, size_t str_len) { + char *entry = str; + ArgStringList *CmdLineArgs = new ArgStringList; + while (entry != NULL) { + CmdLineArgs->push_back(entry); + entry = argz_next(str, str_len, entry); + } + return CmdLineArgs; +} + +void AddFixedArguments(ArgStringList *CmdLineArgs) { + // Add fixed arguments to the command line. These specify the bitcode + // and object code filenames, removing them from the contract with the + // coordinator. + CmdLineArgs->push_back(kBitcodeFilename); + CmdLineArgs->push_back("-o"); + CmdLineArgs->push_back(kObjectFilename); +} + +bool AddDefaultCPU(ArgStringList *CmdLineArgs) { +#if defined(__pnacl__) + switch (__builtin_nacl_target_arch()) { + case PnaclTargetArchitectureX86_32: { + CmdLineArgs->push_back("-mcpu=pentium4"); + break; + } + case PnaclTargetArchitectureX86_64: { + CmdLineArgs->push_back("-mcpu=core2"); + break; + } + case PnaclTargetArchitectureARM_32: { + CmdLineArgs->push_back("-mcpu=cortex-a9"); + break; + } + default: + fprintf(stderr, "no target architecture match.\n"); + return false; + } +// Some cases for building this with nacl-gcc. +#elif defined(__i386__) + CmdLineArgs->push_back("-mcpu=pentium4"); +#elif defined(__x86_64__) + CmdLineArgs->push_back("-mcpu=core2"); +#elif defined(__arm__) + CmdLineArgs->push_back("-mcpu=cortex-a9"); +#error "Unknown architecture" +#endif + return true; +} + +bool HasCPUOverride(ArgStringList *CmdLineArgs) { + const char *Mcpu = "-mcpu"; + size_t McpuLen = strlen(Mcpu); + for (size_t i = 0; i < CmdLineArgs->size(); ++i) { + if (strncmp((*CmdLineArgs)[i], Mcpu, McpuLen) == 0) { + return true; + } + } + return false; +} + +ArgStringList *GetDefaultCommandLine() { + ArgStringList *command_line = new ArgStringList; + // First, those common to all architectures. + static const char *common_args[] = { "pnacl_translator", "-filetype=obj" }; + for (size_t i = 0; i < array_lengthof(common_args); ++i) { + command_line->push_back(common_args[i]); + } + // Then those particular to a platform. + static const char *llc_args_x8632[] = { "-mtriple=i686-none-nacl-gnu", NULL }; + static const char *llc_args_x8664[] = { "-mtriple=x86_64-none-nacl-gnu", + NULL }; + static const char *llc_args_arm[] = { + "-mtriple=armv7a-none-nacl-gnueabi", "-arm-reserve-r9", "-sfi-disable-cp", + "-sfi-store", "-sfi-load", "-sfi-stack", "-sfi-branch", "-sfi-data", + "-mattr=+neon", "-no-inline-jumptables", "-float-abi=hard", NULL + }; + + const char **llc_args = NULL; +#if defined(__pnacl__) + switch (__builtin_nacl_target_arch()) { + case PnaclTargetArchitectureX86_32: { + llc_args = llc_args_x8632; + break; + } + case PnaclTargetArchitectureX86_64: { + llc_args = llc_args_x8664; + break; + } + case PnaclTargetArchitectureARM_32: { + llc_args = llc_args_arm; + break; + } + default: + fprintf(stderr, "no target architecture match.\n"); + delete command_line; + return NULL; + } +// Some cases for building this with nacl-gcc. +#elif defined(__i386__) + llc_args = llc_args_x8632; +#elif defined(__x86_64__) + llc_args = llc_args_x8664; +#elif defined(__arm__) + llc_args = llc_args_arm; +#else +#error "Unknown architecture" +#endif + for (size_t i = 0; llc_args[i] != NULL; i++) + command_line->push_back(llc_args[i]); + return command_line; +} + +// Data passed from main thread to compile thread. +// Takes ownership of the commandline vector. +class StreamingThreadData { +public: + StreamingThreadData(int object_fd, ArgStringList *cmd_line_vec) + : object_fd_(object_fd), cmd_line_vec_(cmd_line_vec) {} + int ObjectFD() const { return object_fd_; } + ArgStringList *CmdLineVec() const { return cmd_line_vec_.get(); } + const int object_fd_; + const OwningPtr cmd_line_vec_; +}; + +void *run_streamed(void *arg) { + StreamingThreadData *data = reinterpret_cast(arg); + data->CmdLineVec()->push_back("-streaming-bitcode"); + if (DoTranslate(data->CmdLineVec(), data->ObjectFD()) != 0) { + fprintf(stderr, "DoTranslate failed.\n"); + srpc_streamer->setError(); + return NULL; + } + delete data; + return NULL; +} + +// Actually do the work for stream initialization. +void do_stream_init(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, + NaClSrpcArg **out_args, NaClSrpcClosure *done, + ArgStringList *command_line_vec) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + srpc_streamer = new SRPCStreamer(); + std::string StrError; + StreamingThreadData *thread_data = + new StreamingThreadData(in_args[0]->u.hval, command_line_vec); + NaClBitcodeStreamer = srpc_streamer->init( + run_streamed, reinterpret_cast(thread_data), &StrError); + if (NaClBitcodeStreamer) { + rpc->result = NACL_SRPC_RESULT_OK; + out_args[0]->arrays.str = strdup("no error"); + } else { + out_args[0]->arrays.str = strdup(StrError.c_str()); + } +} + +// Invoked by the StreamInit RPC to initialize bitcode streaming over SRPC. +// Under the hood it forks a new thread at starts the llc_main, which sets +// up the compilation and blocks when it tries to start reading the bitcode. +// Input arg is a file descriptor to write the output object file to. +// Returns a string, containing an error message if the call fails. +void stream_init(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, + NaClSrpcArg **out_args, NaClSrpcClosure *done) { + // cmd_line_vec allocated by GetDefaultCommandLine() is freed by the + // translation thread in run_streamed() + ArgStringList *cmd_line_vec = GetDefaultCommandLine(); + if (!cmd_line_vec || !AddDefaultCPU(cmd_line_vec)) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + out_args[0]->arrays.str = strdup("Failed to get default commandline."); + return; + } + AddFixedArguments(cmd_line_vec); + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by StreamInitWithCommandLine RPC. Same as stream_init, but +// provides a command line to use instead of the default. +void stream_init_with_command_line(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, + NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + char *command_line = in_args[1]->arrays.carr; + size_t command_line_len = in_args[1]->u.count; + ArgStringList *cmd_line_vec = + CommandLineFromArgz(command_line, command_line_len); + AddFixedArguments(cmd_line_vec); + // cmd_line_vec is freed by the translation thread in run_streamed + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by StreamInitWithOverrides RPC. Same as stream_init, but +// provides commandline flag overrides (appended to the default). +void stream_init_with_overrides(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, + NaClSrpcArg **out_args, NaClSrpcClosure *done) { + ArgStringList *cmd_line_vec = GetDefaultCommandLine(); + if (!cmd_line_vec) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + out_args[0]->arrays.str = strdup("Failed to get default commandline."); + return; + } + AddFixedArguments(cmd_line_vec); + + char *command_line = in_args[1]->arrays.carr; + size_t command_line_len = in_args[1]->u.count; + OwningPtr extra_vec( + CommandLineFromArgz(command_line, command_line_len)); + cmd_line_vec->insert(cmd_line_vec->end(), extra_vec->begin(), + extra_vec->end()); + // Make sure some -mcpu override exists for now to prevent + // auto-cpu feature detection from triggering instructions that + // we do not validate yet. + if (!HasCPUOverride(extra_vec.get())) { + AddDefaultCPU(cmd_line_vec); + } + extra_vec.reset(NULL); + // cmd_line_vec is freed by the translation thread in run_streamed. + do_stream_init(rpc, in_args, out_args, done, cmd_line_vec); +} + +// Invoked by the StreamChunk RPC. Receives a chunk of the bitcode and +// buffers it for later retrieval by the compilation thread. +void stream_chunk(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, + NaClSrpcArg **out_args, NaClSrpcClosure *done) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + size_t len = in_args[0]->u.count; + unsigned char *bytes = + reinterpret_cast(in_args[0]->arrays.carr); + if (srpc_streamer->gotChunk(bytes, len) != len) { + return; + } + rpc->result = NACL_SRPC_RESULT_OK; +} + +// Invoked by the StreamEnd RPC. Waits until the compilation finishes, +// then returns. Returns an int indicating whether the bitcode is a +// shared library, a string with the soname, a string with dependencies, +// and a string which contains an error message if applicable. +void stream_end(NaClSrpcRpc *rpc, NaClSrpcArg **in_args, NaClSrpcArg **out_args, + NaClSrpcClosure *done) { + NaClSrpcClosureRunner runner(done); + rpc->result = NACL_SRPC_RESULT_APP_ERROR; + std::string StrError; + if (srpc_streamer->streamEnd(&StrError)) { + out_args[3]->arrays.str = strdup(StrError.c_str()); + return; + } + // TODO(eliben): We don't really use shared libraries now. At some + // point this should be cleaned up from SRPC as well. + out_args[0]->u.ival = false; + // SRPC deletes the strings returned when the closure is invoked. + // Therefore we need to use strdup. + out_args[1]->arrays.str = strdup(""); + out_args[2]->arrays.str = strdup(""); + rpc->result = NACL_SRPC_RESULT_OK; +} + +const struct NaClSrpcHandlerDesc srpc_methods[] = { + // Protocol for streaming: + // (StreamInit(obj_fd) -> error_str | + // StreamInitWIthCommandLine(obj_fd, escaped_cmdline) -> error_str) + // StreamChunk(data) + + // StreamEnd() -> (is_shared_lib,soname,dependencies,error_str) + { "StreamInit:h:s", stream_init }, + { "StreamInitWithCommandLine:hC:s:", stream_init_with_command_line }, + { "StreamInitWithOverrides:hC:s:", stream_init_with_overrides }, + { "StreamChunk:C:", stream_chunk }, { "StreamEnd::isss", stream_end }, + { NULL, NULL }, +}; + +} // namespace + +int getObjectFileFD() { return object_file_fd; } + +DataStreamer *getNaClBitcodeStreamer() { return NaClBitcodeStreamer; } + +int srpc_main(int argc, char **argv) { + if (!NaClSrpcModuleInit()) { + return 1; + } + + if (!NaClSrpcAcceptClientConnection(srpc_methods)) { + return 1; + } + NaClSrpcModuleFini(); + return 0; +} + +#endif // __native_client__ -- cgit v1.2.3-18-g5258