15#include <fmt/format.h>
32#include <linux/ptrace.h>
33#include <sys/ptrace.h>
41using user_fpregs_struct = user_fpsimd_struct;
75 const std::vector<SyscallRecord>&
get_records()
const {
return syscall_records_; }
91 template <
typename... Args>
98 template <
typename Ret>
112 void assert_invariants()
const;
117 template <
typename Arg>
119 template <std::
floating_po
int Arg>
120 auto setup_function_param(
const Arg& arg);
133 int ptrace_request = PTRACE_CONT)
const;
138 SyscallRecord get_syscall_entry_info(
struct ptrace_syscall_info* entry)
const;
139 void get_syscall_exit_info(
SyscallRecord& rec,
struct ptrace_syscall_info* exit)
const;
148 std::unique_ptr<MemoryIOBase> memory_io_;
150 std::vector<SyscallRecord> syscall_records_;
152 std::optional<int> exit_code_;
154 std::size_t mmaped_address_{};
156 std::size_t mmaped_used_amt_{};
159template <
typename... Args>
161 constexpr std::size_t NUM_FP_ARGS =
count_if_v<std::is_floating_point, Args...>;
162 constexpr std::size_t NUM_INT_ARGS =
sizeof...(Args) - NUM_FP_ARGS;
165 static_assert(NUM_FP_ARGS <= 8 && NUM_INT_ARGS <= 6,
"Stack parameters are not yet supported for aarch64");
167 static_assert(NUM_FP_ARGS <= 8 && NUM_INT_ARGS <= 8,
"Stack parameters are not yet supported for x86_64");
174 mmaped_used_amt_ = 0;
177 TRY(setup_function_return());
184 [[maybe_unused]]
auto setup_raw_arg = [&, num_fp = 0, num_int = 0]<
typename T>(T arg)
mutable {
185 if constexpr (std::floating_point<T>) {
187 static_assert(!std::floating_point<T>,
"Floating point parameters not yet supported for aarch64");
189 std::memcpy(&fp_regs.xmm_space[
static_cast<std::ptrdiff_t
>(num_fp * 4)], &arg,
sizeof(T));
194 int_regs.regs[num_int] = arg;
223 if constexpr (
sizeof...(Args) > 0) {
224 std::tuple reg_param_vals = std::make_tuple(setup_function_param(std::forward<Args>(args))...);
226 std::optional first_error =
tuple_find_first([](
const auto& val) {
return val.has_error(); }, reg_param_vals);
228 if (first_error.has_value()) {
229 return std::visit([](
const auto& err_val) {
return err_val.error(); }, *first_error);
232 std::apply([&](
const auto&... vals) { (setup_raw_arg(*vals), ...); }, reg_param_vals);
241template <
typename Arg>
242Result<u64> Tracer::setup_function_param(
const Arg& arg) {
243 if constexpr (std::integral<Arg>) {
244 return static_cast<u64
>(arg);
245 }
else if constexpr (std::is_pointer_v<Arg>) {
247 return reinterpret_cast<u64
>(arg);
249 std::uintptr_t loc = mmaped_address_ + mmaped_used_amt_;
250 std::size_t num_bytes =
TRY(memory_io_->write(loc, arg));
252 mmaped_used_amt_ += num_bytes;
258template <std::
floating_po
int Arg>
263template <
typename Ret>
265 static_assert(std::is_fundamental_v<Ret> || std::is_pointer_v<Ret>,
266 "Non-fundamental and non-pointer types are not yet supported as function return types");
268 if constexpr (std::floating_point<Ret>) {
271 UNIMPLEMENTED(
"TODO: implement floating-point return types for aarch64");
275 return *
reinterpret_cast<Ret*
>(&fp_regs.xmm_space[0]);
280 u64 ret = int_regs.regs[0];
282 u64 ret = int_regs.rax;
285 if constexpr (std::integral<Ret>) {
287 return *
reinterpret_cast<Ret*
>(&ret);
288 }
else if constexpr (std::is_pointer_v<Ret>) {
290 return reinterpret_cast<Ret
>(ret);
std::variant wrapper for a partial implementation of C++23's expected type
Definition expected.hpp:34
Base class for interacting with a tracee's memory in a variety of ways at a (relatively) high-level F...
Definition memory_io_base.hpp:23
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:187
std::optional< int > get_exit_code() const
Obtain the process exit code, or nullopt if the process has not yet exited.
Definition tracer.hpp:78
Result< Ret > process_function_ret()
AFTER a function has been called, inspects register values (and memory if necessary) to construct the...
Definition tracer.hpp:264
Result< SyscallRecord > execute_syscall(u64 sys_nr, std::array< std::uint64_t, 6 > args)
Executes a syscall with the given arguments as the stopped tracee.
Definition tracer.cpp:235
std::uintptr_t get_mmapped_addr() const
Definition tracer.hpp:103
static Result< void > init_child()
Set up child process for tracing Call this within the newly-forked process.
Definition tracer.cpp:93
Result< user_fpregs_struct > get_fp_registers() const
Definition tracer.cpp:217
static constexpr auto DEFAULT_TIMEOUT
Definition tracer.hpp:89
Result< void > begin(pid_t pid)
Sets up tracing in parent process, then stops child immediately after exec call.
Definition tracer.cpp:51
Result< RunResult > run()
Run the child process. Collect syscall info each time one is executed.
Definition tracer.cpp:297
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:199
Result< void > set_fp_registers(user_fpregs_struct regs) const
Definition tracer.cpp:227
Result< void > set_registers(user_regs_struct regs) const
Set the general purpose registers of the stopped tracee IMPORTANT: this is (obviously) architecture-d...
Definition tracer.cpp:209
static constexpr std::size_t MMAP_LENGTH
Definition tracer.hpp:51
Result< void > setup_function_call(Args &&... args)
Definition tracer.hpp:160
MemoryIOBase & get_memory_io()
Definition tracer.cpp:535
const std::vector< SyscallRecord > & get_records() const
Obtain records of syscalls run so far in the child process.
Definition tracer.hpp:75
#define TRY(val)
If the supplied argument is an error (unexpected) type, then propegate it up the call stack....
Definition error_types.hpp:46
#define UNIMPLEMENTED(msg,...)
For features that have not yet / are not planned to be implemented, so that I don't bang my head agai...
Definition logging.hpp:52
Definition asm_buffer.hpp:19
void unreachable()
Definition unreachable.hpp:11
constexpr auto tuple_find_first(Func &&pred, const Tuple &val)
Definition tuple_matcher.hpp:36
constexpr std::size_t count_if_v
Definition count_if.hpp:17
auto setup_function_param(const Arg &arg)
Definition tracer.hpp:259
Type
Definition syscall.hpp:25
Record of a syscall for use with Tracer to keep track of which syscalls a child process invokes.
Definition syscall_record.hpp:22
std::variant< i32, i64, u32, u64, Result< std::string >, Result< std::vector< Result< std::string > > >, void *, Result< std::timespec > > SyscallArg
An arbitrary syscall argument void* is a catch-all for any pointer type.
Definition syscall_record.hpp:25
Definition tracer_types.hpp:43
Types primarily to wrap Linux result info for use with refTracer