/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "berberis/base/checks.h" #if defined(__i386__) || defined(__x86_64__) #include "berberis/program_runner/program_runner.h" #elif defined(__aarch64__) #include "berberis/guest_state/guest_state.h" #include "berberis/interpreter/riscv64/interpreter.h" #include "berberis/tiny_loader/loaded_elf_file.h" #include "berberis/tiny_loader/tiny_loader.h" #endif // Program runner meant for testing and manual invocation. namespace berberis { namespace { void Usage(const char* argv_0) { printf( "Usage: %s [-h|?] [-l loader] [-s vdso] guest_executable [arg1 [arg2 ...]]\n" " -h, -? - print this message\n" " -l loader - path to guest loader\n" " -s vdso - path to guest vdso\n" " guest_executable - path to the guest executable\n", argv_0); } struct Options { const char* guest_executable; const char* loader_path; const char* vdso_path; bool print_help_and_exit; }; Options ParseArgs(int argc, char* argv[]) { CHECK_GE(argc, 1); static const Options kOptsError{.print_help_and_exit = true}; Options opts{ .guest_executable = nullptr, .loader_path = nullptr, .vdso_path = nullptr, .print_help_and_exit = false, }; int curr_arg = 1; for (int curr_arg = 1; curr_arg < argc; ++curr_arg) { if (argv[curr_arg][0] != '-') { break; } const char option = argv[curr_arg][1]; switch (option) { case 's': case 'l': if (++curr_arg == argc) { return kOptsError; } if (option == 's') { opts.vdso_path = argv[curr_arg]; } else { opts.loader_path = argv[curr_arg]; } break; case 'h': case '?': default: return kOptsError; } } if (curr_arg >= argc) { return kOptsError; } return opts; } } // namespace } // namespace berberis int main(int argc, char* argv[], [[maybe_unused]] char* envp[]) { #if defined(__GLIBC__) // Disable brk in glibc-malloc. // // By default GLIBC uses brk in malloc which may lead to conflicts with // executables that use brk for their own needs. See http://b/64720148 for // example. mallopt(M_MMAP_THRESHOLD, 0); mallopt(M_TRIM_THRESHOLD, -1); #endif berberis::Options opts = berberis::ParseArgs(argc, argv); if (opts.print_help_and_exit) { berberis::Usage(argv[0]); return -1; } std::string error_msg; #if defined(__i386__) || defined(__x86_64__) || defined(__riscv) if (!berberis::Run( // TODO(b/276787135): Make vdso and loader configurable via command line arguments. /* vdso_path */ nullptr, /* loader_path */ nullptr, argc - optind, const_cast(argv + optind), envp, &error_msg)) { fprintf(stderr, "unable to start executable: %s\n", error_msg.c_str()); return -1; } #elif defined(__aarch64__) LoadedElfFile elf_file; if (!TinyLoader::LoadFromFile(argv[optind], &elf_file, &error_msg)) { fprintf(stderr, "unable to start load file: %s\n", error_msg.c_str()); return -1; } if (elf_file.e_type() != ET_EXEC) { fprintf(stderr, "this is not a static executable file: %hu\n", elf_file.e_type()); return -1; } berberis::ThreadState state{}; state.cpu.insn_addr = berberis::ToGuestAddr(elf_file.entry_point()); while (true) { InterpretInsn(&state); } #else #error Unsupported platform #endif return 0; }