commit: 08b2728ab76bc29230377dcbb445a05028f63ee0
parent a9bc1a93890ac28224fd423a2f0cc580108c7ddd
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Wed, 15 Oct 2025 07:52:17 +0200
Add support for -o option
Diffstat:
4 files changed, 76 insertions(+), 17 deletions(-)
diff --git a/mstrace.c b/mstrace.c
@@ -3,6 +3,8 @@
#define _DEFAULT_SOURCE
+#include "mstrace.h"
+
#include <errno.h>
#include <inttypes.h> // PRIu64
#include <linux/ptrace.h> // ptrace_syscall_info, __u64
@@ -18,6 +20,7 @@ extern void print_syscall_entry(__u64 nr, __u64 args[6]);
extern void print_syscall_exit(__u64 nr, __u64 args[6]);
pid_t child = -1;
+FILE *out;
static int
wait_for_syscall(int *status)
@@ -33,18 +36,61 @@ wait_for_syscall(int *status)
}
}
+static void
+usage()
+{
+ fputs("Usage: mstrace [-o output] <command> [args...]\n", stderr);
+}
+
int
main(int argc, char *argv[])
{
- argc -= 1;
- argv += 1;
+ char *outname = NULL;
+ out = stderr;
+
+ for(int c = -1; (c = getopt(argc, argv, ":o:")) != -1;)
+ {
+ switch(c)
+ {
+ case 'o':
+ if(outname)
+ {
+ fprintf(stderr, "mstrace: error: Multiple -o options unsupported\n");
+ usage();
+ return 1;
+ }
+ outname = optarg;
+ break;
+ case ':':
+ fprintf(stderr, "mstrace: error: Missing operand for option: '-%c'\n", optopt);
+ usage();
+ return 1;
+ case '?':
+ fprintf(stderr, "mstrace: error: Unknown option '-%c'\n", optopt);
+ usage();
+ return 1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
if(argc < 1)
{
- fprintf(stderr, "Usage: mstrace <command> [args...]\n");
+ usage();
return 1;
}
+ if(outname)
+ {
+ out = fopen(outname, "wb");
+ if(!out)
+ {
+ fprintf(stderr, "mstrace: error: Failed opening file \"%s\": %s\n", outname, strerror(errno));
+ return 1;
+ }
+ }
+
child = fork();
if(child < 0)
{
@@ -113,14 +159,14 @@ main(int argc, char *argv[])
if(syscall_info.exit.is_error)
{
- fprintf(stderr,
+ fprintf(out,
" = (errno: %" PRIi64 ") %s\n",
(int64_t)(-syscall_info.exit.rval),
strerror(-syscall_info.exit.rval));
}
else
{
- fprintf(stderr, " = %" PRIi64 "\n", (int64_t)syscall_info.exit.rval);
+ fprintf(out, " = %" PRIi64 "\n", (int64_t)syscall_info.exit.rval);
}
entry.nr = 0;
break;
@@ -128,22 +174,23 @@ main(int argc, char *argv[])
print_syscall_exit(syscall_info.seccomp.nr, syscall_info.seccomp.args);
// TODO: Check how strace manages this
- fprintf(stderr, " [seccomp_ret = %" PRIu32 "]", syscall_info.seccomp.ret_data);
+ fprintf(out, " [seccomp_ret = %" PRIu32 "]", syscall_info.seccomp.ret_data);
break;
case PTRACE_SYSCALL_INFO_NONE:
- fprintf(stderr, "[syscall-info] none\n");
+ fprintf(out, "[syscall-info] none\n");
break;
}
}
- if(entry.nr != 0)
- print_syscall_exit(entry.nr, entry.args);
+ if(entry.nr != 0) print_syscall_exit(entry.nr, entry.args);
if(WIFEXITED(status))
{
- fprintf(stderr, "+++ exited with %d +++\n", WEXITSTATUS(status));
+ fprintf(out, "+++ exited with %d +++\n", WEXITSTATUS(status));
return WEXITSTATUS(status);
}
+ fflush(out);
+
return 0;
}
diff --git a/mstrace.h b/mstrace.h
@@ -0,0 +1,6 @@
+// SPDX-FileCopyrightText: 2024 Haelwenn (lanodan) Monnier <contact+mstrace@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#include <stdio.h>
+
+extern FILE *out;
diff --git a/print_syscall.c b/print_syscall.c
@@ -3,6 +3,7 @@
#define _DEFAULT_SOURCE
+#include "mstrace.h"
#include "strsyscall.h"
#include <assert.h>
@@ -78,14 +79,19 @@ print_syscall_entry(__u64 nr, __u64 args[6])
switch(nr)
{
case SYS_execve:
- fprintf(stderr, "<%s("Pri_str ", " Pri_x ", " Pri_x ")\n", str_syscalls[nr], read_str(args[0], PATH_MAX), (int64_t)args[1], (int64_t)args[2]);
+ fprintf(out,
+ "<%s(" Pri_str ", " Pri_x ", " Pri_x ")\n",
+ str_syscalls[nr],
+ read_str(args[0], PATH_MAX),
+ (int64_t)args[1],
+ (int64_t)args[2]);
return;
case SYS_nanosleep:
{
struct timespec *rqtp = read_timespec(args[0]);
struct timespec *rmtp = read_timespec(args[1]);
- fprintf(stderr,
+ fprintf(out,
"<%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
"})\n",
str_syscalls[nr],
@@ -109,7 +115,7 @@ print_syscall_exit(__u64 nr, __u64 args[6])
struct timespec *rqtp = read_timespec(args[0]);
struct timespec *rmtp = read_timespec(args[1]);
- fprintf(stderr,
+ fprintf(out,
">%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
"})",
str_syscalls[nr],
@@ -124,14 +130,14 @@ print_syscall_exit(__u64 nr, __u64 args[6])
assert(nr < SYSCALLS_MAX);
if(str_syscalls[nr] != NULL)
{
- fprintf(stderr, ">%s(", str_syscalls[nr]);
+ fprintf(out, ">%s(", str_syscalls[nr]);
}
else
{
- fprintf(stderr, ">syscall(%" PRIu64 ", ", (uint64_t)nr);
+ fprintf(out, ">syscall(%" PRIu64 ", ", (uint64_t)nr);
}
- fprintf(stderr,
+ fprintf(out,
"0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64
")",
(uint64_t)args[0],
diff --git a/syscalls.sh b/syscalls.sh
@@ -51,6 +51,6 @@ do
fmt="${fmt}"' ")"'
printf ' case SYS_%s:\n' "$syscall"
- printf ' fprintf(stderr, %s, %s);\n' "$fmt" "$fmt_args"
+ printf ' fprintf(out, %s, %s);\n' "$fmt" "$fmt_args"
printf ' return;\n'
done <syscalls.txt >syscalls_cases.h