From 87db26d487f80e0f0954ca6f294cbd076f822b03 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Thu, 8 May 2025 18:30:58 +0000 Subject: [PATCH] GP-5551: Detect and offer installation of missing Python packages. --- .../data/debugger-launchers/kernel-dbgeng.bat | 4 +- .../local-dbgeng-attach.bat | 4 +- .../debugger-launchers/local-dbgeng-ext.bat | 4 +- .../debugger-launchers/local-dbgeng-trace.bat | 4 +- .../data/debugger-launchers/local-dbgeng.bat | 2 +- .../data/debugger-launchers/remote-dbgeng.bat | 4 +- .../data/debugger-launchers/svrcx-dbgeng.bat | 4 +- .../data/support/kernel-dbgeng.py | 36 +-- .../data/support/local-dbgeng-attach.py | 35 +-- .../data/support/local-dbgeng-ext.py | 43 ++- .../data/support/local-dbgeng-trace.py | 28 +- .../data/support/local-dbgeng.py | 37 +-- .../data/support/remote-dbgeng.py | 33 +- .../data/support/standalone_listener.py | 37 +-- .../data/support/svrcx-dbgeng.py | 61 ++-- .../src/main/py/src/ghidradbg/__init__.py | 7 +- .../data/debugger-launchers/core-drgn.sh | 2 +- .../data/debugger-launchers/kernel-drgn.sh | 2 +- .../Debugger-agent-gdb/certification.manifest | 9 +- .../data/debugger-launchers/local-gdb.bat | 75 ----- .../data/debugger-launchers/local-gdb.ps1 | 33 ++ .../data/debugger-launchers/local-gdb.sh | 62 +--- .../data/debugger-launchers/local-rr.sh | 23 +- .../data/debugger-launchers/qemu-gdb.sh | 58 ++-- .../data/debugger-launchers/qemu-sys-gdb.bat | 60 ---- .../data/debugger-launchers/qemu-sys-gdb.ps1 | 52 ++++ .../data/debugger-launchers/qemu-sys-gdb.sh | 61 ++-- .../data/debugger-launchers/remote-gdb.ps1 | 49 +-- .../data/debugger-launchers/remote-gdb.sh | 49 +-- .../data/debugger-launchers/ssh-gdb.bat | 62 ---- .../data/debugger-launchers/ssh-gdb.ps1 | 70 +++++ .../data/debugger-launchers/ssh-gdb.sh | 89 ++++-- .../data/debugger-launchers/ssh-gdbserver.bat | 53 ---- .../data/debugger-launchers/ssh-gdbserver.ps1 | 37 +++ .../data/debugger-launchers/ssh-gdbserver.sh | 44 +-- .../data/debugger-launchers/wine-gdb.sh | 51 +-- .../data/support/gdbsetuputils.ps1 | 92 ++++++ .../data/support/gdbsetuputils.sh | 125 ++++++++ .../certification.manifest | 9 +- .../data/debugger-launchers/android-lldb.bat | 95 ------ .../data/debugger-launchers/android-lldb.ps1 | 34 ++ .../data/debugger-launchers/android-lldb.sh | 56 +--- .../data/debugger-launchers/kernel-lldb.bat | 48 --- .../data/debugger-launchers/kernel-lldb.ps1 | 27 ++ .../data/debugger-launchers/kernel-lldb.sh | 42 +-- .../data/debugger-launchers/local-lldb.bat | 64 ---- .../data/debugger-launchers/local-lldb.ps1 | 30 ++ .../data/debugger-launchers/local-lldb.sh | 60 +--- .../data/debugger-launchers/remote-lldb.ps1 | 44 +-- .../data/debugger-launchers/remote-lldb.sh | 45 +-- .../data/debugger-launchers/ssh-lldb.bat | 51 --- .../data/debugger-launchers/ssh-lldb.ps1 | 69 +++++ .../data/debugger-launchers/ssh-lldb.sh | 79 +++-- .../data/support/lldbsetuputils.ps1 | 106 +++++++ .../data/support/lldbsetuputils.sh | 129 ++++++++ .../src/main/py/MANIFEST.in | 2 +- .../services/DebuggerAutoMappingService.java | 7 + .../ghidra/debug/api/control/ControlMode.java | 16 +- .../data/debugger-launchers/attach-java.jsh | 2 +- .../data/debugger-launchers/bypid-java.jsh | 2 +- .../data/debugger-launchers/local-java.jsh | 2 +- .../Debugger-rmi-trace/certification.manifest | 1 + .../data/support/gmodutils.py | 42 +++ .../data/support/setuputils.ps1 | 97 ++++++ .../data/support/setuputils.sh | 135 ++++++++ .../launcher/AbstractTraceRmiLaunchOffer.java | 2 +- .../gui/tracermi/launcher/LaunchAction.java | 8 +- .../PowerShellScriptTraceRmiLaunchOffer.java | 2 +- .../launcher/ScriptAttributesParser.java | 3 +- .../TraceRmiLauncherServicePlugin.java | 15 +- .../tracermi/AbstractTraceRmiConnection.java | 13 +- .../src/main/py/pyproject.toml | 2 +- .../src/main/py/src/ghidratrace/__init__.py | 26 +- .../src/main/py/src/ghidratrace/client.py | 13 +- .../src/main/py/src/ghidratrace/setuputils.py | 124 ++++++++ .../gui/modules/DebuggerModulesProvider.java | 1 + .../java/ghidra/pty/windows/ConPtyChild.java | 4 +- .../java/agent/gdb/rmi/GdbConnectorsTest.java | 266 ++++++++++++++++ .../agent/lldb/rmi/LldbConnectorsTest.java | 291 ++++++++++++++++++ 79 files changed, 2290 insertions(+), 1275 deletions(-) delete mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.bat create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.bat create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.bat create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.bat create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.ps1 create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.ps1 create mode 100644 Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.sh delete mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.bat create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.bat create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.bat create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.ps1 delete mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.bat create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.ps1 mode change 100644 => 100755 Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.ps1 create mode 100644 Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.sh create mode 100644 Ghidra/Debug/Debugger-rmi-trace/data/support/gmodutils.py create mode 100644 Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.ps1 create mode 100644 Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh create mode 100644 Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/setuputils.py create mode 100644 Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbConnectorsTest.java create mode 100644 Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbConnectorsTest.java diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/kernel-dbgeng.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/kernel-dbgeng.bat index 1b1d5ee79c..f454e638b0 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/kernel-dbgeng.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/kernel-dbgeng.bat @@ -1,4 +1,4 @@ -::@title dbgeng-kernel +::@title dbgeng kernel ::@desc ::@desc

Kernel debugging using dbgeng (in a Python interpreter)

::@desc

@@ -6,7 +6,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#win_kernel ::@enum Connection:str Remote Local EXDI diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-attach.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-attach.bat index a55e48385b..fa79e59322 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-attach.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-attach.bat @@ -1,4 +1,4 @@ -::@title dbgeng-attach +::@title dbgeng attach ::@desc ::@desc

Attach with dbgeng (in a Python interpreter)

::@desc

@@ -6,7 +6,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#attach ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-ext.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-ext.bat index 570325f1b8..9f4330ad91 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-ext.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-ext.bat @@ -1,4 +1,4 @@ -::@title dbgeng-ext +::@title dbgeng extra options ::@image-opt env:OPT_TARGET_IMG ::@desc ::@desc

Launch with dbgeng (in a Python interpreter)

@@ -7,7 +7,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#ext ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-trace.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-trace.bat index 8f844d2d3c..fa1e4708d9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-trace.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng-trace.bat @@ -1,4 +1,4 @@ -::@title dbgeng-trace +::@title dbgeng TTD ::@desc ::@desc

Open trace with dbgeng (in a Python interpreter)

::@desc

@@ -6,7 +6,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#ttd ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.bat index be4136c9a0..f2a17af3e9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.bat @@ -7,7 +7,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#local ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/remote-dbgeng.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/remote-dbgeng.bat index 7c2e328a1c..d54cd208d3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/remote-dbgeng.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/remote-dbgeng.bat @@ -1,4 +1,4 @@ -::@title dbgeng-remote +::@title dbgeng remote ::@desc ::@desc

Connect to a remote debugger (via the .server interface)

::@desc

@@ -6,7 +6,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#remote ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/svrcx-dbgeng.bat b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/svrcx-dbgeng.bat index 7c12a4a01e..f87bae0516 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/svrcx-dbgeng.bat +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/svrcx-dbgeng.bat @@ -1,4 +1,4 @@ -::@title dbgeng-svrcx +::@title dbgeng svrcx ::@image-opt env:OPT_TARGET_IMG ::@desc ::@desc

Connect to a remote dbgeng connection server and launch the target (in a Python interpreter)

@@ -7,7 +7,7 @@ ::@desc For setup instructions, press F1. ::@desc

::@desc -::@menu-group local +::@menu-group dbgeng ::@icon icon.debugger ::@help dbgeng#svrcx ::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py index 514bbb752f..d7fea8022d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py @@ -17,25 +17,16 @@ import os import sys -home = os.getenv('GHIDRA_HOME') -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from ghidradbg import util @@ -59,20 +50,25 @@ def main(): flags = 2 args = os.getenv('OPT_KCONNECT_STRING') cmd.ghidra_trace_attach_kernel(args, flags, start_trace=False) - + # TODO: HACK try: dbg.wait() except KeyboardInterrupt as ki: dbg.interrupt() - #cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG')) + # cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG')) cmd.ghidra_trace_start("System") cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py index bebb644ee0..c9b2a112ae 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py @@ -18,25 +18,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -51,7 +41,7 @@ def main(): flags = os.getenv('OPT_ATTACH_FLAGS') cmd.ghidra_trace_attach( os.getenv('OPT_TARGET_PID'), flags, start_trace=False) - + # TODO: HACK try: dbg.wait() @@ -60,10 +50,15 @@ def main(): cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG')) cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py index 7bb949bf67..35377eacb6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py @@ -18,25 +18,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -56,17 +46,17 @@ def main(): print("dbgeng requires a target image - please try again.") cmd.ghidra_trace_disconnect() return - + cmd.ghidra_trace_create_ext( - target + args, + target + args, os.getenv('OPT_TARGET_DIR'), os.getenv('OPT_TARGET_ENV'), os.getenv('OPT_CREATE_FLAGS'), os.getenv('OPT_CREATE_ENGFLAGS'), - os.getenv('OPT_VERIFIER_FLAGS'), - os.getenv('OPT_ENG_OPTIONS'), + os.getenv('OPT_VERIFIER_FLAGS'), + os.getenv('OPT_ENG_OPTIONS'), start_trace=False) - + # TODO: HACK try: dbg.wait() @@ -75,10 +65,15 @@ def main(): cmd.ghidra_trace_start(target) cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py index e6f2da2b90..dea35669d4 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py @@ -18,25 +18,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -73,4 +63,8 @@ def main(): if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py index f47d3efecf..7e44f339fc 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py @@ -18,25 +18,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -56,9 +46,9 @@ def main(): print("dbgeng requires a target image - please try again.") cmd.ghidra_trace_disconnect() return - + cmd.ghidra_trace_create(target + args, start_trace=False) - + # TODO: HACK try: dbg.wait() @@ -67,10 +57,15 @@ def main(): cmd.ghidra_trace_start(target) cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py index 6e6df60ffc..8748f57a93 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py @@ -18,25 +18,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -53,10 +43,15 @@ def main(): cmd.ghidra_trace_start("Remote") cmd.ghidra_trace_sync_enable() dbg.interrupt() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/standalone_listener.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/standalone_listener.py index 3c11f2aaf2..33ab3f4854 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/standalone_listener.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/standalone_listener.py @@ -20,25 +20,15 @@ import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -60,9 +50,9 @@ def main(): print("dbgeng requires a target image - please try again.") cmd.ghidra_trace_disconnect() return - + cmd.ghidra_trace_create(target + args, start_trace=False) - + # TODO: HACK try: dbg.wait() @@ -71,10 +61,15 @@ def main(): cmd.ghidra_trace_start(target) cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py index f207173f66..4c8e40a75f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py @@ -1,42 +1,32 @@ ## ### -# IP: GHIDRA -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## import os import sys -home = os.getenv('GHIDRA_HOME') - -if os.path.isdir(f'{home}\\ghidra\\.git'): - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -elif os.path.isdir(f'{home}\\.git'): - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src') - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src') -else: - sys.path.append( - f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src') - sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src') +def append_paths(): + sys.path.append("../../../Debugger-rmi-trace/data/support") + from gmodutils import ghidra_module_pypath + sys.path.append(ghidra_module_pypath("Debug/Debugger-rmi-trace")) + sys.path.append(ghidra_module_pypath("Debug/Debugger-agent-dbgeng")) def main(): + append_paths() # Delay these imports until sys.path is patched from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng @@ -55,7 +45,7 @@ def main(): img = os.getenv('OPT_TARGET_IMG') if img is not None and img != "": cmd.ghidra_trace_create(img + args, start_trace=False) - + # TODO: HACK try: dbg.wait() @@ -64,10 +54,15 @@ def main(): cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG')) cmd.ghidra_trace_sync_enable() - - on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK) + + on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, + DbgEng.DEBUG_STATUS_BREAK) cmd.repl() if __name__ == '__main__': - main() + try: + main() + except SystemExit as x: + if x.code != 0: + print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/__init__.py b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/__init__.py index bb1363d5c3..bb2c2bd762 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/__init__.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/__init__.py @@ -14,6 +14,11 @@ # limitations under the License. ## -# NOTE: libraries must precede EVERYTHING, esp pybag and DbgMod +try: + import pybag +except Exception as e: + from ghidratrace.setuputils import prompt_and_mitigate_dependencies + prompt_and_mitigate_dependencies("Debug/Debugger-agent-dbgeng") +# NOTE: libraries must precede EVERYTHING, esp pybag and DbgMod from . import libraries, util, commands, methods, hooks diff --git a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh index 01e5e31995..f4d1a362b2 100755 --- a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh +++ b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title drgn-core +#@title drgn core #@desc #@desc

Launch with drgn-core

#@desc

diff --git a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh index c32f228633..22d5538b32 100755 --- a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh +++ b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title drgn-kernel +#@title drgn kernel #@desc #@desc

Launch with drgn-kernel

#@desc

diff --git a/Ghidra/Debug/Debugger-agent-gdb/certification.manifest b/Ghidra/Debug/Debugger-agent-gdb/certification.manifest index 3749773967..97d4475c6b 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/certification.manifest +++ b/Ghidra/Debug/Debugger-agent-gdb/certification.manifest @@ -2,15 +2,16 @@ ##MODULE IP: JSch License Module.manifest||GHIDRA||||END| README.md||GHIDRA||||END| -data/debugger-launchers/local-gdb.bat||GHIDRA||||END| -data/debugger-launchers/qemu-sys-gdb.bat||GHIDRA||||END| +data/debugger-launchers/local-gdb.ps1||GHIDRA||||END| +data/debugger-launchers/qemu-sys-gdb.ps1||GHIDRA||||END| data/debugger-launchers/remote-gdb.ps1||GHIDRA||||END| -data/debugger-launchers/ssh-gdb.bat||GHIDRA||||END| -data/debugger-launchers/ssh-gdbserver.bat||GHIDRA||||END| +data/debugger-launchers/ssh-gdb.ps1||GHIDRA||||END| +data/debugger-launchers/ssh-gdbserver.ps1||GHIDRA||||END| data/scripts/fallback_info_proc_mappings.gdb||GHIDRA||||END| data/scripts/fallback_maintenance_info_sections.gdb||GHIDRA||||END| data/scripts/getpid-linux-i386.gdb||GHIDRA||||END| data/scripts/wine32_info_proc_mappings.gdb||GHIDRA||||END| +data/support/gdbsetuputils.ps1||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/topics/gdb/gdb.html||GHIDRA||||END| src/main/help/help/topics/gdb/images/GdbLauncher.png||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.bat b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.bat deleted file mode 100644 index 71e78a9190..0000000000 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.bat +++ /dev/null @@ -1,75 +0,0 @@ -::@title gdb -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with gdb

-::@desc

-::@desc This will launch the target on the local machine using gdb. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group local -::@icon icon.debugger -::@help gdb#local -::@enum StartCmd:str run start starti -::@enum Endian:str auto big little -::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH." -::@env OPT_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target." -::@env OPT_ARCH:str="auto" "Architecture" "Target architecture" -::@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" - - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -:: NB: This works - a lot of things do not. Don't change unless you know what you're doing! -set OPT_TARGET_ARGS=%OPT_TARGET_ARGS:"=\"% -set OPT_TARGET_ARGS=%OPT_TARGET_ARGS:)=^)% -:: NB: This seems stupid, but there doesn't seem to be a logical way to test before the previous lines -if %OPT_TARGET_ARGS%=="=\" ( - set OPT_TARGET_ARGS=\"\" -) - -IF "%OPT_TARGET_IMG%"=="" ( - "%OPT_GDB_PATH%" ^ - -q ^ - -ex "set pagination off" ^ - -ex "set confirm off" ^ - -ex "show version" ^ - -ex "python import ghidragdb" ^ - -ex "set architecture %OPT_ARCH%" ^ - -ex "set endian %OPT_ENDIAN%" ^ - -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ - -ex "ghidra trace start" ^ - -ex "ghidra trace sync-enable" ^ - -ex "set confirm on" ^ - -ex "set pagination on" -) ELSE ( - "%OPT_GDB_PATH%" ^ - -q ^ - -ex "set pagination off" ^ - -ex "set confirm off" ^ - -ex "show version" ^ - -ex "python import ghidragdb" ^ - -ex "set architecture %OPT_ARCH%" ^ - -ex "set endian %OPT_ENDIAN%" ^ - -ex "target exec %OPT_TARGET_IMG%" ^ - -ex "set args %OPT_TARGET_ARGS%" ^ - -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ - -ex "ghidra trace start" ^ - -ex "ghidra trace sync-enable" ^ - -ex "%OPT_START_CMD%" ^ - -ex "set confirm on" ^ - -ex "set pagination on" -) diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.ps1 new file mode 100644 index 0000000000..3b43315a3c --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.ps1 @@ -0,0 +1,33 @@ +#@title gdb +#@image-opt arg:1 +#@desc +#@desc

Launch with gdb

+#@desc

+#@desc This will launch the target on the local machine using gdb. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group gdb +#@icon icon.debugger +#@help gdb#local +#@enum StartCmd:str run start starti +#@enum Endian:str auto big little +#@arg :file "Image" "The target binary executable image" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH." +#@env OPT_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target." +#@env OPT_ARCH:str="auto" "Architecture" "Target architecture" +#@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" + +. ..\support\gdbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb" +$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH" + +$arglist = Compute-Gdb-Usermode-Args ` + -TargetImage $args[0] ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] ` + -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh index c41b463751..e79d86177c 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-gdb.sh @@ -23,7 +23,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group local +#@menu-group gdb #@icon icon.debugger #@help gdb#local #@enum StartCmd:str run start starti @@ -37,57 +37,19 @@ #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh + +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH target_image="$1" shift -target_args="$@" -# Ghidra will leave TTY_TARGET empty when OPT_EXTRA_TTY is false. Gdb takes empty to mean the same terminal. +function launch-gdb() { + local -a args + compute-gdb-usermode-args "$target_image" "$GHIDRA_TRACE_RMI_ADDR" "$@" -if [ -z "$target_image" ] -then - "$OPT_GDB_PATH" \ - -q \ - -ex "set pagination off" \ - -ex "set confirm off" \ - -ex "show version" \ - -ex "python import ghidragdb" \ - -ex "set architecture $OPT_ARCH" \ - -ex "set endian $OPT_ENDIAN" \ - -ex "set inferior-tty $TTY_TARGET" \ - -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -ex "ghidra trace start" \ - -ex "ghidra trace sync-enable" \ - -ex "set confirm on" \ - -ex "set pagination on" -else - "$OPT_GDB_PATH" \ - -q \ - -ex "set pagination off" \ - -ex "set confirm off" \ - -ex "show version" \ - -ex "python import ghidragdb" \ - -ex "set architecture $OPT_ARCH" \ - -ex "set endian $OPT_ENDIAN" \ - -ex "file \"$target_image\"" \ - -ex "set args $target_args" \ - -ex "set inferior-tty $TTY_TARGET" \ - -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -ex "ghidra trace start" \ - -ex "ghidra trace sync-enable" \ - -ex "$OPT_START_CMD" \ - -ex "set confirm on" \ - -ex "set pagination on" -fi + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-rr.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-rr.sh index 1de53b37ca..8c5a256204 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-rr.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/local-rr.sh @@ -22,7 +22,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group local +#@menu-group gdb #@icon icon.debugger #@help gdb#rr #@enum StartCmd:str run start starti @@ -34,20 +34,13 @@ #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh -target_image="$1" +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH + +target_trace="$1" # Ghidra will leave TTY_TARGET empty when OPT_EXTRA_TTY is false. Gdb takes empty to mean the same terminal. @@ -68,5 +61,5 @@ set confirm on set pagination on ' > $RRINIT -"$OPT_RR_PATH" replay -x $RRINIT "$target_image" +"$OPT_RR_PATH" replay -x $RRINIT "$target_trace" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh index 9b478141ea..2837b9a080 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title qemu + gdb +#@title gdb + qemu #@image-opt arg:1 #@desc #@desc

Launch with qemu and connect with gdb

@@ -24,7 +24,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group cross +#@menu-group gdb #@icon icon.debugger #@help gdb#qemu #@enum Endian:str auto big little @@ -40,53 +40,33 @@ #@env OPT_PULL_ALL_SECTIONS:bool=false "Pull all section mappings" "Force gdb to send all mappings to Ghidra. This can be costly (see help)." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh + +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH target_image="$1" # No need to put QEMU_GDB on command line. It's already a recognized environment variable. if [ -z "$TTY_TARGET" ] then - "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS $@ & + "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS "$@" & else - "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS $@ <$TTY_TARGET >$TTY_TARGET 2>&1 & + "$GHIDRA_LANG_EXTTOOL_qemu" $OPT_EXTRA_QEMU_ARGS "$@" <$TTY_TARGET >$TTY_TARGET 2>&1 & fi # Give QEMU a moment to open the socket sleep 0.1 -declare -a args +function launch-gdb() { + local -a args + compute-gdb-remote-args "$target_image" "remote localhost:$QEMU_GDB" "$GHIDRA_TRACE_RMI_ADDR" + + if [ "$OPT_PULL_ALL_SECTIONS" = "true" ]; then + args+=(-ex "ghidra trace tx-open 'Put Sections' 'ghidra trace put-sections -all-objects'") + fi -args+=(-q) -args+=(-ex "set pagination off") -args+=(-ex "set confirm off") -args+=(-ex "show version") -args+=(-ex "python import ghidragdb") -args+=(-ex "set architecture $OPT_ARCH") -args+=(-ex "set endian $OPT_ENDIAN") -args+=(-ex "file '$target_image'") -args+=(-ex "ghidra trace connect '$GHIDRA_TRACE_RMI_ADDR'") -args+=(-ex "ghidra trace start") -args+=(-ex "ghidra trace sync-enable") -args+=(-ex "target remote localhost:$QEMU_GDB") -if [ "$OPT_PULL_ALL_SECTIONS" = "true" ] -then - args+=(-ex "ghidra trace tx-start put-all-sections") - args+=(-ex "ghidra trace put-sections -all-objects") - args+=(-ex "ghidra trace tx-commit") -fi -args+=(-ex "set confirm on") -args+=(-ex "set pagination on") - -"$OPT_GDB_PATH" "${args[@]}" + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.bat b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.bat deleted file mode 100644 index 76bde6b38f..0000000000 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.bat +++ /dev/null @@ -1,60 +0,0 @@ -::@title qemu-system + gdb -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with qemu-system and connect with gdb

-::@desc

-::@desc This will launch the target on the local machine using qemu-system. -::@desc Then in a second terminal, it will connect gdb to QEMU's GDBstub. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group cross -::@icon icon.debugger -::@help gdb#qemu -::@enum Endian:str auto big little -::@env OPT_TARGET_IMG:file!="" "Image" "The target binary executable image" -::@env GHIDRA_LANG_EXTTOOL_qemu_system:file="" "QEMU command" "The path to qemu-system for the target architecture." -::@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu" -::@env OPT_EXTRA_QEMU_ARGS:str="" "Extra qemu arguments" "Extra arguments to pass to qemu. Use with care." -::@env OPT_GDB_PATH:file="gdb-multiarch" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH." -::@env OPT_ARCH:str="auto" "Architecture" "Target architecture" -::@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" -::@env OPT_EXTRA_TTY:bool=false "QEMU TTY" "Provide a separate terminal emulator for qemu." - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -IF "%OPT_EXTRA_TTY%"=="true" ( - start "qemu" "%GHIDRA_LANG_EXTTOOL_qemu_system%" %OPT_EXTRA_QEMU_ARGS% -gdb tcp::%QEMU_GDB% -S "%OPT_TARGET_IMG%" -) ELSE ( - start /B "qemu" "%GHIDRA_LANG_EXTTOOL_qemu_system%" %OPT_EXTRA_QEMU_ARGS% -gdb tcp::%QEMU_GDB% -S "%OPT_TARGET_IMG%" -) - -:: Give QEMU a moment to open the socket -powershell -nop -c "& {sleep -m 100}" - -"%OPT_GDB_PATH%" ^ - -q ^ - -ex "set pagination off" ^ - -ex "set confirm off" ^ - -ex "show version" ^ - -ex "python import ghidragdb" ^ - ex "set architecture %OPT_ARCH%" ^ - ex "set endian %OPT_ENDIAN%" ^ - -ex "target exec '%OPT_TARGET_IMG%'" ^ - -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ - -ex "ghidra trace start" ^ - -ex "ghidra trace sync-enable" ^ - -ex "target remote localhost:%QEMU_GDB%" ^ - -ex "set confirm on" ^ - -ex "set pagination on" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.ps1 new file mode 100644 index 0000000000..299d93a1a3 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.ps1 @@ -0,0 +1,52 @@ +#@title gdb + qemu-system +#@image-opt env:OPT_TARGET_IMG +#@desc +#@desc

Launch with qemu-system and connect with gdb

+#@desc

+#@desc This will launch the target on the local machine using qemu-system. +#@desc Then in a second terminal, it will connect gdb to QEMU's GDBstub. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group gdb +#@icon icon.debugger +#@help gdb#qemu +#@enum Endian:str auto big little +#@env OPT_TARGET_IMG:file!="" "Image" "The target binary executable image" +#@env GHIDRA_LANG_EXTTOOL_qemu_system:file="" "QEMU command" "The path to qemu-system for the target architecture." +#@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu" +#@env OPT_EXTRA_QEMU_ARGS:str="" "Extra qemu arguments" "Extra arguments to pass to qemu. Use with care." +#@env OPT_GDB_PATH:file="gdb-multiarch" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH." +#@env OPT_ARCH:str="auto" "Architecture" "Target architecture" +#@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" +#@env OPT_EXTRA_TTY:bool=false "QEMU TTY" "Provide a separate terminal emulator for qemu." + +. ..\support\gdbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb" +$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH" + +$qemuargs = @("`"$Env:GHIDRA_LANG_EXTTOOL_qemu_system`"") +if ("$Env:OPT_EXTRA_QEMU_ARGS" -ne "") { + $qemuargs+=("$Env:OPT_EXTRA_QEMU_ARGS") +} +$qemuargs+=("-gdb", "tcp::$Env:QEMU_GDB", "-S") +$qemuargs+=("`"$Env:OPT_TARGET_IMG`"") + +if ("$Env:OPT_EXTRA_TTY" -eq "true") { + Start-Process -FilePath $qemuargs[0] -ArgumentList $qemuargs[1..$qemuargs.Count] +} +else { + Start-Process -FilePath $qemuargs[0] -ArgumentList $qemuargs[1..$qemuargs.Count] -NoNewWindow +} + +# Give QEMU a moment to open the socket +sleep -m 100 + +$arglist = Compute-Gdb-Remote-Args ` + -TargetImage $args[0] ` + -TargetCx "remote localhost:$Env:QEMU_GDB" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.sh index c1cf9f7064..82515d32ee 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-sys-gdb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title qemu-system + gdb +#@title gdb + qemu-system #@image-opt arg:1 #@desc #@desc

Launch with qemu-system and connect with gdb

@@ -24,7 +24,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group cross +#@menu-group gdb #@icon icon.debugger #@help gdb#qemu #@enum Endian:str auto big little @@ -39,57 +39,32 @@ #@env OPT_PULL_ALL_SECTIONS:bool=false "Pull all section mappings" "Force gdb to send all mappings to Ghidra. This can be costly (see help)." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh + +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH target_image="$1" if [ -z "$TTY_TARGET" ] then - "$GHIDRA_LANG_EXTTOOL_qemu_system" $OPT_EXTRA_QEMU_ARGS -gdb tcp::$QEMU_GDB -S $1 & + "$GHIDRA_LANG_EXTTOOL_qemu_system" $OPT_EXTRA_QEMU_ARGS -gdb tcp::$QEMU_GDB -S $target_image & else - "$GHIDRA_LANG_EXTTOOL_qemu_system" $OPT_EXTRA_QEMU_ARGS -gdb tcp::$QEMU_GDB -S $1 <$TTY_TARGET >$TTY_TARGET 2>&1 & + "$GHIDRA_LANG_EXTTOOL_qemu_system" $OPT_EXTRA_QEMU_ARGS -gdb tcp::$QEMU_GDB -S $target_image <$TTY_TARGET >$TTY_TARGET 2>&1 & fi # Give QEMU a moment to open the socket sleep 0.1 -gdb_args=( - -q - -ex "set pagination off" - -ex "set confirm off" - -ex "show version" - -ex "python import ghidragdb" - -ex "set architecture $OPT_ARCH" - -ex "set endian $OPT_ENDIAN" - -ex "file \"$target_image\"" - -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" - -ex "ghidra trace start" - -ex "ghidra trace sync-enable" - -ex "target remote localhost:$QEMU_GDB" - -ex "set confirm on" - -ex "set pagination on" -) +function launch-gdb() { + local -a args + compute-gdb-remote-args "$target_image" "remote localhost:$QEMU_GDB" "$GHIDRA_TRACE_RMI_ADDR" -# If using OPT_PULL_ALL_SECTIONS, append instructions to push all sections from qemu -if [ "$OPT_PULL_ALL_SECTIONS" = "true" ] -then - gdb_args+=( - -ex "ghidra trace tx-start put-all-sections" - -ex "ghidra trace put-sections -all-objects" - -ex "ghidra trace tx-commit" - ) -fi + if [ "$OPT_PULL_ALL_SECTIONS" = "true" ]; then + args+=(-ex "ghidra trace tx-open 'Put Sections' 'ghidra trace put-sections -all-objects'") + fi -IFS="" -"$OPT_GDB_PATH" ${gdb_args[*]} + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.ps1 index 64a32a8453..fab6f3cc16 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.ps1 +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.ps1 @@ -1,4 +1,4 @@ -#@title remote gdb +#@title gdb remote #@image-opt arg:1 #@desc #@desc

Launch with local gdb and connect to a stub (e.g., gdbserver)

@@ -7,7 +7,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group gdb #@icon icon.debugger #@help gdb#remote #@enum TargetType:str remote extended-remote @@ -20,42 +20,15 @@ #@env OPT_ARCH:str="auto" "Architecture" "Target architecture override" #@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" -[IO.DirectoryInfo] $repo = "$Env:GHIDRA_HOME\.git" -[IO.DirectoryInfo] $repoParent = "$Env:GHIDRA_HOME\ghidra\.git" -if ($repo.Exists) { - $pypathGdb = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src" -} -elseif ($repoParent.Exists) { - $pypathGdb = "$Env:GHIDRA_HOME\ghidra\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src" -} -else { - $pypathGdb = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-agent-gdb\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-rmi-trace\pypkg\src" -} +. ..\support\gdbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb" $Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH" -$arglist = @() +$arglist = Compute-Gdb-Remote-Args ` + -TargetImage $args[0] ` + -TargetCx "$Env:OPT_TARGET_TYPE $Env:OPT_HOST`:$Env:OPT_PORT" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" -$arglist+=("-q") -$arglist+=("-ex", "`"set pagination off`"") -$arglist+=("-ex", "`"set confirm off`"") -$arglist+=("-ex", "`"show version`"") -$arglist+=("-ex", "`"python import ghidragdb`"") -$arglist+=("-ex", "`"set architecture $Env:OPT_ARCH`"") -$arglist+=("-ex", "`"set endian $Env:OPT_ENDIAN`"") -if ("$($args[0])" -ne "") { - $image = $args[0] -replace "\\", "\\\\" - $arglist+=("-ex", "`"file '$image'`"") -} -$arglist+=("-ex", "`"echo Connecting to $Env:OPT_HOST`:$Env:OPT_PORT... `"") -$arglist+=("-ex", "`"target $Env:OPT_TARGET_TYPE $Env:OPT_HOST`:$Env:OPT_PORT`"") -$arglist+=("-ex", "`"ghidra trace connect '$Env:GHIDRA_TRACE_RMI_ADDR'`"") -$arglist+=("-ex", "`"ghidra trace start`"") -$arglist+=("-ex", "`"ghidra trace sync-enable`"") -$arglist+=("-ex", "`"ghidra trace sync-synth-stopped`"") -$arglist+=("-ex", "`"set confirm on`"") -$arglist+=("-ex", "`"set pagination on`"") - -Start-Process -FilePath $Env:OPT_GDB_PATH -ArgumentList $arglist -NoNewWindow -Wait +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh index 8e59bdb434..703701afc8 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/remote-gdb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title remote gdb +#@title gdb remote #@image-opt arg:1 #@desc #@desc

Launch with local gdb and connect to a stub (e.g., gdbserver)

@@ -23,7 +23,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group gdb #@icon icon.debugger #@help gdb#remote #@enum TargetType:str remote extended-remote @@ -36,39 +36,18 @@ #@env OPT_ARCH:str="auto" "Architecture" "Target architecture override" #@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh -declare -a args +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH -args+=(-q) -args+=(-ex "set pagination off") -args+=(-ex "set confirmation off") -args+=(-ex "show version") -args+=(-ex "python import ghidragdb") -args+=(-ex "set architecture $OPT_ARCH") -args+=(-ex "set endian $OPT_ENDIAN") -if [ -n "$1" ] -then - args+=(-ex "file '$1'") -fi -args+=(-ex "echo Connecting to $OPT_HOST:$OPT_PORT...") -args+=(-ex "target $OPT_TARGET_TYPE $OPT_HOST:$OPT_PORT") -args+=(-ex "ghidra trace connect '$GHIDRA_TRACE_RMI_ADDR'") -args+=(-ex "ghidra trace start") -args+=(-ex "ghidra trace sync-enable") -args+=(-ex "ghidra trace sync-synth-stopped") -args+=(-ex "set confirm on") -args+=(-ex "set pagination on") +target_image="$1" -"$OPT_GDB_PATH" "${args[@]}" +function launch-gdb() { + local -a args + compute-gdb-remote-args "$target_image" "$OPT_TARGET_TYPE $OPT_HOST:$OPT_PORT" "$GHIDRA_TRACE_RMI_ADDR" + + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.bat b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.bat deleted file mode 100644 index 58a962a7c5..0000000000 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.bat +++ /dev/null @@ -1,62 +0,0 @@ -::@timeout 60000 -::@title gdb via ssh -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with gdb via ssh

-::@desc

-::@desc This will launch the target on a remote machine using gdb via ssh. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group remote -::@icon icon.debugger -::@help gdb#ssh -::@enum StartCmd:str run start starti -::@enum Endian:str auto big little -::@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image on the remote system" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." -::@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" -::@env OPT_REMOTE_PORT:int=12345 "Remote Trace RMI Port" "A free port on the remote end to receive and forward the Trace RMI connection." -::@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." -::@env OPT_GDB_PATH:str="gdb" "gdb command" "The path to gdb on the remote system. Omit the full path to resolve using the system PATH." -::@env OPT_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target." -::@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture" -::@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" - -@echo off - -IF "%OPT_TARGET_IMG%" == "" ( - set cmd=TERM='%TERM%' '%OPT_GDB_PATH%' ^ - -q ^ - -ex 'set pagination off' ^ - -ex 'set confirm off' ^ - -ex 'show version' ^ - -ex 'python import ghidragdb' ^ - -ex 'set architecture %OPT_ARCH%' ^ - ex 'set endian %OPT_ENDIAN%' ^ - -ex 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -ex 'ghidra trace start' ^ - -ex 'ghidra trace sync-enable' ^ - -ex 'set confirm on' ^ - -ex 'set pagination on' -) ELSE ( - set cmd=TERM='%TERM%' '%OPT_GDB_PATH%' ^ - -q ^ - -ex 'set pagination off' ^ - -ex 'set confirm off' ^ - -ex 'show version' ^ - -ex 'python import ghidragdb' ^ - -ex 'set architecture %OPT_ARCH%' ^ - ex 'set endian %OPT_ENDIAN%' ^ - -ex 'file \"%OPT_TARGET_IMG%\"' ^ - -ex 'set args %OPT_TARGET_ARGS%' ^ - -ex 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -ex 'ghidra trace start' ^ - -ex 'ghidra trace sync-enable' ^ - -ex '%OPT_START_CMD%' ^ - -ex 'set confirm on' ^ - -ex 'set pagination on' -) - -"%OPT_SSH_PATH%" "-R%OPT_REMOTE_PORT%:%GHIDRA_TRACE_RMI_ADDR%" -t %OPT_EXTRA_SSH_ARGS% "%OPT_HOST%" "%cmd%" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.ps1 new file mode 100644 index 0000000000..9900c4a0ab --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.ps1 @@ -0,0 +1,70 @@ +#@timeout 60000 +#@title gdb via ssh +#@image-opt arg:1 +#@desc +#@desc

Launch with gdb via ssh

+#@desc

+#@desc This will launch the target on a remote machine using gdb via ssh. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group gdb +#@icon icon.debugger +#@help gdb#ssh +#@enum StartCmd:str run start starti +#@enum Endian:str auto big little +#@arg :str "Image" "The target binary executable image on the remote system" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." +#@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" +#@env OPT_REMOTE_PORT:int=12345 "Remote Trace RMI Port" "A free port on the remote end to receive and forward the Trace RMI connection." +#@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." +#@env OPT_GDB_PATH:str="gdb" "gdb command" "The path to gdb on the remote system. Omit the full path to resolve using the system PATH." +#@env OPT_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target." +#@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture" +#@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" + +. ..\support\gdbsetuputils.ps1 + +$arglist = Compute-Gdb-Usermode-Args -TargetImage $args[0] -RmiAddress "localhost:$Env:OPT_REMOTE_PORT" +$sshargs = Compute-Ssh-Args $arglist True + +$sshproc = Start-Process -FilePath $sshargs[0] -ArgumentList $sshargs[1..$sshargs.Count] -NoNewWindow -Wait -PassThru + +$version = Get-Ghidra-Version +$answer = Check-Result-And-Prompt-Mitigation $sshproc @" +It appears ghidragdb is missing from the remote system. This can happen if you +forgot to install the required package. This can also happen if you installed +the packages to a different Python environment than is being used by the +remote's gdb. + +This script is about to offer automatic resolution. If you'd like to resolve +this manually, answer no to the next question and then see Ghidra's help by +pressing F1 in the dialog of launch parameters. + +WARNING: Answering yes to the next question will invoke pip to try to install +missing or incorrectly-versioned dependencies. It may attempt to find packages +from the PyPI mirror configured on the REMOTE system. If you have not configured +one, it will connect to the official one. + +WARNING: We invoke pip with the --break-system-packages flag, because some +debuggers that embed Python (gdb, lldb) may not support virtual environments, +and so the packages must be installed to your user environment. + +NOTE: This will copy Python wheels into the HOME directory of the user on the +remote system. You may be prompted to authenticate a few times while packages +are copied and installed. + +NOTE: Automatic resolution will cause this session to terminate. When it has +finished, try launching again. +"@ "Would you like to install 'ghidragdb==$version'?" + +if ($answer) { + Write-Host "Copying Wheels to $Env:OPT_HOST" + Mitigate-Scp-PyModules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-gdb" + + Write-Host "Installing Wheels into GDB's embedded Python" + $arglist = Compute-Gdb-PipInstall-Args "'-f'" "os.environ['HOME']" "'ghidragdb==$version'" + $sshargs = Compute-Ssh-Args $arglist False + Start-Process -FilePath $sshargs[0] -ArgumentList $sshargs[1..$sshargs.Count] -NoNewWindow -Wait +} diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh index f5a80ac53b..34a450424d 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh @@ -24,7 +24,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group gdb #@icon icon.debugger #@help gdb#ssh #@enum StartCmd:str run start starti @@ -40,40 +40,61 @@ #@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture" #@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" +. ../support/gdbsetuputils.sh + target_image="$1" shift -target_args="$@" -if [ -z "$target_image" ] -then - "$OPT_SSH_PATH" "-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR" -t $OPT_EXTRA_SSH_ARGS "$OPT_HOST" "TERM='$TERM' '$OPT_GDB_PATH' \ - -q \ - -ex 'set pagination off' \ - -ex 'set confirm off' \ - -ex 'show version' \ - -ex 'python import ghidragdb' \ - -ex 'set architecture $OPT_ARCH' \ - -ex 'set endian $OPT_ENDIAN' \ - -ex 'ghidra trace connect \"localhost:$OPT_REMOTE_PORT\"' \ - -ex 'ghidra trace start' \ - -ex 'ghidra trace sync-enable' \ - -ex 'set confirm on' \ - -ex 'set pagination on'" -else - "$OPT_SSH_PATH" "-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR" -t $OPT_EXTRA_SSH_ARGS "$OPT_HOST" "TERM='$TERM' '$OPT_GDB_PATH' \ - -q \ - -ex 'set pagination off' \ - -ex 'set confirm off' \ - -ex 'show version' \ - -ex 'python import ghidragdb' \ - -ex 'set architecture $OPT_ARCH' \ - -ex 'set endian $OPT_ENDIAN' \ - -ex 'file \"$target_image\"' \ - -ex 'set args $target_args' \ - -ex 'ghidra trace connect \"localhost:$OPT_REMOTE_PORT\"' \ - -ex 'ghidra trace start' \ - -ex 'ghidra trace sync-enable' \ - -ex '$OPT_START_CMD' \ - -ex 'set confirm on' \ - -ex 'set pagination on'" +function launch-gdb-ssh() { + local -a args + compute-gdb-usermode-args "$target_image" "localhost:$OPT_REMOTE_PORT" "$@" + local -a sshargs + compute-ssh-args true "${args[@]}" + + "${sshargs[@]}" +} +version=$(get-ghidra-version) + +function do-installation() { + local -a pipargs + compute-gdb-pipinstall-args "'-f'" "os.environ['HOME']" "'ghidragdb==$version'" + local -a sshargs + compute-ssh-args false "${pipargs[@]}" + + "${sshargs[@]}" +} + +launch-gdb-ssh +if check-result-and-prompt-mitigation $? " +It appears ghidragdb is missing from the remote system. This can happen if you +forgot to install the required package. This can also happen if you installed +the packages to a different Python environment than is being used by the +remote's gdb. + +This script is about to offer automatic resolution. If you'd like to resolve +this manually, answer no to the next question and then see Ghidra's help by +pressing F1 in the dialog of launch parameters. + +WARNING: Answering yes to the next question will invoke pip to try to install +missing or incorrectly-versioned dependencies. It may attempt to find packages +from the PyPI mirror configured on the REMOTE system. If you have not configured +one, it will connect to the official one. + +WARNING: We invoke pip with the --break-system-packages flag, because some +debuggers that embed Python (gdb, lldb) may not support virtual environments, +and so the packages must be installed to your user environment. + +NOTE: This will copy Python wheels into the HOME directory of the user on the +remote system. You may be prompted to authenticate a few times while packages +are copied and installed. + +NOTE: Automatic resolution will cause this session to terminate. When it has +finished, try launching again. +" "Would you like to install 'ghidragdb==$version'?"; then + + echo "Copying Wheels to $OPT_HOST" + mitigate-scp-pymodules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-gdb" + + echo "Installing Wheels into GDB's embedded Python" + do-installation fi diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.bat b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.bat deleted file mode 100644 index d03fb5e6ad..0000000000 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.bat +++ /dev/null @@ -1,53 +0,0 @@ -::@timeout 60000 -::@title gdb + gdbserver via ssh -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with local gdb and gdbserver via ssh

-::@desc

-::@desc This will start gdb on the local system and then use it to connect and launch the target in gdbserver on the remote system via ssh. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group remote -::@icon icon.debugger -::@help gdb#gdbserver_ssh -::@enum Endian:str auto big little -::@env OPT_TARGET_IMG:str!="" "Image" "The target binary executable image on the remote system" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." -::@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" -::@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." -::@env OPT_GDBSERVER_PATH:str="gdbserver" "gdbserver command (remote)" "The path to gdbserver on the remote system. Omit the full path to resolve using the system PATH." -::@env OPT_EXTRA_GDBSERVER_ARGS:str="" "Extra gdbserver arguments" "Extra arguments to pass to gdbserver. Use with care." -::@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb on the local system. Omit the full path to resolve using the system PATH." -::@env OPT_ARCH:str="auto" "Architecture" "Target architecture" -::@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-gdb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -"%OPT_GDB_PATH%" ^ - -q ^ - -ex "set pagination off" ^ - -ex "set confirm off" ^ - -ex "show version" ^ - -ex "python import ghidragdb" ^ - -ex "set architecture %OPT_ARCH%" ^ - ex "set endian %OPT_ENDIAN%" ^ - -ex "target remote | '%OPT_SSH_PATH%' %OPT_EXTRA_SSH_ARGS% '%OPT_HOST%' '%OPT_GDBSERVER_PATH%' %OPT_EXTRA_GDBSERVER_ARGS% - '%OPT_TARGET_IMG%' %OPT_TARGET_ARGS%" ^ - -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ - -ex "ghidra trace start" ^ - -ex "ghidra trace sync-enable" ^ - -ex "ghidra trace sync-synth-stopped" ^ - -ex "set confirm on" ^ - -ex "set pagination on" diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.ps1 new file mode 100644 index 0000000000..12c5b08060 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.ps1 @@ -0,0 +1,37 @@ +#@timeout 60000 +#@title gdb + gdbserver via ssh +#@image-opt arg:1 +#@desc +#@desc

Launch with local gdb and gdbserver via ssh

+#@desc

+#@desc This will start gdb on the local system and then use it to connect and launch the target in gdbserver on the remote system via ssh. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group gdb +#@icon icon.debugger +#@help gdb#gdbserver_ssh +#@enum Endian:str auto big little +#@arg :str! "Image" "The target binary executable image on the remote system" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." +#@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" +#@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." +#@env OPT_GDBSERVER_PATH:str="gdbserver" "gdbserver command (remote)" "The path to gdbserver on the remote system. Omit the full path to resolve using the system PATH." +#@env OPT_EXTRA_GDBSERVER_ARGS:str="" "Extra gdbserver arguments" "Extra arguments to pass to gdbserver. Use with care." +#@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb on the local system. Omit the full path to resolve using the system PATH." +#@env OPT_ARCH:str="auto" "Architecture" "Target architecture" +#@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" + +. ..\support\gdbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb" +$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH" + +$arglist = Compute-Gdb-Remote-Args ` + -TargetImage $args[0] ` + -TargetCx "remote | '$Env:OPT_SSH_PATH' $Env:OPT_EXTRA_SSH_ARGS '$Env:OPT_HOST' '$Env:OPT_GDBSERVER_PATH' $Env:OPT_EXTRA_GDBSERVER_ARGS - '$($args[0])' $Env:OPT_TARGET_ARGS" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh index f31c5bd16c..3cc5144d90 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdbserver.sh @@ -24,7 +24,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group gdb #@icon icon.debugger #@help gdb#gdbserver_ssh #@enum Endian:str auto big little @@ -39,31 +39,19 @@ #@env OPT_ARCH:str="auto" "Architecture" "Target architecture" #@env OPT_ENDIAN:Endian="auto" "Endian" "Target byte order" -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/gdbsetuputils.sh -"$OPT_GDB_PATH" \ - -q \ - -ex "set pagination off" \ - -ex "set confirm off" \ - -ex "show version" \ - -ex "python import ghidragdb" \ - -ex "set architecture $OPT_ARCH" \ - -ex "set endian $OPT_ENDIAN" \ - -ex "target remote | '$OPT_SSH_PATH' $OPT_EXTRA_SSH_ARGS '$OPT_HOST' '$OPT_GDBSERVER_PATH' $OPT_EXTRA_GDBSERVER_ARGS - $@" \ - -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -ex "ghidra trace start" \ - -ex "ghidra trace sync-enable" \ - -ex "ghidra trace sync-synth-stopped" \ - -ex "set confirm on" \ - -ex "set pagination on" +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH + +target_image="$1" +shift + +function launch-gdb() { + local -a args + compute-gdb-remote-args "$target_image" "remote | '$OPT_SSH_PATH' $OPT_EXTRA_SSH_ARGS '$OPT_HOST' '$OPT_GDBSERVER_PATH' $OPT_EXTRA_GDBSERVER_ARGS - '$target_image' $@" "$GHIDRA_TRACE_RMI_ADDR" + + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh index 59640057b0..f13facef0b 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/wine-gdb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title wine + gdb +#@title gdb + wine #@image-opt arg:1 #@desc #@desc

Launch with gdb and wine

@@ -23,7 +23,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group cross +#@menu-group gdb #@icon icon.debugger #@help gdb#wine #@enum Endian:str auto big little @@ -36,37 +36,20 @@ #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi -# NOTE: Ghidra will leave TTY_TARGET empty, which gdb takes for the same terminal. +. ../support/gdbsetuputils.sh -"$OPT_GDB_PATH" \ - -q \ - -ex "set pagination off" \ - -ex "set confirm off" \ - -ex "show version" \ - -ex "python import ghidragdb.wine" \ - -ex "set architecture $OPT_ARCH" \ - -ex "set endian $OPT_ENDIAN" \ - -ex "file \"$OPT_WINE_PATH\"" \ - -ex "set args $@" \ - -ex "set inferior-tty $TTY_TARGET" \ - -ex "starti" \ - -ex "ghidra wine run-to-image \"$1\"" \ - -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -ex "ghidra trace start \"$1\"" \ - -ex "ghidra trace sync-enable" \ - -ex "ghidra trace sync-synth-stopped" \ - -ex "set confirm on" \ - -ex "set pagination on" +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb") +export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH + +target_image="$1" +shift + +function launch-gdb() { + local -a args + compute-gdb-wine-args "$target_image" "$GHIDRA_TRACE_RMI_ADDR" "$@" + + "${args[@]}" +} +launch-gdb diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.ps1 b/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.ps1 new file mode 100644 index 0000000000..32f8962900 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.ps1 @@ -0,0 +1,92 @@ + +. ..\..\..\Debugger-rmi-trace\data\support\setuputils.ps1 + +function Add-Gdb-Init-Args { + param([ref]$ArgList) + + $ArgList.Value+=("-q") + $ArgList.Value+=("-ex", "`"set pagination off`"") + $ArgList.Value+=("-ex", "`"set confirm off`"") + $ArgList.Value+=("-ex", "`"show version`"") + $ArgList.Value+=("-ex", "`"python import ghidragdb`"") + $ArgList.Value+=("-ex", "`"python if not 'ghidragdb' in locals(): exit(253)`"") + $ArgList.Value+=("-ex", "`"set architecture $Env:OPT_ARCH`"") + $ArgList.Value+=("-ex", "`"set endian $Env:OPT_ENDIAN`"") +} + +function Add-Gdb-Image-And-Args { + param([ref]$ArgList, $TargetImage, $TargetArgs) + + if ("$TargetImage" -ne "") { + $image = $TargetImage -replace "\\", "\\\\" + $ArgList.Value+=("-ex", "`"file '$image'`"") + } + if ("$TargetArgs" -ne "") { + $tgtargs = $TargetArgs -replace "`"", "\`"" + # Escaping parentheses in the arguments is no longer necessary in powershell vs cmd + $ArgList.Value+=("-ex", "`"set args $tgtargs`"") + } +} + +function Add-Gdb-Connect-And-Sync { + param([ref]$ArgList, $Address) + + $ArgList.Value+=("-ex", "`"ghidra trace connect '$Address'`"") + $ArgList.Value+=("-ex", "`"ghidra trace start`"") + $ArgList.Value+=("-ex", "`"ghidra trace sync-enable`"") +} + +function Add-Gdb-Start-If-Image { + param([ref]$ArgList, $TargetImage) + + if ("$TargetImage" -ne "") { + $ArgList.Value+=("-ex", "`"$Env:OPT_START_CMD`"") + } +} + +function Add-Gdb-Tail-Args { + param([ref]$ArgList) + + $ArgList.Value+=("-ex", "`"set confirm on`"") + $ArgList.Value+=("-ex", "`"set pagination on`"") +} + +function Compute-Gdb-Usermode-Args { + param($TargetImage, $RmiAddress) + + $arglist = @("`"$Env:OPT_GDB_PATH`"") + Add-Gdb-Init-Args -ArgList ([ref]$arglist) + Add-Gdb-Image-And-Args -ArgList ([ref]$arglist) -TargetImage $TargetImage -TargetArgs $Env:OPT_TARGET_ARGS + Add-Gdb-Connect-And-Sync -ArgList ([ref]$arglist) -Address $RmiAddress + Add-Gdb-Start-If-Image -ArgList ([ref]$arglist) -TargetImage $TargetImage + Add-Gdb-Tail-Args -ArgList ([ref]$arglist) + + return $arglist +} + +function Compute-Gdb-Remote-Args { + param($TargetImage, $TargetCx, $RmiAddress) + + $arglist = @("`"$Env:OPT_GDB_PATH`"") + Add-Gdb-Init-Args -ArgList ([ref]$arglist) + Add-Gdb-Image-And-Args -ArgList ([ref]$arglist) -TargetImge $TargetImage -TargetArgs "" + $arglist+=("-ex", "`"echo Connecting to $TargetCx\n`"") + $arglist+=("-ex", "`"target $TargetCx`"") + Add-Gdb-Connect-And-Sync -ArgList ([ref]$arglist) -Address $RmiAddress + $arglist+=("-ex", "`"ghidra trace sync-synth-stopped`"") + Add-Gdb-Tail-Args -ArgList ([ref]$arglist) + + return $arglist +} + +function Compute-Gdb-PipInstall-Args { + $argvpart = $args -join ", " + $arglist = @("`"$Env:OPT_GDB_PATH`"") + $arglist+=("-ex", "`"set pagination off`"") + $arglist+=("-ex", "`"python import os, sys, runpy`"") + $arglist+=("-ex", "`"python sys.argv=['pip', 'install', '--force-reinstall', $argvpart]`"") + $arglist+=("-ex", "`"python os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'`"") + $arglist+=("-ex", "`"python runpy.run_module('pip', run_name='__main__')`"") + + return $arglist +} diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.sh b/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.sh new file mode 100644 index 0000000000..5324f295f0 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/support/gdbsetuputils.sh @@ -0,0 +1,125 @@ +## ### +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## +. ../../../Debugger-rmi-trace/data/support/setuputils.sh + +add-gdb-init-args() { + args+=(-q) + args+=(-ex "set pagination off") + args+=(-ex "set confirm off") + args+=(-ex "show version") + args+=(-ex "python import ghidragdb") + args+=(-ex "python if not 'ghidragdb' in locals(): exit(253)") + args+=(-ex "set architecture $OPT_ARCH") + args+=(-ex "set endian $OPT_ENDIAN") +} + +add-gdb-image-and-args() { + target_image=$1 + target_args=$2 + + if [ -n "$target_image" ]; then + args+=(-ex "file '$target_image'") + fi + if [ -n "$target_args" ]; then + args+=(-ex "set args $target_args") + fi +} + +add-gdb-inferior-tty() { + # Ghidra will leave TTY_TARGET empty when OPT_EXTRA_TTY is false. + # Gdb takes empty to mean the same terminal. + args+=(-ex "set inferior-tty $TTY_TARGET") +} + +add-gdb-connect-and-sync() { + address=$1 + + args+=(-ex "ghidra trace connect '$address'") + args+=(-ex "ghidra trace start") + args+=(-ex "ghidra trace sync-enable") +} + +add-gdb-start-if-image() { + target_image=$1 + + if [ -n "$target_image" ]; then + args+=(-ex "$OPT_START_CMD") + fi +} + +add-gdb-tail-args() { + args+=(-ex "set confirm on") + args+=(-ex "set pagination on") +} + +compute-gdb-usermode-args() { + target_image=$1 + rmi_address=$2 + shift + shift + + args+=("$OPT_GDB_PATH") + add-gdb-init-args + add-gdb-image-and-args "$target_image" "$@" + add-gdb-inferior-tty + add-gdb-connect-and-sync "$rmi_address" + add-gdb-start-if-image "$target_image" + add-gdb-tail-args +} + +compute-gdb-wine-args() { + target_image=$1 + rmi_address=$2 + shift + shift + + args+=("$OPT_GDB_PATH") + add-gdb-init-args + add-gdb-image-and-args "$OPT_WINE_PATH" "$target_image" "$@" + add-gdb-inferior-tty + gdb+=(-ex "starti") + gdb+=(-ex "ghidra wine run-to-image '$target_image'") + add-gdb-connect-and-sync "$rmi_address" + gdb+=(-ex "ghidra trace sync-synth-stopped") + add-gdb-tail-args +} + +compute-gdb-remote-args() { + target_image=$1 + target_cx=$2 + rmi_address=$3 + + args+=("$OPT_GDB_PATH") + add-gdb-init-args + add-gdb-image-and-args "$target_image" "" + args+=(-ex "echo Connecting to $target_cx\n") + args+=(-ex "target $target_cx") + add-gdb-connect-and-sync "$rmi_address" + args+=(-ex "ghidra trace sync-synth-stopped") + add-gdb-tail-args +} + +compute-gdb-pipinstall-args() { + local argvpart + printf -v argvpart ", %s" "$@" + pipargs=("$OPT_GDB_PATH") + pipargs+=(-q) + pipargs+=(-ex "set pagination off") + pipargs+=(-ex "python import os, sys, runpy") + pipargs+=(-ex "python sys.argv=['pip', 'install', '--force-reinstall'$argvpart]") + pipargs+=(-ex "python os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'") + pipargs+=(-ex "python runpy.run_module('pip', run_name='__main__')") +} diff --git a/Ghidra/Debug/Debugger-agent-lldb/certification.manifest b/Ghidra/Debug/Debugger-agent-lldb/certification.manifest index 48021f6ccd..9178e37035 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/certification.manifest +++ b/Ghidra/Debug/Debugger-agent-lldb/certification.manifest @@ -4,11 +4,12 @@ Module.manifest||GHIDRA||||END| README.md||GHIDRA||||END| build.gradle||GHIDRA||||END| -data/debugger-launchers/android-lldb.bat||GHIDRA||||END| -data/debugger-launchers/kernel-lldb.bat||GHIDRA||||END| -data/debugger-launchers/local-lldb.bat||GHIDRA||||END| +data/debugger-launchers/android-lldb.ps1||GHIDRA||||END| +data/debugger-launchers/kernel-lldb.ps1||GHIDRA||||END| +data/debugger-launchers/local-lldb.ps1||GHIDRA||||END| data/debugger-launchers/remote-lldb.ps1||GHIDRA||||END| -data/debugger-launchers/ssh-lldb.bat||GHIDRA||||END| +data/debugger-launchers/ssh-lldb.ps1||GHIDRA||||END| +data/support/lldbsetuputils.ps1||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/topics/lldb/lldb.html||GHIDRA||||END| src/main/py/LICENSE||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.bat b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.bat deleted file mode 100644 index b182203c3e..0000000000 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.bat +++ /dev/null @@ -1,95 +0,0 @@ -::@title android lldb -::@desc -::@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

-::@desc

-::@desc This will start lldb on the local system and then use it to connect to the remote system. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group remote -::@icon icon.debugger -::@help lldb#android -::@enum StartCmd:str "process launch" "process launch --stop-at-entry" -::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_HOST:str="localhost" "Host" "The hostname of the target" -::@env OPT_PORT:str="9999" "Port" "The host's listening port" -::@env OPT_ARCH:str="" "Architecture" "Target architecture override" -::@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." -::@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -:: NB: This works - a lot of things do not. Don't change unless you know what you're doing! -set OPT_TARGET_IMG="%OPT_TARGET_IMG%" -set OPT_TARGET_ARGS="%OPT_TARGET_ARGS%" - -IF %OPT_ARCH%=="" ( - IF "%OPT_TARGET_ARGS%"=="" ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "platform select remote-android" ^ - -o "platform connect connect://%OPT_HOST%:%OPT_PORT%" ^ - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" ^ - -o "%OPT_START_CMD%" - ) ELSE ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "platform select remote-android" ^ - -o "platform connect connect://%OPT_HOST%:%OPT_PORT%" ^ - -o "settings set target.default-arch %OPT_ARCH%" - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "settings set target.run-args %OPT_TARGET_ARGS%" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" ^ - -o "%OPT_START_CMD%" - ) -) ELSE ( - if %OPT_TARGET_ARGS=="" ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "platform select remote-android" ^ - -o "platform connect connect://%OPT_HOST%:%OPT_PORT%" ^ - -o "settings set target.default-arch %OPT_ARCH%" - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" ^ - -o "%OPT_START_CMD%" - ) ELSE ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "platform select remote-android" ^ - -o "platform connect connect://%OPT_HOST%:%OPT_PORT%" ^ - -o "settings set target.default-arch %OPT_ARCH%" - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "settings set target.run-args %OPT_TARGET_ARGS%" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" ^ - -o "%OPT_START_CMD%" - ) -) \ No newline at end of file diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.ps1 new file mode 100644 index 0000000000..4cb31d104b --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.ps1 @@ -0,0 +1,34 @@ +#@title lldb Android +#@image-opt arg:1 +#@desc +#@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

+#@desc

+#@desc This will start lldb on the local system and then use it to connect to the remote system. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group lldb +#@icon icon.debugger +#@help lldb#android +#@enum StartCmd:str "process launch" "process launch --stop-at-entry" +#@arg :file "Image" "The target binary executable image" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_HOST:str="localhost" "Host" "The hostname of the target" +#@env OPT_PORT:str="9999" "Port" "The host's listening port" +#@env OPT_ARCH:str="" "Architecture" "Target architecture override" +#@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." +#@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." + +. ..\support\lldbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb" +$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH" + +$arglist = Compute-Lldb-Platform-Args ` + -TargetImage $args[0] ` + -TargetType "remote-android" ` + -TargetUrl "connect://$Env:OPT_HOST`:$Env:OPT_PORT" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.sh index 47395cff2e..a0779c177f 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/android-lldb.sh @@ -14,16 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title android lldb +#@title lldb Android #@image-opt arg:1 #@desc -#@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

+#@desc

Launch with local lldb and connect to an Android target.

#@desc

#@desc This will start lldb on the local system and then use it to connect to the remote system. #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group lldb #@icon icon.debugger #@help lldb#android #@enum StartCmd:str "process launch" "process launch --stop-at-entry" @@ -35,48 +35,20 @@ #@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." #@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/lldbsetuputils.sh + +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb") +export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH target_image="$1" shift target_args="$@" -if [ -z "$target_args" ] -then - argspart= -else - argspart=-o "settings set target.run-args $target_args" -fi - -if [ -z "$OPT_ARCH" ] -then - archcmd= -else - archcmd=-o "settings set target.default-arch $OPT_ARCH" -fi - -"$OPT_LLDB_PATH" \ - -o "version" \ - -o "script import ghidralldb" \ - -o "platform select remote-android" \ - -o "platform connect connect://$OPT_HOST:$OPT_PORT" \ - $archcmd \ - -o "target create \"$target_image\"" \ - $argspart \ - -o "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -o "ghidra trace start" \ - -o "ghidra trace sync-enable" \ - -o "ghidra trace sync-synth-stopped" \ - -o "$OPT_START_CMD" +function launch-lldb() { + local -a args + compute-lldb-platform-args "$target_image" remote-android "connect://$OPT_HOST:$OPT_PORT" "$GHIDRA_TRACE_RMI_ADDR" "$@" + "${args[@]}" +} +launch-lldb diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.bat b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.bat deleted file mode 100644 index 6b2605e36c..0000000000 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.bat +++ /dev/null @@ -1,48 +0,0 @@ -::@title kernel lldb -::@desc -::@desc

Launch with local lldb and connect to a remote kernel

-::@desc

-::@desc This will start lldb on the local system and then use it to connect to the remote system. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group remote -::@icon icon.debugger -::@help lldb#macos_kernel -::@env OPT_HOST:str="localhost" "Host" "The hostname of the target" -::@env OPT_ARCH:str="" "Architecture" "Target architecture override" -::@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -IF "%OPT_ARCH%"=="" ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "kdp-remote %OPT_HOST%" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" -) ELSE ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "settings set target.default-arch %OPT_ARCH%" - -o "kdp-remote %OPT_HOST%" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "ghidra trace sync-synth-stopped" -) \ No newline at end of file diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.ps1 new file mode 100644 index 0000000000..faf22b61eb --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.ps1 @@ -0,0 +1,27 @@ +#@title lldb kernel (kdp) +#@desc +#@desc

Launch with local lldb and connect to a remote kernel

+#@desc

+#@desc This will start lldb on the local system and then use it to connect to the remote system. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group lldb +#@icon icon.debugger +#@help lldb#macos_kernel +#@env OPT_HOST:str="localhost" "Host" "The hostname of the target" +#@env OPT_ARCH:str="" "Architecture" "Target architecture override" +#@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." + +. ..\support\lldbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb" +$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH" + +$arglist = Compute-Lldb-Remote-Args ` + -TargetImage $args[0] ` + -TargetCx "kdp-remote $Env:OPT_HOST" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.sh index b07320a356..b92a45325c 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/kernel-lldb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title kernel lldb +#@title lldb kernel (kdp) #@desc #@desc

Launch with local lldb and connect to a remote kernel

#@desc

@@ -22,39 +22,23 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group lldb #@icon icon.debugger #@help lldb#macos_kernel #@env OPT_HOST:str="localhost" "Host" "The hostname of the target" #@env OPT_ARCH:str="" "Architecture" "Target architecture override" #@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/lldbsetuputils.sh -if [ -z "$OPT_ARCH" ] -then - archcmd= -else - archcmd=-o "settings set target.default-arch $OPT_ARCH" -fi +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb") +export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH -"$OPT_LLDB_PATH" \ - -o "version" \ - -o "script import ghidralldb" \ - $archcmd \ - -o "kdp-remote $OPT_HOST" \ - -o "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -o "ghidra trace start" \ - -o "ghidra trace sync-enable" \ - -o "ghidra trace sync-synth-stopped" +function launch-lldb() { + local -a args + compute-lldb-remote-args "" "kdp-remote $OPT_HOST" "$GHIDRA_TRACE_RMI_ADDR" + + "${args[@]}" +} +launch-lldb diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.bat b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.bat deleted file mode 100644 index 671b7141db..0000000000 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.bat +++ /dev/null @@ -1,64 +0,0 @@ -::@title lldb -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with lldb

-::@desc

-::@desc This will launch the target on the local machine using lldb. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group local -::@icon icon.debugger -::@help lldb#local -::@enum StartCmd:str "process launch" "process launch --stop-at-entry" -::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb. Omit the full path to resolve using the system PATH." -::@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." - -@echo off -set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\pypkg\src -set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\pypkg\src -IF EXIST %GHIDRA_HOME%\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -IF EXIST %GHIDRA_HOME%\ghidra\.git ( - set PYTHONPATH0=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src - set PYTHONPATH1=%GHIDRA_HOME%\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src -) -set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% - -:: NB: This works - a lot of things do not. Don't change unless you know what you're doing! -set OPT_TARGET_IMG="%OPT_TARGET_IMG%" -set OPT_TARGET_ARGS="%OPT_TARGET_ARGS%" - -IF %OPT_TARGET_IMG%=="" ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" -) ELSE ( - IF "%OPT_TARGET_ARGS%"=="" ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "%OPT_START_CMD%" - ) ELSE ( - "%OPT_LLDB_PATH%" ^ - -o "version" ^ - -o "script import ghidralldb" ^ - -o "target create "%OPT_TARGET_IMG%"" ^ - -o "settings set target.run-args %OPT_TARGET_ARGS%" ^ - -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ - -o "ghidra trace start" ^ - -o "ghidra trace sync-enable" ^ - -o "%OPT_START_CMD%" - ) -) \ No newline at end of file diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.ps1 new file mode 100644 index 0000000000..51ce6b9bd7 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.ps1 @@ -0,0 +1,30 @@ +#@title lldb +#@image-opt arg:1 +#@desc +#@desc

Launch with lldb

+#@desc

+#@desc This will launch the target on the local machine using lldb. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group lldb +#@icon icon.debugger +#@help lldb#local +#@enum StartCmd:str "process launch" "process launch --stop-at-entry" +#@arg :file "Image" "The target binary executable image" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb. Omit the full path to resolve using the system PATH." +#@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." + +. ..\support\lldbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb" +$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH" + +$arglist = Compute-Lldb-Usermode-Args ` + -TargetImage $args[0] ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" + +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] ` + -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.sh index 397e0deea9..75086e9a71 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/local-lldb.sh @@ -23,7 +23,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group local +#@menu-group lldb #@icon icon.debugger #@help lldb#local #@enum StartCmd:str "process launch" "process launch --stop-at-entry" @@ -34,55 +34,19 @@ #@env OPT_EXTRA_TTY:bool=false "Target TTY" "Provide a separate terminal emulator for the target." #@tty TTY_TARGET if env:OPT_EXTRA_TTY -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/lldbsetuputils.sh + +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb") +export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH target_image="$1" shift -target_args="$@" -if [ -z "$target_args" ] -then - argspart= -else - argspart=-o "settings set target.run-args $target_args" -fi +function launch-lldb() { + local -a args + compute-lldb-usermode-args "$target_image" "$GHIDRA_TRACE_RMI_ADDR" "$@" -if [ -z "$TARGET_TTY" ] -then - ttypart= -else - ttypart=-o "settings set target.output-path $TTY_TARGET" -o "settings set target.input-path $TTY_TARGET" -fi - -if [ -z "$target_image" ] -then - "$OPT_LLDB_PATH" \ - -o "version" \ - -o "script import ghidralldb" \ - $ttypart \ - -o "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -o "ghidra trace start" \ - -o "ghidra trace sync-enable" -else - "$OPT_LLDB_PATH" \ - -o "version" \ - -o "script import ghidralldb" \ - -o "target create \"$target_image\"" \ - $argspart \ - $ttypart \ - -o "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ - -o "ghidra trace start" \ - -o "ghidra trace sync-enable" \ - -o "$OPT_START_CMD" -fi + "${args[@]}" +} +launch-lldb diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.ps1 index a9bc9457dc..a4fd41666d 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.ps1 +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.ps1 @@ -1,4 +1,4 @@ -#@title remote lldb +#@title lldb remote (gdb) #@image-opt arg:1 #@desc #@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

@@ -7,7 +7,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group lldb #@icon icon.debugger #@help lldb#remote #@arg :file "Image" "The target binary executable image (a copy on the local system)" @@ -16,37 +16,15 @@ #@env OPT_ARCH:str="" "Architecture" "Target architecture override" #@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." -[IO.DirectoryInfo] $repo = "$Env:GHIDRA_HOME\.git" -[IO.DirectoryInfo] $repoParent = "$Env:GHIDRA_HOME\ghidra\.git" -if ($repo.Exists) { - $pypathLldb = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src" -} -elseif ($repoParent.Exists) { - $pypathLldb = "$Env:GHIDRA_HOME\ghidra\Ghidra\Debug\Debugger-agent-lldb\build\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\ghidra\Ghidra\Debug\Debugger-rmi-trace\build\pypkg\src" -} -else { - $pypathLldb = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-agent-lldb\pypkg\src" - $pypathTrace = "$Env:GHIDRA_HOME\Ghidra\Debug\Debugger-rmi-trace\pypkg\src" -} +. ..\support\lldbsetuputils.ps1 + +$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace" +$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb" $Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH" -$arglist = @() +$arglist = Compute-Lldb-Remote-Args ` + -TargetImage $args[0] ` + -TargetCx "gdb-remote $Env:OPT_HOST`:$Env:OPT_PORT" ` + -RmiAddress "$Env:GHIDRA_TRACE_RMI_ADDR" -$arglist+=("-o", "`"version`"") -$arglist+=("-o", "`"script import ghidralldb`"") -if ("$Env:OPT_ARCH" -ne "") { - $arglist+=("-o", "`"settings set target.default-arch $Env:OPT_ARCH`"") -} -if ("$($args[0])" -ne "") { - $image = $args[0] - $arglist+=("-o", "`"file '$image'`"") -} -$arglist+=("-o", "`"gdb-remote $Env:OPT_HOST`:$Env:OPT_PORT`"") -$arglist+=("-o", "`"ghidra trace connect '$Env:GHIDRA_TRACE_RMI_ADDR'`"") -$arglist+=("-o", "`"ghidra trace start`"") -$arglist+=("-o", "`"ghidra trace sync-enable`"") -$arglist+=("-o", "`"ghidra trace sync-synth-stopped`"") - -Start-Process -FilePath $Env:OPT_LLDB_PATH -ArgumentList $arglist -NoNewWindow -Wait +Start-Process -FilePath $arglist[0] -ArgumentList $arglist[1..$arglist.Count] -NoNewWindow -Wait diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh index 4f595b9817..8994d60684 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/remote-lldb.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -#@title remote lldb +#@title lldb remote (gdb) #@image-opt arg:1 #@desc #@desc

Launch with local lldb and connect to a stub (e.g., gdbserver)

@@ -23,7 +23,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group lldb #@icon icon.debugger #@help lldb#remote #@arg :file "Image" "The target binary executable image (a copy on the local system)" @@ -32,35 +32,18 @@ #@env OPT_ARCH:str="" "Architecture" "Target architecture override" #@env OPT_LLDB_PATH:file="lldb" "lldb command" "The path to lldb on the local system. Omit the full path to resolve using the system PATH." -if [ -d ${GHIDRA_HOME}/ghidra/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -elif [ -d ${GHIDRA_HOME}/.git ] -then - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/build/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH -else - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-lldb/pypkg/src:$PYTHONPATH - export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH -fi +. ../support/lldbsetuputils.sh -declare -a args +pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace") +pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb") +export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH -args+=(-o version) -args+=(-o "script import ghidralldb") -if [ -n "$OPT_ARCH" ] -then - args+=(-o "settings set target.default-arch $OPT_ARCH") -fi -if [ -n "$1" ] -then - args+=(-o "file '$1'") -fi -args+=(-o "gdb-remote $OPT_HOST:$OPT_PORT") -args+=(-o "ghidra trace connect '$GHIDRA_TRACE_RMI_ADDR'") -args+=(-o "ghidra trace start") -args+=(-o "ghidra trace sync-enable") -args+=(-o "ghidra trace sync-synth-stopped") +target_image="$1" -"$OPT_LLDB_PATH" "${args[@]}" +function launch-lldb() { + local -a args + compute-lldb-remote-args "$target_image" "gdb-remote $OPT_HOST:$OPT_PORT" "$GHIDRA_TRACE_RMI_ADDR" + + "${args[@]}" +} +launch-lldb diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.bat b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.bat deleted file mode 100644 index 3692ce39cc..0000000000 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.bat +++ /dev/null @@ -1,51 +0,0 @@ -::@timeout 60000 -::@title lldb via ssh -::@image-opt env:OPT_TARGET_IMG -::@desc -::@desc

Launch with lldb via ssh

-::@desc

-::@desc This will launch the target on a remote machine using lldb via ssh. -::@desc For setup instructions, press F1. -::@desc

-::@desc -::@menu-group remote -::@icon icon.debugger -::@help lldb#ssh -::@enum StartCmd:str "process launch" "process launch --stop-at-entry" -::@enum Endian:str auto big little -::@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image on the remote system" -::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" -::@env OPT_SSH_PATH:file!="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." -::@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" -::@env OPT_REMOTE_PORT:int=12345 "Remote Trace RMI Port" "A free port on the remote end to receive and forward the Trace RMI connection." -::@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." -::@env OPT_LLDB_PATH:str="lldb" "lldb command" "The path to lldb on the remote system. Omit the full path to resolve using the system PATH." -::@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." -::@env OPT_ARCH:str="x86_64" "Architecture" "Target architecture" - -@echo off - -IF "%OPT_TARGET_ARGS%" == "" ( - set cmd=TERM='%TERM%' '%OPT_LLDB_PATH%' ^ - -o 'version' ^ - -o 'script import ghidralldb' ^ - -o 'settings set target.default-arch %OPT_ARCH%' ^ - -o 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -o 'target create \"%OPT_TARGET_IMG%\"' ^ - -o 'ghidra trace start' ^ - -o 'ghidra trace sync-enable' ^ - -o '%OPT_START_CMD%' -) ELSE ( - set cmd=TERM='%TERM%' '%OPT_LLDB_PATH%' ^ - -o 'version' ^ - -o 'script import ghidralldb' ^ - -o 'settings set target.default-arch %OPT_ARCH%' ^ - -o 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -o 'target create \"%OPT_TARGET_IMG%\"' ^ - -o 'settings set target.run-args %OPT_TARGET_ARGS%' ^ - -o 'ghidra trace start' ^ - -o 'ghidra trace sync-enable' ^ - -o '%OPT_START_CMD%' -) - -"%OPT_SSH_PATH%" "-R%OPT_REMOTE_PORT%:%GHIDRA_TRACE_RMI_ADDR%" -t %OPT_EXTRA_SSH_ARGS% "%OPT_HOST%" "%cmd%" diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.ps1 new file mode 100644 index 0000000000..d260cfc65a --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.ps1 @@ -0,0 +1,69 @@ +#@timeout 60000 +#@title lldb via ssh +#@image-opt arg:1 +#@desc +#@desc

Launch with lldb via ssh

+#@desc

+#@desc This will launch the target on a remote machine using lldb via ssh. +#@desc For setup instructions, press F1. +#@desc

+#@desc +#@menu-group lldb +#@icon icon.debugger +#@help lldb#ssh +#@enum StartCmd:str "process launch" "process launch --stop-at-entry" +#@enum Endian:str auto big little +#@arg :str "Image" "The target binary executable image on the remote system" +#@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" +#@env OPT_SSH_PATH:file!="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." +#@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" +#@env OPT_REMOTE_PORT:int=12345 "Remote Trace RMI Port" "A free port on the remote end to receive and forward the Trace RMI connection." +#@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." +#@env OPT_LLDB_PATH:str="lldb" "lldb command" "The path to lldb on the remote system. Omit the full path to resolve using the system PATH." +#@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." +#@env OPT_ARCH:str="x86_64" "Architecture" "Target architecture" + +. ..\support\lldbsetuputils.ps1 + +$arglist = Compute-Lldb-Usermode-Args -TargetImage $args[0] -RmiAddress "localhost:$Env:OPT_REMOTE_PORT" +$sshargs = Compute-Ssh-Args $arglist True + +$sshproc = Start-Process -FilePath $sshargs[0] -ArgumentList $sshargs[1..$sshargs.Count] -NoNewWindow -Wait -PassThru + +$version = Get-Ghidra-Version +$answer = Check-Result-And-Prompt-Mitigation $sshproc @" +It appears ghidralldb is missing from the remote system. This can happen if you +forgot to install the required package. This can also happen if you installed +the packages to a different Python environment than is being used by the +remote's lldb. + +This script is about to offer automatic resolution. If you'd like to resolve +this manually, answer no to the next question and then see Ghidra's help by +pressing F1 in the dialog of launch parameters. + +WARNING: Answering yes to the next question will invoke pip to try to install +missing or incorrectly-versioned dependencies. It may attempt to find packages +from the PyPI mirror configured on the REMOTE system. If you have not configured +one, it will connect to the official one. + +WARNING: We invoke pip with the --break-system-packages flag, because some +debuggers that embed Python (gdb, lldb) may not support virtual environments, +and so the packages must be installed to your user environment. + +NOTE: This will copy Python wheels into the HOME directory of the user on the +remote system. You may be prompted to authenticate a few times while packages +are copied and installed. + +NOTE: Automatic resolution will cause this session to terminate. When it has +finished, try launching again. +"@ "Would you like to install 'ghidralldb==$version'?" + +if ($answer) { + Write-Host "Copying Wheels to $Env:OPT_HOST" + Mitigate-Scp-PyModules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-lldb" + + Write-Host "Installing Wheels into LLDB's embedded Python" + $arglist = Compute-Lldb-PipInstall-Args "'-f'" "os.environ['HOME']" "'ghidralldb==$version'" + $sshargs = Compute-Ssh-Args $arglist False + Start-Process -FilePath $sshargs[0] -ArgumentList $sshargs[1..$sshargs.Count] -NoNewWindow -Wait +} diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh old mode 100644 new mode 100755 index 8935da4c19..3fbaf2f5cf --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh @@ -24,7 +24,7 @@ #@desc For setup instructions, press F1. #@desc

#@desc -#@menu-group remote +#@menu-group lldb #@icon icon.debugger #@help lldb#ssh #@enum StartCmd:str "process launch" "process launch --stop-at-entry" @@ -39,30 +39,61 @@ #@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target." #@env OPT_ARCH:str="x86_64" "Architecture" "Target architecture" +. ../support/lldbsetuputils.sh + target_image="$1" shift -target_args="$@" -if [ -z "$target_image" ] -then - "$OPT_SSH_PATH" "-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR" -t $OPT_EXTRA_SSH_ARGS "$OPT_HOST" "TERM='$TERM' '$OPT_LLDB_PATH' \ - -o 'version' ^ - -o 'script import ghidralldb' ^ - -o 'settings set target.default-arch %OPT_ARCH%' ^ - -o 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -o 'target create \"%OPT_TARGET_IMG%\"' ^ - -o 'ghidra trace start' ^ - -o 'ghidra trace sync-enable' ^ - -o '%OPT_START_CMD%' -else - "$OPT_SSH_PATH" "-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR" -t $OPT_EXTRA_SSH_ARGS "$OPT_HOST" "TERM='$TERM' '$OPT_LLDB_PATH' \ - -o 'version' ^ - -o 'script import ghidralldb' ^ - -o 'settings set target.default-arch %OPT_ARCH%' ^ - -o 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ - -o 'target create \"%OPT_TARGET_IMG%\"' ^ - -o 'settings set target.run-args %OPT_TARGET_ARGS%' ^ - -o 'ghidra trace start' ^ - -o 'ghidra trace sync-enable' ^ - -o '%OPT_START_CMD%' +function launch-lldb-ssh() { + local -a args + compute-lldb-usermode-args "$target_image" "localhost:$OPT_REMOTE_PORT" "$@" + local -a sshargs + compute-ssh-args true "${args[@]}" + + "${sshargs[@]}" +} +version=$(get-ghidra-version) + +function do-installation() { + local -a pipargs + compute-lldb-pipinstall-args "'-f'" "os.environ['HOME']" "'ghidralldb==$version'" + local -a sshargs + compute-ssh-args false "${pipargs[@]}" + + "${sshargs[@]}" +} + +launch-lldb-ssh +if check-result-and-prompt-mitigation $? " +It appears ghidralldb is missing from the remote system. This can happen if you +forgot to install the required package. This can also happen if you installed +the packages to a different Python environment than is being used by the +remote's lldb. + +This script is about to offer automatic resolution. If you'd like to resolve +this manually, answer no to the next question and then see Ghidra's help by +pressing F1 in the dialog of launch parameters. + +WARNING: Answering yes to the next question will invoke pip to try to install +missing or incorrectly-versioned dependencies. It may attempt to find packages +from the PyPI mirror configured on the REMOTE system. If you have not configured +one, it will connect to the official one. + +WARNING: We invoke pip with the --break-system-packages flag, because some +debuggers that embed Python (gdb, lldb) may not support virtual environments, +and so the packages must be installed to your user environment. + +NOTE: This will copy Python wheels into the HOME directory of the user on the +remote system. You may be prompted to authenticate a few times while packages +are copied and installed. + +NOTE: Automatic resolution may cause this session to terminate. When it has +finished, try launching again. +" "Would you like to install 'ghidralldb==$version'?"; then + + echo "Copying Wheels to $OPT_HOST" + mitigate-scp-pymodules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-lldb" + + echo "Installing Wheels into LLDB's embedded Python" + do-installation fi diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.ps1 b/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.ps1 new file mode 100644 index 0000000000..f83e8d42e4 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.ps1 @@ -0,0 +1,106 @@ + +. ..\..\..\Debugger-rmi-trace\data\support\setuputils.ps1 + +function Add-Lldb-Init-Args { + param([ref]$ArgList) + + $ArgList.Value+=("-o", "`"version`"") + $ArgList.Value+=("-o", "`"script import os, ghidralldb`"") + $ArgList.Value+=("-o", "`"script if not 'ghidralldb' in locals(): os._exit(253)`"") + if ("$Env:OPT_ARCH" -ne "") { + $ArgList.Value+=("-o", "`"settings set target.default-arch $Env:OPT_ARCH`"") + } +} + +function Add-Lldb-Image-And-Args { + param([ref]$ArgList, $TargetImage, $TargetArgs) + + if ("$TargetImage" -ne "") { + if ("$Env:OPT_ARCH" -ne "") { + $ArgList.Value+=("-o", "`"target create --arch '$Env:OPT_ARCH' '$TargetImage'`"") + } + else { + $ArgList.Value+=("-o", "`"target create '$TargetImage'`"") + } + } + if ("$TargetArgs" -ne "") { + $tgtargs = $TargetArgs -replace "`"", "\`"" + # Escaping parentheses in the arguments is no longer necessary in powershell vs cmd + $ArgList.Value+=("-o", "`"settings set target.run-args $tgtargs`"") + } +} + +function Add-Lldb-Connect-And-Sync { + param([ref]$ArgList, $Address) + + $ArgList.Value+=("-o", "`"ghidra trace connect '$Address'`"") + $ArgList.Value+=("-o", "`"ghidra trace start`"") + $ArgList.Value+=("-o", "`"ghidra trace sync-enable`"") +} + +function Add-Lldb-Start-If-Image { + param([ref]$ArgList, $TargetImage) + + if ("$TargetImage" -ne "") { + $ArgList.Value+=("-o", "`"$Env:OPT_START_CMD`"") + } +} + +function Add-Lldb-Tail-Args { + param([ref]$ArgList) + # NOP +} + +function Compute-Lldb-Usermode-Args { + param($TargetImage, $RmiAddress) + + $arglist = @("`"$Env:OPT_LLDB_PATH`"") + Add-Lldb-Init-Args -ArgList ([ref]$arglist) + Add-Lldb-Image-And-Args -ArgList ([ref]$arglist) -TargetImage $TargetImage -TargetArgs $Env:OPT_TARGET_ARGS + Add-Lldb-Connect-And-Sync -ArgList ([ref]$arglist) -Address $RmiAddress + Add-Lldb-Start-If-Image -ArgList ([ref]$arglist) -TargetImage $TargetImage + Add-Lldb-Tail-Args -ArgList ([ref]$arglist) + + return $arglist +} + +function Compute-Lldb-Platform-Args { + param($TargetImage, $TargetType, $TargetUrl, $RmiAddress) + + $argslist = @("`"$Env:OPT_LLDB_PATH`"") + Add-Lldb-Init-Args -ArgList ([ref]$arglist) + $argslist+=("-o", "`"platform select '$TargetType'`"") + $argslist+=("-o", "`"platform connect '$TargetUrl'`"") + Add-Lldb-Image-And-Args -ArgList ([ref]$arglistt) -TargetImage $TargetImage -TargetArgs $Env:OPT_TARGET_ARGS + Add-Lldb-Connect-And-Sync -ArgList ([ref]$arglist) -Address $RmiAddress + Add-Lldb-Start-If-Image -ArgList ([ref]$arglist) -TargetImage $TargetImage + Add-Lldb-Tail-Args -ArgList ([ref]$arglist) + + return $arglist +} + +function Compute-Lldb-Remote-Args { + param($TargetImage, $TargetCx, $RmiAddress) + + $arglist = @("`"$Env:OPT_LLDB_PATH`"") + Add-Lldb-Init-Args -ArgList ([ref]$arglist) + Add-Lldb-Image-And-Args -ArgList ([ref]$arglist) -TargetImge $TargetImage -TargetArgs "" + $arglist+=("-o", "`"$TargetCx`"") + Add-Lldb-Connect-And-Sync -ArgList ([ref]$arglist) -Address $RmiAddress + $arglist+=("-o", "`"ghidra trace sync-synth-stopped`"") + Add-Lldb-Tail-Args -ArgList ([ref]$arglist) + + return $arglist +} + +function Compute-Lldb-PipInstall-Args { + $argvpart = $args -join ", " + $arglist = @("`"$Env:OPT_LLDB_PATH`"") + $arglist+=("-o", "`"script import os, sys, runpy`"") + $arglist+=("-o", "`"script sys.argv=['pip', 'install', '--force-reinstall', $argvpart]`"") + $arglist+=("-o", "`"script os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'`"") + $arglist+=("-o", "`"script runpy.run_module('pip', run_name='__main__')`"") + $arglist+=("-o", "`"quit`"") + + return $arglist +} diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.sh b/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.sh new file mode 100644 index 0000000000..32135faf2e --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-lldb/data/support/lldbsetuputils.sh @@ -0,0 +1,129 @@ +## ### +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## +. ../../../Debugger-rmi-trace/data/support/setuputils.sh + +add-lldb-init-args() { + args+=(-o "version") + args+=(-o "script import os, ghidralldb") + args+=(-o "script if not 'ghidralldb' in locals(): os._exit(253)") + + if [ -n "$OPT_ARCH" ]; then + args+=(-o "settings set target.default-arch $OPT_ARCH") + fi +} + +add-lldb-image-and-args() { + target_image=$1 + target_args=$2 + + if [ -n "$target_image" ]; then + if [ -n "$OPT_ARCH" ]; then + args+=(-o "target create --arch '$OPT_ARCH' '$target_image'") + else + args+=(-o "target create '$target_image'") + fi + fi + if [ -n "$target_args" ]; then + args+=(-o "settings set target.run-args $target_args") + fi +} + +add-lldb-io-tty() { + if [ -n "$TTY_TARGET" ]; then + args+=(-o "settings set target.output-path '$TTY_TARGET'") + args+=(-o "settings set target.input-path '$TTY_TARGET'") + fi +} + +add-lldb-connect-and-sync() { + address=$1 + + args+=(-o "ghidra trace connect '$address'") + args+=(-o "ghidra trace start") + args+=(-o "ghidra trace sync-enable") +} + +add-lldb-start-if-image() { + target_image=$1 + + if [ -n "$target_image" ]; then + args+=(-o "$OPT_START_CMD") + fi +} + +add-lldb-tail-args() { + true +} + +compute-lldb-usermode-args() { + target_image=$1 + rmi_address=$2 + shift + shift + + args+=("$OPT_LLDB_PATH") + add-lldb-init-args + add-lldb-image-and-args "$target_image" "$@" + add-lldb-io-tty + add-lldb-connect-and-sync "$rmi_address" + add-lldb-start-if-image "$target_image" + add-lldb-tail-args +} + +compute-lldb-platform-args() { + target_image=$1 + target_type=$2 + target_url=$3 + rmi_address=$4 + shift + shift + shift + shift + + args+=("$OPT_LLDB_PATH") + add-lldb-init-args + args+=(-o "platform select '$target_type'") + args+=(-o "platform connect '$target_url'") + add-lldb-image-and-args "$target_image" "$@" + add-lldb-connect-and-sync "$rmi_address" + add-lldb-start-if-image "$target_image" + add-lldb-tail-args +} + +compute-lldb-remote-args() { + target_image=$1 + target_cx=$2 + rmi_address=$3 + + args+=("$OPT_LLDB_PATH") + add-lldb-init-args + add-lldb-image-and-args "$target_image" "" + args+=(-o "$target_cx") + add-lldb-connect-and-sync "$rmi_address" + args+=(-o "ghidra trace sync-synth-stopped") + add-lldb-tail-args +} + +compute-lldb-pipinstall-args() { + local argvpart + printf -v argvpart ", %s" "$@" + pipargs=("$OPT_LLDB_PATH") + pipargs+=(-o "script import os, sys, runpy") + pipargs+=(-o "script sys.argv=['pip', 'install', '--force-reinstall'$argvpart]") + pipargs+=(-o "script os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'") + pipargs+=(-o "script runpy.run_module('pip', run_name='__main__')") + pipargs+=(-o "quit") +} diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/MANIFEST.in b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/MANIFEST.in index bfb9577bc6..623e3cf47a 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/MANIFEST.in +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/MANIFEST.in @@ -1 +1 @@ -include src/ghidragdb/schema.xml \ No newline at end of file +include src/ghidralldb/schema.xml \ No newline at end of file diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerAutoMappingService.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerAutoMappingService.java index 112f00b3a5..2ed831423b 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerAutoMappingService.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerAutoMappingService.java @@ -24,6 +24,13 @@ import ghidra.trace.model.Trace; */ @ServiceInfo(defaultProviderName = "ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesPlugin") public interface DebuggerAutoMappingService { + /** + * Set the current auto-map specification in the Modules provider + * + * @param spec the new setting + */ + void setAutoMapSpec(AutoMapSpec spec); + /** * Get the auto-map setting currently active in the Modules provider * diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/control/ControlMode.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/control/ControlMode.java index edc7e0cff9..cf4e4d26f7 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/control/ControlMode.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/control/ControlMode.java @@ -398,20 +398,18 @@ public enum ControlMode { return coordinates; } - ScheduleForm form = - target.getSupportedTimeForm(coordinates.getObject(), coordinates.getSnap()); + ScheduleForm form = coordinates.getObject() == null ? null + : target.getSupportedTimeForm(coordinates.getObject(), coordinates.getSnap()); if (form == null) { if (coordinates.getTime().isSnapOnly() && coordinates.getSnap() == target.getSnap()) { return coordinates; } - else { - tool.setStatusInfo(""" - Cannot navigate time in %s mode. Switch to Trace or Emulate mode first.""" - .formatted(name), - true); - return null; - } + tool.setStatusInfo(""" + Cannot navigate time in %s mode. Switch to Trace or Emulate mode first.""" + .formatted(name), + true); + return null; } TraceSchedule norm = form.validate(coordinates.getTrace(), coordinates.getTime()); if (norm != null) { diff --git a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/attach-java.jsh b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/attach-java.jsh index 0f54fee825..7c23506bc8 100755 --- a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/attach-java.jsh +++ b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/attach-java.jsh @@ -7,7 +7,7 @@ //@desc For setup instructions, press F1. //@desc

//@desc -//@menu-group attach +//@menu-group java //@icon icon.debugger //@help jpda#attach_port //@enum Arch:str JVM Dalvik diff --git a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/bypid-java.jsh b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/bypid-java.jsh index c7165ecc50..89cdcfe03d 100755 --- a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/bypid-java.jsh +++ b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/bypid-java.jsh @@ -7,7 +7,7 @@ //@desc For setup instructions, press F1. //@desc

//@desc -//@menu-group attach +//@menu-group java //@icon icon.debugger //@help jpda#attach_pid //@enum Arch:str JVM Dalvik diff --git a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh index 551c133895..cb6c6701ef 100755 --- a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh +++ b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh @@ -8,7 +8,7 @@ //@desc For setup instructions, press F1. //@desc

//@desc -//@menu-group local +//@menu-group java //@icon icon.debugger //@help jpda#local //@env OPT_TARGET_CLASS:file="" "Image" "The Main Class to launch (defaults to current program)." diff --git a/Ghidra/Debug/Debugger-rmi-trace/certification.manifest b/Ghidra/Debug/Debugger-rmi-trace/certification.manifest index 596d5a3829..3d590fe366 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/certification.manifest +++ b/Ghidra/Debug/Debugger-rmi-trace/certification.manifest @@ -5,6 +5,7 @@ DEVNOTES.txt||GHIDRA||||END| Module.manifest||GHIDRA||||END| README.md||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/support/setuputils.ps1||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/topics/TraceRmiConnectionManagerPlugin/TraceRmiConnectionManagerPlugin.html||GHIDRA||||END| src/main/help/help/topics/TraceRmiConnectionManagerPlugin/images/ConnectDialog.png||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger-rmi-trace/data/support/gmodutils.py b/Ghidra/Debug/Debugger-rmi-trace/data/support/gmodutils.py new file mode 100644 index 0000000000..ba7443af10 --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/data/support/gmodutils.py @@ -0,0 +1,42 @@ +## ### +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## +""" +This file holds utilities required by Python-based launch scripts. At +the moment, that includes only the launchers on Windows, since they're +just .bat files that invoke the .py file interactively. They require +this utility to set up the PYTHONPATH before importing the actual +connector's Python code. + +This file MUST remain in a predictable location relative to the +working directory or module directory of the scripts needing it, so +that minimal logic is required to get it loaded. + +This file CANNOT be assumed to be available on a remote target. For +that, consider ghidratrace.setuputils. +""" + +def ghidra_module_pypath(name: str) -> str: + installed = f'{home}/Ghidra/{name}/pypkg/src' + if os.path.isdir(installed): + return installed + dev1 = f'{home}/Ghidra/{name}/build/pypkg/src' + if os.path.isdir(dev1): + return dev1 + dev2 = f'{home}/ghidra/Ghidra/{name}/build/pypkg/src' + if os.path.isdir(dev2): + return dev2 + raise Exception( + f"Cannot find Python source for {name}. Try gradle assemblePyPackage?") diff --git a/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.ps1 b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.ps1 new file mode 100644 index 0000000000..6046a06905 --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.ps1 @@ -0,0 +1,97 @@ +function Find-App-Properties { + [IO.FileInfo] $simple = "$Env:GHIDRA_HOME\Ghidra\applications.properties" + if ($simple.Exists) { + return $simple + } + [IO.FileInfo] $dev2 = "$Env:GHIDRA_HOME\ghidra\Ghidra\application.properties" + if ($dev2.Exists) { + return $dev2 + } + throw "Cannot find application.properties" +} + +function Get-Ghidra-Version { + $props = Find-App-Properties + $m = Get-Content $props | Select-String -Pattern "application\.version=(.*)" + return $m.Matches.Groups[1].Value +} + +function Ghidra-Module-PyPath { + [IO.DirectoryInfo] $installed = "$Env:GHIDRA_HOME\Ghidra\$($args[0])\pypkg\src" + if ($installed.Exists) { + return "$installed" + } + [IO.DirectoryInfo] $dev1 = "$Env:GHIDRA_HOME\Ghidra\$($args[0])\build\pypkg\src" + if ($dev1.Exists) { + return "$dev1" + } + [IO.DirectoryInfo] $dev2 = "$Env:GHIDRA_HOME\ghidra\Ghidra\$($args[0])\build\pypkg\src" + if ($dev2.Exists) { + return "$dev2" + } + throw "Cannot find Python source for $($args[0]). Try gradle assemblePyPackage?" +} + +function Ghidra-Module-PyDist { + [IO.DirectoryInfo] $installed = "$Env:GHIDRA_HOME\Ghidra\$($args[0])\pypkg\dist" + if ($installed.Exists) { + return "$installed" + } + [IO.DirectoryInfo] $dev1 = "$Env:GHIDRA_HOME\Ghidra\$($args[0])\build\pypkg\dist" + if ($dev1.Exists) { + return "$dev1" + } + [IO.DirectoryInfo] $dev2 = "$Env:GHIDRA_HOME\ghidra\Ghidra\$($args[0])\build\pypkg\dist" + if ($dev2.Exists) { + return "$dev2" + } + throw "Cannot find Python package for $($args[0]). Try gradle buildPyPackage?" +} + +function Compute-Ssh-Args { + $arglist = $args[0] + $forward = $args[1] + $cmdline = $arglist -join " " -replace "`"", "\`"" + + $sshargs = @("`"$Env:OPT_SSH_PATH`"") + $sshargs+=("-t") + if ($forward) { + $sshargs+=("-R$Env:OPT_REMOTE_PORT`:$Env:GHIDRA_TRACE_RMI_ADDR") + } + if ("$Env:OPT_EXTRA_SSH_ARGS" -ne "") { + $sshargs+=("$Env:OPT_EXTRA_SSH_ARGS") + } + $sshargs+=("$Env:OPT_HOST", "TERM='$Env:TERM' $cmdline") + + return $sshargs +} + +function Check-Result-And-Prompt-Mitigation { + $proc = $args[0] + $msg = $args[1] + $prompt = $args[2] + if ($proc.ExitCode -eq 253) { + Write-Host @" +-------------------------------------------------------------------------------- +!!! INCORRECT OR INCOMPLETE SETUP !!! +-------------------------------------------------------------------------------- + +"@ + Write-Host $msg + Write-Host "" + Write-Host "Select KEEP if you're seeing this in an error dialog." + Write-Host -NoNewline "$prompt [Y/n] " + $answer = Read-Host + return (("$answer" -eq "y") -or ("$answer" -eq "Y") -or ("$answer" -eq "")) + } +} + +function Mitigate-Scp-PyModules { + $scpargs = $args | ForEach-Object { + $dist = Ghidra-Module-PyDist $_ + return "$dist\*" + } + $scpargs+=("$Env:OPT_HOST`:~/") + Start-Process -FilePath "scp" -ArgumentList $scpargs -NoNewWindow -Wait +} + diff --git a/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh new file mode 100644 index 0000000000..991c06505d --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh @@ -0,0 +1,135 @@ +## ### +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## +find-app-properties() { + local simple="$GHIDRA_HOME/Ghidra/application.properties" + if [ -f "$simple" ]; then + echo $simple + return 0 + fi + local dev2="$GHIDRA_HOME/ghidra/Ghidra/application.properties" + if [ -f "$dev2" ]; then + echo $dev2 + return 0 + fi + echo >&2 "Cannot find application.properties" + return 1 +} + +get-ghidra-version() { + local app_ver_re='application\.version=(.*)' + local props=$(find-app-properties) + local version=$(cat "$props" | while read line; do + if [[ $line =~ $app_ver_re ]]; then + echo "${BASH_REMATCH[1]}" + fi + done) + if [ -n "$version" ]; then + echo "$version" + return 0 + fi + echo >&2 "Cannot determine Ghidra version" + return 1 +} + +ghidra-module-pypath() { + installed="$GHIDRA_HOME/Ghidra/$1/pypkg/src" + if [ -d "$instaled" ]; then + echo $installed + return 0 + fi + dev1="$GHIDRA_HOME/Ghidra/$1/build/pypkg/src" + if [ -d "$dev1" ]; then + echo $dev1 + return 0 + fi + dev2="$GHIDRA_HOME/ghidra/Ghidra/$1/build/pypkg/src" + if [ -d "$dev2" ]; then + echo $dev2 + return 0 + fi + echo >&2 "Cannot find Python source for $1. Try gradle assemblePyPackage?" + return 1 +} + +ghidra-module-pydist() { + installed="$GHIDRA_HOME/Ghidra/$1/pypkg/dist" + if [ -d "$instaled" ]; then + echo $installed + return 0 + fi + dev1="$GHIDRA_HOME/Ghidra/$1/build/pypkg/dist" + if [ -d "$dev1" ]; then + echo $dev1 + return 0 + fi + dev2="$GHIDRA_HOME/ghidra/Ghidra/$1/build/pypkg/dist" + if [ -d "$dev2" ]; then + echo $dev2 + return 0 + fi + echo >&2 "Cannot find Python package for $1. Try gradle buildPyPackage?" + return 1 +} + +compute-ssh-args() { + forward=$1 + shift + local qargs + printf -v qargs '%q ' "$@" + + sshargs+=("$OPT_SSH_PATH") + sshargs+=(-t) + if [ "$forward" == "true" ]; then + sshargs+=("-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR") + fi + if [ -n "$OPT_EXTRA_SSH_ARGS" ]; then + sshargs+=($OPT_EXTRA_SSH_ARGS) + fi + sshargs+=("$OPT_HOST") + sshargs+=("TERM='$TERM' $qargs") +} + +check-result-and-prompt-mitigation() { + exitcode=$1 + msg=$2 + prompt=$3 + + if [ "$exitcode" -eq "253" ]; then + cat << EOF +-------------------------------------------------------------------------------- +!!! INCORRECT OR INCOMPLETE SETUP !!! +-------------------------------------------------------------------------------- + +EOF + echo "$msg" + echo "" + echo "Select KEEP if you're seeing this in an error dialog." + echo -n "$prompt [Y/n] " + read answer + [ "$answer" == "y" ] || [ "$answer" == "Y" ] || [ "$answer" == "" ] + return $? + fi + return 1 +} + +mitigate-scp-pymodules() { + local -a scpargs + for mod in "$@"; do + dist=$(ghidra-module-pydist "$mod") + scpargs+=("$dist"/*) + done + scp "${scpargs[@]}" "$OPT_HOST:~/" +} diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java index 52522aa5e9..98107e78b6 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java @@ -538,7 +538,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer Map sessions, Map> args, SocketAddress address) throws Exception; - static class NoStaticMappingException extends Exception { + public static class NoStaticMappingException extends Exception { public NoStaticMappingException(String message) { super(message); } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/LaunchAction.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/LaunchAction.java index 4db42408e7..5a0a4af2bc 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/LaunchAction.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/LaunchAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -91,7 +91,7 @@ public class LaunchAction extends MultiActionDockingAction { .popupMenuIcon(offer.getIcon()) .helpLocation(offer.getHelpLocation()) .enabledWhen(ctx -> true) - .onAction(ctx -> plugin.relaunch(offer)) + .onAction(ctx -> plugin.relaunch(ctx, offer)) .build()); } return actions; @@ -148,7 +148,7 @@ public class LaunchAction extends MultiActionDockingAction { Swing.runLater(() -> button.showPopup()); return; } - plugin.relaunch(offer); + plugin.relaunch(context, offer); } @Override diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/PowerShellScriptTraceRmiLaunchOffer.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/PowerShellScriptTraceRmiLaunchOffer.java index f6a6863485..ba25a11d37 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/PowerShellScriptTraceRmiLaunchOffer.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/PowerShellScriptTraceRmiLaunchOffer.java @@ -78,6 +78,6 @@ public class PowerShellScriptTraceRmiLaunchOffer extends AbstractScriptTraceRmiL protected void prepareSubprocess(List commandLine, Map env, Map> args, SocketAddress address) { super.prepareSubprocess(commandLine, env, args, address); - commandLine.add(0, "powershell"); + commandLine.addAll(0, List.of("powershell", "-File")); } } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/ScriptAttributesParser.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/ScriptAttributesParser.java index 45bcf89f45..d449a2d1c9 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/ScriptAttributesParser.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/ScriptAttributesParser.java @@ -342,7 +342,8 @@ public abstract class ScriptAttributesParser { public record ScriptAttributes(String title, String description, List menuPath, String menuGroup, String menuOrder, Icon icon, HelpLocation helpLocation, Map> parameters, Map extraTtys, - int timeoutMillis, LaunchParameter imageOpt) {} + int timeoutMillis, LaunchParameter imageOpt) { + } /** * Convert an arguments map into a command line and environment variables diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePlugin.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePlugin.java index 4ad0f60145..20d49cc9c4 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePlugin.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/TraceRmiLauncherServicePlugin.java @@ -15,6 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.tracermi.launcher; +import java.awt.event.ActionEvent; import java.io.File; import java.io.IOException; import java.util.*; @@ -25,6 +26,7 @@ import org.jdom.Element; import org.jdom.JDOMException; import db.Transaction; +import docking.ActionContext; import docking.action.DockingActionIf; import docking.action.builder.ActionBuilder; import ghidra.app.events.ProgramActivatedPluginEvent; @@ -348,6 +350,16 @@ public class TraceRmiLauncherServicePlugin extends Plugin executeTask(new ReLaunchTask(offer)); } + protected void relaunch(ActionContext ctx, TraceRmiLaunchOffer offer) { + int mods = ctx == null ? 0 : ctx.getEventClickModifiers(); + if ((mods & ActionEvent.SHIFT_MASK) != 0) { + configureAndLaunch(offer); + } + else { + relaunch(offer); + } + } + protected void configureAndLaunch(TraceRmiLaunchOffer offer) { executeTask(new ConfigureAndLaunchTask(offer)); } @@ -478,7 +490,8 @@ public class TraceRmiLauncherServicePlugin extends Plugin toolLaunchConfigs.putSaveState(name, state); } - protected record ConfigLast(String configName, long last, Program program) {} + protected record ConfigLast(String configName, long last, Program program) { + } protected ConfigLast checkSavedConfig(Program program, ProgramUserData userData, String propName) { diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/AbstractTraceRmiConnection.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/AbstractTraceRmiConnection.java index 6bdd2d1429..e863e29614 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/AbstractTraceRmiConnection.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/AbstractTraceRmiConnection.java @@ -64,13 +64,16 @@ public abstract class AbstractTraceRmiConnection implements TraceRmiConnection { if (!traceManager.getOpenTraces().contains(trace)) { traceManager.openTrace(trace); traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL); + return; } - else { - Trace currentTrace = traceManager.getCurrentTrace(); - if (currentTrace == null || ownsTrace(currentTrace)) { - traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL); - } + Trace currentTrace = traceManager.getCurrentTrace(); + if (currentTrace == null || ownsTrace(currentTrace)) { + traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL); + return; } + // LATER: See if all this ownership checking is really necessary. + // For now, just always activate anyway + traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL); }); } } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/pyproject.toml b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/pyproject.toml index a7d8b74e66..d29c8e2bdb 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/pyproject.toml +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ "Operating System :: OS Independent", ] dependencies = [ - "protobuf >= 3, < 4", + "protobuf >= 3.20.0", ] [project.urls] diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/__init__.py b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/__init__.py index 8c2a3298a5..c8b109d9f3 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/__init__.py +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/__init__.py @@ -1,15 +1,15 @@ ## ### -# IP: GHIDRA -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py index 90787214d7..b5941b0243 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py @@ -13,7 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. ## -from typing import get_args, get_origin + +try: + from . import trace_rmi_pb2 as bufs +except Exception as e: + from .setuputils import prompt_and_mitigate_dependencies + prompt_and_mitigate_dependencies("Debug/Debugger-rmi-trace") + from collections import deque from concurrent.futures import Executor, Future from contextlib import contextmanager @@ -26,12 +32,12 @@ import traceback from typing import (Annotated, Any, Callable, Collection, Dict, Generator, Generic, Iterable, List, MutableSequence, Optional, Sequence, Tuple, TypeVar, Union) +from typing import get_args, get_origin from google.protobuf.internal.containers import ( RepeatedCompositeFieldContainer as RCFC) from . import sch -from . import trace_rmi_pb2 as bufs from .util import send_delimited, recv_delimited @@ -188,7 +194,6 @@ class TraceObject: else: return '' - def insert(self, span: Optional[Lifespan] = None, resolution: str = 'adjust') -> Union[ Lifespan, RemoteResult[Any, Lifespan]]: @@ -654,7 +659,7 @@ class MethodRegistry(object): return '' @classmethod - def _make_param(cls, s:inspect.Signature, p: inspect.Parameter) -> RemoteParameter: + def _make_param(cls, s: inspect.Signature, p: inspect.Parameter) -> RemoteParameter: schema = cls._to_schema(s, p.annotation) required = p.default is p.empty return RemoteParameter( diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/setuputils.py b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/setuputils.py new file mode 100644 index 0000000000..63e268dd7c --- /dev/null +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/setuputils.py @@ -0,0 +1,124 @@ +## ### +# IP: GHIDRA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## +""" +This file holds utilities required by Python-based connectors. At the +moment, that includes all connectors except the ones targeting Java +applications. While uncommon, it is possible that dependencies turn up +missing on a remote target, and so the gmodutils.py file will not be +present. However, by the time such dependencies turn up missing, +whether remote or local, the PYTHONPATH should already include this +module, and so we place the setup logic here. +""" +import os +from typing import List, Sequence + + +home = os.getenv('GHIDRA_HOME') + + +def ghidra_module_src(name: str) -> str: + installed = f'{home}/Ghidra/{name}/pypkg' + if os.path.isdir(installed): + return installed + dev1 = f'{home}/Ghidra/{name}/src/main/py' + if os.path.isdir(dev1): + return dev1 + dev2 = f'{home}/ghidra/Ghidra/{name}/src/main/py' + if os.path.isdir(dev2): + return dev2 + raise Exception(f""" +Cannot find Python source for {name}. +If this is a remote system, we shouldn't even be here. Chances are, +the Python dependencies required by ghidra on the remote system were +removed or replaced with incompatible versions. If this is a local +system, your installation or development repo may be corrupt. +""") + + +def get_module_dependencies(name: str) -> List[str]: + src = ghidra_module_src(name) + # Can't rely on tomllib until Python 3.11 is minimum requirement. + # And, I'm in a place where I presume deps are missing, so do this garbage + # of a parse job. + with open(f"{src}/pyproject.toml") as project: + seen_deps = False + result: List[str] = [] + for l in project.readlines(): + l = l.strip() + if l == "dependencies = [": + seen_deps = True + elif seen_deps and l == ']': + return [r for r in result if not 'ghidra' in r] + elif seen_deps: + if l.endswith(','): # Last one may not have , + l = l[:-1].strip() + result.append(l[1:-1]) # Remove 's or "s + raise Exception("Could not parse pyproject.toml") + + +def prompt_mitigation(msg: str, prompt: str) -> bool: + print(""" +-------------------------------------------------------------------------------- +!!! INCORRECT OR INCOMPLETE SETUP !!! +-------------------------------------------------------------------------------- +""") + print(msg) + print("") + print("Select KEEP if you're seeing this in an error dialog.") + print(f"{prompt} [Y/n] ", end="") + answer = input() + return answer == 'y' or answer == 'Y' or answer == '' + + +def mitigate_by_pip_install(*args: str) -> None: + import sys + import runpy + sys.argv = [ + 'pip', 'install', '--force-reinstall', *args + ] + os.environ['PIP_BREAK_SYSTEM_PACKAGES'] = '1' + runpy.run_module("pip", run_name="__main__") + + +def prompt_and_mitigate_dependencies(name: str) -> None: + deps = get_module_dependencies(name) + deps_str = ' '.join(f"'{d}'" for d in deps) + answer = prompt_mitigation(""" +It appears dependencies are missing or have the wrong version. This can happen +if you forgot to install the required packages. This can also happen if you +installed the packages to a different Python environment than is being used +right now. + +This script is about to offer automatic resolution. If you'd like to resolve +this manually, answer no to the next question and then see Ghidra's help by +pressing F1 in the dialog of launch parameters. + +WARNING: Answering yes to the next question will invoke pip to try to install +missing or incorrectly-versioned dependencies. It may attempt to find packages +from your configured PyPI mirror. If you have not configured one, it will +connect to the official one. + +WARNING: We invoke pip with the --break-system-packages flag, because some +debuggers that embed Python (gdb, lldb) may not support virtual environments, +and so the packages must be installed to your user environment. + +NOTE: Automatic resolution may cause this session to terminate. When it has +finished, close this terminal, and try launching again. +""", f"Would you like to install {deps_str}?") + + if answer: + mitigate_by_pip_install('-f', '../../pypkg/dist', *deps) + diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java index 9525abf1e3..8940f79a9f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProvider.java @@ -1388,6 +1388,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter List.of(programManager.getAllOpenPrograms())); } + @Override public void setAutoMapSpec(AutoMapSpec spec) { actionAutoMap.setCurrentActionStateByUserData(spec); } diff --git a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java index 144b28af0e..cbccbc6a7d 100644 --- a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java +++ b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java @@ -92,9 +92,11 @@ public class ConPtyChild extends ConPtyEndpoint implements PtyChild { STARTUPINFOEX si = prepareStartupInfo(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); + String commandLine = ShellUtils.generateLine(Arrays.asList(args)); + if (!ConsoleApiNative.INSTANCE.CreateProcessW( null /*lpApplicationName*/, - new WString(ShellUtils.generateLine(Arrays.asList(args))), + new WString(commandLine), null /*lpProcessAttributes*/, null /*lpThreadAttributes*/, false /*bInheritHandles*/, diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbConnectorsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbConnectorsTest.java new file mode 100644 index 0000000000..b33090739a --- /dev/null +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbConnectorsTest.java @@ -0,0 +1,266 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package agent.gdb.rmi; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.net.SocketTimeoutException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +import org.junit.Before; +import org.junit.Test; + +import db.Transaction; +import generic.Unique; +import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest; +import ghidra.app.plugin.core.debug.gui.action.BySectionAutoMapSpec; +import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesPlugin; +import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.NoStaticMappingException; +import ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin; +import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; +import ghidra.app.services.DebuggerAutoMappingService; +import ghidra.app.services.TraceRmiLauncherService; +import ghidra.app.util.importer.AutoImporter; +import ghidra.app.util.importer.MessageLog; +import ghidra.debug.api.ValStr; +import ghidra.debug.api.action.AutoMapSpec; +import ghidra.debug.api.tracermi.TerminalSession; +import ghidra.debug.api.tracermi.TraceRmiLaunchOffer; +import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*; +import ghidra.framework.OperatingSystem; +import ghidra.framework.plugintool.AutoConfigState.PathIsFile; +import ghidra.pty.testutil.DummyProc; +import ghidra.util.SystemUtilities; + +public class GdbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationTest { + private TraceRmiLauncherService launchService; + private DebuggerAutoMappingService autoMappingService; + + @Before + public void checkManual() throws Exception { + assumeFalse(SystemUtilities.isInTestingBatchMode()); + addPlugin(tool, DebuggerStaticMappingServicePlugin.class); + addPlugin(tool, DebuggerModulesPlugin.class); + autoMappingService = + Objects.requireNonNull(tool.getService(DebuggerAutoMappingService.class)); + launchService = addPlugin(tool, TraceRmiLauncherServicePlugin.class); + } + + protected PathIsFile chooseImage() { + if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) { + return new PathIsFile(Path.of("C:\\Windows\\notepad.exe")); + } + return new PathIsFile(Path.of("/bin/ls")); + } + + protected PathIsFile findQemu(String bin) { + if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) { + return new PathIsFile(Path.of("C:\\msys64\\ucrt64\bin\\").resolve(bin)); + } + return new PathIsFile(Path.of(bin)); + } + + protected PathIsFile createArmElfImage() throws Exception { + Path tempSrc = Files.createTempFile("hw", ".c"); + Path tempObj = Files.createTempFile("hw", ".o"); + Path tempImg = Files.createTempFile("hw", ""); + try (OutputStream os = new FileOutputStream(tempSrc.toFile())) { + os.write(""" + int main() { + return 0; + } + """.getBytes()); + } + new ProcessBuilder().command( + "arm-linux-eabi-gcc", "-c", + "-o", tempObj.toAbsolutePath().toString(), + tempSrc.toAbsolutePath().toString()).inheritIO().start().waitFor(); + new ProcessBuilder().command( + "arm-linux-eabi-ld", + "-o", tempImg.toAbsolutePath().toString(), + tempObj.toAbsolutePath().toString()).inheritIO().start().waitFor(); + return new PathIsFile(tempImg); + } + + protected PathIsFile createDummyQemuImage() throws Exception { + Path temp = Files.createTempFile("qemudummy", ".bin"); + try (OutputStream os = new FileOutputStream(temp.toFile())) { + os.write(new byte[4096]); + } + return new PathIsFile(temp); + } + + protected LaunchResult doLaunch(String title, Map args) { + TraceRmiLaunchOffer offer = Unique.assertOne( + launchService.getOffers(program).stream().filter(o -> o.getTitle().equals(title))); + return offer.launchProgram(monitor, new LaunchConfigurator() { + @Override + public Map> configureLauncher(TraceRmiLaunchOffer offer, + Map> arguments, RelPrompt relPrompt) { + Map> newArgs = new HashMap<>(arguments); + for (Map.Entry ent : args.entrySet()) { + newArgs.put(ent.getKey(), ValStr.from(ent.getValue())); + } + return newArgs; + } + }); + } + + protected void checkResult(LaunchResult result) { + if (result.exception() != null && + !(result.exception() instanceof NoStaticMappingException)) { + throw new AssertionError(result); + } + } + + @Test + public void testLocalGdbSetup() throws Exception { + new ProcessBuilder().command("pip", "install", "protobuf==3.19.0") + .inheritIO() + .start() + .waitFor(); + try (LaunchResult result = doLaunch("gdb", Map.of("arg:1", chooseImage()))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("gdb", Map.of("arg:1", chooseImage()))) { + checkResult(result); + } + } + + @Test + public void testLocalGdbWithImage() throws Exception { + try (LaunchResult result = doLaunch("gdb", Map.of("arg:1", chooseImage()))) { + checkResult(result); + } + } + + @Test + public void testGdbQemuUser() throws Exception { + PathIsFile image = createArmElfImage(); + program = AutoImporter.importByUsingBestGuess(image.path().toFile(), null, "/", this, + new MessageLog(), monitor).getPrimaryDomainObject(); + programManager.openProgram(program); + try (LaunchResult result = doLaunch("gdb + qemu", Map.ofEntries( + Map.entry("arg:1", image), + Map.entry("env:OPT_GDB_PATH", new PathIsFile(Path.of("gdb"))), + Map.entry("env:GHIDRA_LANG_EXTTOOL_qemu_system", findQemu("qemu-arm")), + Map.entry("env:OPT_PULL_ALL_SECTIONS", true)))) { + checkResult(result); + } + } + + @Test + public void testGdbQemuSys() throws Exception { + autoMappingService + .setAutoMapSpec(AutoMapSpec.fromConfigName(BySectionAutoMapSpec.CONFIG_NAME)); + PathIsFile dummy = createDummyQemuImage(); + createProgram(); + try (Transaction tx = program.openTransaction("Set name")) { + program.setName(dummy.toString()); + } + programManager.openProgram(program); + try (LaunchResult result = doLaunch("gdb + qemu-system", Map.ofEntries( + Map.entry("arg:1", dummy), + Map.entry("env:OPT_GDB_PATH", new PathIsFile(Path.of("gdb"))), + Map.entry("env:GHIDRA_LANG_EXTTOOL_qemu_system", findQemu("qemu-system-aarch64")), + Map.entry("env:OPT_EXTRA_QEMU_ARGS", "-machine virt")))) { + checkResult(result); + } + } + + @Test + public void testGdbRemote() throws Exception { + PathIsFile target = chooseImage(); + try ( + DummyProc gdbServer = + DummyProc.run("gdbserver", ":9999", target.path().toAbsolutePath().toString()); + LaunchResult result = doLaunch("gdb remote", Map.ofEntries( + Map.entry("arg:1", target), + Map.entry("OPT_HOST", "localhost"), + Map.entry("OPT_PORT", 9999)))) { + checkResult(result); + } + } + + @Test + public void testGdbViaSsh() throws Exception { + try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } + + @Test + public void testGdbViaSshSetupGhidraGdb() throws Exception { + new ProcessBuilder().command("pip", "uninstall", "ghidragdb").inheritIO().start().waitFor(); + try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } + + @Test + public void testGdbViaSshSetupProtobuf() throws Exception { + new ProcessBuilder().command("pip", "install", "protobuf==3.19.0") + .inheritIO() + .start() + .waitFor(); + try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } + + @Test + public void testGdbServerViaSsh() throws Exception { + PathIsFile target = chooseImage(); + createProgram(); + try (LaunchResult result = doLaunch("gdb + gdbserver via ssh", Map.ofEntries( + Map.entry("arg:1", target.toString())))) { + checkResult(result); + } + } +} diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbConnectorsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbConnectorsTest.java new file mode 100644 index 0000000000..36b703f794 --- /dev/null +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbConnectorsTest.java @@ -0,0 +1,291 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package agent.lldb.rmi; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.net.SocketTimeoutException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +import org.junit.*; + +import db.Transaction; +import generic.Unique; +import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest; +import ghidra.app.plugin.core.debug.gui.action.BySectionAutoMapSpec; +import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesPlugin; +import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.NoStaticMappingException; +import ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin; +import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; +import ghidra.app.services.DebuggerAutoMappingService; +import ghidra.app.services.TraceRmiLauncherService; +import ghidra.app.util.importer.AutoImporter; +import ghidra.app.util.importer.MessageLog; +import ghidra.debug.api.ValStr; +import ghidra.debug.api.action.AutoMapSpec; +import ghidra.debug.api.tracermi.TerminalSession; +import ghidra.debug.api.tracermi.TraceRmiLaunchOffer; +import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*; +import ghidra.framework.OperatingSystem; +import ghidra.framework.plugintool.AutoConfigState.PathIsFile; +import ghidra.pty.testutil.DummyProc; +import ghidra.util.SystemUtilities; + +/** + * NOTE: On Windows, these tests may need to be run with lldb's version of Python at the front of + * PATH, and it's lib and DLLs dirs at the front of PYTHONPATH. It's probably easiest to just get + * lldb working in a command prompt. Ensure that it can import socket, and then re-launch Eclipse + * from there. + */ +public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationTest { + private TraceRmiLauncherService launchService; + private DebuggerAutoMappingService autoMappingService; + + @Before + public void checkManual() throws Exception { + assumeFalse(SystemUtilities.isInTestingBatchMode()); + addPlugin(tool, DebuggerStaticMappingServicePlugin.class); + addPlugin(tool, DebuggerModulesPlugin.class); + autoMappingService = + Objects.requireNonNull(tool.getService(DebuggerAutoMappingService.class)); + launchService = addPlugin(tool, TraceRmiLauncherServicePlugin.class); + } + + protected PathIsFile chooseImage() { + if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) { + return new PathIsFile(Path.of("C:\\Windows\\notepad.exe")); + } + return new PathIsFile(Path.of("/bin/ls")); + } + + protected PathIsFile findQemu(String bin) { + if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) { + return new PathIsFile(Path.of("C:\\msys64\\ucrt64\bin\\").resolve(bin)); + } + return new PathIsFile(Path.of(bin)); + } + + protected PathIsFile createArmElfImage() throws Exception { + assumeTrue(OperatingSystem.LINUX == OperatingSystem.CURRENT_OPERATING_SYSTEM); + Path tempSrc = Files.createTempFile("hw", ".c"); + Path tempObj = Files.createTempFile("hw", ".o"); + Path tempImg = Files.createTempFile("hw", ""); + try (OutputStream os = new FileOutputStream(tempSrc.toFile())) { + os.write(""" + int main() { + return 0; + } + """.getBytes()); + } + new ProcessBuilder().command( + "arm-linux-eabi-gcc", "-c", + "-o", tempObj.toAbsolutePath().toString(), + tempSrc.toAbsolutePath().toString()).inheritIO().start().waitFor(); + new ProcessBuilder().command( + "arm-linux-eabi-ld", + "-o", tempImg.toAbsolutePath().toString(), + tempObj.toAbsolutePath().toString()).inheritIO().start().waitFor(); + return new PathIsFile(tempImg); + } + + protected PathIsFile createDummyQemuImage() throws Exception { + Path temp = Files.createTempFile("qemudummy", ".bin"); + try (OutputStream os = new FileOutputStream(temp.toFile())) { + os.write(new byte[4096]); + } + return new PathIsFile(temp); + } + + protected LaunchResult doLaunch(String title, Map args) { + TraceRmiLaunchOffer offer = Unique.assertOne( + launchService.getOffers(program).stream().filter(o -> o.getTitle().equals(title))); + return offer.launchProgram(monitor, new LaunchConfigurator() { + @Override + public Map> configureLauncher(TraceRmiLaunchOffer offer, + Map> arguments, RelPrompt relPrompt) { + Map> newArgs = new HashMap<>(arguments); + for (Map.Entry ent : args.entrySet()) { + newArgs.put(ent.getKey(), ValStr.from(ent.getValue())); + } + return newArgs; + } + + @Override + public PromptMode getPromptMode() { + return title.contains("ssh") ? PromptMode.ALWAYS : PromptMode.NEVER; + } + }); + } + + protected void checkResult(LaunchResult result) { + if (result.exception() != null && + !(result.exception() instanceof NoStaticMappingException)) { + throw new AssertionError(result); + } + } + + /** + * This also doesn't quite work correctly on Windows. The prompt appears, but the user is not + * allowed to answer the question before the next lldb script command is run, which finds the + * package missing and exits with code 253. May just have to cut losses there. The message hits + * the screen, and this circumstance should be rare. + * + * @throws Exception + */ + @Test + public void testLocalLldbSetup() throws Exception { + new ProcessBuilder().command("python", "-m", "pip", "install", "protobuf==3.19.0") + .inheritIO() + .start() + .waitFor(); + try (LaunchResult result = doLaunch("lldb", Map.of("arg:1", chooseImage()))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("lldb", Map.of("arg:1", chooseImage()))) { + checkResult(result); + } + } + + @Test + public void testLocalLldbWithImage() throws Exception { + try (LaunchResult result = doLaunch("lldb", Map.ofEntries( + Map.entry("arg:1", chooseImage()), + Map.entry("env:OPT_START_CMD", "process launch --stop-at-entry")))) { + checkResult(result); + } + } + + @Test + @Ignore("TODO") + public void testLldbQemuUser() throws Exception { + assumeFalse(OperatingSystem.WINDOWS == OperatingSystem.CURRENT_OPERATING_SYSTEM); + PathIsFile image = createArmElfImage(); + program = AutoImporter.importByUsingBestGuess(image.path().toFile(), null, "/", this, + new MessageLog(), monitor).getPrimaryDomainObject(); + programManager.openProgram(program); + try (LaunchResult result = doLaunch("lldb + qemu", Map.ofEntries( + Map.entry("arg:1", image), + Map.entry("env:OPT_LLDB_PATH", new PathIsFile(Path.of("lldb"))), + Map.entry("env:GHIDRA_LANG_EXTTOOL_qemu_system", findQemu("qemu-arm")), + Map.entry("env:OPT_PULL_ALL_SECTIONS", true)))) { + checkResult(result); + } + } + + @Test + @Ignore("TODO") + public void testLldbQemuSys() throws Exception { + autoMappingService + .setAutoMapSpec(AutoMapSpec.fromConfigName(BySectionAutoMapSpec.CONFIG_NAME)); + PathIsFile dummy = createDummyQemuImage(); + createProgram(); + try (Transaction tx = program.openTransaction("Set name")) { + program.setName(dummy.toString()); + } + programManager.openProgram(program); + try (LaunchResult result = doLaunch("lldb + qemu-system", Map.ofEntries( + Map.entry("arg:1", dummy), + Map.entry("env:OPT_LLDB_PATH", new PathIsFile(Path.of("lldb"))), + Map.entry("env:GHIDRA_LANG_EXTTOOL_qemu_system", findQemu("qemu-system-aarch64")), + Map.entry("env:OPT_EXTRA_QEMU_ARGS", "-machine virt")))) { + checkResult(result); + } + } + + /** + * This has proven difficult to test on Windows, probably because the version of lldb and + * gdbserver I'm using are not compatible? + * + * @throws Exception + */ + @Test + public void testLldbRemoteGdb() throws Exception { + PathIsFile target = chooseImage(); + try ( + DummyProc gdbServer = + DummyProc.run("gdbserver", ":9999", target.path().toAbsolutePath().toString()); + LaunchResult result = doLaunch("lldb remote (gdb)", Map.ofEntries( + Map.entry("arg:1", target), + Map.entry("OPT_HOST", "localhost"), + Map.entry("OPT_PORT", 9999)))) { + checkResult(result); + } + } + + @Test + public void testLldbViaSsh() throws Exception { + try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } + + @Test + public void testLldbViaSshSetupGhidraLldb() throws Exception { + // This only applies if we leave localhost in the dialog + new ProcessBuilder().command("python", "-m", "pip", "uninstall", "ghidralldb") + .inheritIO() + .start() + .waitFor(); + try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } + + @Test + public void testLldbViaSshSetupProtobuf() throws Exception { + new ProcessBuilder().command("python", "-m", "pip", "install", "protobuf==3.19.0") + .inheritIO() + .start() + .waitFor(); + try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + assertTrue(result.exception() instanceof SocketTimeoutException); + TerminalSession term = Unique.assertOne(result.sessions().values()); + while (!term.isTerminated()) { + Thread.sleep(1000); + } + } + try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries( + Map.entry("arg:1", "/bin/ls"), + Map.entry("OPT_HOST", "localhost")))) { + checkResult(result); + } + } +}