• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unistd.h>
18 
19 #include <cstddef>
20 #include <cstdio>
21 #include <string>
22 #include <tuple>
23 
24 #include "berberis/base/bit_util.h"
25 #include "berberis/base/checks.h"
26 #include "berberis/base/macros.h"
27 #include "berberis/guest_state/guest_addr.h"
28 #include "berberis/guest_state/guest_state.h"
29 #include "berberis/runtime/execute_guest.h"
30 #include "berberis/tiny_loader/loaded_elf_file.h"
31 #include "berberis/tiny_loader/tiny_loader.h"
32 
33 namespace berberis {
34 
35 namespace {
36 
Usage(const char * argv_0)37 void Usage(const char* argv_0) {
38   printf(
39       "Usage: %s [-h] [-a start_addr] guest_executable [arg1 [arg2 ...]]\n"
40       "  -h             - print this message\n"
41       "  -a start_addr  - start execution at start_addr\n"
42       "  guest_executable - path to the guest executable\n",
43       argv_0);
44 }
45 
ParseGuestAddr(const char * addr_cstr)46 std::tuple<GuestAddr, bool> ParseGuestAddr(const char* addr_cstr) {
47   char* end_ptr = nullptr;
48   errno = 0;
49   GuestAddr addr = bit_cast<GuestAddr>(strtoull(addr_cstr, &end_ptr, 16));
50 
51   // Warning: setting errno on failure is implementation defined. So we also use extra heuristics.
52   if (errno != 0 || (*end_ptr != '\n' && *end_ptr != '\0')) {
53     printf("Cannot convert \"%s\" to integer: %s\n", addr_cstr,
54            errno != 0 ? strerror(errno) : "unexpected end of string");
55     return {kNullGuestAddr, false};
56   }
57   return {addr, true};
58 }
59 
60 struct Options {
61   const char* guest_executable;
62   GuestAddr start_addr;
63   bool print_help_and_exit;
64 };
65 
ParseArgs(int argc,char * argv[])66 Options ParseArgs(int argc, char* argv[]) {
67   CHECK_GE(argc, 1);
68 
69   Options opts{};
70 
71   while (true) {
72     int c = getopt(argc, argv, "ha:");
73     if (c < 0) {
74       break;
75     }
76     switch (c) {
77       case 'a': {
78         auto [addr, success] = ParseGuestAddr(optarg);
79         if (!success) {
80           return Options{.print_help_and_exit = true};
81         }
82         opts.start_addr = addr;
83         break;
84       }
85       case 'h':
86         return Options{.print_help_and_exit = true};
87       default:
88         UNREACHABLE();
89     }
90   }
91 
92   if (optind >= argc) {
93     return Options{.print_help_and_exit = true};
94   }
95 
96   opts.guest_executable = argv[optind];
97   opts.print_help_and_exit = false;
98   return opts;
99 }
100 
101 }  // namespace
102 
103 }  // namespace berberis
104 
main(int argc,char * argv[])105 int main(int argc, char* argv[]) {
106   berberis::Options opts = berberis::ParseArgs(argc, argv);
107 
108   if (opts.print_help_and_exit) {
109     berberis::Usage(argv[0]);
110     return -1;
111   }
112 
113   LoadedElfFile elf_file;
114   std::string error_msg;
115   if (!TinyLoader::LoadFromFile(opts.guest_executable, &elf_file, &error_msg)) {
116     printf("%s\n", error_msg.c_str());
117     return -1;
118   }
119 
120   berberis::ThreadState state{};
121   state.cpu.insn_addr = opts.start_addr;
122   ExecuteGuest(&state, berberis::kNullGuestAddr);
123 
124   return 0;
125 }
126