diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java index 2bfcd71cb3..c8658bf505 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java @@ -133,7 +133,7 @@ public interface DbgProcess extends DbgMemoryOperations { * * @return a future that completes when dbgeng has executed the command */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Specify a binary image for execution and debug symbols diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgStackFrame.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgStackFrame.java index d3d0e8d2f6..b39f7b9572 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgStackFrame.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgStackFrame.java @@ -48,7 +48,7 @@ public interface DbgStackFrame extends DbgStackFrameOperations { * * @return a future that completes when the frame is the current frame */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Get the thread for this frame diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java index 267e19dcd2..b2d94e3dd9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java @@ -61,7 +61,7 @@ public interface DbgThread * * @return a future that completes when the thread is the current thread */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Get the process to which this thread belongs diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgRequestActivationCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgRequestActivationCommand.java new file mode 100644 index 0000000000..f2176e79d0 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgRequestActivationCommand.java @@ -0,0 +1,45 @@ +/* ### + * 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 agent.dbgeng.manager.cmd; + +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.model.iface1.DbgModelTargetActiveScope; +import ghidra.dbg.target.TargetObject; + +public class DbgRequestActivationCommand extends AbstractDbgCommand { + + private DbgModelTargetActiveScope activator; + private TargetObject obj; + + /** + * Set focus for the current ref + * + * @param manager the manager to execute the command + * @param activator in most cases the root object (must be an ancestor for the ref) + * @param obj the desired object to be made active + */ + public DbgRequestActivationCommand(DbgManagerImpl manager, DbgModelTargetActiveScope activator, + TargetObject obj) { + super(manager); + this.activator = activator; + this.obj = obj; + } + + @Override + public void invoke() { + activator.doRequestActivation(obj); + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgProcessSelectCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java similarity index 80% rename from Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgProcessSelectCommand.java rename to Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java index 34ad3dcd83..1e867b20bc 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgProcessSelectCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java @@ -19,19 +19,17 @@ import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.impl.DbgManagerImpl; -public class DbgProcessSelectCommand extends AbstractDbgCommand { +public class DbgSetActiveProcessCommand extends AbstractDbgCommand { private DbgProcess process; /** - * Select the given thread and frame level - * - * To simply select a thread, you should use frame 0 as the default. + * Set the active process * * @param manager the manager to execute the command * @param process the desired process */ - public DbgProcessSelectCommand(DbgManagerImpl manager, DbgProcess process) { + public DbgSetActiveProcessCommand(DbgManagerImpl manager, DbgProcess process) { super(manager); this.process = process; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSessionSelectCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveSessionCommand.java similarity index 80% rename from Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSessionSelectCommand.java rename to Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveSessionCommand.java index ef5908bb4c..c29eb214bc 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSessionSelectCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveSessionCommand.java @@ -19,18 +19,16 @@ import agent.dbgeng.dbgeng.DebugSessionId; import agent.dbgeng.manager.DbgSession; import agent.dbgeng.manager.impl.DbgManagerImpl; -public class DbgSessionSelectCommand extends AbstractDbgCommand { +public class DbgSetActiveSessionCommand extends AbstractDbgCommand { private DbgSession session; /** - * Select the given thread and frame level - * - * To simply select a thread, you should use frame 0 as the default. + * Set the active session * * @param manager the manager to execute the command * @param process the desired process */ - public DbgSessionSelectCommand(DbgManagerImpl manager, DbgSession session) { + public DbgSetActiveSessionCommand(DbgManagerImpl manager, DbgSession session) { super(manager); this.session = session; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgThreadSelectCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java similarity index 80% rename from Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgThreadSelectCommand.java rename to Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java index af7e294a71..4ec32dad7c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgThreadSelectCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java @@ -19,20 +19,18 @@ import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgManagerImpl; -public class DbgThreadSelectCommand extends AbstractDbgCommand { +public class DbgSetActiveThreadCommand extends AbstractDbgCommand { private DbgThread thread; /** - * Select the given thread and frame level - * - * To simply select a thread, you should use frame 0 as the default. + * Set the active thread * * @param manager the manager to execute the command * @param thread the desired thread * @param frameId the desired frame level */ - public DbgThreadSelectCommand(DbgManagerImpl manager, DbgThread thread, Integer frameId) { + public DbgSetActiveThreadCommand(DbgManagerImpl manager, DbgThread thread, Integer frameId) { super(manager); this.thread = thread; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java index 1bd9bcd68f..ed87f0ba38 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java @@ -41,6 +41,7 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointType; import agent.dbgeng.manager.cmd.*; import agent.dbgeng.manager.evt.*; +import agent.dbgeng.model.iface1.DbgModelTargetActiveScope; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import ghidra.async.*; import ghidra.comm.util.BitmaskSet; @@ -1402,25 +1403,30 @@ public class DbgManagerImpl implements DbgManager { return (DbgSessionImpl) eventSession; } - public CompletableFuture selectThread(DbgThread thread) { + public CompletableFuture setActiveThread(DbgThread thread) { currentThread = thread; - return execute(new DbgThreadSelectCommand(this, thread, null)); + return execute(new DbgSetActiveThreadCommand(this, thread, null)); } - public CompletableFuture selectProcess(DbgProcess process) { + public CompletableFuture setActiveProcess(DbgProcess process) { currentProcess = process; - return execute(new DbgProcessSelectCommand(this, process)); + return execute(new DbgSetActiveProcessCommand(this, process)); } - public CompletableFuture selectSession(DbgSession session) { + public CompletableFuture setActiveSession(DbgSession session) { currentSession = session; - return execute(new DbgSessionSelectCommand(this, session)); + return execute(new DbgSetActiveSessionCommand(this, session)); } public CompletableFuture requestFocus(DbgModelTargetFocusScope scope, TargetObject obj) { return execute(new DbgRequestFocusCommand(this, scope, obj)); } + public CompletableFuture requestActivation(DbgModelTargetActiveScope activator, + TargetObject obj) { + return execute(new DbgRequestActivationCommand(this, activator, obj)); + } + @Override public CompletableFuture console(String command) { return execute( diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java index e8713d27aa..bf70d7744c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java @@ -231,14 +231,14 @@ public class DbgProcessImpl implements DbgProcess { } @Override - public CompletableFuture select() { - return manager.selectProcess(this); + public CompletableFuture setActive() { + return manager.setActiveProcess(this); } @Override public CompletableFuture fileExecAndSymbols(String file) { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgFileExecAndSymbolsCommand(manager, file)).handle(seq::exit); }).finish(); @@ -247,7 +247,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture run() { return sequence(TypeSpec.cls(DbgThread.class)).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgRunCommand(manager)).handle(seq::exit); }).finish(); @@ -256,7 +256,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture> attach(long toPid) { return sequence(TypeSpec.cls(DbgThread.class).set()).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { pid = toPid; // TODO: Wait for successful completion? manager.execute( @@ -268,7 +268,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture> reattach(TargetAttachable attachable) { return sequence(TypeSpec.cls(DbgThread.class).set()).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute( new DbgAttachCommand(manager, this, BitmaskSet.of(DebugAttachFlags.EXISTING))) @@ -279,7 +279,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture detach() { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgDetachCommand(manager, this)).handle(seq::exit); }).finish(); @@ -288,7 +288,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture kill() { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgKillCommand(manager)).handle(seq::exit); }).finish(); @@ -297,7 +297,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture cont() { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgContinueCommand(manager)).handle(seq::exit); }).finish(); @@ -306,7 +306,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture step(ExecSuffix suffix) { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgStepCommand(manager, null, suffix)).handle(seq::exit); }).finish(); @@ -315,7 +315,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture step(Map args) { return sequence(TypeSpec.VOID).then((seq) -> { - select().handle(seq::next); + setActive().handle(seq::next); }).then((seq) -> { manager.execute(new DbgStepCommand(manager, null, args)).handle(seq::exit); }).finish(); @@ -328,7 +328,7 @@ public class DbgProcessImpl implements DbgProcess { if (first.isPresent()) { return viaThread.apply(first.get()); } - return select().thenCompose(__ -> viaThis.get()); + return setActive().thenCompose(__ -> viaThis.get()); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgStackFrameImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgStackFrameImpl.java index c0ac221c8c..e26f5614d6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgStackFrameImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgStackFrameImpl.java @@ -124,8 +124,8 @@ public class DbgStackFrameImpl implements DbgStackFrame { } @Override - public CompletableFuture select() { - return thread.select(); + public CompletableFuture setActive() { + return thread.setActive(); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java index 45d5fbbe02..b7bde4a778 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java @@ -130,8 +130,8 @@ public class DbgThreadImpl implements DbgThread { } @Override - public CompletableFuture select() { - return manager.selectThread(this); + public CompletableFuture setActive() { + return manager.setActiveThread(this); } @Override @@ -207,35 +207,35 @@ public class DbgThreadImpl implements DbgThread { @Override public CompletableFuture cont() { - return select().thenCompose(__ -> { + return setActive().thenCompose(__ -> { return manager.execute(new DbgContinueCommand(manager)); }); } @Override public CompletableFuture step(ExecSuffix suffix) { - return select().thenCompose(__ -> { + return setActive().thenCompose(__ -> { return manager.execute(new DbgStepCommand(manager, id, suffix)); }); } @Override public CompletableFuture step(Map args) { - return select().thenCompose(__ -> { + return setActive().thenCompose(__ -> { return manager.execute(new DbgStepCommand(manager, id, args)); }); } @Override public CompletableFuture kill() { - return select().thenCompose(__ -> { + return setActive().thenCompose(__ -> { return manager.execute(new DbgKillCommand(manager)); }); } @Override public CompletableFuture detach() { - return select().thenCompose(__ -> { + return setActive().thenCompose(__ -> { return manager.execute(new DbgDetachCommand(manager, process)); }); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelSelectableObject.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelSelectableObject.java index fe25d3218f..502e850ea8 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelSelectableObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelSelectableObject.java @@ -25,21 +25,21 @@ import ghidra.dbg.target.TargetObject; public interface DbgModelSelectableObject extends DbgModelTargetObject { - public default CompletableFuture select() { + public default CompletableFuture setActive() { if (this instanceof DbgModelTargetSession) { DbgManagerImpl manager = getManager(); DbgProcess process = manager.getCurrentProcess(); - return process.select(); + return process.setActive(); } if (this instanceof DbgModelTargetProcess) { DbgModelTargetProcess tp = (DbgModelTargetProcess) this; DbgProcess process = tp.getProcess(); - return process.select(); + return process.setActive(); } if (this instanceof DbgModelTargetThread) { DbgModelTargetThread tt = (DbgModelTargetThread) this; DbgThread thread = tt.getThread(); - return thread.select(); + return thread.setActive(); } if (this instanceof DbgModelTargetStackFrame) { DbgModelTargetStackFrame tf = (DbgModelTargetStackFrame) this; @@ -47,7 +47,7 @@ public interface DbgModelSelectableObject extends DbgModelTargetObject { if (ref instanceof DbgModelTargetThread) { DbgModelTargetThread tt = (DbgModelTargetThread) ref; DbgThread thread = tt.getThread(); - return thread.select(); + return thread.setActive(); } } return CompletableFuture.completedFuture(null); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetActiveScope.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetActiveScope.java new file mode 100644 index 0000000000..2de8b68137 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetActiveScope.java @@ -0,0 +1,68 @@ +/* ### + * 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 agent.dbgeng.model.iface1; + +import java.util.concurrent.CompletableFuture; + +import agent.dbgeng.model.iface2.DbgModelTargetObject; +import ghidra.async.AsyncUtils; +import ghidra.dbg.error.DebuggerIllegalArgumentException; +import ghidra.dbg.target.TargetActiveScope; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.util.PathUtils; + +/** + * An interface which indicates this object is capable of launching targets. + * + * The targets this launcher creates ought to appear in its successors. + * + * @param type for this + */ +public interface DbgModelTargetActiveScope extends DbgModelTargetObject, TargetActiveScope { + + // NB: requesActivation request change in active object - propagates down to manager + // (but, of course, may then cause change in state) + @Override + public default CompletableFuture requestActivation(TargetObject obj) { + return getModel().gateFuture(getManager().requestActivation(this, obj)); + } + + public default CompletableFuture doRequestActivation(TargetObject obj) { + if (getManager().isWaiting()) { + return AsyncUtils.NIL; + } + getModel().assertMine(TargetObject.class, obj); + if (!PathUtils.isAncestor(this.getPath(), obj.getPath())) { + throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope"); + } + TargetObject cur = obj; + while (cur != null) { + if (cur instanceof DbgModelSelectableObject) { + DbgModelSelectableObject sel = (DbgModelSelectableObject) cur; + System.err.println("requestActivation " + obj); + return sel.setActive(); + } + if (cur instanceof DbgModelTargetObject) { + DbgModelTargetObject def = (DbgModelTargetObject) cur; + cur = def.getParent(); + continue; + } + throw new AssertionError(); + } + return AsyncUtils.NIL; + } + +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetFocusScope.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetFocusScope.java index 96344003f7..6fc155314a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetFocusScope.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetFocusScope.java @@ -39,7 +39,7 @@ public interface DbgModelTargetFocusScope extends DbgModelTargetObject, TargetFo // NB: setFocus changes attributes - propagates up to client public boolean setFocus(DbgModelSelectableObject sel); - // NB: requestFocus request change in active object - propagates down to manager + // NB: requestFocus request change in focused object - propagates down to manager // (but, of course, may then cause change in state) @Override public default CompletableFuture requestFocus(TargetObject obj) { @@ -61,8 +61,9 @@ public interface DbgModelTargetFocusScope extends DbgModelTargetObject, TargetFo while (cur != null) { if (cur instanceof DbgModelSelectableObject) { DbgModelSelectableObject sel = (DbgModelSelectableObject) cur; + System.err.println("requestFocus " + obj); setFocus(sel); - return sel.select(); + return AsyncUtils.NIL; } if (cur instanceof DbgModelTargetObject) { DbgModelTargetObject def = (DbgModelTargetObject) cur; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetConnector.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetConnector.java index 6b9961e517..1581cf63fe 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetConnector.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetConnector.java @@ -31,7 +31,7 @@ public interface DbgModelTargetConnector } @Override - public CompletableFuture select(); + public CompletableFuture setActive(); @Override public TargetParameterMap getParameters(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetProcess.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetProcess.java index 2c5cdaebae..e094881875 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetProcess.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetProcess.java @@ -69,13 +69,13 @@ public interface DbgModelTargetProcess extends // } @Override - public default CompletableFuture select() { + public default CompletableFuture setActive() { DbgManagerImpl manager = getManager(); DbgProcess process = getProcess(); if (process == null) { process = manager.getEventProcess(); } - return manager.selectProcess(process); + return manager.setActiveProcess(process); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRoot.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRoot.java index beb267a06d..1c05d05f32 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRoot.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRoot.java @@ -22,6 +22,7 @@ public interface DbgModelTargetRoot extends // ///DbgModelTargetObject, DbgModelTargetAccessConditioned, // DbgModelTargetAttacher, // + DbgModelTargetActiveScope, // DbgModelTargetEventScope, // DbgModelTargetLauncher, // DbgModelTargetFocusScope, // @@ -29,5 +30,6 @@ public interface DbgModelTargetRoot extends // void setDefaultConnector(DbgModelTargetConnector defaultConnector); + // getActive & requestActivation implemented by DbgModelTargetObject & DbgModelTargetActiveScope // getFocus & requestFocus implemented by DbgModelTargetObject & DbgModelTargetFocusScope } 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 8db04022d9..9845313a78 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 @@ -71,12 +71,12 @@ public interface DbgModelTargetSession extends // } @Override - public default CompletableFuture select() { + public default CompletableFuture setActive() { DbgManagerImpl manager = getManager(); DbgSession session = getSession(); if (session == null) { session = manager.getEventSession(); } - return manager.selectSession(session); + return manager.setActiveSession(session); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetStackFrame.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetStackFrame.java index 9ab0313123..0729b179bd 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetStackFrame.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetStackFrame.java @@ -48,10 +48,10 @@ public interface DbgModelTargetStackFrame extends // public static final String FROM_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "from"; // TODO @Override - public default CompletableFuture select() { + public default CompletableFuture setActive() { DbgManagerImpl manager = getManager(); DbgThreadImpl thread = manager.getCurrentThread(); - return manager.selectThread(thread); + return manager.setActiveThread(thread); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java index 4def70c441..1f2032022f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java @@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.manager.*; -import agent.dbgeng.manager.cmd.DbgThreadSelectCommand; +import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand; import agent.dbgeng.manager.impl.*; import agent.dbgeng.model.iface1.*; import agent.dbgeng.model.impl.DbgModelTargetStackImpl; @@ -58,10 +58,10 @@ public interface DbgModelTargetThread extends // public void threadStateChangedSpecific(DbgState state, DbgReason reason); @Override - public default CompletableFuture select() { + public default CompletableFuture setActive() { DbgManagerImpl manager = getManager(); DbgThread thread = getThread(); - return manager.execute(new DbgThreadSelectCommand(manager, thread, null)); + return manager.execute(new DbgSetActiveThreadCommand(manager, thread, null)); } public DbgModelTargetStackImpl getStack(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetKernelConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetKernelConnectorImpl.java index 8b3288f2e3..bc4d0349f6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetKernelConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetKernelConnectorImpl.java @@ -55,7 +55,7 @@ public class DbgModelTargetKernelConnectorImpl extends DbgModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { connectors.setDefaultConnector(this); return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessAttachConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessAttachConnectorImpl.java index fd6b4189bd..f4ec0bf024 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessAttachConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessAttachConnectorImpl.java @@ -56,7 +56,7 @@ public class DbgModelTargetProcessAttachConnectorImpl extends DbgModelTargetObje } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { connectors.setDefaultConnector(this); return CompletableFuture.completedFuture(null); } 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 165313838e..9aa683ef5c 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 @@ -197,9 +197,9 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { DbgManagerImpl manager = getManager(); - return manager.selectProcess(process); + return manager.setActiveProcess(process); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java index 93bac17286..dea77e1fed 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java @@ -54,7 +54,7 @@ public class DbgModelTargetProcessLaunchConnectorImpl extends DbgModelTargetObje } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { connectors.setDefaultConnector(this); return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java index 0c3e5dc828..4f0ca6d995 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java @@ -21,8 +21,7 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.manager.*; import agent.dbgeng.manager.impl.DbgProcessImpl; import agent.dbgeng.model.iface1.DbgModelSelectableObject; -import agent.dbgeng.model.iface2.DbgModelTargetConnector; -import agent.dbgeng.model.iface2.DbgModelTargetRoot; +import agent.dbgeng.model.iface2.*; import ghidra.dbg.error.DebuggerUserException; import ghidra.dbg.target.*; import ghidra.dbg.target.schema.*; @@ -119,10 +118,10 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot @Override public void threadStateChanged(DbgThread thread, DbgState state, DbgCause cause, DbgReason reason) { - DbgProcess process = thread.getProcess(); + DbgModelTargetThread targetThread = + (DbgModelTargetThread) getModel().getModelObject(thread); changeAttributes(List.of(), List.of(), Map.of( // - TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, Long.toHexString(process.getPid()), // - TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, Long.toHexString(thread.getTid()) // + TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread // ), reason.desc()); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java index 7832cf8f45..c2b96ede6f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java @@ -87,7 +87,7 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { //DbgManagerImpl manager = getManager(); //DbgProcessImpl process = manager.getCurrentProcess(); //return manager.execute(new DbgProcessSelectCommand(manager, process)); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java index 553e179f3d..5a0d2d6e1c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java @@ -138,9 +138,9 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { DbgManagerImpl manager = getManager(); - return manager.selectThread(thread.getThread()); + return manager.setActiveThread(thread.getThread()); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java index e0bc532af6..ef50cbfbc7 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java @@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.manager.*; -import agent.dbgeng.manager.cmd.DbgThreadSelectCommand; +import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import agent.dbgeng.model.iface2.*; @@ -138,9 +138,9 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { DbgManagerImpl manager = getManager(); - return manager.execute(new DbgThreadSelectCommand(manager, thread, null)); + return manager.execute(new DbgSetActiveThreadCommand(manager, thread, null)); } public DbgModelTargetRegisterContainerAndBank getRegisters() { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java index fa75c06858..b8e9eeefa8 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java @@ -54,7 +54,7 @@ public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObject } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { connectors.setDefaultConnector(this); return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/manager/impl/AbstractDbgManagerTest.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/manager/impl/AbstractDbgManagerTest.java index f61c3d2956..2e3d11b3b8 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/manager/impl/AbstractDbgManagerTest.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/manager/impl/AbstractDbgManagerTest.java @@ -406,7 +406,7 @@ public abstract class AbstractDbgManagerTest extends AbstractGhidraHeadlessInteg }).then(seq -> { mgr.waitForPrompt().handle(seq::next); }).then(seq -> { - thread.get().select().handle(seq::next); + thread.get().setActive().handle(seq::next); }).finish()); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java index fc06dc474c..8efc695381 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java @@ -114,7 +114,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot ), "Focus changed"); intrinsics.put(TargetFocusScope.FOCUS_ATTRIBUTE_NAME, focus); DbgModelTargetSession session = focus.getParentSession(); - session.select(); + session.setActive(); } return doFire; } @@ -314,15 +314,10 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot if (targetThread == null) { return; } - DbgProcess process = thread.getProcess(); changeAttributes(List.of(), List.of(), Map.of( // - TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, Long.toHexString(process.getPid()), // - TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, Long.toHexString(thread.getTid()) // + TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread // ), reason.desc()); - intrinsics.put(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, - Long.toHexString(process.getPid())); - intrinsics.put(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, - Long.toHexString(thread.getTid())); + intrinsics.put(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread); TargetEventType eventType = getEventType(state, cause, reason); getListeners().fire.event(getProxy(), targetThread, eventType, "Thread " + thread.getId() + " state changed", List.of(targetThread)); diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbInferior.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbInferior.java index 3f75d00fa9..506dfc379c 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbInferior.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbInferior.java @@ -154,7 +154,7 @@ public interface GdbInferior extends GdbMemoryOperations { * * @return a future that completes when GDB has executed the command */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Specify a binary image for execution and debug symbols diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbManager.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbManager.java index 608ab5a2f4..ccf8ec9522 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbManager.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbManager.java @@ -258,7 +258,7 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions { /** * Get the inferior which currently has focus * - * @see GdbInferior#select() + * @see GdbInferior#setActive() * @return a handle to the inferior with focus */ GdbInferior currentInferior(); diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbStackFrame.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbStackFrame.java index dbe0e9ae6b..e992f18aa0 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbStackFrame.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbStackFrame.java @@ -49,7 +49,7 @@ public interface GdbStackFrame extends GdbStackFrameOperations { * * @return a future that completes when the frame is the current frame */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Get the thread for this frame diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbThread.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbThread.java index 95c491cf82..a84c3fbf33 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbThread.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/GdbThread.java @@ -70,7 +70,7 @@ public interface GdbThread * * @return a future that completes when the thread is the current thread */ - CompletableFuture select(); + CompletableFuture setActive(); /** * Set the value of an internal GDB variable diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbInferiorImpl.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbInferiorImpl.java index 9247d1fd27..3cc664815d 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbInferiorImpl.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbInferiorImpl.java @@ -208,7 +208,7 @@ public class GdbInferiorImpl implements GdbInferior { * longer be current for the actual command execution. NB: The select command will cancel * itself if this inferior is already current. */ - return select().thenCombine(manager.execute(cmd), (s, e) -> e); + return setActive().thenCombine(manager.execute(cmd), (s, e) -> e); } @Override @@ -347,8 +347,8 @@ public class GdbInferiorImpl implements GdbInferior { } @Override - public CompletableFuture select() { - return manager.selectInferior(this); + public CompletableFuture setActive() { + return manager.setActiveInferior(this); } @Override diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbManagerImpl.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbManagerImpl.java index 8b60f42b8f..7bad455238 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbManagerImpl.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbManagerImpl.java @@ -957,7 +957,7 @@ public class GdbManagerImpl implements GdbManager { event(() -> listenersEvent.fire.inferiorSelected(cur, evt.getCause()), "groupRemoved-sel"); // Also cause GDB to generate thread selection events, if applicable - selectInferior(cur); + setActiveInferior(cur); } } @@ -1524,7 +1524,7 @@ public class GdbManagerImpl implements GdbManager { * @param inferior the inferior to select * @return a future that completes when GDB has executed the command */ - CompletableFuture selectInferior(GdbInferior inferior) { + CompletableFuture setActiveInferior(GdbInferior inferior) { return execute(new GdbInferiorSelectCommand(this, inferior.getId())); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbStackFrameImpl.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbStackFrameImpl.java index 2910b188a0..c214a7b75f 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbStackFrameImpl.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbStackFrameImpl.java @@ -104,8 +104,8 @@ public class GdbStackFrameImpl implements GdbStackFrame { } @Override - public CompletableFuture select() { - return manager.execute(new GdbThreadSelectCommand(manager, thread.getId(), level)); + public CompletableFuture setActive() { + return manager.execute(new GdbSetActiveThreadCommand(manager, thread.getId(), level)); } @Override diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbThreadImpl.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbThreadImpl.java index 6bbe2b59f3..821c3a8746 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbThreadImpl.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/GdbThreadImpl.java @@ -128,7 +128,7 @@ public class GdbThreadImpl implements GdbThread { protected CompletableFuture execute(AbstractGdbCommand cmd) { switch (cmd.getInterpreter()) { case CLI: - return select().thenCombine(manager.execute(cmd), (__, v) -> v); + return setActive().thenCombine(manager.execute(cmd), (__, v) -> v); case MI2: return manager.execute(cmd); default: @@ -137,9 +137,9 @@ public class GdbThreadImpl implements GdbThread { } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { // Bypass the select-me-first logic - return manager.execute(new GdbThreadSelectCommand(manager, id, null)); + return manager.execute(new GdbSetActiveThreadCommand(manager, id, null)); } @Override diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbThreadSelectCommand.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbSetActiveThreadCommand.java similarity index 93% rename from Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbThreadSelectCommand.java rename to Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbSetActiveThreadCommand.java index a7ecc8bb47..704e4ec944 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbThreadSelectCommand.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/manager/impl/cmd/GdbSetActiveThreadCommand.java @@ -19,7 +19,7 @@ import agent.gdb.manager.evt.*; import agent.gdb.manager.impl.*; import agent.gdb.manager.parsing.GdbMiParser.GdbMiFieldList; -public class GdbThreadSelectCommand extends AbstractGdbCommandWithThreadAndFrameId { +public class GdbSetActiveThreadCommand extends AbstractGdbCommandWithThreadAndFrameId { /** * Select the given thread and frame level * @@ -30,7 +30,7 @@ public class GdbThreadSelectCommand extends AbstractGdbCommandWithThreadAndFrame * @param threadId the desired thread Id * @param frameId the desired frame level */ - public GdbThreadSelectCommand(GdbManagerImpl manager, int threadId, Integer frameId) { + public GdbSetActiveThreadCommand(GdbManagerImpl manager, int threadId, Integer frameId) { super(manager, threadId, frameId); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelSelectableObject.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelSelectableObject.java index 04558ac680..2e30a70cfb 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelSelectableObject.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelSelectableObject.java @@ -20,5 +20,5 @@ import java.util.concurrent.CompletableFuture; import ghidra.dbg.target.TargetObject; interface GdbModelSelectableObject extends TargetObject { - CompletableFuture select(); + CompletableFuture setActive(); } 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 a9c516252d..f90daf4c89 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 @@ -360,8 +360,8 @@ public class GdbModelTargetInferior @Override @Internal - public CompletableFuture select() { - return impl.gateFuture(inferior.select()); + public CompletableFuture setActive() { + return impl.gateFuture(inferior.setActive()); } @TargetAttributeType(name = EXIT_CODE_ATTRIBUTE_NAME) 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 d4a606c859..3c38b0f07e 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 @@ -34,16 +34,13 @@ import ghidra.dbg.target.schema.*; import ghidra.dbg.util.PathUtils; import ghidra.util.Msg; -@TargetObjectSchemaInfo( - name = "Session", - elements = { - @TargetElementType(type = Void.class) }, - attributes = { +@TargetObjectSchemaInfo(name = "Session", elements = { + @TargetElementType(type = Void.class) }, attributes = { @TargetAttributeType(type = Void.class) }) public class GdbModelTargetSession extends DefaultTargetModelRoot - implements TargetAccessConditioned, TargetAttacher, TargetFocusScope, TargetInterpreter, - TargetInterruptible, TargetCmdLineLauncher, TargetEventScope, GdbConsoleOutputListener, - GdbEventsListenerAdapter { + implements TargetAccessConditioned, TargetAttacher, TargetInterpreter, TargetInterruptible, + TargetCmdLineLauncher, TargetActiveScope, TargetEventScope, TargetFocusScope, + GdbConsoleOutputListener, GdbEventsListenerAdapter { protected static final String GDB_PROMPT = "(gdb)"; protected final GdbModelImpl impl; @@ -88,18 +85,12 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot return inferiors; } - @TargetAttributeType( - name = GdbModelTargetAvailableContainer.NAME, - required = true, - fixed = true) + @TargetAttributeType(name = GdbModelTargetAvailableContainer.NAME, required = true, fixed = true) public GdbModelTargetAvailableContainer getAvailable() { return available; } - @TargetAttributeType( - name = GdbModelTargetBreakpointContainer.NAME, - required = true, - fixed = true) + @TargetAttributeType(name = GdbModelTargetBreakpointContainer.NAME, required = true, fixed = true) public GdbModelTargetBreakpointContainer getBreakpoints() { return breakpoints; } @@ -240,7 +231,8 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot } @Override - public CompletableFuture requestFocus(TargetObject obj) { + public CompletableFuture requestActivation(TargetObject obj) { + System.err.println("requestActivation " + obj); impl.assertMine(TargetObject.class, obj); /** * Yes, this is pointless, since I'm the root, but do it right (TM), since this may change @@ -253,13 +245,31 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot while (cur != null) { if (cur instanceof GdbModelSelectableObject) { GdbModelSelectableObject sel = (GdbModelSelectableObject) cur; - /** - * Have to call setFocus here, since the call to select() is considered - * "internally-driven" - */ - return sel.select().thenRun(() -> { - setFocus(sel); - }); + return sel.setActive(); + } + cur = cur.getParent(); + } + return AsyncUtils.NIL; + + } + + @Override + public CompletableFuture requestFocus(TargetObject obj) { + System.err.println("requestFocus " + obj); + impl.assertMine(TargetObject.class, obj); + /** + * Yes, this is pointless, since I'm the root, but do it right (TM), since this may change + * or be used as an example for other implementations. + */ + if (!PathUtils.isAncestor(this.getPath(), obj.getPath())) { + throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope"); + } + TargetObject cur = obj; + while (cur != null) { + if (cur instanceof GdbModelSelectableObject) { + GdbModelSelectableObject sel = (GdbModelSelectableObject) cur; + setFocus(sel); + return AsyncUtils.NIL; } cur = cur.getParent(); } @@ -292,9 +302,8 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot GdbStateChangeRecord sco = new GdbStateChangeRecord(inf, threads, state, thread, cause, reason); - CompletableFuture infUpdates = CompletableFuture.allOf( - breakpoints.stateChanged(sco), - inferiors.stateChanged(sco)); + CompletableFuture infUpdates = + CompletableFuture.allOf(breakpoints.stateChanged(sco), inferiors.stateChanged(sco)); infUpdates.whenComplete((v, t) -> { if (thread == null) { return; @@ -303,10 +312,24 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot * I have to do this for all inferiors, because I don't know in what order they will * complete. */ - thread.select().exceptionally(ex -> { + thread.setActive().exceptionally(ex -> { impl.reportError(this, "Could not restore event thread", ex); return null; }); }); } + + @Override + public void threadStateChanged(GdbThread thread, GdbState state, GdbCause cause, + GdbReason reason) { + + /* REQUIRES GP-762 + TargetThread targetThread = (TargetThread) impl.getModelObject(thread); + changeAttributes(List.of(), List.of(), Map.of( // + TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread // + ), reason.desc()); + */ + + } + } 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 596cf23025..2c9d09f05e 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 @@ -114,8 +114,8 @@ public class GdbModelTargetStackFrame extends DefaultTargetObject select() { - return impl.gateFuture(frame.select()); + public CompletableFuture setActive() { + return impl.gateFuture(frame.setActive()); } @TargetAttributeType(name = FUNC_ATTRIBUTE_NAME) diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetThread.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetThread.java index c268453f48..0ea66a88ed 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetThread.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/model/impl/GdbModelTargetThread.java @@ -216,8 +216,8 @@ public class GdbModelTargetThread @Override @Internal - public CompletableFuture select() { - return impl.gateFuture(thread.select()); + public CompletableFuture setActive() { + return impl.gateFuture(thread.setActive()); } public GdbModelTargetBreakpointLocation breakpointHit(GdbBreakpointHitReason reason) { diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/manager/impl/AbstractGdbManagerTest.java b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/manager/impl/AbstractGdbManagerTest.java index d4eb228ca5..2706149f7c 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/manager/impl/AbstractGdbManagerTest.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/test/java/agent/gdb/manager/impl/AbstractGdbManagerTest.java @@ -412,7 +412,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg GdbThread thread = waitOn(mgr.currentInferior().run()); waitOn(mgr.waitForState(GdbState.STOPPED)); //waitOn(mgr.waitForPrompt()); - waitOn(thread.select()); + waitOn(thread.setActive()); } } diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/GadpRegistry.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/GadpRegistry.java index f928a38fa7..df4c4bb2f6 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/GadpRegistry.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/GadpRegistry.java @@ -65,6 +65,7 @@ public enum GadpRegistry { registerInterface(TargetEnvironment.class, GadpClientTargetEnvironment.class); registerInterface(TargetEventScope.class, GadpClientTargetEventScope.class); registerInterface(TargetExecutionStateful.class, GadpClientTargetExecutionStateful.class); + registerInterface(TargetActiveScope.class, GadpClientTargetActiveScope.class); registerInterface(TargetFocusScope.class, GadpClientTargetFocusScope.class); registerInterface(TargetInterpreter.class, GadpClientTargetInterpreter.class); registerInterface(TargetInterruptible.class, GadpClientTargetInterruptible.class); diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetActiveScope.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetActiveScope.java new file mode 100644 index 0000000000..1b10f5b7ea --- /dev/null +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/client/GadpClientTargetActiveScope.java @@ -0,0 +1,45 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.dbg.gadp.client; + +import java.util.concurrent.CompletableFuture; + +import ghidra.dbg.error.DebuggerIllegalArgumentException; +import ghidra.dbg.gadp.protocol.Gadp; +import ghidra.dbg.target.TargetActiveScope; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.util.PathUtils; + +public interface GadpClientTargetActiveScope extends GadpClientTargetObject, TargetActiveScope { + + @Override + default CompletableFuture requestActivation(TargetObject obj) { + getDelegate().assertValid(); + getModel().assertMine(TargetObject.class, obj); + // The server should detect this error, but we can detect it here without sending a request + if (!PathUtils.isAncestor(getPath(), obj.getPath())) { + throw new DebuggerIllegalArgumentException( + "Can only activate a successor of the scope"); + } + return getModel() + .sendChecked( + Gadp.ActivationRequest.newBuilder() + .setPath(GadpValueUtils.makePath(getPath())) + .setActive(GadpValueUtils.makePath(obj.getPath())), + Gadp.ActivationReply.getDefaultInstance()) + .thenApply(__ -> null); + } +} diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/server/GadpClientHandler.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/server/GadpClientHandler.java index 99e78af375..60a1bbba03 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/server/GadpClientHandler.java +++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/server/GadpClientHandler.java @@ -417,6 +417,8 @@ public class GadpClientHandler return processResume(msg.getSequence(), msg.getResumeRequest()); case STEP_REQUEST: return processStep(msg.getSequence(), msg.getStepRequest()); + case ACTIVATION_REQUEST: + return processActivation(msg.getSequence(), msg.getActivationRequest()); default: throw new GadpErrorException(Gadp.ErrorCode.EC_BAD_REQUEST, "Unrecognized request: " + msg.getMsgCase()); @@ -466,8 +468,8 @@ public class GadpClientHandler return ref; } - protected CompletableFuture sendDelta( - List parentPath, Delta deltaE, Delta deltaA) { + protected CompletableFuture sendDelta(List parentPath, + Delta deltaE, Delta deltaA) { return channel.write(Gadp.RootMessage.newBuilder() .setEventNotification(Gadp.EventNotification.newBuilder() .setPath(GadpValueUtils.makePath(parentPath)) @@ -627,6 +629,19 @@ public class GadpClientHandler }); } + protected CompletableFuture processActivation(int seqno, Gadp.ActivationRequest req) { + TargetActiveScope scope = getObjectChecked(req.getPath()).as(TargetActiveScope.class); + TargetObject active = getObjectChecked(req.getActive()); + return scope.requestActivation(active).thenCompose(__ -> { + return model.flushEvents(); + }).thenCompose(__ -> { + return channel.write(Gadp.RootMessage.newBuilder() + .setSequence(seqno) + .setActivationReply(Gadp.ActivationReply.getDefaultInstance()) + .build()); + }); + } + protected CompletableFuture processFocus(int seqno, Gadp.FocusRequest req) { TargetFocusScope scope = getObjectChecked(req.getPath()).as(TargetFocusScope.class); TargetObject focus = getObjectChecked(req.getFocus()); @@ -705,8 +720,7 @@ public class GadpClientHandler return channel.write(Gadp.RootMessage.newBuilder() .setSequence(seqno) .setMemoryReadReply( - Gadp.MemoryReadReply.newBuilder() - .setContent(ByteString.copyFrom(data))) + Gadp.MemoryReadReply.newBuilder().setContent(ByteString.copyFrom(data))) .build()); }); } diff --git a/Ghidra/Debug/Debugger-gadp/src/main/proto/gadp.proto b/Ghidra/Debug/Debugger-gadp/src/main/proto/gadp.proto index bf254bea39..e91cfefd4b 100644 --- a/Ghidra/Debug/Debugger-gadp/src/main/proto/gadp.proto +++ b/Ghidra/Debug/Debugger-gadp/src/main/proto/gadp.proto @@ -435,6 +435,15 @@ message CacheInvalidateEvent { message CacheInvalidateReply { } +message ActivationRequest { + Path path = 1; + Path active = 2; +} + +message ActivationReply { +} + + message FocusRequest { Path path = 1; Path focus = 2; @@ -578,5 +587,9 @@ message RootMessage { ResyncRequest resync_request = 125; ResyncReply resync_reply = 225; + + ActivationRequest activation_request = 126; + ActivationReply activation_reply = 226; + } } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnector.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnector.java index ee42321606..6eedb0861b 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnector.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetConnector.java @@ -89,7 +89,7 @@ public class JdiModelTargetConnector extends JdiModelTargetObjectImpl } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { connectors.setDefaultConnector(this); return CompletableFuture.completedFuture(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 d17397c305..aecc8e598b 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 @@ -89,7 +89,7 @@ public class JdiModelTargetProcess extends JdiModelTargetObjectImpl @Override @Internal - public CompletableFuture select() { + public CompletableFuture setActive() { return CompletableFuture.completedFuture(null); ///return thread.select(); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStackFrame.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStackFrame.java index 3b3bd67d7f..cf25dddc98 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStackFrame.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetStackFrame.java @@ -126,7 +126,7 @@ public class JdiModelTargetStackFrame extends JdiModelTargetObjectImpl implement } @Override - public CompletableFuture select() { + public CompletableFuture setActive() { ///return frame.select(); return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThread.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThread.java index e7a80234fc..df483e025a 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThread.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetThread.java @@ -299,7 +299,7 @@ public class JdiModelTargetThread extends JdiModelTargetObjectReference implemen @Override @Internal - public CompletableFuture select() { + public CompletableFuture setActive() { return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVM.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVM.java index 030bbe99ce..e10e2a589a 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVM.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/JdiModelTargetVM.java @@ -370,7 +370,7 @@ public class JdiModelTargetVM extends JdiModelTargetObjectImpl implements // @Override @Internal - public CompletableFuture select() { + public CompletableFuture setActive() { return CompletableFuture.completedFuture(null); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelSelectableObject.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelSelectableObject.java index 1f2415cb74..824954fd18 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelSelectableObject.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelSelectableObject.java @@ -21,6 +21,6 @@ import ghidra.dbg.jdi.model.iface2.JdiModelTargetObject; public interface JdiModelSelectableObject extends JdiModelTargetObject { - public CompletableFuture select(); + public CompletableFuture setActive(); } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelTargetFocusScope.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelTargetFocusScope.java index 9753cfffe0..67ed6a9b93 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelTargetFocusScope.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/model/iface1/JdiModelTargetFocusScope.java @@ -55,7 +55,7 @@ public interface JdiModelTargetFocusScope extends JdiModelTargetObject, TargetFo if (cur instanceof JdiModelSelectableObject) { JdiModelSelectableObject sel = (JdiModelSelectableObject) cur; setFocus(sel); - return sel.select(); + return sel.setActive(); } cur = cur.getParent(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java index 5f20740de9..ffe529eb41 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java @@ -205,7 +205,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi @Override public void mousePressed(MouseEvent e) { - requestFocus(); + requestFocus(); // COMPONENT ctrlPressed = false; currentRectangle = null; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index d2b8826094..acf5498a42 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -481,7 +481,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter public void modelActivated(DebuggerObjectModel model) { //TODO: what do we want here - change of focus, selection? if (model != null && model.equals(currentModel)) { - this.requestFocus(); + this.requestFocus(); // COMPONENT this.toFront(); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java index 761a952f3f..5d61267d11 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java @@ -156,16 +156,10 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode if (provider != null) { ObjectContainer rootContainer = provider.getRoot(); Map rootMap = rootContainer.getAttributeMap(); - String cname = container.getDecoratedName(); - if (rootMap.containsKey(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME)) { - String id = (String) rootMap.get(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME); - if (cname.contains("0x" + id)) { - return ICON_EVENT; - } - } - if (rootMap.containsKey(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME)) { - String id = (String) rootMap.get(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME); - if (cname.contains("0x" + id)) { + if (rootMap.containsKey(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME)) { + TargetThread targetProcess = + (TargetThread) rootMap.get(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME); + if (container.getTargetObject().equals(targetProcess)) { return ICON_EVENT; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java index f17483884d..068652f921 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java @@ -85,6 +85,10 @@ public class ObjectTree implements ObjectPane { TargetObject targetObject = node.getTargetObject(); if (targetObject != null && !(targetObject instanceof DummyTargetObject) && e.getEventOrigin().equals(EventOrigin.USER_GENERATED)) { + DebugModelConventions.requestActivation(targetObject).exceptionally(ex -> { + Msg.error(this, "Could not activate " + targetObject, ex); + return null; + }); DebugModelConventions.requestFocus(targetObject).exceptionally(ex -> { Msg.error(this, "Could not focus " + targetObject, ex); return null; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProvider.java index 2645645496..c3ccd35556 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsProvider.java @@ -31,6 +31,7 @@ import docking.widgets.EventTrigger; import docking.widgets.HorizontalTabPanel; import docking.widgets.HorizontalTabPanel.TabListCellRenderer; import docking.widgets.table.*; +import docking.widgets.timeline.TimelineListener; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.gui.DebuggerResources; @@ -39,6 +40,8 @@ import ghidra.app.plugin.core.debug.gui.DebuggerSnapActionContext; import ghidra.app.plugin.core.debug.gui.thread.DebuggerThreadsTimelinePanel.VetoableSnapRequestListener; import ghidra.app.services.*; import ghidra.app.services.DebuggerTraceManagerService.BooleanChangeAdapter; +import ghidra.dbg.DebugModelConventions; +import ghidra.dbg.target.TargetThread; import ghidra.framework.model.DomainObject; import ghidra.framework.plugintool.AutoService; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -345,6 +348,13 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter { private ActionContext myActionContext; + private final TimelineListener timelineListener = new TimelineListener() { + @Override + public void itemActivated(int index) { + timelineItemActivated(index); + } + }; + DockingAction actionSaveTrace; StepSnapBackwardAction actionStepSnapBackward; StepTickBackwardAction actionStepTickBackward; @@ -543,6 +553,23 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter { contextChanged(); } + private void timelineItemActivated(int index) { + ThreadRow row = threadTableModel.getRowObject(index); + rowActivated(row); + } + + private void rowActivated(ThreadRow row) { + TraceThread thread = row.getThread(); + Trace trace = thread.getTrace(); + TraceRecorder recorder = modelService.getRecorder(trace); + if (recorder != null) { + TargetThread targetThread = recorder.getTargetThread(thread); + if (targetThread != null && targetThread.isValid()) { + DebugModelConventions.requestActivation(targetThread); + } + } + } + protected void buildMainPanel() { traceTabPopupMenu = new JPopupMenu("Trace"); @@ -566,6 +593,16 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter { threadTable.getSelectionModel().addListSelectionListener(this::threadRowSelected); threadTimeline.setSelectionModel(threadTable.getSelectionModel()); threadTimeline.addSnapRequestedListener(snapListener); + threadTimeline.addTimelineListener(timelineListener); + + threadTable.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(MouseEvent e) { + int selectedRow = threadTable.getSelectedRow(); + ThreadRow row = threadTableModel.getRowObject(selectedRow); + rowActivated(row); + } + }); mainPanel.add(splitPane, BorderLayout.CENTER); @@ -628,18 +665,15 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter { closeItem.addActionListener(evt -> { traceManager.closeTrace(trace); }); - JMenuItem closeOthers = - new JMenuItem("Close Others", DebuggerResources.ICON_CLOSE); + JMenuItem closeOthers = new JMenuItem("Close Others", DebuggerResources.ICON_CLOSE); closeOthers.addActionListener(evt -> { traceManager.closeOtherTraces(trace); }); - JMenuItem closeDead = - new JMenuItem("Close Dead", DebuggerResources.ICON_CLOSE); + JMenuItem closeDead = new JMenuItem("Close Dead", DebuggerResources.ICON_CLOSE); closeDead.addActionListener(evt -> { traceManager.closeDeadTraces(); }); - JMenuItem closeAll = - new JMenuItem("Close All", DebuggerResources.ICON_CLOSE); + JMenuItem closeAll = new JMenuItem("Close All", DebuggerResources.ICON_CLOSE); closeAll.addActionListener(evt -> { for (Trace t : List.copyOf(traceManager.getOpenTraces())) { traceManager.closeTrace(t); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsTimelinePanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsTimelinePanel.java index 8793b6ccbe..dacb0ada5c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsTimelinePanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsTimelinePanel.java @@ -27,8 +27,9 @@ import com.google.common.collect.Range; import docking.widgets.*; import docking.widgets.RangeCursorPanel.Direction; import docking.widgets.table.RowObjectTableModel; +import docking.widgets.timeline.TimelineListener; import docking.widgets.timeline.TimelinePanel; -import docking.widgets.timeline.TimelineViewRangeListener; +import ghidra.app.services.DebuggerModelService; import ghidra.trace.model.thread.TraceThread; import ghidra.util.datastruct.ListenerSet; @@ -56,8 +57,11 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane { } protected class ThreadTimelinePanel extends TimelinePanel { + protected final RowObjectTableModel model; + public ThreadTimelinePanel(RowObjectTableModel model) { super(model, ThreadRow::getLifespan); + this.model = model; } } @@ -95,9 +99,17 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane { protected final ListenerSet listeners = new ListenerSet<>(VetoableSnapRequestListener.class); protected final RangeCursorValueListener valueListener = this::cursorValueChanged; - protected final TimelineViewRangeListener viewRangeListener = this::viewRangeChanged; + protected final TimelineListener timelineListener = new TimelineListener() { + @Override + public void viewRangeChanged(Range range) { + timelineViewRangeChanged(range); + } + }; + private DebuggerModelService modelService; + private RowObjectTableModel model; public DebuggerThreadsTimelinePanel(RowObjectTableModel model) { + this.model = model; setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); @@ -106,7 +118,7 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane { setColumnHeaderView(topCursor); topCursor.addValueListener(valueListener); - timeline.addViewRangeListener(viewRangeListener); + timeline.addTimelineListener(timelineListener); } public void addSnapRequestedListener(VetoableSnapRequestListener listener) { @@ -122,7 +134,7 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane { } } - private void viewRangeChanged(Range range) { + private void timelineViewRangeChanged(Range range) { topCursor.setRange(range); } @@ -166,4 +178,8 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane { } return timeline.getCellBounds(row); } + + public void addTimelineListener(TimelineListener listener) { + timeline.addTimelineListener(listener); + } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java index 0949cba345..9347b14967 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java @@ -78,8 +78,7 @@ import ghidra.util.task.*; ModelObjectFocusedPluginEvent.class, TraceRecorderAdvancedPluginEvent.class, }, - servicesRequired = { - }, + servicesRequired = {}, servicesProvided = { DebuggerTraceManagerService.class, }) diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsPluginScreenShots.java index 91d39f7c7c..2c52fe4582 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsPluginScreenShots.java @@ -105,11 +105,6 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator @Test public void testCaptureDebuggerObjectsPlugin() throws Throwable { mb.createTestModel("Debugger"); - mb.testModel.session.setAttributes(List.of(), Map.of( - TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, "1a12", // Get arrow icon on process - TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, "1a34", // Get arrow icon on thread - TargetObject.DISPLAY_ATTRIBUTE_NAME, "Debugger"), - "TestOverride"); DefaultTestTargetObject available = new DefaultTestTargetObject<>(mb.testModel.session, "Available", ""); @@ -135,8 +130,7 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator new DefaultTestTargetObject<>(process1a12, "Devices", ""); DefaultTestTargetObject pEnvironment = new DefaultTestTargetObject<>(process1a12, "Environment", ""); - DefaultTestTargetObject pIo = - new DefaultTestTargetObject<>(process1a12, "Io", ""); + DefaultTestTargetObject pIo = new DefaultTestTargetObject<>(process1a12, "Io", ""); DefaultTestTargetObject pMemory = new DefaultTestTargetObject<>(process1a12, "Memory", ""); DefaultTestTargetObject pModules = @@ -147,6 +141,11 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator DefaultTestTargetObject thread1a34 = new ActionyTestTargetObject(pThreads, "[0x1a34]", ""); + mb.testModel.session.setAttributes(List.of(), + Map.of(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, thread1a34, // Get arrow icon on thread + TargetObject.DISPLAY_ATTRIBUTE_NAME, "Debugger"), + "TestOverride"); + DefaultTestTargetObject tEnvironment = new DefaultTestTargetObject<>(thread1a34, "Environment", ""); @@ -155,81 +154,45 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator DefaultTestTargetObject activationContextStackPointer = new DefaultTestTargetObject<>(teEnvBlock, "ActivationContextStackPointer", ""); - activationContextStackPointer.setAttributes(List.of(), Map.of( - TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActivationContextStackPointer : 789abc", - "_modified", true), - "Initialized"); + activationContextStackPointer + .setAttributes(List.of(), + Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, + "ActivationContextStackPointer : 789abc", "_modified", true), + "Initialized"); DefaultTestTargetObject activeFrame = new DefaultTestTargetObject<>(teEnvBlock, "ActiveFrame", ""); - activeFrame.setAttributes(List.of(), Map.of( - TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActiveFrame : 0", - "_modified", true), + activeFrame.setAttributes(List.of(), + Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActiveFrame : 0", "_modified", true), "Initialized"); DefaultTestTargetObject bogusFocus = new DefaultTestTargetObject<>(teEnvBlock, "BOGUS FOCUS", ""); - teEnvBlock.setAttributes( - List.of( - activationContextStackPointer, - activeFrame, - bogusFocus), - Map.of( - "_kind", "OBJECT_TARGET_OBJECT"), // Makes it magenta + teEnvBlock.setAttributes(List.of(activationContextStackPointer, activeFrame, bogusFocus), + Map.of("_kind", "OBJECT_TARGET_OBJECT"), // Makes it magenta "Initialized"); - tEnvironment.setAttributes(List.of( - teEnvBlock), - Map.of(), "Initialized"); + tEnvironment.setAttributes(List.of(teEnvBlock), Map.of(), "Initialized"); - thread1a34.setAttributes( - List.of( - tEnvironment), - Map.of( - TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a34"), - "Initialized"); + thread1a34.setAttributes(List.of(tEnvironment), + Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a34"), "Initialized"); - pThreads.setElements(List.of( - thread1a34), - Map.of(), "Initialized"); + pThreads.setElements(List.of(thread1a34), Map.of(), "Initialized"); process1a12.setAttributes( - List.of( - pDebug, - pDevices, - pEnvironment, - pIo, - pMemory, - pModules, - pThreads), - Map.of( - TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a12", - "Handle", "321", - "Id", "1a12", + List.of(pDebug, pDevices, pEnvironment, pIo, pMemory, pModules, pThreads), + Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a12", "Handle", "321", "Id", "1a12", "Name", "winmine.exe"), "Initialized"); - sProcesses.setElements(List.of( - process1a12), - Map.of(), "Initialized"); + sProcesses.setElements(List.of(process1a12), Map.of(), "Initialized"); - session0.setAttributes( - List.of( - sAttributes, - sDevices, - sProcesses), - Map.of( - TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x0", - "Id", 0), + session0.setAttributes(List.of(sAttributes, sDevices, sProcesses), + Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x0", "Id", 0), "Initialized"); + + sessions.setElements(List.of(session0), Map.of(), "Initialized"); + + mb.testModel.session.changeAttributes(List.of(), List.of(available, sessions), Map.of(), "Initialized"); - sessions.setElements(List.of( - session0), - Map.of(), "Initialized"); - - mb.testModel.session.changeAttributes(List.of(), List.of( - available, - sessions), - Map.of(), "Initialized"); - Swing.runNow(() -> { modelService.addModel(mb.testModel); modelService.activateModel(mb.testModel); 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 5ad3ff8fab..36df370004 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 @@ -813,6 +813,26 @@ public enum DebugModelConventions { return collectAncestors.thenApply(AllRequiredAccess::new); } + /** + * Request activation of the given object in its nearest active scope + * + *

+ * Note if the object has no suitable active scope, this method fails silently. + * + * @param obj the object on which to request activation + * @return a future which completes when activation is granted, or exceptionally + */ + public static CompletableFuture requestActivation(TargetObject obj) { + CompletableFuture futureActivator = + DebugModelConventions.findSuitable(TargetActiveScope.class, obj); + return futureActivator.thenCompose(activator -> { + if (activator == null) { + return AsyncUtils.NIL; + } + return activator.requestActivation(obj); + }); + } + /** * Request focus on the given object in its nearest focus scope * diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetActiveScope.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetActiveScope.java new file mode 100644 index 0000000000..e146f77966 --- /dev/null +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetActiveScope.java @@ -0,0 +1,38 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.dbg.target; + +import java.util.concurrent.CompletableFuture; + +import ghidra.dbg.DebuggerTargetObjectIface; + +/** + * An object made active + * + * "Active" here describes which object in a given class the target should operate on + */ +@DebuggerTargetObjectIface("ActiveScope") +public interface TargetActiveScope extends TargetObject { + + /** + * Set the given object as the target's active object for the given type + * + * @param obj the object to setActive + * @return a future which completes upon successfully changing focus. + */ + CompletableFuture requestActivation(TargetObject obj); + +} diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetEventScope.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetEventScope.java index c89f66b69b..f930a2a6c1 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetEventScope.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetEventScope.java @@ -27,8 +27,7 @@ import ghidra.dbg.target.schema.TargetAttributeType; @DebuggerTargetObjectIface("EventScope") public interface TargetEventScope extends TargetObject { - String EVENT_PROCESS_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_process"; - String EVENT_THREAD_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_thread"; + String EVENT_OBJECT_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_thread"; public enum TargetEventType { /** @@ -116,33 +115,13 @@ public interface TargetEventScope extends TargetObject { } } - /** - * If applicable, get the process producing the last reported event - * - *

- * TODO: This is currently the hexadecimal PID. It should really be a ref to the process object. - * - *

- * TODO: Since the event thread will be a successor of the event process, this may not be - * needed, but perhaps keep it for convenience. - * - * @return the process or reference - */ - @TargetAttributeType(name = EVENT_PROCESS_ATTRIBUTE_NAME, hidden = true) - public default /*TODO: TargetProcess*/ String getEventProcess() { - return getTypedAttributeNowByName(EVENT_PROCESS_ATTRIBUTE_NAME, String.class, null); - } - /** * If applicable, get the thread producing the last reported event * - *

- * TODO: This is currently the hexadecimal TID. It should really be a ref to the thread object. - * * @return the thread or reference */ - @TargetAttributeType(name = EVENT_THREAD_ATTRIBUTE_NAME, hidden = true) - public default /*TODO: TargetThread*/ String getEventThread() { - return getTypedAttributeNowByName(EVENT_THREAD_ATTRIBUTE_NAME, String.class, null); + @TargetAttributeType(name = EVENT_OBJECT_ATTRIBUTE_NAME, hidden = true) + public default TargetThread getEventThread() { + return getTypedAttributeNowByName(EVENT_OBJECT_ATTRIBUTE_NAME, TargetThread.class, null); } } 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 523615a3fd..bea48f48b7 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 @@ -158,20 +158,21 @@ import ghidra.lifecycle.Internal; */ public interface TargetObject extends Comparable { - Set> ALL_INTERFACES = Set.of(TargetAccessConditioned.class, - TargetAggregate.class, TargetAttachable.class, TargetAttacher.class, - TargetBreakpointLocation.class, TargetBreakpointLocationContainer.class, - TargetBreakpointSpec.class, TargetBreakpointSpecContainer.class, TargetConsole.class, - TargetDataTypeMember.class, TargetDataTypeNamespace.class, TargetDeletable.class, - TargetDetachable.class, TargetEnvironment.class, TargetEventScope.class, - TargetExecutionStateful.class, TargetFocusScope.class, TargetInterpreter.class, - TargetInterruptible.class, TargetKillable.class, TargetLauncher.class, TargetMemory.class, - TargetMemoryRegion.class, TargetMethod.class, TargetModule.class, - TargetModuleContainer.class, TargetNamedDataType.class, TargetProcess.class, - TargetRegister.class, TargetRegisterBank.class, TargetRegisterContainer.class, - TargetResumable.class, TargetSection.class, TargetSectionContainer.class, TargetStack.class, - TargetStackFrame.class, TargetSteppable.class, TargetSymbol.class, - TargetSymbolNamespace.class, TargetThread.class, TargetTogglable.class); + Set> ALL_INTERFACES = + Set.of(TargetAccessConditioned.class, TargetAggregate.class, TargetAttachable.class, + TargetAttacher.class, TargetBreakpointLocation.class, + TargetBreakpointLocationContainer.class, TargetBreakpointSpec.class, + TargetBreakpointSpecContainer.class, TargetConsole.class, TargetDataTypeMember.class, + TargetDataTypeNamespace.class, TargetDeletable.class, TargetDetachable.class, + TargetEnvironment.class, TargetEventScope.class, TargetExecutionStateful.class, + TargetActiveScope.class, TargetFocusScope.class, TargetInterpreter.class, + TargetInterruptible.class, TargetKillable.class, TargetLauncher.class, + TargetMemory.class, TargetMemoryRegion.class, TargetMethod.class, TargetModule.class, + TargetModuleContainer.class, TargetNamedDataType.class, TargetProcess.class, + TargetRegister.class, TargetRegisterBank.class, TargetRegisterContainer.class, + TargetResumable.class, TargetSection.class, TargetSectionContainer.class, + TargetStack.class, TargetStackFrame.class, TargetSteppable.class, TargetSymbol.class, + TargetSymbolNamespace.class, TargetThread.class, TargetTogglable.class); Map> INTERFACES_BY_NAME = initInterfacesByName(); /** @@ -300,8 +301,7 @@ public interface TargetObject extends Comparable { return false; } TargetObject that = (TargetObject) obj; - return this.getModel() == that.getModel() && - Objects.equals(this.getPath(), that.getPath()); + return this.getModel() == that.getModel() && Objects.equals(this.getPath(), that.getPath()); } /** @@ -371,8 +371,7 @@ public interface TargetObject extends Comparable { } int result = thisModel.toString().compareTo(thatModel.toString()); if (result == 0) { - return Integer.compare( - System.identityHashCode(thisModel), + return Integer.compare(System.identityHashCode(thisModel), System.identityHashCode(thatModel)); } return result; @@ -707,8 +706,7 @@ public interface TargetObject extends Comparable { * interface */ public default // - CompletableFuture> fetchChildrenSupporting( - Class iface) { + CompletableFuture> fetchChildrenSupporting(Class iface) { return fetchChildren().thenApply(m -> m.entrySet() .stream() .filter(e -> iface.isAssignableFrom(e.getValue().getClass())) @@ -793,8 +791,7 @@ public interface TargetObject extends Comparable { /** * @see #fetchSubAttributes(List) */ - public default CompletableFuture> fetchSubAttributes( - String... sub) { + public default CompletableFuture> fetchSubAttributes(String... sub) { return fetchSubAttributes(List.of(sub)); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineViewRangeListener.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineListener.java similarity index 82% rename from Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineViewRangeListener.java rename to Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineListener.java index 3001c95c77..03ecd7a9bc 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineViewRangeListener.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelineListener.java @@ -17,6 +17,10 @@ package docking.widgets.timeline; import com.google.common.collect.Range; -public interface TimelineViewRangeListener { - void viewRangeChanged(Range viewRange); +public interface TimelineListener { + default void viewRangeChanged(Range viewRange) { + } + + default void itemActivated(int index) { + } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java index 41676f5929..4855f19c48 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java @@ -433,6 +433,7 @@ public class TimelinePanel> extends JPanel { } protected class CellMouseListener extends MouseAdapter { + @Override public void mouseClicked(MouseEvent e) { Component cell = e.getComponent(); @@ -454,6 +455,7 @@ public class TimelinePanel> extends JPanel { else { selectionModel.setSelectionInterval(index, index); } + timelineListeners.fire.itemActivated(index); } } @@ -481,8 +483,8 @@ public class TimelinePanel> extends JPanel { protected final ItemTracker rows = new ItemTracker(); protected final List> tracks = new ArrayList<>(); protected final Map> trackMap = new HashMap<>(); - protected final ListenerSet viewRangeListeners = - new ListenerSet<>(TimelineViewRangeListener.class); + protected final ListenerSet timelineListeners = + new ListenerSet<>(TimelineListener.class); protected final MouseListener mouseListener = new CellMouseListener(); protected final FocusListener focusListener = new CellFocusListener(); @@ -497,12 +499,12 @@ public class TimelinePanel> extends JPanel { setSelectionModel(new DefaultListSelectionModel()); } - public void addViewRangeListener(TimelineViewRangeListener listener) { - viewRangeListeners.add(listener); + public void addTimelineListener(TimelineListener listener) { + timelineListeners.add(listener); } - public void removeViewRangeListener(TimelineViewRangeListener listener) { - viewRangeListeners.remove(listener); + public void removeTimelineListener(TimelineListener listener) { + timelineListeners.remove(listener); } protected Range computeViewRange() { @@ -765,7 +767,7 @@ public class TimelinePanel> extends JPanel { track.setViewRange(newViewRange); } validate(); - viewRangeListeners.fire.viewRangeChanged(newViewRange); + timelineListeners.fire.viewRangeChanged(newViewRange); } public Range getViewRange() { @@ -777,10 +779,8 @@ public class TimelinePanel> extends JPanel { UIManager.getDefaults() .entrySet() .stream() - .filter( - ent -> cls.isInstance(ent.getValue())) - .forEach( - ent -> sorted.put(ent.getKey(), cls.cast(ent.getValue()))); + .filter(ent -> cls.isInstance(ent.getValue())) + .forEach(ent -> sorted.put(ent.getKey(), cls.cast(ent.getValue()))); for (Entry ent : sorted.entrySet()) { System.out.println(String.format("%s=%s", ent.getKey(), fmt.apply(ent.getValue()))); }