#!/usr/bin/env bash
# elf-preload.sh - run an ELF with the libc interposer instead of ptrace.
#
#   elf-preload.sh [-o OUTDIR] -- ./binary [args...]
#
# Use when strace is unavailable or too slow: no ptrace, negligible overhead,
# and the log follows fork()ed children because LD_PRELOAD is inherited.
# It cannot see static binaries, setuid binaries, or raw-syscall programs (Go).
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; ROOT="$(dirname "$HERE")"
LIB="$HERE/libpreload_audit.so"
[[ -f "$LIB" ]] || { echo "building interposer..."; make -C "$HERE" >/dev/null; }

OUTDIR=""
while [[ $# -gt 0 ]]; do
  case "$1" in -o) OUTDIR="$2"; shift 2 ;; --) shift; break ;; *) break ;; esac
done
[[ $# -ge 1 ]] || { sed -n '2,10p' "$0"; exit 1; }
NAME="$(basename "$1")"
OUTDIR="${OUTDIR:-$ROOT/out/${NAME}-preload-$(date +%Y%m%d-%H%M%S)}"
mkdir -p "$OUTDIR"
LOG="$OUTDIR/preload.tsv"

if file -b "$1" 2>/dev/null | grep -q 'statically linked'; then
  echo "WARNING: $1 is statically linked - LD_PRELOAD will see nothing. Use elf-trace.sh." >&2
fi
if [[ -u "$1" || -g "$1" ]]; then
  echo "WARNING: $1 is setuid/setgid - the loader ignores LD_PRELOAD. Use elf-trace.sh." >&2
fi

set +e
ELFAUDIT_LOG="$LOG" LD_PRELOAD="$LIB" "$@"
RC=$?
set -e
echo "== exit code: $RC"
[[ -s "$LOG" ]] || { echo "no events captured (static/setuid binary, or it re-execs without libc)" >&2; exit 1; }

{
echo "# libc-level access report: $NAME"
echo
echo "Command: \`$*\`  |  exit code: $RC  |  events: $(wc -l < "$LOG")"
echo
echo "## Files, by access type"
echo '```'
awk -F'\t' '{print $3"\t"$4"\t"$5}' "$LOG" | sort -u | column -t -s$'\t' 2>/dev/null \
  || awk -F'\t' '{print $3, $4, $5}' "$LOG" | sort -u
echo '```'
echo "## Processes started"
echo '```'
awk -F'\t' '$3 ~ /exec|system|popen|fork/ {print "pid "$2": "$3" "$4}' "$LOG"
echo '```'
echo "## Network"
echo '```'
awk -F'\t' '$3 == "connect" {print "pid "$2": "$4" -> "$5}' "$LOG" || echo "(none)"
echo '```'
echo "## Failures (often the most informative lines)"
echo '```'
awk -F'\t' '$5 == "FAIL" {print "pid "$2": "$3" "$4}' "$LOG" || echo "(none)"
echo '```'
echo "Raw TSV: \`$LOG\` (epoch, pid, call, detail, result)"
} > "$OUTDIR/PRELOAD.md"
echo "== report: $OUTDIR/PRELOAD.md"
