GP-4906: Implement @image-opt. Have local-gdb use it. Fix 'null'.

This commit is contained in:
Dan 2024-10-31 11:50:38 -04:00
parent e476b20476
commit d5a25fa6a3
31 changed files with 497 additions and 462 deletions

View file

@ -9,7 +9,7 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_kernel ::@help TraceRmiLauncherServicePlugin#dbgeng_kernel
::@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_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 :: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_ARGS:str="" "Arguments" "Connection-string arguments (a la .server)" ::@env OPT_TARGET_ARGS:str="" "Arguments" "Connection-string arguments (a la .server)"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."

View file

@ -9,9 +9,9 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_attach ::@help TraceRmiLauncherServicePlugin#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." ::@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:str="" "Process id" "The target process id" ::@env OPT_TARGET_PID:int="" "Process id" "The target process id"
::@env OPT_ATTACH_FLAGS:str="0" "Attach flags" "Attach flags" ::@env OPT_ATTACH_FLAGS:int="0" "Attach flags" "Attach flags"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." ::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."

View file

@ -1,4 +1,5 @@
::@title dbgeng-ext ::@title dbgeng-ext
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3> ::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p> ::@desc <p>
@ -9,17 +10,17 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_ext ::@help TraceRmiLauncherServicePlugin#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." ::@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 :: 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" ::@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_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." ::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
::@env OPT_TARGET_DIR:str="" "Dir" "Initial directory" ::@env OPT_TARGET_DIR:str="" "Dir" "Initial directory"
::@env OPT_TARGET_ENV:str="" "Env" "Environment variables (sep=/0)" ::@env OPT_TARGET_ENV:str="" "Env" "Environment variables (sep=/0)"
::@env OPT_CREATE_FLAGS:str="1" "Create flags" "Creation flags" ::@env OPT_CREATE_FLAGS:int="1" "Create flags" "Creation flags"
::@env OPT_CREATE_ENGFLAGS:str="0" "Create flags (Engine)" "Engine-specific creation flags" ::@env OPT_CREATE_ENGFLAGS:int="0" "Create flags (Engine)" "Engine-specific creation flags"
::@env OPT_VERIFIER_FLAGS:str="0" "Verifier flags" "Verifier flags" ::@env OPT_VERIFIER_FLAGS:int="0" "Verifier flags" "Verifier flags"
@echo off @echo off

View file

@ -1,4 +1,5 @@
::@title dbgeng ::@title dbgeng
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3> ::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p> ::@desc <p>
@ -9,9 +10,9 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng ::@help TraceRmiLauncherServicePlugin#dbgeng
::@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_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 :: 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" ::@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_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." ::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."

View file

@ -9,9 +9,9 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_ttd ::@help TraceRmiLauncherServicePlugin#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." ::@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 :: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file="" "Trace (.run)" "A trace associated with the target binary executable" ::@env OPT_TARGET_IMG:file!="" "Trace (.run)" "A trace associated with the target binary executable"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" ::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env OPT_DBGMODEL_PATH:dir="" "Path to dbgeng.dll & \\ttd" "Path containing dbgeng and associated DLLS (if not Windows Kits)." ::@env OPT_DBGMODEL_PATH:dir="" "Path to dbgeng.dll & \\ttd" "Path containing dbgeng and associated DLLS (if not Windows Kits)."

View file

@ -1,4 +1,5 @@
::@title dbgeng-remote ::@title dbgeng-remote
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> remotely (in a Python interpreter)</h3> ::@desc <h3>Launch with <tt>dbgeng</tt> remotely (in a Python interpreter)</h3>
::@desc <p> ::@desc <p>
@ -9,9 +10,9 @@
::@menu-group local ::@menu-group local
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_remote ::@help TraceRmiLauncherServicePlugin#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." ::@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 :: 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" ::@env OPT_TARGET_IMG:str!="" "Image" "The target binary executable image"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" ::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la dbgsrv args)" ::@env OPT_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la dbgsrv args)"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." ::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."

View file

@ -3,7 +3,6 @@
Module.manifest||GHIDRA||||END| Module.manifest||GHIDRA||||END|
data/debugger-launchers/local-gdb.bat||GHIDRA||||END| data/debugger-launchers/local-gdb.bat||GHIDRA||||END|
data/debugger-launchers/qemu-gdb.bat||GHIDRA||||END| data/debugger-launchers/qemu-gdb.bat||GHIDRA||||END|
data/debugger-launchers/raw-gdb.bat||GHIDRA||||END|
data/debugger-launchers/remote-gdb.bat||GHIDRA||||END| data/debugger-launchers/remote-gdb.bat||GHIDRA||||END|
data/debugger-launchers/ssh-gdb.bat||GHIDRA||||END| data/debugger-launchers/ssh-gdb.bat||GHIDRA||||END|
data/debugger-launchers/ssh-gdbserver.bat||GHIDRA||||END| data/debugger-launchers/ssh-gdbserver.bat||GHIDRA||||END|

View file

@ -1,4 +1,5 @@
::@title gdb ::@title gdb
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>gdb</tt></h3> ::@desc <h3>Launch with <tt>gdb</tt></h3>
::@desc <p> ::@desc <p>
@ -14,6 +15,8 @@
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" ::@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_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_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target."
::@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
@echo off @echo off
set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src
@ -28,7 +31,20 @@ IF EXIST %GHIDRA_HOME%\ghidra\.git (
) )
set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH%
"%OPT_GDB_PATH%" ^ IF "%OPT_TARGET_IMG%"=="" (
"%OPT_GDB_PATH%" ^
-q ^
-ex "set pagination off" ^
-ex "set confirm off" ^
-ex "show version" ^
-ex "python import ghidragdb" ^
-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 ^ -q ^
-ex "set pagination off" ^ -ex "set pagination off" ^
-ex "set confirm off" ^ -ex "set confirm off" ^
@ -36,10 +52,10 @@ set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH%
-ex "python import ghidragdb" ^ -ex "python import ghidragdb" ^
-ex "target exec %OPT_TARGET_IMG%" ^ -ex "target exec %OPT_TARGET_IMG%" ^
-ex "set args %OPT_TARGET_ARGS%" ^ -ex "set args %OPT_TARGET_ARGS%" ^
-ex "set inferior-tty %TTY_TARGET%" ^
-ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^
-ex "ghidra trace start" ^ -ex "ghidra trace start" ^
-ex "ghidra trace sync-enable" ^ -ex "ghidra trace sync-enable" ^
-ex "%OPT_START_CMD%" ^ -ex "%OPT_START_CMD%" ^
-ex "set confirm on" ^ -ex "set confirm on" ^
-ex "set pagination on" -ex "set pagination on"
)

View file

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
## ##
#@title gdb #@title gdb
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with <tt>gdb</tt></h3> #@desc <h3>Launch with <tt>gdb</tt></h3>
#@desc <p> #@desc <p>
@ -26,10 +27,11 @@
#@icon icon.debugger #@icon icon.debugger
#@help TraceRmiLauncherServicePlugin#gdb #@help TraceRmiLauncherServicePlugin#gdb
#@enum StartCmd:str run start starti #@enum StartCmd:str run start starti
#@arg :file "Image" "The target binary executable image" #@arg :file "Image" "The target binary executable image, empty for no target"
#@args "Arguments" "Command-line arguments to pass to the target" #@args "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_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_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_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target."
#@tty TTY_TARGET if env:OPT_EXTRA_TTY #@tty TTY_TARGET if env:OPT_EXTRA_TTY
@ -50,14 +52,31 @@ target_image="$1"
shift shift
target_args="$@" target_args="$@"
# NOTE: Ghidra will leave TTY_TARGET empty, which gdb takes for the same terminal. # Ghidra will leave TTY_TARGET empty when OPT_EXTRA_TTY is false. Gdb takes empty to mean the same terminal.
"$OPT_GDB_PATH" \ if [ -z "$target_image" ]
then
"$OPT_GDB_PATH" \
-q \ -q \
-ex "set pagination off" \ -ex "set pagination off" \
-ex "set confirm off" \ -ex "set confirm off" \
-ex "show version" \ -ex "show version" \
-ex "python import ghidragdb" \ -ex "python import ghidragdb" \
-ex "set architecture $OPT_ARCH" \
-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 "file \"$target_image\"" \ -ex "file \"$target_image\"" \
-ex "set args $target_args" \ -ex "set args $target_args" \
-ex "set inferior-tty $TTY_TARGET" \ -ex "set inferior-tty $TTY_TARGET" \
@ -67,3 +86,4 @@ target_args="$@"
-ex "$OPT_START_CMD" \ -ex "$OPT_START_CMD" \
-ex "set confirm on" \ -ex "set confirm on" \
-ex "set pagination on" -ex "set pagination on"
fi

View file

@ -1,4 +1,5 @@
::@title qemu + gdb ::@title qemu + gdb
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>qemu</tt> and connect with <tt>gdb</tt></h3> ::@desc <h3>Launch with <tt>qemu</tt> and connect with <tt>gdb</tt></h3>
::@desc <p> ::@desc <p>
@ -10,7 +11,7 @@
::@menu-group cross ::@menu-group cross
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#gdb_qemu ::@help TraceRmiLauncherServicePlugin#gdb_qemu
::@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" ::@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_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env GHIDRA_LANG_EXTTOOL_qemu:file="" "QEMU command" "The path to qemu for the target architecture." ::@env GHIDRA_LANG_EXTTOOL_qemu:file="" "QEMU command" "The path to qemu for the target architecture."
::@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu" ::@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu"

View file

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
## ##
#@title qemu + gdb #@title qemu + gdb
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with <tt>qemu</tt> and connect with <tt>gdb</tt></h3> #@desc <h3>Launch with <tt>qemu</tt> and connect with <tt>gdb</tt></h3>
#@desc <p> #@desc <p>
@ -26,7 +27,7 @@
#@menu-group cross #@menu-group cross
#@icon icon.debugger #@icon icon.debugger
#@help TraceRmiLauncherServicePlugin#gdb_qemu #@help TraceRmiLauncherServicePlugin#gdb_qemu
#@arg :file "Image" "The target binary executable image" #@arg :file! "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target" #@args "Arguments" "Command-line arguments to pass to the target"
#@env GHIDRA_LANG_EXTTOOL_qemu:file="" "QEMU command" "The path to qemu for the target architecture." #@env GHIDRA_LANG_EXTTOOL_qemu:file="" "QEMU command" "The path to qemu for the target architecture."
#@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu" #@env QEMU_GDB:int=1234 "QEMU Port" "Port for gdb connection to qemu"

View file

@ -1,41 +0,0 @@
::@title raw gdb
::@no-image
::@desc <html><body width="300px">
::@desc <h3>Start <tt>gdb</tt></h3>
::@desc <p>
::@desc This will start <tt>gdb</tt> and connect to it.
::@desc It will not launch a target, so you can (must) set up your target manually.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group raw
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#gdb_raw
::@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH."
::@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
@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 "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^
-ex "ghidra trace start" ^
-ex "ghidra trace sync-enable" ^
-ex "set confirm on" ^
-ex "set pagination on"

View file

@ -1,57 +0,0 @@
#!/usr/bin/env bash
## ###
# 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.
##
#@title raw gdb
#@no-image
#@desc <html><body width="300px">
#@desc <h3>Start <tt>gdb</tt></h3>
#@desc <p>
#@desc This will start <tt>gdb</tt> and connect to it.
#@desc It will not launch a target, so you can (must) set up your target manually.
#@desc For setup instructions, press <b>F1</b>.
#@desc </p>
#@desc </body></html>
#@menu-group raw
#@icon icon.debugger
#@help TraceRmiLauncherServicePlugin#gdb_raw
#@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH."
#@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
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
"$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 "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \
-ex "ghidra trace start" \
-ex "ghidra trace sync-enable" \
-ex "set confirm on" \
-ex "set pagination on"

View file

@ -1,5 +1,4 @@
::@title remote gdb ::@title remote gdb
::@no-image
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with local <tt>gdb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3> ::@desc <h3>Launch with local <tt>gdb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3>
::@desc <p> ::@desc <p>
@ -14,7 +13,7 @@
::@env OPT_TARGET_TYPE:TargetType="remote" "Target" "The type of remote target" ::@env OPT_TARGET_TYPE:TargetType="remote" "Target" "The type of remote target"
::@env OPT_HOST:str="localhost" "Host" "The hostname of the target" ::@env OPT_HOST:str="localhost" "Host" "The hostname of the target"
::@env OPT_PORT:int=9999 "Port" "The host's listening port" ::@env OPT_PORT:int=9999 "Port" "The host's listening port"
::@env OPT_ARCH:str="" "Architecture (optional)" "Target architecture override" ::@env OPT_ARCH:str="auto" "Architecture" "Target architecture override"
::@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_GDB_PATH:file="gdb" "gdb command" "The path to gdb on the local system. Omit the full path to resolve using the system PATH."
@echo off @echo off
@ -30,19 +29,13 @@ IF EXIST %GHIDRA_HOME%\ghidra\.git (
) )
set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH% set PYTHONPATH=%PYTHONPATH1%;%PYTHONPATH0%;%PYTHONPATH%
IF "%OPT_ARCH%"=="" (
set archcmd=
) ELSE (
set archcmd=-ex "set arch %OPT_ARCH%"
)
"%OPT_GDB_PATH%" ^ "%OPT_GDB_PATH%" ^
-q ^ -q ^
-ex "set pagination off" ^ -ex "set pagination off" ^
-ex "set confirm off" ^ -ex "set confirm off" ^
-ex "show version" ^ -ex "show version" ^
-ex "python import ghidragdb" ^ -ex "python import ghidragdb" ^
%archcmd% ^ -ex "set arch %OPT_ARCH%" ^
-ex "echo Connecting to %OPT_HOST%:%OPT_PORT%... " ^ -ex "echo Connecting to %OPT_HOST%:%OPT_PORT%... " ^
-ex "target %OPT_TARGET_TYPE% %OPT_HOST%:%OPT_PORT%" ^ -ex "target %OPT_TARGET_TYPE% %OPT_HOST%:%OPT_PORT%" ^
-ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^ -ex "ghidra trace connect '%GHIDRA_TRACE_RMI_ADDR%'" ^

View file

@ -15,7 +15,6 @@
# limitations under the License. # limitations under the License.
## ##
#@title remote gdb #@title remote gdb
#@no-image
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with local <tt>gdb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3> #@desc <h3>Launch with local <tt>gdb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3>
#@desc <p> #@desc <p>
@ -30,7 +29,7 @@
#@env OPT_TARGET_TYPE:TargetType="remote" "Target" "The type of remote target" #@env OPT_TARGET_TYPE:TargetType="remote" "Target" "The type of remote target"
#@env OPT_HOST:str="localhost" "Host" "The hostname of the target" #@env OPT_HOST:str="localhost" "Host" "The hostname of the target"
#@env OPT_PORT:int=9999 "Port" "The host's listening port" #@env OPT_PORT:int=9999 "Port" "The host's listening port"
#@env OPT_ARCH:str="" "Architecture (optional)" "Target architecture override" #@env OPT_ARCH:str="auto" "Architecture" "Target architecture override"
#@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_GDB_PATH:file="gdb" "gdb command" "The path to gdb on the local system. Omit the full path to resolve using the system PATH."
if [ -d ${GHIDRA_HOME}/ghidra/.git ] if [ -d ${GHIDRA_HOME}/ghidra/.git ]
@ -46,20 +45,13 @@ else
export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH
fi fi
if [ -z "$OPT_ARCH" ]
then
archcmd=
else
archcmd=-ex "set arch $OPT_ARCH"
fi
"$OPT_GDB_PATH" \ "$OPT_GDB_PATH" \
-q \ -q \
-ex "set pagination off" \ -ex "set pagination off" \
-ex "set confirm off" \ -ex "set confirm off" \
-ex "show version" \ -ex "show version" \
-ex "python import ghidragdb" \ -ex "python import ghidragdb" \
$archcmd \ -ex "set arch $OPT_ARCH" \
-ex "echo Connecting to $OPT_HOST:$OPT_PORT... " \ -ex "echo Connecting to $OPT_HOST:$OPT_PORT... " \
-ex "target $OPT_TARGET_TYPE $OPT_HOST:$OPT_PORT" \ -ex "target $OPT_TARGET_TYPE $OPT_HOST:$OPT_PORT" \
-ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \

View file

@ -1,5 +1,6 @@
::@timeout 60000 ::@timeout 60000
::@title gdb via ssh ::@title gdb via ssh
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>gdb</tt> via <tt>ssh</tt></h3> ::@desc <h3>Launch with <tt>gdb</tt> via <tt>ssh</tt></h3>
::@desc <p> ::@desc <p>
@ -19,14 +20,31 @@
::@env OPT_EXTRA_SSH_ARGS:str="" "Extra ssh arguments" "Extra arguments to pass to ssh. Use with care." ::@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_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_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target."
::@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
@echo off @echo off
set cmd=TERM='%TERM%' '%OPT_GDB_PATH%' ^
IF "%OPT_TARGET_IMG%" == "" (
set cmd=TERM='%TERM%' '%OPT_GDB_PATH%' ^
-q ^ -q ^
-ex 'set pagination off' ^ -ex 'set pagination off' ^
-ex 'set confirm off' ^ -ex 'set confirm off' ^
-ex 'show version' ^ -ex 'show version' ^
-ex 'python import ghidragdb' ^ -ex 'python import ghidragdb' ^
-ex 'set architecture %OPT_ARCH%' ^
-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 'file \"%OPT_TARGET_IMG%\"' ^ -ex 'file \"%OPT_TARGET_IMG%\"' ^
-ex 'set args %OPT_TARGET_ARGS%' ^ -ex 'set args %OPT_TARGET_ARGS%' ^
-ex 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^ -ex 'ghidra trace connect \"localhost:%OPT_REMOTE_PORT%\"' ^
@ -35,5 +53,6 @@ set cmd=TERM='%TERM%' '%OPT_GDB_PATH%' ^
-ex '%OPT_START_CMD%' ^ -ex '%OPT_START_CMD%' ^
-ex 'set confirm on' ^ -ex 'set confirm on' ^
-ex 'set pagination on' -ex 'set pagination on'
)
"%OPT_SSH_PATH%" "-R%OPT_REMOTE_PORT%:%GHIDRA_TRACE_RMI_ADDR%" -t %OPT_EXTRA_SSH_ARGS% "%OPT_HOST%" "%cmd%" "%OPT_SSH_PATH%" "-R%OPT_REMOTE_PORT%:%GHIDRA_TRACE_RMI_ADDR%" -t %OPT_EXTRA_SSH_ARGS% "%OPT_HOST%" "%cmd%"

View file

@ -16,6 +16,7 @@
## ##
#@timeout 60000 #@timeout 60000
#@title gdb via ssh #@title gdb via ssh
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with <tt>gdb</tt> via <tt>ssh</tt></h3> #@desc <h3>Launch with <tt>gdb</tt> via <tt>ssh</tt></h3>
#@desc <p> #@desc <p>
@ -29,23 +30,40 @@
#@enum StartCmd:str run start starti #@enum StartCmd:str run start starti
#@arg :str "Image" "The target binary executable image on the remote system" #@arg :str "Image" "The target binary executable image on the remote system"
#@args "Arguments" "Command-line arguments to pass to the target" #@args "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_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_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_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_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_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_START_CMD:StartCmd="starti" "Run command" "The gdb command to actually run the target."
#@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
target_image="$1" target_image="$1"
shift shift
target_args="$@" target_args="$@"
"$OPT_SSH_PATH" "-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR" -t $OPT_EXTRA_SSH_ARGS "$OPT_HOST" "TERM='$TERM' '$OPT_GDB_PATH' \ 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 \ -q \
-ex 'set pagination off' \ -ex 'set pagination off' \
-ex 'set confirm off' \ -ex 'set confirm off' \
-ex 'show version' \ -ex 'show version' \
-ex 'python import ghidragdb' \ -ex 'python import ghidragdb' \
-ex 'set architecture $OPT_ARCH' \
-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 'file \"$target_image\"' \ -ex 'file \"$target_image\"' \
-ex 'set args $target_args' \ -ex 'set args $target_args' \
-ex 'ghidra trace connect \"localhost:$OPT_REMOTE_PORT\"' \ -ex 'ghidra trace connect \"localhost:$OPT_REMOTE_PORT\"' \
@ -54,3 +72,4 @@ target_args="$@"
-ex '$OPT_START_CMD' \ -ex '$OPT_START_CMD' \
-ex 'set confirm on' \ -ex 'set confirm on' \
-ex 'set pagination on'" -ex 'set pagination on'"
fi

View file

@ -1,5 +1,6 @@
::@timeout 60000 ::@timeout 60000
::@title gdb + gdbserver via ssh ::@title gdb + gdbserver via ssh
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with local <tt>gdb</tt> and <tt>gdbserver</tt> via <tt>ssh</tt></h3> ::@desc <h3>Launch with local <tt>gdb</tt> and <tt>gdbserver</tt> via <tt>ssh</tt></h3>
::@desc <p> ::@desc <p>
@ -10,7 +11,7 @@
::@menu-group remote ::@menu-group remote
::@icon icon.debugger ::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#gdb_gdbserver_ssh ::@help TraceRmiLauncherServicePlugin#gdb_gdbserver_ssh
::@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image on the remote system" ::@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_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_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_HOST:str="localhost" "[User@]Host" "The hostname or user@host"

View file

@ -16,6 +16,7 @@
## ##
#@timeout 60000 #@timeout 60000
#@title gdb + gdbserver via ssh #@title gdb + gdbserver via ssh
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with local <tt>gdb</tt> and <tt>gdbserver</tt> via <tt>ssh</tt></h3> #@desc <h3>Launch with local <tt>gdb</tt> and <tt>gdbserver</tt> via <tt>ssh</tt></h3>
#@desc <p> #@desc <p>
@ -26,9 +27,9 @@
#@menu-group remote #@menu-group remote
#@icon icon.debugger #@icon icon.debugger
#@help TraceRmiLauncherServicePlugin#gdb_gdbserver_ssh #@help TraceRmiLauncherServicePlugin#gdb_gdbserver_ssh
#@arg :str "Image" "The target binary executable image on the remote system" #@arg :str! "Image" "The target binary executable image on the remote system"
#@args "Arguments" "Command-line arguments to pass to the target" #@args "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_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_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_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_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."

View file

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
## ##
#@title wine + gdb #@title wine + gdb
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with <tt>gdb</tt> and <tt>wine</tt></h3> #@desc <h3>Launch with <tt>gdb</tt> and <tt>wine</tt></h3>
#@desc <p> #@desc <p>
@ -25,10 +26,11 @@
#@menu-group cross #@menu-group cross
#@icon icon.debugger #@icon icon.debugger
#@help TraceRmiLauncherServicePlugin#gdb_wine #@help TraceRmiLauncherServicePlugin#gdb_wine
#@arg :file "Image" "The target binary executable image" #@arg :file! "Image" "The target binary executable image"
#@args "Arguments" "Command-line arguments to pass to the target" #@args "Arguments" "Command-line arguments to pass to the target"
#@env OPT_WINE_PATH:file="/usr/lib/wine/wine64" "Path to wine binary" "The path to the wine executable for your target architecture." #@env OPT_WINE_PATH:file="/usr/lib/wine/wine64" "Path to wine binary" "The path to the wine executable for your target architecture."
#@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH." #@env OPT_GDB_PATH:file="gdb" "gdb command" "The path to gdb. Omit the full path to resolve using the system PATH."
#@env OPT_ARCH:str="i386:x86-64" "Architecture" "Target architecture"
#@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target." #@env OPT_EXTRA_TTY:bool=false "Inferior TTY" "Provide a separate terminal emulator for the target."
#@tty TTY_TARGET if env:OPT_EXTRA_TTY #@tty TTY_TARGET if env:OPT_EXTRA_TTY
@ -53,6 +55,7 @@ fi
-ex "set confirm off" \ -ex "set confirm off" \
-ex "show version" \ -ex "show version" \
-ex "python import ghidragdb.wine" \ -ex "python import ghidragdb.wine" \
-ex "set architecture $OPT_ARCH" \
-ex "file \"$OPT_WINE_PATH\"" \ -ex "file \"$OPT_WINE_PATH\"" \
-ex "set args $@" \ -ex "set args $@" \
-ex "set inferior-tty $TTY_TARGET" \ -ex "set inferior-tty $TTY_TARGET" \

View file

@ -1,4 +1,5 @@
::@title lldb ::@title lldb
::@image-opt arg:1
::@desc <html><body width="300px"> ::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>lldb</tt></h3> ::@desc <h3>Launch with <tt>lldb</tt></h3>
::@desc <p> ::@desc <p>
@ -14,8 +15,6 @@
::@args "Arguments" "Command-line arguments to pass to the target" ::@args "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_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." ::@env OPT_START_CMD:StartCmd="process launch" "Run command" "The lldb command to actually run the target."
::@env OPT_EXTRA_TTY:bool=false "Target TTY" "Provide a separate terminal emulator for the target."
::@tty TTY_TARGET if env:OPT_EXTRA_TTY
@echo off @echo off
set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src set PYTHONPATH0=%GHIDRA_HOME%\Ghidra\Debug\Debugger-agent-gdb\pypkg\src
@ -38,17 +37,21 @@ IF DEFINED target_args (
argspart=-o "settings set target.run-args %target_args%" argspart=-o "settings set target.run-args %target_args%"
) )
IF DEFINED TARGET_TTY ( IF "%target_image%"=="" (
ttypart=-o "settings set target.output-path %TTY_TARGET%" -o "settings set target.input-path $TTY_TARGET" "%OPT_LLDB_PATH%" ^
) -o "version" ^
-o "script import ghidralldb" ^
"%OPT_LLDB_PATH%" ^ -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^
-o "ghidra trace start" ^
-o "ghidra trace sync-enable" ^
) ELSE (
"%OPT_LLDB_PATH%" ^
-o "version" ^ -o "version" ^
-o "script import ghidralldb" ^ -o "script import ghidralldb" ^
-o "target create %target_image%" ^ -o "target create %target_image%" ^
%argspart% ^ %argspart% ^
%ttypart% ^
-o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^ -o "ghidra trace connect %GHIDRA_TRACE_RMI_ADDR%" ^
-o "ghidra trace start" ^ -o "ghidra trace start" ^
-o "ghidra trace sync-enable" ^ -o "ghidra trace sync-enable" ^
-o "%OPT_START_CMD%" -o "%OPT_START_CMD%"
)

View file

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
## ##
#@title lldb #@title lldb
#@image-opt arg:1
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with <tt>lldb</tt></h3> #@desc <h3>Launch with <tt>lldb</tt></h3>
#@desc <p> #@desc <p>
@ -64,7 +65,17 @@ else
ttypart=-o "settings set target.output-path $TTY_TARGET" -o "settings set target.input-path $TTY_TARGET" ttypart=-o "settings set target.output-path $TTY_TARGET" -o "settings set target.input-path $TTY_TARGET"
fi fi
"$OPT_LLDB_PATH" \ 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 "version" \
-o "script import ghidralldb" \ -o "script import ghidralldb" \
-o "target create \"$target_image\"" \ -o "target create \"$target_image\"" \
@ -74,3 +85,4 @@ fi
-o "ghidra trace start" \ -o "ghidra trace start" \
-o "ghidra trace sync-enable" \ -o "ghidra trace sync-enable" \
-o "$OPT_START_CMD" -o "$OPT_START_CMD"
fi

View file

@ -15,7 +15,6 @@
# limitations under the License. # limitations under the License.
## ##
#@title remote lldb #@title remote lldb
#@no-image
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Launch with local <tt>lldb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3> #@desc <h3>Launch with local <tt>lldb</tt> and connect to a stub (e.g., <tt>gdbserver</tt>)</h3>
#@desc <p> #@desc <p>
@ -60,4 +59,3 @@ fi
-o "ghidra trace start" \ -o "ghidra trace start" \
-o "ghidra trace sync-enable" \ -o "ghidra trace sync-enable" \
-o "ghidra trace sync-synth-stopped" -o "ghidra trace sync-synth-stopped"

View file

@ -17,6 +17,7 @@ package ghidra.debug.api;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public record ValStr<T>(T val, String str) { public record ValStr<T>(T val, String str) {
@ -56,4 +57,18 @@ public record ValStr<T>(T val, String str) {
.stream() .stream()
.collect(Collectors.toMap(Entry::getKey, e -> e.getValue().val())); .collect(Collectors.toMap(Entry::getKey, e -> e.getValue().val()));
} }
public static String normStr(ValStr<?> val) {
if (val == null) {
return "";
}
return val.normStr();
}
public String normStr() {
if (val == null) {
return "";
}
return Objects.toString(val);
}
} }

View file

@ -295,10 +295,29 @@ public interface TraceRmiLaunchOffer {
*/ */
Map<String, LaunchParameter<?>> getParameters(); Map<String, LaunchParameter<?>> getParameters();
/**
* If present, get the parameter via which this offer expects to receive the current program
*
* @return the parameter, or null
*/
LaunchParameter<?> imageParameter();
/**
* Check if this offer presents a parameter for the open program
*
* @return true if present
*/
default boolean supportsImage() {
return imageParameter() != null;
}
/** /**
* Check if this offer requires an open program * Check if this offer requires an open program
* *
* @return true if required * @return true if required
*/ */
boolean requiresImage(); default boolean requiresImage() {
LaunchParameter<?> param = imageParameter();
return param != null && param.required();
}
} }

View file

@ -16,7 +16,6 @@
## ##
#@title raw python #@title raw python
#@no-image
#@desc <html><body width="300px"> #@desc <html><body width="300px">
#@desc <h3>Start <tt>gdb</tt></h3> #@desc <h3>Start <tt>gdb</tt></h3>
#@desc <p> #@desc <p>

View file

@ -124,7 +124,7 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi
} }
@Override @Override
public boolean requiresImage() { public LaunchParameter<?> imageParameter() {
return !attrs.noImage(); return attrs.imageOpt();
} }
} }

View file

@ -57,7 +57,6 @@ import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer { public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer {
public static final String PARAM_DISPLAY_IMAGE = "Image";
public static final String PREFIX_PARAM_EXTTOOL = "env:GHIDRA_LANG_EXTTOOL_"; public static final String PREFIX_PARAM_EXTTOOL = "env:GHIDRA_LANG_EXTTOOL_";
public static final int DEFAULT_TIMEOUT_MILLIS = 10000; public static final int DEFAULT_TIMEOUT_MILLIS = 10000;
@ -299,15 +298,10 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
protected Map<String, ValStr<?>> generateDefaultLauncherArgs( protected Map<String, ValStr<?>> generateDefaultLauncherArgs(
Map<String, LaunchParameter<?>> params) { Map<String, LaunchParameter<?>> params) {
Map<String, ValStr<?>> map = new LinkedHashMap<>(); Map<String, ValStr<?>> map = new LinkedHashMap<>();
ImageParamSetter imageSetter = null;
for (Entry<String, LaunchParameter<?>> entry : params.entrySet()) { for (Entry<String, LaunchParameter<?>> entry : params.entrySet()) {
LaunchParameter<?> param = entry.getValue(); LaunchParameter<?> param = entry.getValue();
map.put(entry.getKey(), ValStr.cast(Object.class, param.defaultValue())); map.put(entry.getKey(), ValStr.cast(Object.class, param.defaultValue()));
if (PARAM_DISPLAY_IMAGE.equals(param.display())) { if (param.name().startsWith(PREFIX_PARAM_EXTTOOL)) {
imageSetter = ImageParamSetter.get(param);
// May still be null if type is not supported
}
else if (param.name().startsWith(PREFIX_PARAM_EXTTOOL)) {
String tool = param.name().substring(PREFIX_PARAM_EXTTOOL.length()); String tool = param.name().substring(PREFIX_PARAM_EXTTOOL.length());
List<String> names = List<String> names =
program.getLanguage().getLanguageDescription().getExternalNames(tool); program.getLanguage().getLanguageDescription().getExternalNames(tool);
@ -328,7 +322,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
} }
} }
} }
if (imageSetter != null && program != null) { if (supportsImage() && program != null) {
ImageParamSetter imageSetter = ImageParamSetter.get(imageParameter());
imageSetter.setImage(map, program); imageSetter.setImage(map, program);
} }
return map; return map;
@ -559,9 +554,18 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
return auto == null ? ByModuleAutoMapSpec.instance() : auto.getAutoMapSpec(trace); return auto == null ? ByModuleAutoMapSpec.instance() : auto.getAutoMapSpec(trace);
} }
protected void initializeMonitor(TaskMonitor monitor) { protected boolean providesImage(Map<String, ValStr<?>> args) {
LaunchParameter<?> param = imageParameter();
if (param == null) {
return false;
}
return !"".equals(param.get(args).str());
}
protected void updateMonitorMax(TaskMonitor monitor, Map<String, ValStr<?>> args) {
AutoMapSpec spec = getAutoMapSpec(); AutoMapSpec spec = getAutoMapSpec();
if (requiresImage() && spec.hasTask()) { boolean image = args == null ? supportsImage() : providesImage(args);
if (image && spec.hasTask()) {
monitor.setMaximum(6); monitor.setMaximum(6);
} }
else { else {
@ -621,7 +625,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
Trace trace = null; Trace trace = null;
Throwable lastExc = null; Throwable lastExc = null;
initializeMonitor(monitor); updateMonitorMax(monitor, null);
while (true) { while (true) {
try { try {
monitor.setMessage("Gathering arguments"); monitor.setMessage("Gathering arguments");
@ -633,6 +637,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
return new LaunchResult(program, sessions, acceptor, connection, trace, return new LaunchResult(program, sessions, acceptor, connection, trace,
lastExc); lastExc);
} }
updateMonitorMax(monitor, args);
monitor.increment(); monitor.increment();
acceptor = null; acceptor = null;

View file

@ -44,45 +44,46 @@ public abstract class ScriptAttributesParser {
public static final String ENV_GHIDRA_TRACE_RMI_HOST = "GHIDRA_TRACE_RMI_HOST"; 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 ENV_GHIDRA_TRACE_RMI_PORT = "GHIDRA_TRACE_RMI_PORT";
public static final String AT_TITLE = "@title";
public static final String AT_DESC = "@desc";
public static final String AT_MENU_PATH = "@menu-path";
public static final String AT_MENU_GROUP = "@menu-group";
public static final String AT_MENU_ORDER = "@menu-order";
public static final String AT_ICON = "@icon";
public static final String AT_HELP = "@help";
public static final String AT_ENUM = "@enum";
public static final String AT_ENV = "@env";
public static final String AT_ARG = "@arg"; public static final String AT_ARG = "@arg";
public static final String AT_ARGS = "@args"; public static final String AT_ARGS = "@args";
public static final String AT_TTY = "@tty"; public static final String AT_DESC = "@desc";
public static final String AT_ENUM = "@enum";
public static final String AT_ENV = "@env";
public static final String AT_HELP = "@help";
public static final String AT_ICON = "@icon";
public static final String AT_IMAGE_OPT = "@image-opt";
public static final String AT_MENU_GROUP = "@menu-group";
public static final String AT_MENU_ORDER = "@menu-order";
public static final String AT_MENU_PATH = "@menu-path";
public static final String AT_TITLE = "@title";
public static final String AT_TIMEOUT = "@timeout"; public static final String AT_TIMEOUT = "@timeout";
public static final String AT_NOIMAGE = "@no-image"; public static final String AT_TTY = "@tty";
public static final String PREFIX_ENV = "env:";
public static final String PREFIX_ARG = "arg:";
public static final String KEY_ARGS = "args"; public static final String KEY_ARGS = "args";
public static final String PREFIX_ARG = "arg:";
public static final String PREFIX_ENV = "env:";
public static final String MSGPAT_INVALID_HELP_SYNTAX = public static final String MSGPAT_DUPLICATE_TAG = "%s: Duplicate %s";
"%s: Invalid %s syntax. Use Topic#anchor";
public static final String MSGPAT_INVALID_ENUM_SYNTAX =
"%s: Invalid %s syntax. Use NAME:type Choice1 [ChoiceN...]";
public static final String MSGPAT_INVALID_ENV_SYNTAX =
"%s: Invalid %s syntax. Use NAME:type=default \"Display\" \"Tool Tip\"";
public static final String MSGPAT_INVALID_ARG_SYNTAX = public static final String MSGPAT_INVALID_ARG_SYNTAX =
"%s: Invalid %s syntax. Use :type \"Display\" \"Tool Tip\""; "%s: Invalid %s syntax. Use :type \"Display\" \"Tool Tip\"";
public static final String MSGPAT_INVALID_ARGS_SYNTAX = public static final String MSGPAT_INVALID_ARGS_SYNTAX =
"%s: Invalid %s syntax. Use \"Display\" \"Tool Tip\""; "%s: Invalid %s syntax. Use \"Display\" \"Tool Tip\"";
public static final String MSGPAT_INVALID_TTY_SYNTAX = public static final String MSGPAT_INVALID_ENUM_SYNTAX =
"%s: Invalid %s syntax. Use TTY_TARGET [if env:OPT [== VAL]]"; "%s: Invalid %s syntax. Use NAME:type Choice1 [ChoiceN...]";
public static final String MSGPAT_INVALID_ENV_SYNTAX =
"%s: Invalid %s syntax. Use NAME:type=default \"Display\" \"Tool Tip\"";
public static final String MSGPAT_INVALID_HELP_SYNTAX =
"%s: Invalid %s syntax. Use Topic#anchor";
public static final String MSGPAT_INVALID_TIMEOUT_SYNTAX = "" +
"%s: Invalid %s syntax. Use [milliseconds]";
public static final String MSGPAT_INVALID_TTY_BAD_VAL =
"%s: In %s: Parameter '%s' has type %s, but '%s' cannot be parsed as such";
public static final String MSGPAT_INVALID_TTY_NO_PARAM = public static final String MSGPAT_INVALID_TTY_NO_PARAM =
"%s: In %s: No such parameter '%s'"; "%s: In %s: No such parameter '%s'";
public static final String MSGPAT_INVALID_TTY_NOT_BOOL = public static final String MSGPAT_INVALID_TTY_NOT_BOOL =
"%s: In %s: Parameter '%s' must have bool type"; "%s: In %s: Parameter '%s' must have bool type";
public static final String MSGPAT_INVALID_TTY_BAD_VAL = public static final String MSGPAT_INVALID_TTY_SYNTAX =
"%s: In %s: Parameter '%s' has type %s, but '%s' cannot be parsed as such"; "%s: Invalid %s syntax. Use TTY_TARGET [if env:OPT [== VAL]]";
public static final String MSGPAT_INVALID_TIMEOUT_SYNTAX = "" +
"%s: Invalid %s syntax. Use [milliseconds]";
public static class ParseException extends Exception { public static class ParseException extends Exception {
private Location loc; private Location loc;
@ -289,8 +290,9 @@ public abstract class ScriptAttributesParser {
return tac.withCastDefault(new ValStr<>(value, defaultString)); return tac.withCastDefault(new ValStr<>(value, defaultString));
} }
public LaunchParameter<T> createParameter(String name, String display, String description) { public LaunchParameter<T> createParameter(String name, String display, String description,
return type.createParameter(name, display, description, false, defaultValue); boolean required) {
return type.createParameter(name, display, description, required, defaultValue);
} }
} }
@ -340,7 +342,7 @@ public abstract class ScriptAttributesParser {
public record ScriptAttributes(String title, String description, List<String> menuPath, public record ScriptAttributes(String title, String description, List<String> menuPath,
String menuGroup, String menuOrder, Icon icon, HelpLocation helpLocation, String menuGroup, String menuOrder, Icon icon, HelpLocation helpLocation,
Map<String, LaunchParameter<?>> parameters, Map<String, TtyCondition> extraTtys, Map<String, LaunchParameter<?>> parameters, Map<String, TtyCondition> extraTtys,
int timeoutMillis, boolean noImage) {} int timeoutMillis, LaunchParameter<?> imageOpt) {}
/** /**
* Convert an arguments map into a command line and environment variables * Convert an arguments map into a command line and environment variables
@ -371,7 +373,7 @@ public abstract class ScriptAttributesParser {
LaunchParameter<?> param; LaunchParameter<?> param;
for (int i = 1; (param = parameters.get("arg:" + i)) != null; i++) { for (int i = 1; (param = parameters.get("arg:" + i)) != null; i++) {
// Don't use ValStr.str here. I'd like the script's input normalized // Don't use ValStr.str here. I'd like the script's input normalized
commandLine.add(Objects.toString(param.get(args).val())); commandLine.add(param.get(args).normStr());
} }
param = parameters.get("args"); param = parameters.get("args");
@ -384,29 +386,24 @@ public abstract class ScriptAttributesParser {
if (key.startsWith(PREFIX_ENV)) { if (key.startsWith(PREFIX_ENV)) {
String varName = key.substring(PREFIX_ENV.length()); String varName = key.substring(PREFIX_ENV.length());
ValStr<?> val = ent.getValue().get(args); ValStr<?> val = ent.getValue().get(args);
if (val == null || val.val() == null) { env.put(varName, ValStr.normStr(val));
env.put(varName, "");
}
else {
env.put(varName, Objects.toString(val.val()));
}
} }
} }
} }
private int argc = 0; private int argc;
private String title; private String title;
private StringBuilder description; private StringBuilder description;
private List<String> menuPath;
private String menuGroup;
private String menuOrder;
private String iconId; private String iconId;
private HelpLocation helpLocation; private HelpLocation helpLocation;
private String menuGroup;
private String menuOrder;
private List<String> menuPath;
private final Map<String, UserType<?>> userTypes = new HashMap<>(); private final Map<String, UserType<?>> userTypes = new HashMap<>();
private final Map<String, LaunchParameter<?>> parameters = new LinkedHashMap<>(); private final Map<String, LaunchParameter<?>> parameters = new LinkedHashMap<>();
private final Map<String, TtyCondition> extraTtys = new LinkedHashMap<>(); private final Map<String, TtyCondition> extraTtys = new LinkedHashMap<>();
private int timeoutMillis = AbstractTraceRmiLaunchOffer.DEFAULT_TIMEOUT_MILLIS; private int timeoutMillis = AbstractTraceRmiLaunchOffer.DEFAULT_TIMEOUT_MILLIS;
private boolean noImage = false; private String imageOptKey;
/** /**
* Check if a line should just be ignored, e.g., blank lines, or the "shebang" line on UNIX. * Check if a line should just be ignored, e.g., blank lines, or the "shebang" line on UNIX.
@ -489,36 +486,66 @@ public abstract class ScriptAttributesParser {
return; return;
} }
if (parts.length == 1) { if (parts.length == 1) {
switch (parts[0].trim()) { parseUnrecognized(loc, comment);
case AT_NOIMAGE -> parseNoImage(loc);
default -> parseUnrecognized(loc, comment);
}
} }
else { else {
switch (parts[0].trim()) { switch (parts[0].trim()) {
case AT_TITLE -> parseTitle(loc, parts[1]);
case AT_DESC -> parseDesc(loc, parts[1]);
case AT_MENU_PATH -> parseMenuPath(loc, parts[1]);
case AT_MENU_GROUP -> parseMenuGroup(loc, parts[1]);
case AT_MENU_ORDER -> parseMenuOrder(loc, parts[1]);
case AT_ICON -> parseIcon(loc, parts[1]);
case AT_HELP -> parseHelp(loc, parts[1]);
case AT_ENUM -> parseEnum(loc, parts[1]);
case AT_ENV -> parseEnv(loc, parts[1]);
case AT_ARG -> parseArg(loc, parts[1], ++argc); case AT_ARG -> parseArg(loc, parts[1], ++argc);
case AT_ARGS -> parseArgs(loc, parts[1]); case AT_ARGS -> parseArgs(loc, parts[1]);
case AT_TTY -> parseTty(loc, parts[1]); case AT_DESC -> parseDesc(loc, parts[1]);
case AT_ENUM -> parseEnum(loc, parts[1]);
case AT_ENV -> parseEnv(loc, parts[1]);
case AT_HELP -> parseHelp(loc, parts[1]);
case AT_ICON -> parseIcon(loc, parts[1]);
case AT_IMAGE_OPT -> parseImageOpt(loc, parts[1]);
case AT_MENU_GROUP -> parseMenuGroup(loc, parts[1]);
case AT_MENU_ORDER -> parseMenuOrder(loc, parts[1]);
case AT_MENU_PATH -> parseMenuPath(loc, parts[1]);
case AT_TIMEOUT -> parseTimeout(loc, parts[1]); case AT_TIMEOUT -> parseTimeout(loc, parts[1]);
case AT_TITLE -> parseTitle(loc, parts[1]);
case AT_TTY -> parseTty(loc, parts[1]);
default -> parseUnrecognized(loc, comment); default -> parseUnrecognized(loc, comment);
} }
} }
} }
protected void parseTitle(Location loc, String str) { protected void parseArg(Location loc, String str, int argNum) {
if (title != null) { List<String> parts = ShellUtils.parseArgs(str);
reportWarning("%s: Duplicate %s".formatted(loc, AT_TITLE)); if (parts.size() != 3) {
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
return;
}
String colonType = parts.get(0).trim();
if (!colonType.startsWith(":")) {
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
return;
}
OptType<?> type;
boolean required = colonType.endsWith("!");
int endType = required ? colonType.length() - 1 : colonType.length();
try {
type = OptType.parse(loc, colonType.substring(1, endType), userTypes);
String name = PREFIX_ARG + argNum;
parameters.put(name, type.createParameter(name, parts.get(1), parts.get(2), required,
new ValStr<>(null, "")));
}
catch (ParseException e) {
reportError(e.getMessage());
}
}
protected void parseArgs(Location loc, String str) {
List<String> parts = ShellUtils.parseArgs(str);
if (parts.size() != 2) {
reportError(MSGPAT_INVALID_ARGS_SYNTAX.formatted(loc, AT_ARGS));
return;
}
LaunchParameter<String> parameter = BaseType.STRING.createParameter(
"args", parts.get(0), parts.get(1), false, ValStr.str(""));
if (parameters.put(KEY_ARGS, parameter) != null) {
reportWarning("%s: Duplicate %s. Replaced".formatted(loc, AT_ARGS));
} }
title = str;
} }
protected void parseDesc(Location loc, String str) { protected void parseDesc(Location loc, String str) {
@ -529,54 +556,6 @@ public abstract class ScriptAttributesParser {
description.append("\n"); description.append("\n");
} }
protected void parseMenuPath(Location loc, String str) {
if (menuPath != null) {
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_PATH));
}
menuPath = List.of(str.trim().split("\\."));
if (menuPath.isEmpty()) {
reportError(
"%s: Empty %s. Ignoring.".formatted(loc, AT_MENU_PATH));
}
}
protected void parseMenuGroup(Location loc, String str) {
if (menuGroup != null) {
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_GROUP));
}
menuGroup = str;
}
protected void parseMenuOrder(Location loc, String str) {
if (menuOrder != null) {
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_ORDER));
}
menuOrder = str;
}
protected void parseIcon(Location loc, String str) {
if (iconId != null) {
reportWarning("%s: Duplicate %s".formatted(loc, AT_ICON));
}
iconId = str.trim();
if (!Gui.hasIcon(iconId)) {
reportError(
"%s: Icon id %s not registered in the theme".formatted(loc, iconId));
}
}
protected void parseHelp(Location loc, String str) {
if (helpLocation != null) {
reportWarning("%s: Duplicate %s".formatted(loc, AT_HELP));
}
String[] parts = str.trim().split("#", 2);
if (parts.length != 2) {
reportError(MSGPAT_INVALID_HELP_SYNTAX.formatted(loc, AT_HELP));
return;
}
helpLocation = new HelpLocation(parts[0].trim(), parts[1].trim());
}
protected <T> UserType<T> parseEnumChoices(Location loc, BaseType<T> baseType, protected <T> UserType<T> parseEnumChoices(Location loc, BaseType<T> baseType,
List<String> choiceParts) { List<String> choiceParts) {
List<T> choices = new ArrayList<>(); List<T> choices = new ArrayList<>();
@ -642,10 +621,14 @@ public abstract class ScriptAttributesParser {
reportError(MSGPAT_INVALID_ENV_SYNTAX.formatted(loc, AT_ENV)); reportError(MSGPAT_INVALID_ENV_SYNTAX.formatted(loc, AT_ENV));
return; return;
} }
String typePart = tadParts[0].trim();
boolean required = typePart.endsWith("!");
int endType = required ? typePart.length() - 1 : typePart.length();
try { try {
TypeAndDefault<?> tad = TypeAndDefault<?> tad = TypeAndDefault.parse(loc, typePart.substring(0, endType),
TypeAndDefault.parse(loc, tadParts[0].trim(), tadParts[1].trim(), userTypes); tadParts[1].trim(), userTypes);
LaunchParameter<?> param = tad.createParameter(name, parts.get(1), parts.get(2)); LaunchParameter<?> param =
tad.createParameter(name, parts.get(1), parts.get(2), required);
if (parameters.put(name, param) != null) { if (parameters.put(name, param) != null) {
reportWarning("%s: Duplicate %s %s. Replaced.".formatted(loc, AT_ENV, trimmed)); reportWarning("%s: Duplicate %s %s. Replaced.".formatted(loc, AT_ENV, trimmed));
} }
@ -655,42 +638,75 @@ public abstract class ScriptAttributesParser {
} }
} }
protected void parseArg(Location loc, String str, int argNum) { protected void parseHelp(Location loc, String str) {
List<String> parts = ShellUtils.parseArgs(str); if (helpLocation != null) {
if (parts.size() != 3) { reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_HELP));
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG)); }
String[] parts = str.trim().split("#", 2);
if (parts.length != 2) {
reportError(MSGPAT_INVALID_HELP_SYNTAX.formatted(loc, AT_HELP));
return; return;
} }
String colonType = parts.get(0).trim(); helpLocation = new HelpLocation(parts[0].trim(), parts[1].trim());
if (!colonType.startsWith(":")) {
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
return;
} }
OptType<?> type;
protected void parseIcon(Location loc, String str) {
if (iconId != null) {
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_ICON));
}
iconId = str.trim();
if (!Gui.hasIcon(iconId)) {
reportError(
"%s: Icon id %s not registered in the theme".formatted(loc, iconId));
}
}
protected void parseImageOpt(Location loc, String str) {
if (imageOptKey != null) {
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_IMAGE_OPT));
}
imageOptKey = str.strip();
}
protected void parseMenuGroup(Location loc, String str) {
if (menuGroup != null) {
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_GROUP));
}
menuGroup = str;
}
protected void parseMenuOrder(Location loc, String str) {
if (menuOrder != null) {
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_ORDER));
}
menuOrder = str;
}
protected void parseMenuPath(Location loc, String str) {
if (menuPath != null) {
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_PATH));
}
menuPath = List.of(str.trim().split("\\."));
if (menuPath.isEmpty()) {
reportError(
"%s: Empty %s. Ignoring.".formatted(loc, AT_MENU_PATH));
}
}
protected void parseTimeout(Location loc, String str) {
try { try {
type = OptType.parse(loc, colonType.substring(1), userTypes); timeoutMillis = Integer.parseInt(str);
String name = PREFIX_ARG + argNum;
parameters.put(name,
type.createParameter(name, parts.get(1), parts.get(2), true,
new ValStr<>(null, "")));
} }
catch (ParseException e) { catch (NumberFormatException e) {
reportError(e.getMessage()); reportError(MSGPAT_INVALID_TIMEOUT_SYNTAX.formatted(loc, AT_TIMEOUT));
} }
} }
protected void parseArgs(Location loc, String str) { protected void parseTitle(Location loc, String str) {
List<String> parts = ShellUtils.parseArgs(str); if (title != null) {
if (parts.size() != 2) { reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_TITLE));
reportError(MSGPAT_INVALID_ARGS_SYNTAX.formatted(loc, AT_ARGS));
return;
}
LaunchParameter<String> parameter = BaseType.STRING.createParameter(
"args", parts.get(0), parts.get(1), false, ValStr.str(""));
if (parameters.put(KEY_ARGS, parameter) != null) {
reportWarning("%s: Duplicate %s. Replaced".formatted(loc, AT_ARGS));
} }
title = str;
} }
protected void putTty(Location loc, String name, TtyCondition condition) { protected void putTty(Location loc, String name, TtyCondition condition) {
@ -749,19 +765,6 @@ public abstract class ScriptAttributesParser {
reportError(MSGPAT_INVALID_TTY_SYNTAX.formatted(loc, AT_TTY)); reportError(MSGPAT_INVALID_TTY_SYNTAX.formatted(loc, AT_TTY));
} }
protected void parseTimeout(Location loc, String str) {
try {
timeoutMillis = Integer.parseInt(str);
}
catch (NumberFormatException e) {
reportError(MSGPAT_INVALID_TIMEOUT_SYNTAX.formatted(loc, AT_TIMEOUT));
}
}
protected void parseNoImage(Location loc) {
noImage = true;
}
protected void parseUnrecognized(Location loc, String line) { protected void parseUnrecognized(Location loc, String line) {
reportWarning("%s: Unrecognized metadata: %s".formatted(loc, line)); reportWarning("%s: Unrecognized metadata: %s".formatted(loc, line));
} }
@ -784,10 +787,18 @@ public abstract class ScriptAttributesParser {
if (iconId == null) { if (iconId == null) {
iconId = "icon.debugger"; iconId = "icon.debugger";
} }
LaunchParameter<?> imageOpt = null;
if (imageOptKey != null) {
imageOpt = parameters.get(imageOptKey);
if (imageOpt == null) {
reportError("%s: %s refers to %s, which is not a parameter name".formatted(fileName,
AT_IMAGE_OPT, imageOptKey));
}
}
return new ScriptAttributes(title, getDescription(), List.copyOf(menuPath), menuGroup, return new ScriptAttributes(title, getDescription(), List.copyOf(menuPath), menuGroup,
menuOrder, new GIcon(iconId), helpLocation, menuOrder, new GIcon(iconId), helpLocation,
Collections.unmodifiableMap(new LinkedHashMap<>(parameters)), Collections.unmodifiableMap(new LinkedHashMap<>(parameters)),
Collections.unmodifiableMap(new LinkedHashMap<>(extraTtys)), timeoutMillis, noImage); Collections.unmodifiableMap(new LinkedHashMap<>(extraTtys)), timeoutMillis, imageOpt);
} }
private String getDescription() { private String getDescription() {

View file

@ -637,6 +637,9 @@ public abstract class AbstractDebuggerParameterDialog<P> extends DialogComponent
protected void setEditorValue(PropertyEditor editor, P param, ValStr<?> val) { protected void setEditorValue(PropertyEditor editor, P param, ValStr<?> val) {
switch (val.val()) { switch (val.val()) {
case null -> { case null -> {
if (parameterType(param) == String.class) {
editor.setValue(val.str());
}
} }
case BigInteger bi -> editor.setAsText(val.str()); case BigInteger bi -> editor.setAsText(val.str());
default -> editor.setValue(val.val()); default -> editor.setValue(val.val());

View file

@ -30,8 +30,8 @@ public class TestTraceRmiLaunchOpinion implements TraceRmiLaunchOpinion {
public static class TestTraceRmiLaunchOffer extends AbstractTraceRmiLaunchOffer { public static class TestTraceRmiLaunchOffer extends AbstractTraceRmiLaunchOffer {
private static final LaunchParameter<String> PARAM_IMAGE = private static final LaunchParameter<String> PARAM_IMAGE =
LaunchParameter.create(String.class, "image", PARAM_DISPLAY_IMAGE, "Image to execute", LaunchParameter.create(String.class, "image", "Image", "Image to execute",
true, ValStr.str(""), str -> str); false, ValStr.str(""), str -> str);
public TestTraceRmiLaunchOffer(TraceRmiLauncherServicePlugin plugin, Program program) { public TestTraceRmiLaunchOffer(TraceRmiLauncherServicePlugin plugin, Program program) {
super(plugin, program); super(plugin, program);
@ -62,8 +62,8 @@ public class TestTraceRmiLaunchOpinion implements TraceRmiLaunchOpinion {
} }
@Override @Override
public boolean requiresImage() { public LaunchParameter<?> imageParameter() {
return false; return PARAM_IMAGE;
} }
@Override @Override