#!/bin/bash # SPDX-License-Identifier: BSD-3-Clause # # ghidra_batch_decompile.sh - decompile the whole code range of an analyzed # CUDA program in parallel. Chunks already present are skipped, so the command # is safe to re-run and to interrupt. # # Ghidra takes an exclusive project lock even in -readOnly mode, so a single # project cannot be opened by several processes. To parallelize, this script # makes one copy of the analyzed project per worker under /wk/ and # round-robins the chunks across the copies. Copies are kept (they make # resuming cheap) and can be removed with: rm -rf /wk # # Usage: # ghidra_batch_decompile.sh \ # [chunk_size_hex] [jobs] [timeout_s] # # Defaults: chunk 0x100000, jobs 5, timeout 120. # env: GHIDRA_HOME, GHIDRA_HEADLESS_MAXMEM (default 4G for batch jobs), MAX_CPU # # After it completes, merge per-chunk indexes with: # ghidra_index_merge.sh set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" GHIDRA_HOME="${GHIDRA_HOME:-/snap/ghidra/current/ghidra}" ANALYZE="$GHIDRA_HOME/support/analyzeHeadless" export GHIDRA_HEADLESS_MAXMEM="${GHIDRA_HEADLESS_MAXMEM:-4G}" PROJECT_DIR="${1:?usage: $0 [chunk_hex] [jobs] [timeout_s]}" PROJECT_NAME="${2:?}" PROGRAM="${3:?}" OUTDIR="${4:?}" START="${5:?}" END="${6:?}" CHUNK="${7:-0x100000}" JOBS="${8:-5}" TIMEOUT="${9:-120}" mkdir -p "$OUTDIR/buckets" "$OUTDIR/index" "$OUTDIR/logs" "$OUTDIR/wk" START_D=$((START)); END_D=$((END)); CHUNK_D=$((CHUNK)) # Build the chunk list first: every chunk gets its OWN project copy, so two # concurrent jobs can never race on the same Ghidra project lock. ranges="" n=0 for ((a=START_D; a "$log" 2>&1 || { echo "[FAIL] $a-$b (see $log)"; exit 1; } tail -1 "$log" ' _ echo "[ok] batch decompilation done -> $OUTDIR/buckets" echo " merge indexes: $HERE/ghidra_index_merge.sh $OUTDIR"