{ config, lib, pkgs, ... }: let cfg = config.programs.ghidra; isSplit = lib.elem "lib" cfg.package.outputs; libOutput = if isSplit then cfg.package.lib else cfg.package; packageWithExts = cfg.package.withExtensions (p: lib.concatMap (pl: pl p) cfg.extensions); in { disabledModules = [ "programs/ghidra.nix" ]; options.programs.ghidra = { enable = lib.mkEnableOption "Ghidra, a software reverse engineering (SRE) suite of tools"; gdb = lib.mkOption { default = true; type = lib.types.bool; description = '' Whether to add to gdbinit the python modules required to make Ghidra's debugger work. ''; }; package = lib.mkPackageOption pkgs "ghidra" { example = "ghidra_headless"; }; extensions = lib.mkOption { type = with lib.types; listOf (functionTo (listOf package)); default = []; description = '' Ghidra extensions to be included in the installation. ''; example = lib.literalExpression "[ (ps: with ps; [ my_extension ]) ]"; }; binsync = { enable = lib.mkEnableOption "Ghidra binsync integration"; }; }; config = lib.mkIf cfg.enable { programs.ghidra.extensions = lib.mkIf (cfg.binsync.enable) [ (ps: [ ps.binsync ]) ]; environment = { systemPackages = [ packageWithExts ]; etc = lib.mkIf cfg.gdb { "gdb/gdbinit.d/ghidra-modules.gdb".text = with pkgs.python3.pkgs; '' python import sys [sys.path.append(p) for p in "${ (makePythonPath [ psutil protobuf ]) }".split(":")] sys.path.append("${libOutput}/lib/ghidra/Ghidra/Debug/Debugger-agent-gdb/pypkg/src") sys.path.append("${libOutput}/lib/ghidra/Ghidra/Debug/Debugger-rmi-trace/pypkg/src") end ''; }; }; }; }