GP-5700: Expose module directories to scripts on request

This commit is contained in:
Dan 2025-07-02 19:15:54 +00:00
parent 7482131bcc
commit f92076b936
73 changed files with 862 additions and 516 deletions

View file

@ -9,6 +9,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#win_kernel
::@depends Debugger-rmi-trace
::@enum Connection:str Remote Local EXDI
::@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."
:: Use env instead of args, because "all args except first" is terrible to implement in batch

View file

@ -9,6 +9,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#attach
::@depends Debugger-rmi-trace
::@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."
::@env OPT_TARGET_PID:int=0 "Process id" "The target process id"
::@env OPT_ATTACH_FLAGS:int=0 "Attach flags" "Attach flags"

View file

@ -10,6 +10,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#ext
::@depends Debugger-rmi-trace
::@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."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image"

View file

@ -9,6 +9,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#ttd
::@depends Debugger-rmi-trace
::@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."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_TRACE:file="" "Trace (.run)" "The target trace image"

View file

@ -10,6 +10,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#local
::@depends Debugger-rmi-trace
::@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."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image"

View file

@ -9,6 +9,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#remote
::@depends Debugger-rmi-trace
::@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."
::@env OPT_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la .server)"
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."

View file

@ -10,6 +10,7 @@
::@menu-group dbgeng
::@icon icon.debugger
::@help dbgeng#svrcx
::@depends Debugger-rmi-trace
::@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."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image"

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -21,10 +21,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -19,10 +19,11 @@ import sys
def append_paths():
sys.path.append("../../../Debugger-rmi-trace/data/support")
sys.path.append(
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/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"))
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():

View file

@ -18,7 +18,7 @@ try:
import pybag
except Exception as e:
from ghidratrace.setuputils import prompt_and_mitigate_dependencies
prompt_and_mitigate_dependencies("Debug/Debugger-agent-dbgeng")
prompt_and_mitigate_dependencies("<SELF>")
# NOTE: libraries must precede EVERYTHING, esp pybag and DbgMod
from . import libraries, util, commands, methods, hooks

View file

@ -25,6 +25,7 @@
#@menu-group drgn
#@icon icon.debugger
#@help drgn#core
#@depends Debugger-rmi-trace
#@env OPT_TARGET_IMG:file!="" "Core dump" "The target core dump"
export OPT_TARGET_KIND="coredump"

View file

@ -25,6 +25,7 @@
#@menu-group drgn
#@icon icon.debugger
#@help drgn#linux_kernel
#@depends Debugger-rmi-trace
export OPT_TARGET_KIND="kernel"
sudo -E drgn ../support/local-drgn.py

View file

@ -25,6 +25,7 @@
#@menu-group drgn
#@icon icon.debugger
#@help drgn#attach
#@depends Debugger-rmi-trace
#@env OPT_TARGET_PID:int=44068 "PID" "The target's process id"
export OPT_TARGET_KIND="user"

View file

@ -22,25 +22,18 @@ import sys
import drgn.cli
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}/ghidra/.git'):
def append_paths():
sys.path.append(
f'{home}/ghidra/Ghidra/Debug/Debugger-agent-drgn/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-drgn/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-drgn/pypkg/src')
sys.path.append(f'{home}/Ghidra/Debug/Debugger-rmi-trace/pypkg/src')
f"{os.getenv('MODULE_Debugger_rmi_trace_HOME')}/data/support")
from gmodutils import ghidra_module_pypath
sys.path.append(ghidra_module_pypath("Debugger-rmi-trace"))
sys.path.append(ghidra_module_pypath())
def main():
append_paths()
from ghidradrgn import commands as cmd
cmd.ghidra_trace_connect(address=os.getenv('GHIDRA_TRACE_RMI_ADDR'))
cmd.ghidra_trace_create(start_trace=True)
@ -49,9 +42,7 @@ def main():
cmd.ghidra_trace_txcommit()
cmd.ghidra_trace_activate()
drgn.cli.run_interactive(cmd.prog)
if __name__ == '__main__':
main()

View file

@ -10,6 +10,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#local
#@depends Debugger-rmi-trace
#@enum StartCmd:str run start starti
#@enum Endian:str auto big little
#@arg :file "Image" "The target binary executable image"
@ -21,8 +22,8 @@
. ..\support\gdbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Gdb-Usermode-Args `

View file

@ -26,6 +26,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#local
#@depends Debugger-rmi-trace
#@enum StartCmd:str run start starti
#@enum Endian:str auto big little
#@arg :file "Image" "The target binary executable image, empty for no target"
@ -39,8 +40,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -25,6 +25,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#rr
#@depends Debugger-rmi-trace
#@enum StartCmd:str run start starti
#@enum Endian:str auto big little
#@arg :file "Trace Dir" "The target trace directory (e.g. .local/share/rr/trace)"
@ -36,8 +37,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_trace="$1"

View file

@ -27,6 +27,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#qemu
#@depends Debugger-rmi-trace
#@enum Endian:str auto big little
#@arg :file! "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target"
@ -42,8 +43,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -11,6 +11,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#qemu
#@depends Debugger-rmi-trace
#@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."
@ -23,8 +24,8 @@
. ..\support\gdbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH"
$qemuargs = @("`"$Env:GHIDRA_LANG_EXTTOOL_qemu_system`"")

View file

@ -27,6 +27,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#qemu
#@depends Debugger-rmi-trace
#@enum Endian:str auto big little
#@arg :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."
@ -41,8 +42,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -10,6 +10,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#remote
#@depends Debugger-rmi-trace
#@enum TargetType:str remote extended-remote
#@enum Endian:str auto big little
#@arg :file "Image" "The target binary executable image (a copy on the local system)"
@ -22,8 +23,8 @@
. ..\support\gdbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Gdb-Remote-Args `

View file

@ -26,6 +26,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#remote
#@depends Debugger-rmi-trace
#@enum TargetType:str remote extended-remote
#@enum Endian:str auto big little
#@arg :file "Image" "The target binary executable image (a copy on the local system)"
@ -38,8 +39,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -1,4 +1,3 @@
#@timeout 60000
#@title gdb via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -11,6 +10,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#ssh
#@depends Debugger-rmi-trace
#@enum StartCmd:str run start starti
#@enum Endian:str auto big little
#@arg :str "Image" "The target binary executable image on the remote system"
@ -61,7 +61,7 @@ finished, try launching again.
if ($answer) {
Write-Host "Copying Wheels to $Env:OPT_HOST"
Mitigate-Scp-PyModules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-gdb"
Mitigate-Scp-PyModules "Debugger-rmi-trace" "<SELF>"
Write-Host "Installing Wheels into GDB's embedded Python"
$arglist = Compute-Gdb-PipInstall-Args "'-f'" "os.environ['HOME']" "'ghidragdb>=$version'"

View file

@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
#@timeout 60000
#@title gdb via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -27,6 +26,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#ssh
#@depends Debugger-rmi-trace
#@enum StartCmd:str run start starti
#@enum Endian:str auto big little
#@arg :str "Image" "The target binary executable image on the remote system"
@ -93,7 +93,7 @@ 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"
mitigate-scp-pymodules "Debugger-rmi-trace" "<SELF>"
echo "Installing Wheels into GDB's embedded Python"
do-installation

View file

@ -1,4 +1,3 @@
#@timeout 60000
#@title gdb + gdbserver via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -11,6 +10,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#gdbserver_ssh
#@depends Debugger-rmi-trace
#@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"
@ -25,8 +25,8 @@
. ..\support\gdbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath "Debug/Debugger-agent-gdb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathGdb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathGdb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Gdb-Remote-Args `

View file

@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
#@timeout 60000
#@title gdb + gdbserver via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -27,6 +26,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#gdbserver_ssh
#@depends Debugger-rmi-trace
#@enum Endian:str auto big little
#@arg :str! "Image" "The target binary executable image on the remote system"
#@args "Arguments" "Command-line arguments to pass to the target"
@ -41,8 +41,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -26,6 +26,7 @@
#@menu-group gdb
#@icon icon.debugger
#@help gdb#wine
#@depends Debugger-rmi-trace
#@enum Endian:str auto big little
#@arg :file! "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target"
@ -39,8 +40,8 @@
. ../support/gdbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath "Debug/Debugger-agent-gdb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathGdb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathGdb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -1,5 +1,5 @@
. ..\..\..\Debugger-rmi-trace\data\support\setuputils.ps1
. $Env:MODULE_Debugger_rmi_trace_HOME\data\support\setuputils.ps1
function Add-Gdb-Init-Args {
param([ref]$ArgList)
@ -48,7 +48,7 @@ function Add-Gdb-Tail-Args {
param([ref]$ArgList)
$ArgList.Value+=("-ex", "`"set confirm on`"")
$ArgList.Value+=("-ex", "`"set pagination on`"")
# $ArgList.Value+=("-ex", "`"set pagination on`"")
}
function Compute-Gdb-Usermode-Args {

View file

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
. ../../../Debugger-rmi-trace/data/support/setuputils.sh
. $MODULE_Debugger_rmi_trace_HOME/data/support/setuputils.sh
add-gdb-init-args() {
args+=(-q)
@ -64,7 +64,7 @@ add-gdb-start-if-image() {
add-gdb-tail-args() {
args+=(-ex "set confirm on")
args+=(-ex "set pagination on")
# args+=(-ex "set pagination on")
}
compute-gdb-usermode-args() {

View file

@ -10,6 +10,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#android
#@depends Debugger-rmi-trace
#@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"
@ -21,8 +22,8 @@
. ..\support\lldbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Lldb-Platform-Args `

View file

@ -26,6 +26,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#android
#@depends Debugger-rmi-trace
#@enum StartCmd:str "process launch" "process launch --stop-at-entry"
#@arg :file "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target"
@ -37,8 +38,8 @@
. ../support/lldbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -9,14 +9,15 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#macos_kernel
#@depends Debugger-rmi-trace
#@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"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Lldb-Remote-Args `

View file

@ -25,14 +25,15 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#macos_kernel
#@depends Debugger-rmi-trace
#@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.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH
function launch-lldb() {

View file

@ -10,6 +10,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#local
#@depends Debugger-rmi-trace
#@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"
@ -18,8 +19,8 @@
. ..\support\lldbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Lldb-Usermode-Args `

View file

@ -26,6 +26,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#local
#@depends Debugger-rmi-trace
#@enum StartCmd:str "process launch" "process launch --stop-at-entry"
#@arg :file "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target"
@ -36,8 +37,8 @@
. ../support/lldbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -10,6 +10,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#remote
#@depends Debugger-rmi-trace
#@arg :file "Image" "The target binary executable image (a copy on the local system)"
#@env OPT_HOST:str="localhost" "Host" "The hostname of the target"
#@env OPT_PORT:str="9999" "Port" "The host's listening port"
@ -18,8 +19,8 @@
. ..\support\lldbsetuputils.ps1
$pypathTrace = Ghidra-Module-PyPath "Debug/Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath "Debug/Debugger-agent-lldb"
$pypathTrace = Ghidra-Module-PyPath "Debugger-rmi-trace"
$pypathLldb = Ghidra-Module-PyPath
$Env:PYTHONPATH = "$pypathLldb;$pypathTrace;$Env:PYTHONPATH"
$arglist = Compute-Lldb-Remote-Args `

View file

@ -26,6 +26,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#remote
#@depends Debugger-rmi-trace
#@arg :file "Image" "The target binary executable image (a copy on the local system)"
#@env OPT_HOST:str="localhost" "Host" "The hostname of the target"
#@env OPT_PORT:str="9999" "Port" "The host's listening port"
@ -34,8 +35,8 @@
. ../support/lldbsetuputils.sh
pypathTrace=$(ghidra-module-pypath "Debug/Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath "Debug/Debugger-agent-lldb")
pypathTrace=$(ghidra-module-pypath "Debugger-rmi-trace")
pypathLldb=$(ghidra-module-pypath)
export PYTHONPATH=$pypathLldb:$pypathTrace:$PYTHONPATH
target_image="$1"

View file

@ -1,4 +1,3 @@
#@timeout 60000
#@title lldb via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -11,6 +10,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#ssh
#@depends Debugger-rmi-trace
#@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"
@ -60,7 +60,7 @@ finished, try launching again.
if ($answer) {
Write-Host "Copying Wheels to $Env:OPT_HOST"
Mitigate-Scp-PyModules "Debug/Debugger-rmi-trace" "Debug/Debugger-agent-lldb"
Mitigate-Scp-PyModules "Debugger-rmi-trace" "<SELF>"
Write-Host "Installing Wheels into LLDB's embedded Python"
$arglist = Compute-Lldb-PipInstall-Args "'-f'" "os.environ['HOME']" "'ghidralldb>=$version'"

View file

@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
#@timeout 60000
#@title lldb via ssh
#@image-opt arg:1
#@desc <html><body width="300px">
@ -27,6 +26,7 @@
#@menu-group lldb
#@icon icon.debugger
#@help lldb#ssh
#@depends Debugger-rmi-trace
#@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"
@ -92,7 +92,7 @@ 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"
mitigate-scp-pymodules "Debugger-rmi-trace" "<SELF>"
echo "Installing Wheels into LLDB's embedded Python"
do-installation

View file

@ -1,5 +1,5 @@
. ..\..\..\Debugger-rmi-trace\data\support\setuputils.ps1
. $Env:MODULE_Debugger_rmi_trace_HOME\data\support\setuputils.ps1
function Add-Lldb-Init-Args {
param([ref]$ArgList)

View file

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
. ../../../Debugger-rmi-trace/data/support/setuputils.sh
. $MODULE_Debugger_rmi_trace_HOME/data/support/setuputils.sh
add-lldb-init-args() {
args+=(-o "version")

View file

@ -86,8 +86,9 @@ public class JavaTraceRmiLaunchOffer extends AbstractScriptTraceRmiLaunchOffer {
}
@Override
protected void launchBackEnd(TaskMonitor monitor, Map<String, TerminalSession> sessions,
Map<String, ValStr<?>> args, SocketAddress address) throws Exception {
protected TraceRmiBackEnd launchBackEnd(TaskMonitor monitor,
Map<String, TerminalSession> sessions, Map<String, ValStr<?>> args,
SocketAddress address) throws Exception {
List<String> commandLine = new ArrayList<>();
Map<String, String> env = new HashMap<>(System.getenv());
prepareSubprocess(commandLine, env, args, address);
@ -101,18 +102,28 @@ public class JavaTraceRmiLaunchOffer extends AbstractScriptTraceRmiLaunchOffer {
sessions.put(ns.name(), ns);
}
TraceRmiBackEnd result = new TraceRmiBackEnd();
if (hasKeyReally(env, "OPT_JSHELL_PATH")) {
String classPath = computeClassPath(env);
commandLine.add(0, "--startup");
commandLine.add(0, "--class-path=" + classPath);
commandLine.add(0, env.get("OPT_JSHELL_PATH"));
sessions.put("Shell",
runInTerminal(commandLine, env, script.getParentFile(), sessions.values()));
PtyTerminalSession session =
runInTerminal(commandLine, env, script.getParentFile(), sessions.values());
sessions.put("Shell", session);
session.terminal().addTerminalListener(result);
}
else {
JdiClientThread thread = new JdiClientThread(env);
JdiClientThread thread = new JdiClientThread(env) {
@Override
public void run() {
super.run();
result.terminated(0);
}
};
thread.start();
}
return result;
}
private String computeClassPath(Map<String, String> env) {

View file

@ -30,14 +30,9 @@
#@env OPT_LANG:str="DATA:LE:64:default" "Ghidra Language" "The Ghidra LanguageID for the trace"
#@env OPT_COMP:str="pointer64" "Ghidra Compiler" "The Ghidra CompilerSpecID for the trace"
if [ -d ${GHIDRA_HOME}/ghidra/.git ]
then
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-rmi-trace/build/pypkg/src:$PYTHONPATH
else
export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH
fi
. ../support/setuputils.sh
pypathTrace=$(ghidra-module-pypath)
export PYTHONPATH=$pypathTrace:$PYTHONPATH
"$OPT_PYTHON_EXE" -i ../support/raw-python3.py

View file

@ -28,19 +28,17 @@ This file CANNOT be assumed to be available on a remote target. For
that, consider ghidratrace.setuputils.
"""
import os
home = os.getenv('GHIDRA_HOME')
from typing import Optional
def ghidra_module_pypath(name: str) -> str:
installed = f'{home}/Ghidra/{name}/pypkg/src'
def ghidra_module_pypath(name: Optional[str]=None) -> str:
mod_home_name = 'MODULE_HOME' if name is None else f'MODULE_{name.replace("-","_")}_HOME'
mod_home = os.getenv(mod_home_name)
installed = f'{mod_home}/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
dev = f'{mod_home}/build/pypkg/src'
if os.path.isdir(dev):
return dev
raise Exception(
f"Cannot find Python source for {name}. Try gradle assemblePyPackage?")

View file

@ -1,17 +1,17 @@
## ###
# 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.
##
from concurrent.futures import ThreadPoolExecutor
import os
@ -33,4 +33,4 @@ client = Client(
print(f"Connected to {client.description} at {host}:{port}")
trace = client.create_trace("noname", os.getenv(
"OPT_LANG"), os.getenv("OPT_COMP"))
"OPT_LANG"), os.getenv("OPT_COMP"), extra=None)

View file

@ -1,11 +1,7 @@
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
[IO.FileInfo] $props = "$Env:GHIDRA_HOME\application.properties"
if ($props.Exists) {
return $props
}
throw "Cannot find application.properties"
}
@ -17,33 +13,39 @@ function Get-Ghidra-Version {
}
function Ghidra-Module-PyPath {
[IO.DirectoryInfo] $installed = "$Env:GHIDRA_HOME\Ghidra\$($args[0])\pypkg\src"
if ($args.Count -eq 0 -or $args[0] -eq "<SELF>") {
$modhomename = 'MODULE_HOME'
} else {
$modhomename = "MODULE_$($args[0])_HOME" -replace '-', '_'
}
$modhomeitem = Get-ChildItem Env:$modhomename
$modhome = $modhomeitem.Value
[IO.DirectoryInfo] $installed = "$modhome\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"
[IO.DirectoryInfo] $dev = "$modhome\build\pypkg\src"
if ($dev.Exists) {
return "$dev"
}
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 ($args.Count -eq 0 -or $args[0] -eq "<SELF>") {
$modhomename = 'MODULE_HOME'
} else {
$modhomename = "MODULE_$($args[0])_HOME" -replace '-', '_'
}
$modhomeitem = Get-ChildItem Env:$modhomename
$modhome = $modhomeitem.Value
[IO.DirectoryInfo] $installed = "$modhome\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"
[IO.DirectoryInfo] $dev = "$modhome\build\pypkg\dist"
if ($dev.Exists) {
return "$dev"
}
throw "Cannot find Python package for $($args[0]). Try gradle buildPyPackage?"
}

View file

@ -14,14 +14,9 @@
# 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
local props="$GHIDRA_HOME/application.properties"
if [ -f "$props" ]; then
echo $props
return 0
fi
echo >&2 "Cannot find application.properties"
@ -45,19 +40,21 @@ get-ghidra-version() {
}
ghidra-module-pypath() {
installed="$GHIDRA_HOME/Ghidra/$1/pypkg/src"
local modhomename
if [ -z "$1" ] || [ "$1" == "<SELF>" ]; then
modhomename='MODULE_HOME'
else
modhomename="MODULE_${1//-/_}_HOME"
fi
local modhome="${!modhomename}"
local installed="$modhome/pypkg/src"
if [ -d "$installed" ]; 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
local dev="$modhome/build/pypkg/src"
if [ -d "$dev" ]; then
echo $dev
return 0
fi
echo >&2 "Cannot find Python source for $1. Try gradle assemblePyPackage?"
@ -65,19 +62,21 @@ ghidra-module-pypath() {
}
ghidra-module-pydist() {
installed="$GHIDRA_HOME/Ghidra/$1/pypkg/dist"
local modhomename
if [ -z "$1" ] || [ "$1" == "<SELF>" ]; then
modhomename='MODULE_HOME'
else
modhomename="MODULE_${1//-/_}_HOME"
fi
local modhome="${!modhomename}"
local installed="$modhome/pypkg/dist"
if [ -d "$installed" ]; 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
local dev="$modhome/build/pypkg/dist"
if [ -d "$dev" ]; then
echo $dev
return 0
fi
echo >&2 "Cannot find Python package for $1. Try gradle buildPyPackage?"

View file

@ -98,12 +98,13 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi
protected void prepareSubprocess(List<String> commandLine, Map<String, String> env,
Map<String, ValStr<?>> args, SocketAddress address) {
ScriptAttributesParser.processArguments(commandLine, env, script, attrs.parameters(), args,
address);
attrs.dependencies(), address);
}
@Override
protected void launchBackEnd(TaskMonitor monitor, Map<String, TerminalSession> sessions,
Map<String, ValStr<?>> args, SocketAddress address) throws Exception {
protected TraceRmiBackEnd launchBackEnd(TaskMonitor monitor,
Map<String, TerminalSession> sessions, Map<String, ValStr<?>> args,
SocketAddress address) throws Exception {
List<String> commandLine = new ArrayList<>();
Map<String, String> env = new HashMap<>(System.getenv());
prepareSubprocess(commandLine, env, args, address);
@ -112,7 +113,8 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi
if (imageParameter != null) {
ValStr<?> valStr = args.get(imageParameter.name());
if (valStr != null && !valStr.str().contains(program.getName())) {
Msg.warn(this, "Possible mismatch for " + program.getName() + ": " + valStr.str());
Msg.warn(this,
"Possible mismatch for " + program.getName() + ": " + valStr.str());
}
}
env.put("GHIDRA_LANGUAGE_ID", program.getLanguageID().toString());
@ -127,8 +129,12 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi
sessions.put(ent.getKey(), ns);
}
sessions.put("Shell",
runInTerminal(commandLine, env, script.getParentFile(), sessions.values()));
PtyTerminalSession session =
runInTerminal(commandLine, env, script.getParentFile(), sessions.values());
sessions.put("Shell", session);
TraceRmiBackEnd result = new TraceRmiBackEnd();
session.terminal().addTerminalListener(result);
return result;
}
@Override

View file

@ -17,16 +17,18 @@ package ghidra.app.plugin.core.debug.gui.tracermi.launcher;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.*;
import javax.swing.Icon;
import org.apache.commons.lang3.exception.ExceptionUtils;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.gui.action.ByModuleAutoMapSpec;
import ghidra.app.plugin.core.debug.gui.tracermi.launcher.LaunchFailureDialog.ErrPromptResponse;
@ -59,12 +61,14 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
public static final String PREFIX_PARAM_EXTTOOL = "env:GHIDRA_LANG_EXTTOOL_";
public static final int DEFAULT_TIMEOUT_MILLIS = 10000;
public static final int DEFAULT_CONNECTION_TIMEOUT_MILLIS =
(int) Duration.ofMinutes(10).toMillis();
protected record PtyTerminalSession(Terminal terminal, Pty pty, PtySession session,
Thread waiter) implements TerminalSession {
@Override
public void terminate() throws IOException {
terminal.terminated();
terminal.terminated(-1);
session.destroyForcibly();
pty.close();
waiter.interrupt();
@ -80,7 +84,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
implements TerminalSession {
@Override
public void terminate() throws IOException {
terminal.terminated();
terminal.terminated(-1);
pty.close();
}
@ -135,7 +139,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
}
protected int getConnectionTimeoutMillis() {
return getTimeoutMillis();
return DEFAULT_CONNECTION_TIMEOUT_MILLIS;
}
@Override
@ -415,8 +419,9 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
param.display()));
}
catch (Exception e) {
Msg.warn(this, "Could not load saved launcher arg '%s' (%s) - %s".formatted(param.name(),
param.display(), e.getMessage()));
Msg.warn(this,
"Could not load saved launcher arg '%s' (%s) - %s".formatted(param.name(),
param.display(), e.getMessage()));
}
}
return args;
@ -490,8 +495,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
Thread waiter = new Thread(() -> {
try {
session.waitExited();
terminal.terminated();
int exitcode = session.waitExited();
terminal.terminated(exitcode);
pty.close();
for (TerminalSession ss : subordinates) {
@ -538,10 +543,43 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
return terminalSession;
}
protected abstract void launchBackEnd(TaskMonitor monitor,
protected abstract TraceRmiBackEnd launchBackEnd(TaskMonitor monitor,
Map<String, TerminalSession> sessions, Map<String, ValStr<?>> args,
SocketAddress address) throws Exception;
protected TraceRmiHandler acceptOrSessionEnds(DefaultTraceRmiAcceptor acceptor,
TraceRmiBackEnd backEnd)
throws SocketException, CancelledException, EarlyTerminationException {
acceptor.setTimeout(getConnectionTimeoutMillis());
CompletableFuture<TraceRmiHandler> futureConnection = CompletableFuture.supplyAsync(() -> {
try {
return acceptor.accept();
}
catch (CancelledException | IOException e) {
return ExceptionUtils.rethrow(e);
}
});
// Because of accept timeout, should be a finite wait
try {
CompletableFuture.anyOf(backEnd, futureConnection).get();
if (backEnd.isDone()) {
throw new EarlyTerminationException(
"The back-end exited (code=%s) before receiving a connection"
.formatted(backEnd.getNow(null)));
}
return futureConnection.get();
}
catch (ExecutionException e) {
switch (e.getCause()) {
case CancelledException ce -> throw ce;
default -> throw new AssertionError(e);
}
}
catch (InterruptedException e) {
throw new AssertionError(e);
}
}
public static class NoStaticMappingException extends Exception {
public NoStaticMappingException(String message) {
super(message);
@ -553,6 +591,17 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
}
}
public static class EarlyTerminationException extends Exception {
public EarlyTerminationException(String message) {
super(message);
}
@Override
public String toString() {
return getMessage();
}
}
protected AutoMapSpec getAutoMapSpec() {
DebuggerAutoMappingService auto = tool.getService(DebuggerAutoMappingService.class);
return auto == null ? ByModuleAutoMapSpec.instance() : auto.getAutoMapSpec();
@ -660,12 +709,16 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
monitor.increment();
monitor.setMessage("Launching back-end");
launchBackEnd(monitor, sessions, args, acceptor.getAddress());
TraceRmiBackEnd backEnd =
launchBackEnd(monitor, sessions, args, acceptor.getAddress());
monitor.increment();
/**
* LATER: We might be able to disable timeouts, now that we know if the back-end
* terminates early
*/
monitor.setMessage("Waiting for connection");
acceptor.setTimeout(getConnectionTimeoutMillis());
connection = acceptor.accept();
connection = acceptOrSessionEnds(acceptor, backEnd);
connection.registerTerminals(sessions.values());
monitor.increment();

View file

@ -25,6 +25,7 @@ import java.util.Map.Entry;
import javax.swing.Icon;
import generic.jar.ResourceFile;
import generic.theme.GIcon;
import generic.theme.Gui;
import ghidra.debug.api.ValStr;
@ -40,12 +41,15 @@ import ghidra.util.*;
*/
public abstract class ScriptAttributesParser {
public static final String ENV_GHIDRA_HOME = "GHIDRA_HOME";
public static final String ENV_MODULE_HOME = "MODULE_HOME";
public static final String ENV_MODULE_HOME_PAT = "MODULE_%s_HOME";
public static final String ENV_GHIDRA_TRACE_RMI_ADDR = "GHIDRA_TRACE_RMI_ADDR";
public static final String ENV_GHIDRA_TRACE_RMI_HOST = "GHIDRA_TRACE_RMI_HOST";
public static final String ENV_GHIDRA_TRACE_RMI_PORT = "GHIDRA_TRACE_RMI_PORT";
public static final String AT_ARG = "@arg";
public static final String AT_ARGS = "@args";
public static final String AT_DEPENDS = "@depends";
public static final String AT_DESC = "@desc";
public static final String AT_ENUM = "@enum";
public static final String AT_ENV = "@env";
@ -341,8 +345,8 @@ public abstract class ScriptAttributesParser {
public record ScriptAttributes(String title, String description, List<String> menuPath,
String menuGroup, String menuOrder, Icon icon, HelpLocation helpLocation,
Map<String, LaunchParameter<?>> parameters, Map<String, TtyCondition> extraTtys,
int timeoutMillis, LaunchParameter<?> imageOpt) {
Map<String, LaunchParameter<?>> parameters, Set<String> dependencies,
Map<String, TtyCondition> extraTtys, int timeoutMillis, LaunchParameter<?> imageOpt) {
}
/**
@ -355,14 +359,35 @@ public abstract class ScriptAttributesParser {
* @param script the script file
* @param parameters the descriptions of the parameters
* @param args the arguments to process
* @param dependencies a set of module names this script needs
* @param address the address of the listening TraceRmi socket
*/
public static void processArguments(List<String> commandLine, Map<String, String> env,
File script, Map<String, LaunchParameter<?>> parameters, Map<String, ValStr<?>> args,
SocketAddress address) {
Set<String> dependencies, SocketAddress address) {
commandLine.add(script.getAbsolutePath());
env.put(ENV_GHIDRA_HOME, Application.getInstallationDirectory().getAbsolutePath());
env.put(ENV_GHIDRA_HOME, Application.getApplicationRootDirectory().getAbsolutePath());
ResourceFile myModule =
Application.getModuleContainingResourceFile(new ResourceFile(script));
if (myModule == null) {
Msg.warn(ScriptAttributes.class, "Launch script is not contained in a module");
}
else {
env.put(ENV_MODULE_HOME, myModule.getAbsolutePath());
}
for (String dep : dependencies) {
ResourceFile module = Application.getModuleRootDir(dep);
if (module == null) {
Msg.warn(ScriptAttributes.class, "Could not find module " + dep);
}
else {
env.put(ENV_MODULE_HOME_PAT.formatted(dep.replace('-', '_')),
module.getAbsolutePath());
}
}
if (address != null) {
env.put(ENV_GHIDRA_TRACE_RMI_ADDR, sockToString(address));
if (address instanceof InetSocketAddress tcp) {
@ -402,8 +427,9 @@ public abstract class ScriptAttributesParser {
private List<String> menuPath;
private final Map<String, UserType<?>> userTypes = new HashMap<>();
private final Map<String, LaunchParameter<?>> parameters = new LinkedHashMap<>();
private final Set<String> dependencies = new LinkedHashSet<>();
private final Map<String, TtyCondition> extraTtys = new LinkedHashMap<>();
private int timeoutMillis = AbstractTraceRmiLaunchOffer.DEFAULT_TIMEOUT_MILLIS;
private int timeoutMillis = AbstractTraceRmiLaunchOffer.DEFAULT_CONNECTION_TIMEOUT_MILLIS;
private String imageOptKey;
/**
@ -493,6 +519,7 @@ public abstract class ScriptAttributesParser {
switch (parts[0].trim()) {
case AT_ARG -> parseArg(loc, parts[1], ++argc);
case AT_ARGS -> parseArgs(loc, parts[1]);
case AT_DEPENDS -> parseDepends(loc, parts[1]);
case AT_DESC -> parseDesc(loc, parts[1]);
case AT_ENUM -> parseEnum(loc, parts[1]);
case AT_ENV -> parseEnv(loc, parts[1]);
@ -549,6 +576,13 @@ public abstract class ScriptAttributesParser {
}
}
protected void parseDepends(Location loc, String str) {
String moduleName = str.trim();
if (!dependencies.add(moduleName)) {
reportWarning("%s: Duplicate %s %s. Ignored.".formatted(loc, AT_DEPENDS, str));
}
}
protected void parseDesc(Location loc, String str) {
if (description == null) {
description = new StringBuilder();
@ -796,9 +830,11 @@ public abstract class ScriptAttributesParser {
AT_IMAGE_OPT, imageOptKey));
}
}
// NOTE: Don't use copyOf, or else we lose ordering
return new ScriptAttributes(title, getDescription(), List.copyOf(menuPath), menuGroup,
menuOrder, new GIcon(iconId), helpLocation,
Collections.unmodifiableMap(new LinkedHashMap<>(parameters)),
Collections.unmodifiableSet(new LinkedHashSet<>(dependencies)),
Collections.unmodifiableMap(new LinkedHashMap<>(extraTtys)), timeoutMillis, imageOpt);
}

View file

@ -0,0 +1,27 @@
/* ###
* 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 ghidra.app.plugin.core.debug.gui.tracermi.launcher;
import java.util.concurrent.CompletableFuture;
import ghidra.app.plugin.core.terminal.TerminalListener;
public class TraceRmiBackEnd extends CompletableFuture<Integer> implements TerminalListener {
@Override
public void terminated(int exitcode) {
complete(exitcode);
}
}

View file

@ -17,7 +17,7 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
"protobuf >= 6.31.0",
"protobuf>=6.31.0",
]
[project.urls]

View file

@ -18,7 +18,7 @@ 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")
prompt_and_mitigate_dependencies("Debugger-rmi-trace")
from collections import deque
from concurrent.futures import Executor, Future

View file

@ -23,22 +23,18 @@ 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
from typing import List, Optional, Sequence
home = os.getenv('GHIDRA_HOME')
def ghidra_module_src(name: str) -> str:
installed = f'{home}/Ghidra/{name}/pypkg'
def ghidra_module_src(name: Optional[str]=None) -> str:
mod_home_name = 'MODULE_HOME' if name is None else f'MODULE_{name.replace("-","_")}_HOME'
mod_home = os.getenv(mod_home_name)
installed = f'{mod_home}/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
dev = f'{mod_home}/src/main/py'
if os.path.isdir(dev):
return dev
raise Exception(f"""
Cannot find Python source for {name}.
If this is a remote system, we shouldn't even be here. Chances are,
@ -63,9 +59,9 @@ def get_module_dependencies(name: str) -> List[str]:
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 ,
if l.endswith(','): # Last one may not have ,
l = l[:-1].strip()
result.append(l[1:-1]) # Remove 's or "s
result.append(l[1:-1]) # Remove 's or "s
raise Exception("Could not parse pyproject.toml")
@ -93,15 +89,29 @@ def mitigate_by_pip_install(*args: str) -> None:
runpy.run_module("pip", run_name="__main__")
def compute_suggestion(*args: str) -> None:
def maybe_quote(a):
if '>' in a or '<' in a or ' ' in a:
return f"'{a}'"
return a
wquotes = ' '.join(maybe_quote(a) for a in args)
return f"python -m pip install --force-reinstall {wquotes}"
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("""
suggestion = compute_suggestion(*deps)
answer = prompt_mitigation(f"""
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.
The following command should resolve the issue:
{suggestion}
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.
@ -121,4 +131,3 @@ finished, close this terminal, and try launching again.
if answer:
mitigate_by_pip_install('-f', '../../pypkg/dist', *deps)

View file

@ -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.
@ -41,8 +41,8 @@ public class DefaultTerminal implements Terminal {
}
@Override
public void terminated() {
provider.terminated();
public void terminated(int exitcode) {
provider.terminated(exitcode);
}
@Override

View file

@ -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.
@ -38,4 +38,12 @@ public interface TerminalListener {
*/
default void retitled(String title) {
}
/**
* The terminal session was terminated
*
* @param exitcode the exit code of the session leader, or -1 if not applicable
*/
default void terminated(int exitcode) {
}
}

View file

@ -39,7 +39,9 @@ import ghidra.app.plugin.core.terminal.TerminalFinder.TextTerminalFinder;
import ghidra.app.plugin.core.terminal.vt.*;
import ghidra.app.plugin.core.terminal.vt.VtHandler.*;
import ghidra.app.services.ClipboardService;
import ghidra.util.*;
import ghidra.util.ColorUtils;
import ghidra.util.Swing;
import ghidra.util.datastruct.ListenerSet;
/**
* A VT100 terminal emulator in a panel.
@ -180,7 +182,8 @@ public class TerminalPanel extends JPanel implements FieldLocationListener, Fiel
protected TerminalClipboardProvider clipboardProvider;
protected String selectedText;
protected final ArrayList<TerminalListener> terminalListeners = new ArrayList<>();
protected final ListenerSet<TerminalListener> terminalListeners =
new ListenerSet<TerminalListener>(TerminalListener.class, false);
protected VtOutput outputCb;
protected final TerminalAwtEventEncoder eventEncoder;
@ -363,25 +366,15 @@ public class TerminalPanel extends JPanel implements FieldLocationListener, Fiel
}
protected void notifyTerminalResized(short cols, short rows) {
for (TerminalListener l : terminalListeners) {
try {
l.resized(cols, rows);
}
catch (Throwable t) {
Msg.showError(this, null, "Error", t.getMessage(), t);
}
}
terminalListeners.invoke().resized(cols, rows);
}
protected void notifyTerminalRetitled(String title) {
for (TerminalListener l : terminalListeners) {
try {
l.retitled(title);
}
catch (Throwable t) {
Msg.showError(this, null, "Error", t.getMessage(), t);
}
}
terminalListeners.invoke().retitled(title);
}
protected void notifyTerminalTerminated(int exitcode) {
terminalListeners.invoke().terminated(exitcode);
}
@Override

View file

@ -53,7 +53,7 @@ import ghidra.util.Swing;
* This also provides UI actions for searching the terminal's contents.
*/
public class TerminalProvider extends ComponentProviderAdapter {
// TODO: A separate color?
// Should I use a separate color id?
private static final Color COLOR_TERMINATED = new GColor("color.border.provider.disconnected");
protected class FindDialog extends DialogComponentProvider {
@ -433,10 +433,13 @@ public class TerminalProvider extends ComponentProviderAdapter {
* <p>
* The title and sub title are adjusted and all terminal listeners are removed. If/when the
* window is closed, it is removed from the tool.
*
* @param exitcode the exit code of the session leader, or -1 if not applicable
*/
public void terminated() {
public void terminated(int exitcode) {
Swing.runIfSwingOrRunLater(() -> {
terminated = true;
panel.terminalListeners.invoke().terminated(exitcode);
removeLocalAction(actionTerminate);
panel.terminalListeners.clear();
panel.setOutputCallback(buf -> {

View file

@ -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.
@ -201,8 +201,10 @@ public interface Terminal extends AutoCloseable {
* <p>
* The title and sub title are adjust and all listeners are removed. If/when the terminal is
* closed, it is permanently removed from the tool.
*
* @param exitcode the exit code of the session leader, or -1 if not applicable
*/
void terminated();
void terminated(int exitcode);
/**
* Allow the user to terminate the session forcefully

View file

@ -0,0 +1,182 @@
/* ###
* 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import org.junit.Before;
import generic.Unique;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
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.debug.api.ValStr;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*;
import ghidra.framework.Application;
import ghidra.framework.OperatingSystem;
import ghidra.framework.plugintool.AutoConfigState.PathIsFile;
import ghidra.util.SystemUtilities;
public abstract class AbstractRmiConnectorsTest
extends AbstractGhidraHeadedDebuggerIntegrationTest {
protected TraceRmiLauncherService launchService;
protected DebuggerAutoMappingService autoMappingService;
protected String getPythonCmd() {
return "python";
}
protected abstract List<ResourceFile> getPipLinkModules();
protected void unpip(String... specs) throws Exception {
List<String> args = new ArrayList<>();
args.addAll(List.of(getPythonCmd(), "-m", "pip", "uninstall", "-y"));
args.addAll(List.of(specs));
int result = new ProcessBuilder().command(args).inheritIO().start().waitFor();
assertEquals("pip failed", 0, result);
}
protected void pipOob(String... specs) throws Exception {
List<String> args = new ArrayList<>();
args.addAll(List.of(getPythonCmd(), "-m", "pip", "install"));
args.addAll(List.of(specs));
int result = new ProcessBuilder().command(args).inheritIO().start().waitFor();
assertEquals("pip failed", 0, result);
}
protected void pip(String... specs) throws Exception {
List<String> args = new ArrayList<>();
args.addAll(List.of(getPythonCmd(), "-m", "pip", "install", "--no-index"));
for (ResourceFile root : Application.getApplicationRootDirectories()) {
if (root.getAbsolutePath().contains("ghidra.bin")) {
for (; root != null; root = root.getParentFile()) {
if (root.getName().equals("ghidra.bin")) {
args.addAll(List.of("-f", root.getAbsolutePath() + "/ExternalPyWheels"));
}
}
}
}
for (ResourceFile module : getPipLinkModules()) {
args.addAll(List.of("-f", module.getAbsolutePath() + "/build/pypkg/dist"));
}
args.addAll(List.of(specs));
int result = new ProcessBuilder().command(args).inheritIO().start().waitFor();
assertEquals("pip failed", 0, result);
}
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<String, Object> args) {
TraceRmiLaunchOffer offer = Unique.assertOne(
launchService.getOffers(program).stream().filter(o -> o.getTitle().equals(title)));
return offer.launchProgram(monitor, new LaunchConfigurator() {
@Override
public Map<String, ValStr<?>> configureLauncher(TraceRmiLaunchOffer offer,
Map<String, ValStr<?>> arguments, RelPrompt relPrompt) {
Map<String, ValStr<?>> newArgs = new HashMap<>(arguments);
for (Map.Entry<String, Object> ent : args.entrySet()) {
newArgs.put(ent.getKey(), ValStr.from(ent.getValue()));
}
return newArgs;
}
@Override
public PromptMode getPromptMode() {
return title.contains("ssh") &&
OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS
? PromptMode.ALWAYS
: PromptMode.NEVER;
}
});
}
protected void checkResult(LaunchResult result) {
if (result.exception() != null &&
!(result.exception() instanceof NoStaticMappingException)) {
throw new AssertionError(result);
}
}
@Before
public void setUpRmiConnectorsTest() throws Exception {
// Check manual
assumeFalse(SystemUtilities.isInTestingBatchMode());
addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
addPlugin(tool, DebuggerModulesPlugin.class);
autoMappingService =
Objects.requireNonNull(tool.getService(DebuggerAutoMappingService.class));
launchService = addPlugin(tool, TraceRmiLauncherServicePlugin.class);
}
}

View file

@ -0,0 +1,93 @@
/* ###
* 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.dbgeng.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import agent.AbstractRmiConnectorsTest;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.EarlyTerminationException;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.LaunchResult;
import ghidra.framework.Application;
import ghidra.framework.plugintool.AutoConfigState.PathIsFile;
public class DbgEngConnectorsTest extends AbstractRmiConnectorsTest {
@Override
protected String getPythonCmd() {
return "C:\\Python313\\python";
}
@Override
protected List<ResourceFile> getPipLinkModules() {
return List.of(
Application.getModuleRootDir("Debugger-rmi-trace"),
Application.getModuleRootDir("Debugger-agent-dbgeng"));
}
@Before
public void setUpDbgEng() throws Exception {
// Make sure system doesn't cause path failures to pass
unpip("ghidradbg", "ghidratrace");
// Ensure a compatible version of protobuf
pip("protobuf==6.31.0");
}
@Test
public void testLocalDbgSetup() throws Exception {
pipOob("protobuf==3.19.0");
try (LaunchResult result = doLaunch("dbgeng", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseImage()),
Map.entry("env:OPT_PYTHON_EXE",
new PathIsFile(Path.of("C:\\Python313\\python.exe")))))) {
assertThat(result.exception(), instanceOf(EarlyTerminationException.class));
assertThat(result.sessions().get("Shell").content(),
containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("dbgeng", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseImage()),
Map.entry("env:OPT_PYTHON_EXE",
new PathIsFile(Path.of("C:\\Python313\\python.exe")))))) {
checkResult(result);
}
}
@Test
public void testLocalDbgWithImage() throws Exception {
try (LaunchResult result = doLaunch("dbgeng", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseImage()),
Map.entry("env:OPT_PYTHON_EXE",
new PathIsFile(Path.of("C:\\Python313\\python.exe")))))) {
checkResult(result);
}
}
// LATER?: kernel
// LATER?: attach (usermode by PID)
// LATER?: ext
// LATER?: trace (TTD)
// LATER?: remote (Start WinDbg and join session)
// LATER?: svrcx (what scenario?)
}

View file

@ -52,9 +52,9 @@ import junit.framework.AssertionFailedError;
public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebuggerTest {
protected static String CORE = "core.12137";
protected static String MDO = "/New Traces/" + CORE;
public static String PREAMBLE = """
protected static final String CORE = "core.12137";
protected static final String MDO = "/New Traces/" + CORE;
public static final String PREAMBLE = """
import os
import drgn
import drgn.cli

View file

@ -0,0 +1,82 @@
/* ###
* 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.drgn.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import agent.AbstractRmiConnectorsTest;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.EarlyTerminationException;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.LaunchResult;
import ghidra.framework.Application;
import ghidra.framework.plugintool.AutoConfigState.PathIsFile;
public class DrgnConnectorsTest extends AbstractRmiConnectorsTest {
@Override
protected List<ResourceFile> getPipLinkModules() {
return List.of(
Application.getModuleRootDir("Debugger-rmi-trace"),
Application.getModuleRootDir("Debugger-agent-drgn"));
}
protected PathIsFile chooseCore() throws FileNotFoundException {
return new PathIsFile(Application
.getModuleDataFile("TestResources", AbstractDrgnTraceRmiTest.CORE)
.getFile(true)
.toPath());
}
@Before
public void setUpDrgn() throws Exception {
// Make sure system doesn't cause path failures to pass
unpip("ghidradrgn", "ghidratrace");
// Ensure a compatible version of protobuf
pip("protobuf==6.31.0");
}
@Test
public void testLocalDrgnSetup() throws Exception {
pipOob("protobuf==3.19.0");
try (LaunchResult result = doLaunch("drgn core", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseCore())))) {
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("drgn core", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseCore())))) {
checkResult(result);
}
}
@Test
public void testLocalDrgnWithCore() throws Exception {
try (LaunchResult result = doLaunch("drgn core", Map.ofEntries(
Map.entry("env:OPT_TARGET_IMG", chooseCore())))) {
checkResult(result);
}
}
}

View file

@ -15,134 +15,54 @@
*/
package agent.gdb.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
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 java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import agent.AbstractRmiConnectorsTest;
import db.Transaction;
import generic.Unique;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
import generic.jar.ResourceFile;
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.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.EarlyTerminationException;
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.debug.api.tracermi.TraceRmiLaunchOffer.LaunchResult;
import ghidra.framework.Application;
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;
public class GdbConnectorsTest extends AbstractRmiConnectorsTest {
@Override
protected List<ResourceFile> getPipLinkModules() {
return List.of(
Application.getModuleRootDir("Debugger-rmi-trace"),
Application.getModuleRootDir("Debugger-agent-gdb"));
}
@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<String, Object> args) {
TraceRmiLaunchOffer offer = Unique.assertOne(
launchService.getOffers(program).stream().filter(o -> o.getTitle().equals(title)));
return offer.launchProgram(monitor, new LaunchConfigurator() {
@Override
public Map<String, ValStr<?>> configureLauncher(TraceRmiLaunchOffer offer,
Map<String, ValStr<?>> arguments, RelPrompt relPrompt) {
Map<String, ValStr<?>> newArgs = new HashMap<>(arguments);
for (Map.Entry<String, Object> 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);
}
public void setUpGdb() throws Exception {
// Make sure system doesn't cause path failures to pass
unpip("ghidragdb", "ghidratrace");
// Ensure a compatible version of protobuf
pip("protobuf==6.31.0");
}
@Test
public void testLocalGdbSetup() throws Exception {
new ProcessBuilder().command("pip", "install", "protobuf==3.19.0")
.inheritIO()
.start()
.waitFor();
pipOob("protobuf==3.19.0");
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);
}
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("gdb", Map.of("arg:1", chooseImage()))) {
checkResult(result);
@ -206,6 +126,7 @@ public class GdbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationTe
@Test
public void testGdbViaSsh() throws Exception {
pip("ghidragdb==%s".formatted(Application.getApplicationVersion()));
try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),
Map.entry("OPT_HOST", "localhost")))) {
@ -215,15 +136,12 @@ public class GdbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationTe
@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);
}
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),
@ -234,18 +152,15 @@ public class GdbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationTe
@Test
public void testGdbViaSshSetupProtobuf() throws Exception {
new ProcessBuilder().command("pip", "install", "protobuf==3.19.0")
.inheritIO()
.start()
.waitFor();
pip("ghidragdb==%s".formatted(Application.getApplicationVersion()));
// Overwrite with an incompatible version we don't include
pipOob("protobuf==3.19.0");
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);
}
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("gdb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),

View file

@ -15,132 +15,52 @@
*/
package agent.lldb.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
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 java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.*;
import agent.AbstractRmiConnectorsTest;
import db.Transaction;
import generic.Unique;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
import generic.jar.ResourceFile;
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.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.EarlyTerminationException;
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.debug.api.tracermi.TraceRmiLaunchOffer.LaunchResult;
import ghidra.framework.Application;
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
* PATH, and its 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;
public class LldbConnectorsTest extends AbstractRmiConnectorsTest {
@Override
protected List<ResourceFile> getPipLinkModules() {
return List.of(
Application.getModuleRootDir("Debugger-rmi-trace"),
Application.getModuleRootDir("Debugger-agent-lldb"));
}
@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<String, Object> args) {
TraceRmiLaunchOffer offer = Unique.assertOne(
launchService.getOffers(program).stream().filter(o -> o.getTitle().equals(title)));
return offer.launchProgram(monitor, new LaunchConfigurator() {
@Override
public Map<String, ValStr<?>> configureLauncher(TraceRmiLaunchOffer offer,
Map<String, ValStr<?>> arguments, RelPrompt relPrompt) {
Map<String, ValStr<?>> newArgs = new HashMap<>(arguments);
for (Map.Entry<String, Object> 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);
}
public void setupLldb() throws Exception {
// Make sure system doesn't cause path failures to pass
unpip("ghidralldb", "ghidratrace");
// Ensure a compatible version of protobuf
pip("protobuf==6.31.0");
}
/**
@ -149,24 +69,17 @@ public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationT
* package missing and exits with code 253. May just have to cut losses there. The message hits
* the screen, and this circumstance <em>should</em> be rare.
*
* @throws Exception
* @throws Exception because
*/
@Test
public void testLocalLldbSetup() throws Exception {
new ProcessBuilder().command("python", "-m", "pip", "install", "protobuf==3.19.0")
.inheritIO()
.start()
.waitFor();
pipOob("protobuf==3.19.0");
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);
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
// NOTE: lldb will not let me prompt the user, so cannot test automatic mitigation
}
@Test
@ -219,7 +132,7 @@ public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationT
* This has proven difficult to test on Windows, probably because the version of lldb and
* gdbserver I'm using are not compatible?
*
* @throws Exception
* @throws Exception because
*/
@Test
public void testLldbRemoteGdb() throws Exception {
@ -237,6 +150,7 @@ public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationT
@Test
public void testLldbViaSsh() throws Exception {
pip("ghidralldb==%s".formatted(Application.getApplicationVersion()));
try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),
Map.entry("OPT_HOST", "localhost")))) {
@ -246,19 +160,12 @@ public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationT
@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);
}
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),
@ -269,18 +176,15 @@ public class LldbConnectorsTest extends AbstractGhidraHeadedDebuggerIntegrationT
@Test
public void testLldbViaSshSetupProtobuf() throws Exception {
new ProcessBuilder().command("python", "-m", "pip", "install", "protobuf==3.19.0")
.inheritIO()
.start()
.waitFor();
pip("ghidralldb==%s".formatted(Application.getApplicationVersion()));
// Overwrite with an incompatible version we don't include
pipOob("protobuf==3.19.0");
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);
}
assertTrue(result.exception() instanceof EarlyTerminationException);
assertThat(result.sessions().get("Shell").content(),
Matchers.containsString("Would you like to install"));
}
try (LaunchResult result = doLaunch("lldb via ssh", Map.ofEntries(
Map.entry("arg:1", "/bin/ls"),

View file

@ -187,7 +187,7 @@ public class ScriptTraceRmiLaunchOfferTest extends AbstractGhidraHeadedDebuggerT
}
@Override
public void terminated() {
public void terminated(int exitcode) {
}
@Override

View file

@ -67,8 +67,10 @@ public class TestTraceRmiLaunchOpinion implements TraceRmiLaunchOpinion {
}
@Override
protected void launchBackEnd(TaskMonitor monitor, Map<String, TerminalSession> sessions,
protected TraceRmiBackEnd launchBackEnd(TaskMonitor monitor,
Map<String, TerminalSession> sessions,
Map<String, ValStr<?>> args, SocketAddress address) throws Exception {
return null;
}
@Override