#! /usr/bin/perl # SPDX-FileCopyrightText: edef # SPDX-License-Identifier: OSL-3.0 use strict; use POSIX qw(mkfifo); @ARGV or die "Usage: $0 PROGRAM [ARG]... 2> [LOG FILE]"; die "bpftrace does not support spaces in argv" if grep {/ /} @ARGV; unlink(my $fifo = "tracepipe"); mkfifo($fifo, 0600) or die; my $script = do { local $/; }; defined(my $pid = fork) or die; if (!$pid) { open(STDERR, ">&", STDOUT) or die; exec( 'systemd-run', '--user', '--scope', '--', # NOTE: this expects bpftrace to be SUID-root, # and relies on shells dropping euid 'bpftrace', '-o', $fifo, '-e', $script, '-c', join(' ', @ARGV) ) or die; } my %count; # TODO(edef): if bpftrace fails, the FIFO will never open open(TRACE, '<', $fifo) or die; while () { chomp; next if /^Attaching \d+ probes[.][.][.]$/ or /^$/; /^@\[tracepoint:syscalls:sys_enter_(\w+), (.+)\]: (\d+)$/ or die $_; $count{$1}{$2} += $3; } waitpid $pid, 0; foreach my $comm (sort keys %count) { die "unhandled: $comm" if $comm =~ /\s/; my $comm_count = $count{$comm}; foreach my $sys (sort keys %$comm_count) { my $n = $comm_count->{$sys}; print STDERR "$comm\t$sys\t$n\n"; } } __DATA__ BEGIN { @cgroup = cgroup; @self = pid; } tracepoint:syscalls:sys_enter_* /cgroup == @cgroup && pid != @self/ { @[probe, comm] = count(); } interval:s:1 { print(@); clear(@); } tracepoint:sched:sched_process_exit /tid == cpid/ { clear(@cgroup); clear(@self); exit(); }