#!/usr/bin/env perl use strict; use warnings; use Getopt::Long qw/:config posix_default no_ignore_case bundling permute/; # from libseccomp my $DISASM = 'scmp_bpf_disasm'; my $RESOLVER = 'scmp_sys_resolver'; my %opt = ( arch => undef, # x86_64, x32, x86 ); GetOptions( 'a=s' => \$opt{arch}, ) or usage(); my $arch = $opt{arch}; my $bpf = shift or usage(); my %arch_def = ( 3221225534 => 'x86_64', 1073741886 => 'x32', 1073741827 => 'x86', ); sub inspect { my $line = shift; my ($ln, $op, $jt, $jf, $k, $code) = $line =~ /^\s+(\d+):\s+(0x\w+)\s+(0x\w+)\s+(0x\w+)\s+(0x\w+)\s+(.+)$/ or return; return { line => $ln, op => hex($op), jt => hex($jt), jf => hex($jf), k => hex($k), code => $code, bpf_x => (hex($op) & 8 ? 1 : 0), }; } my $dump = `$DISASM < $bpf`; my $nr = 0; for my $line (split /\n/, $dump) { $line =~ s/\$data\[0\]/seccomp_data.nr/ && ($nr = 1); $line =~ s/\$data\[4\]/seccomp_data.arch/ && ($nr = 0); $line =~ s/\$data\[8\]/seccomp_data.instruction_pointer/ && ($nr = 0); $line =~ s/\$data\[12\]/seccomp_data.instruction_pointer+4/ && ($nr = 0); for my $i (0..5) { my $n = 16 + $i * 8; $line =~ s/\$data\[$n\]/seccomp_data.args[$i]/ && ($nr = 0); } $line =~ s{(jeq )(\d+)}{ my $val; if ($nr) { $val = resolve_syscall_num($2); } else { $val = $arch_def{$2}; if (!$opt{arch}) { $arch = $opt{arch} = $val; } if (!$val) { if ($2 > 4096) { $val = sprintf '0x%x', $2; } else { $val = $2; } } } "$1$val"; }e; my $inspect = inspect($line); if ($inspect->{bpf_x}) { my $code = $inspect->{code}; (my $modified = $code) =~ s/^(\w+\s+)(.+?)(\s+|$)/$1X$3/; $line =~ s/\Q$code\E/$modified/; } print "$line\n"; } sub resolve_syscall_num { my $num = shift; my $resolved = `$RESOLVER -a $arch $num 2>/dev/null`; if ($? == 0) { chomp $resolved; return 'SYS_' . $resolved; } else { return sprintf '0x%x', $num; } } sub usage { die "Usage; $0 [-a arch] bpf\n"; }