mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-1978: Delete Framework-Debugging. Merge needed parts into
TraceModeling.
This commit is contained in:
parent
8dd0ea698a
commit
f5a93c3072
429 changed files with 5093 additions and 23085 deletions
|
@ -32,6 +32,7 @@ from pybag.dbgeng.win32.kernel32 import STILL_ACTIVE
|
|||
|
||||
from . import util, arch, methods, hooks
|
||||
from .dbgmodel.imodelobject import ModelObjectKind
|
||||
if util.is_exdi():
|
||||
from .exdi import exdi_commands, exdi_methods
|
||||
|
||||
PAGE_SIZE = 4096
|
||||
|
|
|
@ -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)."""
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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'):
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.*;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, "")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
# Framework-Debugging
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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|
|
|
@ -1 +0,0 @@
|
|||
DebuggerClientFactory
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue