#!/usr/bin/env bash # Batch-decompile many binaries listed in a file (paths under client/), several # per Ghidra JVM and several JVMs in parallel. Output mirrors the path under # client/, e.g. client/runtime/x/lib/libc.so.6 -> decomp/runtime/x/lib/libc.so.6/. # Ghidra databases are not kept (-readOnly), and binaries whose output already # exists are skipped, so re-running resumes. Chunks that die (e.g. OOM) are # retried one binary per JVM at the end. # Usage: tools/decompile_batch.sh # Knobs: CHUNK (binaries per JVM, 40), PARALLEL (JVMs at once, 4), plus the # per-JVM WORKERS / GHIDRA_HEADLESS_MAXMEM / MEMLIMIT from ghidra-env.sh. set -uo pipefail source "$(dirname "$0")/ghidra-env.sh" LIST="$1" CHUNK="${CHUNK:-40}" PARALLEL="${PARALLEL:-4}" TAG="$(basename "$LIST" .txt)" WORK="$ROOT/decomp/logs/batch_$TAG" mkdir -p "$WORK" pending() { while read -r bin; do [ -n "$bin" ] && [ ! -f "$ROOT/decomp/${bin#client/}/functions.tsv" ] && echo "$bin" done < "$LIST" } run_chunk() { # $1 = chunk file local name; name="batch_${TAG}_$(basename "$1")" mapfile -t bins < "$1" run_headless "$ROOT/ghidra_projects" "$name" \ -import "${bins[@]/#/$ROOT/}" -readOnly -deleteProject \ -scriptPath "$ROOT/tools/ghidra" \ -preScript SetAnalysisOptions.java "${ANALYSIS_OPTS:-GCC Exception Handlers=false}" \ -postScript RecoverClassesFromRTTIScript.java \ -postScript RecoverNamesFromStrings.java \ -postScript ExportDecompiled.java "$ROOT/decomp" "$ROOT/client" \ -analysisTimeoutPerFile 86400 \ -log "$WORK/$(basename "$1").log" > "$WORK/$(basename "$1").out" 2>&1 echo "$(basename "$1") rc=$? $(date +%T)" >> "$WORK/chunks.log" } export -f run_chunk run_headless export ROOT GHIDRA WORK TAG MEMLIMIT for pass in batch single; do rm -f "$WORK"/list_* [ "$pass" = single ] && CHUNK=1 PARALLEL=1 pending | split -l "$CHUNK" -d -a 5 - "$WORK/list_${pass}_" ls "$WORK"/list_* >/dev/null 2>&1 || break ls "$WORK"/list_* | xargs -P "$PARALLEL" -I{} bash -c 'run_chunk "$1"' _ {} done echo "$TAG: $(pending | wc -l) binaries still without output" | tee -a "$WORK/chunks.log"