111 lines
No EOL
3.6 KiB
C
111 lines
No EOL
3.6 KiB
C
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* main.c :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2025/12/11 04:07:30 by thrieg #+# #+# */
|
|
/* Updated: 2025/12/11 23:25:15 by thrieg ### ########.fr */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
|
|
#include "../includes/ft_strace.h"
|
|
|
|
int main_loop(size_t binary_type, pid_t pid)
|
|
{
|
|
int in_syscall = 0;
|
|
while (1) {
|
|
// Ask kernel to run until next syscall or signal
|
|
if (ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1) break;
|
|
|
|
int status;
|
|
if (waitpid(pid, &status, 0) == -1) break;
|
|
|
|
if (WIFEXITED(status)) {
|
|
// child exited normally
|
|
printf("+++ exited with %d +++\n", WEXITSTATUS(status));
|
|
break;
|
|
}
|
|
if (WIFSIGNALED(status)) {
|
|
// killed by a signal
|
|
printf("+++ killed by %s +++\n", strsignal(WTERMSIG(status)));
|
|
break;
|
|
}
|
|
if (!WIFSTOPPED(status))
|
|
continue;
|
|
|
|
int sig = WSTOPSIG(status);
|
|
|
|
if (sig == (SIGTRAP | 0x80)) {
|
|
// syscall-enter or syscall-exit
|
|
if (!in_syscall) {
|
|
// ENTRY
|
|
read_regs_and_print_entry(pid, binary_type);
|
|
in_syscall = 1;
|
|
} else {
|
|
// EXIT
|
|
read_regs_and_print_exit(pid, binary_type);
|
|
in_syscall = 0;
|
|
}
|
|
} else {
|
|
// A real signal: print it
|
|
print_signal(pid, sig);
|
|
// pass down the signal to the actual program
|
|
if (ptrace(PTRACE_SYSCALL, pid, 0, sig) == -1) break;
|
|
//waitpid(pid, &status, 0);
|
|
}
|
|
}
|
|
return (EXIT_SUCCESS);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (argc < 2)
|
|
{
|
|
dprintf(2, "usage: %s <path/to/program> <arg1> <arg2> ...\n", argv[0]);
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
//determine if this file is an executable, and if so, 64 or 32 bits
|
|
ssize_t binary_bits = binary_type(argv[1]);
|
|
if (binary_bits < 0)
|
|
{
|
|
if (binary_bits == -1)
|
|
{
|
|
dprintf(2, "couldn't read that file, make sure you have the read and execute permissions on %s\n", argv[1]);
|
|
}
|
|
else if (binary_bits == -2)
|
|
{
|
|
dprintf(2, "%s is not a supported binary\n", argv[1]);
|
|
}
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
|
execvp(argv[1], argv + 1);
|
|
perror("execvp");
|
|
return (EXIT_FAILURE);
|
|
}
|
|
else {
|
|
// 1) Seize the child
|
|
if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) perror("PTRACE_SEIZE");
|
|
|
|
// 2) Interrupt it to force a stop
|
|
if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) perror("PTRACE_INTERRUPT");
|
|
|
|
// 3) Wait for it to stop
|
|
int status;
|
|
waitpid(pid, &status, 0);
|
|
|
|
// 4) Set options
|
|
long opts = PTRACE_O_TRACESYSGOOD;
|
|
ptrace(PTRACE_SETOPTIONS, pid, 0, opts);
|
|
|
|
// 5) Enter main trace loop
|
|
return (main_loop((size_t)binary_bits, pid));
|
|
}
|
|
return (EXIT_SUCCESS);
|
|
} |