AsmGrader 0.0.0
Loading...
Searching...
No Matches
program.hpp
Go to the documentation of this file.
1#pragma once
2
15
16#include <fmt/format.h>
17
18#include <concepts>
19#include <cstddef>
20#include <cstdint>
21#include <filesystem>
22#include <functional>
23#include <memory>
24#include <optional>
25#include <string>
26#include <string_view>
27#include <vector>
28
29namespace asmgrader {
30
32{
33public:
34 explicit Program(std::filesystem::path path, std::vector<std::string> args = {});
35
36 Program(Program&& other) = default;
37 Program& operator=(Program&& rhs) = default;
38
39 ~Program() = default;
40
43
45 Result<RunResult> run_until(const std::function<bool(SyscallRecord)>& pred);
46
48 const TracedSubprocess& get_subproc() const;
50 const SymbolTable& get_symtab() const;
51
52 const std::filesystem::path& get_path() const;
53 const std::vector<std::string>& get_args() const;
54
57 template <typename Func, typename... Args>
58 Result<typename FunctionTraits<Func>::Ret> call_function(std::string_view name, Args&&... args);
59
60 template <typename Func, typename... Args>
61 Result<typename FunctionTraits<Func>::Ret> call_function(std::uintptr_t addr, Args&&... args);
62
63 // TODO: Proper allocation (and deallocation!!)
64 std::uintptr_t alloc_mem(std::size_t amt);
65
66 static Expected<void, std::string> check_is_compat_elf(const std::filesystem::path& path);
67
68private:
69 std::filesystem::path path_;
70 std::vector<std::string> args_;
71
72 std::unique_ptr<TracedSubprocess> subproc_;
73 std::unique_ptr<SymbolTable> symtab_;
74
75 std::size_t alloced_mem_{};
76};
77
78template <typename Func, typename... Args>
80 using Ret = typename FunctionTraits<Func>::Ret;
81
82 Tracer& tracer = subproc_->get_tracer();
83 TRY(tracer.setup_function_call(std::forward<Args>(args)...));
84
85 if (auto res = subproc_->get_tracer().get_memory_io().read_bytes(subproc_->get_tracer().get_mmapped_addr(), 32);
86 res) {
87 LOG_TRACE("Memory (32 bytes) at start of mmaped addr (0x{:x}): {::x}",
88 subproc_->get_tracer().get_mmapped_addr(), *res);
89 }
90
91#if defined(ASMGRADER_AARCH64)
92 [[maybe_unused]] std::uintptr_t instr_pointer = TRY(tracer.get_registers()).pc;
93#elif defined(ASMGRADER_X86_64)
94 [[maybe_unused]] std::uintptr_t instr_pointer = TRY(tracer.get_registers()).rip;
95#endif
96 LOG_TRACE("Jumping to: {:#X} from {:#X}", addr, instr_pointer);
97 TRY(tracer.jump_to(addr));
98
99 auto run_res = tracer.run();
100
101 if (!run_res) {
102 return run_res.error();
103 }
104
105 using enum RunResult::Kind;
106
107 // If the subprocess is no longer alive, restart it
108 // TODO: Should instead catch exit condition before it has an effect
109 if (run_res->get_kind() == Exited || run_res->get_kind() == Killed) {
110 TRY(subproc_->restart());
111 }
112
113 // We expect that the function returns to our written instruction, which is essentially a breakpoint
114 // that raises SIGTRAP
115 if (run_res->get_kind() != SignalCaught || run_res->get_code() != SIGTRAP) {
116 LOG_DEBUG("Unexpected return from function: kind={}, code={}", fmt::underlying(run_res->get_kind()),
117 run_res->get_code());
118
119 std::uintptr_t instr_addr =
120#ifdef __aarch64__
121 subproc_->get_tracer().get_registers()->pc;
122#else
123 subproc_->get_tracer().get_registers()->rip;
124#endif
125 if (auto res = subproc_->get_tracer().get_memory_io().read_bytes(instr_addr, 16); res) {
126 LOG_TRACE("Memory (16 bytes) at point of instruction ptr (0x{:x}): {::x}", instr_addr, *res);
127 }
128
130 }
131
132 if constexpr (std::same_as<Ret, void>) {
133 return {};
134 } else {
135 std::optional<Ret> return_val = TRY(tracer.process_function_ret<Ret>());
136
137 if (!return_val) {
139 }
140
141 return *return_val;
142 }
143}
144
145template <typename Func, typename... Args>
147 auto symbol = symtab_->find(name);
148 if (!symbol) {
150 }
151
152 LOG_TRACE("Resolved symbol {:?} at {:#X}", symbol->name, symbol->address);
153
154 return call_function<Func>(symbol->address, std::forward<Args>(args)...);
155}
156
157} // namespace asmgrader
std::variant wrapper for a partial implementation of C++23's expected type
Definition expected.hpp:34
A trivially-movable, but non-copyable type.
Definition class_traits.hpp:14
Definition program.hpp:32
const std::vector< std::string > & get_args() const
Definition program.cpp:119
static Expected< void, std::string > check_is_compat_elf(const std::filesystem::path &path)
Definition program.cpp:58
Program(std::filesystem::path path, std::vector< std::string > args={})
Definition program.cpp:38
Program(Program &&other)=default
Result< typename FunctionTraits< Func >::Ret > call_function(std::string_view name, Args &&... args)
Returns the result of the function call, or nullopt if the symbol name was not found or some other er...
Definition program.hpp:146
SymbolTable & get_symtab()
Definition program.cpp:86
Program & operator=(Program &&rhs)=default
Result< RunResult > run_until(const std::function< bool(SyscallRecord)> &pred)
Definition program.cpp:98
std::uintptr_t alloc_mem(std::size_t amt)
Definition program.cpp:102
Result< RunResult > run()
Definition program.cpp:94
TracedSubprocess & get_subproc()
Definition program.cpp:78
const std::filesystem::path & get_path() const
Definition program.cpp:115
Kind
Definition run_result.hpp:8
A basic symbol table, for simple interaction with a number of symbols loaded from an ELF file.
Definition symbol_table.hpp:14
A subprocess managed by a tracer.
Definition traced_subprocess.hpp:17
A lightweight wrapper of ptrace(2)
Definition tracer.hpp:49
Result< void > jump_to(std::uintptr_t address)
Set the child process's instruction pointer to address
Definition tracer.cpp:223
Result< Ret > process_function_ret()
AFTER a function has been called, inspects register values (and memory if necessary) to construct the...
Definition tracer.hpp:277
Result< RunResult > run()
Run the child process. Records each syscall execution. Equivalent to run_until({})
Definition tracer.cpp:332
Result< user_regs_struct > get_registers() const
Get the general purpose registers of the stopped tracee IMPORTANT: this is (obviously) architecture-d...
Definition tracer.cpp:235
Result< void > setup_function_call(Args &&... args)
Definition tracer.hpp:173
#define TRY(val)
If the supplied argument is an error (unexpected) type, then propegate it up the call stack....
Definition error_types.hpp:52
#define LOG_TRACE(...)
Definition logging.hpp:40
#define LOG_DEBUG(...)
Definition logging.hpp:41
Definition asm_buffer.hpp:20
@ UnexpectedReturn
A function returned happened due to an unexpected condition.
@ UnresolvedSymbol
Failed to resolve a named symbol in a program.
@ UnknownError
As named; use this as little as possible.
Definition functional_traits.hpp:14
Record of a syscall for use with Tracer to keep track of which syscalls a child process invokes.
Definition syscall_record.hpp:22