From fb9a7c62a282e204599de542d62bc36248b6f381 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:15:45 +0000 Subject: [PATCH] GP-4546: Add 'Set breakpoint' multi-action to Breakpoints window. --- .../src/main/py/src/ghidradbg/methods.py | 52 ++-- .../src/main/py/src/ghidragdb/methods.py | 30 ++- .../src/main/py/src/ghidralldb/methods.py | 42 +-- .../ghidra/debug/api/target/ActionName.java | 244 ++++++++++++++---- .../java/ghidra/debug/api/target/Target.java | 94 +++++-- .../debug/api/tracermi/RemoteMethod.java | 16 ++ .../ghidra/debug/flatapi/FlatDebuggerAPI.java | 13 +- .../ghidra/dbg/jdi/rmi/jpda/JdiConnector.java | 14 +- .../core/debug/client/tracermi/RmiClient.java | 6 +- .../client/tracermi/RmiMethodRegistry.java | 4 + .../client/tracermi/RmiRemoteMethod.java | 31 ++- .../service/tracermi/RecordRemoteMethod.java | 25 +- .../service/tracermi/TraceRmiHandler.java | 5 +- .../service/tracermi/TraceRmiTarget.java | 155 +++++++---- .../src/main/proto/trace-rmi.proto | 6 +- .../src/main/py/src/ghidratrace/client.py | 28 +- .../tracermi/TestTraceRmiConnection.java | 17 ++ .../DebuggerBreakpointsPlugin.html | 7 + .../images/DebuggerBreakpointsPlugin.png | Bin 28715 -> 30412 bytes .../debug/gui/InvokeActionEntryAction.java | 39 +++ .../DebuggerBreakpointsProvider.java | 78 ++++++ .../gui/control/DebuggerControlPlugin.java | 5 +- .../control/DebuggerMethodActionsPlugin.java | 37 +-- .../gui/control/TargetDockingAction.java | 6 +- .../trace/model/TraceExecutionState.java | 68 +---- .../DebuggerMethodActionsPluginTest.java | 12 +- .../Debugger/A1-GettingStarted.html | 3 +- .../GhidraClass/Debugger/A2-UITour.html | 3 +- .../GhidraClass/Debugger/A3-Breakpoints.html | 31 ++- .../GhidraClass/Debugger/A3-Breakpoints.md | 3 +- .../GhidraClass/Debugger/A4-MachineState.html | 3 +- .../GhidraClass/Debugger/A5-Navigation.html | 3 +- .../GhidraClass/Debugger/A6-MemoryMap.html | 3 +- .../Debugger/B1-RemoteTargets.html | 3 +- .../GhidraClass/Debugger/B2-Emulation.html | 3 +- .../GhidraClass/Debugger/B3-Scripting.html | 5 +- .../GhidraClass/Debugger/B3-Scripting.md | 2 +- .../GhidraClass/Debugger/B4-Modeling.html | 85 +++--- .../ghidra_scripts/ZeroTimerScript.java | 6 +- .../images/Breakpoints_EmptyAfterLaunch.png | Bin 14679 -> 16326 bytes .../images/Breakpoints_PopAfterSRandRand.png | Bin 24384 -> 26447 bytes .../Breakpoints_SyncedAfterImportLibC.png | Bin 218844 -> 217291 bytes .../GettingStarted_DisassemblyAfterLaunch.png | Bin 203605 -> 210345 bytes .../images/GettingStarted_ToolWSpecimen.png | Bin 129396 -> 136294 bytes 44 files changed, 785 insertions(+), 402 deletions(-) create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/InvokeActionEntryAction.java diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py index 5326cc5be5..b98cfa1c93 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py @@ -144,8 +144,8 @@ def find_thread_by_regs_obj(object): def find_frame_by_level(level): for f in util.dbg._base.backtrace_list(): if f.FrameNumber == level: - return f - #return dbg().backtrace_list()[level] + return f + # return dbg().backtrace_list()[level] def find_frame_by_pattern(pattern, object, err_msg): @@ -206,8 +206,8 @@ def execute(cmd: str, to_string: bool=False): @REGISTRY.method(action='evaluate', display='Evaluate') # @util.dbg.eng_thread def evaluate( - session: sch.Schema('Session'), - expr: ParamDesc(str, display='Expr')): + session: sch.Schema('Session'), + expr: ParamDesc(str, display='Expr')): """Evaluate a Python3 expression.""" return str(eval(expr, shared_globals)) @@ -328,8 +328,8 @@ def remove_process(process: sch.Schema('Process')): @REGISTRY.method(action='connect', display='Connect') @util.dbg.eng_thread def target( - session: sch.Schema('Session'), - cmd: ParamDesc(str, display='Command')): + session: sch.Schema('Session'), + cmd: ParamDesc(str, display='Command')): """Connect to a target machine or process.""" dbg().attach_kernel(cmd) @@ -345,8 +345,8 @@ def attach_obj(target: sch.Schema('Attachable')): @REGISTRY.method(action='attach', display='Attach by pid') @util.dbg.eng_thread def attach_pid( - session: sch.Schema('Session'), - pid: ParamDesc(str, display='PID')): + session: sch.Schema('Session'), + pid: ParamDesc(str, display='PID')): """Attach the process to the given target.""" dbg().attach_proc(int(pid)) @@ -354,8 +354,8 @@ def attach_pid( @REGISTRY.method(action='attach', display='Attach by name') @util.dbg.eng_thread def attach_name( - session: sch.Schema('Session'), - name: ParamDesc(str, display='Name')): + session: sch.Schema('Session'), + name: ParamDesc(str, display='Name')): """Attach the process to the given target.""" dbg().attach_proc(name) @@ -369,7 +369,7 @@ def detach(process: sch.Schema('Process')): @REGISTRY.method(action='launch', display='Launch') def launch_loader( - session: sch.Schema('Session'), + session: sch.Schema('Session'), file: ParamDesc(str, display='File'), args: ParamDesc(str, display='Arguments')=''): """ @@ -383,7 +383,7 @@ def launch_loader( @REGISTRY.method(action='launch', display='LaunchEx') def launch( - session: sch.Schema('Session'), + session: sch.Schema('Session'), file: ParamDesc(str, display='File'), args: ParamDesc(str, display='Arguments')='', initial_break: ParamDesc(bool, display='Initial Break')=True, @@ -405,7 +405,7 @@ def kill(process: sch.Schema('Process')): commands.ghidra_trace_kill() -@REGISTRY.method(action='resume') +@REGISTRY.method(action='resume', display="Go") def go(process: sch.Schema('Process')): """Continue execution of the process.""" util.dbg.run_async(lambda: dbg().go()) @@ -456,7 +456,7 @@ def break_address(process: sch.Schema('Process'), address: Address): dbg().bp(expr=address.offset) -@REGISTRY.method(action='break_sw_execute') +@REGISTRY.method(action='break_ext', display='Set Breakpoint') @util.dbg.eng_thread def break_expression(expression: str): """Set a breakpoint.""" @@ -472,7 +472,7 @@ def break_hw_address(process: sch.Schema('Process'), address: Address): dbg().ba(expr=address.offset) -@REGISTRY.method(action='break_hw_execute') +@REGISTRY.method(action='break_ext', display='Set Hardware Breakpoint') @util.dbg.eng_thread def break_hw_expression(expression: str): """Set a hardware-assisted breakpoint.""" @@ -482,50 +482,50 @@ def break_hw_expression(expression: str): @REGISTRY.method(action='break_read') @util.dbg.eng_thread def break_read_range(process: sch.Schema('Process'), range: AddressRange): - """Set a read watchpoint.""" + """Set a read breakpoint.""" find_proc_by_obj(process) dbg().ba(expr=range.min, size=range.length(), access=DbgEng.DEBUG_BREAK_READ) -@REGISTRY.method(action='break_read') +@REGISTRY.method(action='break_ext', display='Set Read Breakpoint') @util.dbg.eng_thread def break_read_expression(expression: str): - """Set a read watchpoint.""" + """Set a read breakpoint.""" dbg().ba(expr=expression, access=DbgEng.DEBUG_BREAK_READ) @REGISTRY.method(action='break_write') @util.dbg.eng_thread def break_write_range(process: sch.Schema('Process'), range: AddressRange): - """Set a watchpoint.""" + """Set a write breakpoint.""" find_proc_by_obj(process) dbg().ba(expr=range.min, size=range.length(), access=DbgEng.DEBUG_BREAK_WRITE) -@REGISTRY.method(action='break_write') +@REGISTRY.method(action='break_ext', display='Set Write Breakpoint') @util.dbg.eng_thread def break_write_expression(expression: str): - """Set a watchpoint.""" + """Set a write breakpoint.""" dbg().ba(expr=expression, access=DbgEng.DEBUG_BREAK_WRITE) @REGISTRY.method(action='break_access') @util.dbg.eng_thread def break_access_range(process: sch.Schema('Process'), range: AddressRange): - """Set an access watchpoint.""" + """Set an access breakpoint.""" find_proc_by_obj(process) dbg().ba(expr=range.min, size=range.length(), access=DbgEng.DEBUG_BREAK_READ | DbgEng.DEBUG_BREAK_WRITE) -@REGISTRY.method(action='break_access') +@REGISTRY.method(action='break_ext', display='Set Access Breakpoint') @util.dbg.eng_thread def break_access_expression(expression: str): - """Set an access watchpoint.""" + """Set an access breakpoint.""" dbg().ba(expr=expression, access=DbgEng.DEBUG_BREAK_READ | DbgEng.DEBUG_BREAK_WRITE) -@REGISTRY.method(action='toggle') +@REGISTRY.method(action='toggle', display='Toggle Breakpoint') @util.dbg.eng_thread def toggle_breakpoint(breakpoint: sch.Schema('BreakpointSpec'), enabled: bool): """Toggle a breakpoint.""" @@ -536,7 +536,7 @@ def toggle_breakpoint(breakpoint: sch.Schema('BreakpointSpec'), enabled: bool): dbg().bd(bpt.GetId()) -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display='Delete Breakpoint') @util.dbg.eng_thread def delete_breakpoint(breakpoint: sch.Schema('BreakpointSpec')): """Delete a breakpoint.""" diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py index a019d4b160..30263b3fe0 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py @@ -391,19 +391,19 @@ def refresh_sections(node: sch.Schema('Module')): gdb.execute(f'ghidra trace put-sections "{modname}"') -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display="Activate Inferior") def activate_inferior(inferior: sch.Schema('Inferior')): """Switch to the inferior.""" switch_inferior(find_inf_by_obj(inferior)) -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display="Activate Thread") def activate_thread(thread: sch.Schema('Thread')): """Switch to the thread.""" find_thread_by_obj(thread).switch() -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display="Activate Frame") def activate_frame(frame: sch.Schema('StackFrame')): """Select the frame.""" find_frame_by_obj(frame).select() @@ -415,7 +415,7 @@ def add_inferior(container: sch.Schema('InferiorContainer')): gdb.execute('add-inferior') -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display="Delete Inferior") def delete_inferior(inferior: sch.Schema('Inferior')): """Remove the inferior.""" inf = find_inf_by_obj(inferior) @@ -433,7 +433,7 @@ def connect(inferior: sch.Schema('Inferior'), spec: str): @REGISTRY.method(action='attach', display='Attach') def attach_obj(target: sch.Schema('Attachable')): """Attach the inferior to the given target.""" - #switch_inferior(find_inf_by_obj(inferior)) + # switch_inferior(find_inf_by_obj(inferior)) pid = find_availpid_by_obj(target) gdb.execute(f'attach {pid}') @@ -577,7 +577,7 @@ def break_sw_execute_address(inferior: sch.Schema('Inferior'), address: Address) gdb.execute(f'break *0x{offset:x}') -@REGISTRY.method(action='break_sw_execute') +@REGISTRY.method(action='break_ext', display="Set Breakpoint") def break_sw_execute_expression(expression: str): """Set a breakpoint (break).""" # TODO: Escape? @@ -592,7 +592,7 @@ def break_hw_execute_address(inferior: sch.Schema('Inferior'), address: Address) gdb.execute(f'hbreak *0x{offset:x}') -@REGISTRY.method(action='break_hw_execute') +@REGISTRY.method(action='break_ext', display="Set Hardware Breakpoint") def break_hw_execute_expression(expression: str): """Set a hardware-assisted breakpoint (hbreak).""" # TODO: Escape? @@ -609,7 +609,7 @@ def break_read_range(inferior: sch.Schema('Inferior'), range: AddressRange): f'rwatch -location *((char(*)[{range.length()}]) 0x{offset_start:x})') -@REGISTRY.method(action='break_read') +@REGISTRY.method(action='break_ext', display="Set Read Watchpoint") def break_read_expression(expression: str): """Set a read watchpoint (rwatch).""" gdb.execute(f'rwatch {expression}') @@ -625,7 +625,7 @@ def break_write_range(inferior: sch.Schema('Inferior'), range: AddressRange): f'watch -location *((char(*)[{range.length()}]) 0x{offset_start:x})') -@REGISTRY.method(action='break_write') +@REGISTRY.method(action='break_ext', display="Set Watchpoint") def break_write_expression(expression: str): """Set a watchpoint (watch).""" gdb.execute(f'watch {expression}') @@ -641,7 +641,7 @@ def break_access_range(inferior: sch.Schema('Inferior'), range: AddressRange): f'awatch -location *((char(*)[{range.length()}]) 0x{offset_start:x})') -@REGISTRY.method(action='break_access') +@REGISTRY.method(action='break_ext', display="Set Access Watchpoint") def break_access_expression(expression: str): """Set an access watchpoint (awatch).""" gdb.execute(f'awatch {expression}') @@ -653,21 +653,23 @@ def break_event(inferior: sch.Schema('Inferior'), spec: str): gdb.execute(f'catch {spec}') -@REGISTRY.method(action='toggle') +@REGISTRY.method(action='toggle', display="Toggle Breakpoint") def toggle_breakpoint(breakpoint: sch.Schema('BreakpointSpec'), enabled: bool): """Toggle a breakpoint.""" bpt = find_bpt_by_obj(breakpoint) bpt.enabled = enabled -@REGISTRY.method(action='toggle', condition=util.GDB_VERSION.major >= 13) +@REGISTRY.method(action='toggle', display="Toggle Breakpoint Location", + condition=util.GDB_VERSION.major >= 13) def toggle_breakpoint_location(location: sch.Schema('BreakpointLocation'), enabled: bool): """Toggle a breakpoint location.""" loc = find_bpt_loc_by_obj(location) loc.enabled = enabled -@REGISTRY.method(action='toggle', condition=util.GDB_VERSION.major < 13) +@REGISTRY.method(action='toggle', display="Toggle Breakpoint Location", + condition=util.GDB_VERSION.major < 13) def toggle_breakpoint_location(location: sch.Schema('BreakpointLocation'), enabled: bool): """Toggle a breakpoint location.""" bptnum, locnum = find_bptlocnum_by_obj(location) @@ -675,7 +677,7 @@ def toggle_breakpoint_location(location: sch.Schema('BreakpointLocation'), enabl gdb.execute(f'{cmd} {bptnum}.{locnum}') -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display="Delete Breakpoint") def delete_breakpoint(breakpoint: sch.Schema('BreakpointSpec')): """Delete a breakpoint.""" bpt = find_bpt_by_obj(breakpoint) diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py index 66592d6d9a..4a0e04c2fe 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/methods.py @@ -17,11 +17,11 @@ from concurrent.futures import Future, ThreadPoolExecutor import re import sys +import lldb + from ghidratrace import sch from ghidratrace.client import MethodRegistry, ParamDesc, Address, AddressRange -import lldb - from . import commands, util @@ -248,7 +248,7 @@ def execute(cmd: str, to_string: bool=False): return exec_convert_errors(cmd, to_string) -@REGISTRY.method +@REGISTRY.method(display='Evaluate') def evaluate(expr: str): """Evaluate an expression.""" value = util.get_target().EvaluateExpression(expr) @@ -257,7 +257,7 @@ def evaluate(expr: str): return commands.convert_value(value) -@REGISTRY.method +@REGISTRY.method(display="Python Evaluate") def pyeval(expr: str): return eval(expr) @@ -345,28 +345,28 @@ def refresh_modules(node: sch.Schema('ModuleContainer')): exec_convert_errors('ghidra trace put-modules') -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display='Activate Process') def activate_process(process: sch.Schema('Process')): """Switch to the process.""" # TODO return -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display='Activate Thread') def activate_thread(thread: sch.Schema('Thread')): """Switch to the thread.""" t = find_thread_by_obj(thread) t.process.SetSelectedThread(t) -@REGISTRY.method(action='activate') +@REGISTRY.method(action='activate', display='Activate Frame') def activate_frame(frame: sch.Schema('StackFrame')): """Select the frame.""" f = find_frame_by_obj(frame) f.thread.SetSelectedFrame(f.GetFrameID()) -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display='Remove Process') def remove_process(process: sch.Schema('Process')): """Remove the process.""" proc = find_proc_by_obj(process) @@ -442,7 +442,7 @@ def kill(process: sch.Schema('Process')): exec_convert_errors('process kill') -@REGISTRY.method(name='continue', action='resume') +@REGISTRY.method(name='continue', action='resume', display="Continue") def _continue(process: sch.Schema('Process')): """Continue execution of the process.""" exec_convert_errors('process continue') @@ -510,7 +510,7 @@ def break_address(process: sch.Schema('Process'), address: Address): exec_convert_errors(f'breakpoint set -a 0x{offset:x}') -@REGISTRY.method(action='break_sw_execute') +@REGISTRY.method(action='break_ext', display='Set Breakpoint') def break_expression(expression: str): """Set a breakpoint.""" # TODO: Escape? @@ -525,7 +525,7 @@ def break_hw_address(process: sch.Schema('Process'), address: Address): exec_convert_errors(f'breakpoint set -H -a 0x{offset:x}') -@REGISTRY.method(action='break_hw_execute') +@REGISTRY.method(action='break_ext', display='Set Hardware Breakpoint') def break_hw_expression(expression: str): """Set a hardware-assisted breakpoint.""" # TODO: Escape? @@ -543,7 +543,7 @@ def break_read_range(process: sch.Schema('Process'), range: AddressRange): f'watchpoint set expression -s {sz} -w read -- {offset_start}') -@REGISTRY.method(action='break_read') +@REGISTRY.method(action='break_ext', display='Set Read Watchpoint') def break_read_expression(expression: str, size=None): """Set a read watchpoint.""" size_part = '' if size is None else f'-s {size}' @@ -562,7 +562,7 @@ def break_write_range(process: sch.Schema('Process'), range: AddressRange): f'watchpoint set expression -s {sz} -- {offset_start}') -@REGISTRY.method(action='break_write') +@REGISTRY.method(action='break_ext', display='Set Watchpoint') def break_write_expression(expression: str, size=None): """Set a watchpoint.""" size_part = '' if size is None else f'-s {size}' @@ -572,7 +572,7 @@ def break_write_expression(expression: str, size=None): @REGISTRY.method(action='break_access') def break_access_range(process: sch.Schema('Process'), range: AddressRange): - """Set an access watchpoint.""" + """Set a read/write watchpoint.""" proc = find_proc_by_obj(process) offset_start = process.trace.memory_mapper.map_back( proc, Address(range.space, range.min)) @@ -581,9 +581,9 @@ def break_access_range(process: sch.Schema('Process'), range: AddressRange): f'watchpoint set expression -s {sz} -w read_write -- {offset_start}') -@REGISTRY.method(action='break_access') +@REGISTRY.method(action='break_ext', display='Set Read/Write Watchpoint') def break_access_expression(expression: str, size=None): - """Set an access watchpoint.""" + """Set a read/write watchpoint.""" size_part = '' if size is None else f'-s {size}' exec_convert_errors( f'watchpoint set expression {size_part} -w read_write -- {expression}') @@ -595,7 +595,7 @@ def break_exception(lang: str): exec_convert_errors(f'breakpoint set -E {lang}') -@REGISTRY.method(action='toggle') +@REGISTRY.method(action='toggle', display='Toggle Watchpoint') def toggle_watchpoint(watchpoint: sch.Schema('WatchpointSpec'), enabled: bool): """Toggle a watchpoint.""" wpt = find_wpt_by_obj(watchpoint) @@ -604,7 +604,7 @@ def toggle_watchpoint(watchpoint: sch.Schema('WatchpointSpec'), enabled: bool): exec_convert_errors(f'watchpoint {cmd} {wpt.GetID()}') -@REGISTRY.method(action='toggle') +@REGISTRY.method(action='toggle', display='Toggle Breakpoint') def toggle_breakpoint(breakpoint: sch.Schema('BreakpointSpec'), enabled: bool): """Toggle a breakpoint.""" bpt = find_bpt_by_obj(breakpoint) @@ -612,7 +612,7 @@ def toggle_breakpoint(breakpoint: sch.Schema('BreakpointSpec'), enabled: bool): exec_convert_errors(f'breakpoint {cmd} {bpt.GetID()}') -@REGISTRY.method(action='toggle') +@REGISTRY.method(action='toggle', display='Toggle Breakpoint Location') def toggle_breakpoint_location(location: sch.Schema('BreakpointLocation'), enabled: bool): """Toggle a breakpoint location.""" bptnum, locnum = find_bptlocnum_by_obj(location) @@ -620,7 +620,7 @@ def toggle_breakpoint_location(location: sch.Schema('BreakpointLocation'), enabl exec_convert_errors(f'breakpoint {cmd} {bptnum}.{locnum}') -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display='Delete Watchpoint') def delete_watchpoint(watchpoint: sch.Schema('WatchpointSpec')): """Delete a watchpoint.""" wpt = find_wpt_by_obj(watchpoint) @@ -628,7 +628,7 @@ def delete_watchpoint(watchpoint: sch.Schema('WatchpointSpec')): exec_convert_errors(f'watchpoint delete {wptnum}') -@REGISTRY.method(action='delete') +@REGISTRY.method(action='delete', display='Delete Breakpoint') def delete_breakpoint(breakpoint: sch.Schema('BreakpointSpec')): """Delete a breakpoint.""" bpt = find_bpt_by_obj(breakpoint) diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/ActionName.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/ActionName.java index eecb36a0ef..214c4631e1 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/ActionName.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/ActionName.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,8 +15,16 @@ */ package ghidra.debug.api.target; -import java.util.HashMap; -import java.util.Map; +import java.awt.event.InputEvent; +import java.util.*; + +import javax.swing.Icon; + +import docking.ActionContext; +import generic.theme.GIcon; +import ghidra.app.context.ProgramLocationActionContext; +import ghidra.trace.model.TraceExecutionState; +import ghidra.trace.model.target.TraceObject; /** * A name for a commonly-recognized target action. @@ -35,21 +43,137 @@ import java.util.Map; * the UI to decide what is presented where. * * @param name the name of the action (given as the action attribute on method annotations) - * @param builtIn true if the action should not be presented in generic contexts, but - * reserved for built-in, purpose-specific actions + * @param show when to show the general UI action for this debugger action + * @param enabler determines when the action is enabled, based on the object + * @param display the default text to display + * @param icon the default icon for menus and dialogs + * @param okText the default text for confirm buttons in dialogs */ -public record ActionName(String name, boolean builtIn) { +public record ActionName(String name, Show show, Enabler enabler, String display, Icon icon, + String okText) { + + private static final Icon ICON_ATTACH = new GIcon("icon.debugger.attach"); + private static final Icon ICON_CONNECT = new GIcon("icon.debugger.connect"); + private static final Icon ICON_DETACH = new GIcon("icon.debugger.detach"); + private static final Icon ICON_INTERRUPT = new GIcon("icon.debugger.interrupt"); + private static final Icon ICON_KILL = new GIcon("icon.debugger.kill"); + private static final Icon ICON_LAUNCH = new GIcon("icon.debugger.launch"); + private static final Icon ICON_REFRESH = new GIcon("icon.debugger.refresh"); + private static final Icon ICON_RESUME = new GIcon("icon.debugger.resume"); + private static final Icon ICON_STEP_BACK = new GIcon("icon.debugger.step.back"); + private static final Icon ICON_STEP_INTO = new GIcon("icon.debugger.step.into"); + private static final Icon ICON_STEP_LAST = new GIcon("icon.debugger.step.last"); + private static final Icon ICON_STEP_OUT = new GIcon("icon.debugger.step.finish"); + private static final Icon ICON_STEP_OVER = new GIcon("icon.debugger.step.over"); + private static final Icon ICON_SKIP_OVER = new GIcon("icon.debugger.skip.over"); + private static final Icon ICON_SET_BREAKPOINT = new GIcon("icon.debugger.breakpoint.set"); + private static final Map NAMES = new HashMap<>(); + /** + * Specifies when an action should appear in the menus. For diagnostics, a user may override + * this by holding SHIFT when right-clicking, causing all applicable general actions to appear. + */ + public enum Show { + /** + * Don't show general actions. The tool has built-in actions that already know how to invoke + * this. + */ + BUILTIN { + @Override + boolean doIsShowing(ActionContext context) { + return false; + } + }, + /** + * Only show general actions in address-based context, e.g., when right-clicking in the + * listing. + */ + ADDRESS { + @Override + boolean doIsShowing(ActionContext context) { + return context instanceof ProgramLocationActionContext; + } + }, + /** + * Show in all contexts. This is the default. + */ + EXTENDED { + @Override + boolean doIsShowing(ActionContext context) { + return true; + } + }; + + public boolean isShowing(ActionContext context) { + if (isOverriden(context)) { + return true; + } + return doIsShowing(context); + } + + abstract boolean doIsShowing(ActionContext context); + + private boolean isOverriden(ActionContext context) { + return (context.getEventClickModifiers() & InputEvent.SHIFT_DOWN_MASK) != 0; + } + } + + public enum Enabler { + ALWAYS { + @Override + public boolean isEnabled(TraceObject obj, long snap) { + return true; + } + }, + NOT_RUNNING { + @Override + boolean doIsEnabled(TraceExecutionState state) { + return state != null && state != TraceExecutionState.RUNNING; + } + }, + NOT_STOPPED { + @Override + boolean doIsEnabled(TraceExecutionState state) { + return state != TraceExecutionState.STOPPED; + } + }, + NOT_DEAD { + @Override + boolean doIsEnabled(TraceExecutionState state) { + return state != TraceExecutionState.TERMINATED; + } + }; + + private TraceExecutionState getState(TraceObject obj, long snap) { + try { + return obj.getExecutionState(snap); + } + catch (NoSuchElementException e) { + return TraceExecutionState.TERMINATED; + } + } + + boolean doIsEnabled(TraceExecutionState state) { + return true; + } + + public boolean isEnabled(TraceObject obj, long snap) { + return doIsEnabled(getState(obj, snap)); + } + } + public static ActionName name(String name) { synchronized (NAMES) { - return NAMES.computeIfAbsent(name, n -> new ActionName(n, false)); + return NAMES.computeIfAbsent(name, + n -> new ActionName(n, Show.EXTENDED, Enabler.ALWAYS, n, null, "OK")); } } - private static ActionName builtIn(String name) { + private static ActionName create(String name, Show show, Enabler enabler, String display, + Icon icon, String okText) { synchronized (NAMES) { - ActionName action = new ActionName(name, true); + ActionName action = new ActionName(name, show, enabler, display, icon, okText); if (NAMES.put(name, action) != null) { throw new AssertionError(); } @@ -57,24 +181,16 @@ public record ActionName(String name, boolean builtIn) { } } - private static ActionName extended(String name) { - synchronized (NAMES) { - ActionName action = new ActionName(name, false); - if (NAMES.put(name, action) != null) { - throw new AssertionError(); - } - return action; - } - } - - public static final ActionName REFRESH = extended("refresh"); + public static final ActionName REFRESH = + create("refresh", Show.EXTENDED, Enabler.ALWAYS, "Refresh", ICON_REFRESH, "Refresh"); /** * Activate a given object and optionally a time * *

* Forms: (focus:Object), (focus:Object, snap:LONG), (focus:Object, time:STR) */ - public static final ActionName ACTIVATE = builtIn("activate"); + public static final ActionName ACTIVATE = + create("activate", Show.BUILTIN, Enabler.ALWAYS, "Activate", null, "Activate"); /** * A weaker form of activate. * @@ -83,9 +199,12 @@ public record ActionName(String name, boolean builtIn) { * used to communicate selection (i.e., highlight) of the object. Whereas, double-clicking or * pressing enter would more likely invoke 'activate.' */ - public static final ActionName FOCUS = builtIn("focus"); - public static final ActionName TOGGLE = builtIn("toggle"); - public static final ActionName DELETE = builtIn("delete"); + public static final ActionName FOCUS = + create("focus", Show.BUILTIN, Enabler.ALWAYS, "Focus", null, "Focus"); + public static final ActionName TOGGLE = + create("toggle", Show.BUILTIN, Enabler.ALWAYS, "Toggle", null, "Toggle"); + public static final ActionName DELETE = + create("delete", Show.BUILTIN, Enabler.ALWAYS, "Delete", null, "Delete"); /** * Execute a CLI command @@ -93,7 +212,8 @@ public record ActionName(String name, boolean builtIn) { *

* Forms: (cmd:STRING):STRING; Optional arguments: capture:BOOL */ - public static final ActionName EXECUTE = builtIn("execute"); + public static final ActionName EXECUTE = + create("execute", Show.BUILTIN, Enabler.ALWAYS, "Execute", null, "Execute"); /** * Connect the back-end to a (usually remote) target @@ -101,23 +221,31 @@ public record ActionName(String name, boolean builtIn) { *

* Forms: (spec:STRING) */ - public static final ActionName CONNECT = extended("connect"); + public static final ActionName CONNECT = + create("connect", Show.EXTENDED, Enabler.ALWAYS, "Connect", ICON_CONNECT, "Connect"); /** * Forms: (target:Attachable), (pid:INT), (spec:STRING) */ - public static final ActionName ATTACH = extended("attach"); - public static final ActionName DETACH = extended("detach"); + public static final ActionName ATTACH = + create("attach", Show.EXTENDED, Enabler.ALWAYS, "Attach", ICON_ATTACH, "Attach"); + public static final ActionName DETACH = + create("detach", Show.EXTENDED, Enabler.ALWAYS, "Detach", ICON_DETACH, "Detach"); /** * Forms: (command_line:STRING), (file:STRING,args:STRING), (file:STRING,args:STRING_ARRAY), * (ANY*) */ - public static final ActionName LAUNCH = extended("launch"); - public static final ActionName KILL = builtIn("kill"); + public static final ActionName LAUNCH = + create("launch", Show.EXTENDED, Enabler.ALWAYS, "Launch", ICON_LAUNCH, "Launch"); + public static final ActionName KILL = + create("kill", Show.BUILTIN, Enabler.NOT_DEAD, "Kill", ICON_KILL, "Kill"); - public static final ActionName RESUME = builtIn("resume"); - public static final ActionName INTERRUPT = builtIn("interrupt"); + public static final ActionName RESUME = + create("resume", Show.BUILTIN, Enabler.NOT_RUNNING, "Resume", ICON_RESUME, "Resume"); + public static final ActionName INTERRUPT = + create("interrupt", Show.BUILTIN, Enabler.NOT_STOPPED, "Interrupt", ICON_INTERRUPT, + "Interrupt"); /** * All of these will show in the "step" portion of the control toolbar, if present. The @@ -128,25 +256,31 @@ public record ActionName(String name, boolean builtIn) { * context. (Multiple will appear, but may confuse the user.) You can have as many extended step * actions as you like. They will be ordered lexicographically by name. */ - public static final ActionName STEP_INTO = builtIn("step_into"); - public static final ActionName STEP_OVER = builtIn("step_over"); - public static final ActionName STEP_OUT = builtIn("step_out"); + public static final ActionName STEP_INTO = + create("step_into", Show.BUILTIN, Enabler.NOT_RUNNING, "Step Into", ICON_STEP_INTO, "Step"); + public static final ActionName STEP_OVER = + create("step_over", Show.BUILTIN, Enabler.NOT_RUNNING, "Step Over", ICON_STEP_OVER, "Step"); + public static final ActionName STEP_OUT = + create("step_out", Show.BUILTIN, Enabler.NOT_RUNNING, "Step Out", ICON_STEP_OUT, "Step"); /** * Skip is not typically available, except in emulators. If the back-end debugger does not have * a command for this action out-of-the-box, we do not recommend trying to implement it * yourself. The purpose of these actions just to expose/map each command to the UI, not to * invent new features for the back-end debugger. */ - public static final ActionName STEP_SKIP = builtIn("step_skip"); + public static final ActionName STEP_SKIP = + create("step_skip", Show.BUILTIN, Enabler.NOT_RUNNING, "Skip Over", ICON_SKIP_OVER, "Skip"); /** * Step back is not typically available, except in emulators and timeless (or time-travel) * debuggers. */ - public static final ActionName STEP_BACK = builtIn("step_back"); + public static final ActionName STEP_BACK = + create("step_back", Show.BUILTIN, Enabler.NOT_RUNNING, "Step Back", ICON_STEP_BACK, "Back"); /** * The action for steps that don't fit one of the common stepping actions. */ - public static final ActionName STEP_EXT = extended("step_ext"); + public static final ActionName STEP_EXT = + create("step_ext", Show.ADDRESS, Enabler.NOT_RUNNING, null, ICON_STEP_LAST, "Step"); /** * Forms: (addr:ADDRESS), R/W(rng:RANGE), (expr:STRING) @@ -158,25 +292,39 @@ public record ActionName(String name, boolean builtIn) { * The client may pass either null or "" for condition and/or commands to indicate omissions of * those arguments. */ - public static final ActionName BREAK_SW_EXECUTE = builtIn("break_sw_execute"); - public static final ActionName BREAK_HW_EXECUTE = builtIn("break_hw_execute"); - public static final ActionName BREAK_READ = builtIn("break_read"); - public static final ActionName BREAK_WRITE = builtIn("break_write"); - public static final ActionName BREAK_ACCESS = builtIn("break_access"); - public static final ActionName BREAK_EXT = extended("break_ext"); + public static final ActionName BREAK_SW_EXECUTE = + create("break_sw_execute", Show.BUILTIN, Enabler.ALWAYS, "Set Software Breakpoint", + ICON_SET_BREAKPOINT, "Set"); + public static final ActionName BREAK_HW_EXECUTE = + create("break_hw_execute", Show.BUILTIN, Enabler.ALWAYS, "Set Hardware Breakpoint", + ICON_SET_BREAKPOINT, "Set"); + public static final ActionName BREAK_READ = + create("break_read", Show.BUILTIN, Enabler.ALWAYS, "Set Read Breakpoint", + ICON_SET_BREAKPOINT, "Set"); + public static final ActionName BREAK_WRITE = + create("break_write", Show.BUILTIN, Enabler.ALWAYS, "Set Write Breakpoint", + ICON_SET_BREAKPOINT, "Set"); + public static final ActionName BREAK_ACCESS = + create("break_access", Show.BUILTIN, Enabler.ALWAYS, "Set Access Breakpont", + ICON_SET_BREAKPOINT, "Set"); + public static final ActionName BREAK_EXT = + create("break_ext", Show.BUILTIN, Enabler.ALWAYS, null, ICON_SET_BREAKPOINT, "Set"); /** * Forms: (rng:RANGE) */ - public static final ActionName READ_MEM = builtIn("read_mem"); + public static final ActionName READ_MEM = + create("read_mem", Show.BUILTIN, Enabler.ALWAYS, "Read Memory", null, "Read"); /** * Forms: (addr:ADDRESS,data:BYTES) */ - public static final ActionName WRITE_MEM = builtIn("write_mem"); + public static final ActionName WRITE_MEM = + create("write_mem", Show.BUILTIN, Enabler.ALWAYS, "Write Memory", null, "Write"); // NOTE: no read_reg. Use refresh(RegContainer), refresh(RegGroup), refresh(Register) /** * Forms: (frame:Frame,name:STRING,value:BYTES), (register:Register,value:BYTES) */ - public static final ActionName WRITE_REG = builtIn("write_reg"); + public static final ActionName WRITE_REG = + create("write_reg", Show.BUILTIN, Enabler.NOT_RUNNING, "Write Register", null, "Write"); } diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/Target.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/Target.java index 133f186892..4f6eb5e6cd 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/Target.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/target/Target.java @@ -18,16 +18,17 @@ package ghidra.debug.api.target; import java.util.Map; import java.util.Set; import java.util.concurrent.*; -import java.util.function.BooleanSupplier; -import java.util.function.Function; + +import javax.swing.Icon; import docking.ActionContext; +import ghidra.debug.api.target.ActionName.Show; import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; -import ghidra.trace.model.TraceExecutionState; import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceExecutionState; import ghidra.trace.model.breakpoint.TraceBreakpoint; import ghidra.trace.model.breakpoint.TraceBreakpointKind; import ghidra.trace.model.guest.TracePlatform; @@ -58,28 +59,72 @@ public interface Target { * just invoked implicitly. Often, the two suppliers are implemented using lambda functions, and * those functions will keep whatever some means of querying UI and/or target context in their * closures. - * - * @param display the text to display on UI actions associated with this entry - * @param name the name of a common debugger command this action implements - * @param details text providing more details, usually displayed in a tool tip - * @param requiresPrompt true if invoking the action requires further user interaction - * @param specificity a relative score of specificity. These are only meaningful when compared - * among entries returned in the same collection. - * @param enabled a supplier to determine whether an associated action in the UI is enabled. - * @param action a function for invoking this action asynchronously */ - record ActionEntry(String display, ActionName name, String details, boolean requiresPrompt, - long specificity, BooleanSupplier enabled, - Function> action) { + interface ActionEntry { + + /** + * Get the text to display on UI actions associated with this entry + * + * @return the display + */ + String display(); + + /** + * Get the name of a common debugger command this action implements + * + * @return the name + */ + ActionName name(); + + /** + * Get the icon to display in menus and dialogs + * + * @return the icon + */ + Icon icon(); + + /** + * Get the text providing more details, usually displayed in a tool tip + * + * @return the details + */ + String details(); + + /** + * Check whether invoking the action requires further user interaction + * + * @return true if prompting is required + */ + boolean requiresPrompt(); + + /** + * Get a relative score of specificity. + * + *

+ * These are only meaningful when compared among entries returned in the same collection. + * + * @return the specificity + */ + long specificity(); + + /** + * Invoke the action asynchronously, prompting if desired. + * + *

+ * The implementation is not required to provide a timeout; however, downstream components + * may. + * + * @param prompt whether or not to prompt the user for arguments + * @return the future result, often {@link Void} + */ + CompletableFuture invokeAsyncWithoutTimeout(boolean prompt); /** * Check if this action is currently enabled * * @return true if enabled */ - public boolean isEnabled() { - return enabled.getAsBoolean(); - } + boolean isEnabled(); /** * Invoke the action asynchronously, prompting if desired @@ -90,8 +135,9 @@ public interface Target { * @param prompt whether or not to prompt the user for arguments * @return the future result, often {@link Void} */ - public CompletableFuture invokeAsync(boolean prompt) { - return action.apply(prompt).orTimeout(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + default CompletableFuture invokeAsync(boolean prompt) { + return invokeAsyncWithoutTimeout(prompt).orTimeout(TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS); } /** @@ -103,7 +149,7 @@ public interface Target { * * @param prompt whether or not to prompt the user for arguments */ - public void run(boolean prompt) { + default void run(boolean prompt) { get(prompt); } @@ -113,7 +159,7 @@ public interface Target { * @param prompt whether or not to prompt the user for arguments * @return the resulting value, if applicable */ - public Object get(boolean prompt) { + default Object get(boolean prompt) { if (Swing.isSwingThread()) { throw new AssertionError("Refusing to block the Swing thread. Use a Task."); } @@ -130,8 +176,8 @@ public interface Target { * * @return true if built in. */ - public boolean builtIn() { - return name != null && name.builtIn(); + default Show getShow() { + return name() == null ? Show.EXTENDED : name().show(); } } diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracermi/RemoteMethod.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracermi/RemoteMethod.java index 4838df5716..e4325badd7 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracermi/RemoteMethod.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/tracermi/RemoteMethod.java @@ -20,6 +20,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; +import javax.swing.Icon; + import ghidra.async.AsyncUtils; import ghidra.debug.api.target.ActionName; import ghidra.trace.model.Trace; @@ -62,6 +64,20 @@ public interface RemoteMethod { */ String display(); + /** + * The icon to display in menu's and in the prompt dialog. + * + * @return the icon + */ + Icon icon(); + + /** + * Text to display in the OK button of any prompt dialog. + * + * @return the text + */ + String okText(); + /** * A description of the method. * diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java index d36d03eab5..f72685d120 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java @@ -49,7 +49,8 @@ import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.memory.TraceMemoryOperations; import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.program.TraceProgramView; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.thread.TraceThread; @@ -1740,7 +1741,7 @@ public interface FlatDebuggerAPI { * @return true if alive */ default boolean isTargetAlive(Trace trace) { - return getExecutionState(trace).isAlive(); + return getExecutionState(trace) != TraceExecutionState.TERMINATED; } /** @@ -1763,7 +1764,7 @@ public interface FlatDebuggerAPI { * @return true if alive */ default boolean isThreadAlive(TraceThread thread) { - return getExecutionState(thread).isAlive(); + return getExecutionState(thread) != TraceExecutionState.TERMINATED; } /** @@ -1792,7 +1793,7 @@ public interface FlatDebuggerAPI { * @throws TimeoutException if the timeout expires */ default void waitForBreak(Trace trace, long timeout, TimeUnit unit) throws TimeoutException { - if (!getExecutionState(trace).isRunning()) { + if (getExecutionState(trace) != TraceExecutionState.RUNNING) { return; } var listener = new DomainObjectListener() { @@ -1800,14 +1801,14 @@ public interface FlatDebuggerAPI { @Override public void domainObjectChanged(DomainObjectChangedEvent ev) { - if (!getExecutionState(trace).isRunning()) { + if (getExecutionState(trace) != TraceExecutionState.RUNNING) { future.complete(null); } } }; trace.addListener(listener); try { - if (!getExecutionState(trace).isRunning()) { + if (getExecutionState(trace) != TraceExecutionState.RUNNING) { return; } listener.future.get(timeout, unit); diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiConnector.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiConnector.java index c7fce87c50..7b85272d16 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiConnector.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiConnector.java @@ -144,20 +144,10 @@ public class JdiConnector { } public void registerRemoteMethod(JdiMethods methods, java.lang.reflect.Method m, String name) { - String action = name; - String display = name; - String description = name; TraceMethod annot = m.getAnnotation(TraceMethod.class); if (annot == null) { return; } - action = annot.action(); - if (annot.display() != null) { - display = annot.display(); - } - if (annot.description() != null) { - description = annot.description(); - } int pcount = m.getParameterCount(); if (pcount < 1) { return; @@ -167,8 +157,8 @@ public class JdiConnector { * collection routines currently use the return type, so just use ANY for now. */ TraceObjectSchema schema = PrimitiveTraceObjectSchema.ANY; - RmiRemoteMethod method = new RmiRemoteMethod(rootSchema.getContext(), name, action, display, - description, schema, methods, m); + RmiRemoteMethod method = new RmiRemoteMethod(rootSchema.getContext(), name, annot.action(), + annot.display(), annot.description(), annot.okText(), annot.icon(), schema, methods, m); remoteMethodRegistry.putMethod(name, method); } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiClient.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiClient.java index 405b35c3fc..c9fada1ef8 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiClient.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiClient.java @@ -605,9 +605,11 @@ public class RmiClient { private Method buildMethod(RmiRemoteMethod method) { Method.Builder builder = Method.newBuilder() .setName(method.getName()) - .setDescription(method.getDescription()) .setAction(method.getAction()) - .setDisplay(method.getDisplay()); + .setDisplay(method.getDisplay()) + .setDescription(method.getDescription()) + .setOkText(method.getOkText()) + .setIcon(method.getIcon()); int i = 0; for (RmiRemoteMethodParameter p : method.getParameters()) { MethodParameter param = buildParameter(p); diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiMethodRegistry.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiMethodRegistry.java index c00d65f37a..a929e0b578 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiMethodRegistry.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiMethodRegistry.java @@ -32,6 +32,10 @@ public class RmiMethodRegistry { String display() default ""; String description() default ""; + + String okText() default ""; + + String icon() default ""; } Map map = new HashMap<>(); diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiRemoteMethod.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiRemoteMethod.java index 54e1034c35..f7473316e0 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiRemoteMethod.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/client/tracermi/RmiRemoteMethod.java @@ -25,22 +25,27 @@ import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; public class RmiRemoteMethod { private final SchemaContext schemaContext; - private String name; - private String action; - private String display; - private String description; - private RmiRemoteMethodParameter[] params; - private TraceObjectSchema schema; - private RmiMethods instance; - private Method m; + private final String name; + private final String action; + private final String display; + private final String description; + private final String okText; + private final String icon; + private final RmiRemoteMethodParameter[] params; + private final TraceObjectSchema schema; + private final RmiMethods instance; + private final Method m; public RmiRemoteMethod(SchemaContext schemaContext, String name, String action, String display, - String description, TraceObjectSchema schema, RmiMethods instance, Method m) { + String description, String okText, String icon, TraceObjectSchema schema, + RmiMethods instance, Method m) { this.schemaContext = schemaContext; this.name = name; this.action = action; this.display = display; this.description = description; + this.okText = okText; + this.icon = icon; this.params = new RmiRemoteMethodParameter[m.getParameterCount()]; this.schema = schema; this.instance = instance; @@ -69,6 +74,14 @@ public class RmiRemoteMethod { return description; } + public String getOkText() { + return okText; + } + + public String getIcon() { + return icon; + } + public String getAction() { return action; } diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/RecordRemoteMethod.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/RecordRemoteMethod.java index ae57681c30..7742df15df 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/RecordRemoteMethod.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/RecordRemoteMethod.java @@ -17,14 +17,33 @@ package ghidra.app.plugin.core.debug.service.tracermi; import java.util.Map; +import javax.swing.Icon; + import ghidra.debug.api.target.ActionName; -import ghidra.debug.api.tracermi.*; +import ghidra.debug.api.tracermi.RemoteMethod; +import ghidra.debug.api.tracermi.RemoteParameter; import ghidra.trace.model.Trace; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; public record RecordRemoteMethod(TraceRmiHandler handler, String name, ActionName action, - String display, String description, Map parameters, - SchemaName retType) implements RemoteMethod { + String display, Icon icon, String okText, String description, + Map parameters, SchemaName retType) implements RemoteMethod { + + public RecordRemoteMethod { + if (display == null || display.isBlank()) { + display = action.display(); + } + if (display == null || display.isBlank()) { // still + display = name; + } + if (icon == null) { + icon = action.icon(); + } + if (okText.isEmpty() || okText.isBlank()) { + okText = action.okText(); + } + } + @Override public DefaultRemoteAsyncResult invokeAsync(Map arguments) { Trace trace = validate(arguments); diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java index bb2d959c9b..8ffb81edee 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java @@ -31,6 +31,7 @@ import org.apache.commons.lang3.ArrayUtils; import com.google.protobuf.ByteString; import db.Transaction; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.disassemble.DebuggerDisassemblerPlugin; import ghidra.app.plugin.core.debug.disassemble.TraceDisassembleCommand; import ghidra.app.services.DebuggerControlService; @@ -1027,7 +1028,9 @@ public class TraceRmiHandler extends AbstractTraceRmiConnection { } for (Method m : req.getMethodsList()) { RemoteMethod rm = new RecordRemoteMethod(this, m.getName(), - ActionName.name(m.getAction()), m.getDisplay(), m.getDescription(), + ActionName.name(m.getAction()), m.getDisplay(), + m.getIcon().isBlank() ? null : new GIcon(m.getIcon()), m.getOkText(), + m.getDescription(), m.getParametersList() .stream() .collect(Collectors.toMap(MethodParameter::getName, this::makeParameter)), diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java index 5c91394553..327bea8d65 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java @@ -19,9 +19,11 @@ import java.io.IOException; import java.math.BigInteger; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.function.*; +import java.util.function.Supplier; import java.util.stream.Collectors; +import javax.swing.Icon; + import org.apache.commons.lang3.exception.ExceptionUtils; import docking.ActionContext; @@ -60,6 +62,70 @@ import ghidra.util.Msg; import ghidra.util.task.TaskMonitor; public class TraceRmiTarget extends AbstractTarget { + + class TraceRmiActionEntry implements ActionEntry { + private final RemoteMethod method; + private final Map args; + private final boolean requiresPrompt; + private final long specificity; + private final ParamAndObjectArg first; + + public TraceRmiActionEntry(RemoteMethod method, Map args) { + this.method = method; + this.args = args; + + this.requiresPrompt = args.values().contains(Missing.MISSING); + this.specificity = computeSpecificity(args); + this.first = getFirstObjectArgument(method, args); + } + + @Override + public String display() { + return method.display(); + } + + @Override + public ActionName name() { + return method.action(); + } + + @Override + public Icon icon() { + return method.icon(); + } + + @Override + public String details() { + return method.description(); + } + + @Override + public boolean requiresPrompt() { + return requiresPrompt; + } + + @Override + public long specificity() { + return specificity; + } + + @Override + public CompletableFuture invokeAsyncWithoutTimeout(boolean prompt) { + return invokeMethod(prompt, method, args); + } + + @Override + public boolean isEnabled() { + if (first == null) { + return true; + } + if (first.obj == null) { + return false; + } + return name().enabler().isEnabled(first.obj, getSnap()); + } + } + private final TraceRmiConnection connection; private final Trace trace; @@ -224,8 +290,12 @@ public class TraceRmiTarget extends AbstractTarget { return null; } + /** + * A singleton to indicate missing arguments + */ public enum Missing { - MISSING; // The argument requires a prompt + /** The argument requires a prompt */ + MISSING; } protected Object findArgument(ActionName action, RemoteParameter parameter, @@ -266,28 +336,7 @@ public class TraceRmiTarget extends AbstractTarget { return args; } - private TraceExecutionState getStateOf(TraceObject object) { - try { - return object.getExecutionState(getSnap()); - } - catch (NoSuchElementException e) { - return TraceExecutionState.TERMINATED; - } - } - - private boolean whenState(TraceObject object, - Predicate predicate) { - try { - TraceExecutionState state = getStateOf(object); - return state == null || predicate.test(state); - } - catch (Exception e) { - Msg.error(this, "Could not get state: " + e); - return false; - } - } - - protected long computeSpecificity(Map args) { + protected static long computeSpecificity(Map args) { long score = 0; for (Object o : args.values()) { if (o instanceof TraceObject obj) { @@ -297,46 +346,34 @@ public class TraceRmiTarget extends AbstractTarget { return score; } - protected BooleanSupplier chooseEnabler(RemoteMethod method, Map args) { - ActionName name = method.action(); + protected RemoteParameter getFirstObjectParameter(RemoteMethod method) { SchemaContext ctx = getSchemaContext(); if (ctx == null) { - return () -> true; + return null; } - RemoteParameter firstParam = method.parameters() + return method.parameters() .values() .stream() .filter( p -> TraceObjectInterfaceUtils.isTraceObject(ctx.getSchema(p.type()).getType())) .findFirst() .orElse(null); + } + + record ParamAndObjectArg(RemoteParameter param, TraceObject obj) {} + + protected ParamAndObjectArg getFirstObjectArgument(RemoteMethod method, + Map args) { + RemoteParameter firstParam = getFirstObjectParameter(method); if (firstParam == null) { - return () -> true; + return null; } Object firstArg = args.get(firstParam.name()); - if (firstArg == null || firstArg == Missing.MISSING) { + if (firstArg == null || !(firstArg instanceof TraceObject obj)) { Msg.trace(this, "MISSING first argument for " + method + "(" + firstParam + ")"); - return () -> false; + return new ParamAndObjectArg(firstParam, null); } - TraceObject obj = (TraceObject) firstArg; - if (ActionName.RESUME.equals(name) || - ActionName.STEP_BACK.equals(name) || - ActionName.STEP_EXT.equals(name) || - ActionName.STEP_INTO.equals(name) || - ActionName.STEP_OUT.equals(name) || - ActionName.STEP_OVER.equals(name) || - ActionName.STEP_SKIP.equals(name)) { - return () -> whenState(obj, - state -> state != null && (state.isStopped() || state.isUnknown())); - } - else if (ActionName.INTERRUPT.equals(name)) { - return () -> whenState(obj, - state -> state == null || state.isRunning() || state.isUnknown()); - } - else if (ActionName.KILL.equals(name)) { - return () -> whenState(obj, state -> state == null || !state.isTerminated()); - } - return () -> true; + return new ParamAndObjectArg(firstParam, obj); } private Map promptArgs(RemoteMethod method, Map defaults) { @@ -346,7 +383,7 @@ public class TraceRmiTarget extends AbstractTarget { */ Map> defs = ValStr.fromPlainMap(defaults); RemoteMethodInvocationDialog dialog = new RemoteMethodInvocationDialog(tool, - getSchemaContext(), method.display(), method.display(), null); + getSchemaContext(), method.display(), method.okText(), method.icon()); Map> args = dialog.promptArguments(method.parameters(), defs, defs); return args == null ? null : ValStr.toPlainMap(args); } @@ -374,10 +411,7 @@ public class TraceRmiTarget extends AbstractTarget { boolean allowContextObject, boolean allowCoordsObject, boolean allowSuitableObject) { Map args = collectArguments(method, context, allowContextObject, allowCoordsObject, allowSuitableObject); - boolean requiresPrompt = args.values().contains(Missing.MISSING); - return new ActionEntry(method.display(), method.action(), method.description(), - requiresPrompt, computeSpecificity(args), chooseEnabler(method, args), - prompt -> invokeMethod(prompt, method, args)); + return new TraceRmiActionEntry(method, args); } protected Map collectFromMethods(Collection methods, @@ -432,6 +466,17 @@ public class TraceRmiTarget extends AbstractTarget { true); } + @Override + public Map collectActions(ActionName name, ActionContext context) { + if (name == null) { + if (context instanceof ProgramLocationActionContext ctx) { + return collectAddressActions(ctx); + } + return collectAllActions(context); + } + return collectByName(name, context); + } + @Override protected Map collectResumeActions(ActionContext context) { return collectByName(ActionName.RESUME, context); diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/proto/trace-rmi.proto b/Ghidra/Debug/Debugger-rmi-trace/src/main/proto/trace-rmi.proto index 0ff04e0fb1..f469723ea8 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/proto/trace-rmi.proto +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/proto/trace-rmi.proto @@ -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. @@ -423,6 +423,8 @@ message Method { // I'd like to make them all void, but I think executing a command and capturing its output // justifies being able to return a result. It should be used very sparingly. ValueType return_type = 6; + string ok_text = 7; + string icon = 8; } message RequestNegotiate { diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py index 6b3c2d10ac..40784b67a1 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/client.py @@ -27,10 +27,11 @@ from . import sch from . import trace_rmi_pb2 as bufs from .util import send_delimited, recv_delimited + # This need not be incremented every Ghidra release. When a breaking protocol # change is made, this should be updated to match the first Ghidra release that # includes the change. -# +# # Other places to change: # * every pyproject.toml file (incl. deps) # * TraceRmiHandler.VERSION @@ -98,7 +99,8 @@ class Receiver(Thread): while not self._is_shutdown: #print("Receiving message") try: - reply = recv_delimited(self.client.s, bufs.RootMessage(), dbg_seq) + reply = recv_delimited( + self.client.s, bufs.RootMessage(), dbg_seq) except BaseException as e: self._is_shutdown = True return @@ -448,6 +450,8 @@ class RemoteMethod: name: str action: str display: str + icon: str + ok_text: str description: str parameters: List[RemoteParameter] return_schema: sch.Schema @@ -508,30 +512,28 @@ class MethodRegistry(object): @classmethod def create_method(cls, function, name=None, action=None, display=None, - description=None) -> RemoteMethod: + icon=None, ok_text=None, description=None) -> RemoteMethod: if name is None: name = function.__name__ if action is None: action = name - if display is None: - display = name if description is None: - description = function.__doc__ or '' + description = function.__doc__ sig = inspect.signature(function) params = [] for p in sig.parameters.values(): params.append(cls._make_param(p)) return_schema = cls._to_schema(sig, sig.return_annotation) - return RemoteMethod(name, action, display, description, params, - return_schema, function) + return RemoteMethod(name, action, display, icon, ok_text, description, + params, return_schema, function) def method(self, func=None, *, name=None, action=None, display=None, - description='', condition=True): + icon=None, ok_text=None, description=None, condition=True): def _method(func): if condition: method = self.create_method(func, name, action, display, - description) + icon, ok_text, description) self.register_method(method) return func @@ -705,8 +707,10 @@ class Client(object): def _write_method(to: bufs.Method, method: RemoteMethod): to.name = method.name to.action = method.action - to.display = method.display - to.description = method.description + to.display = method.display or '' + to.icon = method.icon or '' + to.ok_text = method.ok_text or '' + to.description = method.description or '' Client._write_parameters(to.parameters, method.parameters) to.return_type.name = method.return_schema.name diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TestTraceRmiConnection.java b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TestTraceRmiConnection.java index 12901a480a..3ba6116ba0 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TestTraceRmiConnection.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TestTraceRmiConnection.java @@ -24,6 +24,8 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.Icon; + import db.Transaction; import ghidra.app.services.DebuggerTargetService; import ghidra.async.*; @@ -56,6 +58,11 @@ public abstract class TestTraceRmiConnection extends AbstractTraceRmiConnection String description, Map parameters, SchemaName retType, AsyncPairingQueue> argQueue, AsyncPairingQueue retQueue) implements RemoteMethod { + + public TestRemoteMethod { + Objects.requireNonNull(action); + } + public TestRemoteMethod(String name, ActionName action, String display, String description, Map parameters, SchemaName retType) { this(name, action, display, description, parameters, retType, new AsyncPairingQueue<>(), @@ -106,6 +113,16 @@ public abstract class TestTraceRmiConnection extends AbstractTraceRmiConnection result.thenApply(ar -> ar.ret).handle(AsyncUtils.copyTo(retQueue().give())); return result.thenApply(ar -> ar.args); } + + @Override + public String okText() { + return "OK"; + } + + @Override + public Icon icon() { + return null; + } } public record TestRemoteParameter(String name, SchemaName type, boolean required, diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html index d4681846f3..daa63d1045 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html @@ -163,6 +163,13 @@ "help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html">Breakpoint Marker Actions in the listings.

+

Set Breakpoint

+ +

This is a dropdown of actions provided by the back-end debugger, usually for setting + breakpoints by symbol, expression, etc. Setting breakpoints by address is typically done from + the Listings. If no such actions are available, or there is no live target, this action is + disabled.

+

Enable

diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png index 4188c674e017d986b3e5192fc4b4af1e45d66981..77722233b8436ab54077bbf690254ed5400f82fd 100644 GIT binary patch literal 30412 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 true, loc -> true); } + protected class GenericSetBreakpointAction extends InvokeActionEntryAction { + public GenericSetBreakpointAction(ActionEntry entry) { + super(plugin, entry); + setMenuBarData(new MenuData(new String[] { getName() }, entry.icon())); + setHelpLocation(AbstractSetBreakpointAction.help(plugin)); + } + } + + protected class StubSetBreakpointAction extends DockingAction { + public StubSetBreakpointAction() { + super("(Use the Listings to Set Breakpoints)", plugin.getName()); + setMenuBarData(new MenuData(new String[] { getName() })); + setHelpLocation(AbstractSetBreakpointAction.help(plugin)); + setEnabled(false); + } + + @Override + public void actionPerformed(ActionContext context) { + } + } + + protected class SetBreakpointAction extends MultiActionDockingAction { + public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS; + + private final List stub = List.of(new StubSetBreakpointAction()); + + public SetBreakpointAction() { + super("Set Breakpoint", plugin.getName()); + // TODO: Different icon? + setToolBarData(new ToolBarData(DebuggerResources.ICON_ADD, GROUP)); + setHelpLocation(AbstractSetBreakpointAction.help(plugin)); + addLocalAction(this); + } + + @Override + public List getActionList(ActionContext context) { + if (traceManager == null) { + return stub; + } + Trace trace = traceManager.getCurrentTrace(); + if (trace == null) { + return stub; + } + + // TODO: Set-by-address (like the listing one) always present? + if (controlService == null) { + return stub; + } + ControlMode mode = controlService.getCurrentMode(trace); + if (!mode.isTarget()) { + return stub; + // TODO: Consider a Sleigh expression for emulation? + // Actually, any "Address" field could be a Sleigh expression.... + } + + Target target = traceManager.getCurrent().getTarget(); + if (target == null) { + return stub; + } + List result = new ArrayList<>(); + for (ActionEntry entry : target.collectActions(ActionName.BREAK_EXT, context) + .values()) { + result.add(new GenericSetBreakpointAction(entry)); + } + if (result.isEmpty()) { + return stub; + } + Collections.sort(result, Comparator.comparing(a -> a.getName())); + return result; + } + } + protected class EnableSelectedBreakpointsAction extends AbstractEnableSelectedBreakpointsAction { public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS; @@ -708,6 +784,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter new DebuggerMakeBreakpointsEffectiveActionContext(); // package access for testing + SetBreakpointAction actionSetBreakpoint; EnableSelectedBreakpointsAction actionEnableSelectedBreakpoints; EnableAllBreakpointsAction actionEnableAllBreakpoints; DisableSelectedBreakpointsAction actionDisableSelectedBreakpoints; @@ -1163,6 +1240,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter } protected void createActions() { + actionSetBreakpoint = new SetBreakpointAction(); actionEnableSelectedBreakpoints = new EnableSelectedBreakpointsAction(); actionEnableAllBreakpoints = new EnableAllBreakpointsAction(); actionDisableSelectedBreakpoints = new DisableSelectedBreakpointsAction(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java index b4ab401c7b..68db4d689e 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerControlPlugin.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -288,6 +288,7 @@ public class DebuggerControlPlugin extends AbstractDebuggerPlugin } actionsTargetStepExt.add(TargetStepExtAction.builder(entry.display(), this) .description(entry.details()) + .toolBarIcon(entry.icon()) .enabledWhen(ctx -> entry.isEnabled()) .onAction(ctx -> TargetActionTask.runAction(tool, entry.display(), entry)) .build()); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPlugin.java index 9a77a0c6a6..a3074a91c3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPlugin.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,21 +18,19 @@ package ghidra.app.plugin.core.debug.gui.control; import java.util.ArrayList; import java.util.List; -import javax.swing.Icon; - import docking.ActionContext; import docking.Tool; -import docking.action.*; +import docking.action.DockingActionIf; +import docking.action.MenuData; import docking.actions.PopupActionProvider; import ghidra.app.context.ProgramActionContext; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; -import ghidra.app.plugin.core.debug.gui.DebuggerResources; +import ghidra.app.plugin.core.debug.gui.InvokeActionEntryAction; import ghidra.app.services.*; import ghidra.debug.api.control.ControlMode; import ghidra.debug.api.model.DebuggerObjectActionContext; -import ghidra.debug.api.target.ActionName; import ghidra.debug.api.target.Target; import ghidra.debug.api.target.Target.ActionEntry; import ghidra.debug.api.tracemgr.DebuggerCoordinates; @@ -57,23 +55,10 @@ import ghidra.trace.model.program.TraceProgramView; public class DebuggerMethodActionsPlugin extends Plugin implements PopupActionProvider { public static final String GROUP_METHODS = "Debugger Methods"; - class InvokeActionEntryAction extends DockingAction { - private final ActionEntry entry; - - public InvokeActionEntryAction(ActionEntry entry) { - super(entry.display(), DebuggerMethodActionsPlugin.this.getName()); - this.entry = entry; - Icon icon = null; - if (ActionName.REFRESH.equals(entry.name())) { - // TODO: Allow method annotation to specify icon? - icon = DebuggerResources.ICON_REFRESH; - } - setPopupMenuData(new MenuData(new String[] { getName() }, icon, GROUP_METHODS)); - } - - @Override - public void actionPerformed(ActionContext context) { - TargetActionTask.runAction(tool, entry.display(), entry); + class MethodAction extends InvokeActionEntryAction { + public MethodAction(ActionEntry entry) { + super(DebuggerMethodActionsPlugin.this, entry); + setPopupMenuData(new MenuData(new String[] { getName() }, entry.icon(), GROUP_METHODS)); } } @@ -136,10 +121,10 @@ public class DebuggerMethodActionsPlugin extends Plugin implements PopupActionPr List result = new ArrayList<>(); for (ActionEntry entry : target.collectActions(null, context).values()) { //if (entry.requiresPrompt() || entry.builtIn()) { - if (!entry.isEnabled() || entry.builtIn()) { + if (!entry.isEnabled() || !entry.getShow().isShowing(context)) { continue; } - result.add(new InvokeActionEntryAction(entry)); + result.add(new MethodAction(entry)); } return result; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/TargetDockingAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/TargetDockingAction.java index 6868eeb61f..72efd87cf7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/TargetDockingAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/control/TargetDockingAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -65,9 +65,11 @@ class TargetDockingAction extends DockingAction { protected void updateFromContext(ActionContext context) { entry = findEntry(context); if (entry == null) { + getToolBarData().setIcon(action.icon()); setDescription(defaultDescription); } else { + getToolBarData().setIcon(entry.icon()); setDescription(entry.details()); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceExecutionState.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceExecutionState.java index 641b045544..b9bd7efd5a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceExecutionState.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceExecutionState.java @@ -26,7 +26,7 @@ public enum TraceExecutionState { * This may apply, e.g., to a GDB "Inferior," which has no yet been used to launch or attach to * a process. */ - INACTIVE(false, false, false, false), + INACTIVE, /** * The object is alive, but its execution state is unspecified @@ -38,12 +38,12 @@ public enum TraceExecutionState { * all of its threads are stopped. For the clients' sakes, all models should implement * these conventions internally. */ - ALIVE(true, false, false, false), + ALIVE, /** * The object is alive, but not executing */ - STOPPED(true, false, true, false), + STOPPED, /** * The object is alive and executing @@ -53,7 +53,7 @@ public enum TraceExecutionState { * thread is currently executing, waiting on an event, or scheduled for execution. It does not * necessarily mean it is executing on a CPU at this exact moment. */ - RUNNING(true, true, false, false), + RUNNING, /** * The object is no longer alive @@ -63,63 +63,5 @@ public enum TraceExecutionState { * stale handles to objects which may still be queried (e.g., for a process exit code), or e.g., * a GDB "Inferior," which could be re-used to launch or attach to another process. */ - TERMINATED(false, false, false, true); - - private final boolean alive; - private final boolean running; - private final boolean stopped; - private final boolean terminated; - - private TraceExecutionState(boolean alive, boolean running, boolean stopped, - boolean terminated) { - this.alive = alive; - this.running = running; - this.stopped = stopped; - this.terminated = terminated; - } - - /** - * Check if this state implies the object is alive - * - * @return true if alive - */ - public boolean isAlive() { - return alive; - } - - /** - * Check if this state implies the object is running - * - * @return true if running - */ - public boolean isRunning() { - return running; - } - - /** - * Check if this state implies the object is stopped - * - * @return true if stopped - */ - public boolean isStopped() { - return stopped; - } - - /** - * Check if this state implies the object was terminated - * - * @return true if terminated - */ - public boolean isTerminated() { - return terminated; - } - - /** - * Check if this state is ambiguous - * - * @return true if terminated - */ - public boolean isUnknown() { - return !stopped && !running && !terminated; - } + TERMINATED; } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPluginTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPluginTest.java index cd5590c358..55b7bd891b 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPluginTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/control/DebuggerMethodActionsPluginTest.java @@ -31,6 +31,7 @@ import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiConnection.*; import ghidra.app.services.DebuggerStaticMappingService; +import ghidra.debug.api.target.ActionName; import ghidra.program.util.ProgramLocation; import ghidra.trace.model.Lifespan; import ghidra.trace.model.target.schema.PrimitiveTraceObjectSchema; @@ -57,7 +58,7 @@ public class DebuggerMethodActionsPluginTest extends AbstractGhidraHeadedDebugge protected void addMethods() { TestRemoteMethodRegistry reg = rmiCx.getMethods(); - rmiMethodAdvance = new TestRemoteMethod("advance", null, "Advance", + rmiMethodAdvance = new TestRemoteMethod("advance", ActionName.STEP_EXT, "Advance", "Advance to the given address", PrimitiveTraceObjectSchema.VOID, new TestRemoteParameter("thread", new SchemaName("Thread"), true, null, "Thread", "The thread to advance"), @@ -65,14 +66,15 @@ public class DebuggerMethodActionsPluginTest extends AbstractGhidraHeadedDebugge "Target", "The target address")); reg.add(rmiMethodAdvance); - rmiMethodStepExt = new TestRemoteMethod("step_ext", null, "StepExt", + rmiMethodStepExt = new TestRemoteMethod("step_ext", ActionName.STEP_EXT, "StepExt", "Step in some special way", PrimitiveTraceObjectSchema.VOID, new TestRemoteParameter("thread", new SchemaName("Thread"), true, null, "Thread", "The thread to step")); reg.add(rmiMethodStepExt); - rmiMethodAdvanceWithFlag = new TestRemoteMethod("advance_flag", null, "Advance With Flag", - "Advance to the given address, with flag", PrimitiveTraceObjectSchema.VOID, + rmiMethodAdvanceWithFlag = new TestRemoteMethod("advance_flag", ActionName.STEP_EXT, + "Advance With Flag", "Advance to the given address, with flag", + PrimitiveTraceObjectSchema.VOID, new TestRemoteParameter("thread", new SchemaName("Thread"), true, null, "Thread", "The thread to advance"), new TestRemoteParameter("target", PrimitiveTraceObjectSchema.ADDRESS, true, null, @@ -81,7 +83,7 @@ public class DebuggerMethodActionsPluginTest extends AbstractGhidraHeadedDebugge "Flag", "The flag")); reg.add(rmiMethodAdvanceWithFlag); - rmiMethodBetween = new TestRemoteMethod("between", null, "Between", + rmiMethodBetween = new TestRemoteMethod("between", ActionName.STEP_EXT, "Between", "Advance between two given addresses", PrimitiveTraceObjectSchema.VOID, new TestRemoteParameter("thread", new SchemaName("Thread"), true, null, "Thread", "The thread to advance"), diff --git a/GhidraDocs/GhidraClass/Debugger/A1-GettingStarted.html b/GhidraDocs/GhidraClass/Debugger/A1-GettingStarted.html index ebb31ae6ed..bd758d9b6f 100644 --- a/GhidraDocs/GhidraClass/Debugger/A1-GettingStarted.html +++ b/GhidraDocs/GhidraClass/Debugger/A1-GettingStarted.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

Ghidra Debugger

diff --git a/GhidraDocs/GhidraClass/Debugger/A2-UITour.html b/GhidraDocs/GhidraClass/Debugger/A2-UITour.html index 4835a64152..63e0f8913d 100644 --- a/GhidraDocs/GhidraClass/Debugger/A2-UITour.html +++ b/GhidraDocs/GhidraClass/Debugger/A2-UITour.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

Ghidra Debugger

diff --git a/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.html b/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.html index 0189f37b89..40731c17b3 100644 --- a/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.html +++ b/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

Ghidra Debugger

@@ -160,22 +161,26 @@ Memory/Hex, and the Decompiler, right-click and select set breakpoint Set Breakpoint, press K on the keyboard, or double-click the margin. +
  • From the Breakpoints window, use the Set Breakpoint +dropdown to to access the various breakpoint actions defined by +GDB.
  • From the Terminal window, use the GDB command, e.g., break main.
  • The advantage of using the listings is that you can quickly set a -breakpoint at any address. The advantage of using the Terminal window is -that you can specify something other than an address. Often, those -specifications still resolve to addresses, and Ghidra will display them. -Ghidra will memorize breakpoints by recording them as special bookmarks -in the program database. There is some iconography to communicate the -various states of a breakpoint. When all is well and normal, you should -only see enabled and disabled disabled breakpoint -breakpoints. If the target is terminated (or not launched yet), you may -also see ineffective breakpoints.

    +breakpoint at any address. The advantage of using the dropdown action or +Terminal window is that you can specify something other than an address. +Often, those specifications still resolve to addresses, and Ghidra will +display them. Ghidra will memorize breakpoints by recording them as +special bookmarks in the program database. There is some iconography to +communicate the various states of a breakpoint. When all is well and +normal, you should only see enabled enabled breakpoint and +disabled breakpoints. If the target is terminated +(or not launched yet), you may also see ineffective ineffective breakpoint +breakpoints.

    Examining Minesweeper Board Setup

    diff --git a/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.md b/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.md index ebf3c86fbd..954ee14dfd 100644 --- a/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.md +++ b/GhidraDocs/GhidraClass/Debugger/A3-Breakpoints.md @@ -17,10 +17,11 @@ From here, you can toggle and delete existing breakpoints. There are several ways to set a new breakpoint: 1. From any static or dynamic listing window, including Disassembly, Memory/Hex, and the Decompiler, right-click and select ![set breakpoint](images/breakpoint-enable.png) Set Breakpoint, press **`K`** on the keyboard, or double-click the margin. +1. From the Breakpoints window, use the **Set Breakpoint** dropdown to to access the various breakpoint actions defined by GDB. 1. From the Terminal window, use the GDB command, e.g., `break main`. The advantage of using the listings is that you can quickly set a breakpoint at any address. -The advantage of using the Terminal window is that you can specify something other than an address. +The advantage of using the dropdown action or Terminal window is that you can specify something other than an address. Often, those specifications still resolve to addresses, and Ghidra will display them. Ghidra will memorize breakpoints by recording them as special bookmarks in the program database. There is some iconography to communicate the various states of a breakpoint. diff --git a/GhidraDocs/GhidraClass/Debugger/A4-MachineState.html b/GhidraDocs/GhidraClass/Debugger/A4-MachineState.html index 6fc4a3ca2a..a0ca3dd35b 100644 --- a/GhidraDocs/GhidraClass/Debugger/A4-MachineState.html +++ b/GhidraDocs/GhidraClass/Debugger/A4-MachineState.html @@ -35,7 +35,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    diff --git a/GhidraDocs/GhidraClass/Debugger/A5-Navigation.html b/GhidraDocs/GhidraClass/Debugger/A5-Navigation.html index 5c0a2be03e..e40e48f46c 100644 --- a/GhidraDocs/GhidraClass/Debugger/A5-Navigation.html +++ b/GhidraDocs/GhidraClass/Debugger/A5-Navigation.html @@ -35,7 +35,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    diff --git a/GhidraDocs/GhidraClass/Debugger/A6-MemoryMap.html b/GhidraDocs/GhidraClass/Debugger/A6-MemoryMap.html index c72d319760..c35e1f8d6e 100644 --- a/GhidraDocs/GhidraClass/Debugger/A6-MemoryMap.html +++ b/GhidraDocs/GhidraClass/Debugger/A6-MemoryMap.html @@ -35,7 +35,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    diff --git a/GhidraDocs/GhidraClass/Debugger/B1-RemoteTargets.html b/GhidraDocs/GhidraClass/Debugger/B1-RemoteTargets.html index 288fb4200e..0fbe63ac0a 100644 --- a/GhidraDocs/GhidraClass/Debugger/B1-RemoteTargets.html +++ b/GhidraDocs/GhidraClass/Debugger/B1-RemoteTargets.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    diff --git a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html index 0d95b521f4..2d5a708ed3 100644 --- a/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html +++ b/GhidraDocs/GhidraClass/Debugger/B2-Emulation.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    diff --git a/GhidraDocs/GhidraClass/Debugger/B3-Scripting.html b/GhidraDocs/GhidraClass/Debugger/B3-Scripting.html index d382eea0da..0a29e84350 100644 --- a/GhidraDocs/GhidraClass/Debugger/B3-Scripting.html +++ b/GhidraDocs/GhidraClass/Debugger/B3-Scripting.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    @@ -379,7 +380,7 @@ class="sourceCode numberSource java numberLines">< throw new AssertionError("The current program must be termmines"); } -if (getExecutionState(trace).isRunning()) { +if (getExecutionState(trace) != TraceExecutionState.STOPPED) { monitor.setMessage("Interrupting target and waiting for STOPPED"); interrupt(); waitForBreak(3, TimeUnit.SECONDS); diff --git a/GhidraDocs/GhidraClass/Debugger/B3-Scripting.md b/GhidraDocs/GhidraClass/Debugger/B3-Scripting.md index bd54ccfbcc..5edd3b3bcd 100644 --- a/GhidraDocs/GhidraClass/Debugger/B3-Scripting.md +++ b/GhidraDocs/GhidraClass/Debugger/B3-Scripting.md @@ -210,7 +210,7 @@ if (!"termmines".equals(currentProgram.getName())) { throw new AssertionError("The current program must be termmines"); } -if (getExecutionState(trace).isRunning()) { +if (getExecutionState(trace) != TraceExecutionState.STOPPED) { monitor.setMessage("Interrupting target and waiting for STOPPED"); interrupt(); waitForBreak(3, TimeUnit.SECONDS); diff --git a/GhidraDocs/GhidraClass/Debugger/B4-Modeling.html b/GhidraDocs/GhidraClass/Debugger/B4-Modeling.html index b1929f6147..837eb91088 100644 --- a/GhidraDocs/GhidraClass/Debugger/B4-Modeling.html +++ b/GhidraDocs/GhidraClass/Debugger/B4-Modeling.html @@ -99,7 +99,8 @@ class="advanced" href="B1-RemoteTargets.html">Remote TargetsEmulationScriptingModeling + class="advanced" href="B4-Modeling.html">ModelingAdding Debuggers

    Ghidra Debugger

    @@ -634,46 +635,47 @@ class="sourceCode numberSource java numberLines">< } @Override - public Expr modBeforeStore(int sizeinAddress, Expr inAddress, int sizeinValue, - Expr inValue) { + public Expr modBeforeStore(int sizeinOffset, AddressSpace space, Expr inOffset, + int sizeinValue, Expr inValue) { return inValue; } @Override - public Expr modAfterLoad(int sizeinAddress, Expr inAddress, int sizeinValue, Expr inValue) { - return inValue; - } - - @Override - public Expr fromConst(byte[] value) { - if (endian.isBigEndian()) { - return new LitExpr(new BigInteger(1, value), value.length); - } - byte[] reversed = Arrays.copyOf(value, value.length); - ArrayUtils.reverse(reversed); - return new LitExpr(new BigInteger(1, reversed), reversed.length); - } - - @Override - public Expr fromConst(BigInteger value, int size, boolean isContextreg) { - return new LitExpr(value, size); - } - - @Override - public Expr fromConst(long value, int size) { - return fromConst(BigInteger.valueOf(value), size); - } - - @Override - public byte[] toConcrete(Expr value, Purpose purpose) { - throw new UnsupportedOperationException(); - } - - @Override - public long sizeOf(Expr value) { - throw new UnsupportedOperationException(); - } -} + public Expr modAfterLoad(int sizeinOffset, AddressSpace space, Expr inOffset, + int sizeinValue, Expr inValue) { + return inValue; + } + + @Override + public Expr fromConst(byte[] value) { + if (endian.isBigEndian()) { + return new LitExpr(new BigInteger(1, value), value.length); + } + byte[] reversed = Arrays.copyOf(value, value.length); + ArrayUtils.reverse(reversed); + return new LitExpr(new BigInteger(1, reversed), reversed.length); + } + + @Override + public Expr fromConst(BigInteger value, int size, boolean isContextreg) { + return new LitExpr(value, size); + } + + @Override + public Expr fromConst(long value, int size) { + return fromConst(BigInteger.valueOf(value), size); + } + + @Override + public byte[] toConcrete(Expr value, Purpose purpose) { + throw new UnsupportedOperationException(); + } + + @Override + public long sizeOf(Expr value) { + throw new UnsupportedOperationException(); + } +}

    We have implemented two arithmetic models: one for big-endian languages and one for little-endian. The endianness comes into play when we encode constant values passed to fromConst(). We must @@ -706,11 +708,10 @@ storage mechanism. For example, were this a dynamic taint analyzer, we could use modAfterLoad() to record that a value was retrieved via a tainted address. The inValue parameter gives the Expr actually retrieved from the emulator’s -storage, and inAddress gives the address (really just the -Expr piece) used to retrieve it. Conversely, in -modBeforeStore(), inValue gives the value -about to be stored, and inAddress gives the address used to -store it.

    +storage, and inOffset gives the offset used to retrieve it. +Conversely, in modBeforeStore(), inValue gives +the value about to be stored, and inOffset gives the offset +used to store it.

    We implement neither toConcrete() nor sizeOf(). Since we will be augmenting a concrete emulator, these methods will be provided by the concrete piece. If this model is diff --git a/GhidraDocs/GhidraClass/Debugger/ghidra_scripts/ZeroTimerScript.java b/GhidraDocs/GhidraClass/Debugger/ghidra_scripts/ZeroTimerScript.java index c958258858..f2ce28f99b 100644 --- a/GhidraDocs/GhidraClass/Debugger/ghidra_scripts/ZeroTimerScript.java +++ b/GhidraDocs/GhidraClass/Debugger/ghidra_scripts/ZeroTimerScript.java @@ -27,8 +27,8 @@ import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.Symbol; import ghidra.program.util.ProgramLocation; -import ghidra.trace.model.TraceExecutionState; import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceExecutionState; public class ZeroTimerScript extends GhidraScript implements FlatDebuggerAPI { @Override @@ -43,7 +43,7 @@ public class ZeroTimerScript extends GhidraScript implements FlatDebuggerAPI { throw new AssertionError("The current program must be termmines"); } - if (getExecutionState(trace).isRunning()) { + if (getExecutionState(trace) != TraceExecutionState.STOPPED) { monitor.setMessage("Interrupting target and waiting for STOPPED"); interrupt(); waitForBreak(3, TimeUnit.SECONDS); @@ -87,7 +87,7 @@ public class ZeroTimerScript extends GhidraScript implements FlatDebuggerAPI { // -------------------------------- while (true) { - monitor.checkCanceled(); + monitor.checkCancelled(); TraceExecutionState execState = getExecutionState(trace); switch (execState) { diff --git a/GhidraDocs/GhidraClass/Debugger/images/Breakpoints_EmptyAfterLaunch.png b/GhidraDocs/GhidraClass/Debugger/images/Breakpoints_EmptyAfterLaunch.png index 0bda62bfb5cbeb7fca8dfcd148af463b66ad5755..3955c953446395c24a7c0b2b997dc2602a924111 100644 GIT binary patch literal 16326 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 z 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 literal 14679 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 P0jD`A&$ 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 literal 24384 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