15#include <fmt/format.h>
32#include <linux/ptrace.h>
33#include <sys/ptrace.h>
41using user_fpregs_struct = user_fpsimd_struct;
88 const std::vector<SyscallRecord>&
get_records()
const {
return syscall_records_; }
104 template <
typename... Args>
111 template <
typename Ret>
125 void assert_invariants()
const;
130 template <
typename Arg>
132 template <std::
floating_po
int Arg>
133 auto setup_function_param(
const Arg& arg);
146 int ptrace_request = PTRACE_CONT)
const;
151 SyscallRecord get_syscall_entry_info(
struct ptrace_syscall_info* entry)
const;
152 void get_syscall_exit_info(
SyscallRecord& rec,
struct ptrace_syscall_info* exit)
const;
161 std::unique_ptr<MemoryIOBase> memory_io_;
163 std::vector<SyscallRecord> syscall_records_;
165 std::optional<int> exit_code_;
167 std::size_t mmaped_address_{};
169 std::size_t mmaped_used_amt_{};
172template <
typename... Args>
174 constexpr std::size_t NUM_FP_ARGS =
count_if_v<std::is_floating_point, Args...>;
175 constexpr std::size_t NUM_INT_ARGS =
sizeof...(Args) - NUM_FP_ARGS;
178 static_assert(NUM_FP_ARGS <= 8 && NUM_INT_ARGS <= 6,
"Stack parameters are not yet supported for aarch64");
180 static_assert(NUM_FP_ARGS <= 8 && NUM_INT_ARGS <= 8,
"Stack parameters are not yet supported for x86_64");
187 mmaped_used_amt_ = 0;
190 TRY(setup_function_return());
197 [[maybe_unused]]
auto setup_raw_arg = [&, num_fp = 0, num_int = 0]<
typename T>(T arg)
mutable {
198 if constexpr (std::floating_point<T>) {
200 static_assert(!std::floating_point<T>,
"Floating point parameters not yet supported for aarch64");
202 std::memcpy(&fp_regs.xmm_space[
static_cast<std::ptrdiff_t
>(num_fp * 4)], &arg,
sizeof(T));
207 int_regs.regs[num_int] = arg;
236 if constexpr (
sizeof...(Args) > 0) {
237 std::tuple reg_param_vals = std::make_tuple(setup_function_param(std::forward<Args>(args))...);
239 std::optional first_error =
tuple_find_first([](
const auto& val) {
return val.has_error(); }, reg_param_vals);
241 if (first_error.has_value()) {
242 return std::visit([](
const auto& err_val) {
return err_val.error(); }, *first_error);
245 std::apply([&](
const auto&... vals) { (setup_raw_arg(*vals), ...); }, reg_param_vals);
254template <
typename Arg>
255Result<u64> Tracer::setup_function_param(
const Arg& arg) {
256 if constexpr (std::integral<Arg>) {
257 return static_cast<u64
>(arg);
258 }
else if constexpr (std::is_pointer_v<Arg>) {
260 return reinterpret_cast<u64
>(arg);
262 std::uintptr_t loc = mmaped_address_ + mmaped_used_amt_;
263 std::size_t num_bytes =
TRY(memory_io_->write(loc, arg));
265 mmaped_used_amt_ += num_bytes;
271template <std::
floating_po
int Arg>
276template <
typename Ret>
278 static_assert(std::is_fundamental_v<Ret> || std::is_pointer_v<Ret>,
279 "Non-fundamental and non-pointer types are not yet supported as function return types");
281 if constexpr (std::floating_point<Ret>) {
284 UNIMPLEMENTED(
"TODO: implement floating-point return types for aarch64");
288 return *
reinterpret_cast<Ret*
>(&fp_regs.xmm_space[0]);
293 u64 ret = int_regs.regs[0];
295 u64 ret = int_regs.rax;
298 if constexpr (std::integral<Ret>) {
300 return *
reinterpret_cast<Ret*
>(&ret);
301 }
else if constexpr (std::is_pointer_v<Ret>) {
303 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:25
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
std::optional< int > get_exit_code() const
Obtain the process exit code, or nullopt if the process has not yet exited.
Definition tracer.hpp:91
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< 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:271
std::uintptr_t get_mmapped_addr() const
Definition tracer.hpp:116
static Result< void > init_child()
Set up child process for tracing Call this within the newly-forked process.
Definition tracer.cpp:100
Result< RunResult > run_until(const std::function< bool(SyscallRecord)> &pred)
Run the child process until pred returns true.
Definition tracer.cpp:336
Result< user_fpregs_struct > get_fp_registers() const
Definition tracer.cpp:253
static constexpr auto DEFAULT_TIMEOUT
Definition tracer.hpp:102
Result< void > begin(pid_t pid)
Sets up tracing in parent process, then stops child immediately after exec call.
Definition tracer.cpp:58
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 > set_fp_registers(user_fpregs_struct regs) const
Definition tracer.cpp:263
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:245
static constexpr std::size_t MMAP_LENGTH
Definition tracer.hpp:51
Result< void > setup_function_call(Args &&... args)
Definition tracer.hpp:173
MemoryIOBase & get_memory_io()
Definition tracer.cpp:578
const std::vector< SyscallRecord > & get_records() const
Obtain records of syscalls run so far in the child process.
Definition tracer.hpp:88
#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 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:49
Definition asm_buffer.hpp:20
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:272
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