diff options
Diffstat (limited to 'nixpkgs/pkgs/development/tools/analysis/radare2')
3 files changed, 328 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/development/tools/analysis/radare2/cutter.nix b/nixpkgs/pkgs/development/tools/analysis/radare2/cutter.nix new file mode 100644 index 000000000000..25c6d6d58792 --- /dev/null +++ b/nixpkgs/pkgs/development/tools/analysis/radare2/cutter.nix @@ -0,0 +1,54 @@ +{ stdenv, fetchFromGitHub +# nativeBuildInputs +, qmake, pkgconfig +# Qt +, qtbase, qtsvg, qtwebengine +# buildInputs +, r2-for-cutter +, python3 }: + +let + version = "1.7.2"; +in +stdenv.mkDerivation rec { + name = "radare2-cutter-${version}"; + + src = fetchFromGitHub { + owner = "radareorg"; + repo = "cutter"; + rev = "v${version}"; + sha256 = "09cqfz66r3830jkz1rwyfqw1xl1jfj6xg4pcccd2ml456kddh9dn"; + }; + + postUnpack = "export sourceRoot=$sourceRoot/src"; + + # Remove this "very helpful" helper file intended for discovering r2, + # as it's a doozy of harddcoded paths and unexpected behavior. + # Happily Nix has everything all set so we don't need it, + # other than as basis for the qmakeFlags set below. + postPatch = '' + substituteInPlace Cutter.pro \ + --replace "include(lib_radare2.pri)" "" + ''; + + nativeBuildInputs = [ qmake pkgconfig ]; + buildInputs = [ qtbase qtsvg qtwebengine r2-for-cutter python3 ]; + + qmakeFlags = [ + "CONFIG+=link_pkgconfig" + "PKGCONFIG+=r_core" + # Leaving this enabled doesn't break build but generates errors + # at runtime (to console) about being unable to load needed bits. + # Disable until can be looked at. + "CUTTER_ENABLE_JUPYTER=false" + ]; + + enableParallelBuilding = true; + + meta = with stdenv.lib; { + description = "A Qt and C++ GUI for radare2 reverse engineering framework"; + homepage = src.meta.homepage; + license = licenses.gpl3; + maintainers = with maintainers; [ mic92 dtzWill ]; + }; +} diff --git a/nixpkgs/pkgs/development/tools/analysis/radare2/default.nix b/nixpkgs/pkgs/development/tools/analysis/radare2/default.nix new file mode 100644 index 000000000000..f88dc3f6d333 --- /dev/null +++ b/nixpkgs/pkgs/development/tools/analysis/radare2/default.nix @@ -0,0 +1,133 @@ +{stdenv, fetchFromGitHub +, buildPackages +, callPackage +, pkgconfig +, libusb, readline, libewf, perl, zlib, openssl +, libuv, file, libzip, xxHash +, gtk2 ? null, vte ? null, gtkdialog ? null +, python3 ? null +, ruby ? null +, lua ? null +, useX11 ? false +, rubyBindings ? false +, pythonBindings ? false +, luaBindings ? false +}: + +assert useX11 -> (gtk2 != null && vte != null && gtkdialog != null); +assert rubyBindings -> ruby != null; +assert pythonBindings -> python3 != null; + + +let + inherit (stdenv.lib) optional; + + generic = { + version_commit, + gittap, + gittip, + rev, + version, + sha256, + cs_ver, + cs_sha256 + }: + stdenv.mkDerivation rec { + name = "radare2-${version}"; + + src = fetchFromGitHub { + owner = "radare"; + repo = "radare2"; + inherit rev sha256; + }; + + postPatch = let + capstone = fetchFromGitHub { + owner = "aquynh"; + repo = "capstone"; + # version from $sourceRoot/shlr/Makefile + rev = cs_ver; + sha256 = cs_sha256; + }; + in '' + mkdir -p build/shlr + cp -r ${capstone} capstone-${cs_ver} + chmod -R +w capstone-${cs_ver} + # radare 3.3 compat for radare2-cutter + (cd shlr && ln -s ../capstone-${cs_ver} capstone) + tar -czvf shlr/capstone-${cs_ver}.tar.gz capstone-${cs_ver} + # necessary because they broke the offline-build: + # https://github.com/radare/radare2/commit/6290e4ff4cc167e1f2c28ab924e9b99783fb1b38#diff-a44d840c10f1f1feaf401917ae4ccd54R258 + # https://github.com/radare/radare2/issues/13087#issuecomment-465159716 + curl() { true; } + export -f curl + ''; + + postInstall = '' + install -D -m755 $src/binr/r2pm/r2pm $out/bin/r2pm + ''; + + WITHOUT_PULL="1"; + makeFlags = [ + "GITTAP=${gittap}" + "GITTIP=${gittip}" + "RANLIB=${stdenv.cc.bintools.bintools}/bin/${stdenv.cc.bintools.targetPrefix}ranlib" + ]; + configureFlags = [ + "--with-sysmagic" + "--with-syszip" + "--with-sysxxhash" + "--with-openssl" + ]; + + enableParallelBuilding = true; + depsBuildBuild = [ buildPackages.stdenv.cc ]; + + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ file readline libusb libewf perl zlib openssl libuv ] + ++ optional useX11 [ gtkdialog vte gtk2 ] + ++ optional rubyBindings [ ruby ] + ++ optional pythonBindings [ python3 ] + ++ optional luaBindings [ lua ]; + + propagatedBuildInputs = [ + # radare2 exposes r_lib which depends on these libraries + file # for its list of magic numbers (`libmagic`) + libzip + xxHash + ]; + + meta = { + description = "unix-like reverse engineering framework and commandline tools"; + homepage = http://radare.org/; + license = stdenv.lib.licenses.gpl2Plus; + maintainers = with stdenv.lib.maintainers; [ raskin makefu mic92 ]; + platforms = with stdenv.lib.platforms; linux; + inherit version; + }; + }; +in { + #<generated> + # DO NOT EDIT! Automatically generated by ./update.py + radare2 = generic { + version_commit = "20942"; + gittap = "3.3.0"; + gittip = "5a9127d2599c8ff61d8544be7d4c9384402e94a3"; + rev = "3.3.0"; + version = "3.3.0"; + sha256 = "11ap3icr8w0y49lq5dxch2h589qdmwf3qv9lsdyfsz4l0mjm49ri"; + cs_ver = "4.0.1"; + cs_sha256 = "0ijwxxk71nr9z91yxw20zfj4bbsbrgvixps5c7cpj163xlzlwba6"; + }; + r2-for-cutter = generic { + version_commit = "20942"; + gittap = "2.9.0-310-gcb62c376b"; + gittip = "cb62c376bef6c7427019a7c28910c33c364436dd"; + rev = "cb62c376bef6c7427019a7c28910c33c364436dd"; + version = "2018-10-07"; + sha256 = "0z4nr1d2ca8ibq34441j15pj22wh46brcbr00j5hcqvn8y2lh96l"; + cs_ver = "e2c1cd46c06744beaceff42dd882de3a90f0a37c"; + cs_sha256 = "1czzqj8zdjgh7h2ixi26ij3mm4bgm4xw2slin6fv73nic8yaw722"; + }; + #</generated> +} diff --git a/nixpkgs/pkgs/development/tools/analysis/radare2/update.py b/nixpkgs/pkgs/development/tools/analysis/radare2/update.py new file mode 100755 index 000000000000..794581bca7ad --- /dev/null +++ b/nixpkgs/pkgs/development/tools/analysis/radare2/update.py @@ -0,0 +1,141 @@ +#!/usr/bin/env nix-shell +#!nix-shell -p nix -p python3 -p git -i python +# USAGE - just run the script: ./update.py +# When editing this file, make also sure it passes the mypy typecheck +# and is formatted with black. +import fileinput +import json +import re +import subprocess +import tempfile +import urllib.request +from datetime import datetime +from pathlib import Path +from typing import Dict + +SCRIPT_DIR = Path(__file__).parent.resolve() + + +def sh(*args: str) -> str: + out = subprocess.check_output(list(args)) + return out.strip().decode("utf-8") + + +def prefetch_github(owner: str, repo: str, ref: str) -> str: + return sh( + "nix-prefetch-url", + "--unpack", + f"https://github.com/{owner}/{repo}/archive/{ref}.tar.gz", + ) + + +def get_radare2_rev() -> str: + url = "https://api.github.com/repos/radare/radare2/releases/latest" + with urllib.request.urlopen(url) as response: + release = json.load(response) # type: ignore + return release["tag_name"] + + +def get_cutter_version() -> str: + version_expr = """ +(with import <nixpkgs> {}; (builtins.parseDrvName (qt5.callPackage <radare2/cutter.nix> {}).name).version) +""" + return sh("nix", "eval", "--raw", version_expr.strip(), "-I", "radare2={0}".format(SCRIPT_DIR)) + + +def get_r2_cutter_rev() -> str: + version = get_cutter_version() + url = f"https://api.github.com/repos/radareorg/cutter/contents?ref=v{version}" + with urllib.request.urlopen(url) as response: + data = json.load(response) # type: ignore + for entry in data: + if entry["name"] == "radare2": + return entry["sha"] + raise Exception("no radare2 submodule found in github.com/radareorg/cutter") + + +def git(dirname: str, *args: str) -> str: + return sh("git", "-C", dirname, *args) + + +def get_repo_info(dirname: str, rev: str) -> Dict[str, str]: + sha256 = prefetch_github("radare", "radare2", rev) + + cs_ver = None + with open(Path(dirname).joinpath("shlr", "Makefile")) as makefile: + for l in makefile: + match = re.match("CS_VER=(\S+)", l) + if match: + cs_ver = match.group(1) + assert cs_ver is not None + + cs_sha256 = prefetch_github("aquynh", "capstone", cs_ver) + + return dict( + rev=rev, + sha256=sha256, + version_commit=git(dirname, "rev-list", "--all", "--count"), + gittap=git(dirname, "describe", "--tags", "--match", "[0-9]*"), + gittip=git(dirname, "rev-parse", "HEAD"), + cs_ver=cs_ver, + cs_sha256=cs_sha256, + ) + + +def write_package_expr(version: str, info: Dict[str, str]) -> str: + return f"""generic {{ + version_commit = "{info["version_commit"]}"; + gittap = "{info["gittap"]}"; + gittip = "{info["gittip"]}"; + rev = "{info["rev"]}"; + version = "{version}"; + sha256 = "{info["sha256"]}"; + cs_ver = "{info["cs_ver"]}"; + cs_sha256 = "{info["cs_sha256"]}"; + }}""" + + +def main() -> None: + radare2_rev = get_radare2_rev() + r2_cutter_rev = get_r2_cutter_rev() + + with tempfile.TemporaryDirectory() as dirname: + git( + dirname, + "clone", + "--branch", + radare2_rev, + "https://github.com/radare/radare2", + ".", + ) + nix_file = str(SCRIPT_DIR.joinpath("default.nix")) + + radare2_info = get_repo_info(dirname, radare2_rev) + + git(dirname, "checkout", r2_cutter_rev) + + timestamp = git(dirname, "log", "-n1", "--format=%at") + r2_cutter_version = datetime.fromtimestamp(int(timestamp)).strftime("%Y-%m-%d") + + r2_cutter_info = get_repo_info(dirname, r2_cutter_rev) + + in_block = False + with fileinput.FileInput(nix_file, inplace=True) as f: + for l in f: + if "#<generated>" in l: + in_block = True + print( + f""" #<generated> + # DO NOT EDIT! Automatically generated by ./update.py + radare2 = {write_package_expr(radare2_rev, radare2_info)}; + r2-for-cutter = {write_package_expr(r2_cutter_version, r2_cutter_info)}; + #</generated>""" + ) + elif "#</generated>" in l: + in_block = False + elif not in_block: + print(l, end="") + + +if __name__ == "__main__": + main() |