Update Nix files for LLDB Pwndbg (#2410)

* Update nix files for `pwndbg-lldb`

* Update nix/pwndbg.nix

Co-authored-by: patryk4815 <bux.patryk@gmail.com>

* Update nix/pwndbg.nix

Co-authored-by: patryk4815 <bux.patryk@gmail.com>

* Remaining fixes

---------

Co-authored-by: patryk4815 <bux.patryk@gmail.com>
This commit is contained in:
Matt. 2024-09-03 12:27:59 -03:00 committed by GitHub
parent 7ed76041b9
commit 6cac3dfd0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 96 additions and 21 deletions

View File

@ -71,6 +71,14 @@
inputs.pwndbg = self;
isDev = true;
};
pwndbg-lldb = import ./nix/pwndbg.nix {
pkgs = pkgsBySystem.${system};
python3 = pkgsBySystem.${system}.python3;
gdb = pkgsBySystem.${system}.gdb;
inputs.pwndbg = self;
isDev = true;
isLLDB = true;
};
}
// (portableDrvs system)
// (tarballDrv system)
@ -82,6 +90,7 @@
pkgs = pkgsBySystem.${system};
python3 = pkgsBySystem.${system}.python3;
inputs.pwndbg = self;
isLLDB = true;
}
);
};

View File

@ -12,11 +12,12 @@
import nixpkgs { overlays = [ ]; },
python3 ? pkgs.python3,
inputs ? null,
isLLDB ? false,
...
}:
let
pyEnv = import ./pyenv.nix {
inherit pkgs python3 inputs;
inherit pkgs python3 inputs isLLDB;
lib = pkgs.lib;
isDev = true;
};
@ -25,7 +26,7 @@ in
default = pkgs.mkShell {
NIX_CONFIG = "extra-experimental-features = nix-command flakes repl-flake";
# Anything not handled by the poetry env
nativeBuildInputs = with pkgs; [
nativeBuildInputs = (with pkgs; [
# from setup-dev.sh
nasm
gcc
@ -38,7 +39,9 @@ in
go
pyEnv
];
]) ++ pkgs.lib.optionals isLLDB (with pkgs; [
lldb_19
]);
shellHook = ''
export PWNDBG_VENV_PATH="PWNDBG_PLEASE_SKIP_VENV"
export ZIGPATH="${pkgs.lib.getBin pkgs.zig_0_10}/bin/"

View File

@ -4,6 +4,8 @@
gdb ? pkgs.gdb,
inputs ? null,
isDev ? false,
isLLDB ? false,
lldb ? pkgs.lldb_19,
}:
let
binPath = pkgs.lib.makeBinPath (
@ -14,6 +16,9 @@ let
python3.pkgs.ropper # ref: https://github.com/pwndbg/pwndbg/blob/2023.07.17/pwndbg/commands/ropper.py#L30
python3.pkgs.ropgadget # ref: https://github.com/pwndbg/pwndbg/blob/2023.07.17/pwndbg/commands/rop.py#L34
]
++ pkgs.lib.optionals isLLDB [
python3.pkgs.gnureadline
]
);
pyEnv = import ./pyenv.nix {
@ -22,7 +27,7 @@ let
python3
inputs
isDev
;
isLLDB;
lib = pkgs.lib;
};
@ -35,33 +40,60 @@ let
''
);
pwndbg = pkgs.stdenv.mkDerivation {
name = "pwndbg";
pwndbg = let
pwndbgName = if isLLDB then "pwndbg-lldb" else "pwndbg";
in pkgs.stdenv.mkDerivation {
name = pwndbgName;
version = pwndbgVersion;
src = pkgs.lib.sourceByRegex inputs.pwndbg [
src = pkgs.lib.sourceByRegex inputs.pwndbg ([
"pwndbg"
"pwndbg/.*"
] ++ (if isLLDB then [
"lldbinit.py"
"pwndbg-lldb.py"
] else [
"gdbinit.py"
];
]));
nativeBuildInputs = [ pkgs.makeWrapper ];
buildInputs = [ pyEnv ];
installPhase = ''
installPhase = let
fix_init_script = { target, line }: ''
# Build self-contained init script for lazy loading from vanilla gdb
# I purposely use insert() so I can re-import during development without having to restart gdb
sed "${line} i import sys, os\n\
sys.path.insert(0, '${pyEnv}/${pyEnv.sitePackages}')\n\
sys.path.insert(0, '$out/share/pwndbg/')\n\
os.environ['PATH'] += ':${binPath}'\n" -i ${target}
'';
in (if isLLDB then ''
mkdir -p $out/share/pwndbg
mkdir -p $out/bin
cp -r lldbinit.py pwndbg $out/share/pwndbg
cp pwndbg-lldb.py $out/bin/${pwndbgName}
${fix_init_script { target = "$out/bin/${pwndbgName}"; line = "4"; } }
touch $out/share/pwndbg/.skip-venv
wrapProgram $out/bin/${pwndbgName} \
--prefix PATH : ${ pkgs.lib.makeBinPath [ lldb ] } \
'' + (pkgs.lib.optionalString (!pkgs.stdenv.isDarwin) ''
--set LLDB_DEBUGSERVER_PATH ${ pkgs.lib.makeBinPath [ lldb ] }/lldb-server \
'') + ''
--set PWNDBG_LLDBINIT_DIR $out/share/pwndbg
'' else ''
mkdir -p $out/share/pwndbg
cp -r gdbinit.py pwndbg $out/share/pwndbg
# Build self-contained init script for lazy loading from vanilla gdb
# I purposely use insert() so I can re-import during development without having to restart gdb
sed "2 i import sys, os\n\
sys.path.insert(0, '${pyEnv}/${pyEnv.sitePackages}')\n\
sys.path.insert(0, '$out/share/pwndbg/')\n\
os.environ['PATH'] += ':${binPath}'\n" -i $out/share/pwndbg/gdbinit.py
${fix_init_script { target = "$out/share/pwndbg/gdbinit.py"; line = "2"; } }
touch $out/share/pwndbg/.skip-venv
makeWrapper ${gdb}/bin/gdb $out/bin/pwndbg \
makeWrapper ${gdb}/bin/gdb $out/bin/${pwndbgName} \
--add-flags "--quiet --early-init-eval-command=\"set auto-load safe-path /\" --command=$out/share/pwndbg/gdbinit.py"
'';
'');
meta = {
pwndbgVenv = pyEnv;

View File

@ -3,12 +3,13 @@
python3 ? pkgs.python3,
inputs ? null,
isDev ? false,
isLLDB ? false,
lib,
...
}:
pkgs.poetry2nix.mkPoetryEnv {
groups = lib.optionals isDev [ "dev" ];
checkGroups = lib.optionals isDev [ "dev" ];
groups = lib.optionals isDev [ "dev" ] ++ lib.optionals isLLDB [ "lldb" ];
checkGroups = lib.optionals isDev [ "dev" ] ++ lib.optionals isLLDB [ "lldb" ];
projectDir = inputs.pwndbg;
python = python3;
overrides = pkgs.poetry2nix.overrides.withDefaults (

View File

@ -41,16 +41,24 @@ def find_lldb_python_path() -> str:
if __name__ == "__main__":
debug = "PWNDBG_LLDB_DEBUG" in os.environ
# Find the path for the LLDB Python bindings.
path = find_lldb_python_path()
sys.path.append(path)
if debug:
print(f"[-] Launcher: LLDB Python path: {path}")
# Older LLDB versions crash newer versions of CPython on import, so check
# for it, and stop early with an error message.
#
# See https://github.com/llvm/llvm-project/issues/70453
lldb_version = find_lldb_version()
if debug:
print(f"[-] Launcher: LLDB version {lldb_version[0]}.{lldb_version[1]}")
if sys.version_info.minor >= 12 and lldb_version[0] <= 18:
print("LLDB 18 and earlier is incompatible with Python 3.12 and later", file=sys.stderr)
sys.exit(1)
@ -60,13 +68,32 @@ if __name__ == "__main__":
lldb.SBDebugger.Initialize()
debugger = lldb.SBDebugger.Create()
debugger.HandleCommand("command script import ./lldbinit.py")
debug = "PWNDBG_LLDB_DEBUG" in os.environ
# Resolve the location of lldbinit.py based on the environment, if needed.
lldbinit_dir = os.path.dirname(sys.argv[0])
if "PWNDBG_LLDBINIT_DIR" in os.environ:
lldbinit_dir = os.environ["PWNDBG_LLDBINIT_DIR"]
lldbinit_dir = os.path.abspath(lldbinit_dir)
lldbinit_path = os.path.join(lldbinit_dir, "lldbinit.py")
if debug:
print(f"[-] Launcher: Importing main LLDB module at '{lldbinit_path}'")
if not os.path.exists(lldbinit_path):
print(f"Could not find '{lldbinit_path}, please specify it with PWNDBG_LLDBINIT_DIR")
sys.exit(1)
if lldbinit_path not in sys.path:
sys.path.append(lldbinit_dir)
# Load the lldbinit module we just found.
debugger.HandleCommand(f"command script import {lldbinit_path}")
# Initialize the debugger, proper.
import lldbinit
if debug:
print("[-] Launcher: Initializing Pwndbg")
lldbinit.main(debugger, lldb_version[0], lldb_version[1], debug=debug)
# Run our REPL until the user decides to leave.
@ -80,6 +107,9 @@ if __name__ == "__main__":
from pwndbg.dbg.lldb.repl import run as run_repl
if debug:
print("[-] Launcher: Entering Pwndbg CLI")
run_repl([f"target create '{target}'"] if target else None, debug=debug)
# Dispose of our debugger and terminate LLDB.