1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <malloc.h>
18 #include <sys/auxv.h>
19 #include <unistd.h>
20 
21 #include <cstdio>
22 #include <cstring>
23 #include <string>
24 #include <tuple>
25 
26 #include "berberis/base/bit_util.h"
27 #include "berberis/base/checks.h"
28 #include "berberis/base/file.h"
29 #include "berberis/guest_loader/guest_loader.h"
30 #include "berberis/guest_state/guest_addr.h"
31 #include "berberis/program_runner/program_runner.h"
32 #include "berberis/runtime/berberis.h"
33 
34 // Program runner meant for testing and manual invocation.
35 
36 namespace berberis {
37 
38 namespace {
39 
Usage(const char * argv_0)40 void Usage(const char* argv_0) {
41   printf(
42       "Usage: %s [-h] guest_executable [arg1 [arg2 ...]]\n"
43       "  -h             - print this message\n"
44       "  guest_executable - path to the guest executable\n",
45       argv_0);
46 }
47 
48 struct Options {
49   bool print_help_and_exit;
50 };
51 
ParseArgs(int argc,char * argv[])52 Options ParseArgs(int argc, char* argv[]) {
53   CHECK_GE(argc, 1);
54 
55   Options opts{};
56 
57   while (true) {
58     int c = getopt(argc, argv, "+h:");
59     if (c < 0) {
60       break;
61     }
62     switch (c) {
63       case 'h':
64         return Options{.print_help_and_exit = true};
65       default:
66         UNREACHABLE();
67     }
68   }
69 
70   if (optind >= argc) {
71     return Options{.print_help_and_exit = true};
72   }
73 
74   opts.print_help_and_exit = false;
75   return opts;
76 }
77 
78 }  // namespace
79 
80 }  // namespace berberis
81 
main(int argc,char * argv[],char * envp[])82 int main(int argc, char* argv[], char* envp[]) {
83 #if defined(__GLIBC__)
84   // Disable brk in glibc-malloc.
85   //
86   // By default GLIBC uses brk in malloc which may lead to conflicts with
87   // executables that use brk for their own needs. See http://b/64720148 for
88   // example.
89   mallopt(M_MMAP_THRESHOLD, 0);
90   mallopt(M_TRIM_THRESHOLD, -1);
91 #endif
92 
93   berberis::Options opts = berberis::ParseArgs(argc, argv);
94 
95   if (opts.print_help_and_exit) {
96     berberis::Usage(argv[0]);
97     return -1;
98   }
99 
100   std::string error_msg;
101   if (!berberis::Run(
102           // TODO(b/276787135): Make vdso and loader configurable via command line arguments.
103           /* vdso_path */ nullptr,
104           /* loader_path */ nullptr,
105           argc - optind,
106           const_cast<const char**>(argv + optind),
107           envp,
108           &error_msg)) {
109     fprintf(stderr, "unable to start executable: %s\n", error_msg.c_str());
110     return -1;
111   }
112 
113   return 0;
114 }
115