diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh new file mode 100755 index 0000000000..54bc6932b1 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/qemu-gdb.sh @@ -0,0 +1,78 @@ +#!/usr/bin/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 qemu + gdb +#@desc +#@desc

Launch with qemu and connect with gdb

+#@desc

This will launch the target on the local machine using qemu. Then in a second +#@desc terminal, it will connect gdb to QEMU's GDBstub. +#@desc GDB must already be installed on your system, it must support your target architecture +#@desc (you may install gdb-multiarch), and it must embed the Python 3 interpreter. You +#@desc will also need protobuf installed for Python 3. +#@desc +#@menu-group qemu +#@icon icon.debugger +#@help TraceRmiLauncherServicePlugin#gdb +#@enum StartCmd:str run start starti +#@arg :str "Image" "The target binary executable image" +#@args "Arguments" "Command-line arguments to pass to the target" +#@env GHIDRA_LANG_EXTTOOL_qemu:str="" "Path to qemu" "The path to qemu for the target architecture." +#@env QEMU_GDB:int=12345 "QEMU Port" "Port for gdb connection to qemu" +#@env OPT_EXTRA_QEMU_ARGS:str="" "Extra qemu arguments" "Extra arguments to pass to qemu. Use with care." +#@env OPT_GDB_PATH:str="gdb-multiarch" "Path to gdb" "The path to gdb. Omit the full path to resolve using the system PATH." +#@env OPT_EXTRA_TTY:bool=false "QEMU TTY" "Provide a separate terminal emulator for the target." +#@tty TTY_TARGET if env:OPT_EXTRA_TTY + +if [ -d ${GHIDRA_HOME}/ghidra/.git ] +then + export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH + export PYTHONPATH=$GHIDRA_HOME/ghidra/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH +elif [ -d ${GHIDRA_HOME}/.git ] +then + export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/build/pypkg/src:$PYTHONPATH + export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/build/pypkg/src:$PYTHONPATH +else + export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-agent-gdb/pypkg/src:$PYTHONPATH + export PYTHONPATH=$GHIDRA_HOME/Ghidra/Debug/Debugger-rmi-trace/pypkg/src:$PYTHONPATH +fi + +target_image="$1" + +if [ -z "$TTY_TARGET" ] +then + "$GHIDRA_LANG_EXTTOOL_qemu" $@ & +else + "$GHIDRA_LANG_EXTTOOL_qemu" $@ <$TTY_TARGET >$TTY_TARGET 2>&1 & +fi + +# Give QEMU a moment to open the socket +sleep 0.1 + +"$OPT_GDB_PATH" \ + -q \ + -ex "set pagination off" \ + -ex "set confirm off" \ + -ex "show version" \ + -ex "python import ghidragdb" \ + -ex "file \"$target_image\"" \ + -ex "set args $target_args" \ + -ex "set inferior-tty $TTY_TARGET" \ + -ex "ghidra trace connect \"$GHIDRA_TRACE_RMI_ADDR\"" \ + -ex "ghidra trace start" \ + -ex "ghidra trace sync-enable" \ + -ex "target remote localhost:$QEMU_GDB" \ + -ex "set confirm on" \ + -ex "set pagination on" diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/hooks.py b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/hooks.py index 96a282006d..f861bb550f 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/hooks.py +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/hooks.py @@ -513,7 +513,8 @@ def install_hooks(): gdb.events.exited.connect(on_exited) # Inferior exited gdb.events.clear_objfiles.connect(on_clear_objfiles) - gdb.events.free_objfile.connect(on_free_objfile) + if hasattr(gdb.events, 'free_objfile'): + gdb.events.free_objfile.connect(on_free_objfile) gdb.events.new_objfile.connect(on_new_objfile) gdb.events.breakpoint_created.connect(on_breakpoint_created) @@ -547,7 +548,8 @@ def remove_hooks(): gdb.events.exited.disconnect(on_exited) # Inferior exited gdb.events.clear_objfiles.disconnect(on_clear_objfiles) - gdb.events.free_objfile.disconnect(on_free_objfile) + if hasattr(gdb.events, 'free_objfile'): + gdb.events.free_objfile.disconnect(on_free_objfile) gdb.events.new_objfile.disconnect(on_new_objfile) gdb.events.breakpoint_created.disconnect(on_breakpoint_created) diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractScriptTraceRmiLaunchOffer.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractScriptTraceRmiLaunchOffer.java index fcd6bd8e60..ee2e90b327 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractScriptTraceRmiLaunchOffer.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractScriptTraceRmiLaunchOffer.java @@ -102,6 +102,7 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi List commandLine = new ArrayList<>(); Map env = new HashMap<>(System.getenv()); prepareSubprocess(commandLine, env, args, address); + env.put("GHIDRA_LANGUAGE_ID", program.getLanguageID().toString()); for (Map.Entry ent : attrs.extraTtys().entrySet()) { if (!ent.getValue().isActive(args)) { diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java index ab6ac8dc99..1aab3f8287 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/gui/tracermi/launcher/AbstractTraceRmiLaunchOffer.java @@ -64,6 +64,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer public static final String PREFIX_DBGLAUNCH = "DBGLAUNCH_"; public static final String PARAM_DISPLAY_IMAGE = "Image"; + public static final String PREFIX_PARAM_EXTTOOL = "env:GHIDRA_LANG_EXTTOOL_"; + public static final int DEFAULT_TIMEOUT_MILLIS = 10000; protected record PtyTerminalSession(Terminal terminal, Pty pty, PtySession session, @@ -273,6 +275,15 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer } paramImage = (ParameterDescription) param; } + else if (param.name.startsWith(PREFIX_PARAM_EXTTOOL)) { + String tool = param.name.substring(PREFIX_PARAM_EXTTOOL.length()); + List names = + program.getLanguage().getLanguageDescription().getExternalNames(tool); + if (names != null && !names.isEmpty()) { + var paramStr = (ParameterDescription) param; + paramStr.set(map, names.get(0)); + } + } } if (paramImage != null) { File imageFile = TraceRmiLauncherServicePlugin.getProgramPath(program); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java index 3a3465f593..4f49a8aca8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java @@ -31,6 +31,16 @@ import ghidra.trace.model.modules.TraceModule; public class DefaultModuleMapProposal extends AbstractMapProposal implements ModuleMapProposal { + protected static final int BLOCK_BITS = 12; + protected static final int BLOCK_SIZE = 1 << BLOCK_BITS; + protected static final long BLOCK_MASK = -1L << BLOCK_BITS; + + protected static AddressRange quantize(AddressRange range) { + AddressSpace space = range.getAddressSpace(); + Address min = space.getAddress(range.getMinAddress().getOffset() & BLOCK_MASK); + Address max = space.getAddress(range.getMaxAddress().getOffset() | ~BLOCK_MASK); + return new AddressRangeImpl(min, max); + } /** * A module-program entry in a proposed module map @@ -129,8 +139,8 @@ public class DefaultModuleMapProposal public void setProgram(Program program) { setToObject(program, program); try { - this.moduleRange = - new AddressRangeImpl(getModule().getBase(), computeImageSize(program)); + this.moduleRange = quantize( + new AddressRangeImpl(getModule().getBase(), computeImageSize(program))); } catch (AddressOverflowException e) { // This is terribly unlikely @@ -203,7 +213,7 @@ public class DefaultModuleMapProposal private void processModule() { moduleBase = module.getBase(); try { - moduleRange = new AddressRangeImpl(moduleBase, imageSize); + moduleRange = quantize(new AddressRangeImpl(moduleBase, imageSize)); } catch (AddressOverflowException e) { return; // Just score it as having no matches? diff --git a/Ghidra/Processors/68000/data/languages/68000.ldefs b/Ghidra/Processors/68000/data/languages/68000.ldefs index c93a4c0df0..075e521cbe 100644 --- a/Ghidra/Processors/68000/data/languages/68000.ldefs +++ b/Ghidra/Processors/68000/data/languages/68000.ldefs @@ -17,6 +17,7 @@ + + + + diff --git a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs index a33d0cac6a..da3a7b1b3b 100644 --- a/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs +++ b/Ghidra/Processors/AARCH64/data/languages/AARCH64.ldefs @@ -14,6 +14,7 @@ + + + + diff --git a/Ghidra/Processors/ARM/data/languages/ARM.ldefs b/Ghidra/Processors/ARM/data/languages/ARM.ldefs index 3705510473..972573ac56 100644 --- a/Ghidra/Processors/ARM/data/languages/ARM.ldefs +++ b/Ghidra/Processors/ARM/data/languages/ARM.ldefs @@ -23,6 +23,7 @@ + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Loongarch/data/languages/loongarch.ldefs b/Ghidra/Processors/Loongarch/data/languages/loongarch.ldefs index e49fbe075b..e0ea214f42 100644 --- a/Ghidra/Processors/Loongarch/data/languages/loongarch.ldefs +++ b/Ghidra/Processors/Loongarch/data/languages/loongarch.ldefs @@ -41,6 +41,7 @@ Loongson 3 64-bit with 32-bit FP + Loongson 3 64-bit with 64-bit FP + \ No newline at end of file diff --git a/Ghidra/Processors/MIPS/data/languages/mips.ldefs b/Ghidra/Processors/MIPS/data/languages/mips.ldefs index 17cbf93a8f..bb5e61c939 100644 --- a/Ghidra/Processors/MIPS/data/languages/mips.ldefs +++ b/Ghidra/Processors/MIPS/data/languages/mips.ldefs @@ -17,6 +17,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Sparc/data/languages/SparcV9.ldefs b/Ghidra/Processors/Sparc/data/languages/SparcV9.ldefs index 9121216ec6..2477899954 100644 --- a/Ghidra/Processors/Sparc/data/languages/SparcV9.ldefs +++ b/Ghidra/Processors/Sparc/data/languages/SparcV9.ldefs @@ -14,6 +14,7 @@ + + diff --git a/Ghidra/Processors/SuperH4/data/languages/SuperH4.ldefs b/Ghidra/Processors/SuperH4/data/languages/SuperH4.ldefs index d51da4fc99..e1ab74b65d 100644 --- a/Ghidra/Processors/SuperH4/data/languages/SuperH4.ldefs +++ b/Ghidra/Processors/SuperH4/data/languages/SuperH4.ldefs @@ -14,6 +14,7 @@ + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs b/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs index 45830597eb..94989266b8 100644 --- a/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs @@ -14,6 +14,7 @@ + + diff --git a/Ghidra/Processors/x86/data/languages/x86.ldefs b/Ghidra/Processors/x86/data/languages/x86.ldefs index 85c0c6801b..49e851632a 100644 --- a/Ghidra/Processors/x86/data/languages/x86.ldefs +++ b/Ghidra/Processors/x86/data/languages/x86.ldefs @@ -30,6 +30,7 @@ + +