GP-1978: Delete Framework-Debugging. Merge needed parts into

TraceModeling.
This commit is contained in:
Dan 2024-12-11 17:02:23 -05:00
parent 8dd0ea698a
commit f5a93c3072
429 changed files with 5093 additions and 23085 deletions

View file

@ -32,7 +32,8 @@ from pybag.dbgeng.win32.kernel32 import STILL_ACTIVE
from . import util, arch, methods, hooks
from .dbgmodel.imodelobject import ModelObjectKind
from .exdi import exdi_commands, exdi_methods
if util.is_exdi():
from .exdi import exdi_commands, exdi_methods
PAGE_SIZE = 4096

View file

@ -243,18 +243,6 @@ def refresh_processes(node: sch.Schema('ProcessContainer')):
commands.ghidra_trace_put_processes()
@REGISTRY.method(action='refresh', display='Refresh Breakpoint Locations')
def refresh_proc_breakpoints(node: sch.Schema('BreakpointLocationContainer')):
"""
Refresh the breakpoint locations for the process.
In the course of refreshing the locations, the breakpoint list will also be
refreshed.
"""
with commands.open_tracked_tx('Refresh Breakpoint Locations'):
commands.ghidra_trace_put_breakpoints()
@REGISTRY.method(action='refresh', display='Refresh Environment')
def refresh_environment(node: sch.Schema('Environment')):
"""Refresh the environment descriptors (arch, os, endian)."""

View file

@ -1,6 +1,5 @@
<context>
<schema name="DbgRoot" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<attribute name="Sessions" schema="SessionContainer" required="yes" fixed="yes" />
<attribute name="Settings" schema="ANY" />
<attribute name="State" schema="ANY" />
@ -11,19 +10,12 @@
<attribute schema="ANY"/>
</schema>
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Session" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY"/>
</schema>
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
<interface name="Activatable" />
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="EventScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
@ -49,20 +41,16 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Attachable" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Process" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
@ -70,12 +58,11 @@
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="BreakpointLocation" />
<interface name="Deletable" />
<interface name="Togglable" />
<element schema="VOID" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Range" schema="RANGE" />
@ -92,7 +79,6 @@
<attribute schema="VOID" />
</schema>
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="PID" schema="LONG" />
<attribute-alias from="_pid" to="PID" />
@ -105,18 +91,9 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Debug" schema="DebugBreakpointContainer" required="yes" fixed="yes" />
<!-- attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" /-->
<attribute name="Exit Code" schema="LONG" />
<attribute-alias from="_exit_code" to="Exit Code" />
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
@ -128,7 +105,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -149,7 +125,6 @@
<attribute schema="VOID" />
</schema>
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="ModuleContainer" />
<element schema="Module" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
@ -160,22 +135,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocation" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocation" />
<element schema="VOID" />
<attribute name="Range" schema="RANGE" />
<attribute-alias from="_range" to="Range" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<element schema="BreakpointLocation" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Thread" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
@ -192,7 +152,6 @@
<interface name="Activatable" />
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="StackFramesContainer" required="yes" fixed="yes" />
@ -238,7 +197,6 @@
<attribute schema="VOID" />
</schema>
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Section" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -258,13 +216,11 @@
<attribute schema="ANY" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -298,7 +254,6 @@
</schema>
<schema name="RegisterValueContainer" attributeResync="ONCE">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<attribute name="General Purpose Registers" schema="RegisterBank" />
<attribute name="Floating Point Registers" schema="RegisterBank" />
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
@ -310,7 +265,6 @@
<attribute schema="VOID" />
</schema>
<schema name="RegisterBank" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="RegisterBank" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>

View file

@ -1,6 +1,5 @@
<context>
<schema name="DbgRoot" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<attribute name="Sessions" schema="SessionContainer" required="yes" fixed="yes" />
<attribute name="Settings" schema="ANY" />
<attribute name="State" schema="ANY" />
@ -11,19 +10,12 @@
<attribute schema="ANY"/>
</schema>
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Session" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY"/>
</schema>
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
<interface name="Activatable" />
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="EventScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
@ -52,20 +44,16 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Attachable" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Process" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
@ -73,12 +61,11 @@
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="BreakpointLocation" />
<interface name="Deletable" />
<interface name="Togglable" />
<element schema="VOID" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Range" schema="RANGE" />
@ -95,7 +82,6 @@
<attribute schema="VOID" />
</schema>
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="PID" schema="LONG" />
<attribute-alias from="_pid" to="PID" />
@ -108,18 +94,9 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Debug" schema="DebugBreakpointContainer" required="yes" fixed="yes" />
<!-- attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" /-->
<attribute name="Exit Code" schema="LONG" />
<attribute-alias from="_exit_code" to="Exit Code" />
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
@ -131,7 +108,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -163,22 +139,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocation" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocation" />
<element schema="VOID" />
<attribute name="Range" schema="RANGE" />
<attribute-alias from="_range" to="Range" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<element schema="BreakpointLocation" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Thread" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
@ -195,7 +156,6 @@
<interface name="Activatable" />
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="StackFramesContainer" required="yes" fixed="yes" />
@ -241,7 +201,6 @@
<attribute schema="VOID" />
</schema>
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Section" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -261,13 +220,11 @@
<attribute schema="ANY" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -301,7 +258,6 @@
</schema>
<schema name="RegisterValueContainer" attributeResync="ONCE">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<attribute name="General Purpose Registers" schema="RegisterBank" />
<attribute name="Floating Point Registers" schema="RegisterBank" />
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
@ -313,7 +269,6 @@
<attribute schema="VOID" />
</schema>
<schema name="RegisterBank" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="RegisterBank" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
@ -328,14 +283,6 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ExdiThreadContainer" required="yes" fixed="yes" />
<!-- attribute name="Modules" schema="ModuleContainer" required="yes" fixed="yes" /-->
@ -343,7 +290,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -375,7 +321,6 @@
<schema name="ExdiThread" elementResync="NEVER" attributeResync="NEVER">
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="TID" schema="LONG" />

View file

@ -228,19 +228,6 @@ def refresh_processes(node: sch.Schema('ProcessContainer')):
commands.ghidra_trace_put_threads()
@REGISTRY.method(action='refresh')
def refresh_proc_breakpoints(node: sch.Schema('BreakpointLocationContainer')):
"""
Refresh the breakpoint locations for the process.
In the course of refreshing the locations, the breakpoint list will also be
refreshed.
"""
with commands.open_tracked_tx('Refresh Breakpoint Locations'):
commands.ghidra_trace_put_breakpoints()
@REGISTRY.method(action='refresh')
def refresh_environment(node: sch.Schema('Environment')):
"""Refresh the environment descriptors (arch, os, endian)."""
with commands.open_tracked_tx('Refresh Environment'):

View file

@ -1,11 +1,5 @@
<context>
<schema name="TTDSession" elementResync="NEVER" attributeResync="NEVER">
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="EventScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
@ -24,20 +18,16 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Attachable" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Process" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -45,12 +35,11 @@
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="BreakpointLocation" />
<interface name="Deletable" />
<interface name="Togglable" />
<element schema="VOID" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -67,7 +56,6 @@
<attribute schema="VOID" />
</schema>
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="PID" schema="LONG" />
<attribute-alias from="_pid" to="PID" />
@ -80,18 +68,9 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="yes" />
<!-- attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" /-->
<attribute name="Exit Code" schema="LONG" />
<attribute-alias from="_exit_code" to="Exit Code" />
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
@ -101,7 +80,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -122,7 +100,6 @@
<attribute schema="VOID" />
</schema>
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="ModuleContainer" />
<element schema="Module" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -133,23 +110,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocation" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocation" />
<element schema="VOID" />
<attribute name="Range" schema="RANGE" />
<attribute-alias from="_range" to="Range" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<element schema="BreakpointLocation" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Thread" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -166,7 +127,6 @@
<interface name="Activatable" />
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
@ -209,7 +169,6 @@
<attribute schema="VOID" />
</schema>
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Section" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -221,13 +180,11 @@
<attribute schema="VOID" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -262,7 +219,6 @@
</schema>
<schema name="RegisterValueContainer" attributeResync="ONCE">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<attribute name="General Purpose Registers" schema="RegisterBank" />
<attribute name="Floating Point Registers" schema="RegisterBank" />
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
@ -271,7 +227,6 @@
<attribute schema="VOID" />
</schema>
<schema name="RegisterBank" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="RegisterBank" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>

View file

@ -1,11 +1,5 @@
<context>
<schema name="GdbSession" elementResync="NEVER" attributeResync="NEVER">
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="EventScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
@ -25,31 +19,27 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Attachable" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="InferiorContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Inferior" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="Deletable" />
<interface name="Togglable" />
<element schema="BreakpointLocation" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -65,7 +55,6 @@
<attribute schema="VOID" />
</schema>
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="PID" schema="LONG" />
<attribute-alias from="_pid" to="PID" />
@ -78,14 +67,6 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" />
@ -98,7 +79,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -119,7 +99,6 @@
<attribute schema="VOID" />
</schema>
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="ModuleContainer" />
<element schema="Module" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -142,30 +121,19 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<element schema="BreakpointLocation" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Thread" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
<interface name="Method" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" required="yes" fixed="yes" hidden="yes" />
<attribute name="_return_type" schema="TYPE" required="yes" fixed="yes" hidden="yes" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute schema="VOID" fixed="yes" hidden="yes" />
</schema>
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
<interface name="Activatable" />
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
@ -208,7 +176,6 @@
<attribute schema="VOID" />
</schema>
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Section" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -220,13 +187,11 @@
<attribute schema="VOID" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -259,7 +224,6 @@
</schema>
<schema name="RegisterValueContainer" attributeResync="NEVER">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>

View file

@ -5,8 +5,6 @@ Module.manifest||GHIDRA||||END|
README.md||GHIDRA||||END|
build.gradle||GHIDRA||||END|
data/debugger-launchers/local-lldb.bat||GHIDRA||||END|
src/llvm-project/lldb/bindings/java/java-typemaps.swig||Apache License 2.0 with LLVM Exceptions||||END|
src/llvm-project/lldb/bindings/java/java.swig||Apache License 2.0 with LLVM Exceptions||||END|
src/main/py/LICENSE||GHIDRA||||END|
src/main/py/MANIFEST.in||GHIDRA||||END|
src/main/py/README.md||GHIDRA||||END|

View file

@ -1,11 +1,5 @@
<context>
<schema name="LldbSession" elementResync="NEVER" attributeResync="NEVER">
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="EventScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
@ -26,7 +20,6 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -37,25 +30,22 @@
<attribute schema="VOID" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Attachable" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Process" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="Deletable" />
<interface name="Togglable" />
<element schema="BreakpointLocation" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -72,11 +62,10 @@
</schema>
<schema name="WatchpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="Deletable" />
<interface name="Togglable" />
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_expression" to="Expression" />
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="Kinds" schema="STRING" required="yes" hidden="yes" />
<attribute-alias from="_kinds" to="Kinds" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -90,7 +79,6 @@
<attribute schema="VOID" />
</schema>
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="PID" schema="LONG" />
<attribute-alias from="_pid" to="PID" />
@ -103,14 +91,6 @@
<interface name="Process" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Attacher" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Launcher" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" />
@ -124,7 +104,6 @@
<attribute-alias from="_pid" to="PID" />
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute-alias from="_state" to="State" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -146,7 +125,6 @@
<attribute schema="VOID" />
</schema>
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="ModuleContainer" />
<element schema="Module" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -168,30 +146,19 @@
<attribute schema="VOID" />
</schema>
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<element schema="BreakpointLocation" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Thread" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
<interface name="Method" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" required="yes" fixed="yes" hidden="yes" />
<attribute name="_return_type" schema="TYPE" required="yes" fixed="yes" hidden="yes" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute schema="VOID" fixed="yes" hidden="yes" />
</schema>
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
<interface name="Activatable" />
<interface name="Thread" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
@ -203,7 +170,6 @@
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Advance" schema="Method" required="yes" fixed="yes" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
@ -234,7 +200,6 @@
<attribute schema="VOID" />
</schema>
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Section" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
@ -246,13 +211,11 @@
<attribute schema="VOID" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
@ -286,7 +249,6 @@
</schema>
<schema name="RegisterValueContainer" attributeResync="ONCE">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<attribute name="General Purpose Registers" schema="RegisterBank" />
<attribute name="Floating Point Registers" schema="RegisterBank" />
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
@ -298,7 +260,6 @@
<attribute schema="VOID" />
</schema>
<schema name="RegisterBank" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="RegisterBank" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>

View file

@ -28,7 +28,7 @@ import ghidra.trace.model.Trace;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.TraceSchedule;
import ghidra.util.TriConsumer;
@ -467,14 +467,14 @@ public interface DebuggerTraceManagerService {
* @param path the path
* @return the best coordinates
*/
DebuggerCoordinates resolvePath(TraceObjectKeyPath path);
DebuggerCoordinates resolvePath(KeyPath path);
/**
* Activate the given canonical object path
*
* @param path the desired path
*/
default void activatePath(TraceObjectKeyPath path) {
default void activatePath(KeyPath path) {
activate(resolvePath(path));
}

View file

@ -27,7 +27,6 @@ import generic.theme.GIcon;
import ghidra.app.services.DebuggerEmulationService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
import ghidra.async.AsyncUtils;
import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.plugintool.PluginTool;
@ -258,7 +257,7 @@ public enum ControlMode {
return CompletableFuture.failedFuture(new MemoryAccessException());
}
}
return AsyncUtils.nil();
return CompletableFuture.completedFuture(null);
}
@Override

View file

@ -16,19 +16,19 @@
package ghidra.debug.api.model;
import docking.DefaultActionContext;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
/**
* Really just used by scripts to get a path into an action context
*/
public class DebuggerSingleObjectPathActionContext extends DefaultActionContext {
private final TraceObjectKeyPath path;
private final KeyPath path;
public DebuggerSingleObjectPathActionContext(TraceObjectKeyPath path) {
public DebuggerSingleObjectPathActionContext(KeyPath path) {
this.path = path;
}
public TraceObjectKeyPath getPath() {
public KeyPath getPath() {
return path;
}
}

View file

@ -22,18 +22,18 @@ import java.util.function.BooleanSupplier;
import java.util.function.Function;
import docking.ActionContext;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
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.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.TraceMemoryState;
import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Swing;
import ghidra.util.exception.CancelledException;
@ -196,7 +196,7 @@ public interface Target {
* @param path the path of the object
* @return the thread, or null
*/
TraceThread getThreadForSuccessor(TraceObjectKeyPath path);
TraceThread getThreadForSuccessor(KeyPath path);
/**
* Get the execution state of the given thread
@ -204,7 +204,7 @@ public interface Target {
* @param thread the thread
* @return the state
*/
TargetExecutionState getThreadExecutionState(TraceThread thread);
TraceExecutionState getThreadExecutionState(TraceThread thread);
/**
* Get the trace stack frame that contains the given object
@ -212,7 +212,7 @@ public interface Target {
* @param path the path of the object
* @return the stack frame, or null
*/
TraceStackFrame getStackFrameForSuccessor(TraceObjectKeyPath path);
TraceStackFrame getStackFrameForSuccessor(KeyPath path);
/**
* Check if the target supports synchronizing focus
@ -226,7 +226,7 @@ public interface Target {
*
* @return the focused object's path, or null
*/
TraceObjectKeyPath getFocus();
KeyPath getFocus();
/**
* @see #activate(DebuggerCoordinates, DebuggerCoordinates)

View file

@ -21,7 +21,6 @@ import java.util.*;
import org.jdom.Element;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.dbg.target.TargetObject;
import ghidra.debug.api.target.Target;
import ghidra.framework.data.DefaultProjectData;
import ghidra.framework.model.*;
@ -35,7 +34,7 @@ import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.stack.*;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.TraceSnapshot;
@ -98,7 +97,7 @@ public class DebuggerCoordinates {
private final TraceProgramView view;
private final TraceSchedule time;
private final Integer frame;
private final TraceObjectKeyPath path;
private final KeyPath path;
private final int hash;
@ -107,7 +106,7 @@ public class DebuggerCoordinates {
private TraceObject registerContainer;
DebuggerCoordinates(Trace trace, TracePlatform platform, Target target, TraceThread thread,
TraceProgramView view, TraceSchedule time, Integer frame, TraceObjectKeyPath path) {
TraceProgramView view, TraceSchedule time, Integer frame, KeyPath path) {
this.trace = trace;
this.platform = platform;
this.target = target;
@ -182,13 +181,13 @@ public class DebuggerCoordinates {
return resolveThread(trace, TraceSchedule.ZERO);
}
private static TraceObjectKeyPath resolvePath(Trace trace, TraceThread thread, Integer frame,
private static KeyPath resolvePath(Trace trace, TraceThread thread, Integer frame,
TraceSchedule time) {
TraceObjectKeyPath path = resolvePath(thread, frame, time);
KeyPath path = resolvePath(thread, frame, time);
if (path != null) {
return path;
}
return TraceObjectKeyPath.of();
return KeyPath.of();
}
private static TraceProgramView resolveView(Trace trace, TraceSchedule time) {
@ -214,7 +213,7 @@ public class DebuggerCoordinates {
TraceProgramView newView = resolveView(newTrace);
TraceSchedule newTime = null; // Allow later resolution
Integer newFrame = resolveFrame(newThread, newTime);
TraceObjectKeyPath newPath = resolvePath(newTrace, newThread, newFrame, newTime);
KeyPath newPath = resolvePath(newTrace, newThread, newFrame, newTime);
return new DebuggerCoordinates(newTrace, newPlatform, null, newThread, newView, newTime,
newFrame, newPath);
}
@ -248,7 +247,7 @@ public class DebuggerCoordinates {
return resolveFrame(target, target.getFocus());
}
private static TraceObjectKeyPath resolvePath(Target target, TraceThread thread,
private static KeyPath resolvePath(Target target, TraceThread thread,
Integer frame, TraceSchedule time) {
if (target.getSnap() != time.getSnap() || !target.isSupportsFocus()) {
return resolvePath(target.getTrace(), thread, frame, time);
@ -273,7 +272,7 @@ public class DebuggerCoordinates {
TraceProgramView newView = resolveView(newTrace);
TraceSchedule newTime = null; // Allow later resolution
Integer newFrame = resolveFrame(newThread, newTime);
TraceObjectKeyPath newPath = resolvePath(newTrace, newThread, newFrame, newTime);
KeyPath newPath = resolvePath(newTrace, newThread, newFrame, newTime);
return new DebuggerCoordinates(newTrace, newPlatform, null, newThread, newView, newTime,
newFrame, newPath);
}
@ -300,8 +299,8 @@ public class DebuggerCoordinates {
TraceThread newThread = thread != null ? thread : resolveThread(newTarget, newTime);
TraceProgramView newView = view != null ? view : resolveView(newTrace, newTime);
Integer newFrame = frame != null ? frame : resolveFrame(newTarget, newThread, newTime);
TraceObjectKeyPath threadOrFramePath = resolvePath(newTarget, newThread, newFrame, newTime);
TraceObjectKeyPath newPath = choose(path, threadOrFramePath);
KeyPath threadOrFramePath = resolvePath(newTarget, newThread, newFrame, newTime);
KeyPath newPath = choose(path, threadOrFramePath);
return new DebuggerCoordinates(newTrace, newPlatform, newTarget, newThread, newView,
newTime, newFrame, newPath);
}
@ -313,7 +312,7 @@ public class DebuggerCoordinates {
return thread(trace.getThreadManager().getThread(thread.getKey()));
}
private static TraceObjectKeyPath resolvePath(TraceThread thread, Integer frameLevel,
private static KeyPath resolvePath(TraceThread thread, Integer frameLevel,
TraceSchedule time) {
if (thread instanceof TraceObjectThread tot) {
TraceObject objThread = tot.getObject();
@ -340,8 +339,8 @@ public class DebuggerCoordinates {
return null;
}
private static TraceObjectKeyPath choose(TraceObjectKeyPath curPath,
TraceObjectKeyPath newPath) {
private static KeyPath choose(KeyPath curPath,
KeyPath newPath) {
if (curPath == null) {
return newPath;
}
@ -371,8 +370,8 @@ public class DebuggerCoordinates {
// Yes, override frame with 0 on thread changes, unless target says otherwise
Integer newFrame = resolveFrame(target, newThread, newTime);
// Yes, forced frame change may also force object change
TraceObjectKeyPath threadOrFramePath = resolvePath(newThread, newFrame, newTime);
TraceObjectKeyPath newPath = choose(path, threadOrFramePath);
KeyPath threadOrFramePath = resolvePath(newThread, newFrame, newTime);
KeyPath newPath = choose(path, threadOrFramePath);
return new DebuggerCoordinates(newTrace, newPlatform, target, newThread, newView, newTime,
newFrame, newPath);
}
@ -412,8 +411,8 @@ public class DebuggerCoordinates {
: resolveThread(trace, target, newTime);
// This will cause the frame to reset to 0 on every snap change. That's fair....
Integer newFrame = resolveFrame(newThread, newTime);
TraceObjectKeyPath threadOrFramePath = resolvePath(newThread, newFrame, newTime);
TraceObjectKeyPath newPath = choose(path, threadOrFramePath);
KeyPath threadOrFramePath = resolvePath(newThread, newFrame, newTime);
KeyPath newPath = choose(path, threadOrFramePath);
return new DebuggerCoordinates(trace, platform, target, newThread, view, newTime,
newFrame, newPath);
}
@ -425,8 +424,8 @@ public class DebuggerCoordinates {
if (Objects.equals(frame, newFrame)) {
return this;
}
TraceObjectKeyPath threadOrFramePath = resolvePath(thread, newFrame, getTime());
TraceObjectKeyPath newPath = choose(path, threadOrFramePath);
KeyPath threadOrFramePath = resolvePath(thread, newFrame, getTime());
KeyPath newPath = choose(path, threadOrFramePath);
return new DebuggerCoordinates(trace, platform, target, thread, view, time, newFrame,
newPath);
}
@ -480,7 +479,7 @@ public class DebuggerCoordinates {
return time(resolveTime(newView)).replaceView(newView);
}
private static TraceThread resolveThread(Trace trace, TraceObjectKeyPath path) {
private static TraceThread resolveThread(Trace trace, KeyPath path) {
TraceObject object = trace.getObjectManager().getObjectByCanonicalPath(path);
if (object == null) {
return null;
@ -490,7 +489,7 @@ public class DebuggerCoordinates {
.orElse(null);
}
private static Integer resolveFrame(Trace trace, TraceObjectKeyPath path) {
private static Integer resolveFrame(Trace trace, KeyPath path) {
TraceObject object = trace.getObjectManager().getObjectByCanonicalPath(path);
if (object == null) {
return null;
@ -502,7 +501,7 @@ public class DebuggerCoordinates {
return frame == null ? null : frame.getLevel();
}
public DebuggerCoordinates path(TraceObjectKeyPath newPath) {
public DebuggerCoordinates path(KeyPath newPath) {
if (trace == null && newPath == null) {
return NOWHERE;
}
@ -524,7 +523,7 @@ public class DebuggerCoordinates {
newFrame, newPath);
}
public DebuggerCoordinates pathNonCanonical(TraceObjectKeyPath newPath) {
public DebuggerCoordinates pathNonCanonical(KeyPath newPath) {
if (trace == null && newPath == null) {
return NOWHERE;
}
@ -549,19 +548,15 @@ public class DebuggerCoordinates {
throw new IllegalArgumentException("No such object at path " + newPath);
}
protected static TraceThread resolveThread(Target target, TraceObjectKeyPath objectPath) {
protected static TraceThread resolveThread(Target target, KeyPath objectPath) {
return target.getThreadForSuccessor(objectPath);
}
protected static Integer resolveFrame(Target target, TraceObjectKeyPath objectPath) {
protected static Integer resolveFrame(Target target, KeyPath objectPath) {
TraceStackFrame frame = target.getStackFrameForSuccessor(objectPath);
return frame == null ? null : frame.getLevel();
}
public DebuggerCoordinates object(TargetObject targetObject) {
return path(TraceObjectKeyPath.of(targetObject.getPath()));
}
public DebuggerCoordinates object(TraceObject newObject) {
if (newObject == null) {
return path(null);
@ -604,7 +599,7 @@ public class DebuggerCoordinates {
return frame == null ? 0 : frame;
}
public TraceObjectKeyPath getPath() {
public KeyPath getPath() {
return path;
}
@ -626,7 +621,7 @@ public class DebuggerCoordinates {
if (registerContainer != null) {
return registerContainer;
}
return registerContainer = getObject().queryRegisterContainer(getFrame());
return registerContainer = getObject().findRegisterContainer(getFrame());
}
public synchronized long getViewSnap() {
@ -761,7 +756,7 @@ public class DebuggerCoordinates {
if (trace != null && coordState.hasValue(KEY_OBJ_PATH)) {
String pathString = coordState.getString(KEY_OBJ_PATH, "");
try {
TraceObjectKeyPath path = TraceObjectKeyPath.parse(pathString);
KeyPath path = KeyPath.parse(pathString);
object = trace.getObjectManager().getObjectByCanonicalPath(path);
}
catch (Exception e) {

View file

@ -21,12 +21,11 @@ import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import ghidra.async.AsyncUtils;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.target.ActionName;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
/**
* A remote method registered by the back-end debugger.
@ -102,7 +101,7 @@ public interface RemoteMethod {
* Check the type of an argument.
*
* <p>
* This is a hack, because {@link TargetObjectSchema} expects {@link TargetObject}, or a
* This is a hack, because {@link TraceObjectSchema} expects {@link TargetObject}, or a
* primitive. We instead need {@link TraceObject}. I'd add the method to the schema, except that
* trace stuff is not in its dependencies.
*
@ -111,17 +110,17 @@ public interface RemoteMethod {
* @param sch the type of the parameter
* @param arg the argument
*/
static void checkType(String paramName, SchemaName schName, TargetObjectSchema sch,
static void checkType(String paramName, SchemaName schName, TraceObjectSchema sch,
Object arg) {
// if sch is null, it was definitely an object-type schema without context
if (sch != null) {
if (sch.getType() != TargetObject.class) {
if (sch.getType() != TraceObject.class) {
if (sch.getType().isInstance(arg)) {
return;
}
}
else if (arg instanceof TraceObject obj) {
if (sch.isAssignableFrom(obj.getTargetSchema())) {
if (sch.isAssignableFrom(obj.getSchema())) {
return;
}
}
@ -144,7 +143,7 @@ public interface RemoteMethod {
*/
default Trace validate(Map<String, Object> arguments) {
Trace trace = null;
SchemaContext ctx = EnumerableTargetObjectSchema.MinimalSchemaContext.INSTANCE;
SchemaContext ctx = PrimitiveTraceObjectSchema.MinimalSchemaContext.INSTANCE;
for (Map.Entry<String, RemoteParameter> ent : parameters().entrySet()) {
if (!arguments.containsKey(ent.getKey())) {
if (ent.getValue().required()) {
@ -165,7 +164,7 @@ public interface RemoteMethod {
}
}
SchemaName schName = ent.getValue().type();
TargetObjectSchema sch = ctx.getSchemaOrNull(schName);
TraceObjectSchema sch = ctx.getSchemaOrNull(schName);
checkType(ent.getKey(), schName, sch, arg);
}
for (Map.Entry<String, Object> ent : arguments.entrySet()) {

View file

@ -15,7 +15,7 @@
*/
package ghidra.debug.api.tracermi;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
public interface RemoteParameter {
String name();

View file

@ -27,7 +27,6 @@ import ghidra.app.script.GhidraScript;
import ghidra.app.script.GhidraState;
import ghidra.app.services.*;
import ghidra.app.services.DebuggerControlService.StateEditor;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.debug.api.breakpoint.LogicalBreakpoint;
import ghidra.debug.api.control.ControlMode;
import ghidra.debug.api.model.DebuggerObjectActionContext;
@ -51,6 +50,7 @@ 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.path.KeyPath;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.TraceSchedule;
@ -1452,13 +1452,13 @@ public interface FlatDebuggerAPI {
return createContext(objThread.getObject());
}
return new DebuggerSingleObjectPathActionContext(
TraceObjectKeyPath.parse(thread.getPath()));
KeyPath.parse(thread.getPath()));
}
default ActionContext createContext(Trace trace) {
DebuggerCoordinates coords = getTraceManager().getCurrentFor(trace);
if (coords == null) {
return new DebuggerSingleObjectPathActionContext(TraceObjectKeyPath.of());
return new DebuggerSingleObjectPathActionContext(KeyPath.of());
}
if (coords.getObject() != null) {
return createContext(coords.getObject());
@ -1466,7 +1466,7 @@ public interface FlatDebuggerAPI {
if (coords.getPath() != null) {
return new DebuggerSingleObjectPathActionContext(coords.getPath());
}
return new DebuggerSingleObjectPathActionContext(TraceObjectKeyPath.of());
return new DebuggerSingleObjectPathActionContext(KeyPath.of());
}
default ActionEntry findAction(Target target, ActionName action, ActionContext context) {
@ -1688,25 +1688,25 @@ public interface FlatDebuggerAPI {
*
* <p>
* If the trace does not have a live target, it is considered
* {@link TargetExecutionState#TERMINATED} (even if the trace <em>never</em> technically had a
* {@link TraceExecutionState#TERMINATED} (even if the trace <em>never</em> technically had a
* live target.) Otherwise, this gets the state of that live target. <b>NOTE:</b> This does not
* consider the current snap. It only considers a live target in the present.
*
* @param trace the trace
* @return the trace's execution state
*/
default TargetExecutionState getExecutionState(Trace trace) {
default TraceExecutionState getExecutionState(Trace trace) {
Target target = getTargetService().getTarget(trace);
if (target == null) {
return TargetExecutionState.TERMINATED;
return TraceExecutionState.TERMINATED;
}
// Use resume action's enablement as a proxy for state
// This should work for recorder or rmi targets
ActionEntry action = findAction(target, ActionName.RESUME, createContext(trace));
if (action == null) {
return TargetExecutionState.ALIVE;
return TraceExecutionState.ALIVE;
}
return action.isEnabled() ? TargetExecutionState.STOPPED : TargetExecutionState.RUNNING;
return action.isEnabled() ? TraceExecutionState.STOPPED : TraceExecutionState.RUNNING;
}
/**
@ -1714,7 +1714,7 @@ public interface FlatDebuggerAPI {
*
* <p>
* If the thread does not have a corresponding live target thread, it is considered
* {@link TargetExecutionState#TERMINATED} (even if the thread <em>never</em> technically had a
* {@link TraceExecutionState#TERMINATED} (even if the thread <em>never</em> technically had a
* live target thread.) Otherwise, this gets the state of that live target thread. <b>NOTE:</b>
* This does not consider the current snap. It only considers a live target thread in the
* present. In other words, if the user rewinds trace history to a point where the thread was
@ -1725,10 +1725,10 @@ public interface FlatDebuggerAPI {
* @param thread
* @return the thread's execution state
*/
default TargetExecutionState getExecutionState(TraceThread thread) {
default TraceExecutionState getExecutionState(TraceThread thread) {
DebuggerCoordinates coords = getTraceManager().getCurrentFor(thread.getTrace());
if (!coords.isAlive()) {
return TargetExecutionState.TERMINATED;
return TraceExecutionState.TERMINATED;
}
return coords.getTarget().getThreadExecutionState(thread);
}

View file

@ -25,9 +25,7 @@ eclipse.project.name = 'Debug Debugger-isf'
dependencies {
api project(':Framework-AsyncComm')
api project(':Framework-Debugging')
api project(':ProposedUtils')
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
}

View file

@ -15,9 +15,14 @@
*/
package ghidra.dbg.jdi.manager;
import ghidra.dbg.target.TargetConsole.Channel;
public interface JdiConsoleOutputListener {
/**
* For console output notifications, indicates whether it is normal or error output
*/
public static enum Channel {
STDOUT, STDERR;
}
/**
* JDI outputted some text
*

View file

@ -22,7 +22,7 @@ import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.Connector.Argument;
import ghidra.dbg.util.ShellUtils;
import ghidra.pty.ShellUtils;
public class JdiArguments {
enum Mode {

View file

@ -24,9 +24,9 @@ import ghidra.app.plugin.core.debug.client.tracermi.*;
import ghidra.app.plugin.core.debug.client.tracermi.RmiMethodRegistry.TraceMethod;
import ghidra.dbg.jdi.manager.impl.DebugStatus;
import ghidra.dbg.jdi.manager.impl.JdiManagerImpl;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.program.model.address.*;
import ghidra.trace.model.target.schema.PrimitiveTraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.util.Msg;
public class JdiConnector {
@ -92,7 +92,7 @@ public class JdiConnector {
private final Map<ReferenceType, AddressRange> cpAddressRangeByClass = new HashMap<>();
private final Map<String, DebugStatus> returnStatusMap = new HashMap<>();
final TargetObjectSchema rootSchema;
final TraceObjectSchema rootSchema;
private Map<String, String> env;
public JdiConnector(JdiManagerImpl manager, Map<String, String> env) {
@ -166,7 +166,7 @@ public class JdiConnector {
* TODO: The return type should be reflected from the method; however, none of the parameter
* collection routines currently use the return type, so just use ANY for now.
*/
TargetObjectSchema schema = EnumerableTargetObjectSchema.ANY;
TraceObjectSchema schema = PrimitiveTraceObjectSchema.ANY;
RmiRemoteMethod method = new RmiRemoteMethod(rootSchema.getContext(), name, action, display,
description, schema, methods, m);
remoteMethodRegistry.putMethod(name, method);

View file

@ -25,10 +25,10 @@ import com.sun.jdi.request.*;
import ghidra.app.plugin.core.debug.client.tracermi.*;
import ghidra.app.plugin.core.debug.client.tracermi.RmiMethodRegistry.TraceMethod;
import ghidra.dbg.target.TargetMethod.Param;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.rmi.trace.TraceRmi.MemoryState;
import ghidra.trace.model.target.iface.TraceObjectMethod.Param;
import ghidra.util.Msg;
public class JdiMethods implements RmiMethods {
@ -377,7 +377,9 @@ public class JdiMethods implements RmiMethods {
@TraceMethod(display = "Refresh reference types")
public void refresh_canonical_reference_types(
@Param(schema = "CanonicalReferenceTypeContainer", name = "container") RmiTraceObject obj) {
@Param(
schema = "CanonicalReferenceTypeContainer",
name = "container") RmiTraceObject obj) {
refresh_reference_types(obj);
}

View file

@ -1,11 +1,7 @@
<?xml version="1.0"?>
<context>
<schema name="Debugger" elementResync="NEVER" attributeResync="ALWAYS">
<interface name="Access" />
<interface name="Attacher" />
<interface name="EventScope" />
<interface name="Launcher" />
<interface name="ActiveScope" />
<interface name="FocusScope" />
<interface name="Aggregate" />
<element schema="VOID" />
@ -20,7 +16,6 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_event_process" schema="OBJECT" hidden="yes" />
<attribute name="_event_thread" schema="OBJECT" hidden="yes" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
<attribute name="_focus" schema="OBJECT" required="no" hidden="yes" />
<attribute name="_system" schema="OBJECT" hidden="no" />
<attribute name="Available" schema="AvailableContainer" fixed="yes" />
@ -73,9 +68,7 @@
<attribute schema="VOID" />
</schema>
<schema name="KernelConnector" elementResync="NEVER" attributeResync="NEVER">
<interface name="Launcher" />
<element schema="VOID" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -87,9 +80,7 @@
<attribute schema="VOID" />
</schema>
<schema name="ProcessAttachConnector" elementResync="NEVER" attributeResync="NEVER">
<interface name="Launcher" />
<element schema="VOID" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -101,9 +92,7 @@
<attribute schema="VOID" />
</schema>
<schema name="ProcessLaunchConnector" elementResync="NEVER" attributeResync="NEVER">
<interface name="Launcher" />
<element schema="VOID" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -115,9 +104,7 @@
<attribute schema="VOID" />
</schema>
<schema name="TraceOrDumpConnector" elementResync="NEVER" attributeResync="NEVER">
<interface name="Launcher" />
<element schema="VOID" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -131,17 +118,8 @@
<schema name="VirtualMachine" elementResync="NEVER" attributeResync="ONCE">
<interface name="Process" />
<interface name="Aggregate" />
<interface name="Access" />
<interface name="Activatable" />
<interface name="ExecutionStateful" />
<interface name="Interpreter" />
<interface name="Interruptible" />
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="_accessible" schema="BOOL" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
@ -168,7 +146,6 @@
<attribute schema="ANY" />
</schema>
<schema name="Available" elementResync="NEVER" attributeResync="NEVER">
<interface name="Attachable" />
<element schema="VOID" />
<attribute name="_pid" schema="LONG" hidden="yes" required="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
@ -236,16 +213,6 @@
<interface name="Activatable" />
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Access" />
<interface name="Attacher" />
<interface name="Attachable" />
<!-- interface name="Launcher" / -->
<interface name="Deletable" />
<interface name="Detachable" />
<interface name="Killable" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="_pid" schema="LONG" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
@ -258,8 +225,6 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_state" schema="EXECUTION_STATE" required="no" hidden="yes" />
<attribute name="_accessible" schema="BOOL" required="yes" hidden="yes" />
<attribute name="_supported_attach_kinds" schema="SET_ATTACH_KIND" required="yes" hidden="yes" />
<attribute name="_supported_step_kinds" schema="SET_STEP_KIND" required="yes" fixed="yes" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
@ -296,25 +261,8 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="DebugContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Aggregate" />
<element schema="OBJECT" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_update_mode" schema="UPDATE_MODE" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="no" />
<attribute schema="ANY" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<interface name="BreakpointSpecContainer" />
<element schema="BreakpointSpec" />
<attribute name="_supported_breakpoint_kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -328,12 +276,9 @@
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
<interface name="BreakpointLocation" />
<interface name="Deletable" />
<element schema="OBJECT" />
<attribute name="_expression" schema="STRING" required="yes" hidden="yes" />
<attribute name="_kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
<attribute name="_container" schema="BreakpointContainer" />
<attribute name="_affects" schema="LIST_OBJECT" hidden="yes" />
<attribute name="_kinds" schema="STRING" required="yes" hidden="yes" />
<attribute name="_spec" schema="BreakpointSpec" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
@ -362,7 +307,6 @@
<attribute schema="ANY" />
</schema>
<schema name="Event" elementResync="NEVER" attributeResync="NEVER">
<interface name="Deletable" />
<element schema="OBJECT" />
<attribute name="_enabled" schema="BOOL" required="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
@ -375,57 +319,12 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
<element schema="Symbol" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_update_mode" schema="UPDATE_MODE" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
<interface name="Symbol" />
<element schema="VOID" />
<attribute name="_namespace" schema="SymbolContainer" />
<attribute name="_data_type" schema="DATA_TYPE" fixed="yes" hidden="yes" />
<attribute name="_size" schema="LONG" fixed="yes" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_update_mode" schema="UPDATE_MODE" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_value" schema="ADDRESS" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="RegisterContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="RegisterContainer" />
<interface name="RegisterBank" />
<element schema="VOID" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="ANY" />
</schema>
<schema name="RegisterDescriptor" elementResync="NEVER" attributeResync="NEVER">
<interface name="Register" />
<element schema="VOID" />
<attribute name="_length" schema="INT" fixed="yes" hidden="yes" />
<attribute name="_container" schema="RegisterContainer" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_update_mode" schema="UPDATE_MODE" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_value" schema="ANY" required="yes" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Stack" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Stack" />
<element schema="StackFrame" />
@ -553,17 +452,14 @@
<attribute schema="ANY" />
</schema>
<schema name="CanonicalMethodContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Method" />
<attribute schema="ANY" />
</schema>
<schema name="MethodContainer" canonical="no" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Method" />
<attribute schema="ANY" />
</schema>
<schema name="MethodProxy" elementResync="NEVER" attributeResync="NEVER">
<interface name="SectionContainer" />
<element schema="Method" />
</schema>
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
@ -701,13 +597,13 @@
<attribute name="Type" schema="Type" />
<attribute schema="ANY" />
</schema>
<schema name="ClassObjecReferenceContainer" elementResync="NEVER" attributeResync="NEVER">
<element schema="ClassObjecReference" />
<schema name="ClassObjectReferenceContainer" elementResync="NEVER" attributeResync="NEVER">
<element schema="ClassObjectReference" />
</schema>
<schema name="ClassObjecReferenceProxy" elementResync="NEVER" attributeResync="NEVER">
<element schema="ClassObjecReference" />
<schema name="ClassObjectReferenceProxy" elementResync="NEVER" attributeResync="NEVER">
<element schema="ClassObjectReference" />
</schema>
<schema name="ClassObjecReference" elementResync="NEVER" attributeResync="NEVER">
<schema name="ClassObjectReference" elementResync="NEVER" attributeResync="NEVER">
<element schema="ANY" />
<attribute name="ReflectedType" schema="ReferenceTypeProxy" />
<attribute name="Relations" schema="ObjectRelations" required="no" fixed="yes" />
@ -750,7 +646,6 @@
<schema name="ThreadGroupReference" elementResync="NEVER" attributeResync="NEVER">
<interface name="Aggregate" />
<interface name="ExecutionStateful" />
<interface name="Steppable" />
<element schema="ANY" />
<attribute name="Parent" schema="ThreadGroupReferenceProxy" />
<attribute name="Relations" schema="ObjectRelations" required="no" fixed="yes" />
@ -775,12 +670,8 @@
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
<interface name="Thread" />
<interface name="Aggregate" />
<interface name="Access" />
<interface name="Activatable" />
<interface name="ExecutionStateful" />
<interface name="Resumable" />
<interface name="Steppable" />
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="_tid" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
@ -793,7 +684,6 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_accessible" schema="BOOL" required="yes" hidden="yes" />
<attribute name="_state" schema="EXECUTION_STATE" required="no" hidden="yes" />
<attribute name="_supported_step_kinds" schema="SET_STEP_KIND" required="yes" fixed="yes" hidden="yes" />
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
<attribute name="Id" schema="OBJECT" />
<attribute name="Name" schema="OBJECT" />

View file

@ -33,7 +33,6 @@ dependencies {
testImplementation project(path: ':Generic', configuration: 'testArtifacts')
testImplementation project(path: ':Debugger', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-TraceModeling', configuration: 'testArtifacts')
}

View file

@ -27,8 +27,6 @@ import org.jdom.JDOMException;
import com.google.protobuf.ByteString;
import ghidra.app.plugin.core.debug.service.tracermi.TraceRmiHandler;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.rmi.trace.TraceRmi;
@ -36,6 +34,8 @@ import ghidra.rmi.trace.TraceRmi.*;
import ghidra.rmi.trace.TraceRmi.Language;
import ghidra.rmi.trace.TraceRmi.Value.Builder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.util.Msg;
import ghidra.util.Swing;
@ -83,7 +83,7 @@ public class RmiClient {
private static RmiMethodRegistry methodRegistry;
private Deque<RequestResult> requests = new LinkedList<>();
public static TargetObjectSchema loadSchema(String resourceName, String rootName) {
public static TraceObjectSchema loadSchema(String resourceName, String rootName) {
XmlSchemaContext schemaContext;
try {
@ -820,7 +820,7 @@ public class RmiClient {
}
}
public TargetObjectSchema getSchema(String schema) {
public TraceObjectSchema getSchema(String schema) {
return schemaContext.getSchema(new SchemaName(schema));
}

View file

@ -18,10 +18,9 @@ package ghidra.app.plugin.core.debug.client.tracermi;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.trace.model.target.iface.TraceObjectMethod.ParameterDescription;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
public class RmiRemoteMethod {
@ -31,12 +30,12 @@ public class RmiRemoteMethod {
private String display;
private String description;
private RmiRemoteMethodParameter[] params;
private TargetObjectSchema schema;
private TraceObjectSchema schema;
private RmiMethods instance;
private Method m;
public RmiRemoteMethod(SchemaContext schemaContext, String name, String action, String display,
String description, TargetObjectSchema schema, RmiMethods instance, Method m) {
String description, TraceObjectSchema schema, RmiMethods instance, Method m) {
this.schemaContext = schemaContext;
this.name = name;
this.action = action;
@ -49,10 +48,10 @@ public class RmiRemoteMethod {
int i = 0;
for (Parameter p : m.getParameters()) {
ParameterDescription<?> desc = TargetMethod.ParameterDescription.annotated(p);
TargetObjectSchema pschema;
ParameterDescription<?> desc = ParameterDescription.annotated(p);
TraceObjectSchema pschema;
if (desc.type != RmiTraceObject.class) {
pschema = EnumerableTargetObjectSchema.schemaForPrimitive(desc.type);
pschema = PrimitiveTraceObjectSchema.schemaForPrimitive(desc.type);
}
else {
pschema = schemaContext.getSchema(new SchemaName(desc.schema));
@ -86,7 +85,7 @@ public class RmiRemoteMethod {
return m;
}
public TargetObjectSchema getSchema() {
public TraceObjectSchema getSchema() {
return schema;
}

View file

@ -15,19 +15,19 @@
*/
package ghidra.app.plugin.core.debug.client.tracermi;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.rmi.trace.TraceRmi.*;
import ghidra.trace.model.target.schema.TraceObjectSchema;
public class RmiRemoteMethodParameter {
private final String name;
private final TargetObjectSchema schema;
private final TraceObjectSchema schema;
private final boolean required;
private final Object defaultValue;
private final String display;
private final String description;
public RmiRemoteMethodParameter(String name, TargetObjectSchema schema, boolean required,
public RmiRemoteMethodParameter(String name, TraceObjectSchema schema, boolean required,
Object defaultValue, String display, String description) {
this.name = name;
this.schema = schema;

View file

@ -21,12 +21,12 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import ghidra.app.plugin.core.debug.client.tracermi.RmiClient.RequestResult;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.RegisterValue;
import ghidra.rmi.trace.TraceRmi.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.util.LockHold;
import ghidra.util.Msg;
@ -181,7 +181,7 @@ public class RmiTrace {
RmiTraceObject parent = proxyObject(d.getParent());
Lifespan span = Lifespan.span(d.getSpan().getMin(), d.getSpan().getMax());
Object value = client.argToObject(id, d.getValue());
TargetObjectSchema schema = client.getSchema(client.argToType(d.getValue()));
TraceObjectSchema schema = client.getSchema(client.argToType(d.getValue()));
result.add(new RmiTraceObjectValue(parent, span, d.getKey(), value, schema));
}
return result;

View file

@ -15,8 +15,8 @@
*/
package ghidra.app.plugin.core.debug.client.tracermi;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.schema.TraceObjectSchema;
public record RmiTraceObjectValue(RmiTraceObject parent, Lifespan span, String key, Object value,
TargetObjectSchema schema) {}
TraceObjectSchema schema) {}

View file

@ -24,14 +24,13 @@ import javax.swing.JLabel;
import ghidra.app.plugin.core.debug.gui.AbstractDebuggerParameterDialog;
import ghidra.app.plugin.core.debug.service.tracermi.TraceRmiTarget.Missing;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.debug.api.ValStr;
import ghidra.debug.api.tracermi.RemoteParameter;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.ConfigStateField;
import ghidra.framework.plugintool.PluginTool;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.schema.SchemaContext;
public class RemoteMethodInvocationDialog extends AbstractDebuggerParameterDialog<RemoteParameter> {
@ -84,11 +83,7 @@ public class RemoteMethodInvocationDialog extends AbstractDebuggerParameterDialo
@Override
protected Class<?> parameterType(RemoteParameter parameter) {
Class<?> type = ctx.getSchema(parameter.type()).getType();
if (TargetObject.class.isAssignableFrom(type)) {
return TraceObject.class;
}
return type;
return ctx.getSchema(parameter.type()).getType();
}
@Override

View file

@ -36,7 +36,6 @@ import ghidra.app.plugin.core.terminal.TerminalListener;
import ghidra.app.services.*;
import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
import ghidra.async.AsyncUtils;
import ghidra.dbg.util.ShellUtils;
import ghidra.debug.api.ValStr;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.DebuggerMissingProgramActionContext;

View file

@ -27,12 +27,12 @@ import javax.swing.Icon;
import generic.theme.GIcon;
import generic.theme.Gui;
import ghidra.dbg.util.ShellUtils;
import ghidra.debug.api.ValStr;
import ghidra.debug.api.tracermi.LaunchParameter;
import ghidra.framework.Application;
import ghidra.framework.plugintool.AutoConfigState.PathIsDir;
import ghidra.framework.plugintool.AutoConfigState.PathIsFile;
import ghidra.pty.ShellUtils;
import ghidra.util.*;
/**

View file

@ -17,10 +17,10 @@ package ghidra.app.plugin.core.debug.service.tracermi;
import java.util.Map;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.tracermi.*;
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<String, RemoteParameter> parameters,

View file

@ -15,10 +15,10 @@
*/
package ghidra.app.plugin.core.debug.service.tracermi;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.tracermi.RemoteParameter;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
public record RecordRemoteParameter(TraceRmiHandler handler, String name, SchemaName type,
boolean required, ValueSupplier defaultValue, String display, String description)

View file

@ -35,10 +35,6 @@ import ghidra.app.plugin.core.debug.disassemble.DebuggerDisassemblerPlugin;
import ghidra.app.plugin.core.debug.disassemble.TraceDisassembleCommand;
import ghidra.app.services.DebuggerControlService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.dbg.util.PathPattern;
import ghidra.dbg.util.PathUtils;
import ghidra.debug.api.progress.CloseableTaskMonitor;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.target.Target;
@ -60,6 +56,9 @@ import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
@ -652,12 +651,12 @@ public class TraceRmiHandler extends AbstractTraceRmiConnection {
.getCompilerSpecByID(new CompilerSpecID(compiler.getId()));
}
protected static TraceObjectKeyPath toKeyPath(ObjPath path) {
return TraceObjectKeyPath.parse(path.getPath());
protected static KeyPath toKeyPath(ObjPath path) {
return KeyPath.parse(path.getPath());
}
protected static PathPattern toPathPattern(ObjPath path) {
return new PathPattern(PathUtils.parse(path.getPath()));
return PathFilter.parse(path.getPath());
}
protected static Lifespan toLifespan(Span span) {
@ -686,7 +685,7 @@ public class TraceRmiHandler extends AbstractTraceRmiConnection {
return ObjSpec.newBuilder().setId(object.getKey()).build();
}
protected static ObjPath makeObjPath(TraceObjectKeyPath path) {
protected static ObjPath makeObjPath(KeyPath path) {
return ObjPath.newBuilder().setPath(path.toString()).build();
}

View file

@ -30,13 +30,6 @@ import ghidra.app.plugin.core.debug.service.target.AbstractTarget;
import ghidra.app.services.DebuggerConsoleService;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.async.*;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.util.PathMatcher;
import ghidra.dbg.util.PathPredicates;
import ghidra.dbg.util.PathPredicates.Align;
import ghidra.debug.api.ValStr;
import ghidra.debug.api.model.DebuggerObjectActionContext;
import ghidra.debug.api.model.DebuggerSingleObjectPathActionContext;
@ -48,17 +41,20 @@ import ghidra.pcode.utils.Utils;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.stack.*;
import ghidra.trace.model.target.*;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.target.iface.*;
import ghidra.trace.model.target.info.TraceObjectInterfaceUtils;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.path.PathFilter.Align;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.thread.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
@ -110,16 +106,16 @@ public class TraceRmiTarget extends AbstractTarget {
}
@Override
public TargetExecutionState getThreadExecutionState(TraceThread thread) {
public TraceExecutionState getThreadExecutionState(TraceThread thread) {
if (!(thread instanceof TraceObjectThread tot)) {
Msg.error(this, "Non-object thread with Trace RMI!");
return TargetExecutionState.ALIVE;
return TraceExecutionState.ALIVE;
}
return tot.getObject().getExecutionState(getSnap());
}
@Override
public TraceThread getThreadForSuccessor(TraceObjectKeyPath path) {
public TraceThread getThreadForSuccessor(KeyPath path) {
TraceObject object = trace.getObjectManager().getObjectByCanonicalPath(path);
if (object == null) {
return null;
@ -130,7 +126,7 @@ public class TraceRmiTarget extends AbstractTarget {
}
@Override
public TraceStackFrame getStackFrameForSuccessor(TraceObjectKeyPath path) {
public TraceStackFrame getStackFrameForSuccessor(KeyPath path) {
TraceObject object = trace.getObjectManager().getObjectByCanonicalPath(path);
if (object == null) {
return null;
@ -203,15 +199,15 @@ public class TraceRmiTarget extends AbstractTarget {
return null;
}
TraceObjectValue attrEnabled =
object.getAttribute(getSnap(), TargetTogglable.ENABLED_ATTRIBUTE_NAME);
object.getAttribute(getSnap(), TraceObjectTogglable.KEY_ENABLED);
boolean enabled = attrEnabled != null && attrEnabled.getValue() instanceof Boolean b && b;
return !enabled;
}
protected Object findArgumentForSchema(ActionName action, ActionContext context,
TargetObjectSchema schema, boolean allowContextObject, boolean allowCoordsObject,
TraceObjectSchema schema, boolean allowContextObject, boolean allowCoordsObject,
boolean allowSuitableObject) {
if (schema instanceof EnumerableTargetObjectSchema prim) {
if (schema instanceof PrimitiveTraceObjectSchema prim) {
return switch (prim) {
case OBJECT -> findObject(context, allowContextObject, allowCoordsObject);
case ADDRESS -> findAddress(context);
@ -225,9 +221,9 @@ public class TraceRmiTarget extends AbstractTarget {
return null;
}
if (allowSuitableObject) {
return object.querySuitableSchema(schema);
return object.findSuitableSchema(schema);
}
if (object.getTargetSchema() == schema) {
if (object.getSchema() == schema) {
return object;
}
return null;
@ -246,7 +242,7 @@ public class TraceRmiTarget extends AbstractTarget {
Msg.trace(this, "No root schema, yet: " + trace);
return null;
}
TargetObjectSchema schema = ctx.getSchemaOrNull(type);
TraceObjectSchema schema = ctx.getSchemaOrNull(type);
if (schema == null) {
Msg.error(this, "Schema " + type + " not in trace! " + trace);
return null;
@ -275,19 +271,19 @@ public class TraceRmiTarget extends AbstractTarget {
return args;
}
private TargetExecutionState getStateOf(TraceObject object) {
private TraceExecutionState getStateOf(TraceObject object) {
try {
return object.getExecutionState(getSnap());
}
catch (NoSuchElementException e) {
return TargetExecutionState.TERMINATED;
return TraceExecutionState.TERMINATED;
}
}
private boolean whenState(TraceObject object,
Predicate<TargetExecutionState> predicate) {
Predicate<TraceExecutionState> predicate) {
try {
TargetExecutionState state = getStateOf(object);
TraceExecutionState state = getStateOf(object);
return state == null || predicate.test(state);
}
catch (Exception e) {
@ -300,7 +296,7 @@ public class TraceRmiTarget extends AbstractTarget {
long score = 0;
for (Object o : args.values()) {
if (o instanceof TraceObject obj) {
score += obj.getCanonicalPath().getKeyList().size();
score += obj.getCanonicalPath().size();
}
}
return score;
@ -315,7 +311,8 @@ public class TraceRmiTarget extends AbstractTarget {
RemoteParameter firstParam = method.parameters()
.values()
.stream()
.filter(p -> TargetObject.class.isAssignableFrom(ctx.getSchema(p.type()).getType()))
.filter(
p -> TraceObjectInterfaceUtils.isTraceObject(ctx.getSchema(p.type()).getType()))
.findFirst()
.orElse(null);
if (firstParam == null) {
@ -405,7 +402,7 @@ public class TraceRmiTarget extends AbstractTarget {
.values()
.stream()
.filter(p -> {
TargetObjectSchema schema = ctx.getSchemaOrNull(p.type());
TraceObjectSchema schema = ctx.getSchemaOrNull(p.type());
if (schema == null) {
Msg.error(this,
"Method " + method + " refers to invalid schema name: " + p.type());
@ -489,22 +486,22 @@ public class TraceRmiTarget extends AbstractTarget {
@Override
public boolean isSupportsFocus() {
TargetObjectSchema schema = trace.getObjectManager().getRootSchema();
TraceObjectSchema schema = trace.getObjectManager().getRootSchema();
if (schema == null) {
Msg.trace(this, "Checked for focus support before root schema is available");
return false;
}
return schema
.getInterfaces()
.contains(TargetFocusScope.class) &&
.contains(TraceObjectFocusScope.class) &&
!connection.getMethods().getByAction(ActionName.ACTIVATE).isEmpty();
}
@Override
public TraceObjectKeyPath getFocus() {
public KeyPath getFocus() {
TraceObjectValue focusVal = trace.getObjectManager()
.getRootObject()
.getAttribute(getSnap(), TargetFocusScope.FOCUS_ATTRIBUTE_NAME);
.getAttribute(getSnap(), TraceObjectFocusScope.KEY_FOCUS);
if (focusVal == null || !focusVal.isObject()) {
return null;
}
@ -552,17 +549,17 @@ public class TraceRmiTarget extends AbstractTarget {
protected static boolean typeMatches(RemoteMethod method, RemoteParameter param,
SchemaContext ctx, Class<?> type) {
TargetObjectSchema sch = ctx.getSchemaOrNull(param.type());
TraceObjectSchema sch = ctx.getSchemaOrNull(param.type());
if (sch == null) {
throw new RuntimeException(
"The parameter '%s' of method '%s' refers to a non-existent schema '%s'"
.formatted(param.name(), method.name(), param.type()));
}
if (type == TargetObject.class) {
if (type == TraceObject.class) {
// The method cannot impose any further restriction. It must accept any object.
return sch == EnumerableTargetObjectSchema.OBJECT;
return sch == PrimitiveTraceObjectSchema.OBJECT;
}
else if (TargetObject.class.isAssignableFrom(type)) {
else if (TraceObjectInterface.class.isAssignableFrom(type)) {
return sch.getInterfaces().contains(type);
}
else {
@ -651,14 +648,13 @@ public class TraceRmiTarget extends AbstractTarget {
return matchers(hasFocusTime, hasFocusSnap, hasFocus);
}
static List<ActivateMatcher> makeBySpecificity(TargetObjectSchema rootSchema,
TraceObjectKeyPath path) {
static List<ActivateMatcher> makeBySpecificity(TraceObjectSchema rootSchema,
KeyPath path) {
List<ActivateMatcher> result = new ArrayList<>();
List<String> keyList = path.getKeyList();
result.addAll(makeAllFor((keyList.size() + 1) * 3,
new TypeParamSpec("focus", TargetObject.class)));
List<TargetObjectSchema> schemas = rootSchema.getSuccessorSchemas(keyList);
for (int i = keyList.size(); i > 0; i--) { // Inclusive on both ends
result.addAll(makeAllFor((path.size() + 1) * 3,
new TypeParamSpec("focus", TraceObject.class)));
List<TraceObjectSchema> schemas = rootSchema.getSuccessorSchemas(path);
for (int i = path.size(); i > 0; i--) { // Inclusive on both ends
result.addAll(
makeAllFor(i * 3, new SchemaParamSpec("focus", schemas.get(i).getName())));
}
@ -675,7 +671,7 @@ public class TraceRmiTarget extends AbstractTarget {
record ReadMemMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final ReadMemMatcher HAS_PROC_RANGE = new ReadMemMatcher(2, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("range", AddressRange.class)));
static final ReadMemMatcher HAS_RANGE = new ReadMemMatcher(1, List.of(
new TypeParamSpec("range", AddressRange.class)));
@ -684,7 +680,7 @@ public class TraceRmiTarget extends AbstractTarget {
record WriteMemMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final WriteMemMatcher HAS_PROC_START_DATA = new WriteMemMatcher(2, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("start", Address.class),
new TypeParamSpec("data", byte[].class)));
static final WriteMemMatcher HAS_START_DATA = new WriteMemMatcher(1, List.of(
@ -695,45 +691,43 @@ public class TraceRmiTarget extends AbstractTarget {
record ReadRegsMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final ReadRegsMatcher HAS_CONTAINER = new ReadRegsMatcher(3, List.of(
new TypeParamSpec("container", TargetRegisterContainer.class)));
static final ReadRegsMatcher HAS_BANK = new ReadRegsMatcher(2, List.of(
new TypeParamSpec("bank", TargetRegisterBank.class)));
new TypeParamSpec("container", TraceObjectRegisterContainer.class)));
static final ReadRegsMatcher HAS_REGISTER = new ReadRegsMatcher(1, List.of(
new TypeParamSpec("register", TargetRegister.class)));
static final List<ReadRegsMatcher> ALL = matchers(HAS_CONTAINER, HAS_BANK, HAS_REGISTER);
new TypeParamSpec("register", TraceObjectRegister.class)));
static final List<ReadRegsMatcher> ALL = matchers(HAS_CONTAINER, HAS_REGISTER);
}
record WriteRegMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final WriteRegMatcher HAS_FRAME_NAME_VALUE = new WriteRegMatcher(3, List.of(
new TypeParamSpec("frame", TargetStackFrame.class),
new TypeParamSpec("frame", TraceObjectStackFrame.class),
new TypeParamSpec("name", String.class),
new TypeParamSpec("value", byte[].class)));
static final WriteRegMatcher HAS_THREAD_NAME_VALUE = new WriteRegMatcher(2, List.of(
new TypeParamSpec("thread", TargetThread.class),
new TypeParamSpec("thread", TraceObjectThread.class),
new TypeParamSpec("name", String.class),
new TypeParamSpec("value", byte[].class)));
static final WriteRegMatcher HAS_REG_VALUE = new WriteRegMatcher(1, List.of(
new TypeParamSpec("register", TargetRegister.class),
new TypeParamSpec("register", TraceObjectRegister.class),
new TypeParamSpec("value", byte[].class)));
static final List<WriteRegMatcher> ALL = matchers(HAS_FRAME_NAME_VALUE, HAS_REG_VALUE);
}
record BreakExecMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final BreakExecMatcher HAS_PROC_ADDR_COND_CMDS = new BreakExecMatcher(8, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("address", Address.class),
new NameParamSpec("condition", String.class),
new NameParamSpec("commands", String.class)));
static final BreakExecMatcher HAS_PROC_ADDR_COND = new BreakExecMatcher(7, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("address", Address.class),
new NameParamSpec("condition", String.class)));
static final BreakExecMatcher HAS_PROC_ADDR_CMDS = new BreakExecMatcher(6, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("address", Address.class),
new NameParamSpec("commands", String.class)));
static final BreakExecMatcher HAS_PROC_ADDR = new BreakExecMatcher(5, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("address", Address.class)));
static final BreakExecMatcher HAS_ADDR_COND_CMDS = new BreakExecMatcher(4, List.of(
new TypeParamSpec("address", Address.class),
@ -755,20 +749,20 @@ public class TraceRmiTarget extends AbstractTarget {
// TODO: Probably need a better way to deal with optional requirements
record BreakAccMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final BreakAccMatcher HAS_PROC_RNG_COND_CMDS = new BreakAccMatcher(8, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("range", AddressRange.class),
new NameParamSpec("condition", String.class),
new NameParamSpec("commands", String.class)));
static final BreakAccMatcher HAS_PROC_RNG_COND = new BreakAccMatcher(7, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("range", AddressRange.class),
new NameParamSpec("condition", String.class)));
static final BreakAccMatcher HAS_PROC_RNG_CMDS = new BreakAccMatcher(6, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("range", AddressRange.class),
new NameParamSpec("commands", String.class)));
static final BreakAccMatcher HAS_PROC_RNG = new BreakAccMatcher(5, List.of(
new TypeParamSpec("process", TargetProcess.class),
new TypeParamSpec("process", TraceObjectProcess.class),
new TypeParamSpec("range", AddressRange.class)));
static final BreakAccMatcher HAS_RNG_COND_CMDS = new BreakAccMatcher(4, List.of(
new TypeParamSpec("range", AddressRange.class),
@ -789,19 +783,19 @@ public class TraceRmiTarget extends AbstractTarget {
record DelBreakMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final DelBreakMatcher HAS_LOC = new DelBreakMatcher(2, List.of(
new TypeParamSpec("location", TargetBreakpointLocation.class)));
new TypeParamSpec("location", TraceObjectBreakpointLocation.class)));
static final DelBreakMatcher HAS_SPEC = new DelBreakMatcher(1, List.of(
new TypeParamSpec("specification", TargetBreakpointSpec.class)));
new TypeParamSpec("specification", TraceObjectBreakpointSpec.class)));
static final List<DelBreakMatcher> ALL = matchers(HAS_LOC, HAS_SPEC);
static final List<DelBreakMatcher> SPEC = matchers(HAS_SPEC);
}
record ToggleBreakMatcher(int score, List<ParamSpec> spec) implements MethodMatcher {
static final ToggleBreakMatcher HAS_LOC = new ToggleBreakMatcher(2, List.of(
new TypeParamSpec("location", TargetBreakpointLocation.class),
new TypeParamSpec("location", TraceObjectBreakpointLocation.class),
new TypeParamSpec("enabled", Boolean.class)));
static final ToggleBreakMatcher HAS_SPEC = new ToggleBreakMatcher(1, List.of(
new TypeParamSpec("specification", TargetBreakpointSpec.class),
new TypeParamSpec("specification", TraceObjectBreakpointSpec.class),
new TypeParamSpec("enabled", Boolean.class)));
static final List<ToggleBreakMatcher> ALL = matchers(HAS_LOC, HAS_SPEC);
static final List<ToggleBreakMatcher> SPEC = matchers(HAS_SPEC);
@ -928,7 +922,7 @@ public class TraceRmiTarget extends AbstractTarget {
return AsyncUtils.nil();
}
SchemaName name = object.getTargetSchema().getName();
SchemaName name = object.getSchema().getName();
MatchedMethod activate = matches.getBest("activate_" + name, ActionName.ACTIVATE,
() -> ActivateMatcher.makeBySpecificity(trace.getObjectManager().getRootSchema(),
object.getCanonicalPath()));
@ -939,7 +933,7 @@ public class TraceRmiTarget extends AbstractTarget {
Map<String, Object> args = new HashMap<>();
RemoteParameter paramFocus = activate.params.get("focus");
args.put(paramFocus.name(),
object.querySuitableSchema(getSchemaContext().getSchema(paramFocus.type())));
object.findSuitableSchema(getSchemaContext().getSchema(paramFocus.type())));
RemoteParameter paramTime = activate.params.get("time");
if (paramTime != null) {
args.put(paramTime.name(), coords.getTime().toString());
@ -974,7 +968,7 @@ public class TraceRmiTarget extends AbstractTarget {
}
protected SchemaContext getSchemaContext() {
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return null;
}
@ -987,7 +981,7 @@ public class TraceRmiTarget extends AbstractTarget {
Lifespan.at(getSnap()),
new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress()))) {
TraceObject obj = ((TraceObjectMemoryRegion) region).getObject();
return obj.queryCanonicalAncestorsTargetInterface(TargetProcess.class)
return obj.findCanonicalAncestorsInterface(TraceObjectProcess.class)
.findFirst()
.orElse(null);
}
@ -1092,7 +1086,7 @@ public class TraceRmiTarget extends AbstractTarget {
Msg.error(this, "Non-object trace with TraceRmi!");
return AsyncUtils.nil();
}
TraceObject container = tot.getObject().queryRegisterContainer(frame);
TraceObject container = tot.getObject().findRegisterContainer(frame);
if (container == null) {
Msg.error(this,
"Cannot find register container for thread,frame: " + thread + "," + frame);
@ -1110,25 +1104,11 @@ public class TraceRmiTarget extends AbstractTarget {
keys.add("[" + lower + "]");
}
Set<TraceObject> regs = container
.querySuccessorsTargetInterface(Lifespan.at(getSnap()), TargetRegister.class,
.findSuccessorsInterface(Lifespan.at(getSnap()), TraceObjectRegister.class,
true)
.filter(p -> keys.contains(p.getLastEntry().getEntryKey().toLowerCase()))
.map(r -> r.getDestination(null))
.collect(Collectors.toSet());
RemoteParameter paramBank = readRegs.params.get("bank");
if (paramBank != null) {
Set<TraceObject> banks = regs.stream()
.flatMap(r -> r.queryCanonicalAncestorsTargetInterface(TargetRegisterBank.class)
.findFirst()
.stream())
.collect(Collectors.toSet());
AsyncFence fence = new AsyncFence();
banks.stream().forEach(b -> {
fence.include(requestCaches.readRegs(b, readRegs.method, Map.of(
paramBank.name(), b)));
});
return fence.ready();
}
RemoteParameter paramRegister = readRegs.params.get("register");
if (paramRegister != null) {
AsyncFence fence = new AsyncFence();
@ -1142,17 +1122,18 @@ public class TraceRmiTarget extends AbstractTarget {
}
protected TraceObject findRegisterObject(TraceObjectThread thread, int frame, String name) {
TraceObject container = thread.getObject().queryRegisterContainer(frame);
TraceObject container = thread.getObject().findRegisterContainer(frame);
if (container == null) {
Msg.error(this, "No register container for thread=" + thread + ",frame=" + frame);
return null;
}
PathMatcher matcher = container.getTargetSchema().searchFor(TargetRegister.class, true);
PathPredicates pred = matcher.applyKeys(Align.RIGHT, name)
PathMatcher matcher =
container.getSchema().searchFor(TraceObjectRegister.class, true);
PathFilter filter = matcher.applyKeys(Align.RIGHT, name)
.or(matcher.applyKeys(Align.RIGHT, name.toLowerCase()))
.or(matcher.applyKeys(Align.RIGHT, name.toUpperCase()));
TraceObjectValPath regValPath =
container.getCanonicalSuccessors(pred).findFirst().orElse(null);
container.getCanonicalSuccessors(filter).findFirst().orElse(null);
if (regValPath == null) {
Msg.error(this, "Cannot find register object for " + name + " in " + container);
return null;

View file

@ -32,15 +32,15 @@ import ghidra.app.plugin.core.debug.gui.InvocationDialogHelper;
import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiConnection.TestRemoteMethod;
import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiConnection.TestRemoteParameter;
import ghidra.async.SwingExecutorService;
import ghidra.dbg.target.TargetMethod.Param;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema.MinimalSchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.ValStr;
import ghidra.debug.api.tracermi.RemoteMethod;
import ghidra.debug.api.tracermi.RemoteParameter;
import ghidra.framework.options.PropertyBoolean;
import ghidra.trace.model.target.iface.TraceObjectMethod.Param;
import ghidra.trace.model.target.iface.TraceObjectMethod.ParameterDescription;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.PrimitiveTraceObjectSchema.MinimalSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
public class RemoteMethodInvocationDialogTest extends AbstractGhidraHeadedDebuggerTest {
@ -53,14 +53,14 @@ public class RemoteMethodInvocationDialogTest extends AbstractGhidraHeadedDebugg
params.put(parameter.name(), parameter);
}
return new TestRemoteMethod(m.getName(), null, "Test", "A test method", params,
EnumerableTargetObjectSchema.schemaForPrimitive(m.getReturnType()));
PrimitiveTraceObjectSchema.schemaForPrimitive(m.getReturnType()));
}
public static TestRemoteParameter createParameter(Parameter p) {
ParameterDescription<?> desc = ParameterDescription.annotated(p);
TargetObjectSchema schema = EnumerableTargetObjectSchema.schemaForPrimitive(desc.type);
if (schema == EnumerableTargetObjectSchema.OBJECT ||
schema == EnumerableTargetObjectSchema.ANY) {
TraceObjectSchema schema = PrimitiveTraceObjectSchema.schemaForPrimitive(desc.type);
if (schema == PrimitiveTraceObjectSchema.OBJECT ||
schema == PrimitiveTraceObjectSchema.ANY) {
schema = CTX.getSchema(new SchemaName(desc.schema));
}
return new TestRemoteParameter(desc.name, schema, desc.required, desc.defaultValue,

View file

@ -38,13 +38,13 @@ import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiClient.Tx;
import ghidra.app.plugin.core.debug.service.tracermi.TraceRmiPlugin;
import ghidra.app.services.DebuggerControlService;
import ghidra.app.services.TraceRmiService;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.control.ControlMode;
import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracermi.TraceRmiAcceptor;
import ghidra.debug.api.tracermi.TraceRmiConnection;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.util.exception.CancelledException;
public class TraceRmiConnectionManagerProviderTest extends AbstractGhidraHeadedDebuggerTest {

View file

@ -25,20 +25,21 @@ import db.Transaction;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiConnection.TestRemoteMethod;
import ghidra.app.plugin.core.debug.service.tracermi.TestTraceRmiConnection.TestRemoteParameter;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.tracermi.RemoteMethod;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.PrimitiveTraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateObjectGivenObject() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", EnumerableTargetObjectSchema.OBJECT.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", PrimitiveTraceObjectSchema.OBJECT.getName(), true,
null, "Arg1", "An argument"));
createTrace();
@ -56,8 +57,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateObjectGivenProcess() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", EnumerableTargetObjectSchema.OBJECT.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", PrimitiveTraceObjectSchema.OBJECT.getName(), true,
null, "Arg1", "An argument"));
createTrace();
@ -66,7 +67,7 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getObjectManager().createRootObject(CTX.getSchema(new SchemaName("Session")));
process =
tb.trace.getObjectManager().createObject(TraceObjectKeyPath.parse("Processes[0]"));
tb.trace.getObjectManager().createObject(KeyPath.parse("Processes[0]"));
process.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
}
@ -76,8 +77,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test(expected = IllegalArgumentException.class)
public void testRemoteMethodValidateObjectGivenInt() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", EnumerableTargetObjectSchema.OBJECT.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("obj", PrimitiveTraceObjectSchema.OBJECT.getName(), true,
null, "Arg1", "An argument"));
method.validate(Map.of("obj", 1));
@ -86,7 +87,7 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateProcessGivenProcess() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("proc", new SchemaName("Process"), true,
null, "Proc1", "A Process argument"));
@ -96,7 +97,7 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getObjectManager().createRootObject(CTX.getSchema(new SchemaName("Session")));
process =
tb.trace.getObjectManager().createObject(TraceObjectKeyPath.parse("Processes[0]"));
tb.trace.getObjectManager().createObject(KeyPath.parse("Processes[0]"));
process.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
}
@ -106,7 +107,7 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test(expected = IllegalArgumentException.class)
public void testRemoteMethodValidateProcessGivenInt() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("proc", new SchemaName("Process"), true,
null, "Proc1", "A Process argument"));
@ -122,8 +123,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateAnyGivenInteger() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", EnumerableTargetObjectSchema.ANY.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", PrimitiveTraceObjectSchema.ANY.getName(), true,
null, "Arg1", "An argument"));
method.validate(Map.of("arg", 1));
@ -132,8 +133,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateAnyGivenObject() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", EnumerableTargetObjectSchema.ANY.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", PrimitiveTraceObjectSchema.ANY.getName(), true,
null, "Arg1", "An argument"));
createTrace();
@ -151,8 +152,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateAnyGivenProcess() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", EnumerableTargetObjectSchema.ANY.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", PrimitiveTraceObjectSchema.ANY.getName(), true,
null, "Arg1", "An argument"));
createTrace();
@ -161,7 +162,7 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getObjectManager().createRootObject(CTX.getSchema(new SchemaName("Session")));
process =
tb.trace.getObjectManager().createObject(TraceObjectKeyPath.parse("Processes[0]"));
tb.trace.getObjectManager().createObject(KeyPath.parse("Processes[0]"));
process.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
}
@ -171,8 +172,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test
public void testRemoteMethodValidateIntegerGivenInteger() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", EnumerableTargetObjectSchema.INT.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", PrimitiveTraceObjectSchema.INT.getName(), true,
null, "Arg1", "An argument"));
method.validate(Map.of("arg", 1));
@ -181,8 +182,8 @@ public class RemoteMethodTest extends AbstractGhidraHeadedDebuggerTest {
@Test(expected = IllegalArgumentException.class)
public void testRemoteMethodValidateIntegerGivenLong() throws Throwable {
RemoteMethod method = new TestRemoteMethod("test", ActionName.name("test"), "Test",
"A test method", EnumerableTargetObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", EnumerableTargetObjectSchema.INT.getName(), true,
"A test method", PrimitiveTraceObjectSchema.VOID.getName(),
new TestRemoteParameter("arg", PrimitiveTraceObjectSchema.INT.getName(), true,
null, "Arg1", "An argument"));
method.validate(Map.of("arg", 1L));

View file

@ -20,11 +20,11 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.framework.Application;
import ghidra.rmi.trace.TraceRmi.*;
import ghidra.rmi.trace.TraceRmi.Compiler;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.target.schema.XmlSchemaContext;
public class TestTraceRmiClient {
final ProtobufSocket<RootMessage> socket;
@ -128,7 +128,7 @@ public class TestTraceRmiClient {
socket.recv());
}
public void createRootObject(int traceId, TargetObjectSchema schema) throws IOException {
public void createRootObject(int traceId, TraceObjectSchema schema) throws IOException {
String xmlCtx = XmlSchemaContext.serialize(schema.getContext());
socket.send(RootMessage.newBuilder()
.setRequestCreateRootObject(RequestCreateRootObject.newBuilder()

View file

@ -27,14 +27,14 @@ import java.util.stream.Stream;
import db.Transaction;
import ghidra.app.services.DebuggerTargetService;
import ghidra.async.*;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracermi.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.time.TraceSnapshot;
public abstract class TestTraceRmiConnection extends AbstractTraceRmiConnection {
@ -70,13 +70,13 @@ public abstract class TestTraceRmiConnection extends AbstractTraceRmiConnection
}
public TestRemoteMethod(String name, ActionName action, String display, String description,
Map<String, RemoteParameter> parameters, TargetObjectSchema retType) {
Map<String, RemoteParameter> parameters, TraceObjectSchema retType) {
this(name, action, display, description, parameters, retType.getName(),
new AsyncPairingQueue<>(), new AsyncPairingQueue<>());
}
public TestRemoteMethod(String name, ActionName action, String display, String description,
TargetObjectSchema retType, RemoteParameter... parameters) {
TraceObjectSchema retType, RemoteParameter... parameters) {
this(name, action, display, description, Stream.of(parameters)
.collect(Collectors.toMap(RemoteParameter::name, p -> p)),
retType);
@ -110,7 +110,7 @@ public abstract class TestTraceRmiConnection extends AbstractTraceRmiConnection
public record TestRemoteParameter(String name, SchemaName type, boolean required,
Object defaultValue, String display, String description) implements RemoteParameter {
public TestRemoteParameter(String name, TargetObjectSchema type, boolean required,
public TestRemoteParameter(String name, TraceObjectSchema type, boolean required,
Object defaultValue, String display, String description) {
this(name, type.getName(), required, defaultValue, display, description);
}

View file

@ -25,7 +25,6 @@ eclipse.project.name = 'Debug Debugger'
dependencies {
api project(':Debugger-api')
api project(':Framework-AsyncComm')
api project(':Framework-Debugging')
api project(':Framework-TraceModeling')
api project(':Base')
api project(':ByteViewer')
@ -36,7 +35,6 @@ dependencies {
testImplementation project(path: ':Generic', configuration: 'testArtifacts')
testImplementation project(path: ':Base', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-TraceModeling', configuration: 'testArtifacts')
testImplementation project(path: ':Project', configuration: 'testArtifacts')
}

View file

@ -1,36 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.debug.event;
import java.lang.ref.WeakReference;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.framework.plugintool.PluginEvent;
public class ModelActivatedPluginEvent extends PluginEvent {
static final String NAME = "Model Focus";
private final WeakReference<DebuggerObjectModel> newModelRef;
public ModelActivatedPluginEvent(String source, DebuggerObjectModel model) {
super(source, NAME);
this.newModelRef = new WeakReference<>(model);
}
public DebuggerObjectModel getActiveModel() {
return newModelRef.get();
}
}

View file

@ -16,7 +16,6 @@
package ghidra.app.plugin.core.debug.gui.memory;
import java.awt.Font;
import java.util.List;
import java.util.Set;
import javax.swing.*;
@ -27,15 +26,15 @@ import docking.ReusableDialogComponentProvider;
import docking.widgets.model.GAddressRangeField;
import docking.widgets.model.GSpanField;
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.util.layout.PairLayout;
public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
@ -155,17 +154,17 @@ public class DebuggerAddRegionDialog extends ReusableDialogComponentProvider {
}
protected String computeDefaultPath(DebuggerCoordinates current) {
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return "";
}
List<String> suitable = rootSchema.searchForSuitableContainer(TargetMemoryRegion.class,
current.getPath().getKeyList());
KeyPath suitable = rootSchema.searchForSuitableContainer(TraceObjectMemoryRegion.class,
current.getPath());
if (suitable == null) {
return "";
}
return TraceObjectKeyPath.of(suitable).index("New").toString();
return suitable.index("New").toString();
}
protected void setValues(DebuggerCoordinates current) {

View file

@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.memory;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -23,8 +22,6 @@ import docking.widgets.table.TableColumnDescriptor;
import ghidra.app.plugin.core.debug.gui.model.*;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.debug.api.model.DebuggerObjectActionContext;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
@ -32,9 +29,11 @@ import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.thread.TraceObjectProcess;
public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceObjectMemoryRegion> {
@ -67,7 +66,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class RegionStartColumn extends AbstractTraceValueObjectAddressColumn {
public RegionStartColumn() {
super(TargetMemoryRegion.RANGE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_RANGE);
}
@Override
@ -83,7 +82,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class RegionEndColumn extends AbstractTraceValueObjectAddressColumn {
public RegionEndColumn() {
super(TargetMemoryRegion.RANGE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_RANGE);
}
@Override
@ -99,7 +98,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class RegionLengthColumn extends AbstractTraceValueObjectLengthColumn {
public RegionLengthColumn() {
super(TargetMemoryRegion.RANGE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_RANGE);
}
@Override
@ -121,7 +120,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
public static class RegionReadColumn extends RegionFlagColumn {
public RegionReadColumn() {
super(TargetMemoryRegion.READABLE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_READABLE);
}
@Override
@ -132,7 +131,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
public static class RegionWriteColumn extends RegionFlagColumn {
public RegionWriteColumn() {
super(TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_WRITABLE);
}
@Override
@ -143,7 +142,7 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
public static class RegionExecuteColumn extends RegionFlagColumn {
public RegionExecuteColumn() {
super(TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME);
super(TraceObjectMemoryRegion.KEY_EXECUTABLE);
}
@Override
@ -173,9 +172,9 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
}
}
protected static ModelQuery successorRegions(TargetObjectSchema rootSchema, List<String> path) {
TargetObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TargetMemoryRegion.class, path, true));
protected static ModelQuery successorRegions(TraceObjectSchema rootSchema, KeyPath path) {
TraceObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TraceObjectMemoryRegion.class, path, true));
}
protected Set<TraceMemoryRegion> getSelectedRegions(DebuggerObjectActionContext ctx) {
@ -193,23 +192,23 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
@Override
protected ModelQuery computeQuery(TraceObject object) {
TargetObjectSchema rootSchema = object.getRoot().getTargetSchema();
List<String> seedPath = object.getCanonicalPath().getKeyList();
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
TraceObjectSchema rootSchema = object.getRoot().getSchema();
KeyPath seedPath = object.getCanonicalPath();
KeyPath processPath = rootSchema.searchForAncestor(TraceObjectProcess.class, seedPath);
if (processPath != null) {
ModelQuery result = successorRegions(rootSchema, processPath);
if (!result.isEmpty()) {
return result;
}
}
List<String> memoryPath = rootSchema.searchForSuitable(TargetMemory.class, seedPath);
KeyPath memoryPath = rootSchema.searchForSuitable(TraceObjectMemory.class, seedPath);
if (memoryPath != null) {
ModelQuery result = successorRegions(rootSchema, memoryPath);
if (!result.isEmpty()) {
return result;
}
}
return successorRegions(rootSchema, List.of());
return successorRegions(rootSchema, KeyPath.ROOT);
}
public void setSelectedRegions(Set<TraceMemoryRegion> sel) {

View file

@ -35,6 +35,8 @@ import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.iface.TraceObjectInterface;
import ghidra.trace.model.target.path.KeyPath;
public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterface>
extends ObjectsTablePanel
@ -136,7 +138,7 @@ public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterf
}
@Override
public void activatePath(TraceObjectKeyPath path) {
public void activatePath(KeyPath path) {
if (current.getTrace() == null) {
return;
}

View file

@ -63,6 +63,7 @@ import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
@ -229,7 +230,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
protected PathsTablePanel attributesTablePanel;
/*testing*/ DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
/*testing*/ TraceObjectKeyPath path = TraceObjectKeyPath.of();
/*testing*/ KeyPath path = KeyPath.of();
@AutoServiceConsumed
protected DebuggerTraceManagerService traceManager;
@ -433,7 +434,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
mainPanel.revalidate();
}
protected void activatePath(TraceObjectKeyPath path) {
protected void activatePath(KeyPath path) {
if (current.getTrace() == null) {
return;
}
@ -457,7 +458,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
}
@Override
public void activatePath(TraceObjectKeyPath path) {
public void activatePath(KeyPath path) {
DebuggerModelProvider.this.activatePath(path);
}
}
@ -510,7 +511,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
List<AbstractNode> sel = objectsTreePanel.getSelectedItems();
if (sel.size() == 1) {
TraceObjectValue value = sel.get(0).getValue();
setPath(value == null ? TraceObjectKeyPath.of() : value.getCanonicalPath(),
setPath(value == null ? KeyPath.of() : value.getCanonicalPath(),
objectsTreePanel, EventOrigin.INTERNAL_GENERATED);
}
}
@ -674,7 +675,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
@Override
public boolean verify(JComponent input) {
try {
TraceObjectKeyPath path = TraceObjectKeyPath.parse(pathField.getText());
KeyPath path = KeyPath.parse(pathField.getText());
setPath(path, null, EventOrigin.USER_GENERATED);
return true;
}
@ -687,7 +688,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
goButton = new JButton("Go");
ActionListener gotoPath = evt -> {
try {
TraceObjectKeyPath path = TraceObjectKeyPath.parse(pathField.getText());
KeyPath path = KeyPath.parse(pathField.getText());
activatePath(path);
KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
}
@ -854,7 +855,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
SaveState dataState = new SaveState();
this.writeDataState(dataState);
// Selection is not saved to the tool state
Set<TraceObjectKeyPath> selection = this.objectsTreePanel.getSelectedKeyPaths();
Set<KeyPath> selection = this.objectsTreePanel.getSelectedKeyPaths();
// coords are omitted by main window
// also, cannot save unless trace is in a project
clone.coordinatesActivated(current);
@ -908,7 +909,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
if (values.size() != 1) {
return;
}
TraceObjectKeyPath canonicalPath = values.get(0).getChild().getCanonicalPath();
KeyPath canonicalPath = values.get(0).getChild().getCanonicalPath();
setPath(canonicalPath);
}
@ -917,12 +918,12 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
return mainPanel;
}
protected TraceObjectKeyPath findAsSibling(TraceObject object) {
protected KeyPath findAsSibling(TraceObject object) {
Trace trace = current.getTrace();
if (trace == null) {
return null;
}
TraceObjectKeyPath parentPath = path.parent();
KeyPath parentPath = path.parent();
if (parentPath == null) {
return null;
}
@ -940,7 +941,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
return null;
}
protected TraceObjectKeyPath findAsParent(TraceObject object) {
protected KeyPath findAsParent(TraceObject object) {
Trace trace = current.getTrace();
if (trace == null) {
return null;
@ -953,7 +954,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
if (sel == null) {
return null;
}
for (TraceObjectKeyPath p = sel.getCanonicalPath(); p != null; p = p.parent()) {
for (KeyPath p = sel.getCanonicalPath(); p != null; p = p.parent()) {
if (objectManager.getObjectByCanonicalPath(p) == object) {
return p;
}
@ -985,7 +986,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
if (findAsParent(object) != null) {
return;
}
TraceObjectKeyPath sibling = findAsSibling(object);
KeyPath sibling = findAsSibling(object);
if (sibling != null) {
objectsTreePanel.setSelectedKeyPaths(List.of(sibling));
setPath(sibling);
@ -1002,7 +1003,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
}
}
protected void setPath(TraceObjectKeyPath path, JComponent source, EventOrigin origin) {
protected void setPath(KeyPath path, JComponent source, EventOrigin origin) {
if (Objects.equals(this.path, path) && getTreeSelection() != null) {
return;
}
@ -1018,11 +1019,11 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
attributesTablePanel.setQuery(ModelQuery.attributesOf(path));
}
public void setPath(TraceObjectKeyPath path) {
public void setPath(KeyPath path) {
setPath(path, null, EventOrigin.API_GENERATED);
}
public TraceObjectKeyPath getPath() {
public KeyPath getPath() {
return path;
}
@ -1137,11 +1138,11 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
return showMethodsInTree;
}
protected void setTreeSelection(TraceObjectKeyPath path, EventOrigin origin) {
protected void setTreeSelection(KeyPath path, EventOrigin origin) {
objectsTreePanel.setSelectedKeyPaths(List.of(path), origin);
}
protected void setTreeSelection(TraceObjectKeyPath path) {
protected void setTreeSelection(KeyPath path) {
setTreeSelection(path, EventOrigin.API_GENERATED);
}
@ -1189,6 +1190,6 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
coordinatesActivated(coords);
}
}
setPath(TraceObjectKeyPath.parse(saveState.getString(KEY_PATH, "")));
setPath(KeyPath.parse(saveState.getString(KEY_PATH, "")));
}
}

View file

@ -17,11 +17,11 @@ package ghidra.app.plugin.core.debug.gui.model;
import java.util.Objects;
import ghidra.dbg.util.PathPredicates;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.path.PathFilter;
public interface DisplaysModified {
/**
@ -140,8 +140,7 @@ public interface DisplaysModified {
return isEdgesDiffer(newContains ? value : null, diffEdge);
}
TraceObjectValue diffEdge = diffTrace.getObjectManager()
.getValuePaths(Lifespan.at(diffSnap),
PathPredicates.pattern(value.getCanonicalPath().getKeyList()))
.getValuePaths(Lifespan.at(diffSnap), PathFilter.pattern(value.getCanonicalPath()))
.findAny()
.map(p -> p.getLastEntry())
.orElse(null);

View file

@ -19,9 +19,9 @@ import java.util.stream.*;
import org.apache.commons.lang3.ArrayUtils;
import ghidra.dbg.target.TargetObject;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.iface.TraceObjectInterface;
import ghidra.util.HTMLUtilities;
import ghidra.util.NumericUtilities;
@ -114,7 +114,7 @@ public interface DisplaysObjectValues {
default String getObjectType(TraceObjectValue edge) {
TraceObject object = edge.getChild();
return object.getTargetSchema().getName().toString();
return object.getSchema().getName().toString();
}
default String getObjectLinkToolTip(TraceObjectValue edge) {
@ -132,7 +132,7 @@ public interface DisplaysObjectValues {
default String getObjectDisplay(TraceObjectValue edge) {
TraceObject object = edge.getChild();
TraceObjectValue displayAttr =
object.getAttribute(getSnap(), TargetObject.DISPLAY_ATTRIBUTE_NAME);
object.getAttribute(getSnap(), TraceObjectInterface.KEY_DISPLAY);
if (displayAttr != null) {
return displayAttr.getValue().toString();
}

View file

@ -15,50 +15,51 @@
*/
package ghidra.app.plugin.core.debug.gui.model;
import java.util.*;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.AttributeSchema;
import ghidra.dbg.util.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.schema.PrimitiveTraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema.AttributeSchema;
public class ModelQuery {
public static final ModelQuery EMPTY = new ModelQuery(PathPredicates.EMPTY);
public static final ModelQuery EMPTY = new ModelQuery(PathFilter.NONE);
// TODO: A more capable query language, e.g., with WHERE clauses.
// Could also want math expressions for the conditionals... Hmm.
// They need to be user enterable, so just a Java API won't suffice.
public static ModelQuery parse(String queryString) {
return new ModelQuery(PathPredicates.parse(queryString));
return new ModelQuery(PathFilter.parse(queryString));
}
public static ModelQuery elementsOf(TraceObjectKeyPath path) {
return new ModelQuery(new PathPattern(PathUtils.extend(path.getKeyList(), "[]")));
public static ModelQuery elementsOf(KeyPath path) {
return new ModelQuery(new PathPattern(path.index("")));
}
public static ModelQuery attributesOf(TraceObjectKeyPath path) {
return new ModelQuery(new PathPattern(PathUtils.extend(path.getKeyList(), "")));
public static ModelQuery attributesOf(KeyPath path) {
return new ModelQuery(new PathPattern(path.key("")));
}
private final PathPredicates predicates;
private final PathFilter filter;
/**
* TODO: This should probably be more capable, but for now, just support simple path patterns
*
* @param predicates the patterns
* @param filter the filter
*/
public ModelQuery(PathPredicates predicates) {
this.predicates = predicates;
public ModelQuery(PathFilter filter) {
this.filter = filter;
}
@Override
public String toString() {
return "<ModelQuery: " + predicates.toString() + ">";
return "<ModelQuery: " + filter.toString() + ">";
}
@Override
@ -70,7 +71,7 @@ public class ModelQuery {
return false;
}
ModelQuery that = (ModelQuery) obj;
if (!Objects.equals(this.predicates, that.predicates)) {
if (!Objects.equals(this.filter, that.filter)) {
return false;
}
return true;
@ -82,7 +83,7 @@ public class ModelQuery {
* @return the string
*/
public String toQueryString() {
return predicates.getSingletonPattern().toPatternString();
return filter.getSingletonPattern().toPatternString();
}
/**
@ -95,7 +96,7 @@ public class ModelQuery {
public Stream<TraceObject> streamObjects(Trace trace, Lifespan span) {
TraceObjectManager objects = trace.getObjectManager();
TraceObject root = objects.getRootObject();
return objects.getValuePaths(span, predicates)
return objects.getValuePaths(span, filter)
.map(p -> p.getDestinationValue(root))
.filter(v -> v instanceof TraceObject)
.map(v -> (TraceObject) v);
@ -103,32 +104,32 @@ public class ModelQuery {
public Stream<TraceObjectValue> streamValues(Trace trace, Lifespan span) {
TraceObjectManager objects = trace.getObjectManager();
return objects.getValuePaths(span, predicates).map(p -> {
return objects.getValuePaths(span, filter).map(p -> {
TraceObjectValue last = p.getLastEntry();
return last == null ? objects.getRootObject().getCanonicalParent(0) : last;
});
}
public Stream<TraceObjectValPath> streamPaths(Trace trace, Lifespan span) {
return trace.getObjectManager().getValuePaths(span, predicates).map(p -> p);
return trace.getObjectManager().getValuePaths(span, filter).map(p -> p);
}
public List<TargetObjectSchema> computeSchemas(Trace trace) {
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
public List<TraceObjectSchema> computeSchemas(Trace trace) {
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return List.of();
}
return predicates.getPatterns()
return filter.getPatterns()
.stream()
.map(p -> rootSchema.getSuccessorSchema(p.asPath()))
.distinct()
.collect(Collectors.toList());
}
public TargetObjectSchema computeSingleSchema(Trace trace) {
List<TargetObjectSchema> schemas = computeSchemas(trace);
public TraceObjectSchema computeSingleSchema(Trace trace) {
List<TraceObjectSchema> schemas = computeSchemas(trace);
if (schemas.size() != 1) {
return EnumerableTargetObjectSchema.OBJECT;
return PrimitiveTraceObjectSchema.OBJECT;
}
return schemas.get(0);
}
@ -143,7 +144,7 @@ public class ModelQuery {
* @return the list of attributes
*/
public Stream<AttributeSchema> computeAttributes(Trace trace) {
TargetObjectSchema schema = computeSingleSchema(trace);
TraceObjectSchema schema = computeSingleSchema(trace);
return schema.getAttributeSchemas()
.entrySet()
.stream()
@ -155,12 +156,12 @@ public class ModelQuery {
}
protected static boolean includes(Lifespan span, PathPattern pattern, TraceObjectValue value) {
List<String> asPath = pattern.asPath();
if (asPath.isEmpty()) {
KeyPath asPath = pattern.asPath();
if (asPath.isRoot()) {
// If the pattern is the root, then only match the "root value"
return value.getParent() == null;
}
if (!PathPredicates.keyMatches(PathUtils.getKey(asPath), value.getEntryKey())) {
if (!PathFilter.keyMatches(asPath.key(), value.getEntryKey())) {
return false;
}
TraceObject parent = value.getParent();
@ -188,7 +189,7 @@ public class ModelQuery {
if (!span.intersects(value.getLifespan())) {
return false;
}
for (PathPattern pattern : predicates.getPatterns()) {
for (PathPattern pattern : filter.getPatterns()) {
if (includes(span, pattern, value)) {
return true;
}
@ -204,16 +205,16 @@ public class ModelQuery {
}
// Check if any of the value's paths could be an ancestor of a result
List<String> asPath = new ArrayList<>(pattern.asPath());
KeyPath asPath = pattern.asPath();
// Destroy the pattern from the right, thus iterating each ancestor
while (!asPath.isEmpty()) {
while (!asPath.isRoot()) {
// The value's key much match somewhere in the pattern to be involved
if (!PathPredicates.keyMatches(PathUtils.getKey(asPath), value.getEntryKey())) {
asPath.remove(asPath.size() - 1);
if (!PathFilter.keyMatches(asPath.key(), value.getEntryKey())) {
asPath = asPath.parent();
continue;
}
// If it does, then check if any path to the value's parent matches the rest
asPath.remove(asPath.size() - 1);
asPath = asPath.parent();
if (parent.getAncestors(span, new PathPattern(asPath))
.anyMatch(v -> v.getSource(parent).isRoot())) {
return true;
@ -233,7 +234,7 @@ public class ModelQuery {
if (!span.intersects(value.getLifespan())) {
return false;
}
for (PathPattern pattern : predicates.getPatterns()) {
for (PathPattern pattern : filter.getPatterns()) {
if (involves(span, pattern, value)) {
return true;
}
@ -242,6 +243,6 @@ public class ModelQuery {
}
public boolean isEmpty() {
return predicates.isEmpty();
return filter.isNone();
}
}

View file

@ -24,7 +24,6 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueProperty;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.PathTableModel.PathRow;
import ghidra.app.services.DebuggerListingService;
import ghidra.dbg.target.*;
import ghidra.debug.api.model.DebuggerSingleObjectPathActionContext;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.target.Target;
@ -36,6 +35,8 @@ import ghidra.program.model.address.AddressRange;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.iface.*;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.util.Msg;
public interface ObjectDefaultActionsMixin {
@ -44,7 +45,7 @@ public interface ObjectDefaultActionsMixin {
DebuggerCoordinates getCurrent();
void activatePath(TraceObjectKeyPath path);
void activatePath(KeyPath path);
default void toggleObject(TraceObject object) {
if (!getCurrent().isAliveAndPresent()) {
@ -124,8 +125,9 @@ public interface ObjectDefaultActionsMixin {
}
default boolean performDefaultAction(TraceObject object) {
Set<Class<? extends TargetObject>> interfaces = object.getTargetSchema().getInterfaces();
if (interfaces.contains(TargetActivatable.class)) {
Set<Class<? extends TraceObjectInterface>> interfaces =
object.getSchema().getInterfaces();
if (interfaces.contains(TraceObjectActivatable.class)) {
activatePath(object.getCanonicalPath());
return true;
}
@ -133,7 +135,7 @@ public interface ObjectDefaultActionsMixin {
* Should I check aliveAndPresent() here? If I do, behavior changes when target is dead,
* which might be unexpected.
*/
if (interfaces.contains(TargetTogglable.class)) {
if (interfaces.contains(TraceObjectTogglable.class)) {
toggleObject(object);
return true;
}

View file

@ -26,9 +26,6 @@ import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener;
import docking.widgets.table.TableColumnDescriptor;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.AttributeSchema;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.ServiceProvider;
@ -38,6 +35,9 @@ import ghidra.trace.model.Lifespan.*;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema.AttributeSchema;
import ghidra.util.HTMLUtilities;
import ghidra.util.NumericUtilities;
import ghidra.util.datastruct.ListenerSet;
@ -444,7 +444,7 @@ public class ObjectTableModel extends AbstractQueryTableModel<ValueRow> {
AttributeSchema attributeSchema) {
String name = attributeSchema.getName();
Class<?> type = computeAttributeType(ctx, attributeSchema);
return new AutoAttributeColumn<>(name, type, attributeSchema.isHidden());
return new AutoAttributeColumn<>(name, type, attributeSchema.isHidden(name));
}
final boolean hidden;
@ -528,7 +528,7 @@ public class ObjectTableModel extends AbstractQueryTableModel<ValueRow> {
if (trace == null || query == null) {
return List.of();
}
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return List.of();
}
@ -563,7 +563,7 @@ public class ObjectTableModel extends AbstractQueryTableModel<ValueRow> {
if (trace == null) {
return;
}
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return;
}
@ -573,7 +573,7 @@ public class ObjectTableModel extends AbstractQueryTableModel<ValueRow> {
TraceValueObjectAttributeColumn<?> column =
columnCache.computeIfAbsent(ColKey.fromSchema(ctx, as),
ck -> AutoAttributeColumn.fromSchema(ctx, as));
if (as.isHidden()) {
if (as.isHidden(as.getName())) {
descriptor.addHiddenColumn(column);
}
else {

View file

@ -24,11 +24,15 @@ import docking.widgets.tree.GTreeLazyNode;
import docking.widgets.tree.GTreeNode;
import generic.theme.GIcon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.dbg.target.*;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
import ghidra.framework.model.*;
import ghidra.trace.model.*;
import ghidra.trace.model.target.*;
import ghidra.trace.model.breakpoint.TraceObjectBreakpointLocation;
import ghidra.trace.model.breakpoint.TraceObjectBreakpointSpec;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.iface.*;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.path.KeyPath.KeyComparator;
import ghidra.trace.util.TraceEvents;
import ghidra.util.HTMLUtilities;
import ghidra.util.LockHold;
@ -59,25 +63,26 @@ public class ObjectTreeModel implements DisplaysModified {
protected boolean isEventValue(TraceObjectValue value) {
if (!value.getParent()
.getTargetSchema()
.getSchema()
.getInterfaces()
.contains(TargetEventScope.class)) {
.contains(TraceObjectEventScope.class)) {
return false;
}
if (!TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME.equals(value.getEntryKey())) {
if (!TraceObjectEventScope.KEY_EVENT_THREAD.equals(value.getEntryKey())) {
return false;
}
return true;
}
protected boolean isEnabledValue(TraceObjectValue value) {
Set<Class<? extends TargetObject>> interfaces =
value.getParent().getTargetSchema().getInterfaces();
if (!interfaces.contains(TargetBreakpointSpec.class) &&
!interfaces.contains(TargetBreakpointLocation.class)) {
Set<Class<? extends TraceObjectInterface>> interfaces =
value.getParent().getSchema().getInterfaces();
if (!interfaces.contains(TraceObjectBreakpointSpec.class) &&
!interfaces.contains(TraceObjectBreakpointLocation.class) &&
!interfaces.contains(TraceObjectTogglable.class)) {
return false;
}
if (!TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME.equals(value.getEntryKey())) {
if (!TraceObjectTogglable.KEY_ENABLED.equals(value.getEntryKey())) {
return false;
}
return true;
@ -257,7 +262,7 @@ public class ObjectTreeModel implements DisplaysModified {
return -1;
}
int c;
c = TargetObjectKeyComparator.CHILD.compare(this.getValue().getEntryKey(),
c = KeyComparator.CHILD.compare(this.getValue().getEntryKey(),
that.getValue().getEntryKey());
if (c != 0) {
return c;
@ -297,11 +302,11 @@ public class ObjectTreeModel implements DisplaysModified {
}
}
protected AbstractNode getNode(TraceObjectKeyPath p, int pos) {
if (pos >= p.getKeyList().size()) {
protected AbstractNode getNode(KeyPath p, int pos) {
if (pos >= p.size()) {
return this;
}
String key = p.getKeyList().get(pos);
String key = p.key(pos);
AbstractNode matched = children().stream()
.map(c -> (AbstractNode) c)
.filter(c -> key.equals(c.getValue().getEntryKey()))
@ -313,7 +318,7 @@ public class ObjectTreeModel implements DisplaysModified {
return matched.getNode(p, pos + 1);
}
public AbstractNode getNode(TraceObjectKeyPath p) {
public AbstractNode getNode(KeyPath p) {
return getNode(p, 0);
}
@ -575,7 +580,7 @@ public class ObjectTreeModel implements DisplaysModified {
if (parentValue == null) {
return super.getIcon(expanded);
}
if (!parentValue.getParent().getTargetSchema().isCanonicalContainer()) {
if (!parentValue.getParent().getSchema().isCanonicalContainer()) {
return super.getIcon(expanded);
}
if (!isOnEventPath(object)) {
@ -661,7 +666,8 @@ public class ObjectTreeModel implements DisplaysModified {
}
protected TraceObject getEventObject(TraceObject object) {
TraceObject scope = object.queryCanonicalAncestorsTargetInterface(TargetEventScope.class)
TraceObject scope = object
.findCanonicalAncestorsInterface(TraceObjectEventScope.class)
.findFirst()
.orElse(null);
if (scope == null) {
@ -671,7 +677,7 @@ public class ObjectTreeModel implements DisplaysModified {
return null;
}
TraceObjectValue eventValue =
scope.getAttribute(snap, TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME);
scope.getAttribute(snap, TraceObjectEventScope.KEY_EVENT_THREAD);
if (eventValue == null || !eventValue.isObject()) {
return null;
}
@ -698,7 +704,7 @@ public class ObjectTreeModel implements DisplaysModified {
if (type.contains("Breakpoint")) {
TraceObject object = edge.getChild();
TraceObjectValue en =
object.getAttribute(snap, TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME);
object.getAttribute(snap, TraceObjectTogglable.KEY_ENABLED);
// includes true or non-boolean values
if (en == null || !Objects.equals(false, en.getValue())) {
return DebuggerResources.ICON_SET_BREAKPOINT;
@ -941,7 +947,7 @@ public class ObjectTreeModel implements DisplaysModified {
return showMethods;
}
public AbstractNode getNode(TraceObjectKeyPath p) {
public AbstractNode getNode(KeyPath p) {
return root.getNode(p);
}
}

View file

@ -26,10 +26,10 @@ import javax.swing.table.TableColumn;
import docking.widgets.table.GTableColumnModel;
import docking.widgets.table.GTableTextCellEditor;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.framework.plugintool.Plugin;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.schema.TraceObjectSchema;
public class ObjectsTablePanel extends AbstractQueryTablePanel<ValueRow, ObjectTableModel> {
@ -91,11 +91,11 @@ public class ObjectsTablePanel extends AbstractQueryTablePanel<ValueRow, ObjectT
if (query == null) {
return DEFAULT_PREF_KEY;
}
List<TargetObjectSchema> schemas = query.computeSchemas(trace);
List<TraceObjectSchema> schemas = query.computeSchemas(trace);
if (schemas.isEmpty()) {
return DEFAULT_PREF_KEY;
}
TargetObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
TraceObjectSchema rootSchema = trace.getObjectManager().getRootSchema();
if (rootSchema == null) {
return DEFAULT_PREF_KEY;
}

View file

@ -37,6 +37,7 @@ import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.util.Swing;
public class ObjectsTreePanel extends JPanel {
@ -173,7 +174,7 @@ public class ObjectsTreePanel extends JPanel {
protected final ObjectGTree tree;
protected boolean showing = false;
protected Set<TraceObjectKeyPath> savedSelection = null;
protected Set<KeyPath> savedSelection = null;
protected DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
protected DebuggerCoordinates previous = DebuggerCoordinates.NOWHERE;
protected boolean limitToSnap = true;
@ -264,13 +265,13 @@ public class ObjectsTreePanel extends JPanel {
// Repaint for bold current path is already going to happen
// Repaint is not enough, as node sizes may change
for (TraceObjectKeyPath path = current.getPath(); path != null; path = path.parent()) {
for (KeyPath path = current.getPath(); path != null; path = path.parent()) {
AbstractNode node = treeModel.getNode(path);
if (node != null) {
node.fireNodeChanged();
}
}
for (TraceObjectKeyPath path = previous.getPath(); path != null; path = path.parent()) {
for (KeyPath path = previous.getPath(); path != null; path = path.parent()) {
AbstractNode node = treeModel.getNode(path);
if (node != null) {
node.fireNodeChanged();
@ -421,14 +422,14 @@ public class ObjectsTreePanel extends JPanel {
return getItemFromPath(tree.getSelectionPath());
}
public AbstractNode getNode(TraceObjectKeyPath path) {
public AbstractNode getNode(KeyPath path) {
return treeModel.getNode(path);
}
public void setSelectedKeyPaths(Collection<TraceObjectKeyPath> keyPaths, EventOrigin origin) {
savedSelection = keyPaths instanceof Set<TraceObjectKeyPath> s ? s : Set.copyOf(keyPaths);
public void setSelectedKeyPaths(Collection<KeyPath> keyPaths, EventOrigin origin) {
savedSelection = keyPaths instanceof Set<KeyPath> s ? s : Set.copyOf(keyPaths);
List<TreePath> treePaths = new ArrayList<>();
for (TraceObjectKeyPath path : keyPaths) {
for (KeyPath path : keyPaths) {
AbstractNode node = getNode(path);
if (node != null) {
treePaths.add(node.getTreePath());
@ -437,12 +438,12 @@ public class ObjectsTreePanel extends JPanel {
tree.setSelectionPaths(treePaths.toArray(TreePath[]::new), origin);
}
public Set<TraceObjectKeyPath> getSelectedKeyPaths() {
Set<TraceObjectKeyPath> result = new HashSet<>();
public Set<KeyPath> getSelectedKeyPaths() {
Set<KeyPath> result = new HashSet<>();
for (AbstractNode node : getSelectedItems()) {
TraceObjectValue value = node.getValue();
if (value == null) {
result.add(TraceObjectKeyPath.of());
result.add(KeyPath.of());
}
else {
result.add(value.getCanonicalPath());
@ -451,7 +452,7 @@ public class ObjectsTreePanel extends JPanel {
return result;
}
public void setSelectedKeyPaths(Collection<TraceObjectKeyPath> keyPaths) {
public void setSelectedKeyPaths(Collection<KeyPath> keyPaths) {
setSelectedKeyPaths(keyPaths, EventOrigin.API_GENERATED);
}

View file

@ -16,7 +16,8 @@
package ghidra.app.plugin.core.debug.gui.model;
import java.awt.Color;
import java.util.*;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener;
@ -27,12 +28,13 @@ import ghidra.framework.plugintool.Plugin;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.path.KeyPath;
public class PathTableModel extends AbstractQueryTableModel<PathRow> {
record Seen(List<String> path, long minSnap) {
static Seen forPath(TraceObjectValPath path) {
TraceObjectValue last = path.getLastEntry();
return new Seen(path.getKeyList(), last == null ? 0 : last.getMinSnap());
record Seen(KeyPath path, long minSnap) {
static Seen forPath(TraceObjectValPath valPath) {
TraceObjectValue last = valPath.getLastEntry();
return new Seen(valPath.getPath(), last == null ? 0 : last.getMinSnap());
}
}

View file

@ -17,7 +17,6 @@ package ghidra.app.plugin.core.debug.gui.model.columns;
import docking.widgets.table.AbstractDynamicTableColumn;
import ghidra.app.plugin.core.debug.gui.model.PathTableModel.PathRow;
import ghidra.dbg.util.PathUtils;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.trace.model.Trace;
@ -39,6 +38,6 @@ public class TracePathStringColumn extends AbstractDynamicTableColumn<PathRow, S
@Override
public String getValue(PathRow rowObject, Settings settings, Trace data,
ServiceProvider serviceProvider) throws IllegalArgumentException {
return PathUtils.toString(rowObject.getPath().getKeyList());
return rowObject.getPath().getPath().toString();
}
}

View file

@ -19,10 +19,10 @@ import java.util.Comparator;
import docking.widgets.table.AbstractDynamicTableColumn;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.path.KeyPath.KeyComparator;
import ghidra.util.table.column.GColumnRenderer;
public class TraceValueKeyColumn extends AbstractDynamicTableColumn<ValueRow, String, Trace> {
@ -46,6 +46,6 @@ public class TraceValueKeyColumn extends AbstractDynamicTableColumn<ValueRow, St
@Override
public Comparator<String> getComparator() {
return TargetObjectKeyComparator.CHILD;
return KeyComparator.CHILD;
}
}

View file

@ -17,16 +17,10 @@ package ghidra.app.plugin.core.debug.gui.model.columns;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueProperty;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.dbg.target.TargetAttacher.TargetAttachKindSet;
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.TargetSteppable.TargetStepKindSet;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.AttributeSchema;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.TraceExecutionState;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.target.schema.TraceObjectSchema.AttributeSchema;
/**
* A column which displays the object's value for a given attribute
@ -44,24 +38,9 @@ public class TraceValueObjectAttributeColumn<T> extends TraceValueObjectProperty
*/
public static Class<?> computeAttributeType(SchemaContext ctx,
AttributeSchema attributeSchema) {
TargetObjectSchema schema = ctx.getSchema(attributeSchema.getSchema());
TraceObjectSchema schema = ctx.getSchema(attributeSchema.getSchema());
Class<?> type = schema.getType();
if (type == TargetObject.class) {
return TraceObject.class;
}
if (type == TargetExecutionState.class) {
return String.class;
}
if (type == TargetParameterMap.class) {
return String.class;
}
if (type == TargetAttachKindSet.class) {
return String.class;
}
if (type == TargetBreakpointKindSet.class) {
return String.class;
}
if (type == TargetStepKindSet.class) {
if (type == TraceExecutionState.class) {
return String.class;
}
return type;

View file

@ -15,7 +15,8 @@
*/
package ghidra.app.plugin.core.debug.gui.modules;
import java.util.*;
import java.util.HashSet;
import java.util.Set;
import javax.swing.event.ListSelectionEvent;
@ -25,9 +26,6 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueAttribute;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetProcess;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.debug.api.model.DebuggerObjectActionContext;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
@ -38,12 +36,15 @@ import ghidra.trace.model.Trace;
import ghidra.trace.model.modules.*;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.thread.TraceObjectProcess;
public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceObjectModule> {
private static class ModuleBaseColumn extends AbstractTraceValueObjectAddressColumn {
public ModuleBaseColumn() {
super(TargetModule.RANGE_ATTRIBUTE_NAME);
super(TraceObjectModule.KEY_RANGE);
}
@Override
@ -59,7 +60,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class ModuleMaxColumn extends AbstractTraceValueObjectAddressColumn {
public ModuleMaxColumn() {
super(TargetModule.RANGE_ATTRIBUTE_NAME);
super(TraceObjectModule.KEY_RANGE);
}
@Override
@ -75,7 +76,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class ModuleNameColumn extends TraceValueObjectAttributeColumn<String> {
public ModuleNameColumn() {
super(TargetModule.MODULE_NAME_ATTRIBUTE_NAME, String.class);
super(TraceObjectModule.KEY_MODULE_NAME, String.class);
}
@Override
@ -97,7 +98,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
return "";
}
ValueAttribute<AddressRange> attr =
rowObject.getAttribute(TargetModule.RANGE_ATTRIBUTE_NAME, AddressRange.class);
rowObject.getAttribute(TraceObjectModule.KEY_RANGE, AddressRange.class);
if (attr == null) {
return "";
}
@ -130,7 +131,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class ModuleLengthColumn extends AbstractTraceValueObjectLengthColumn {
public ModuleLengthColumn() {
super(TargetModule.RANGE_ATTRIBUTE_NAME);
super(TraceObjectModule.KEY_RANGE);
}
@Override
@ -219,9 +220,9 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
return result;
}
protected static ModelQuery successorModules(TargetObjectSchema rootSchema, List<String> path) {
TargetObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TargetModule.class, path, true));
protected static ModelQuery successorModules(TraceObjectSchema rootSchema, KeyPath path) {
TraceObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TraceObjectModule.class, path, true));
}
private final DebuggerModulesProvider provider;
@ -238,25 +239,24 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
@Override
protected ModelQuery computeQuery(TraceObject object) {
TargetObjectSchema rootSchema = object.getRoot().getTargetSchema();
List<String> seedPath = object.getCanonicalPath().getKeyList();
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
TraceObjectSchema rootSchema = object.getRoot().getSchema();
KeyPath seedPath = object.getCanonicalPath();
KeyPath processPath = rootSchema.searchForAncestor(TraceObjectProcess.class, seedPath);
if (processPath != null) {
ModelQuery result = successorModules(rootSchema, processPath);
if (!result.isEmpty()) {
return result;
}
}
List<String> containerPath =
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
KeyPath containerPath =
rootSchema.searchForSuitableContainer(TraceObjectModule.class, seedPath);
if (containerPath != null) {
ModelQuery result = successorModules(rootSchema, containerPath);
if (!result.isEmpty()) {
return result;
}
}
return successorModules(rootSchema, List.of());
return successorModules(rootSchema, KeyPath.ROOT);
}
public void setSelectedModules(Set<TraceModule> sel) {

View file

@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.modules;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -26,9 +25,6 @@ import docking.widgets.table.TableFilter;
import ghidra.app.plugin.core.debug.gui.model.*;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.ServiceProvider;
@ -36,16 +32,20 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.trace.database.module.TraceObjectSection;
import ghidra.trace.model.Trace;
import ghidra.trace.model.modules.TraceObjectModule;
import ghidra.trace.model.modules.TraceSection;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.thread.TraceObjectProcess;
public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceObjectSection> {
private static class SectionStartColumn extends AbstractTraceValueObjectAddressColumn {
public SectionStartColumn() {
super(TargetSection.RANGE_ATTRIBUTE_NAME);
super(TraceObjectSection.KEY_RANGE);
}
@Override
@ -61,7 +61,7 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
private static class SectionEndColumn extends AbstractTraceValueObjectAddressColumn {
public SectionEndColumn() {
super(TargetSection.RANGE_ATTRIBUTE_NAME);
super(TraceObjectSection.KEY_RANGE);
}
@Override
@ -84,11 +84,7 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
@Override
public String getValue(ValueRow rowObject, Settings settings, Trace data,
ServiceProvider serviceProvider) throws IllegalArgumentException {
String key = rowObject.getValue().getEntryKey();
if (PathUtils.isIndex(key)) {
return PathUtils.parseIndex(key);
}
return key;
return KeyPath.parseIfIndex(rowObject.getValue().getEntryKey());
}
}
@ -125,7 +121,7 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
return "";
}
TraceObjectValue nameEntry = module.getAttribute(row.currentSnap(),
TargetModule.MODULE_NAME_ATTRIBUTE_NAME);
TraceObjectModule.KEY_MODULE_NAME);
if (nameEntry == null) {
return "";
}
@ -137,7 +133,7 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
private static class SectionLengthColumn extends AbstractTraceValueObjectLengthColumn {
public SectionLengthColumn() {
super(TargetSection.RANGE_ATTRIBUTE_NAME);
super(TraceObjectSection.KEY_RANGE);
}
@Override
@ -166,21 +162,20 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
private static TraceObject getModule(ValueRow row) {
TraceObjectValue moduleEntry =
row.getAttributeEntry(TargetSection.MODULE_ATTRIBUTE_NAME);
row.getAttributeEntry(TraceObjectSection.KEY_MODULE);
if (moduleEntry != null && moduleEntry.isObject()) {
return moduleEntry.getChild();
}
return row.getValue()
.getChild()
.queryCanonicalAncestorsTargetInterface(TargetModule.class)
.findCanonicalAncestorsInterface(TraceObjectModule.class)
.findFirst()
.orElse(null);
}
protected static ModelQuery successorSections(TargetObjectSchema rootSchema,
List<String> path) {
TargetObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TargetSection.class, path, true));
protected static ModelQuery successorSections(TraceObjectSchema rootSchema, KeyPath path) {
TraceObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TraceObjectSection.class, path, true));
}
private class SectionsBySelectedModulesTableFilter implements TableFilter<ValueRow> {
@ -217,9 +212,9 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
@Override
protected ModelQuery computeQuery(TraceObject object) {
TargetObjectSchema rootSchema = object.getRoot().getTargetSchema();
List<String> seedPath = object.getCanonicalPath().getKeyList();
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
TraceObjectSchema rootSchema = object.getRoot().getSchema();
KeyPath seedPath = object.getCanonicalPath();
KeyPath processPath = rootSchema.searchForAncestor(TraceObjectProcess.class, seedPath);
if (processPath != null) {
ModelQuery result = successorSections(rootSchema, processPath);
if (!result.isEmpty()) {
@ -227,8 +222,8 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
}
}
// Yes, anchor on the *module* container when searching for sections
List<String> containerPath =
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
KeyPath containerPath =
rootSchema.searchForSuitableContainer(TraceObjectModule.class, seedPath);
if (containerPath != null) {
ModelQuery result = successorSections(rootSchema, containerPath);
@ -236,7 +231,7 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
return result;
}
}
return successorSections(rootSchema, List.of());
return successorSections(rootSchema, KeyPath.ROOT);
}
public void setFilteredBySelectedModules(boolean filtered) {

View file

@ -21,12 +21,12 @@ import java.util.Set;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.AbstractDebuggerParameterDialog;
import ghidra.dbg.target.TargetMethod;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.debug.api.ValStr;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.ConfigStateField;
import ghidra.framework.plugintool.PluginTool;
import ghidra.trace.model.target.iface.TraceObjectMethod;
import ghidra.trace.model.target.iface.TraceObjectMethod.ParameterDescription;
@Deprecated(forRemoval = true, since = "11.3")
public class DebuggerMethodInvocationDialog
@ -71,7 +71,7 @@ public class DebuggerMethodInvocationDialog
protected Map<String, ValStr<?>> validateArguments(
Map<String, ParameterDescription<?>> parameters, Map<String, ValStr<?>> arguments) {
Map<String, ?> args = ValStr.toPlainMap(arguments);
return ValStr.fromPlainMap(TargetMethod.validateArguments(parameters, args, false));
return ValStr.fromPlainMap(TraceObjectMethod.validateArguments(parameters, args, false));
}
@Override

View file

@ -49,7 +49,6 @@ import ghidra.app.services.DebuggerControlService.StateEditor;
import ghidra.async.AsyncLazyValue;
import ghidra.async.AsyncUtils;
import ghidra.base.widgets.table.DataTypeTableCellEditor;
import ghidra.dbg.error.DebuggerModelAccessException;
import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.docking.settings.*;
@ -1318,7 +1317,7 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
private void reportError(String title, String message, Throwable ex) {
plugin.getTool().setStatusInfo(message + ": " + ex.getMessage());
if (title != null && !(ex instanceof DebuggerModelAccessException)) {
if (title != null) {
Msg.showError(this, getComponent(), title, message, ex);
}
else if (consoleService != null) {

View file

@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.stack;
import java.util.List;
import java.util.Objects;
import javax.swing.JTable;
@ -27,10 +26,6 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.dbg.target.TargetStack;
import ghidra.dbg.target.TargetStackFrame;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathMatcher;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
@ -39,9 +34,13 @@ import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.trace.model.Trace;
import ghidra.trace.model.stack.TraceObjectStack;
import ghidra.trace.model.stack.TraceObjectStackFrame;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.path.PathMatcher;
import ghidra.trace.model.target.schema.TraceObjectSchema;
public class DebuggerStackPanel extends AbstractObjectsTableBasedPanel<TraceObjectStackFrame>
implements ListSelectionListener {
@ -60,7 +59,7 @@ public class DebuggerStackPanel extends AbstractObjectsTableBasedPanel<TraceObje
private static class FramePcColumn extends TraceValueObjectAttributeColumn<Address> {
public FramePcColumn() {
super(TargetStackFrame.PC_ATTRIBUTE_NAME, Address.class);
super(TraceObjectStackFrame.KEY_PC, Address.class);
}
@Override
@ -73,7 +72,7 @@ public class DebuggerStackPanel extends AbstractObjectsTableBasedPanel<TraceObje
if (!(row.getValue().getValue() instanceof TraceObject object)) {
return null;
}
TraceObjectValue attrPc = object.getAttribute(snap, TargetStackFrame.PC_ATTRIBUTE_NAME);
TraceObjectValue attrPc = object.getAttribute(snap, TraceObjectStackFrame.KEY_PC);
if (attrPc == null || !(attrPc.getValue() instanceof Address pc)) {
return null;
}
@ -189,14 +188,14 @@ public class DebuggerStackPanel extends AbstractObjectsTableBasedPanel<TraceObje
@Override
protected ModelQuery computeQuery(TraceObject object) {
TargetObjectSchema rootSchema = object.getRoot().getTargetSchema();
List<String> stackPath = rootSchema
.searchForSuitable(TargetStack.class, object.getCanonicalPath().getKeyList());
TraceObjectSchema rootSchema = object.getRoot().getSchema();
KeyPath stackPath =
rootSchema.searchForSuitable(TraceObjectStack.class, object.getCanonicalPath());
if (stackPath == null) {
return ModelQuery.EMPTY;
}
TargetObjectSchema stackSchema = rootSchema.getSuccessorSchema(stackPath);
PathMatcher matcher = stackSchema.searchFor(TargetStackFrame.class, stackPath, true);
TraceObjectSchema stackSchema = rootSchema.getSuccessorSchema(stackPath);
PathMatcher matcher = stackSchema.searchFor(TraceObjectStackFrame.class, stackPath, true);
return new ModelQuery(matcher);
}

View file

@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.thread;
import java.util.List;
import java.util.Objects;
import javax.swing.event.ListSelectionEvent;
@ -30,8 +29,6 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.Plugin;
@ -41,13 +38,17 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.iface.TraceObjectExecutionStateful;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema;
import ghidra.trace.model.thread.TraceObjectProcess;
import ghidra.trace.model.thread.TraceObjectThread;
public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceObjectThread> {
protected static ModelQuery successorThreads(TargetObjectSchema rootSchema, List<String> path) {
TargetObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TargetThread.class, path, true));
protected static ModelQuery successorThreads(TraceObjectSchema rootSchema, KeyPath path) {
TraceObjectSchema schema = rootSchema.getSuccessorSchema(path);
return new ModelQuery(schema.searchFor(TraceObjectThread.class, path, true));
}
private static class ThreadPathColumn extends TraceValueKeyColumn {
@ -245,7 +246,7 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceOb
private static class ThreadStateColumn extends TraceValueObjectAttributeColumn<String> {
public ThreadStateColumn() {
// NB. The recorder converts enums to strings
super(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, String.class);
super(TraceObjectExecutionStateful.KEY_STATE, String.class);
}
@Override
@ -343,17 +344,17 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceOb
@Override
protected ModelQuery computeQuery(TraceObject object) {
TargetObjectSchema rootSchema = object.getRoot().getTargetSchema();
List<String> seedPath = object.getCanonicalPath().getKeyList();
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
TraceObjectSchema rootSchema = object.getRoot().getSchema();
KeyPath seedPath = object.getCanonicalPath();
KeyPath processPath = rootSchema.searchForAncestor(TraceObjectProcess.class, seedPath);
if (processPath != null) {
ModelQuery result = successorThreads(rootSchema, processPath);
if (!result.isEmpty()) {
return result;
}
}
List<String> containerPath =
rootSchema.searchForSuitableContainer(TargetThread.class, seedPath);
KeyPath containerPath =
rootSchema.searchForSuitableContainer(TraceObjectThread.class, seedPath);
if (containerPath != null) {
ModelQuery result = successorThreads(rootSchema, containerPath);
@ -361,7 +362,7 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceOb
return result;
}
}
return successorThreads(rootSchema, List.of());
return successorThreads(rootSchema, KeyPath.ROOT);
}
private void trySelectCurrentThread() {

View file

@ -19,13 +19,11 @@ import db.Transaction;
import ghidra.app.plugin.core.debug.gui.action.PCLocationTrackingSpec;
import ghidra.app.plugin.core.debug.gui.action.SPLocationTrackingSpec;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.debug.api.target.Target;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.*;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
@ -120,7 +118,7 @@ public class ThreadRow {
if (target == null) {
return ThreadState.ALIVE;
}
TargetExecutionState state = target.getThreadExecutionState(thread);
TraceExecutionState state = target.getThreadExecutionState(thread);
if (state == null) {
return ThreadState.UNKNOWN;
}

View file

@ -17,13 +17,14 @@ package ghidra.app.plugin.core.debug.mapping;
import java.util.*;
import ghidra.dbg.target.TargetEnvironment;
import ghidra.dbg.util.PathPredicates;
import ghidra.program.model.lang.Endian;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.target.iface.TraceObjectEnvironment;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.path.PathFilter;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ExtensionPoint;
@ -65,12 +66,12 @@ public interface DebuggerPlatformOpinion extends ExtensionPoint {
return null;
}
TraceObject root = object.getRoot();
List<String> pathToEnv = root.getTargetSchema()
.searchForSuitable(TargetEnvironment.class, object.getCanonicalPath().getKeyList());
KeyPath pathToEnv = root.getSchema()
.searchForSuitable(TraceObjectEnvironment.class, object.getCanonicalPath());
if (pathToEnv == null) {
return null;
}
return root.getSuccessors(Lifespan.at(snap), PathPredicates.pattern(pathToEnv))
return root.getSuccessors(Lifespan.at(snap), PathFilter.pattern(pathToEnv))
.findAny()
.map(p -> p.getDestination(root))
.orElse(null);
@ -85,15 +86,15 @@ public interface DebuggerPlatformOpinion extends ExtensionPoint {
}
static String getDebugggerFromEnv(TraceObject env, long snap) {
return getStringAttribute(env, snap, TargetEnvironment.DEBUGGER_ATTRIBUTE_NAME);
return getStringAttribute(env, snap, TraceObjectEnvironment.KEY_DEBUGGER);
}
static String getArchitectureFromEnv(TraceObject env, long snap) {
return getStringAttribute(env, snap, TargetEnvironment.ARCH_ATTRIBUTE_NAME);
return getStringAttribute(env, snap, TraceObjectEnvironment.KEY_ARCH);
}
static String getOperatingSystemFromEnv(TraceObject env, long snap) {
return getStringAttribute(env, snap, TargetEnvironment.OS_ATTRIBUTE_NAME);
return getStringAttribute(env, snap, TraceObjectEnvironment.KEY_OS);
}
/**
@ -104,7 +105,7 @@ public interface DebuggerPlatformOpinion extends ExtensionPoint {
* @return the endianness, or null
*/
static Endian getEndianFromEnv(TraceObject env, long snap) {
String strEndian = getStringAttribute(env, snap, TargetEnvironment.ENDIAN_ATTRIBUTE_NAME);
String strEndian = getStringAttribute(env, snap, TraceObjectEnvironment.KEY_ENDIAN);
if (strEndian == null) {
return null;
}

View file

@ -15,21 +15,21 @@
*/
package ghidra.app.plugin.core.debug.service.breakpoint;
import java.util.*;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import db.Transaction;
import ghidra.async.AsyncUtils;
import ghidra.dbg.target.*;
import ghidra.dbg.util.PathMatcher;
import ghidra.program.model.address.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.path.PathMatcher;
import ghidra.util.exception.DuplicateNameException;
public record PlaceEmuBreakpointActionItem(Trace trace, long snap, Address address, long length,
@ -69,7 +69,8 @@ public record PlaceEmuBreakpointActionItem(Trace trace, long snap, Address addre
if (region == null) {
throw new IllegalArgumentException("Address does not belong to a memory in the trace");
}
return region.getObject().querySuitableTargetInterface(TargetBreakpointSpecContainer.class);
return region.getObject()
.findSuitableContainerInterface(TraceObjectBreakpointSpec.class);
}
private String computePath() {
@ -83,21 +84,21 @@ public record PlaceEmuBreakpointActionItem(Trace trace, long snap, Address addre
"Address is not associated with a breakpoint container");
}
PathMatcher specMatcher =
container.getTargetSchema().searchFor(TargetBreakpointSpec.class, true);
container.getSchema().searchFor(TraceObjectBreakpointSpec.class, true);
if (specMatcher == null) {
throw new IllegalArgumentException("Cannot find path to breakpoint specifications");
}
List<String> specRelPath = specMatcher.applyKeys(name).getSingletonPath();
KeyPath specRelPath = specMatcher.applyKeys(name).getSingletonPath();
if (specRelPath == null) {
throw new IllegalArgumentException("Too many wildcards to breakpoint specification");
}
PathMatcher locMatcher = container.getTargetSchema()
PathMatcher locMatcher = container.getSchema()
.getSuccessorSchema(specRelPath)
.searchFor(TargetBreakpointLocation.class, true);
.searchFor(TraceObjectBreakpointLocation.class, true);
if (locMatcher == null) {
throw new IllegalArgumentException("Cannot find path to breakpoint locations");
}
List<String> locRelPath = locMatcher.applyIntKeys(0).getSingletonPath();
KeyPath locRelPath = locMatcher.applyIntKeys(0).getSingletonPath();
if (locRelPath == null) {
throw new IllegalArgumentException("Too many wildcards to breakpoint location");
}

View file

@ -27,10 +27,6 @@ import db.Transaction;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils.Extrema;
import ghidra.app.services.DebuggerEmulationService;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.util.*;
import ghidra.framework.model.DomainFile;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
@ -42,8 +38,13 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.model.*;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.TraceConflictedMappingException;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectManager;
import ghidra.trace.model.target.iface.TraceObjectInterface;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.schema.*;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.thread.*;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.*;
@ -72,8 +73,6 @@ public class ProgramEmulationUtils {
</schema>
<schema name='BreakpointContainer' canonical='yes' elementResync='NEVER'
attributeResync='NEVER'>
<interface name='BreakpointSpecContainer' />
<interface name='BreakpointLocationContainer' />
<element schema='Breakpoint' />
</schema>
<schema name='Breakpoint' elementResync='NEVER' attributeResync='NEVER'>
@ -123,7 +122,7 @@ public class ProgramEmulationUtils {
</context>
""";
public static final SchemaContext EMU_CTX;
public static final TargetObjectSchema EMU_SESSION_SCHEMA;
public static final TraceObjectSchema EMU_SESSION_SCHEMA;
static {
try {
EMU_CTX = XmlSchemaContext.deserialize(EMU_CTX_XML);
@ -234,9 +233,10 @@ public class ProgramEmulationUtils {
// NB. No need to populate as module.
// UI will sync from mapping, so it's obvious where the cursor is.
String path = PathUtils.toString(patRegion
String path = patRegion
.applyKeys(block.getStart() + "-" + modName + ":" + block.getName())
.getSingletonPath());
.getSingletonPath()
.toString();
trace.getMemoryManager()
.createRegion(path, snapshot.getKey(), range, getRegionFlags(block));
}
@ -270,8 +270,8 @@ public class ProgramEmulationUtils {
// N.B. Bytes will be loaded lazily
}
public static PathPattern computePattern(TargetObjectSchema root, Trace trace,
Class<? extends TargetObject> iface) {
public static PathPattern computePattern(TraceObjectSchema root, Trace trace,
Class<? extends TraceObjectInterface> iface) {
PathMatcher matcher = root.searchFor(iface, true);
PathPattern pattern = matcher.getSingletonPattern();
if (pattern == null || pattern.countWildcards() != 1) {
@ -282,19 +282,19 @@ public class ProgramEmulationUtils {
}
public static PathPattern computePatternRegion(Trace trace) {
TargetObjectSchema root = trace.getObjectManager().getRootSchema();
TraceObjectSchema root = trace.getObjectManager().getRootSchema();
if (root == null) {
return new PathPattern(PathUtils.parse("Memory[]"));
return PathFilter.parse("Memory[]");
}
return computePattern(root, trace, TargetMemoryRegion.class);
return computePattern(root, trace, TraceObjectMemoryRegion.class);
}
public static PathPattern computePatternThread(Trace trace) {
TargetObjectSchema root = trace.getObjectManager().getRootSchema();
TraceObjectSchema root = trace.getObjectManager().getRootSchema();
if (root == null) {
return new PathPattern(PathUtils.parse("Threads[]"));
return PathFilter.parse("Threads[]");
}
return computePattern(root, trace, TargetThread.class);
return computePattern(root, trace, TraceObjectThread.class);
}
/**
@ -312,13 +312,13 @@ public class ProgramEmulationUtils {
PathPattern patThread = computePatternThread(trace);
long next = tm.getAllThreads().size();
String path;
while (!tm.getThreadsByPath(path =
PathUtils.toString(patThread.applyKeys(Long.toString(next)).getSingletonPath()))
while (!tm.getThreadsByPath(
path = patThread.applyKeys(Long.toString(next)).getSingletonPath().toString())
.isEmpty()) {
next++;
}
try {
return tm.createThread(path, "[" + next + "]", snap);
return tm.createThread(path, KeyPath.makeIndex(next), snap);
}
catch (DuplicateNameException e) {
throw new AssertionError(e);
@ -341,15 +341,14 @@ public class ProgramEmulationUtils {
TraceMemoryManager memory = trace.getMemoryManager();
if (thread instanceof TraceObjectThread ot) {
TraceObject object = ot.getObject();
PathPredicates regsMatcher = object.getRoot()
.getTargetSchema()
.searchForRegisterContainer(0, object.getCanonicalPath().getKeyList());
if (regsMatcher.isEmpty()) {
PathFilter regsFilter = object.getRoot()
.getSchema()
.searchForRegisterContainer(0, object.getCanonicalPath());
if (regsFilter.isNone()) {
throw new IllegalArgumentException("Cannot create register container");
}
for (PathPattern regsPattern : regsMatcher.getPatterns()) {
trace.getObjectManager()
.createObject(TraceObjectKeyPath.of(regsPattern.getSingletonPath()));
for (PathPattern regsPattern : regsFilter.getPatterns()) {
trace.getObjectManager().createObject(regsPattern.getSingletonPath());
break;
}
}
@ -448,12 +447,10 @@ public class ProgramEmulationUtils {
}
PathPattern patRegion = computePatternRegion(trace);
String threadName = PathUtils.isIndex(thread.getName())
? PathUtils.parseIndex(thread.getName())
: thread.getName();
String path = PathUtils.toString(
patRegion.applyKeys(alloc.getMinAddress() + "-stack " + threadName)
.getSingletonPath());
String threadName = KeyPath.parseIfIndex(thread.getName());
String path = patRegion.applyKeys(alloc.getMinAddress() + "-stack " + threadName)
.getSingletonPath()
.toString();
TraceMemoryManager mm = trace.getMemoryManager();
try {
return mm.createRegion(path, snap, alloc,
@ -512,9 +509,9 @@ public class ProgramEmulationUtils {
return alloc;
}
PathPattern patRegion = computePatternRegion(trace);
String path = PathUtils.toString(
patRegion.applyKeys(stackBlock.getStart() + "-STACK")
.getSingletonPath());
String path = patRegion.applyKeys(stackBlock.getStart() + "-STACK")
.getSingletonPath()
.toString();
TraceMemoryManager mm = trace.getMemoryManager();
try {
return mm.createRegion(path, snap, alloc,
@ -584,12 +581,11 @@ public class ProgramEmulationUtils {
for (AddressRange candidate : left) {
if (Long.compareUnsigned(candidate.getLength(), size) >= 0) {
AddressRange alloc = new AddressRangeImpl(candidate.getMinAddress(), size);
String threadName = PathUtils.isIndex(thread.getName())
? PathUtils.parseIndex(thread.getName())
: thread.getName();
String path = PathUtils.toString(
patRegion.applyKeys(alloc.getMinAddress() + "-stack " + threadName)
.getSingletonPath());
String threadName = KeyPath.parseIfIndex(thread.getName());
String path = patRegion
.applyKeys(alloc.getMinAddress() + "-stack " + threadName)
.getSingletonPath()
.toString();
return mm.createRegion(path, snap, alloc,
TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange();
}
@ -606,13 +602,13 @@ public class ProgramEmulationUtils {
TraceObjectManager om = trace.getObjectManager();
om.createRootObject(EMU_SESSION_SCHEMA);
om.createObject(TraceObjectKeyPath.parse("Breakpoints"))
om.createObject(KeyPath.parse("Breakpoints"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Memory"))
om.createObject(KeyPath.parse("Memory"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Modules"))
om.createObject(KeyPath.parse("Modules"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Threads"))
om.createObject(KeyPath.parse("Threads"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
}

View file

@ -23,7 +23,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import ghidra.app.plugin.core.debug.service.modules.ProgramModuleIndexer.IndexEntry;
import ghidra.dbg.util.PathUtils;
import ghidra.debug.api.modules.*;
import ghidra.framework.model.DomainFile;
import ghidra.graph.*;
@ -31,6 +30,7 @@ import ghidra.graph.jung.JungDirectedGraph;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.util.Msg;
public enum DebuggerStaticMappingProposals {
@ -243,11 +243,8 @@ public enum DebuggerStaticMappingProposals {
protected static Set<String> getLikelyModulesFromName(TraceMemoryRegion region) {
String key;
try {
List<String> path = PathUtils.parse(region.getPath());
key = PathUtils.getKey(path);
if (PathUtils.isIndex(key)) {
key = PathUtils.parseIndex(key);
}
KeyPath path = KeyPath.parse(region.getPath());
key = KeyPath.parseIfIndex(path.key());
}
catch (IllegalArgumentException e) { // Parse error
Msg.error(DebuggerStaticMappingProposals.class,

View file

@ -496,7 +496,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
synchronized (lock) {
InfoPerTrace info = requireTrackedInfo(trace);
if (info == null) {
return null;
return Map.of();
}
return info.getOpenMappedViews(set, Lifespan.at(snap));
}

View file

@ -39,7 +39,6 @@ import ghidra.app.services.*;
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
import ghidra.async.*;
import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec;
import ghidra.dbg.target.TargetObject;
import ghidra.debug.api.control.ControlMode;
import ghidra.debug.api.platform.DebuggerPlatformMapper;
import ghidra.debug.api.target.Target;
@ -61,7 +60,7 @@ import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceVariableSnapProgramView;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.trace.model.time.schedule.TraceSchedule;
@ -120,7 +119,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
Target target = current.getTarget();
if (supportsFocus(target)) {
// TODO: Same for stack frame? I can't imagine it's as common as this....
TraceObjectKeyPath focus = target.getFocus();
KeyPath focus = target.getFocus();
if (focus == null) {
return;
}
@ -257,7 +256,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
return;
}
DebuggerCoordinates coords = current;
TraceObjectKeyPath focus = curTarget.getFocus();
KeyPath focus = curTarget.getFocus();
if (focus != null) {
coords = coords.path(focus);
}
@ -288,7 +287,6 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
new ForFollowPresentListener();
protected DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
protected TargetObject curObj;
@AutoConfigStateField(codec = BooleanAsyncConfigFieldCodec.class)
protected final AsyncReference<Boolean, Void> saveTracesByDefault = new AsyncReference<>(true);
@AutoConfigStateField(codec = BooleanAsyncConfigFieldCodec.class)
@ -1216,7 +1214,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
}
@Override
public DebuggerCoordinates resolvePath(TraceObjectKeyPath path) {
public DebuggerCoordinates resolvePath(KeyPath path) {
return current.path(path);
}

View file

@ -24,9 +24,6 @@ import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerService
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.app.services.ProgramManager;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.framework.model.DomainFolder;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.Address;
@ -36,6 +33,9 @@ import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.util.task.TaskMonitor;
import help.screenshot.GhidraScreenShotGenerator;

View file

@ -26,10 +26,6 @@ import db.Transaction;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.dbg.target.TargetEventScope;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.program.database.ProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.target.DBTraceObjectManager;
@ -37,6 +33,10 @@ import ghidra.trace.database.target.DBTraceObjectValue;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.iface.TraceObjectEventScope;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import help.screenshot.GhidraScreenShotGenerator;
public class DebuggerModelPluginScreenShots extends GhidraScreenShotGenerator {
@ -61,8 +61,6 @@ public class DebuggerModelPluginScreenShots extends GhidraScreenShotGenerator {
<attribute name="Modules" schema="ModuleContainer" />
</schema>
<schema name="BreakpointContainer" canonical="yes">
<interface name="BreakpointSpecContainer" />
<interface name="BreakpointLocationContainer" />
<element schema="Breakpoint" />
</schema>
<schema name="Breakpoint">
@ -98,7 +96,10 @@ public class DebuggerModelPluginScreenShots extends GhidraScreenShotGenerator {
<attribute-alias from="_pc" to="PC" />
</schema>
<schema name="ModuleContainer" canonical="yes">
<interface name="ModuleContainer" />
<element schema="Module" />
</schema>
<schema name="Module">
<interface name="Module" />
</schema>
</context>""";
public static final SchemaContext CTX;
@ -179,7 +180,7 @@ public class DebuggerModelPluginScreenShots extends GhidraScreenShotGenerator {
proc.child("Modules");
}
}
root.value(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, l.thread);
root.value(TraceObjectEventScope.KEY_EVENT_THREAD, l.thread);
}
traceManager.openTrace(tb.trace);

View file

@ -21,11 +21,11 @@ import org.junit.Test;
import db.Transaction;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.target.DBTraceObjectManagerTest;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import help.screenshot.GhidraScreenShotGenerator;
public class DebuggerPlatformPluginScreenShots extends GhidraScreenShotGenerator {

View file

@ -40,9 +40,6 @@ import ghidra.app.services.*;
import ghidra.app.services.DebuggerControlService.StateEditor;
import ghidra.app.services.DebuggerEmulationService.EmulationResult;
import ghidra.async.AsyncTestUtils;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.control.ControlMode;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.model.DomainFolder;
@ -66,6 +63,9 @@ import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.stack.TraceStack;
import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.Scheduler;
import ghidra.util.InvalidNameException;

View file

@ -44,7 +44,7 @@ import ghidra.trace.database.time.DBTraceTimeManager;
import ghidra.trace.model.DefaultTraceLocation;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.task.TaskMonitor;
@ -122,13 +122,13 @@ public class DebuggerThreadsPluginScreenShots extends GhidraScreenShotGenerator
t3.getObject().setValue(Lifespan.nowOn(0), "_state", "TERMINATED");
t4.getObject().setValue(Lifespan.nowOn(0), "_state", "TERMINATED");
om.createObject(TraceObjectKeyPath.parse("Threads[1].Registers"))
om.createObject(KeyPath.parse("Threads[1].Registers"))
.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Threads[2].Registers"))
om.createObject(KeyPath.parse("Threads[2].Registers"))
.insert(Lifespan.nowOn(2), ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Threads[3].Registers"))
om.createObject(KeyPath.parse("Threads[3].Registers"))
.insert(Lifespan.nowOn(5), ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Threads[4].Registers"))
om.createObject(KeyPath.parse("Threads[4].Registers"))
.insert(Lifespan.nowOn(10), ConflictResolution.DENY);
// insert calls will extend thread life :/
t3.getObject().getCanonicalParent(13).setMaxSnap(10);

View file

@ -40,10 +40,6 @@ import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePl
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
import ghidra.app.plugin.core.debug.service.platform.DebuggerPlatformServicePlugin;
import ghidra.app.services.*;
import ghidra.dbg.target.TargetEnvironment;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.control.ControlMode;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@ -66,7 +62,11 @@ import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.stack.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.iface.TraceObjectEnvironment;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.TraceSchedule;
@ -174,15 +174,15 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
objects.createRootObject(ctx.getSchema(new SchemaName("Session")));
DBTraceObject env =
objects.createObject(TraceObjectKeyPath.parse("Targets[0].Environment"));
assertEquals(ctx.getSchema(new SchemaName("Environment")), env.getTargetSchema());
objects.createObject(KeyPath.parse("Targets[0].Environment"));
assertEquals(ctx.getSchema(new SchemaName("Environment")), env.getSchema());
Lifespan zeroOn = Lifespan.nowOn(0);
env.insert(zeroOn, ConflictResolution.DENY);
env.setAttribute(zeroOn, TargetEnvironment.DEBUGGER_ATTRIBUTE_NAME, "test");
env.setAttribute(zeroOn, TargetEnvironment.ARCH_ATTRIBUTE_NAME, arch);
env.setAttribute(zeroOn, TraceObjectEnvironment.KEY_DEBUGGER, "test");
env.setAttribute(zeroOn, TraceObjectEnvironment.KEY_ARCH, arch);
DBTraceObject objBinText =
objects.createObject(TraceObjectKeyPath.parse("Targets[0].Memory[bin:.text]"));
objects.createObject(KeyPath.parse("Targets[0].Memory[bin:.text]"));
TraceObjectMemoryRegion binText =
objBinText.queryInterface(TraceObjectMemoryRegion.class);
binText.addFlags(zeroOn, Set.of(TraceMemoryFlag.EXECUTE));
@ -193,17 +193,17 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
DBTraceMemoryManager memory = tb.trace.getMemoryManager();
if (pcInStack) {
DBTraceObject objFrame = objects
.createObject(TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0]"));
.createObject(KeyPath.parse("Targets[0].Threads[0].Stack[0]"));
objFrame.insert(zeroOn, ConflictResolution.DENY);
TraceObjectStackFrame frame = objFrame.queryInterface(TraceObjectStackFrame.class);
frame.setProgramCounter(zeroOn, tb.addr(offset));
}
else {
objects.createObject(
TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
KeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
.insert(zeroOn, ConflictResolution.DENY);
TraceObjectThread thread = objects
.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Targets[0].Threads[0]"))
.getObjectByCanonicalPath(KeyPath.parse("Targets[0].Threads[0]"))
.queryInterface(TraceObjectThread.class);
traceManager.activateThread(thread);
DBTraceMemorySpace regs =
@ -218,7 +218,7 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
assertEquals(bytes.remaining(), memory.putBytes(0, tb.addr(offset), bytes));
}
TraceObjectThread thread =
objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Targets[0].Threads[0]"))
objects.getObjectByCanonicalPath(KeyPath.parse("Targets[0].Threads[0]"))
.queryInterface(TraceObjectThread.class);
traceManager.activateThread(thread);
return thread;
@ -484,7 +484,7 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getObjectManager()
.createObject(
TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
KeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
DBTraceMemorySpace regs = Objects.requireNonNull(
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, true));
@ -519,7 +519,7 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getObjectManager()
.createObject(
TraceObjectKeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
KeyPath.parse("Targets[0].Threads[0].Stack[0].Registers"))
.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
DBTraceMemorySpace regs = Objects.requireNonNull(
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, true));

View file

@ -51,8 +51,6 @@ import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerService
import ghidra.app.services.*;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.async.AsyncTestUtils;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.action.LocationTrackingSpec;
import ghidra.debug.api.action.LocationTrackingSpecFactory;
import ghidra.docking.settings.SettingsImpl;
@ -68,6 +66,8 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.util.InvalidNameException;
import ghidra.util.NumericUtilities;
import ghidra.util.datastruct.TestDataStructureErrorHandlerInstaller;
@ -77,6 +77,39 @@ import ghidra.util.task.ConsoleTaskMonitor;
public abstract class AbstractGhidraHeadedDebuggerTest
extends AbstractGhidraHeadedIntegrationTest implements AsyncTestUtils {
/**
* Any test that uses staticall-initialized variables with any real complexity runs the risk of
* invoking the logger before said logger has been initialized. The abstract test case is
* responsible for initializing it, and it affords its subclasses the opportunity to override
* things like the application layout and configuration. Thus, we cannot initialize the
* application in the static initializer here. What will happen, then, is the logger will be
* partially initialized, and the XML config files refer to system properties that will not have
* been set yet. This manifests in strange files being created in the tests' working
* directories, e.g., <code>${sys:logFilename}</code>.
*
* <p>
* A cheap hack to avoid this issue is to just initialize those system properties to some temp
* file. Once the logging system is initialized, the variables will be overwritten by the
* application config and the logger re- and fully-initialized. For what it's worth, the logging
* config for the test case is going to be a file in a temp directory, anyway. As long as it's
* cleaned up by the JVM or the OS, we should be happy. I just want to ensure they're not
* showing up in git commits.
*
* <p>
* TODO: Should this hack be moved up into the super classes of the Ghidra Test framework?
*/
static {
try {
System.setProperty("logFilename",
Files.createTempFile("ghidraTest", ".log").toString());
System.setProperty("scriptLogFilename",
Files.createTempFile("ghidraTestScript", ".log").toString());
}
catch (IOException e) {
throw new AssertionError(e);
}
}
public static final String LANGID_TOYBE64 = "Toy:BE:64:default";
protected static byte[] arr(String hex) {

View file

@ -36,10 +36,6 @@ import ghidra.app.plugin.core.debug.gui.memory.DebuggerRegionMapProposalDialog.R
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueProperty;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.QueryPanelTestHelper;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.program.model.address.*;
@ -53,6 +49,10 @@ import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.modules.TraceStaticMapping;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.util.table.GhidraTable;
@Category(NightlyCategory.class)
@ -111,18 +111,18 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTes
protected TraceObjectMemoryRegion addRegion(String name, long loaded, AddressRange range) {
boolean isData = name.endsWith(".data");
TraceObjectManager om = tb.trace.getObjectManager();
TraceObjectKeyPath memPath = TraceObjectKeyPath.parse("Memory");
KeyPath memPath = KeyPath.parse("Memory");
Lifespan span = Lifespan.nowOn(loaded);
TraceObjectMemoryRegion region = Objects.requireNonNull(om.createObject(memPath.index(name))
.insert(span, ConflictResolution.TRUNCATE)
.getDestination(null)
.queryInterface(TraceObjectMemoryRegion.class));
TraceObject obj = region.getObject();
obj.setAttribute(span, TargetMemoryRegion.DISPLAY_ATTRIBUTE_NAME, name);
obj.setAttribute(span, TargetMemoryRegion.RANGE_ATTRIBUTE_NAME, range);
obj.setAttribute(span, TargetMemoryRegion.READABLE_ATTRIBUTE_NAME, true);
obj.setAttribute(span, TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME, isData);
obj.setAttribute(span, TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME, !isData);
obj.setAttribute(span, TraceObjectMemoryRegion.KEY_DISPLAY, name);
obj.setAttribute(span, TraceObjectMemoryRegion.KEY_RANGE, range);
obj.setAttribute(span, TraceObjectMemoryRegion.KEY_READABLE, true);
obj.setAttribute(span, TraceObjectMemoryRegion.KEY_WRITABLE, isData);
obj.setAttribute(span, TraceObjectMemoryRegion.KEY_EXECUTABLE, !isData);
return region;
}

View file

@ -38,15 +38,16 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.ObjectTreeModel.AbstractNode;
import ghidra.app.plugin.core.debug.gui.model.PathTableModel.PathRow;
import ghidra.app.plugin.core.debug.gui.model.columns.*;
import ghidra.dbg.target.TargetEventScope;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.iface.TraceObjectEventScope;
import ghidra.trace.model.target.iface.TraceObjectInterface;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
@ -150,7 +151,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
protected TraceObject createThread(long i, TraceObject prevThread) {
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObjectKeyPath threadContainerPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadContainerPath = KeyPath.parse("Processes[0].Threads");
TraceObject thread = objects.createObject(threadContainerPath.index(i));
thread.insert(Lifespan.span(i, 10), ConflictResolution.DENY);
thread.insert(Lifespan.nowOn(10 + i), ConflictResolution.DENY);
@ -162,14 +163,14 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
prevThread.setAttribute(Lifespan.nowOn(i), "_next", thread);
}
objects.getRootObject()
.setAttribute(Lifespan.nowOn(i), TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME,
.setAttribute(Lifespan.nowOn(i), TraceObjectEventScope.KEY_EVENT_THREAD,
thread);
return thread;
}
protected TraceObject createStack(TraceObject thread) {
try (Transaction tx = tb.startTransaction()) {
TraceObjectKeyPath stackPath = thread.getCanonicalPath().key("Stack");
KeyPath stackPath = thread.getCanonicalPath().key("Stack");
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObject stack = objects.createObject(stackPath);
objects.createObject(stackPath.index(0))
@ -194,7 +195,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
TraceObjectManager objects = tb.trace.getObjectManager();
try (Transaction tx = tb.startTransaction()) {
createThread(10, objects.getObjectByCanonicalPath(
TraceObjectKeyPath.parse("Processes[0].Threads[9]")));
KeyPath.parse("Processes[0].Threads[9]")));
}
}
@ -202,7 +203,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
TraceObjectManager objects = tb.trace.getObjectManager();
try (Transaction tx = tb.startTransaction()) {
TraceObject handleContainer =
objects.createObject(TraceObjectKeyPath.parse("Processes[0].Handles"));
objects.createObject(KeyPath.parse("Processes[0].Handles"));
handleContainer.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
for (int i = 0; i < 10; i++) {
handleContainer.setElement(Lifespan.nowOn(-i), i,
@ -213,10 +214,10 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
protected void populateLinks() throws Throwable {
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObjectKeyPath threadContainerPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadContainerPath = KeyPath.parse("Processes[0].Threads");
try (Transaction tx = tb.startTransaction()) {
TraceObject linkContainer =
objects.createObject(TraceObjectKeyPath.parse("Processes[0].Links"));
objects.createObject(KeyPath.parse("Processes[0].Links"));
linkContainer.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
for (int i = 0; i < 10; i++) {
linkContainer.setElement(Lifespan.nowOn(0), i,
@ -229,10 +230,10 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
TraceObjectManager objects = tb.trace.getObjectManager();
try (Transaction tx = tb.startTransaction()) {
TraceObject boxed =
objects.createObject(TraceObjectKeyPath.parse("Processes[0].Boxed"));
objects.createObject(KeyPath.parse("Processes[0].Boxed"));
boxed.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
boxed.setAttribute(Lifespan.nowOn(2), TargetObject.DISPLAY_ATTRIBUTE_NAME, "2");
boxed.setAttribute(Lifespan.nowOn(4), TargetObject.DISPLAY_ATTRIBUTE_NAME, "4");
boxed.setAttribute(Lifespan.nowOn(2), TraceObjectInterface.KEY_DISPLAY, "2");
boxed.setAttribute(Lifespan.nowOn(4), TraceObjectInterface.KEY_DISPLAY, "4");
}
}
@ -246,7 +247,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
populateBoxedPrimitive();
}
protected void assertPathIs(TraceObjectKeyPath path, int elemCount, int attrCount) {
protected void assertPathIs(KeyPath path, int elemCount, int attrCount) {
assertEquals(path, modelProvider.getPath());
assertEquals(path.toString(), modelProvider.pathField.getText());
// Table model is threaded
@ -257,22 +258,22 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
}
protected void assertPathIsThreadsContainer() {
assertPathIs(TraceObjectKeyPath.parse("Processes[0].Threads"), 10, 0);
assertPathIs(KeyPath.parse("Processes[0].Threads"), 10, 0);
}
@Test
public void testSetPathWOutTrace() throws Throwable {
modelProvider.setPath(TraceObjectKeyPath.parse(""));
modelProvider.setPath(KeyPath.parse(""));
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse(""));
modelProvider.setPath(KeyPath.parse(""));
waitForSwing();
}
@Test
public void testSelectRootWOutTrace() throws Throwable {
modelProvider.objectsTreePanel.setSelectedKeyPaths(Set.of(TraceObjectKeyPath.parse("")));
modelProvider.objectsTreePanel.setSelectedKeyPaths(Set.of(KeyPath.parse("")));
waitForSwing();
}
@ -283,7 +284,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.objectsTreePanel.setSelectedKeyPaths(Set.of(TraceObjectKeyPath.parse("")));
modelProvider.objectsTreePanel.setSelectedKeyPaths(Set.of(KeyPath.parse("")));
waitForSwing();
}
@ -293,7 +294,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForSwing();
assertPathIsThreadsContainer();
@ -319,7 +320,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForTasks();
modelProvider.objectsTreePanel
.setSelectedKeyPaths(List.of(TraceObjectKeyPath.parse("Processes[0].Threads")));
.setSelectedKeyPaths(List.of(KeyPath.parse("Processes[0].Threads")));
waitForSwing();
waitForPass(() -> assertPathIsThreadsContainer());
@ -331,7 +332,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForTasks();
ValueRow selElem = waitForValue(() -> {
@ -354,7 +355,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.activatePath(TraceObjectKeyPath.parse("Processes[0].NoSuch"));
modelProvider.activatePath(KeyPath.parse("Processes[0].NoSuch"));
waitForTasks();
assertEquals("No such object at path Processes[0].NoSuch", tool.getStatusInfo());
@ -366,7 +367,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Handles"));
modelProvider.setPath(KeyPath.parse("Processes[0].Handles"));
waitForTasks();
int keyColIndex =
@ -397,7 +398,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForTasks();
modelProvider.pathField.setText("SomeNonsenseToBeCancelled");
@ -413,7 +414,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObject root = objects.getRootObject();
TraceObjectKeyPath process0Path = TraceObjectKeyPath.parse("Processes[0]");
KeyPath process0Path = KeyPath.parse("Processes[0]");
TraceObject process0 = objects.getObjectByCanonicalPath(process0Path);
traceManager.activateObject(root);
waitForTasks();
@ -441,7 +442,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
TraceObjectKeyPath pathLinks = TraceObjectKeyPath.parse("Processes[0].Links");
KeyPath pathLinks = KeyPath.parse("Processes[0].Links");
modelProvider.setPath(pathLinks);
waitForTasks();
@ -463,7 +464,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
});
clickTableCell(modelProvider.elementsTablePanel.table, rowIndex, 0, 2);
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[7]"),
assertEquals(KeyPath.parse("Processes[0].Threads[7]"),
traceManager.getCurrentObject().getCanonicalPath());
}
@ -473,7 +474,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForTasks();
ValueRow row2 = waitForValue(() -> {
@ -494,7 +495,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
});
clickTableCell(modelProvider.elementsTablePanel.table, rowIndex, 0, 2);
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[2]"),
assertEquals(KeyPath.parse("Processes[0].Threads[2]"),
traceManager.getCurrentObject().getCanonicalPath());
}
@ -522,7 +523,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads[2]"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads[2]"));
waitForTasks();
selectAttribute("_next");
waitForTasks();
@ -536,7 +537,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
});
clickTableCell(modelProvider.attributesTablePanel.table, rowIndex, 0, 2);
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[3]"),
assertEquals(KeyPath.parse("Processes[0].Threads[3]"),
traceManager.getCurrentObject().getCanonicalPath());
}
@ -546,7 +547,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0]"));
modelProvider.setPath(KeyPath.parse("Processes[0]"));
waitForTasks();
PathRow rowNext = waitForValue(() -> {
@ -574,7 +575,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
clickTableCell(modelProvider.attributesTablePanel.table, rowIndex, 0, 2);
// ThreadContainer is not activatable, so only changes provider's path
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads"), modelProvider.getPath());
assertEquals(KeyPath.parse("Processes[0].Threads"), modelProvider.getPath());
}
@Test
@ -585,23 +586,23 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads"));
waitForTasks();
assertPathIs(TraceObjectKeyPath.parse("Processes[0].Threads"), 10, 0);
assertPathIs(KeyPath.parse("Processes[0].Threads"), 10, 0);
performAction(modelProvider.actionLimitToCurrentSnap);
assertTrue(modelProvider.isLimitToCurrentSnap());
assertTrue(modelProvider.actionLimitToCurrentSnap.isSelected());
assertPathIs(TraceObjectKeyPath.parse("Processes[0].Threads"), 1, 0);
assertPathIs(KeyPath.parse("Processes[0].Threads"), 1, 0);
traceManager.activateSnap(5);
assertPathIs(TraceObjectKeyPath.parse("Processes[0].Threads"), 6, 0);
assertPathIs(KeyPath.parse("Processes[0].Threads"), 6, 0);
performAction(modelProvider.actionLimitToCurrentSnap);
assertFalse(modelProvider.isLimitToCurrentSnap());
assertFalse(modelProvider.actionLimitToCurrentSnap.isSelected());
assertPathIs(TraceObjectKeyPath.parse("Processes[0].Threads"), 10, 0);
assertPathIs(KeyPath.parse("Processes[0].Threads"), 10, 0);
}
@Test
@ -611,7 +612,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
TraceObjectKeyPath thread2Path = TraceObjectKeyPath.parse("Processes[0].Threads[2]");
KeyPath thread2Path = KeyPath.parse("Processes[0].Threads[2]");
modelProvider.setPath(thread2Path);
modelProvider.setTreeSelection(thread2Path);
waitForTasks();
@ -641,7 +642,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads[2]"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads[2]"));
waitForTasks();
selectAttribute("_next");
waitForSwing();
@ -651,7 +652,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
assertTrue(runSwing(() -> modelProvider.actionFollowLink.isEnabledForContext(ctx)));
performAction(modelProvider.actionFollowLink, ctx, true);
TraceObjectKeyPath thread3Path = TraceObjectKeyPath.parse("Processes[0].Threads[3]");
KeyPath thread3Path = KeyPath.parse("Processes[0].Threads[3]");
assertPathIs(thread3Path, 0, 5);
}
@ -661,24 +662,24 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateTrace(tb.trace);
waitForSwing();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads[2]"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads[2]"));
waitForTasks();
// Pre-check
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[2]"), modelProvider.path);
assertEquals(KeyPath.parse("Processes[0].Threads[2]"), modelProvider.path);
performAction(modelProvider.actionCloneWindow);
DebuggerModelProvider clone = Unique.assertOne(modelPlugin.getDisconnectedProviders());
assertEquals(tb.trace, clone.current.getTrace());
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[2]"), clone.path);
assertEquals(KeyPath.parse("Processes[0].Threads[2]"), clone.path);
}
@Test
public void testPanesTrackAddElement() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath path = KeyPath.parse("Processes[0].Threads");
traceManager.activateTrace(tb.trace);
waitForSwing();
@ -696,7 +697,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testPanesTrackAddAttribute() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads[2]");
KeyPath path = KeyPath.parse("Processes[0].Threads[2]");
traceManager.activateTrace(tb.trace);
waitForSwing();
@ -717,7 +718,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testPanesTrackRemoveElement() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath path = KeyPath.parse("Processes[0].Threads");
traceManager.activateTrace(tb.trace);
waitForSwing();
@ -738,7 +739,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testPanesTrackRemoveAttribute() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads[2]");
KeyPath path = KeyPath.parse("Processes[0].Threads[2]");
traceManager.activateTrace(tb.trace);
waitForSwing();
@ -760,7 +761,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
public void testPanesTrackLifespanChangedElement() throws Throwable {
modelProvider.setLimitToCurrentSnap(true);
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath path = KeyPath.parse("Processes[0].Threads");
TraceObject threads = tb.trace.getObjectManager().getObjectByCanonicalPath(path);
TraceObjectValue element2 = threads.getElement(2, 2);
@ -792,7 +793,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
modelProvider.setLimitToCurrentSnap(true);
modelProvider.setShowHidden(true);
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads[2]");
KeyPath path = KeyPath.parse("Processes[0].Threads[2]");
TraceObject thread = tb.trace.getObjectManager().getObjectByCanonicalPath(path);
TraceObjectValue attrSelf = thread.getAttribute(2, "_self");
@ -822,7 +823,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testTreeTracksDisplayChange() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath path = TraceObjectKeyPath.parse("Processes[0].Threads[2]");
KeyPath path = KeyPath.parse("Processes[0].Threads[2]");
TraceObject thread = tb.trace.getObjectManager().getObjectByCanonicalPath(path);
traceManager.activateTrace(tb.trace);
@ -848,7 +849,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObject root = objects.getRootObject();
TraceObject process0 =
objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Processes[0]"));
objects.getObjectByCanonicalPath(KeyPath.parse("Processes[0]"));
traceManager.activateObject(root);
waitForTasks();
@ -885,20 +886,20 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
createTraceAndPopulateObjects();
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObject thread0 =
objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Processes[0].Threads[0]"));
objects.getObjectByCanonicalPath(KeyPath.parse("Processes[0].Threads[0]"));
TraceObject thread1 =
objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Processes[0].Threads[1]"));
objects.getObjectByCanonicalPath(KeyPath.parse("Processes[0].Threads[1]"));
modelProvider.setShowHidden(true);
traceManager.activateObject(thread0);
traceManager.activateSnap(1);
waitForTasks();
modelProvider.setPath(TraceObjectKeyPath.parse("Processes[0].Threads[0]._self"));
modelProvider.setPath(KeyPath.parse("Processes[0].Threads[0]._self"));
waitForTasks();
traceManager.activateObject(thread1);
waitForSwing();
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[0]._next"),
assertEquals(KeyPath.parse("Processes[0].Threads[0]._next"),
modelProvider.getPath());
}
@ -906,7 +907,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
public void testObjectActivationSelectsElement() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObjectKeyPath processesPath = TraceObjectKeyPath.parse("Processes");
KeyPath processesPath = KeyPath.parse("Processes");
TraceObject processes = objects.getObjectByCanonicalPath(processesPath);
TraceObject process0 = processes.getElement(0, 0).getChild();
traceManager.activateObject(processes);
@ -947,14 +948,14 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateObject(processes);
waitForTasks();
assertEquals(TraceObjectKeyPath.of(), modelProvider.getPath());
assertEquals(KeyPath.of(), modelProvider.getPath());
assertEquals(processes, modelProvider.attributesTablePanel.getSelectedItem().getValue());
}
protected TraceThread populateThread0Stack() {
TraceObjectManager objects = tb.trace.getObjectManager();
TraceObject threadObj0 =
objects.getObjectByCanonicalPath(TraceObjectKeyPath.parse("Processes[0].Threads[0]"));
objects.getObjectByCanonicalPath(KeyPath.parse("Processes[0].Threads[0]"));
TraceThread thread0 = threadObj0.queryInterface(TraceObjectThread.class);
createStack(threadObj0);
return thread0;
@ -967,12 +968,12 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activate(DebuggerCoordinates.NOWHERE.thread(thread0).frame(0));
waitForSwing();
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[0].Stack[0]"),
assertEquals(KeyPath.parse("Processes[0].Threads[0].Stack[0]"),
modelProvider.getPath());
traceManager.activateFrame(1);
waitForSwing();
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[0].Stack[1]"),
assertEquals(KeyPath.parse("Processes[0].Threads[0].Stack[1]"),
modelProvider.getPath());
}
@ -980,7 +981,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
public void testFrameActivationSelectsElement() throws Throwable {
createTraceAndPopulateObjects();
TraceThread thread0 = populateThread0Stack();
TraceObjectKeyPath stackPath = TraceObjectKeyPath.parse("Processes[0].Threads[0].Stack");
KeyPath stackPath = KeyPath.parse("Processes[0].Threads[0].Stack");
traceManager.activateThread(thread0);
waitForSwing();
@ -1012,11 +1013,11 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
traceManager.activateThread(thread0);
traceManager.activateSnap(1);
waitForSwing();
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[0]"), modelProvider.getPath());
assertEquals(KeyPath.parse("Processes[0].Threads[0]"), modelProvider.getPath());
traceManager.activateThread(thread1);
waitForSwing();
assertEquals(TraceObjectKeyPath.parse("Processes[0].Threads[1]"), modelProvider.getPath());
assertEquals(KeyPath.parse("Processes[0].Threads[1]"), modelProvider.getPath());
}
@Test
@ -1026,7 +1027,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
tb.trace.getThreadManager().getLiveThreadByPath(1, "Processes[0].Threads[0]");
TraceThread thread1 =
tb.trace.getThreadManager().getLiveThreadByPath(1, "Processes[0].Threads[1]");
TraceObjectKeyPath threadsPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadsPath = KeyPath.parse("Processes[0].Threads");
traceManager.activateTrace(tb.trace);
traceManager.activateSnap(1);
@ -1053,7 +1054,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
public void testSetValueAffectsTree() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath threadsPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadsPath = KeyPath.parse("Processes[0].Threads");
TraceObject threads = tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath);
TraceObject thread0 =
tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath.index(0));
@ -1080,7 +1081,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
public void testDuplicateNameInSameParentDoesntCorruptTree() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath threadsPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadsPath = KeyPath.parse("Processes[0].Threads");
TraceObject threads = tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath);
TraceObject thread0 =
tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath.index(0));
@ -1123,7 +1124,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testDuplicateNameDifferentLifespanAppearInAttributesTable() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath threadsPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadsPath = KeyPath.parse("Processes[0].Threads");
TraceObject threads = tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath);
TraceObject thread0 =
tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath.index(0));
@ -1151,7 +1152,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
@Test
public void testDuplicateNameDifferentLifespanAppearInElementsTable() throws Throwable {
createTraceAndPopulateObjects();
TraceObjectKeyPath threadsPath = TraceObjectKeyPath.parse("Processes[0].Threads");
KeyPath threadsPath = KeyPath.parse("Processes[0].Threads");
TraceObject threads = tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath);
TraceObject thread0 =
tb.trace.getObjectManager().getObjectByCanonicalPath(threadsPath.index(0));

View file

@ -22,11 +22,11 @@ import org.junit.Test;
import db.Transaction;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.trace.database.target.DBTraceObjectManager;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.TraceObjectValue;
public class ModelQueryTest extends AbstractGhidraHeadedDebuggerTest {
@ -44,7 +44,7 @@ public class ModelQueryTest extends AbstractGhidraHeadedDebuggerTest {
objects.createRootObject(CTX.getSchema(new SchemaName("Session")));
TraceObjectValue thread0Val =
objects.createObject(TraceObjectKeyPath.parse("Processes[0].Threads[0]"))
objects.createObject(KeyPath.parse("Processes[0].Threads[0]"))
.insert(Lifespan.nowOn(0), ConflictResolution.DENY)
.getLastEntry();
@ -71,7 +71,7 @@ public class ModelQueryTest extends AbstractGhidraHeadedDebuggerTest {
objects.createRootObject(CTX.getSchema(new SchemaName("Session")));
TraceObjectValue thread0Val =
objects.createObject(TraceObjectKeyPath.parse("Processes[0].Threads[0]"))
objects.createObject(KeyPath.parse("Processes[0].Threads[0]"))
.insert(Lifespan.nowOn(0), ConflictResolution.DENY)
.getLastEntry();

View file

@ -44,12 +44,6 @@ import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProvider.MapSecti
import ghidra.app.plugin.core.debug.gui.modules.DebuggerSectionMapProposalDialog.SectionMapTableColumns;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServiceTestAccess;
import ghidra.app.services.DebuggerListingService;
import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.dbg.util.PathPattern;
import ghidra.dbg.util.PathUtils;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
@ -60,10 +54,16 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.trace.database.module.TraceObjectSection;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.modules.TraceObjectModule;
import ghidra.trace.model.modules.TraceStaticMapping;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectManager;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.util.table.GhidraTable;
@Category(NightlyCategory.class)
@ -139,32 +139,33 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
}
protected void addRegionsFromModules() throws Exception {
PathPattern regionPattern = new PathPattern(PathUtils.parse("Processes[1].Memory[]"));
PathPattern regionPattern = PathFilter.parse("Processes[1].Memory[]");
TraceObjectManager om = tb.trace.getObjectManager();
try (Transaction tx = tb.startTransaction()) {
TraceObject root = om.getRootObject();
for (TraceObject module : (Iterable<TraceObject>) () -> root
.querySuccessorsTargetInterface(Lifespan.at(0), TargetModule.class, true)
.findSuccessorsInterface(Lifespan.at(0), TraceObjectModule.class, true)
.map(p -> p.getDestination(root))
.iterator()) {
String moduleName = module.getCanonicalPath().index();
Lifespan span = module.getLife().bound();
for (TraceObject section : (Iterable<TraceObject>) () -> module
.querySuccessorsTargetInterface(Lifespan.at(0), TargetSection.class, true)
.findSuccessorsInterface(Lifespan.at(0), TraceObjectSection.class,
true)
.map(p -> p.getDestination(root))
.iterator()) {
String sectionName = section.getCanonicalPath().index();
TraceObject region = om.createObject(TraceObjectKeyPath
.of(regionPattern.applyKeys(moduleName + ":" + sectionName)
.getSingletonPath()))
TraceObject region = om
.createObject(regionPattern.applyKeys(moduleName + ":" + sectionName)
.getSingletonPath())
.insert(span, ConflictResolution.TRUNCATE)
.getDestination(root);
region.setAttribute(span, TargetMemoryRegion.RANGE_ATTRIBUTE_NAME,
section.getAttribute(0, TargetSection.RANGE_ATTRIBUTE_NAME).getValue());
region.setAttribute(span, TargetMemoryRegion.READABLE_ATTRIBUTE_NAME, true);
region.setAttribute(span, TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME,
region.setAttribute(span, TraceObjectMemoryRegion.KEY_RANGE,
section.getAttribute(0, TraceObjectSection.KEY_RANGE).getValue());
region.setAttribute(span, TraceObjectMemoryRegion.KEY_READABLE, true);
region.setAttribute(span, TraceObjectMemoryRegion.KEY_WRITABLE,
".data".equals(sectionName));
region.setAttribute(span, TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME,
region.setAttribute(span, TraceObjectMemoryRegion.KEY_EXECUTABLE,
".text".equals(sectionName));
}
}
@ -172,15 +173,15 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
}
protected TraceObjectModule addModule(String name, AddressRange range, Lifespan span) {
PathPattern modulePattern = new PathPattern(PathUtils.parse("Processes[1].Modules[]"));
PathPattern modulePattern = PathFilter.parse("Processes[1].Modules[]");
TraceObjectManager om = tb.trace.getObjectManager();
TraceObjectModule module = Objects.requireNonNull(
om.createObject(TraceObjectKeyPath.of(modulePattern.applyKeys(name).getSingletonPath()))
om.createObject(modulePattern.applyKeys(name).getSingletonPath())
.insert(span, ConflictResolution.TRUNCATE)
.getDestination(null)
.queryInterface(TraceObjectModule.class));
module.getObject().setAttribute(span, TargetModule.MODULE_NAME_ATTRIBUTE_NAME, name);
module.getObject().setAttribute(span, TargetModule.RANGE_ATTRIBUTE_NAME, range);
module.getObject().setAttribute(span, TraceObjectModule.KEY_MODULE_NAME, name);
module.getObject().setAttribute(span, TraceObjectModule.KEY_RANGE, range);
return module;
}
@ -194,7 +195,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
.insert(span, ConflictResolution.TRUNCATE)
.getDestination(null)
.queryInterface(TraceObjectSection.class));
section.getObject().setAttribute(span, TargetSection.RANGE_ATTRIBUTE_NAME, range);
section.getObject().setAttribute(span, TraceObjectSection.KEY_RANGE, range);
return section;
}
@ -717,7 +718,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes
for (ValueRow row : visibleSections()) {
assertEquals(modExe.getObject(), row.getValue()
.getChild()
.queryCanonicalAncestorsTargetInterface(TargetModule.class)
.findCanonicalAncestorsInterface(TraceObjectModule.class)
.findFirst()
.orElse(null));
}

View file

@ -33,13 +33,6 @@ import ghidra.app.plugin.core.debug.gui.model.QueryPanelTestHelper;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.dbg.target.TargetStackFrame;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.dbg.util.PathPattern;
import ghidra.dbg.util.PathUtils;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@ -50,8 +43,14 @@ import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.stack.TraceObjectStack;
import ghidra.trace.model.target.*;
import ghidra.trace.model.stack.TraceObjectStackFrame;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectManager;
import ghidra.trace.model.target.path.*;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.util.table.GhidraTable;
import ghidra.util.task.TaskMonitor;
@ -169,9 +168,8 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
}
protected TraceObjectThread addThread(int n) {
PathPattern threadPattern = new PathPattern(PathUtils.parse("Processes[1].Threads[]"));
TraceObjectKeyPath threadPath =
TraceObjectKeyPath.of(threadPattern.applyIntKeys(n).getSingletonPath());
PathPattern threadPattern = PathFilter.parse("Processes[1].Threads[]");
KeyPath threadPath = threadPattern.applyIntKeys(n).getSingletonPath();
try (Transaction tx = tb.startTransaction()) {
return Objects.requireNonNull(tb.trace.getObjectManager()
.createObject(threadPath)
@ -182,7 +180,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
}
protected TraceObjectStack addStack(TraceObjectThread thread) {
TraceObjectKeyPath stackPath = thread.getObject().getCanonicalPath().extend("Stack");
KeyPath stackPath = thread.getObject().getCanonicalPath().extend("Stack");
try (Transaction tx = tb.startTransaction()) {
return Objects.requireNonNull(tb.trace.getObjectManager()
.createObject(stackPath)
@ -197,14 +195,14 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
}
protected void addStackFrames(TraceObjectStack stack, int count) {
TraceObjectKeyPath stackPath = stack.getObject().getCanonicalPath();
KeyPath stackPath = stack.getObject().getCanonicalPath();
TraceObjectManager om = tb.trace.getObjectManager();
try (Transaction tx = tb.startTransaction()) {
for (int i = 0; i < count; i++) {
TraceObject frame = om.createObject(stackPath.index(i))
.insert(Lifespan.nowOn(0), ConflictResolution.TRUNCATE)
.getDestination(null);
frame.setAttribute(Lifespan.nowOn(0), TargetStackFrame.PC_ATTRIBUTE_NAME,
frame.setAttribute(Lifespan.nowOn(0), TraceObjectStackFrame.KEY_PC,
tb.addr(0x00400100 + 0x100 * i));
}
}
@ -233,7 +231,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
.getColumnByNameAndType(tableModel, table, "Function", ValueProperty.class)
.column();
assertEquals(PathUtils.makeKey(PathUtils.makeIndex(level)), rowColVal(row, levelCol));
assertEquals(KeyPath.makeKey(KeyPath.makeIndex(level)), rowColVal(row, levelCol));
assertEquals(pcVal, rowColVal(row, pcCol));
assertEquals(func, rowColVal(row, funcCol));
}
@ -334,7 +332,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
assertTableSize(15);
List<ValueRow> allItems = stackProvider.panel.getAllItems();
for (int i = 0; i < 15; i++) {
assertEquals(PathUtils.makeKey(PathUtils.makeIndex(i)), allItems.get(i).getKey());
assertEquals(KeyPath.makeKey(KeyPath.makeIndex(i)), allItems.get(i).getKey());
}
});
}
@ -358,7 +356,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
.createObject(stack.getObject().getCanonicalPath().index(2))
.insert(Lifespan.nowOn(0), ConflictResolution.TRUNCATE)
.getDestination(null);
frame2.setAttribute(Lifespan.nowOn(0), TargetStackFrame.PC_ATTRIBUTE_NAME,
frame2.setAttribute(Lifespan.nowOn(0), TraceObjectStackFrame.KEY_PC,
tb.addr(0x00400300));
}
waitForDomainObject(tb.trace);
@ -583,12 +581,12 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerTest
try (Transaction tx = tb.startTransaction()) {
TraceObjectMemoryRegion region = Objects.requireNonNull(tb.trace.getObjectManager()
.createObject(TraceObjectKeyPath.parse("Processes[1].Memory[bin:.text]"))
.createObject(KeyPath.parse("Processes[1].Memory[bin:.text]"))
.insert(Lifespan.nowOn(0), ConflictResolution.TRUNCATE)
.getDestination(null)
.queryInterface(TraceObjectMemoryRegion.class));
region.getObject()
.setAttribute(Lifespan.nowOn(0), TargetMemoryRegion.RANGE_ATTRIBUTE_NAME,
.setAttribute(Lifespan.nowOn(0), TraceObjectMemoryRegion.KEY_RANGE,
tb.drng(0x00400000, 0x00400fff));
TraceLocation dloc =

View file

@ -30,19 +30,16 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.*;
import ghidra.app.plugin.core.debug.gui.model.QueryPanelTestHelper;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServiceTestAccess;
import ghidra.dbg.target.TargetExecutionStateful;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.dbg.util.PathPattern;
import ghidra.dbg.util.PathUtils;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.TraceObjectManager;
import ghidra.trace.model.target.iface.TraceObjectExecutionStateful;
import ghidra.trace.model.target.path.PathFilter;
import ghidra.trace.model.target.path.PathPattern;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.time.TraceTimeManager;
import ghidra.util.table.GhidraTable;
@ -100,15 +97,15 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTes
protected TraceObjectThread addThread(int index, Lifespan lifespan, String comment) {
TraceObjectManager om = tb.trace.getObjectManager();
PathPattern threadPattern = new PathPattern(PathUtils.parse("Processes[1].Threads[]"));
PathPattern threadPattern = PathFilter.parse("Processes[1].Threads[]");
TraceObjectThread thread = Objects.requireNonNull(om.createObject(
TraceObjectKeyPath.of(threadPattern.applyIntKeys(index).getSingletonPath()))
threadPattern.applyIntKeys(index).getSingletonPath())
.insert(lifespan, ConflictResolution.TRUNCATE)
.getDestination(null)
.queryInterface(TraceObjectThread.class));
thread.getObject()
.setAttribute(lifespan, TargetExecutionStateful.STATE_ATTRIBUTE_NAME,
TargetExecutionState.STOPPED.name());
.setAttribute(lifespan, TraceObjectExecutionStateful.KEY_STATE,
TraceExecutionState.STOPPED.name());
thread.getObject().setAttribute(lifespan, TraceObjectThread.KEY_COMMENT, comment);
return thread;
}
@ -129,7 +126,7 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTes
}
protected void assertThreadRow(int position, Object object, String name,
TargetExecutionState state, String comment) {
TraceExecutionState state, String comment) {
// NB. Not testing plot, since that's unmodified from generic ObjectTable
ValueRow row = provider.panel.getAllItems().get(position);
var tableModel = QueryPanelTestHelper.getTableModel(provider.panel);
@ -154,9 +151,9 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTes
assertThreadsTableSize(2);
assertThreadRow(0, thread1.getObject(), "Processes[1].Threads[1]",
TargetExecutionState.STOPPED, "A comment");
TraceExecutionState.STOPPED, "A comment");
assertThreadRow(1, thread2.getObject(), "Processes[1].Threads[2]",
TargetExecutionState.STOPPED, "Another comment");
TraceExecutionState.STOPPED, "Another comment");
}
protected void assertNoThreadSelected() {
@ -289,7 +286,7 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerTes
waitForPass(() -> {
assertThreadRow(0, thread1.getObject(), "Processes[1].Threads[1]",
TargetExecutionState.STOPPED, "A comment");
TraceExecutionState.STOPPED, "A comment");
});
// NOTE: Destruction will not be visible in plot unless snapshot 15 is created
}

View file

@ -21,19 +21,19 @@ import java.util.concurrent.CompletableFuture;
import docking.ActionContext;
import ghidra.async.AsyncUtils;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.debug.api.target.ActionName;
import ghidra.debug.api.target.Target;
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.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -76,17 +76,17 @@ public class MockTarget implements Target {
}
@Override
public TraceThread getThreadForSuccessor(TraceObjectKeyPath path) {
public TraceThread getThreadForSuccessor(KeyPath path) {
return null;
}
@Override
public TargetExecutionState getThreadExecutionState(TraceThread thread) {
public TraceExecutionState getThreadExecutionState(TraceThread thread) {
return null;
}
@Override
public TraceStackFrame getStackFrameForSuccessor(TraceObjectKeyPath path) {
public TraceStackFrame getStackFrameForSuccessor(KeyPath path) {
return null;
}
@ -96,7 +96,7 @@ public class MockTarget implements Target {
}
@Override
public TraceObjectKeyPath getFocus() {
public KeyPath getFocus() {
return null;
}

View file

@ -28,9 +28,6 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProviderTest;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
import ghidra.dbg.target.schema.SchemaContext;
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.framework.model.DomainFile;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
@ -44,7 +41,10 @@ import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.modules.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.trace.model.target.schema.SchemaContext;
import ghidra.trace.model.target.schema.XmlSchemaContext;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.util.Msg;
// Not technically a GUI test, but must be carried out in the context of a plugin tool
@ -684,7 +684,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
DBTraceObjectManager objects = tb.trace.getObjectManager();
objects.createRootObject(ctx.getSchema(new SchemaName("Session")));
objModBash =
objects.createObject(TraceObjectKeyPath.parse("Processes[1].Modules[/bin/bash]"));
objects.createObject(KeyPath.parse("Processes[1].Modules[/bin/bash]"));
objModBash.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
}

View file

@ -1,2 +0,0 @@
MODULE FILE LICENSE: lib/jna-5.14.0.jar Apache License 2.0
MODULE FILE LICENSE: lib/jna-platform-5.14.0.jar Apache License 2.0

View file

@ -1 +0,0 @@
# Framework-Debugging

View file

@ -1,172 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply from: "${rootProject.projectDir}/gradle/javaProject.gradle"
apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle"
apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle"
apply from: "${rootProject.projectDir}/gradle/nativeProject.gradle"
apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Framework-Debugging'
dependencies {
api project(':Framework-AsyncComm')
api project(':Generic')
api project(':SoftwareModeling')
api project(':ProposedUtils')
api "net.java.dev.jna:jna:5.14.0"
api "net.java.dev.jna:jna-platform:5.14.0"
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
}
// Ensure the below native test binaries don't get built for a distribution
ext.nativesTestOnly = true
task testSpecimenWin_x86_64 {
dependsOn 'expCreateProcessWin_x86_64Executable'
dependsOn 'expCreateThreadExitWin_x86_64Executable'
//dependsOn 'expCreateThreadSpinWin_x86_64Executable'
dependsOn 'expPrintWin_x86_64Executable'
//dependsOn 'expSpinWin_x86_64Executable'
dependsOn 'expRegistersWin_x86_64Executable'
dependsOn 'expStackWin_x86_64Executable'
}
task testSpecimenLinux_x86_64 {
dependsOn 'expCloneExecExecutable'//Linux_x86_64Executable'
dependsOn 'expCloneExitLinux_x86_64Executable'
//dependsOn 'expCloneSpinExecutable'//Linux_x86_64Executable'
dependsOn 'expForkExecutable'//Linux_x86_64Executable'
dependsOn 'expPrintLinux_x86_64Executable'
dependsOn 'expReadLinux_x86_64Executable'
dependsOn 'expSpinLinux_x86_64Executable'
dependsOn 'expRegistersLinux_x86_64Executable'
dependsOn 'expStackLinux_x86_64Executable'
dependsOn 'expTraceableSleepExecutable'//Linux_x86_64Executable'
doLast {
exec {
workingDir "build/os/linux_x86_64"
commandLine "strip", "-o", "expSpin.stripped", "expSpin"
}
}
}
task testSpecimenMac_arm_64 {
dependsOn 'expCloneExitMac_arm_64Executable'
dependsOn 'expPrintMac_arm_64Executable'
dependsOn 'expReadMac_arm_64Executable'
}
// TODO: testSpecimenMac_x86_64 (Intel)
// will likely need to codesign them to grant debugee-entitlement
model {
components {
expCreateProcess(NativeExecutableSpec) {
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expCreateThreadExit(NativeExecutableSpec) {
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expCreateThreadSpin(NativeExecutableSpec) {
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expCloneExec(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
}
expCloneExit(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
targetPlatform "mac_arm_64"
}
expCloneSpin(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
}
expFork(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
}
expPrint(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
targetPlatform "mac_arm_64"
}
expRead(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
targetPlatform "mac_arm_64"
}
expSpin(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expRegisters(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expStack(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
//targetPlatform "linux_x86_32" // TODO: Test on these
targetPlatform "win_x86_64"
targetPlatform "win_x86_32" // TODO: Test on these
}
expTraceableSleep(NativeExecutableSpec) {
targetPlatform "linux_x86_64"
}
}
binaries {
withType(NativeExecutableBinarySpec) {
if (toolChain in Gcc) {
cCompiler.args("-std=c99")
linker.args("-lpthread")
linker.args("-lutil")
}
if (toolChain in VisualCpp) {
cppCompiler.define("VS_PROJECT")
// NB. No /SUBSYSTEM:CONSOLE
// that creates a subprocess
linker.args("/SUBSYSTEM:windows", "/DYNAMICBASE", "/NXCOMPAT")
linker.args("shell32.lib");
}
if (isWindows(targetPlatform.name)) {
cppCompiler.define("WIN32")
cCompiler.define("WIN32")
cppCompiler.define("_WINDOWS")
cCompiler.define("_WINDOWS")
cppCompiler.define("UNICODE")
cCompiler.define("_UNICODE")
cppCompiler.define("_UNICODE")
cCompiler.define("UNICODE")
}
}
}
}

View file

@ -1,9 +0,0 @@
##VERSION: 2.0
##MODULE IP: Apache License 2.0
Module.manifest||GHIDRA||||END|
README.md||GHIDRA||||END|
data/ExtensionPoint.manifest||GHIDRA||||END|
src/main/resources/agent.log4j.xml||GHIDRA||||END|
src/main/resources/log4j-appender-console.xml||GHIDRA||||END|
src/main/resources/log4j-appender-logpanel.xml||GHIDRA||||END|
src/test/resources/ghidra/dbg/model/test_schema.xml||GHIDRA||||END|

View file

@ -1 +0,0 @@
DebuggerClientFactory

View file

@ -1,141 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
import java.lang.annotation.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import ghidra.dbg.target.TargetObject;
import ghidra.util.Msg;
/**
* A model listener that permits {@link AttributeCallback} annotations for convenient callbacks when
* the named attribute changes
*
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public abstract class AnnotatedDebuggerAttributeListener implements DebuggerModelListener {
private static final String ATTR_METHODS =
"@" + AttributeCallback.class.getSimpleName() + "-annotated methods";
private static final String PARAMS_ERR =
ATTR_METHODS + " must accept 2 parameters: (TargetObject, T)";
/**
* Annotation for a method receiving an attribute change callback
*
* <p>
* The annotated method must accept parameters {@code (TargetObject, T)}, where {@code T} is the
* type of the attribute. Currently, very little checks are applied during construction.
* Incorrect use will result in errors during callback invocation.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
protected @interface AttributeCallback {
String value();
}
private static class Wiring {
private final Map<String, Set<MethodHandle>> handles = new HashMap<>();
private Wiring(Class<?> cls, Lookup lookup) {
try {
collect(cls, lookup);
}
catch (IllegalAccessException e) {
throw new IllegalArgumentException("Lookup must have access " + ATTR_METHODS, e);
}
}
private void collectFromClass(Class<?> cls, Lookup lookup) throws IllegalAccessException {
for (Method m : cls.getDeclaredMethods()) {
AttributeCallback annot = m.getAnnotation(AttributeCallback.class);
if (annot == null) {
continue;
}
Parameter[] parameters = m.getParameters();
if (parameters.length != 2) {
throw new IllegalArgumentException(PARAMS_ERR);
}
if (!parameters[0].getType().isAssignableFrom(TargetObject.class)) {
throw new IllegalArgumentException(PARAMS_ERR);
}
MethodHandle handle = lookup.unreflect(m);
handles.computeIfAbsent(annot.value(), __ -> new HashSet<>()).add(handle);
}
}
private void collect(Class<?> cls, Lookup lookup) throws IllegalAccessException {
collectFromClass(cls, lookup);
Class<?> s = cls.getSuperclass();
if (s != null) {
collect(s, lookup);
}
for (Class<?> i : cls.getInterfaces()) {
collect(i, lookup);
}
}
private void fireChange(AnnotatedDebuggerAttributeListener l, TargetObject object,
String name, Object value) {
Set<MethodHandle> set = handles.get(name);
if (set == null) {
return;
}
for (MethodHandle h : set) {
try {
h.invoke(l, object, value);
}
catch (Throwable e) {
Msg.error(this, "Error invoking " + h + ": " + e);
}
}
}
}
private static final Map<Class<? extends AnnotatedDebuggerAttributeListener>, Wiring> WIRINGS_BY_CLASS =
new HashMap<>();
private final Wiring wiring;
public AnnotatedDebuggerAttributeListener(Lookup lookup) {
wiring = WIRINGS_BY_CLASS.computeIfAbsent(getClass(), cls -> new Wiring(cls, lookup));
}
protected boolean checkFire(TargetObject object) {
return true;
}
@Override
public void attributesChanged(TargetObject object, Collection<String> removed,
Map<String, ?> added) {
if (!checkFire(object)) {
return;
}
for (String name : removed) {
wiring.fireChange(this, object, name, null);
}
for (Map.Entry<String, ?> ent : added.entrySet()) {
wiring.fireChange(this, object, ent.getKey(), ent.getValue());
}
}
}

View file

@ -1,556 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import ghidra.async.*;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathPredicates;
import ghidra.dbg.util.PathUtils;
import ghidra.dbg.util.PathUtils.PathComparator;
import ghidra.util.Msg;
import ghidra.util.Swing;
/**
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public enum DebugModelConventions {
;
protected static CompletableFuture<Void> runNotInSwing(Object originator, Runnable runnable,
String cbName) {
if (Swing.isSwingThread()) {
return CompletableFuture.runAsync(runnable).exceptionally(e -> {
Msg.error(originator, "Error in " + cbName, e);
return null;
});
}
try {
runnable.run();
}
catch (Throwable e) {
Msg.error(originator, "Error in " + cbName, e);
}
return AsyncUtils.nil();
}
/**
* Search for a suitable object implementing the given interface, starting at a given seed.
*
* <p>
* This performs an n-up-1-down search starting at the given seed, seeking an object which
* implements the given interface. The 1-down part is only applied from objects implementing
* {@link TargetAggregate}. See {@link TargetObject} for the specifics of expected model
* conventions.
*
* <p>
* Note that many a debugger target object interface type require a self-referential {@code T}
* parameter referring to the implementing class type. To avoid referring to a particular
* implementation, it becomes necessary to leave {@code T} as {@code ?}, but that can never
* satisfy the constraints of this method. To work around this, such interfaces must provide a
* static {@code tclass} field, which can properly satisfy the type constraints of this method
* for such self-referential type variables. The returned value must be ascribed to the
* wild-carded type, because the work-around involves a hidden class. Perhaps a little verbose
* (hey, it's Java!), the following is the recommended pattern, e.g., to discover the
* environment of a given process:
*
* <pre>
* CompletableFuture<? extends TargetEnvironment<?>> futureEnv =
* DebugModelConventions.findSuitable(TargetEnvironment.tclass, aProcess);
* </pre>
*
* @param <T> the desired interface type.
* @param iface the (probably {@code tclass}) of the desired interface type
* @param seed the starting object
* @return a future which completes with the discovered object or completes with null, if not
* found.
* @deprecated use {@link #suitable(Class, TargetObject)} instead
*/
@Deprecated(forRemoval = true)
public static <T extends TargetObject> CompletableFuture<T> findSuitable(Class<T> iface,
TargetObject seed) {
if (iface.isAssignableFrom(seed.getClass())) {
return CompletableFuture.completedFuture(iface.cast(seed));
}
if (seed instanceof TargetAggregate) {
return findInAggregate(iface, seed).thenCompose(agg -> {
if (agg.size() == 1) {
return CompletableFuture.completedFuture(agg.iterator().next());
}
return findParentSuitable(iface, seed);
});
}
return findParentSuitable(iface, seed);
}
/**
* Search for a suitable object implementing the given interface, starting at a given seed.
*
* <p>
* This performs an n-up-m-down search starting at the given seed, seeking an object which
* implements the given interface. The m-down part is only applied from objects implementing
* {@link TargetAggregate}. See {@link TargetObject} for the specifics of expected model
* conventions.
*
* <p>
* Note that many a debugger target object interface type require a self-referential {@code T}
* parameter referring to the implementing class type. To avoid referring to a particular
* implementation, it becomes necessary to leave {@code T} as {@code ?}, but that can never
* satisfy the constraints of this method. To work around this, such interfaces must provide a
* static {@code tclass} field, which can properly satisfy the type constraints of this method
* for such self-referential type variables. The returned value must be ascribed to the
* wild-carded type, because the work-around involves a hidden class. Perhaps a little verbose
* (hey, it's Java!), the following is the recommended pattern, e.g., to discover the
* environment of a given process:
*
* <pre>
* CompletableFuture<? extends TargetEnvironment<?>> futureEnv =
* DebugModelConventions.suitable(TargetEnvironment.tclass, aProcess);
* </pre>
*
* @param <T> the desired interface type.
* @param iface the (probably {@code tclass}) of the desired interface type
* @param seed the starting object
* @return a future which completes with the discovered object or completes with null, if not
* found.
*/
public static <T extends TargetObject> CompletableFuture<T> suitable(Class<T> iface,
TargetObject seed) {
List<String> path =
seed.getModel().getRootSchema().searchForSuitable(iface, seed.getPath());
if (path == null) {
return null;
}
return seed.getModel().fetchModelObject(path).thenApply(obj -> iface.cast(obj));
}
public static <T extends TargetObject> T ancestor(Class<T> iface, TargetObject seed) {
List<String> path =
seed.getModel().getRootSchema().searchForAncestor(iface, seed.getPath());
if (path == null) {
return null;
}
return iface.cast(seed.getModel().getModelObject(path));
}
private static <T extends TargetObject> CompletableFuture<T> findParentSuitable(Class<T> iface,
TargetObject obj) {
TargetObject parent = obj.getParent();
if (parent == null) {
return AsyncUtils.nil();
}
return findSuitable(iface, parent);
}
/**
* Search for an object implementing the given interface among itself and its attributes.
*
* <p>
* This method descends into the attributes of objects which implement the
* {@link TargetAggregate} interface. All found objects will comes from the same "level" in the
* tree, the algorithm terminating as soon as it finds a level with at least one object having
* the interface. When it terminates, all such objects at that level will be included. The
* resulting collection is in no particular order.
*
* @param <T> the desired interface type.
* @param iface the (probably {@code tclass}) of the desired interface type
* @param seed the starting object
* @return a future which completes with the, possibly empty, collection of discovered objects
*/
public static <T extends TargetObject> CompletableFuture<Collection<T>> findInAggregate(
Class<T> iface, TargetObject seed) {
return findInAggregate(iface, Set.of(seed));
}
/**
* Search for an object implementing the given interface among those given and their attributes.
*
* <p>
* All seeds should be at the same "level", or else the result is not well defined.
*
* @see #findInAggregate(Class, TargetObject)
*/
public static <T extends TargetObject> CompletableFuture<Collection<T>> findInAggregate(
Class<T> iface, Collection<? extends TargetObject> seeds) {
if (seeds.isEmpty()) {
return CompletableFuture.completedFuture(Set.of());
}
Set<T> result = seeds.stream()
.filter(obj -> iface.isAssignableFrom(obj.getClass()))
.map(obj -> iface.cast(obj))
.collect(Collectors.toSet());
if (!result.isEmpty()) {
return CompletableFuture.completedFuture(result);
}
AsyncFence fence = new AsyncFence();
Set<TargetObject> nextLevel = new HashSet<>();
for (TargetObject seed : seeds) {
if (!(seed instanceof TargetAggregate)) {
continue;
}
fence.include(seed.fetchAttributes().thenAccept(attributes -> {
synchronized (nextLevel) {
for (Map.Entry<String, ?> ent : attributes.entrySet()) {
Object val = ent.getValue();
if (!(val instanceof TargetObject)) {
continue;
}
TargetObject obj = (TargetObject) val;
if (PathUtils.isLink(seed.getPath(), ent.getKey(), obj.getPath())) {
// TODO: Resolve links? Must ensure I don't re-visit anyone
continue;
}
nextLevel.add(obj);
}
}
}));
}
return fence.ready().thenCompose(__ -> findInAggregate(iface, nextLevel));
}
public abstract static class AncestorTraversal<T> extends CompletableFuture<T> {
public enum Result {
FOUND, CONTINUE, TERMINATE;
}
protected TargetObject cur;
public AncestorTraversal(TargetObject successor) {
cur = successor;
}
protected abstract Result check(TargetObject obj);
protected abstract T finish(TargetObject obj);
public AncestorTraversal<T> start() {
try {
next(cur);
}
catch (Throwable ex) {
completeExceptionally(ex);
}
return this;
}
protected void next(TargetObject ancestor) {
cur = ancestor;
if (cur == null) {
complete(null);
return;
}
switch (check(cur)) {
case FOUND:
complete(finish(cur));
return;
case CONTINUE:
next(cur.getParent());
return;
case TERMINATE:
complete(null);
return;
}
}
protected Void exc(Throwable ex) {
completeExceptionally(ex);
return null;
}
}
/**
* Find the nearest ancestor which implements the given interface.
*
* <p>
* This is similar to {@link #findSuitable(Class, TargetObject)}, except without the 1-down
* rule.
*
* @param <T> the type of the required interface
* @param iface the (probably {@code tclass}) for the required interface
* @param successor the seed object
* @return a future which completes with the found object or completes with null if not found.
*/
public static <T extends TargetObject> CompletableFuture<T> nearestAncestor(Class<T> iface,
TargetObject successor) {
return new AncestorTraversal<T>(successor) {
@Override
protected Result check(TargetObject obj) {
if (iface.isAssignableFrom(obj.getClass())) {
return Result.FOUND;
}
return Result.CONTINUE;
}
@Override
protected T finish(TargetObject obj) {
return iface.cast(obj);
}
}.start();
}
/**
* Collect all ancestors (including seed) supporting the given interface
*
* @param <T> the type of interface
* @param seed the starting point
* @param iface the class of the interface
* @return the collection of ancestors supporting the interface
*/
public static <T extends TargetObject> CompletableFuture<Collection<T>> collectAncestors(
TargetObject seed, Class<T> iface) {
DebuggerObjectModel model = seed.getModel();
List<T> result = new ArrayList<>(seed.getPath().size() + 1);
AsyncFence fence = new AsyncFence();
for (List<String> path = seed.getPath(); path != null; path = PathUtils.parent(path)) {
fence.include(model.fetchModelObject(path).thenAccept(obj -> {
if (iface.isAssignableFrom(obj.getClass())) {
result.add(iface.cast(obj));
}
}));
}
return fence.ready().thenApply(__ -> {
result.sort(Comparator.comparing(o -> o.getPath().size()));
return result;
});
}
/**
* Collect all successors (including seed) that are elements supporting the given interface.
*
* @param <T> the type of interface
* @param seed the starting point (root of subtree to inspect)
* @param iface the class of the interface
* @return the collection of successor elements supporting the interface
* @deprecated use {@link TargetObjectSchema#searchFor(Class, boolean)} and
* {@link PathPredicates#collectSuccessorRefs(TargetObject)} instead.
*/
// TODO: Test this method
@Deprecated(forRemoval = true)
public static <T extends TargetObject> CompletableFuture<Collection<T>> collectSuccessors(
TargetObject seed, Class<T> iface) {
Collection<T> result =
new TreeSet<>(Comparator.comparing(TargetObject::getPath, PathComparator.KEYED));
AsyncFence fence = new AsyncFence();
fence.include(seed.fetchElements().thenCompose(elements -> {
AsyncFence elemFence = new AsyncFence();
synchronized (result) {
for (TargetObject e : elements.values()) {
if (iface.isInstance(e)) {
result.add(iface.cast(e));
continue;
}
elemFence.include(collectSuccessors(e, iface).thenAccept(sub -> {
synchronized (result) {
result.addAll(sub);
}
}));
}
}
return elemFence.ready();
}));
fence.include(seed.fetchAttributes().thenCompose(attributes -> {
AsyncFence attrFence = new AsyncFence();
synchronized (result) {
for (Map.Entry<String, ?> ent : attributes.entrySet()) {
Object val = ent.getValue();
if (!(val instanceof TargetObject)) {
continue;
}
TargetObject a = (TargetObject) val;
if (PathUtils.isLink(seed.getPath(), ent.getKey(), a.getPath())) {
continue;
}
if (iface.isInstance(a)) {
result.add(iface.cast(a));
continue;
}
attrFence.include(collectSuccessors(a, iface).thenAccept(sub -> {
synchronized (result) {
result.addAll(sub);
}
}));
}
}
return attrFence.ready();
}));
return fence.ready().thenApply(__ -> {
return result;
});
}
/**
* Find the nearest ancestor thread
*
* @param successor the seed object
* @return a future which completes with the found thread or completes with {@code null}.
*/
public static CompletableFuture<TargetThread> findThread(TargetObject successor) {
return new AncestorTraversal<TargetThread>(successor) {
@Override
protected Result check(TargetObject obj) {
if (obj.isRoot()) {
return Result.TERMINATE;
}
if (obj instanceof TargetThread) {
return Result.FOUND;
}
return Result.CONTINUE;
}
@Override
protected TargetThread finish(TargetObject obj) {
return (TargetThread) obj;
}
}.start();
}
/**
* Check if the given process is alive
*
* @param process the process
* @return true if alive
*/
public static boolean isProcessAlive(TargetProcess process) {
if (!process.isValid()) {
return false;
}
if (!(process instanceof TargetExecutionStateful)) {
return true;
}
TargetExecutionStateful exe = (TargetExecutionStateful) process;
TargetExecutionState state = exe.getExecutionState();
if (state == null) {
Msg.trace(null, "null state for " + exe);
return false;
}
return state.isAlive();
}
/**
* Check if a target is a live process, and cast if so
*
* @param target the potential process
* @return the process if live, or null
*/
public static TargetProcess liveProcessOrNull(TargetObject target) {
if (!(target instanceof TargetProcess)) {
return null;
}
TargetProcess process = (TargetProcess) target;
return isProcessAlive(process) ? process : null;
}
public static class AsyncAttribute<T> extends AsyncReference<T, Void>
implements DebuggerModelListener {
private final TargetObject obj;
private final String name;
@SuppressWarnings("unchecked")
public AsyncAttribute(TargetObject obj, String name) {
this.name = name;
this.obj = obj;
obj.getModel().addModelListener(this);
set((T) obj.getCachedAttribute(name), null);
obj.fetchAttribute(name).exceptionally(ex -> {
Msg.error(this, "Could not get initial value of " + name + " for " + obj, ex);
return null;
});
}
@Override
@SuppressWarnings("unchecked")
public void attributesChanged(TargetObject parent, Collection<String> removed,
Map<String, ?> added) {
if (parent != obj) {
return;
}
if (added.containsKey(name)) {
set((T) added.get(name), null);
}
else if (removed.contains(name)) {
set(null, null);
}
}
public void dispose() {
this.dispose(new AssertionError("disposed"));
}
@Override
public void dispose(Throwable reason) {
super.dispose(reason);
obj.getModel().removeModelListener(this);
}
}
public static class AsyncState extends AsyncAttribute<TargetExecutionState> {
public AsyncState(TargetExecutionStateful stateful) {
super(stateful, TargetExecutionStateful.STATE_ATTRIBUTE_NAME);
}
}
public static class AsyncAccess extends AsyncAttribute<Boolean> {
public AsyncAccess(TargetAccessConditioned ac) {
super(ac, TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME);
}
}
/**
* Request activation of the given object in its nearest active scope
*
* <p>
* Note if the object has no suitable active scope, this method fails silently.
*
* @param obj the object on which to request activation
* @return a future which completes when activation is granted, or exceptionally
*/
public static CompletableFuture<Void> requestActivation(TargetObject obj) {
CompletableFuture<? extends TargetActiveScope> futureActivator =
DebugModelConventions.findSuitable(TargetActiveScope.class, obj);
return futureActivator.thenCompose(activator -> {
if (activator == null) {
return AsyncUtils.nil();
}
return activator.requestActivation(obj);
});
}
/**
* Request focus on the given object in its nearest focus scope
*
* <p>
* Note if the object has no suitable focus scope, this method fails silently.
*
* @param obj the object on which to request focus
* @return a future which completes when focus is granted, or exceptionally
*/
public static CompletableFuture<Void> requestFocus(TargetObject obj) {
CompletableFuture<? extends TargetFocusScope> futureScope =
DebugModelConventions.findSuitable(TargetFocusScope.class, obj);
return futureScope.thenCompose(scope -> {
if (scope == null) {
return AsyncUtils.nil();
}
return scope.requestFocus(obj);
});
}
}

View file

@ -1,40 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
@Deprecated(forRemoval = true, since = "11.2")
class DebuggerAbnormalModelClosedReason implements DebuggerModelClosedReason {
final Throwable exc;
public DebuggerAbnormalModelClosedReason(Throwable exc) {
this.exc = exc;
}
@Override
public boolean hasException() {
return true;
}
@Override
public boolean isClientInitiated() {
return false;
}
@Override
public Throwable getException() {
return exc;
}
}

View file

@ -1,63 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
/**
* A reason given for a closed connection
*
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public interface DebuggerModelClosedReason {
DebuggerModelClosedReason NORMAL = DebuggerNormalModelClosedReason.NORMAL;
static DebuggerModelClosedReason normal() {
return NORMAL;
}
static DebuggerModelClosedReason abnormal(Throwable exc) {
return new DebuggerAbnormalModelClosedReason(exc);
}
/**
* Check for exceptional cause for the closed model
*
* <p>
* Usually, if the model is closed unexpectedly, there is an exception to document the cause. If
* available, the implementation should provide this exception.
*
* @return true if an exception is recorded
*/
boolean hasException();
/**
* Check if the model was closed by the client
*
* <p>
* In this case, the closed model is completely ordinary. While the model is still no longer
* valid, there is no cause to alert the user.
*
* @return true if the model was closed by the client
*/
boolean isClientInitiated();
/**
* Get the recorded exception, if available
*
* @return the exception or null
*/
Throwable getException();
}

View file

@ -1,70 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
import ghidra.dbg.util.ConfigurableFactory;
import ghidra.program.model.listing.Program;
import ghidra.util.classfinder.ExtensionPoint;
/**
* A factory for a debugger model
*
* <p>
* This provides a discoverable means of configuring and creating a debug model.
*
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public interface DebuggerModelFactory
extends ExtensionPoint, ConfigurableFactory<DebuggerObjectModel> {
/**
* Get the priority for selecting this factory by default for the given program
*
* <p>
* A default factory is selected when the current factory and the last successful factory are
* incompatible with the current program, or if this is the very first time connecting. Of those
* factories compatible with the current program, the one with the highest priority (larger
* numerical value) is selected. If none are compatible, then the current selection is left as
* is.
*
* <p>
* Note that negative priorities imply the factory is not compatible with the given program or
* local system.
*
* @param program the current program, or null
* @return the priority, higher values mean higher priority
*/
default int getPriority(Program program) {
return 0;
}
/**
* Check if this factory is compatible with the local system and given program.
*
* <p>
* <b>WARNING:</b> Implementations should not likely override this method. If one does, it must
* behave in the same manner as given in this default implementation: If
* {@link #getPriority(Program)} would return a non-negative result for the program, then this
* factory is compatible with that program. If negative, this factory is not compatible.
*
* @param program the current program, or null
* @return true if compatible
*/
default boolean isCompatible(Program program) {
return getPriority(program) >= 0;
}
}

View file

@ -1,323 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
import java.util.*;
import ghidra.dbg.error.DebuggerMemoryAccessException;
import ghidra.dbg.target.*;
import ghidra.dbg.target.TargetConsole.Channel;
import ghidra.dbg.target.TargetEventScope.TargetEventType;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.util.Msg;
/**
* A listener for events related to the debugger model, including its connection and objects
*
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public interface DebuggerModelListener {
/**
* An error occurred such that this listener will no longer receive events
*
* @param t the exception describing the error
*/
default public void catastrophic(Throwable t) {
Msg.error(this, "Catastrophic listener error", t);
}
/**
* The model has been successfully opened
*
* <p>
* For example, the connection to a debugger daemon has been established and negotiated.
*/
default public void modelOpened() {
}
/**
* The model's state has changed, prompting an update to its description
*/
default public void modelStateChanged() {
}
/**
* The model was closed
*
* <p>
* For example, the remote closed the connection, or the connection was lost. Whatever the case,
* the model is invalid after this callback.
*
* @param reason the reason for the model to close
*/
default public void modelClosed(DebuggerModelClosedReason reason) {
}
/**
* An object was created
*
* <p>
* This can only be received by listening on the model. While the created object can now appear
* in other callbacks, it should not be used aside from those callbacks, until it is added to
* the model. Until that time, the object may not adhere to the schema, since its children are
* still being initialized.
*
* @param object the newly-created object
*/
default void created(TargetObject object) {
}
/**
* An object is no longer valid
*
* <p>
* This should be the final callback ever issued for this object. Invalidation of an object
* implies invalidation of all its successors; nevertheless, the implementation MUST explicitly
* invoke this callback for those successors in preorder. Users need only listen for
* invalidation by installing a listener on the object of interest. However, a user must be able
* to ignore invalidation events on an object it has already removed and/or invalidated. The
* {@code branch} parameter will identify the branch node of the sub-tree being removed. For
* models that are managed by a client connection, disconnecting or otherwise terminating the
* session should invalidate the root, and thus every object must receive this callback.
*
* <p>
* If an invalidated object is replaced (i.e., a new object with the same path is added to the
* model), the implementation must be careful to issue all invalidations related to the removed
* object before the replacement is added, so that delayed invalidations are not mistakenly
* applied to the replacement or its successors.
*
* @param object the now-invalid object
* @param branch the root of the sub-tree being invalidated
* @param reason an informational, human-consumable reason, if applicable
*/
default void invalidated(TargetObject object, TargetObject branch, String reason) {
}
/**
* The root object has been added to the model
*
* <p>
* This indicates the root is ready, not just {@link #created(TargetObject)}. Note this callback
* indicates the root being "added to the model."
*
* @param root the root object
*/
default public void rootAdded(TargetObject root) {
}
/**
* The object's elements changed
*
* <p>
* The listener must have received a prior {@link #created(TargetObject)} callback for the
* parent and all (object-valued) elements being added. Assuming {@code object} has already been
* "added the model," this callback indicates all objects in the {@code added} parameter being
* "added to the model" along with their successors.
*
* @param object the object whose children changed
* @param removed the list of removed children
* @param added a map of indices to new children references
*/
default void elementsChanged(TargetObject object, Collection<String> removed,
Map<String, ? extends TargetObject> added) {
}
/**
* The object's attributes changed
*
* <p>
* In the case of an object-valued attribute, changes to that object do not constitute a changed
* attribute. The attribute is considered changed only when that attribute is assigned to a
* completely different object.
*
* @param object the object whose attributes changed
* @param removed the list of removed attributes
* @param added a map of names to new/changed attributes
*/
default void attributesChanged(TargetObject object, Collection<String> removed,
Map<String, ?> added) {
}
/**
* The model has requested the client invalidate (non-tree) caches associated with an object
*
* <p>
* For objects with methods exposing contents other than elements and attributes (e.g., memory
* and register contents), this callback requests that any caches associated with that content
* be invalidated. Most notably, this usually occurs when an object (e.g., thread) enters the
* {@link TargetExecutionState#RUNNING} state, to inform proxies that they should invalidate
* their memory and register caches. In most cases, clients need not worry about this callback.
* Protocol implementations that use the model, however, should forward this request to the
* client-side peer.
*
* <p>
* Note caches of elements and attributes are not affected by this callback. See
* {@link TargetObject#invalidateCaches()}.
*
* @param object the object whose caches must be invalidated
*/
default void invalidateCacheRequested(TargetObject object) {
}
/**
* A breakpoint trapped execution
*
* <p>
* The program counter can be obtained in a few ways. The most reliable is to get the address of
* the breakpoint location. If available, the frame will also contain the program counter.
* Finally, the trapped object or one of its relatives may offer the program counter.
*
* @param container the container whose breakpoint trapped execution
* @param trapped the object whose execution was trapped, usually a {@link TargetThread}
* @param frame the innermost stack frame, if available, of the trapped object
* @param spec the breakpoint specification
* @param breakpoint the breakpoint location that actually trapped execution
*/
default void breakpointHit(TargetObject container, TargetObject trapped,
TargetStackFrame frame, TargetBreakpointSpec spec,
TargetBreakpointLocation breakpoint) {
}
/**
* A console has produced output (given as bytes)
*
* <p>
* Note that "captured" outputs will not be reported in this callback. See
* {@link TargetInterpreter#executeCapture(String)}.
*
* @param console the console producing the output
* @param channel identifies the "output stream", stdout or stderr
* @param data the output data
*/
default void consoleOutput(TargetObject console, Channel channel, byte[] data) {
}
/**
* A console has produced output (given as a string)
*
* @implNote Overriding this method is not a substitute for overriding
* {@link #consoleOutput(TargetObject, Channel, byte[])}. Some models may invoke this
* {@code String} variant as a convenience, which by default, invokes the
* {@code byte[]} variant, but models are only expected to invoke the {@code byte[]}
* variant. A client may override this method simply to avoid back-and-forth
* conversions between {@code String}s and {@code byte[]}s.
*
* @param console the console producing the output
* @param channel identifies the "output stream", stdout or stderr
* @param text the output text
*/
default void consoleOutput(TargetObject console, Channel channel, String text) {
consoleOutput(console, channel, text.getBytes(TargetConsole.CHARSET));
}
/**
* A "special" event has occurred
*
* <p>
* When present, this callback must be invoked before any other callback which results from this
* event, except creation events. E.g., for PROCESS_EXITED, this must be called before the
* affected process is invalidated.
*
* <p>
* Whenever possible, event thread must be given. This is often the thread given focus by the
* debugger immediately upon stopping for the event. Parameters are not (yet) strictly
* specified, but it should include the stopped target, if that target is not already given by
* the event thread. It may optionally contain other useful information, such as an exit code,
* but no client should depend on that information being given.
*
* <p>
* The best way to communicate to users what has happened is via the description. Almost every
* other result of an event is communicated by other means in the model, e.g., state changes,
* object creation, invalidation. The description should contain as much information as possible
* to cue users as to why the other changes have occurred, and point them to relevant objects.
* For example, if trapped on a breakpoint, the description might contain the breakpoint's
* identifier. If the debugger prints a message for this event, that message is probably a
* sufficient description.
*
* @param object the event scope
* @param eventThread if applicable, the thread causing the event
* @param type the type of event
* @param description a human-readable description of the event
* @param parameters extra parameters for the event. TODO: Specify these for each type, or break
* this into other callbacks.
*/
default void event(TargetObject object, TargetThread eventThread, TargetEventType type,
String description, List<Object> parameters) {
}
/**
* Memory was successfully read or written
*
* <p>
* This implies memory caches should be updated. If the implementation employs a cache, then it
* need only report reads or writes which updated that cache. However, that cache must be
* invalidated whenever any other event occurs which could change memory, e.g., the target
* stepping or running. See {@link #invalidateCacheRequested(TargetObject)}. If the
* implementation does not employ a cache, then it must report <em>every</em> successful
* client-driven read or write. If the implementation can detect <em>debugger-driven</em> memory
* reads and writes, then it is recommended to call this method for those events. However, this
* method <em>must not</em> be called for <em>target-driven</em> memory changes. In other words,
* this method should only be called for reads or writes requested by the user.
*
* @param memory this memory object
* @param address the starting address of the affected range
* @param data the new data for the affected range
*/
default void memoryUpdated(TargetObject memory, Address address, byte[] data) {
}
/**
* An attempt to read memory failed
*
* <p>
* Like {@link #memoryUpdated(TargetMemory, Address, byte[])}, this should only be invoked for
* <em>user-driven</em> requests. Failure of the <em>target</em> to read its own memory would
* likely be reported via an exception, not this callback.
*
* @param memory the memory object
* @param range the range for the read which generated the error
* @param e the error
*/
default void memoryReadError(TargetObject memory, AddressRange range,
DebuggerMemoryAccessException e) {
}
/**
* Registers were successfully read or written
*
* <p>
* This implies register caches should be updated. If the implementation employs a cache, then
* it need only report reads or writes which updated that cache. However, that cache must be
* invalidated whenever any other event occurs which could change register values, e.g., the
* target stepping or running. See {@link #invalidateCacheRequested(TargetObject)}. If the
* implementation does not employ a cache, then it must report <em>every</em> successful
* client-driven read or write. If the implementation can detect <em>debugger-driven</em>
* register reads and writes, then it recommended to call this method for those events. However,
* this method <em>must not</em> be called for <em>target-driven</em> register changes, except
* perhaps when the target becomes suspended. Note that some models may additionally provide a
* {@code value} attribute on each register -- when the register bank is its own description
* container -- however, updating those attributes is not a substitute for this callback.
*
* @param bank this register bank object
* @param updates a name-value map of updated registers
*/
default void registersUpdated(TargetObject bank, Map<String, byte[]> updates) {
}
}

View file

@ -1,36 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
@Deprecated(forRemoval = true, since = "11.2")
enum DebuggerNormalModelClosedReason implements DebuggerModelClosedReason {
NORMAL;
@Override
public boolean hasException() {
return false;
}
@Override
public boolean isClientInitiated() {
return true;
}
@Override
public Throwable getException() {
return null;
}
}

View file

@ -1,614 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.dbg;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.RejectedExecutionException;
import java.util.function.Predicate;
import ghidra.async.*;
import ghidra.dbg.error.*;
import ghidra.dbg.target.TargetMemory;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.EnumerableTargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.*;
import ghidra.util.Msg;
/**
* A debugger model, often a connection to an external debugger
*
* <p>
* This is an abstraction of debugger operations and attempts to limit assumptions to those that
* generalize to most platforms. Debuggers and the target processes may be temperamental, so an
* asynchronous pattern is employed to prevent deadlocks on dropped connections, slow connections,
* buggy daemons, etc.
*
* <p>
* For methods returning a {@link CompletableFuture}, the documentation describes its return value
* assuming successful completion. Any of the futures may complete exceptionally.
*
* <p>
* The completion of any future returned by a method does not imply any state change in the
* debugger. It merely acknowledges that the request was received by the debugger. Only listener
* callbacks confirm or otherwise communicate actual state changes. If, in the underlying protocol,
* confirmation of a request implies a state change, then the implementation must make the
* appropriate callbacks.
*
* <p>
* The model object only exposes the connection state and a root object. The model comprises an
* arbitrary tree of {@link TargetObject}s each supporting zero or more discoverable interfaces. The
* debugging framework provides a number of "stock" interfaces which should be sufficient to model
* most debuggers. The tree is how the client accesses objects, e.g., processes and threads, on the
* target.
*
* <p>
* Users and implementors of this interface may find {@link AsyncUtils} useful. An implementation of
* this interface should never block the calling thread to wait on an external event, otherwise, you
* risk deadlocking Ghidra's UI.
*
* @deprecated Will be removed in 11.3. Portions may be refactored into trace object database.
*/
@Deprecated(forRemoval = true, since = "11.2")
public interface DebuggerObjectModel {
public static enum RefreshBehavior {
REFRESH_ALWAYS {
@Override
public boolean isRefresh(Collection<?> col) {
return true;
}
},
REFRESH_NEVER {
@Override
public boolean isRefresh(Collection<?> col) {
return false;
}
},
REFRESH_WHEN_ABSENT {
@Override
public boolean isRefresh(Collection<?> col) {
return col.isEmpty();
}
};
public abstract boolean isRefresh(Collection<?> col);
}
public static final TypeSpec<Map<String, ? extends TargetObject>> ELEMENT_MAP_TYPE =
TypeSpec.auto();
public static final TypeSpec<Map<String, ?>> ATTRIBUTE_MAP_TYPE = TypeSpec.auto();
/**
* Check that a given {@link TargetObject} interface has a name
*
* <p>
* Names are assigned using the {@link DebuggerTargetObjectIface} annotation.
*
* @implNote To be language agnostic, we never use the name of the Java implementation of the
* interface.
*
* @param iface the class of the interface
* @return the name of the interface
* @throws IllegalArgumentException if the interface is not annotated
*/
public static String requireIfaceName(Class<? extends TargetObject> iface) {
DebuggerTargetObjectIface annot = iface.getAnnotation(DebuggerTargetObjectIface.class);
if (annot == null) {
throw new IllegalArgumentException(iface + " has no @" +
DebuggerTargetObjectIface.class.getSimpleName() + " annotation.");
}
return annot.value();
}
/**
* Check that the given value is not null
*
* @param <T> the type of the value
* @param val the value
* @param path the path where the value was expected
* @return the non-null value
* @throws DebuggerModelNoSuchPathException if -val- is null
*/
public static <T> T requireNonNull(T val, List<String> path) {
if (val == null) {
throw new DebuggerModelNoSuchPathException("Path " + path + " does not exist");
}
return val;
}
/**
* Check that the given object is non-null and supports a required interface
*
* <p>
* Because most of the {@link TargetObject} interfaces have a (self-referential) type parameter,
* this call will most likely be on its own line, assigned to a variable of the interface type
* using a wildcard {@code <?>} parameter. Otherwise, raw types get involved, making things
* rather messy.
*
* @param <T> the type of the interface
* @param iface the class for the interface
* @param obj the object to check
* @param path the path where the object was expected
* @return the (non-null) object cast to the required interface
* @throws DebuggerModelNoSuchPathException if -obj- is null
* @throws DebuggerModelTypeException if -obj- does not support -iface-
*/
public static <T extends TargetObject> T requireIface(Class<T> iface, TargetObject obj,
List<String> path) {
requireNonNull(obj, path);
String name = requireIfaceName(iface);
if (iface.isAssignableFrom(obj.getClass())) {
return iface.cast(obj);
}
throw new DebuggerModelTypeException("Object " + path + " is missing " + name);
}
/**
* Get a brief description of the client, suitable for display in lists
*
* @return the description
*/
public default String getBrief() {
return toString();
}
/**
* Add a listener for model events
*
* <p>
* If requested, the listener is notified of existing objects via an event replay. It will first
* replay all the created events in the same order they were originally emitted. Any objects
* which have since been invalidated are excluded in the replay. They don't exist anymore, after
* all. Next it will replay the attribute- and element-added events in post order. This is an
* attempt to ensure an object's dependencies are met by the time the client receives its added
* event. This isn't always possible due to cycles, but such cycles are usually informational.
*
* @param listener the listener
* @param replay true to replay object tree events (doesn't include register or memory caches)
*/
public void addModelListener(DebuggerModelListener listener, boolean replay);
/**
* Add a listener for model events, without replay
*
* @param listener the listener
*/
public default void addModelListener(DebuggerModelListener listener) {
addModelListener(listener, false);
}
/**
* Remove a model event listener
*
* @param listener the listener
*/
public void removeModelListener(DebuggerModelListener listener);
/**
* Check if the model believes it is alive
*
* <p>
* Basically, this should be true if the model has started, but not yet terminated. To test
* whether the model is actually responsive, use {@link #ping(String)}.
*
* @return true if alive
*/
public boolean isAlive();
/**
* Get the schema of this model, i.e., the schema of its root object.
*
* <p>
* The schema may not be known until the model has been successfully opened. Some factories will
* ensure success before providing the model, but this may not always be the case. Callers
* should listen for {@link DebuggerModelListener#modelOpened()} or retrieve the root object
* first.
*
* @return the root schema
*/
public default TargetObjectSchema getRootSchema() {
return EnumerableTargetObjectSchema.OBJECT;
}
/**
* Check if the debugger agent is alive (optional operation)
*
* <p>
* For models providing such a mechanism, check if the debugger is alive and able to process
* commands. Even if an explicit "ping" command is not available, an implementor is encouraged
* to use some sort of NOP or echo command to test for responsiveness.
*
* @param content some content to optionally incorporate into the test
* @return a future that completes when the daemon is verified to be alive
*/
public CompletableFuture<Void> ping(String content);
/**
* Check that a given reference (or object) belongs to this model
*
* <p>
* As a convenience, this method takes an expected class and casts -ref- to it. This is meant
* only to cast to an implementation-specific type, not for checking that an object supports a
* given interface. Use {@link #requireIface(Class, TargetObject, List)} for interface checking.
*
* @param <T> the required implementation-specific type
* @param cls the class for the required type
* @param obj the object to check
* @return the object, cast to the desired typed
* @throws DebuggerIllegalArgumentException if {@code obj} does not belong to this model
*/
default <T extends TargetObject> T assertMine(Class<T> cls, TargetObject obj) {
if (obj.getModel() != this) {
throw new DebuggerIllegalArgumentException(
"TargetObject " + obj + " does not belong to this model");
}
return cls.cast(obj);
}
/**
* Fetch the attributes of a given model path
*
* <p>
* Giving an empty path will retrieve the attributes of the root object. If the path does not
* exist, the future completes with {@code null}.
*
* @param path the path
* @param refresh true to invalidate caches involved in handling this request
* @return a future map of attributes
*/
public CompletableFuture<? extends Map<String, ?>> fetchObjectAttributes(List<String> path,
RefreshBehavior refresh);
/**
* Fetch the attributes of the given model path, without refreshing
*
* @see #fetchObjectAttributes(List, RefreshBehavior)
*/
public default CompletableFuture<? extends Map<String, ?>> fetchObjectAttributes(
List<String> path) {
return fetchObjectAttributes(path, RefreshBehavior.REFRESH_NEVER);
}
/**
* @see #fetchObjectAttributes(List)
*/
public default CompletableFuture<? extends Map<String, ?>> fetchObjectAttributes(
String... path) {
return fetchObjectAttributes(List.of(path));
}
/**
* Fetch the elements of a given model path
*
* <p>
* Giving an empty path will retrieve all the top-level objects, i.e., elements of the root. If
* the path does not exist, the future completes with {@code null}.
*
* @param path the path
* @param refresh true to invalidate caches involved in handling this request
* @return a future map of elements
*/
public CompletableFuture<? extends Map<String, ? extends TargetObject>> fetchObjectElements(
List<String> path, RefreshBehavior refresh);
/**
* Fetch the elements of the given model path, without refreshing
*
* @see #fetchObjectElements(List, RefreshBehavior)
*/
public default CompletableFuture<? extends Map<String, ? extends TargetObject>> fetchObjectElements(
List<String> path) {
return fetchObjectElements(path, RefreshBehavior.REFRESH_NEVER);
}
/**
* @see #fetchObjectElements(List)
*/
public default CompletableFuture<? extends Map<String, ? extends TargetObject>> fetchObjectElements(
String... path) {
return fetchObjectElements(List.of(path));
}
/**
* Fetch the root object of the model
*
* <p>
* The root is a virtual object to contain all the top-level objects of the model tree. This
* object represents the debugger itself. Note in most cases {@link #getModelRoot()} is
* sufficient; however, if you've just created the model, it is prudent to wait for it to create
* its root. For asynchronous cases, just listen for the root-creation and -added events. This
* method returns a future which completes after the root-added event.
*
* @return a future which completes with the root
*/
public CompletableFuture<? extends TargetObject> fetchModelRoot();
/**
* Get the root object of the model
*
* @return the root or {@code null} if it hasn't been created, yet
*/
public TargetObject getModelRoot();
/**
* Fetch the value at the given path
*
* @param path the path of the value
* @return a future completing with the value or with {@code null} if the path does not exist
*/
public CompletableFuture<?> fetchModelValue(List<String> path);
/**
* Fetch a model value, optionally refreshing caches along the path
*
* <p>
* By convention, no attribute nor element may have a {@code null} value. Thus, a {@code null}
* return value always indicates the path does not exist.
*
* <p>
* When refresh is true, only the applicable cache at each successor is refreshed. For example,
* when the path is {@code A.B[1].C[2]}, then only {@code B}'s and {@code C}'s element caches
* are refreshed; and {@code A}'s, {@code B[1]}'s, and {@code C[2]}'s attribute caches are
* refreshed.
*
* @param path the path
* @param refresh true to refresh caches
* @return the found value, or {@code null} if it does not exist
*/
public CompletableFuture<?> fetchModelValue(List<String> path, RefreshBehavior refresh);
/**
* @see #fetchModelValue(List)
*/
public default CompletableFuture<?> fetchModelValue(String... path) {
return fetchModelValue(List.of(path));
}
/**
* Get the value at a given path
*
* <p>
* If the path does not exist, null is returned. Note that an attempt to access the child of a
* primitive is the same as accessing a path that does not exist; however, an error will be
* logged, since this typically indicates a programming error.
*
* @param path the path
* @return the value
*/
public default Object getModelValue(List<String> path) {
Object cur = getModelRoot();
for (String key : path) {
if (cur == null) {
return null;
}
if (!(cur instanceof TargetObject)) {
Msg.error(this, "Primitive " + cur + " cannot have child '" + key + "'");
return null;
}
TargetObject obj = (TargetObject) cur;
if (PathUtils.isIndex(key)) {
cur = obj.getCachedElements().get(PathUtils.parseIndex(key));
continue;
}
assert PathUtils.isName(key);
cur = obj.getCachedAttribute(key);
}
return cur;
}
/**
* Fetch the object with the given path
*
* <p>
* If the value at the path is a link, this will attempt to fetch it.
*
* @param path the path of the object
* @param refresh ignore the cache
* @return a future completing with the object or with {@code null} if it does not exist
* @throws DebuggerModelTypeException if the value at the path is not a {@link TargetObject}
*/
public default CompletableFuture<? extends TargetObject> fetchModelObject(List<String> path,
RefreshBehavior refresh) {
return fetchModelValue(path, refresh).thenApply(v -> {
if (v == null) {
return null;
}
if (!(v instanceof TargetObject)) {
throw DebuggerModelTypeException.typeRequired(v, path, TargetObject.class);
}
return (TargetObject) v;
});
}
/**
* Get an object from the model, resyncing according to the schema
*
* <p>
* This is necessary when an object in the path has a resync mode other than
* {@link ResyncMode#NEVER} for the child being retrieved. Please note that some synchronization
* may still be required on the client side, since accessing the object before it is created
* will cause a {@code null} completion.
*
* @return a future that completes with the object or with {@code null} if it doesn't exist
*/
@Deprecated
public default CompletableFuture<? extends TargetObject> fetchModelObject(List<String> path) {
return fetchModelObject(path, RefreshBehavior.REFRESH_NEVER);
}
/**
* Get an object from the model
*
* <p>
* Note this may return an object which is still being constructed, i.e., between being created
* and being added to the model. This differs from {@link #getModelValue(List)}, which will only
* return an object after it has been added. This method also never follows links.
*
* @param path the path of the object
* @return the object or {@code null} if it doesn't exist
*/
public TargetObject getModelObject(List<String> path);
/**
* Get all created objects matching a given predicate
*
* <p>
* Note the predicate is executed while holding an internal model-wide lock. Be careful and keep
* it simple.
*
* @param predicate the predicate
* @return the set of matching objects
*/
public Set<TargetObject> getModelObjects(Predicate<? super TargetObject> predicate);
/**
* @see #fetchModelObject(List)
*/
@Deprecated
public default CompletableFuture<? extends TargetObject> fetchModelObject(String... path) {
return fetchModelObject(List.of(path));
}
/**
* @see #getModelObject(List)
*/
public default TargetObject getModelObject(String... path) {
return getModelObject(List.of(path));
}
/**
* Fetch the attribute with the given path
*
* Note that model implementations should avoid nullable attributes, since a null-valued
* attribute cannot easily be distinguished from a non-existent attribute.
*
* @param path the path of the attribute
* @return a future that completes with the value or with {@code null} if it does not exist
*/
public default CompletableFuture<?> fetchObjectAttribute(List<String> path) {
return fetchModelObject(PathUtils.parent(path)).thenApply(
parent -> parent == null ? null : parent.fetchAttribute(PathUtils.getKey(path)));
}
/**
* @see #fetchObjectAttribute(List)
*/
public default CompletableFuture<?> getObjectAttribute(String... path) {
return fetchObjectAttribute(List.of(path));
}
/**
* Get a factory for target addresses
*
* <p>
* Technically, putting this here instead of just {@link TargetMemory} imposes a subtle
* limitation: All targets in the model have to have the same factory. I'm not certain that's a
* huge concern at this point. The alternative is that the memory mapper has to accept and
* compose new address factories, or we need a separate mapper per factory encountered along
* with a mechanism to choose the correct one.
*
* @return the factory
*/
public AddressFactory getAddressFactory();
/**
* TODO Document me
*
* @param name
* @return
*/
default public AddressSpace getAddressSpace(String name) {
return getAddressFactory().getAddressSpace(name);
}
/**
* TODO Document me
*
* @param space
* @param offset
* @return
*/
public default Address getAddress(String space, long offset) {
if (Address.NO_ADDRESS.getAddressSpace().getName().equals(space)) {
return Address.NO_ADDRESS;
}
return getAddressSpace(space).getAddress(offset);
}
/**
* Invalidate the caches for every object known locally.
*
* <p>
* Unlike, {@link TargetObject#invalidateCaches()}, this does not push the request to a remote
* object. If the objects are proxies, just the proxies' caches are cleared. Again, this does
* not apply to caches for the objects' children.
*/
public void invalidateAllLocalCaches();
/**
* Close the session and dispose the model
*
* <p>
* For local sessions, terminate the debugger. For client sessions, disconnect.
*
* @return a future which completes when the session is closed
*/
public CompletableFuture<Void> close();
/**
* A convenience for reporting errors conditionally
*
* <p>
* If the message is ignorable, e.g., a {@link DebuggerModelTerminatingException}, then the
* report will be reduced to a stack-free warning.
*
* @param origin the object producing the error
* @param message the error message
* @param ex the exception
*/
default void reportError(Object origin, String message, Throwable ex) {
Throwable unwrapped = AsyncUtils.unwrapThrowable(ex);
if (ex == null || DebuggerModelTerminatingException.isIgnorable(ex)) {
Msg.warn(origin, message + ": " + ex);
}
else if (unwrapped instanceof RejectedExecutionException) {
Msg.trace(origin, "Ignoring rejection", ex);
}
else if (unwrapped instanceof DisposedException) {
Msg.trace(origin, "Ignoring disposal", ex);
}
else {
Msg.error(origin, message, ex);
}
}
/**
* Permit all callbacks to be invoked before proceeding
*
* <p>
* This operates by placing the request into the queue itself, so that any event callbacks
* queued <em>at the time of the flush invocation</em> are completed first. There are no
* guarantees with respect to events which get queued <em>after the flush invocation</em>.
*
* @return a future which completes when all queued callbacks have been invoked
*/
CompletableFuture<Void> flushEvents();
}

Some files were not shown because too many files have changed in this diff Show more