From 50c7217635ab1c047136a7affbaecd6f4e86e03b Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Thu, 10 Nov 2022 13:46:23 -0500 Subject: [PATCH] GP-2752: Remove TargetObject.addListener() and related --- .../model/iface2/DbgModelTargetObject.java | 4 - .../iface2/DbgModelTargetRegisterBank.java | 10 +- .../model/iface2/DbgModelTargetSession.java | 2 +- ...DbgModelTargetBreakpointContainerImpl.java | 2 +- .../DbgModelTargetMemoryContainerImpl.java | 4 +- .../DbgModelTargetModuleContainerImpl.java | 22 +- .../DbgModelTargetProcessContainerImpl.java | 12 +- .../model/impl/DbgModelTargetProcessImpl.java | 5 +- .../DbgModelTargetRegisterContainerImpl.java | 4 +- .../DbgModelTargetThreadContainerImpl.java | 22 +- .../model/impl/DbgModel2TargetObjectImpl.java | 9 +- .../model/impl/DbgModel2TargetRootImpl.java | 16 +- .../model/iface2/FridaModelTargetObject.java | 4 - .../model/iface2/FridaModelTargetSession.java | 2 +- ...aModelTargetKernelMemoryContainerImpl.java | 6 +- ...aModelTargetKernelModuleContainerImpl.java | 19 +- .../FridaModelTargetMemoryContainerImpl.java | 6 +- .../FridaModelTargetModuleContainerImpl.java | 41 +-- .../FridaModelTargetProcessContainerImpl.java | 2 +- .../impl/FridaModelTargetProcessImpl.java | 2 +- ...FridaModelTargetRegisterContainerImpl.java | 51 ++- .../FridaModelTargetThreadContainerImpl.java | 8 +- .../GdbModelTargetBreakpointContainer.java | 2 +- .../model/impl/GdbModelTargetInferior.java | 25 +- .../impl/GdbModelTargetInferiorContainer.java | 10 +- .../impl/GdbModelTargetProcessMemory.java | 10 +- .../gdb/model/impl/GdbModelTargetSession.java | 2 +- .../model/impl/GdbModelTargetStackFrame.java | 2 +- ...odelTargetStackFrameRegisterContainer.java | 2 +- .../model/iface2/LldbModelTargetObject.java | 4 - .../model/iface2/LldbModelTargetSession.java | 2 +- ...ldbModelTargetBreakpointContainerImpl.java | 19 +- .../LldbModelTargetMemoryContainerImpl.java | 4 +- .../LldbModelTargetModuleContainerImpl.java | 8 +- .../LldbModelTargetProcessContainerImpl.java | 2 +- .../impl/LldbModelTargetProcessImpl.java | 4 +- ...ModelTargetStackFrameRegisterBankImpl.java | 15 +- .../LldbModelTargetThreadContainerImpl.java | 6 +- ...dpClientTargetBreakpointSpecContainer.java | 2 +- .../client/GadpClientTargetEventScope.java | 2 +- .../gadp/client/GadpClientTargetMemory.java | 5 +- .../gadp/client/GadpClientTargetObject.java | 3 +- .../client/GadpClientTargetRegisterBank.java | 2 +- .../ghidra/dbg/gadp/GadpClientServerTest.java | 70 ++-- .../model/JdiModelTargetClassContainer.java | 4 - .../JdiModelTargetConnectorContainer.java | 4 - .../model/JdiModelTargetModuleContainer.java | 4 - .../dbg/jdi/model/JdiModelTargetProcess.java | 2 +- .../JdiModelTargetRegisterContainer.java | 8 +- .../model/JdiModelTargetSectionContainer.java | 4 +- .../dbg/jdi/model/JdiModelTargetStack.java | 6 +- .../model/JdiModelTargetThreadContainer.java | 2 +- .../jdi/model/JdiModelTargetVMContainer.java | 24 +- .../model/iface2/JdiModelTargetObject.java | 4 - ...tractDebuggerWrappedConsoleConnection.java | 24 +- .../gui/objects/DebuggerObjectsProvider.java | 7 +- .../objects/components/DummyTargetObject.java | 11 +- .../gui/objects/components/ObjectTree.java | 1 - .../model/DebuggerModelServicePlugin.java | 141 +++----- .../service/model/RecorderComposedMemory.java | 251 -------------- .../model/RecorderComposedRegisterSet.java | 107 ------ .../ghidra/dbg/DebugModelConventions.java | 312 +----------------- .../dbg/agent/AbstractTargetObject.java | 49 +-- .../ghidra/dbg/agent/DefaultTargetObject.java | 34 +- .../ghidra/dbg/agent/SpiTargetObject.java | 3 + .../java/ghidra/dbg/target/TargetObject.java | 37 --- ...nnotatedDebuggerAttributeListenerTest.java | 14 +- .../agent/DefaultDebuggerObjectModelTest.java | 4 +- .../model/AbstractTestTargetRegisterBank.java | 4 +- .../dbg/model/TestTargetInterpreter.java | 2 +- .../ghidra/dbg/model/TestTargetMemory.java | 4 +- .../ghidra/dbg/model/TestTargetSession.java | 2 +- .../AbstractDebuggerModelInterpreterTest.java | 14 +- .../util/DebuggerCallbackReordererTest.java | 27 +- .../AbstractDBTraceProgramViewMemory.java | 7 +- .../program/DBTraceProgramViewMemory.java | 9 +- .../ghidra/util/datastruct/ListenerMap.java | 53 --- .../ghidra/util/datastruct/ListenerSet.java | 12 - 78 files changed, 384 insertions(+), 1261 deletions(-) delete mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java delete mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedRegisterSet.java diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetObject.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetObject.java index 027f9a62fa..0776aeaa21 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetObject.java @@ -23,11 +23,9 @@ import agent.dbgeng.dbgeng.DebugClient.DebugStatus; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.AbstractDbgModel; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.agent.SpiTargetObject; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.CollectionUtils.Delta; -import ghidra.util.datastruct.ListenerSet; public interface DbgModelTargetObject extends SpiTargetObject { @@ -65,8 +63,6 @@ public interface DbgModelTargetObject extends SpiTargetObject { public CompletableFuture> requestNativeElements(); - public ListenerSet getListeners(); - public DbgModelTargetSession getParentSession(); public DbgModelTargetProcess getParentProcess(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java index 55f2209a7b..f7f3a37b68 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java @@ -25,12 +25,10 @@ import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.*; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.error.DebuggerRegisterAccessException; import ghidra.dbg.target.TargetRegisterBank; import ghidra.dbg.util.ConversionUtils; import ghidra.util.Msg; -import ghidra.util.datastruct.ListenerSet; public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, TargetRegisterBank { @@ -91,10 +89,8 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target reg.setModified(value.toString(16).equals(oldval)); } } - ListenerSet listeners = getListeners(); - if (listeners != null) { - listeners.fire.registersUpdated(getProxy(), result); - } + + broadcast().registersUpdated(getProxy(), result); return result; }); } @@ -126,7 +122,7 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target getParentThread().getThread().writeRegisters(toWrite).handle(seq::next); // TODO: Should probably filter only effective and normalized writes in the callback }).then(seq -> { - getListeners().fire.registersUpdated(getProxy(), values); + broadcast().registersUpdated(getProxy(), values); seq.exit(); }).finish(); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java index 7ef618bd6d..e70d744dc7 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java @@ -79,7 +79,7 @@ public interface DbgModelTargetSession extends // if (!isValid()) { return; } - getListeners().fire.consoleOutput(getProxy(), chan, output); + broadcast().consoleOutput(getProxy(), chan, output); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java index b6e8ef76a5..5a2c9afe4c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java @@ -95,7 +95,7 @@ public class DbgModelTargetBreakpointContainerImpl extends DbgModelTargetObjectI DbgModelTargetThread targetThread = getParentProcess().getThreads().getTargetThread(getManager().getEventThread()); DbgModelTargetBreakpointSpec spec = getTargetBreakpointSpec(info); - listeners.fire.breakpointHit(getProxy(), targetThread, null, spec, spec); + broadcast().breakpointHit(getProxy(), targetThread, null, spec, spec); spec.breakpointHit(); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java index fc6bab41bc..143de6b324 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java @@ -121,7 +121,7 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl if (span == null) { throw new DebuggerMemoryAccessException("Cannot read at " + address); } - listeners.fire.memoryUpdated(getProxy(), address, buf.array()); + broadcast().memoryUpdated(getProxy(), address, buf.array()); return Arrays.copyOf(buf.array(), (int) span.length()); } @@ -138,7 +138,7 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl } private void writeAssist(Address address, byte[] data) { - listeners.fire.memoryUpdated(getProxy(), address, data); + broadcast().memoryUpdated(getProxy(), address, data); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java index 3a267508b9..b369f0f93d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java @@ -27,13 +27,16 @@ import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode; import ghidra.lifecycle.Internal; -@TargetObjectSchemaInfo(name = "ModuleContainer", elements = { // - @TargetElementType(type = DbgModelTargetModuleImpl.class) // -}, // - elementResync = ResyncMode.ONCE, // - attributes = { // - @TargetAttributeType(type = Void.class) // - }, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "ModuleContainer", + elements = { + @TargetElementType(type = DbgModelTargetModuleImpl.class) + }, + elementResync = ResyncMode.ONCE, + attributes = { + @TargetAttributeType(type = Void.class) + }, + canonicalContainer = true) public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetModuleContainer { // NOTE: -file-list-shared-libraries omits the main module and system-supplied DSO. @@ -66,7 +69,7 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl TargetThread eventThread = (TargetThread) getModel().getModelObject(getManager().getEventThread()); changeElements(List.of(), List.of(module), Map.of(), "Loaded"); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, "Library " + name + " loaded", List.of(module)); } @@ -77,7 +80,7 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl if (targetModule != null) { TargetThread eventThread = (TargetThread) getModel().getModelObject(getManager().getEventThread()); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, "Library " + name + " unloaded", List.of(targetModule)); DbgModelImpl impl = (DbgModelImpl) model; impl.deleteModelObject(targetModule.getDbgModule()); @@ -108,6 +111,7 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl }); } + @Override public DbgModelTargetModule getTargetModule(String name) { // Only get here from libraryLoaded or getElements. The known list should be fresh. DbgModule module = process.getKnownModules().get(name); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java index f9d9e5b4f8..bc581e0507 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java @@ -33,12 +33,12 @@ import ghidra.dbg.target.schema.*; @TargetObjectSchemaInfo( name = "ProcessContainer", - elements = { // - @TargetElementType(type = DbgModelTargetProcessImpl.class) // + elements = { + @TargetElementType(type = DbgModelTargetProcessImpl.class) }, - attributes = { // - @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), // - @TargetAttributeType(type = Void.class) // + attributes = { + @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), + @TargetAttributeType(type = Void.class) }, canonicalContainer = true) public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl @@ -58,7 +58,7 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl DbgModelTargetProcess process = getTargetProcess(proc); changeElements(List.of(), List.of(process), Map.of(), "Added"); process.processStarted(proc.getPid()); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_CREATED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_CREATED, "Process " + proc.getId() + " started " + process.getName() + "pid=" + proc.getPid(), List.of(process)); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessImpl.java index 348de016ec..d0845d2156 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessImpl.java @@ -139,6 +139,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl } } + @Override public void threadStateChangedSpecific(DbgThread thread, DbgState state) { TargetExecutionState targetState = convertState(state); setExecutionState(targetState, "ThreadStateChanged"); @@ -212,7 +213,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl STATE_ATTRIBUTE_NAME, TargetExecutionState.TERMINATED, // EXIT_CODE_ATTRIBUTE_NAME, proc.getExitCode() // ), "Exited"); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_EXITED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_EXITED, "Process " + proc.getId() + " exited code=" + proc.getExitCode(), List.of(getProxy())); } @@ -221,7 +222,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl @Override public void memoryChanged(DbgProcess proc, long addr, int len, DbgCause cause) { if (proc.equals(this.process)) { - listeners.fire.invalidateCacheRequested(memory); + broadcast().invalidateCacheRequested(memory); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java index 5c7aa075bb..f1fb8887f4 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java @@ -134,7 +134,7 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp changeAttrs(reg, value); } this.values = result; - listeners.fire.registersUpdated(getProxy(), result); + broadcast().registersUpdated(getProxy(), result); return result; })); } @@ -159,7 +159,7 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp return thread.writeRegisters(toWrite); // TODO: Should probably filter only effective and normalized writes in the callback }).thenAccept(__ -> { - listeners.fire.registersUpdated(getProxy(), values); + broadcast().registersUpdated(getProxy(), values); })); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java index 532a150890..c224e733fd 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java @@ -31,12 +31,16 @@ import ghidra.dbg.target.TargetConfigurable; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.*; -@TargetObjectSchemaInfo(name = "ThreadContainer", elements = { // - @TargetElementType(type = DbgModelTargetThreadImpl.class) // -}, attributes = { // - @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), // - @TargetAttributeType(type = Void.class) // -}, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "ThreadContainer", + elements = { + @TargetElementType(type = DbgModelTargetThreadImpl.class) + }, + attributes = { + @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), + @TargetAttributeType(type = Void.class) + }, + canonicalContainer = true) public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetThreadContainer, DbgModelTargetConfigurable { @@ -59,7 +63,7 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl DbgModelTargetThread targetThread = getTargetThread(thread); changeElements(List.of(), List.of(targetThread), Map.of(), "Created"); targetThread.threadStateChangedSpecific(DbgState.STARTING, DbgReason.getReason(null)); - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, "Thread " + thread.getId() + " started", List.of(targetThread)); } @@ -68,7 +72,7 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl DbgReason reason) { DbgModelTargetThread targetThread = getTargetThread(thread); TargetEventType eventType = getEventType(state, cause, reason); - getListeners().fire.event(getProxy(), targetThread, eventType, + broadcast().event(getProxy(), targetThread, eventType, "Thread " + thread.getId() + " state changed", List.of(targetThread)); targetThread.threadStateChangedSpecific(state, reason); } @@ -78,7 +82,7 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl DbgModelImpl impl = (DbgModelImpl) model; DbgModelTargetThread targetThread = (DbgModelTargetThread) impl.getModelObject(threadId); if (targetThread != null) { - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, "Thread " + threadId + " exited", List.of(targetThread)); } //synchronized (this) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java index 5f4f4aad84..1214224aaa 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java @@ -32,7 +32,6 @@ import agent.dbgmodel.jna.dbgmodel.DbgModelNative.ModelObjectKind; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.TypeKind; import agent.dbgmodel.manager.DbgManager2Impl; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.agent.DefaultTargetObject; import ghidra.dbg.target.*; import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; @@ -254,7 +253,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject { TargetThread eventThread = (TargetThread) t; - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, "Library " + info.getModuleName() + " loaded", List.of(mod)); }); getObject(getManager().getEventProcess()).thenAccept(p -> { @@ -231,7 +231,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot } getObject(getManager().getEventThread()).thenAccept(t -> { TargetThread eventThread = (TargetThread) t; - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, "Library " + info.getModuleName() + " unloaded", List.of(mod)); }); getObject(getManager().getEventProcess()).thenAccept(p -> { @@ -369,7 +369,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, proc.getExitCode() // ), "Exited"); } - getListeners().fire.event(targetProcess.getProxy(), null, + broadcast().event(targetProcess.getProxy(), null, TargetEventType.PROCESS_EXITED, "Process " + proc.getId() + " exited code=" + proc.getExitCode(), List.of(getProxy())); @@ -383,7 +383,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot return; } DbgModelTargetThread targetThread = (DbgModelTargetThread) thread.getProxy(); - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, "Thread " + threadId + " exited", List.of(targetThread)); }); } @@ -401,7 +401,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot ), reason.desc()); intrinsics.put(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread); TargetEventType eventType = getEventType(state, cause, reason); - getListeners().fire.event(getProxy(), targetThread, eventType, + broadcast().event(getProxy(), targetThread, eventType, "Thread " + thread.getId() + " state changed", List.of(targetThread)); DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) targetThread.getDelegate(); @@ -472,7 +472,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DbgThread thread = info.getEventThread(); TargetObject targetThread = getModel().getModelObject(thread); - listeners.fire.breakpointHit(bpt.getParent(), targetThread, null, bpt, bpt); + broadcast().breakpointHit(bpt.getParent(), targetThread, null, bpt, bpt); bpt.breakpointHit(); }); } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetObject.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetObject.java index f498c89ee3..e1197e3bdd 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetObject.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetObject.java @@ -22,11 +22,9 @@ import java.util.concurrent.CompletableFuture; import agent.frida.manager.impl.FridaManagerImpl; import agent.frida.model.AbstractFridaModel; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.agent.SpiTargetObject; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.CollectionUtils.Delta; -import ghidra.util.datastruct.ListenerSet; public interface FridaModelTargetObject extends SpiTargetObject { @@ -59,8 +57,6 @@ public interface FridaModelTargetObject extends SpiTargetObject { public CompletableFuture> requestNativeElements(); - public ListenerSet getListeners(); - public FridaModelTargetSession getParentSession(); public FridaModelTargetProcess getParentProcess(); diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetSession.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetSession.java index 91a837c9d3..39588f6291 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetSession.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/iface2/FridaModelTargetSession.java @@ -50,7 +50,7 @@ public interface FridaModelTargetSession extends // == DebugOutputFlags.DEBUG_OUTPUT_WARNING.getValue())) { chan = TargetConsole.Channel.STDERR; } - getListeners().fire.consoleOutput(getProxy(), chan, output); + broadcast().consoleOutput(getProxy(), chan, output); } @Override diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelMemoryContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelMemoryContainerImpl.java index 360f02cbb7..15343c74b8 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelMemoryContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelMemoryContainerImpl.java @@ -80,7 +80,7 @@ public class FridaModelTargetKernelMemoryContainerImpl extends FridaModelTargetO @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listKernelMemory(); } @@ -104,12 +104,12 @@ public class FridaModelTargetKernelMemoryContainerImpl extends FridaModelTargetO if (range == null) { throw new DebuggerMemoryAccessException("Cannot read at " + address); } - listeners.fire.memoryUpdated(getProxy(), address, buf.array()); + broadcast().memoryUpdated(getProxy(), address, buf.array()); return Arrays.copyOf(buf.array(), (int) range.getLength()); } private void writeAssist(Address address, byte[] data) { - listeners.fire.memoryUpdated(getProxy(), address, data); + broadcast().memoryUpdated(getProxy(), address, data); } @Override diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelModuleContainerImpl.java index 6e60c25431..2d3aa54d3b 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetKernelModuleContainerImpl.java @@ -72,12 +72,13 @@ public class FridaModelTargetKernelModuleContainerImpl extends FridaModelTargetO TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); changeElements(List.of(), List.of(targetModule), Map.of(), "Loaded"); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, - "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, + "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); } @Override - public void moduleReplaced(FridaProcess proc, FridaModuleInfo info, int index, FridaCause cause) { + public void moduleReplaced(FridaProcess proc, FridaModuleInfo info, int index, + FridaCause cause) { FridaModule module = info.getModule(index); changeElements(List.of(), List.of(getTargetModule(module)), Map.of(), "Replaced"); FridaModelTargetModule targetModule = getTargetModule(module); @@ -85,14 +86,15 @@ public class FridaModelTargetKernelModuleContainerImpl extends FridaModelTargetO } @Override - public void moduleUnloaded(FridaProcess proc, FridaModuleInfo info, int index, FridaCause cause) { + public void moduleUnloaded(FridaProcess proc, FridaModuleInfo info, int index, + FridaCause cause) { FridaModelTargetModule targetModule = getTargetModule(info.getModule(index)); if (targetModule != null) { FridaThread thread = getManager().getCurrentThread(); TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, - "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, + "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); FridaModelImpl impl = (FridaModelImpl) model; impl.deleteModelObject(targetModule.getModule()); } @@ -112,7 +114,7 @@ public class FridaModelTargetKernelModuleContainerImpl extends FridaModelTargetO @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listKernelModules(); } @@ -121,7 +123,8 @@ public class FridaModelTargetKernelModuleContainerImpl extends FridaModelTargetO public FridaModelTargetKernelModuleImpl getTargetModule(FridaModule module) { TargetObject targetObject = getMapObject(module); if (targetObject != null) { - FridaModelTargetKernelModuleImpl targetModule = (FridaModelTargetKernelModuleImpl) targetObject; + FridaModelTargetKernelModuleImpl targetModule = + (FridaModelTargetKernelModuleImpl) targetObject; targetModule.setModelObject(module); return targetModule; } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetMemoryContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetMemoryContainerImpl.java index cb77ef4f16..9fe20eeff1 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetMemoryContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetMemoryContainerImpl.java @@ -102,7 +102,7 @@ public class FridaModelTargetMemoryContainerImpl extends FridaModelTargetObjectI @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listMemory(process.getProcess()); } @@ -126,12 +126,12 @@ public class FridaModelTargetMemoryContainerImpl extends FridaModelTargetObjectI if (range == null) { throw new DebuggerMemoryAccessException("Cannot read at " + address); } - listeners.fire.memoryUpdated(getProxy(), address, buf.array()); + broadcast().memoryUpdated(getProxy(), address, buf.array()); return Arrays.copyOf(buf.array(), (int) range.getLength()); } private void writeAssist(Address address, byte[] data) { - listeners.fire.memoryUpdated(getProxy(), address, data); + broadcast().memoryUpdated(getProxy(), address, data); } @Override diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetModuleContainerImpl.java index 42f76d2b39..79d9170f93 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetModuleContainerImpl.java @@ -20,25 +20,12 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import agent.frida.frida.FridaModuleInfo; -import agent.frida.manager.FridaCause; -import agent.frida.manager.FridaModule; -import agent.frida.manager.FridaProcess; -import agent.frida.manager.FridaSession; -import agent.frida.manager.FridaThread; -import agent.frida.model.iface2.FridaModelTargetModule; -import agent.frida.model.iface2.FridaModelTargetModuleContainer; -import agent.frida.model.iface2.FridaModelTargetSession; -import agent.frida.model.methods.FridaModelTargetModuleInitImpl; -import agent.frida.model.methods.FridaModelTargetModuleInterceptorImpl; -import agent.frida.model.methods.FridaModelTargetModuleLoadImpl; -import agent.frida.model.methods.FridaModelTargetUnloadScriptImpl; -import ghidra.dbg.target.TargetModule; -import ghidra.dbg.target.TargetObject; -import ghidra.dbg.target.TargetThread; -import ghidra.dbg.target.schema.TargetAttributeType; -import ghidra.dbg.target.schema.TargetElementType; +import agent.frida.manager.*; +import agent.frida.model.iface2.*; +import agent.frida.model.methods.*; +import ghidra.dbg.target.*; +import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode; -import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.util.Msg; @TargetObjectSchemaInfo( @@ -77,7 +64,7 @@ public class FridaModelTargetModuleContainerImpl extends FridaModelTargetObjectI unload // ), Map.of( // ), "Initialized"); - + getManager().addEventsListener(this); requestElements(true); } @@ -103,12 +90,13 @@ public class FridaModelTargetModuleContainerImpl extends FridaModelTargetObjectI TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); changeElements(List.of(), List.of(targetModule), Map.of(), "Loaded"); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, - "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, + "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); } @Override - public void moduleReplaced(FridaProcess proc, FridaModuleInfo info, int index, FridaCause cause) { + public void moduleReplaced(FridaProcess proc, FridaModuleInfo info, int index, + FridaCause cause) { FridaModule module = info.getModule(index); changeElements(List.of(), List.of(getTargetModule(module)), Map.of(), "Replaced"); FridaModelTargetModule targetModule = getTargetModule(module); @@ -116,14 +104,15 @@ public class FridaModelTargetModuleContainerImpl extends FridaModelTargetObjectI } @Override - public void moduleUnloaded(FridaProcess proc, FridaModuleInfo info, int index, FridaCause cause) { + public void moduleUnloaded(FridaProcess proc, FridaModuleInfo info, int index, + FridaCause cause) { FridaModelTargetModule targetModule = getTargetModule(info.getModule(index)); if (targetModule != null) { FridaThread thread = getManager().getCurrentThread(); TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, - "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, + "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); FridaModelImpl impl = (FridaModelImpl) model; impl.deleteModelObject(targetModule.getModule()); } @@ -143,7 +132,7 @@ public class FridaModelTargetModuleContainerImpl extends FridaModelTargetObjectI @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listModules(session.getProcess()); } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessContainerImpl.java index 7d27935c7e..68bd459e8d 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessContainerImpl.java @@ -64,7 +64,7 @@ public class FridaModelTargetProcessContainerImpl extends FridaModelTargetObject FridaModelTargetProcess process = getTargetProcess(proc); changeElements(List.of(), List.of(process), Map.of(), "Added"); process.processStarted(proc); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_CREATED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_CREATED, "Process " + FridaClient.getId(proc) + " started " + process.getName(), List.of(process)); } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessImpl.java index a8350ddf01..3df4e9826d 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetProcessImpl.java @@ -236,7 +236,7 @@ public class FridaModelTargetProcessImpl extends FridaModelTargetObjectImpl STATE_ATTRIBUTE_NAME, TargetExecutionState.TERMINATED, // EXIT_CODE_ATTRIBUTE_NAME, exitDesc // ), "Exited"); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_EXITED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_EXITED, "Process " + FridaClient.getId(getProcess()) + " exited code=" + exitDesc, List.of(getProxy())); } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetRegisterContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetRegisterContainerImpl.java index 1f152da536..16e71d5224 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetRegisterContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetRegisterContainerImpl.java @@ -16,42 +16,31 @@ package agent.frida.model.impl; import java.math.BigInteger; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import agent.frida.manager.FridaReason; -import agent.frida.manager.FridaState; -import agent.frida.manager.FridaValue; -import agent.frida.model.iface2.FridaModelTargetRegister; -import agent.frida.model.iface2.FridaModelTargetRegisterBank; -import agent.frida.model.iface2.FridaModelTargetRegisterContainerAndBank; +import agent.frida.manager.*; +import agent.frida.model.iface2.*; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.error.DebuggerRegisterAccessException; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetRegisterBank; -import ghidra.dbg.target.schema.TargetAttributeType; -import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode; -import ghidra.dbg.target.schema.TargetObjectSchemaInfo; -import ghidra.util.datastruct.ListenerSet; @TargetObjectSchemaInfo( name = "RegisterContainer", attributeResync = ResyncMode.ALWAYS, elements = { // - @TargetElementType(type = FridaModelTargetRegisterImpl.class) // + @TargetElementType(type = FridaModelTargetRegisterImpl.class) // }, attributes = { - @TargetAttributeType( - name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, - type = FridaModelTargetRegisterContainerImpl.class), - @TargetAttributeType(type = Void.class) + @TargetAttributeType( + name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, + type = FridaModelTargetRegisterContainerImpl.class), + @TargetAttributeType(type = Void.class) }, canonicalContainer = true) public class FridaModelTargetRegisterContainerImpl @@ -64,10 +53,10 @@ public class FridaModelTargetRegisterContainerImpl public FridaModelTargetRegisterContainerImpl(FridaModelTargetThreadImpl thread) { super(thread.getModel(), thread, NAME, "RegisterContainer"); this.thread = thread; - + changeAttributes(List.of(), List.of(), Map.of( - DISPLAY_ATTRIBUTE_NAME, getName(), - DESCRIPTIONS_ATTRIBUTE_NAME, this), "Initialized"); + DISPLAY_ATTRIBUTE_NAME, getName(), + DESCRIPTIONS_ATTRIBUTE_NAME, this), "Initialized"); requestElements(false); } @@ -78,7 +67,7 @@ public class FridaModelTargetRegisterContainerImpl @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listRegisters(thread.getThread()).thenAccept(registers -> { List targetRegisters; @@ -114,7 +103,8 @@ public class FridaModelTargetRegisterContainerImpl requestAttributes(false).thenAccept(__ -> { for (Object attribute : getCachedAttributes().values()) { if (attribute instanceof FridaModelTargetRegisterBank) { - FridaModelTargetRegisterBank bank = (FridaModelTargetRegisterBank) attribute; + FridaModelTargetRegisterBank bank = + (FridaModelTargetRegisterBank) attribute; bank.threadStateChangedSpecific(state, reason); } } @@ -136,12 +126,9 @@ public class FridaModelTargetRegisterContainerImpl byte[] bytes = register.getBytes(); result.put(regname, bytes); } - ListenerSet ls = getListeners(); - if (ls != null) { - //if (getName().contains("General")) { - ls.fire.registersUpdated(this, result); - //} - } + //if (getName().contains("General")) { + broadcast().registersUpdated(this, result); + //} return CompletableFuture.completedFuture(result); } @@ -158,7 +145,7 @@ public class FridaModelTargetRegisterContainerImpl BigInteger val = new BigInteger(1, ent.getValue()); reg.getRegister().setValue(val.toString()); } - getListeners().fire.registersUpdated(getProxy(), values); + broadcast().registersUpdated(getProxy(), values); return AsyncUtils.NIL; } diff --git a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetThreadContainerImpl.java b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetThreadContainerImpl.java index 4d485f94ad..1c33a68ca1 100644 --- a/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetThreadContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-frida/src/main/java/agent/frida/model/impl/FridaModelTargetThreadContainerImpl.java @@ -76,7 +76,7 @@ public class FridaModelTargetThreadContainerImpl extends FridaModelTargetObjectI changeElements(List.of(), List.of(targetThread), Map.of(), "Created"); targetThread.threadStateChangedSpecific(FridaState.FRIDA_THREAD_UNINTERRUPTIBLE, FridaReason.getReason(null)); - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, "Thread " + FridaClient.getId(thread) + " started", List.of(targetThread)); } @@ -95,7 +95,7 @@ public class FridaModelTargetThreadContainerImpl extends FridaModelTargetObjectI String threadId = FridaModelTargetThreadImpl.indexThread(thread); FridaModelTargetThread targetThread = (FridaModelTargetThread) getMapObject(thread); if (targetThread != null) { - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, "Thread " + threadId + " exited", List.of(targetThread)); } changeElements(List.of( // @@ -108,7 +108,7 @@ public class FridaModelTargetThreadContainerImpl extends FridaModelTargetObjectI FridaReason reason) { FridaModelTargetThread targetThread = getTargetThread(thread); TargetEventType eventType = getEventType(state, cause, reason); - getListeners().fire.event(getProxy(), targetThread, eventType, + broadcast().event(getProxy(), targetThread, eventType, "Thread " + FridaClient.getId(thread) + " state changed", List.of(targetThread)); targetThread.threadStateChangedSpecific(state, reason); } @@ -133,7 +133,7 @@ public class FridaModelTargetThreadContainerImpl extends FridaModelTargetObjectI @Override public CompletableFuture requestElements(boolean refresh) { if (refresh) { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } return getManager().listThreads(process); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetBreakpointContainer.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetBreakpointContainer.java index a3d545183e..95bd9a4742 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetBreakpointContainer.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetBreakpointContainer.java @@ -102,7 +102,7 @@ public class GdbModelTargetBreakpointContainer spec + " (pc=" + frame.getProgramCounter() + ")"); //return; // Not ideal, but eb == null should be fine, since the spec holds the actions } - listeners.fire.breakpointHit(this, frame.thread, frame, spec, loc); + broadcast().breakpointHit(this, frame.thread, frame, spec, loc); spec.breakpointHit(frame, loc); return loc; } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferior.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferior.java index abb658c70b..55d52e3deb 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferior.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferior.java @@ -186,7 +186,6 @@ public class GdbModelTargetInferior return impl.gateFuture(inferior.cont()); } - @Override public CompletableFuture step(TargetStepKind kind) { switch (kind) { @@ -210,7 +209,7 @@ public class GdbModelTargetInferior public CompletableFuture interrupt() { return impl.session.interrupt(); } - + @Override public CompletableFuture attach(TargetAttachable attachable) { GdbModelTargetAttachable mine = impl.assertMine(GdbModelTargetAttachable.class, attachable); @@ -233,7 +232,7 @@ public class GdbModelTargetInferior } protected CompletableFuture inferiorStarted(Long pid) { - parent.getListeners().fire.event(parent, null, TargetEventType.PROCESS_CREATED, + broadcast().event(parent, null, TargetEventType.PROCESS_CREATED, "Inferior " + inferior.getId() + " started " + inferior.getExecutable() + " pid=" + pid, List.of(this)); /*System.err.println("inferiorStarted: realState = " + realState); @@ -315,28 +314,28 @@ public class GdbModelTargetInferior params.add(loc); } gatherThreads(params, sco.getAffectedThreads()); - impl.session.getListeners().fire.event(impl.session, targetEventThread, - TargetEventType.BREAKPOINT_HIT, bpHit.desc(), params); + broadcast().event(impl.session, targetEventThread, TargetEventType.BREAKPOINT_HIT, + bpHit.desc(), params); } else if (reason instanceof GdbEndSteppingRangeReason) { List params = new ArrayList<>(); gatherThreads(params, sco.getAffectedThreads()); - impl.session.getListeners().fire.event(impl.session, targetEventThread, - TargetEventType.STEP_COMPLETED, reason.desc(), params); + broadcast().event(impl.session, targetEventThread, TargetEventType.STEP_COMPLETED, + reason.desc(), params); } else if (reason instanceof GdbSignalReceivedReason) { GdbSignalReceivedReason signal = (GdbSignalReceivedReason) reason; List params = new ArrayList<>(); params.add(signal.getSignalName()); gatherThreads(params, sco.getAffectedThreads()); - impl.session.getListeners().fire.event(impl.session, targetEventThread, - TargetEventType.SIGNAL, reason.desc(), params); + broadcast().event(impl.session, targetEventThread, TargetEventType.SIGNAL, + reason.desc(), params); } else { List params = new ArrayList<>(); gatherThreads(params, sco.getAffectedThreads()); - impl.session.getListeners().fire.event(impl.session, targetEventThread, - TargetEventType.STOPPED, reason.desc(), params); + broadcast().event(impl.session, targetEventThread, TargetEventType.STOPPED, + reason.desc(), params); } } @@ -445,8 +444,8 @@ public class GdbModelTargetInferior threads.getTargetThread(sco.getAffectedThreads().iterator().next()); } if (targetEventThread != null) { - impl.session.getListeners().fire.event(impl.session, targetEventThread, - TargetEventType.RUNNING, "Running", params); + broadcast().event(impl.session, targetEventThread, TargetEventType.RUNNING, + "Running", params); invalidateMemoryAndRegisterCaches(); } } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferiorContainer.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferiorContainer.java index a3bbe3d31d..83cb80bade 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferiorContainer.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetInferiorContainer.java @@ -71,7 +71,7 @@ public class GdbModelTargetInferiorContainer @Override public void inferiorExited(GdbInferior inf, GdbCause cause) { GdbModelTargetInferior inferior = getTargetInferior(inf); - parent.getListeners().fire.event(parent, null, TargetEventType.PROCESS_EXITED, + broadcast().event(parent, null, TargetEventType.PROCESS_EXITED, "Inferior " + inf.getId() + " exited code=" + inf.getExitCode(), List.of(inferior)); inferior.inferiorExited(inf.getExitCode()); } @@ -89,7 +89,7 @@ public class GdbModelTargetInferiorContainer public void threadCreated(GdbThread thread, GdbCause cause) { GdbModelTargetInferior inferior = getTargetInferior(thread.getInferior()); GdbModelTargetThread targetThread = inferior.threads.threadCreated(thread); - parent.getListeners().fire.event(parent, targetThread, TargetEventType.THREAD_CREATED, + broadcast().event(parent, targetThread, TargetEventType.THREAD_CREATED, "Thread " + thread.getId() + " started", List.of(targetThread)); } @@ -98,7 +98,7 @@ public class GdbModelTargetInferiorContainer GdbModelTargetInferior inferior = getTargetInferior(inf); GdbModelTargetThread targetThread = inferior.threads.getCachedElements().get(GdbModelTargetThread.indexThread(threadId)); - parent.getListeners().fire.event(parent, targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(parent, targetThread, TargetEventType.THREAD_EXITED, "Thread " + threadId + " exited", List.of(targetThread)); inferior.threads.threadExited(threadId); } @@ -107,7 +107,7 @@ public class GdbModelTargetInferiorContainer public void libraryLoaded(GdbInferior inf, String name, GdbCause cause) { GdbModelTargetInferior inferior = getTargetInferior(inf); GdbModelTargetModule module = inferior.modules.libraryLoaded(name); - parent.getListeners().fire.event(parent, null, TargetEventType.MODULE_LOADED, + broadcast().event(parent, null, TargetEventType.MODULE_LOADED, "Library " + name + " loaded", List.of(module)); } @@ -115,7 +115,7 @@ public class GdbModelTargetInferiorContainer public void libraryUnloaded(GdbInferior inf, String name, GdbCause cause) { GdbModelTargetInferior inferior = getTargetInferior(inf); GdbModelTargetModule module = inferior.modules.getTargetModuleIfPresent(name); - parent.getListeners().fire.event(parent, null, TargetEventType.MODULE_UNLOADED, + broadcast().event(parent, null, TargetEventType.MODULE_UNLOADED, "Library " + name + " unloaded", List.of(module)); inferior.modules.libraryUnloaded(name); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetProcessMemory.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetProcessMemory.java index 60e598ae53..b6e08b9091 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetProcessMemory.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetProcessMemory.java @@ -159,7 +159,7 @@ public class GdbModelTargetProcessMemory throw new DebuggerMemoryAccessException("Cannot read at " + address); } byte[] content = Arrays.copyOf(buf.array(), (int) s.length()); - listeners.fire.memoryUpdated(this, address, content); + broadcast().memoryUpdated(this, address, content); return content; }).exceptionally(e -> { e = AsyncUtils.unwrapThrowable(e); @@ -167,10 +167,10 @@ public class GdbModelTargetProcessMemory GdbCommandError gce = (GdbCommandError) e; e = new DebuggerMemoryAccessException( "Cannot read at " + address + ": " + gce.getInfo().getString("msg")); - listeners.fire.memoryReadError(this, range, (DebuggerMemoryAccessException) e); + broadcast().memoryReadError(this, range, (DebuggerMemoryAccessException) e); } if (e instanceof DebuggerMemoryAccessException) { - listeners.fire.memoryReadError(this, range, (DebuggerMemoryAccessException) e); + broadcast().memoryReadError(this, range, (DebuggerMemoryAccessException) e); } return ExceptionUtils.rethrow(e); }); @@ -186,12 +186,12 @@ public class GdbModelTargetProcessMemory CompletableFuture future = inferior.writeMemory(address.getOffset(), ByteBuffer.wrap(data)); return impl.gateFuture(future.thenAccept(__ -> { - listeners.fire.memoryUpdated(this, address, data); + broadcast().memoryUpdated(this, address, data); })); } protected void invalidateMemoryCaches() { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } public void memoryChanged(long offset, int len) { diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetSession.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetSession.java index d3206c6cba..5b9df1b2e9 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetSession.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetSession.java @@ -147,7 +147,7 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot default: throw new AssertionError(); } - listeners.fire.consoleOutput(this, dbgChannel, out); + broadcast().consoleOutput(this, dbgChannel, out); } @Override diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrame.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrame.java index 97f98db2c6..afc6d16ae1 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrame.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrame.java @@ -110,7 +110,7 @@ public class GdbModelTargetStackFrame } protected void invalidateRegisterCaches() { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } @Override diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrameRegisterContainer.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrameRegisterContainer.java index 650a0f3d65..0579e3fcc6 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrameRegisterContainer.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetStackFrameRegisterContainer.java @@ -117,7 +117,7 @@ public class GdbModelTargetStackFrameRegisterContainer elements.get(regName).stateChanged(bytes); } this.regValues = result; - listeners.fire.registersUpdated(this, result); + broadcast().registersUpdated(this, result); return result; }); } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetObject.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetObject.java index 501992ac05..35d8fd7fc6 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetObject.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetObject.java @@ -22,11 +22,9 @@ import java.util.concurrent.CompletableFuture; import agent.lldb.manager.impl.LldbManagerImpl; import agent.lldb.model.AbstractLldbModel; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.agent.SpiTargetObject; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.CollectionUtils.Delta; -import ghidra.util.datastruct.ListenerSet; public interface LldbModelTargetObject extends SpiTargetObject { @@ -59,8 +57,6 @@ public interface LldbModelTargetObject extends SpiTargetObject { public CompletableFuture> requestNativeElements(); - public ListenerSet getListeners(); - public LldbModelTargetSession getParentSession(); public LldbModelTargetProcess getParentProcess(); diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetSession.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetSession.java index 8c5f2d2db2..1e234bce37 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetSession.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/iface2/LldbModelTargetSession.java @@ -53,7 +53,7 @@ public interface LldbModelTargetSession extends // if (output.contains("loaded *kernel* extension dll for usermode")) { return; } - getListeners().fire.consoleOutput(getProxy(), chan, output); + broadcast().consoleOutput(getProxy(), chan, output); } @Override diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetBreakpointContainerImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetBreakpointContainerImpl.java index efaec668d8..cc95bf42f3 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetBreakpointContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetBreakpointContainerImpl.java @@ -47,8 +47,7 @@ public class LldbModelTargetBreakpointContainerImpl extends LldbModelTargetObjec TargetBreakpointKind.SW_EXECUTE, //TargetBreakpointKind.HW_EXECUTE, TargetBreakpointKind.READ, - TargetBreakpointKind.WRITE - ); + TargetBreakpointKind.WRITE); private final SBTarget session; @@ -98,22 +97,25 @@ public class LldbModelTargetBreakpointContainerImpl extends LldbModelTargetObjec BigInteger bptId = t.GetStopReasonDataAtIndex(0); BigInteger locId = t.GetStopReasonDataAtIndex(1); if (bpt.GetID() == bptId.intValue()) { - LldbModelTargetProcess targetProcess = (LldbModelTargetProcess) getModel().getModelObject(eventProcess); + LldbModelTargetProcess targetProcess = + (LldbModelTargetProcess) getModel().getModelObject(eventProcess); LldbModelTargetThread targetThread = - targetProcess.getThreads().getTargetThread(t); + targetProcess.getThreads().getTargetThread(t); LldbModelTargetBreakpointSpec spec = getTargetBreakpointSpec(bpt); if (spec == null) { - Msg.error(this, "Stopped for breakpoint unknown to the agent: " + bpt + " (pc=" + - targetThread + ")"); + Msg.error(this, + "Stopped for breakpoint unknown to the agent: " + bpt + " (pc=" + + targetThread + ")"); return; } LldbModelTargetBreakpointLocation loc = spec.findLocation(locId); if (loc == null) { Msg.warn(this, - "Stopped for a breakpoint whose location is unknown to the agent: " + spec); + "Stopped for a breakpoint whose location is unknown to the agent: " + + spec); } - listeners.fire.breakpointHit(this, targetThread, null, spec, loc); + broadcast().breakpointHit(this, targetThread, null, spec, loc); } } } @@ -148,6 +150,7 @@ public class LldbModelTargetBreakpointContainerImpl extends LldbModelTargetObjec }); } + @Override public SBTarget getSession() { return session; } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetMemoryContainerImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetMemoryContainerImpl.java index 17a49c8931..7ac40ba1ee 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetMemoryContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetMemoryContainerImpl.java @@ -87,12 +87,12 @@ public class LldbModelTargetMemoryContainerImpl extends LldbModelTargetObjectImp if (range == null) { throw new DebuggerMemoryAccessException("Cannot read at " + address); } - listeners.fire.memoryUpdated(getProxy(), address, buf.array()); + broadcast().memoryUpdated(getProxy(), address, buf.array()); return Arrays.copyOf(buf.array(), (int) range.getLength()); } private void writeAssist(Address address, byte[] data) { - listeners.fire.memoryUpdated(getProxy(), address, data); + broadcast().memoryUpdated(getProxy(), address, data); } @Override diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetModuleContainerImpl.java index b055e51b01..514491ca6f 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetModuleContainerImpl.java @@ -72,8 +72,8 @@ public class LldbModelTargetModuleContainerImpl extends LldbModelTargetObjectImp TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); changeElements(List.of(), List.of(targetModule), Map.of(), "Loaded"); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, - "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_LOADED, + "Library " + info.getModuleName(index) + " loaded", List.of(targetModule)); } @Override @@ -84,8 +84,8 @@ public class LldbModelTargetModuleContainerImpl extends LldbModelTargetObjectImp SBThread thread = getManager().getEventThread(); TargetThread eventThread = (TargetThread) getModel().getModelObject(thread); - getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, - "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); + broadcast().event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, + "Library " + info.getModuleName(index) + " unloaded", List.of(targetModule)); LldbModelImpl impl = (LldbModelImpl) model; impl.deleteModelObject(targetModule.getModule()); } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessContainerImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessContainerImpl.java index 478c80c784..fbb56c6d24 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessContainerImpl.java @@ -70,7 +70,7 @@ public class LldbModelTargetProcessContainerImpl extends LldbModelTargetObjectIm LldbModelTargetProcess process = getTargetProcess(proc); changeElements(List.of(), List.of(process), Map.of(), "Added"); process.processStarted(proc); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_CREATED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_CREATED, "Process " + DebugClient.getId(proc) + " started " + process.getName(), List.of(process)); } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessImpl.java index 22e47aef99..85e2c9e6f4 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetProcessImpl.java @@ -153,7 +153,7 @@ public class LldbModelTargetProcessImpl extends LldbModelTargetObjectImpl threads.requestElements(true); StopReason stopReason = getManager().getCurrentThread().GetStopReason(); if (!stopReason.equals(StopReason.eStopReasonPlanComplete)) { - memory.requestElements(true); + memory.requestElements(true); } } } @@ -245,7 +245,7 @@ public class LldbModelTargetProcessImpl extends LldbModelTargetObjectImpl STATE_ATTRIBUTE_NAME, TargetExecutionState.TERMINATED, // EXIT_CODE_ATTRIBUTE_NAME, exitDesc // ), "Exited"); - getListeners().fire.event(getProxy(), null, TargetEventType.PROCESS_EXITED, + broadcast().event(getProxy(), null, TargetEventType.PROCESS_EXITED, "Process " + DebugClient.getId(getProcess()) + " exited code=" + exitDesc, List.of(getProxy())); } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetStackFrameRegisterBankImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetStackFrameRegisterBankImpl.java index da4b0792dc..027619f3f1 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetStackFrameRegisterBankImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetStackFrameRegisterBankImpl.java @@ -25,13 +25,11 @@ import agent.lldb.manager.LldbReason; import agent.lldb.model.iface2.LldbModelTargetRegister; import agent.lldb.model.iface2.LldbModelTargetStackFrameRegisterBank; import ghidra.async.AsyncUtils; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.error.DebuggerRegisterAccessException; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode; import ghidra.dbg.util.PathUtils; -import ghidra.util.datastruct.ListenerSet; @TargetObjectSchemaInfo( name = "RegisterValueBank", @@ -66,6 +64,7 @@ public class LldbModelTargetStackFrameRegisterBankImpl requestElements(false); } + @Override public String getDescription(int level) { SBStream stream = new SBStream(); SBValue val = (SBValue) getModelObject(); @@ -105,6 +104,7 @@ public class LldbModelTargetStackFrameRegisterBankImpl return new LldbModelTargetStackFrameRegisterImpl(this, register); } + @Override public void threadStateChangedSpecific(StateType state, LldbReason reason) { if (state.equals(StateType.eStateStopped)) { requestElements(false).thenAccept(__ -> { @@ -127,12 +127,9 @@ public class LldbModelTargetStackFrameRegisterBankImpl byte[] bytes = register.getBytes(); result.put(regname, bytes); } - ListenerSet listeners = getListeners(); - if (listeners != null) { - //if (getName().contains("General")) { - listeners.fire.registersUpdated(this, result); - //} - } + //if (getName().contains("General")) { + broadcast().registersUpdated(this, result); + //} return CompletableFuture.completedFuture(result); } @@ -149,7 +146,7 @@ public class LldbModelTargetStackFrameRegisterBankImpl BigInteger val = new BigInteger(1, ent.getValue()); reg.getRegister().SetValueFromCString(val.toString()); } - getListeners().fire.registersUpdated(getProxy(), values); + broadcast().registersUpdated(getProxy(), values); return AsyncUtils.NIL; } diff --git a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetThreadContainerImpl.java b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetThreadContainerImpl.java index ea6899aaee..f81708554a 100644 --- a/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetThreadContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-lldb/src/main/java/agent/lldb/model/impl/LldbModelTargetThreadContainerImpl.java @@ -65,7 +65,7 @@ public class LldbModelTargetThreadContainerImpl extends LldbModelTargetObjectImp changeElements(List.of(), List.of(targetThread), Map.of(), "Created"); targetThread.threadStateChangedSpecific(StateType.eStateConnected, LldbReason.getReason(null)); - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_CREATED, "Thread " + DebugClient.getId(thread) + " started", List.of(targetThread)); } @@ -81,7 +81,7 @@ public class LldbModelTargetThreadContainerImpl extends LldbModelTargetObjectImp LldbReason reason) { LldbModelTargetThread targetThread = getTargetThread(thread); TargetEventType eventType = getEventType(state, cause, reason); - getListeners().fire.event(getProxy(), targetThread, eventType, + broadcast().event(getProxy(), targetThread, eventType, "Thread " + DebugClient.getId(thread) + " state changed", List.of(targetThread)); targetThread.threadStateChangedSpecific(state, reason); } @@ -94,7 +94,7 @@ public class LldbModelTargetThreadContainerImpl extends LldbModelTargetObjectImp String threadId = LldbModelTargetThreadImpl.indexThread(thread); LldbModelTargetThread targetThread = (LldbModelTargetThread) getMapObject(thread); if (targetThread != null) { - getListeners().fire.event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(getProxy(), targetThread, TargetEventType.THREAD_EXITED, "Thread " + threadId + " exited", List.of(targetThread)); } changeElements(List.of( // diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetBreakpointSpecContainer.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetBreakpointSpecContainer.java index 7e2f22a096..6bfe39fa0d 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetBreakpointSpecContainer.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetBreakpointSpecContainer.java @@ -71,7 +71,7 @@ public interface GadpClientTargetBreakpointSpecContainer Path bptPath = evt.getEffective(); TargetBreakpointLocation breakpoint = bptPath == null ? null : getModel().getProxy(bptPath.getEList(), true).as(TargetBreakpointLocation.class); - getDelegate().getListeners().fire.breakpointHit(this, trapped, frame, spec, breakpoint); + broadcast().breakpointHit(this, trapped, frame, spec, breakpoint); if (spec instanceof GadpClientTargetBreakpointSpec) { // If I don't have a cached proxy, then I don't have any listeners GadpClientTargetBreakpointSpec specObj = (GadpClientTargetBreakpointSpec) spec; diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetEventScope.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetEventScope.java index ca19515795..afdf51f864 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetEventScope.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetEventScope.java @@ -33,6 +33,6 @@ public interface GadpClientTargetEventScope extends GadpClientTargetObject, Targ String description = evt.getDescription(); List parameters = GadpValueUtils.getValues(getModel(), evt.getParametersList()); - getDelegate().getListeners().fire.event(this, thread, type, description, parameters); + broadcast().event(this, thread, type, description, parameters); } } diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetMemory.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetMemory.java index 55ed3731cc..872b464bf8 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetMemory.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetMemory.java @@ -89,7 +89,7 @@ public interface GadpClientTargetMemory extends GadpClientTargetObject, TargetMe byte[] data = evt.getContent().toByteArray(); DelegateGadpClientTargetObject delegate = getDelegate(); delegate.getMemoryCache(address.getAddressSpace()).updateMemory(address.getOffset(), data); - delegate.getListeners().fire.memoryUpdated(this, address, data); + broadcast().memoryUpdated(this, address, data); } @GadpEventHandler(Gadp.EventNotification.EvtCase.MEMORY_ERROR_EVENT) @@ -98,7 +98,6 @@ public interface GadpClientTargetMemory extends GadpClientTargetObject, TargetMe AddressRange range = GadpValueUtils.getAddressRange(getModel(), evt.getRange()); String message = evt.getMessage(); // Errors are not cached, but recorded in trace - getDelegate().getListeners().fire.memoryReadError(this, range, - new DebuggerMemoryAccessException(message)); + broadcast().memoryReadError(this, range, new DebuggerMemoryAccessException(message)); } } diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetObject.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetObject.java index 0092235279..dcc4b3c760 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetObject.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetObject.java @@ -56,8 +56,7 @@ public interface GadpClientTargetObject extends SpiTargetObject { int channelIndex = evt.getChannel(); Channel[] allChannels = Channel.values(); if (0 <= channelIndex && channelIndex < allChannels.length) { - getDelegate().getListeners().fire.consoleOutput(this, allChannels[channelIndex], - evt.getData().toByteArray()); + broadcast().consoleOutput(this, allChannels[channelIndex], evt.getData().toByteArray()); } else { Msg.error(this, "Received output for unknown channel " + channelIndex + ": " + diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetRegisterBank.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetRegisterBank.java index 80506f56e5..e7d50b6dc8 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetRegisterBank.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetRegisterBank.java @@ -82,6 +82,6 @@ public interface GadpClientTargetRegisterBank extends GadpClientTargetObject, Ta Map updates = GadpValueUtils.getRegisterValueMap(evt.getValueList()); DelegateGadpClientTargetObject delegate = getDelegate(); delegate.getRegisterCache().putAll(updates); - delegate.getListeners().fire.registersUpdated(this, updates); + broadcast().registersUpdated(this, updates); } } diff --git a/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/GadpClientServerTest.java b/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/GadpClientServerTest.java index 921158b544..7438992dba 100644 --- a/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/GadpClientServerTest.java +++ b/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/GadpClientServerTest.java @@ -926,6 +926,9 @@ public class GadpClientServerTest implements AsyncTestUtils { @Test public void testGetAvailableWithObjectGettingListener() throws Throwable { + var l = new Object() { + TargetObject avail; + }; List invocations = new ArrayList<>(); // Any listener which calls .get on a child ref would do.... // This object-getting listener is the pattern that revealed this problem, though. @@ -933,18 +936,21 @@ public class GadpClientServerTest implements AsyncTestUtils { @Override public void elementsChanged(TargetObject parent, Collection removed, Map added) { + if (parent != l.avail) { + return; + } invocations.add(new ElementsChangedInvocation(parent, removed, added)); } }; AsynchronousSocketChannel socket = socketChannel(); try (ServerRunner runner = new ServerRunner()) { GadpClient client = new GadpClient("Test", socket); + client.addModelListener(listener); waitOn(AsyncUtils.completable(TypeSpec.VOID, socket::connect, runner.server.getLocalAddress())); waitOn(client.connect()); - TargetObject avail = waitOn(client.fetchModelObject(List.of("Available"))); - avail.addListener(listener); - Map elements = waitOn(avail.fetchElements()); + l.avail = waitOn(client.fetchModelObject(List.of("Available"))); + Map elements = waitOn(l.avail.fetchElements()); Msg.debug(this, "Elements: " + elements); waitOn(client.close()); } @@ -957,13 +963,18 @@ public class GadpClientServerTest implements AsyncTestUtils { public void testFocus() throws Throwable { // Interesting because it involves a non-object-valued attribute (link) // Need to check callback as well as getAttributes - + var l = new Object() { + TargetObject session; + }; CompletableFuture> focusPath = new CompletableFuture<>(); AtomicBoolean failed = new AtomicBoolean(); DebuggerModelListener focusListener = new AnnotatedDebuggerAttributeListener(MethodHandles.lookup()) { @AttributeCallback(TargetFocusScope.FOCUS_ATTRIBUTE_NAME) public void focusChanged(TargetObject object, TargetObject focused) { + if (object != l.session) { + return; + } Msg.info(this, "Focus changed to " + focused); if (!focusPath.complete(focused.getPath())) { failed.set(true); @@ -976,8 +987,7 @@ public class GadpClientServerTest implements AsyncTestUtils { waitOn(AsyncUtils.completable(TypeSpec.VOID, socket::connect, runner.server.getLocalAddress())); waitOn(client.connect()); - TargetObject session = waitOn(client.fetchModelObject(List.of())); - session.addListener(focusListener); + l.session = waitOn(client.fetchModelObject(List.of())); TargetObject procCont = waitOn(client.fetchModelObject(List.of("Processes"))); assertTrue(procCont.getInterfaceNames().contains("Launcher")); TargetLauncher launcher = procCont.as(TargetLauncher.class); @@ -1017,7 +1027,19 @@ public class GadpClientServerTest implements AsyncTestUtils { @Test public void testSubscribeLaunchForChildrenChanged() throws Throwable { - ElementsChangedListener elemL = new ElementsChangedListener(); + var l = new Object() { + TargetObject procContainer; + }; + ElementsChangedListener elemL = new ElementsChangedListener() { + @Override + public void elementsChanged(TargetObject parent, Collection removed, + Map added) { + if (parent != l.procContainer) { + return; + } + super.elementsChanged(parent, removed, added); + } + }; AsynchronousSocketChannel socket = socketChannel(); try (ServerRunner runner = new ServerRunner()) { @@ -1026,10 +1048,9 @@ public class GadpClientServerTest implements AsyncTestUtils { waitOn(AsyncUtils.completable(TypeSpec.VOID, socket::connect, runner.server.getLocalAddress())); waitOn(client.connect()); - TargetObject procContainer = waitOn(client.fetchModelObject(List.of("Processes"))); - assertTrue(procContainer.getInterfaceNames().contains("Launcher")); - procContainer.addListener(elemL); - TargetLauncher launcher = procContainer.as(TargetLauncher.class); + l.procContainer = waitOn(client.fetchModelObject(List.of("Processes"))); + assertTrue(l.procContainer.getInterfaceNames().contains("Launcher")); + TargetLauncher launcher = l.procContainer.as(TargetLauncher.class); waitOn(launcher.launch( Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, "/bin/echo Hello, World!"))); waitOn(elemL.count.waitValue(1)); @@ -1038,7 +1059,7 @@ public class GadpClientServerTest implements AsyncTestUtils { assertEquals(1, elemL.invocations.size()); ElementsChangedInvocation eci = elemL.invocations.get(0); - assertEquals(procContainer, eci.parent); + assertEquals(l.procContainer, eci.parent); assertEquals(List.of(), List.copyOf(eci.removed)); assertEquals(1, eci.added.size()); Entry ent = eci.added.entrySet().iterator().next(); @@ -1107,20 +1128,31 @@ public class GadpClientServerTest implements AsyncTestUtils { @Test public void testReplaceAttribute() throws Throwable { - AttributesChangedListener attrL = new AttributesChangedListener(); + var l = new Object() { + TargetObject echoAvail; + }; + AttributesChangedListener attrL = new AttributesChangedListener() { + @Override + public void attributesChanged(TargetObject parent, Collection removed, + Map added) { + if (parent != l.echoAvail) { + return; + } + super.attributesChanged(parent, removed, added); + } + }; try (AsynchronousSocketChannel socket = socketChannel(); ServerRunner runner = new ServerRunner()) { GadpClient client = new GadpClient("Test", socket); + client.addModelListener(attrL); waitOn(AsyncUtils.completable(TypeSpec.VOID, socket::connect, runner.server.getLocalAddress())); waitOn(client.connect()); - TargetObject echoAvail = - waitOn(client.fetchModelObject(PathUtils.parse("Available[1]"))); - echoAvail.addListener(attrL); + l.echoAvail = waitOn(client.fetchModelObject(PathUtils.parse("Available[1]"))); assertEquals(Map.ofEntries(Map.entry("pid", 1), Map.entry("cmd", "echo"), - Map.entry("_display", "[1]")), waitOn(echoAvail.fetchAttributes())); + Map.entry("_display", "[1]")), waitOn(l.echoAvail.fetchAttributes())); TestGadpTargetAvailable ssEchoAvail = runner.server.model.session.available.getCachedElements().get("1"); @@ -1132,10 +1164,10 @@ public class GadpClientServerTest implements AsyncTestUtils { waitOn(attrL.count.waitValue(1)); assertEquals(Map.ofEntries(Map.entry("cmd", "echo"), Map.entry("args", "Hello, World!"), - Map.entry("_display", "[1]")), echoAvail.getCachedAttributes()); + Map.entry("_display", "[1]")), l.echoAvail.getCachedAttributes()); AttributesChangedInvocation changed = Unique.assertOne(attrL.invocations); - assertSame(echoAvail, changed.parent); + assertSame(l.echoAvail, changed.parent); assertEquals(Set.of("pid"), Set.copyOf(changed.removed)); assertEquals(Map.ofEntries(Map.entry("args", "Hello, World!")), changed.added); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetClassContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetClassContainer.java index 2ba22fb6eb..6bbe627932 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetClassContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetClassContainer.java @@ -22,7 +22,6 @@ import java.util.stream.Collectors; import com.sun.jdi.ReferenceType; import ghidra.async.AsyncFence; -import ghidra.async.AsyncUtils; import ghidra.dbg.target.schema.*; import ghidra.util.Msg; @@ -90,9 +89,6 @@ public class JdiModelTargetClassContainer extends JdiModelTargetObjectImpl { } public CompletableFuture refreshInternal() { - if (!isObserved()) { - return AsyncUtils.NIL; - } return doRefresh().exceptionally(ex -> { Msg.error(this, "Problem refreshing vm's classes", ex); return null; diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnectorContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnectorContainer.java index 41b4a27657..a355f45b9b 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnectorContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnectorContainer.java @@ -23,7 +23,6 @@ import com.sun.jdi.VirtualMachineManager; import com.sun.jdi.connect.Connector; import ghidra.async.AsyncFence; -import ghidra.async.AsyncUtils; import ghidra.dbg.target.schema.*; import ghidra.util.Msg; @@ -96,9 +95,6 @@ public class JdiModelTargetConnectorContainer extends JdiModelTargetObjectImpl { } public CompletableFuture refreshInternal() { - if (!isObserved()) { - return AsyncUtils.NIL; - } return doRefresh().exceptionally(ex -> { Msg.error(this, "Problem refreshing inferior's modules", ex); return null; diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetModuleContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetModuleContainer.java index 307e4637c7..7638084452 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetModuleContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetModuleContainer.java @@ -22,7 +22,6 @@ import java.util.stream.Collectors; import com.sun.jdi.ModuleReference; import ghidra.async.AsyncFence; -import ghidra.async.AsyncUtils; import ghidra.dbg.error.DebuggerUserException; import ghidra.dbg.target.TargetModule; import ghidra.dbg.target.TargetModuleContainer; @@ -136,9 +135,6 @@ public class JdiModelTargetModuleContainer extends JdiModelTargetObjectImpl } public CompletableFuture refreshInternal() { - if (!isObserved()) { - return AsyncUtils.NIL; - } return doRefresh().exceptionally(ex -> { Msg.error(this, "Problem refreshing inferior's modules", ex); return null; diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetProcess.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetProcess.java index aecc8e598b..9fa60f265d 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetProcess.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetProcess.java @@ -106,7 +106,7 @@ public class JdiModelTargetProcess extends JdiModelTargetObjectImpl default: throw new AssertionError(); } - listeners.fire.consoleOutput(this, channel, out); + broadcast().consoleOutput(this, channel, out); } private void readStream(InputStream in, TargetConsole.Channel channel) { diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetRegisterContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetRegisterContainer.java index 062562707d..aa7a67f63f 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetRegisterContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetRegisterContainer.java @@ -20,7 +20,6 @@ import java.util.concurrent.CompletableFuture; import com.sun.jdi.Location; -import ghidra.async.AsyncUtils; import ghidra.dbg.target.TargetRegisterBank; import ghidra.dbg.target.TargetRegisterContainer; import ghidra.dbg.target.schema.*; @@ -121,7 +120,7 @@ public class JdiModelTargetRegisterContainer extends JdiModelTargetObjectImpl map.put(retAddr.getIndex(), bytes); } if (!map.isEmpty()) { - listeners.fire.registersUpdated(this, map); + broadcast().registersUpdated(this, map); } return CompletableFuture.completedFuture(map); } @@ -133,13 +132,10 @@ public class JdiModelTargetRegisterContainer extends JdiModelTargetObjectImpl } public void invalidateRegisterCaches() { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } protected CompletableFuture update() { - if (!isObserved()) { - return AsyncUtils.NIL; - } return fetchElements(true).exceptionally(e -> { Msg.error(this, "Could not update registers " + this + " on STOPPED"); return null; diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetSectionContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetSectionContainer.java index 74ef0a3d8c..fa64bcfc69 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetSectionContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetSectionContainer.java @@ -125,12 +125,12 @@ public class JdiModelTargetSectionContainer extends JdiModelTargetObjectImpl bytes[i] = (byte) 0xFF; } } - listeners.fire.memoryUpdated(this, address, bytes); + broadcast().memoryUpdated(this, address, bytes); return CompletableFuture.completedFuture(bytes); } if (addressSpace.equals(impl.getAddressSpace("constantPool"))) { byte[] bytes = constantPool.getPool(); - listeners.fire.memoryUpdated(this, address, bytes); + broadcast().memoryUpdated(this, address, bytes); return CompletableFuture.completedFuture(bytes); } throw new RuntimeException(); diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStack.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStack.java index f982fe0954..16440ec731 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStack.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStack.java @@ -20,7 +20,6 @@ import java.util.concurrent.CompletableFuture; import com.sun.jdi.*; -import ghidra.async.AsyncUtils; import ghidra.dbg.target.TargetStack; import ghidra.dbg.target.schema.*; import ghidra.util.Msg; @@ -104,9 +103,6 @@ public class JdiModelTargetStack extends JdiModelTargetObjectImpl * @return null */ protected CompletableFuture update() { - if (!isObserved()) { - return AsyncUtils.NIL; - } return fetchElements(true).exceptionally(e -> { Msg.error(this, "Could not update stack " + this + " on STOPPED"); return null; @@ -114,6 +110,6 @@ public class JdiModelTargetStack extends JdiModelTargetObjectImpl } public void invalidateRegisterCaches() { - listeners.fire.invalidateCacheRequested(this); + broadcast().invalidateCacheRequested(this); } } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThreadContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThreadContainer.java index 6e0ac65f02..835c2a5720 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThreadContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThreadContainer.java @@ -77,7 +77,7 @@ public class JdiModelTargetThreadContainer extends JdiModelTargetObjectImpl TargetExecutionState targetState = targetThread.convertState(state); targetThread.threadStateChanged(targetState); TargetEventType eventType = getEventType(reason); - getListeners().fire.event(this, targetThread, eventType, + broadcast().event(this, targetThread, eventType, "Thread " + targetThread.getName() + " state changed", List.of(targetThread)); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVMContainer.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVMContainer.java index fe65e56ff8..89ec15229a 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVMContainer.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVMContainer.java @@ -31,11 +31,15 @@ import ghidra.dbg.target.schema.*; import ghidra.util.Msg; import ghidra.util.datastruct.WeakValueHashMap; -@TargetObjectSchemaInfo(name = "VMContainer", elements = { // - @TargetElementType(type = JdiModelTargetVM.class) // -}, attributes = { // - @TargetAttributeType(type = Void.class) // -}, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "VMContainer", + elements = { // + @TargetElementType(type = JdiModelTargetVM.class) // + }, + attributes = { // + @TargetAttributeType(type = Void.class) // + }, + canonicalContainer = true) public class JdiModelTargetVMContainer extends JdiModelTargetObjectImpl implements JdiEventsListenerAdapter { @@ -56,7 +60,7 @@ public class JdiModelTargetVMContainer extends JdiModelTargetObjectImpl // TODO: Move PROCESS_CREATED here to restore proper order of event reporting // Pending some client-side changes to handle architecture selection, though. target.started(vm.name()).thenAccept(__ -> { - session.getListeners().fire.event(session, null, TargetEventType.PROCESS_CREATED, + broadcast().event(session, null, TargetEventType.PROCESS_CREATED, "VM " + vm.name() + " started " + vm.process() + " pid=" + vm.name(), List.of(vm)); }).exceptionally(ex -> { Msg.error(this, "Could not notify vm started", ex); @@ -70,8 +74,8 @@ public class JdiModelTargetVMContainer extends JdiModelTargetObjectImpl public void vmDied(VMDeathEvent event, JdiCause cause) { VirtualMachine vm = event.virtualMachine(); JdiModelTargetVM tgtVM = vmsById.get(vm.name()); - session.getListeners().fire.event(session, null, TargetEventType.PROCESS_EXITED, - "VM " + vm.name(), List.of(tgtVM)); + broadcast().event(session, null, TargetEventType.PROCESS_EXITED, "VM " + vm.name(), + List.of(tgtVM)); tgtVM.exited(vm); synchronized (this) { vmsById.remove(vm.name()); @@ -99,7 +103,7 @@ public class JdiModelTargetVMContainer extends JdiModelTargetObjectImpl return; } JdiModelTargetThread targetThread = vm.threads.threadCreated(thread); - session.getListeners().fire.event(session, targetThread, TargetEventType.THREAD_CREATED, + broadcast().event(session, targetThread, TargetEventType.THREAD_CREATED, "Thread " + thread.name() + " started", List.of(targetThread)); } @@ -108,7 +112,7 @@ public class JdiModelTargetVMContainer extends JdiModelTargetObjectImpl ThreadReference thread = event.thread(); JdiModelTargetVM tgtVM = vmsById.get(thread.virtualMachine().name()); JdiModelTargetThread targetThread = tgtVM.threads.threadsById.get(thread.name()); - session.getListeners().fire.event(session, targetThread, TargetEventType.THREAD_EXITED, + broadcast().event(session, targetThread, TargetEventType.THREAD_EXITED, "Thread " + thread.name() + " exited", List.of(targetThread)); tgtVM.threads.threadExited(thread); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface2/JdiModelTargetObject.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface2/JdiModelTargetObject.java index 708cce55fc..2db1e5ecbe 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface2/JdiModelTargetObject.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface2/JdiModelTargetObject.java @@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture; import com.sun.jdi.*; -import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.agent.InvalidatableTargetObjectIf; import ghidra.dbg.jdi.manager.JdiManager; import ghidra.dbg.jdi.model.*; @@ -30,7 +29,6 @@ import ghidra.dbg.target.schema.EnumerableTargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName; import ghidra.dbg.util.CollectionUtils.Delta; -import ghidra.util.datastruct.ListenerSet; public interface JdiModelTargetObject extends TargetObject, InvalidatableTargetObjectIf { @@ -56,8 +54,6 @@ public interface JdiModelTargetObject extends TargetObject, InvalidatableTargetO public Delta changeAttributes(List remove, Map add, String reason); - public ListenerSet getListeners(); - public default JdiModelTargetObject getInstance(Mirror object) { JdiModelTargetObject targetObject = getTargetObject(object); if (targetObject == null) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java index 46908e939a..2c928fe299 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java @@ -53,7 +53,10 @@ public abstract class AbstractDebuggerWrappedConsoleConnection { - if (object == targetConsole) { // Redundant - consoleInvalidated(); - } + consoleInvalidated(); }); } } @@ -131,7 +141,7 @@ public abstract class AbstractDebuggerWrappedConsoleConnection sendLine(String line); @@ -188,7 +198,7 @@ public abstract class AbstractDebuggerWrappedConsoleConnection copy; - synchronized (proxies) { - copy = List.copyOf(proxies); - } - for (DebuggerModelServiceProxyPlugin proxy : copy) { - proxy.fireFocusEvent(focused); - } - } - }; - - protected ListenersForRemovalAndFocus(DebuggerObjectModel model) { - this.model = model; } - protected CompletableFuture init() { - return model.fetchModelRoot().thenCompose(r -> { - synchronized (this) { - this.root = r; - } - boolean isInvalid = false; - try { - r.addListener(this.forRemoval); - } - catch (IllegalStateException e) { - isInvalid = true; - } - isInvalid |= !r.isValid(); - if (isInvalid) { - forRemoval.invalidated(root, root, "Who knows?"); - } - CompletableFuture findSuitable = - DebugModelConventions.findSuitable(TargetFocusScope.class, r); - return findSuitable; - }).thenAccept(fs -> { - synchronized (this) { - this.focusScope = fs; - } - if (fs != null) { - fs.addListener(this.forFocus); - } - }); - } - - public void dispose() { - TargetObject savedRoot; - TargetFocusScope savedFocusScope; - synchronized (this) { - savedRoot = root; - savedFocusScope = focusScope; + @AttributeCallback(TargetFocusScope.FOCUS_ATTRIBUTE_NAME) + public void focusChanged(TargetObject object, TargetObject focused) { + // I don't think I care which scope + fireFocusEvent(focused); + List copy; + synchronized (proxies) { + copy = List.copyOf(proxies); } - if (savedRoot != null) { - savedRoot.removeListener(this.forRemoval); - } - if (savedFocusScope != null) { - savedFocusScope.removeListener(this.forFocus); + for (DebuggerModelServiceProxyPlugin proxy : copy) { + proxy.fireFocusEvent(focused); } } - } + }; protected class ListenerOnRecorders implements TraceRecorderListener { @Override @@ -195,8 +145,11 @@ public class DebuggerModelServicePlugin extends Plugin protected final Set factories = new HashSet<>(); // Keep strong references to my listeners, or they'll get torched - protected final Map listenersByModel = - new LinkedHashMap<>(); + //protected final Map listenersByModel = + //new LinkedHashMap<>(); + protected final Set models = new LinkedHashSet<>(); + protected final ForRemovalAndFocusListener forRemovalAndFocusListener = + new ForRemovalAndFocusListener(); protected final Map recordersByTarget = new WeakHashMap<>(); protected final ListenerSet> factoryListeners = @@ -262,8 +215,8 @@ public class DebuggerModelServicePlugin extends Plugin @Override public Set getModels() { - synchronized (listenersByModel) { - return Set.copyOf(listenersByModel.keySet()); + synchronized (models) { + return Set.copyOf(models); } } @@ -286,20 +239,16 @@ public class DebuggerModelServicePlugin extends Plugin @Override public boolean addModel(DebuggerObjectModel model) { Objects.requireNonNull(model); - synchronized (listenersByModel) { - if (listenersByModel.containsKey(model)) { + synchronized (models) { + if (models.contains(model)) { return false; } - ListenersForRemovalAndFocus listener = new ListenersForRemovalAndFocus(model); - listener.init().exceptionally(e -> { - Msg.error(this, "Could not add model " + model, e); - synchronized (listenersByModel) { - listenersByModel.remove(model); - listener.dispose(); - } - return null; - }); - listenersByModel.put(model, listener); + model.addModelListener(forRemovalAndFocusListener); + TargetObject root = model.getModelRoot(); + if (!root.isValid()) { + forRemovalAndFocusListener.invalidated(root, root, + "Invalidated before or during add to service"); + } } modelListeners.fire.elementAdded(model); return true; @@ -307,14 +256,12 @@ public class DebuggerModelServicePlugin extends Plugin @Override public boolean removeModel(DebuggerObjectModel model) { - ListenersForRemovalAndFocus listener; - synchronized (listenersByModel) { - listener = listenersByModel.remove(model); - if (listener == null) { + model.removeModelListener(forRemovalAndFocusListener); + synchronized (models) { + if (!models.remove(model)) { return false; } } - listener.dispose(); modelListeners.fire.elementRemoved(model); return true; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java deleted file mode 100644 index 2ec9b0c743..0000000000 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java +++ /dev/null @@ -1,251 +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.service.model; - -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.CompletableFuture; -import java.util.function.Predicate; - -import ghidra.app.plugin.core.debug.mapping.DebuggerMemoryMapper; -import ghidra.app.plugin.core.debug.service.model.interfaces.AbstractRecorderMemory; -import ghidra.async.AsyncLazyMap; -import ghidra.async.AsyncUtils; -import ghidra.dbg.DebugModelConventions; -import ghidra.dbg.DebugModelConventions.AllRequiredAccess; -import ghidra.dbg.target.*; -import ghidra.program.model.address.*; -import ghidra.util.Msg; -import ghidra.util.TriConsumer; -import ghidra.util.datastruct.ListenerSet; - -public class RecorderComposedMemory implements AbstractRecorderMemory { - - private static final int BLOCK_SIZE = 4096; - private static final long BLOCK_MASK = -1L << 12; - - protected final RecorderComposedMemory chain; - - protected final NavigableMap byMin = new TreeMap<>(); - - protected final Map byRegion = new HashMap<>(); - protected final AsyncLazyMap accessibilityByMemory = - new AsyncLazyMap<>(new HashMap<>(), this::fetchMemAccessibility) { - public AllRequiredAccess remove(TargetMemory key) { - AllRequiredAccess acc = super.remove(key); - if (acc != null) { - acc.removeChangeListener(getMemAccListeners().fire); - } - return acc; - } - }; - - protected CompletableFuture fetchMemAccessibility(TargetMemory mem) { - return DebugModelConventions.trackAccessibility(mem).thenApply(acc -> { - acc.addChangeListener(getMemAccListeners().fire); - return acc; - }); - } - - /** - * Get accessible memory, as viewed in the trace - * - * @param pred an additional predicate applied via "AND" with accessibility - * @param memMapper target-to-trace mapping utility - * @return the computed set - */ - @Override - public AddressSet getAccessibleMemory(Predicate pred, - DebuggerMemoryMapper memMapper) { - synchronized (accessibilityByMemory) { - // TODO: Might accomplish by using listeners and tracking the accessible set - AddressSet accessible = new AddressSet(); - for (Entry ent : byRegion.entrySet()) { - TargetMemory mem = ent.getValue(); - if (!pred.test(mem)) { - continue; - } - AllRequiredAccess acc = accessibilityByMemory.getCompletedMap().get(mem); - if (acc == null || !acc.getAllAccessibility()) { - continue; - } - AddressRange traceRange = memMapper.targetToTraceTruncated(ent.getKey().getRange()); - if (traceRange == null) { - continue; - } - accessible.add(traceRange); - } - return accessible; - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private final ListenerSet> memAccListeners = - new ListenerSet(TriConsumer.class); - - public RecorderComposedMemory(AbstractRecorderMemory memory) { - this.chain = (RecorderComposedMemory) memory; - } - - protected TargetMemory getMemory(Address address, int length) { - Entry floor = findChainedFloor(address); - if (floor == null) { - throw new IllegalArgumentException( - "address " + address + " is not in any known region"); - } - Address max; - try { - max = address.addNoWrap(length - 1); - } - catch (AddressOverflowException e) { - throw new IllegalArgumentException("read extends beyond the address space"); - } - if (!floor.getValue().getRange().contains(max)) { - throw new IllegalArgumentException("read extends beyond a single region"); - } - return byRegion.get(floor.getValue()); - } - - @Override - public void addMemory(TargetMemory memory) { - // Do nothing - // This delegates by region, so need regions even if I have memory - } - - @Override - public void addRegion(TargetMemoryRegion region, TargetMemory memory) { - synchronized (accessibilityByMemory) { - TargetMemory old = byRegion.put(region, memory); - assert old == null; - byMin.put(region.getRange().getMinAddress(), region); - accessibilityByMemory.get(memory).exceptionally(e -> { - e = AsyncUtils.unwrapThrowable(e); - Msg.error(this, "Could not track memory accessibility: " + e.getMessage()); - return null; - }); - } - } - - @Override - public void removeMemory(TargetMemory invalid) { - // Do nothing - } - - @Override - public boolean removeRegion(TargetObject invalid) { - if (!(invalid instanceof TargetMemoryRegion)) { - return false; - } - synchronized (accessibilityByMemory) { - TargetMemoryRegion invRegion = (TargetMemoryRegion) invalid; - TargetMemory old = byRegion.remove(invRegion); - assert old != null; - byMin.remove(invRegion.getRange().getMinAddress()); - if (!old.isValid() || !byRegion.containsValue(old)) { - accessibilityByMemory.remove(old); - } - return true; - } - } - - /* - protected AllRequiredAccess findChainedMemoryAccess(TargetMemoryRegion region) { - synchronized (accessibilityByMemory) { - TargetMemory mem = byRegion.get(region); - if (mem != null) { - return accessibilityByMemory.getCompletedMap().get(mem); - } - return chain == null ? null : chain.findChainedMemoryAccess(region); - } - } - */ - - public Entry findChainedFloor(Address address) { - synchronized (accessibilityByMemory) { - Entry myFloor = byMin.floorEntry(address); - Entry byChain = - chain == null ? null : chain.findChainedFloor(address); - if (byChain == null) { - return myFloor; - } - if (myFloor == null) { - return byChain; - } - int c = myFloor.getKey().compareTo(byChain.getKey()); - if (c < 0) { - return byChain; - } - return myFloor; - } - } - - protected AddressRange align(Address address, int length) { - AddressSpace space = address.getAddressSpace(); - long offset = address.getOffset(); - Address start = space.getAddress(offset & BLOCK_MASK); - Address end = space.getAddress(((offset + length - 1) & BLOCK_MASK) + BLOCK_SIZE - 1); - return new AddressRangeImpl(start, end); - } - - protected AddressRange alignWithLimit(Address address, int length, - TargetMemoryRegion limit) { - return align(address, length).intersect(limit.getRange()); - } - - @Override - public AddressRange alignAndLimitToFloor(Address address, int length) { - Entry floor = findChainedFloor(address); - if (floor == null) { - return null; - } - return alignWithLimit(address, length, floor.getValue()); - } - - public AddressRange alignWithOptionalLimit(Address address, int length, - TargetMemoryRegion limit) { - if (limit == null) { - return alignAndLimitToFloor(address, length); - } - return alignWithLimit(address, length, limit); - } - - @Override - public CompletableFuture readMemory(Address address, int length) { - synchronized (accessibilityByMemory) { - TargetMemory mem = getMemory(address, length); - if (mem != null) { - return mem.readMemory(address, length); - } - return CompletableFuture.completedFuture(new byte[0]); - } - } - - @Override - public CompletableFuture writeMemory(Address address, byte[] data) { - synchronized (accessibilityByMemory) { - TargetMemory mem = getMemory(address, data.length); - if (mem != null) { - return mem.writeMemory(address, data); - } - throw new IllegalArgumentException("read starts outside any address space"); - } - } - - public ListenerSet> getMemAccListeners() { - return memAccListeners; - } - -} diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedRegisterSet.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedRegisterSet.java deleted file mode 100644 index c1a2e72736..0000000000 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedRegisterSet.java +++ /dev/null @@ -1,107 +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.service.model; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import ghidra.async.AsyncLazyMap; -import ghidra.async.AsyncLazyMap.KeyedFuture; -import ghidra.async.AsyncUtils; -import ghidra.dbg.DebugModelConventions; -import ghidra.dbg.DebugModelConventions.AllRequiredAccess; -import ghidra.dbg.target.TargetObject; -import ghidra.dbg.target.TargetRegisterBank; -import ghidra.util.Msg; -import ghidra.util.TriConsumer; - -public class RecorderComposedRegisterSet { - - private DefaultTraceRecorder recorder; - - protected final TriConsumer listenerRegAccChanged = - this::registerAccessibilityChanged; - - protected void registerAccessibilityChanged(boolean old, boolean acc, - Void __) { - recorder.getListeners().fire.registerAccessibilityChanged(recorder); - } - - protected final AsyncLazyMap accessibilityByRegBank = - new AsyncLazyMap<>(new HashMap<>(), this::fetchRegAccessibility) { - public AllRequiredAccess remove(TargetRegisterBank key) { - AllRequiredAccess acc = super.remove(key); - if (acc != null) { - acc.removeChangeListener(listenerRegAccChanged); - } - return acc; - } - }; - - protected CompletableFuture fetchRegAccessibility( - TargetRegisterBank bank) { - return DebugModelConventions.trackAccessibility(bank).thenApply(acc -> { - acc.addChangeListener(listenerRegAccChanged); - return acc; - }); - } - - public RecorderComposedRegisterSet(DefaultTraceRecorder recorder) { - this.recorder = recorder; - } - - public void updateRegisters(TargetRegisterBank newRegs, TargetRegisterBank oldRegs) { - synchronized (accessibilityByRegBank) { - if (oldRegs != null) { - accessibilityByRegBank.remove(oldRegs); - } - accessibilityByRegBank.get(newRegs).exceptionally(e -> { - e = AsyncUtils.unwrapThrowable(e); - Msg.error(this, "Could not track register accessibility: " + e.getMessage()); - return null; - }); - } - } - - public boolean checkRegistersRemoved(Map regs, - TargetObject invalid) { - synchronized (accessibilityByRegBank) { - if (regs.values().remove(invalid)) { - accessibilityByRegBank.remove((TargetRegisterBank) invalid); - return true; - } - return false; - } - } - - public boolean isRegisterBankAccessible(TargetRegisterBank bank) { - if (bank == null) { - return false; - } - synchronized (accessibilityByRegBank) { - KeyedFuture future = accessibilityByRegBank.get(bank); - if (future == null) { - return false; - } - AllRequiredAccess acc = future.getNow(null); - if (acc == null) { - return false; - } - return acc.get(); - } - } -} diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebugModelConventions.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebugModelConventions.java index 9cc5f3f3c6..991bbb3bcc 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebugModelConventions.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebugModelConventions.java @@ -15,9 +15,7 @@ */ package ghidra.dbg; -import java.lang.invoke.MethodHandles; import java.util.*; -import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -457,281 +455,6 @@ public enum DebugModelConventions { return isProcessAlive(process) ? process : null; } - /** - * A convenience for listening to selected portions (possible all) of a sub-tree of a model - */ - public abstract static class SubTreeListenerAdapter extends AnnotatedDebuggerAttributeListener { - protected boolean disposed = false; - protected final NavigableMap, TargetObject> objects = - new TreeMap<>(PathComparator.KEYED); - - public SubTreeListenerAdapter() { - super(MethodHandles.lookup()); - } - - /** - * An object has been removed from the sub-tree - * - * @param removed the removed object - */ - protected abstract void objectRemoved(TargetObject removed); - - /** - * An object has been added to the sub-tree - * - * @param added the added object - */ - protected abstract void objectAdded(TargetObject added); - - /** - * Decide whether a sub-tree (of the sub-tree) should be tracked - * - * @param obj the root of the sub-tree to consider - * @return false to ignore, true to track - */ - protected abstract boolean checkDescend(TargetObject obj); - - @Override - public void invalidated(TargetObject object, TargetObject branch, String reason) { - runNotInSwing(this, () -> doInvalidated(object, reason), "invalidated"); - } - - private void doInvalidated(TargetObject object, String reason) { - List removed = new ArrayList<>(); - synchronized (objects) { - if (disposed) { - return; - } - /** - * NOTE: Can't use iteration, because subtrees will also remove stuff, causing - * ConcurrentModificationException, even if removal is via the iterator... - */ - List path = object.getPath(); - while (true) { - Entry, TargetObject> ent = objects.ceilingEntry(path); - if (ent == null || !PathUtils.isAncestor(path, ent.getKey())) { - break; - } - objects.remove(ent.getKey()); - TargetObject succ = ent.getValue(); - succ.removeListener(this); - removed.add(succ); - } - } - for (TargetObject r : removed) { - objectRemovedSafe(r); - } - } - - private void objectRemovedSafe(TargetObject removed) { - try { - objectRemoved(removed); - } - catch (Throwable t) { - Msg.error(this, "Error in callback", t); - } - } - - private void objectAddedSafe(TargetObject obj) { - try { - objectAdded(obj); - } - catch (Throwable t) { - Msg.error(this, "Error in callback", t); - } - } - - private void considerObj(TargetObject obj) { - if (!checkDescend(obj)) { - return; - } - CompletableFuture.runAsync(() -> addListenerAndConsiderSuccessors(obj)) - .exceptionally(ex -> { - Msg.error(this, "Could add to object: " + obj, ex); - return null; - }); - } - - private void considerElements(TargetObject parent, - Map elements) { - synchronized (objects) { - if (disposed) { - return; - } - if (!objects.containsKey(parent.getPath())) { - return; - } - } - for (TargetObject e : elements.values()) { - considerObj(e); - } - } - - protected void considerAttributes(TargetObject obj, Map attributes) { - synchronized (objects) { - if (disposed) { - return; - } - if (!objects.containsKey(obj.getPath())) { - return; - } - } - for (Map.Entry ent : attributes.entrySet()) { - String name = ent.getKey(); - Object val = ent.getValue(); - if (!(val instanceof TargetObject)) { - continue; - } - TargetObject a = (TargetObject) val; - if (PathUtils.isLink(obj.getPath(), name, a.getPath())) { - continue; - } - considerObj(a); - } - } - - /** - * Track a specified object, without initially adding the sub-tree - * - *

- * Note that {@link #checkDescend(TargetObject)} must also exclude the sub-tree, otherwise - * children added later will be tracked. - * - * @param obj the object to track - * @return true if the object was not already being listened to - */ - public boolean addListener(TargetObject obj) { - if (obj == null) { - return false; - } - obj.addListener(this); - synchronized (objects) { - if (objects.put(obj.getPath(), obj) == obj) { - return false; - } - } - objectAddedSafe(obj); - return true; - } - - /** - * Add a specified sub-tree to this listener - * - * @param obj - * @return true if the object was not already being listened to - */ - public boolean addListenerAndConsiderSuccessors(TargetObject obj) { - boolean result = addListener(obj); - if (result && checkDescend(obj)) { - obj.fetchElements() - .thenAcceptAsync(elems -> considerElements(obj, elems)) - .exceptionally(ex -> { - Msg.error(this, "Could not fetch elements of obj: " + obj, ex); - return null; - }); - obj.fetchAttributes() - .thenAcceptAsync(attrs -> considerAttributes(obj, attrs)) - .exceptionally(ex -> { - Msg.error(this, "Could not fetch attributes of obj: " + obj, ex); - return null; - }); - } - return result; - } - - @Override - public void elementsChanged(TargetObject parent, Collection removed, - Map added) { - runNotInSwing(this, () -> doElementsChanged(parent, removed, added), "elementsChanged"); - } - - private void doElementsChanged(TargetObject parent, Collection removed, - Map added) { - if (checkDescend(parent)) { - considerElements(parent, added); - } - } - - @Override - public void attributesChanged(TargetObject parent, Collection removed, - Map added) { - runNotInSwing(this, () -> doAttributesChanged(parent, removed, added), - "attributesChanged"); - } - - private void doAttributesChanged(TargetObject parent, Collection removed, - Map added) { - if (checkDescend(parent)) { - considerAttributes(parent, added); - } - } - - /** - * Dispose of this sub-tree tracker/listener - * - *

- * This uninstalls the listener from every tracked object and clears its collection of - * tracked objects. - */ - public void dispose() { - synchronized (objects) { - disposed = true; - for (Iterator it = objects.values().iterator(); it.hasNext();) { - TargetObject obj = it.next(); - obj.removeListener(this); - it.remove(); - } - } - } - } - - /** - * A variable that is updated whenever access changes according to the (now deprecated) - * "every-ancestor" convention. - * - * @deprecated The "every-ancestor" thing doesn't add any flexibility to model implementations. - * It might even restrict it. Not to mention it's obtuse to implement. - */ - @Deprecated(forRemoval = true) - public static class AllRequiredAccess extends AsyncReference { - protected class ListenerForAccess extends AnnotatedDebuggerAttributeListener { - protected final TargetAccessConditioned access; - private boolean accessible; - - public ListenerForAccess(TargetAccessConditioned access) { - super(MethodHandles.lookup()); - this.access = access; - this.access.addListener(this); - this.accessible = access.isAccessible(); - } - - @AttributeCallback(TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME) - public void accessibilityChanged(TargetObject object, boolean accessibility) { - //Msg.debug(this, "Obj " + object + " has become " + accessibility); - synchronized (AllRequiredAccess.this) { - this.accessible = accessibility; - // Check that all requests have been issued (fence is ready) - if (listeners != null) { - set(getAllAccessibility(), null); - } - } - } - } - - protected final List listeners; - protected final AsyncFence initFence = new AsyncFence(); - - public AllRequiredAccess(Collection allReq) { - Msg.debug(this, "Listening for access on: " + allReq); - listeners = allReq.stream().map(ListenerForAccess::new).collect(Collectors.toList()); - set(getAllAccessibility(), null); - } - - public boolean getAllAccessibility() { - return listeners.stream().allMatch(l -> l.accessible); - } - } - public static class AsyncAttribute extends AsyncReference implements DebuggerModelListener { private final TargetObject obj; @@ -741,7 +464,7 @@ public enum DebugModelConventions { public AsyncAttribute(TargetObject obj, String name) { this.name = name; this.obj = obj; - obj.addListener(this); + 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); @@ -753,6 +476,9 @@ public enum DebugModelConventions { @SuppressWarnings("unchecked") public void attributesChanged(TargetObject parent, Collection removed, Map added) { + if (parent != obj) { + return; + } if (added.containsKey(name)) { set((T) added.get(name), null); } @@ -768,7 +494,7 @@ public enum DebugModelConventions { @Override public void dispose(Throwable reason) { super.dispose(reason); - obj.removeListener(this); + obj.getModel().removeModelListener(this); } } @@ -784,34 +510,6 @@ public enum DebugModelConventions { } } - /** - * Obtain an object which tracks accessibility for a given target object. - * - *

- * Recall that for an object to be considered accessible, it and its ancestors must all be - * accessible. Objects without the {@link TargetAccessConditioned} interface, are assumed - * accessible. - * - *

- * Caution: The returned {@link AllRequiredAccess} object has the only strong references - * to the listeners. If you intend to wait for access, e.g., by calling - * {@link AsyncReference#waitValue(Object)}, you must ensure a strong reference to this object - * is maintained for the duration of the wait. If not, it could be garbage collected, and you - * will never get a callback. - * - * @param obj the object whose accessibility to track - * @return a future which completes with an {@link AsyncReference} of the objects effective - * accessibility. - * @deprecated Just listen on the nearest {@link TargetAccessConditioned} ancestor instead. The - * "every-ancestor" convention is deprecated. - */ - @Deprecated - public static CompletableFuture trackAccessibility(TargetObject obj) { - CompletableFuture> collectAncestors = - collectAncestors(obj, TargetAccessConditioned.class); - return collectAncestors.thenApply(AllRequiredAccess::new); - } - /** * Request activation of the given object in its nearest active scope * diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AbstractTargetObject.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AbstractTargetObject.java index 265a3ae821..a466df71a9 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AbstractTargetObject.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AbstractTargetObject.java @@ -25,9 +25,6 @@ import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.EnumerableTargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.util.PathUtils; -import ghidra.lifecycle.Internal; -import ghidra.util.Msg; -import ghidra.util.datastruct.ListenerSet; /** * An abstract implementation of {@link TargetObject} @@ -63,15 +60,10 @@ public abstract class AbstractTargetObject

implements Sp protected volatile boolean valid = true; - // TODO: Remove these, and just do invocations on model's listeners? - protected final ListenerSet listeners; - public AbstractTargetObject(ProxyFactory proxyFactory, I proxyInfo, AbstractDebuggerObjectModel model, P parent, String key, String typeHint, TargetObjectSchema schema) { - this.listeners = new ListenerSet<>(DebuggerModelListener.class, model.clientExecutor); this.model = model; - listeners.addChained(model.listeners); this.parent = parent; if (parent == null) { this.path = key == null ? List.of() : List.of(key); @@ -103,7 +95,7 @@ public abstract class AbstractTargetObject

implements Sp assert proxy != null; synchronized (model.lock) { model.objectCreated(proxy); - listeners.fire.created(proxy); + broadcast().created(proxy); } } @@ -193,19 +185,6 @@ public abstract class AbstractTargetObject

implements Sp return valid; } - @Override - public void addListener(DebuggerModelListener l) { - if (!valid) { - throw new IllegalStateException("Object is no longer valid: " + getProxy()); - } - listeners.add(l); - } - - @Override - public void removeListener(DebuggerModelListener l) { - listeners.remove(l); - } - @Override public AbstractDebuggerObjectModel getModel() { return model; @@ -252,14 +231,7 @@ public abstract class AbstractTargetObject

implements Sp } valid = false; model.objectInvalidated(getProxy()); - listeners.fire.invalidated(getProxy(), branch, reason); - CompletableFuture.runAsync(() -> { - listeners.clear(); - listeners.clearChained(); - }, model.clientExecutor).exceptionally(ex -> { - Msg.error(this, "Error emptying invalidated object's listener set: ", ex); - return null; - }); + broadcast().invalidated(getProxy(), branch, reason); } protected void doInvalidateElements(Map elems, String reason) { @@ -330,19 +302,8 @@ public abstract class AbstractTargetObject

implements Sp } } - /** - * Get the listener set - * - *

- * TODO: This method should only be used by the internal implementation. It's not exposed on the - * {@link TargetObject} interface, but it could be dangerous to have it here, since clients - * could cast to {@link AbstractTargetObject} and get at it, even if the implementation's jar is - * excluded from the compile-time classpath. - * - * @return the listener set - */ - @Internal - public ListenerSet getListeners() { - return listeners; + @Override + public DebuggerModelListener broadcast() { + return model.listeners.fire; } } diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/DefaultTargetObject.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/DefaultTargetObject.java index 31a3852273..a381546f31 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/DefaultTargetObject.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/DefaultTargetObject.java @@ -131,32 +131,6 @@ public class DefaultTargetObject parent.getSchema().getChildSchema(key)); } - /** - * Check if this object is being observed - * - *

- * TODO: It'd be nice if we could know what is being observed: attributes, elements, console - * output, etc. In other words, the sub-types and overrides of the listeners. - * - *

- * Note, if an implementation chooses to cull requests because no one is listening, it should - * take care to re-synchronize when a listener is added. The implementor will need to override - * {@link #addListener(TargetObjectListener)}. - * - * @implNote The recommended pattern on the client side for keeping a synchronized cache is to - * add a listener, and then retrieve the current elements. Thus, it is acceptable to - * neglect invoking the callback on the new listener during re-synchronization. - * However, more testing is needed to verify this doesn't cause problems when network - * messaging is involved. - * - * @return true if there is at least one listener on this object - * @deprecated Since the addition of model listeners, everything is always observed - */ - @Deprecated(forRemoval = true) - protected boolean isObserved() { - return !listeners.isEmpty(); - } - @Override public CompletableFuture resync(boolean refreshAttributes, boolean refreshElements) { return CompletableFuture.allOf(fetchAttributes(refreshAttributes), @@ -303,7 +277,7 @@ public class DefaultTargetObject doInvalidateElements(delta.removed, reason); if (!delta.isEmpty()) { updateCallbackElements(delta); - listeners.fire.elementsChanged(getProxy(), delta.getKeysRemoved(), delta.added); + broadcast().elementsChanged(getProxy(), delta.getKeysRemoved(), delta.added); } } return delta; @@ -351,7 +325,7 @@ public class DefaultTargetObject doInvalidateElements(delta.removed, reason); if (!delta.isEmpty()) { updateCallbackElements(delta); - listeners.fire.elementsChanged(getProxy(), delta.getKeysRemoved(), delta.added); + broadcast().elementsChanged(getProxy(), delta.getKeysRemoved(), delta.added); } } return delta; @@ -493,7 +467,7 @@ public class DefaultTargetObject doInvalidateAttributes(delta.removed, reason); if (!delta.isEmpty()) { updateCallbackAttributes(delta); - listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); + broadcast().attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); } } return delta; @@ -558,7 +532,7 @@ public class DefaultTargetObject doInvalidateAttributes(delta.removed, reason); if (!delta.isEmpty()/* && !reason.equals("Default")*/) { updateCallbackAttributes(delta); - listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); + broadcast().attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); } } return delta; diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiTargetObject.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiTargetObject.java index 3afe260134..f43930b002 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiTargetObject.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiTargetObject.java @@ -15,6 +15,7 @@ */ package ghidra.dbg.agent; +import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.target.TargetObject; public interface SpiTargetObject extends TargetObject, InvalidatableTargetObjectIf { @@ -35,4 +36,6 @@ public interface SpiTargetObject extends TargetObject, InvalidatableTargetObject default SpiTargetObject getDelegate() { return this; } + + DebuggerModelListener broadcast(); } diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetObject.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetObject.java index e2e6501f27..5bebb43252 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetObject.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetObject.java @@ -1084,41 +1084,4 @@ public interface TargetObject extends Comparable { public default CompletableFuture invalidateCaches() { return AsyncUtils.NIL; } - - /** - * Listen for object events - * - *

- * The client must maintain a strong reference to the listener. To allow stale listeners to be - * garbage collected, the implementation should use weak or soft references. That said, the - * client should not rely on the implementation to garbage collect its listeners. All unneeded - * listeners should be removed using {@link #removeListener(TargetObjectListener)}. The - * exception is when an object is invalidated. The client may safely neglect removing any - * listeners it registered with that object. If the object does not keep listeners, i.e., it - * produces no events, this method may do nothing. - * - *

- * Clients ought to listen on the model instead of specific objects, especially since an object - * may emit events immediately after its creation, but before the client has a chance to add a - * listener. Worse yet, the object could be invalidated before the client can retrieve its - * children. Listening on the model ensures the reception of a complete log of events. - * - * @see DebuggerObjectModel#addModelListener(DebuggerModelListener) - * @param l the listener - */ - public default void addListener(DebuggerModelListener l) { - throw new UnsupportedOperationException(); - } - - /** - * Remove a listener - * - *

- * If the given listener is not registered with this object, this method does nothing. - * - * @param l the listener - */ - public default void removeListener(DebuggerModelListener l) { - throw new UnsupportedOperationException(); - } } diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/AnnotatedDebuggerAttributeListenerTest.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/AnnotatedDebuggerAttributeListenerTest.java index c1539d9dde..5000e03dbc 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/AnnotatedDebuggerAttributeListenerTest.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/AnnotatedDebuggerAttributeListenerTest.java @@ -16,8 +16,7 @@ package ghidra.dbg; import java.lang.invoke.MethodHandles; -import java.util.List; -import java.util.Map; +import java.util.*; import org.junit.Test; @@ -45,8 +44,17 @@ public class AnnotatedDebuggerAttributeListenerTest implements DebuggerModelTest private void testChanged(TargetObject object, String disp) { display.set(disp, null); } + + @Override + public void attributesChanged(TargetObject object, Collection removed, + Map added) { + if (object != obj) { + return; + } + super.attributesChanged(object, removed, added); + } }; - obj.addListener(l); + obj.getModel().addModelListener(l); obj.changeAttributes(List.of(), Map.ofEntries(Map.entry("_test", "Testing")), "Because"); waitOn(display.waitValue("Testing")); diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/agent/DefaultDebuggerObjectModelTest.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/agent/DefaultDebuggerObjectModelTest.java index 5f900dbb03..78826c2619 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/agent/DefaultDebuggerObjectModelTest.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/agent/DefaultDebuggerObjectModelTest.java @@ -309,7 +309,7 @@ public class DefaultDebuggerObjectModelTest implements AsyncTestUtils { FakeTargetObject fakeA = new FakeTargetObject(model, model.root, "A"); FakeTargetRegisterBank fakeA1rb = new FakeTargetRegisterBank(model, fakeA, "[1]"); - fakeA1rb.listeners.fire.registersUpdated(fakeA1rb, Map.of()); + fakeA1rb.broadcast().registersUpdated(fakeA1rb, Map.of()); fakeA.setElements(List.of(fakeA1rb), "Init"); model.root.setAttributes(List.of(fakeA), Map.of(), "Init"); @@ -329,7 +329,7 @@ public class DefaultDebuggerObjectModelTest implements AsyncTestUtils { FakeTargetObject fakeA = new FakeTargetObject(model, model.root, "A"); FakeTargetRegisterBank fakeA1rb = new FakeTargetRegisterBank(model, fakeA, "[1]"); - fakeA1rb.listeners.fire.registersUpdated(fakeA1rb, Map.of()); + fakeA1rb.broadcast().registersUpdated(fakeA1rb, Map.of()); fakeA.setElements(List.of(fakeA1rb), "Init"); model.root.setAttributes(List.of(fakeA), Map.of(), "Init"); EventRecordingListener listener = new EventRecordingListener(); diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/AbstractTestTargetRegisterBank.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/AbstractTestTargetRegisterBank.java index aecdb28261..17d92f957d 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/AbstractTestTargetRegisterBank.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/AbstractTestTargetRegisterBank.java @@ -64,7 +64,7 @@ public abstract class AbstractTestTargetRegisterBank

} populateObjectValues(result, "Read registers"); return model.gateFuture(descs.getModel().future(result).thenApply(__ -> { - listeners.fire.registersUpdated(this, result); + broadcast().registersUpdated(this, result); return result; })); } @@ -90,7 +90,7 @@ public abstract class AbstractTestTargetRegisterBank

} populateObjectValues(updates, "Write registers"); future.thenAccept(__ -> { - listeners.fire.registersUpdated(this, updates); + broadcast().registersUpdated(this, updates); }); return model.gateFuture(future); } diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetInterpreter.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetInterpreter.java index 219b811033..1a5c8756bb 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetInterpreter.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetInterpreter.java @@ -75,7 +75,7 @@ public class TestTargetInterpreter } public void output(Channel channel, String line) { - listeners.fire.consoleOutput(this, channel, line + "\n"); + broadcast().consoleOutput(this, channel, line + "\n"); } public void clearCalls() { diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetMemory.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetMemory.java index a1934519f2..49e25bfe9f 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetMemory.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetMemory.java @@ -52,7 +52,7 @@ public class TestTargetMemory getMemory(address, data); CompletableFuture future = getModel().future(data); future.thenAccept(__ -> { - listeners.fire.memoryUpdated(this, address, data); + broadcast().memoryUpdated(this, address, data); }); return future; } @@ -67,7 +67,7 @@ public class TestTargetMemory setMemory(address, data); CompletableFuture future = getModel().future(null); future.thenAccept(__ -> { - listeners.fire.memoryUpdated(this, address, data); + broadcast().memoryUpdated(this, address, data); }); return future; } diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetSession.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetSession.java index 0e43681f71..2cc280a9da 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetSession.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/model/TestTargetSession.java @@ -75,7 +75,7 @@ public class TestTargetSession extends DefaultTargetModelRoot public void simulateStep(TestTargetThread eventThread) { eventThread.setState(TargetExecutionState.RUNNING); - listeners.fire.event(this, eventThread, TargetEventType.STEP_COMPLETED, + broadcast().event(this, eventThread, TargetEventType.STEP_COMPLETED, "Test thread completed a step", List.of()); eventThread.setState(TargetExecutionState.STOPPED); } diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/test/AbstractDebuggerModelInterpreterTest.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/test/AbstractDebuggerModelInterpreterTest.java index 9710b579d6..9f643afb1b 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/test/AbstractDebuggerModelInterpreterTest.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/test/AbstractDebuggerModelInterpreterTest.java @@ -119,7 +119,10 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug AsyncReference lastOut = new AsyncReference<>(); DebuggerModelListener l = new DebuggerModelListener() { @Override - public void consoleOutput(TargetObject interpreter, Channel channel, byte[] out) { + public void consoleOutput(TargetObject object, Channel channel, byte[] out) { + if (object != interpreter) { + return; + } String str = new String(out); Msg.debug(this, "Got " + channel + " output: " + str); for (String line : str.split("\n")) { @@ -127,7 +130,7 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug } } }; - interpreter.addListener(l); + interpreter.getModel().addModelListener(l); waitAcc(interpreter); waitOn(interpreter.execute(cmd)); waitOn(lastOut.waitValue("test")); @@ -150,7 +153,10 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug try (CatchOffThread off = new CatchOffThread()) { DebuggerModelListener l = new DebuggerModelListener() { @Override - public void consoleOutput(TargetObject interpreter, Channel channel, byte[] out) { + public void consoleOutput(TargetObject object, Channel channel, byte[] out) { + if (object != interpreter) { + return; + } String str = new String(out); Msg.debug(this, "Got " + channel + " output: " + str); if (!str.contains("test")) { @@ -159,7 +165,7 @@ public abstract class AbstractDebuggerModelInterpreterTest extends AbstractDebug off.catching(() -> fail("Unexpected output:" + str)); } }; - interpreter.addListener(l); + interpreter.getModel().addModelListener(l); waitAcc(interpreter); String out = waitOn(interpreter.executeCapture(cmd)); // Not the greatest, but allow extra lines diff --git a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/util/DebuggerCallbackReordererTest.java b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/util/DebuggerCallbackReordererTest.java index 011b890db7..25fa53303c 100644 --- a/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/util/DebuggerCallbackReordererTest.java +++ b/Ghidra/Debug/Framework-Debugging/src/test/java/ghidra/dbg/util/DebuggerCallbackReordererTest.java @@ -262,7 +262,7 @@ public class DebuggerCallbackReordererTest implements DebuggerModelTestUtils { * child of [r1], to guarantee registersUpdated has happened */ toA.changeElements(List.of(), List.of(toA1), "Test"); - toA.getListeners().fire.registersUpdated(toA, Map.of("r1", new byte[4])); + toA.broadcast().registersUpdated(toA, Map.of("r1", new byte[4])); root.changeAttributes(List.of(), List.of(toA), Map.of(), "Test"); /** * CFs may get queued in depth, so add root here to ensure registersUpdated comes before @@ -321,12 +321,14 @@ public class DebuggerCallbackReordererTest implements DebuggerModelTestUtils { FakeTargetRoot root = new FakeTargetRoot(model, "Root", model.getRootSchema()); FakeTargetObject processes = new FakeTargetObject(model, root, "Processes"); FakeTargetProcess proc1 = new FakeTargetProcess(model, processes, "[1]"); - root.getListeners().fire.event(root, null, TargetEventType.PROCESS_CREATED, - "Process 1 created", List.of(proc1)); + root.broadcast() + .event(root, null, TargetEventType.PROCESS_CREATED, "Process 1 created", + List.of(proc1)); FakeTargetObject p1threads = new FakeTargetObject(model, proc1, "Threads"); FakeTargetThread thread1 = new FakeTargetThread(model, p1threads, "[1]"); - root.getListeners().fire.event(root, thread1, TargetEventType.THREAD_CREATED, - "Thread 1 created", List.of()); + root.broadcast() + .event(root, thread1, TargetEventType.THREAD_CREATED, "Thread 1 created", + List.of()); p1threads.changeElements(List.of(), List.of(thread1), "Test"); proc1.changeAttributes(List.of(), List.of(p1threads), Map.of(), "Test"); @@ -366,15 +368,18 @@ public class DebuggerCallbackReordererTest implements DebuggerModelTestUtils { FakeTargetRoot root = new FakeTargetRoot(model, "Root", model.getRootSchema()); FakeTargetObject processes = new FakeTargetObject(model, root, "Processes"); FakeTargetProcess proc1 = new FakeTargetProcess(model, processes, "[1]"); - root.getListeners().fire.event(root, null, TargetEventType.PROCESS_CREATED, - "Process 1 created", List.of(proc1)); + root.broadcast() + .event(root, null, TargetEventType.PROCESS_CREATED, "Process 1 created", + List.of(proc1)); FakeTargetObject p1threads = new FakeTargetObject(model, proc1, "Threads"); FakeTargetThread thread1 = new FakeTargetThread(model, p1threads, "[1]"); - root.getListeners().fire.event(root, thread1, TargetEventType.THREAD_CREATED, - "Thread 1 created", List.of()); + root.broadcast() + .event(root, thread1, TargetEventType.THREAD_CREATED, "Thread 1 created", + List.of()); FakeTargetThread thread2 = new FakeTargetThread(model, p1threads, "[2]"); - root.getListeners().fire.event(root, thread1, TargetEventType.THREAD_CREATED, - "Thread 2 created", List.of()); + root.broadcast() + .event(root, thread1, TargetEventType.THREAD_CREATED, "Thread 2 created", + List.of()); p1threads.changeElements(List.of(), List.of(thread2), "Test"); proc1.changeAttributes(List.of(), List.of(p1threads), Map.of(), "Test"); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java index ec8e008f5c..f1237c1fb6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java @@ -34,6 +34,7 @@ import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramViewMemory; import ghidra.trace.util.MemoryAdapter; +import ghidra.util.LockHold; import ghidra.util.MathUtilities; import ghidra.util.exception.CancelledException; import ghidra.util.exception.NotFoundException; @@ -79,9 +80,11 @@ public abstract class AbstractDBTraceProgramViewMemory } } - protected synchronized void computeFullAdddressSet() { + protected void computeFullAdddressSet() { AddressSet temp = new AddressSet(); - forPhysicalSpaces(space -> temp.add(space.getMinAddress(), space.getMaxAddress())); + try (LockHold hold = program.trace.lockRead()) { + forPhysicalSpaces(space -> temp.add(space.getMinAddress(), space.getMaxAddress())); + } addressSet = temp; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java index bf0fa70e95..94cf24aa31 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java @@ -24,6 +24,7 @@ import com.google.common.cache.CacheBuilder; import ghidra.program.model.address.*; import ghidra.program.model.mem.MemoryBlock; import ghidra.trace.model.memory.TraceMemoryRegion; +import ghidra.util.LockHold; public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { @@ -74,10 +75,12 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { } @Override - protected synchronized void recomputeAddressSet() { + protected void recomputeAddressSet() { AddressSet temp = new AddressSet(); - // TODO: Performance test this - forVisibleRegions(reg -> temp.add(reg.getRange())); + try (LockHold hold = program.trace.lockRead()) { + // TODO: Performance test this + forVisibleRegions(reg -> temp.add(reg.getRange())); + } addressSet = temp; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerMap.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerMap.java index a1bf059731..8e4382fe5f 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerMap.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerMap.java @@ -142,25 +142,6 @@ public class ListenerMap { } } }); - Set> chainedVolatile; - synchronized (lock) { - chainedVolatile = chained; - } - for (ListenerMap c : chainedVolatile) { - // Invocation will check if assignable - @SuppressWarnings("unchecked") - T l = ((ListenerMap) c).fire(ext); - try { - method.invoke(l, args); - } - catch (InvocationTargetException e) { - Throwable cause = e.getCause(); - reportError(l, cause); - } - catch (Throwable e) { - reportError(l, e); - } - } return null; // TODO: Assumes void return type } } @@ -169,7 +150,6 @@ public class ListenerMap { private final Class

iface; private final Executor executor; private Map map = createMap(); - private Set> chained = new LinkedHashSet<>(); /** * A proxy which passes invocations to each value of this map @@ -300,37 +280,4 @@ public class ListenerMap { map = createMap(); } } - - public void addChained(ListenerMap map) { - synchronized (lock) { - if (chained.contains(map)) { - return; - } - Set> newChained = new LinkedHashSet<>(); - newChained.addAll(chained); - newChained.add(map); - chained = newChained; - } - } - - public void removeChained(ListenerMap map) { - synchronized (lock) { - if (!chained.contains(map)) { - return; - } - Set> newChained = new LinkedHashSet<>(); - newChained.addAll(chained); - newChained.remove(map); - chained = newChained; - } - } - - public void clearChained() { - synchronized (lock) { - if (chained.isEmpty()) { - return; - } - chained = new LinkedHashSet<>(); - } - } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerSet.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerSet.java index bf813be5ec..8ae184812d 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerSet.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/datastruct/ListenerSet.java @@ -107,16 +107,4 @@ public class ListenerSet { public void clear() { map.clear(); } - - public void addChained(ListenerSet set) { - map.addChained(set.map); - } - - public void removeChained(ListenerSet set) { - map.removeChained(set.map); - } - - public void clearChained() { - map.clearChained(); - } }