diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugModuleInfo.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugModuleInfo.java index c8a87dfb0c..a0b378fe49 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugModuleInfo.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugModuleInfo.java @@ -41,4 +41,8 @@ public class DebugModuleInfo { this.checkSum = checkSum; this.timeDateStamp = timeDateStamp; // TODO: Convert to DateTime? } + + public String toString() { + return Long.toHexString(baseOffset); + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/gadp/impl/AbstractClientThreadExecutor.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/gadp/impl/AbstractClientThreadExecutor.java index 69d913a42c..324f7e3330 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/gadp/impl/AbstractClientThreadExecutor.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/gadp/impl/AbstractClientThreadExecutor.java @@ -217,6 +217,10 @@ public abstract class AbstractClientThreadExecutor extends AbstractExecutorServi } } + public boolean isCurrentThread() { + return thread.equals(Thread.currentThread()); + } + /** * Schedule a task with the given priority, taking a reference to the client. * diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java index 9064c41eca..690750736d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java @@ -130,7 +130,7 @@ public interface DbgEventsListener { * @param name the name of the module on the target * @param cause the cause of this event */ - void moduleLoaded(DbgProcess process, String name, DbgCause cause); + void moduleLoaded(DbgProcess process, DebugModuleInfo info, DbgCause cause); /** * A module has been unloaded from an process @@ -139,7 +139,7 @@ public interface DbgEventsListener { * @param name the name of the module on the target * @param cause the cause of this event */ - void moduleUnloaded(DbgProcess process, String name, DbgCause cause); + void moduleUnloaded(DbgProcess process, DebugModuleInfo info, DbgCause cause); /** * A breakpoint has been created in the session diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java index dacfad1b72..17e9343b34 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java @@ -83,12 +83,12 @@ public interface DbgEventsListenerAdapter extends DbgEventsListener { } @Override - public default void moduleLoaded(DbgProcess process, String name, DbgCause cause) { + public default void moduleLoaded(DbgProcess process, DebugModuleInfo info, DbgCause cause) { // Extension point } @Override - public default void moduleUnloaded(DbgProcess process, String name, DbgCause cause) { + public default void moduleUnloaded(DbgProcess process, DebugModuleInfo info, DbgCause cause) { // Extension point } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/breakpoint/DbgBreakpointInfo.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/breakpoint/DbgBreakpointInfo.java index 83bd88f4fc..1ac4e7fe7c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/breakpoint/DbgBreakpointInfo.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/breakpoint/DbgBreakpointInfo.java @@ -86,12 +86,17 @@ public class DbgBreakpointInfo { return Objects.hash(number, bptType, getFlags(), location, enabled, access, size); } + public String toString() { + return Integer.toHexString(bpt.getId()); + } + /* @Override public String toString() { return ""; } + */ @Override public boolean equals(Object obj) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java index baa54aa42e..d072b8837b 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java @@ -16,7 +16,7 @@ package agent.dbgeng.manager.cmd; import agent.dbgeng.manager.*; -import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; +import agent.dbgeng.manager.evt.DbgCommandDoneEvent; import agent.dbgeng.manager.impl.DbgManagerImpl; /** @@ -43,8 +43,8 @@ public abstract class AbstractDbgCommand implements DbgCommand { @Override public boolean handle(DbgEvent evt, DbgPendingCommand pending) { - if (evt instanceof AbstractDbgCompletedCommandEvent) { - if (pending.getCommand().equals(this)) { + if (evt instanceof DbgCommandDoneEvent) { + if (pending.getCommand().equals(((DbgCommandDoneEvent) evt).getCmd())) { return true; } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java index 17151c301c..5f00478ad9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java @@ -18,7 +18,6 @@ package agent.dbgeng.manager.cmd; import java.util.*; import agent.dbgeng.dbgeng.*; -import agent.dbgeng.dbgeng.DebugModule.DebugModuleName; import agent.dbgeng.manager.DbgModule; import agent.dbgeng.manager.impl.*; import ghidra.util.Msg; @@ -43,8 +42,8 @@ public class DbgListModulesCommand extends AbstractDbgCommand(cur)) { @@ -63,7 +62,7 @@ public class DbgListModulesCommand extends AbstractDbgCommand { + + private DbgModelTargetFocusScope scope; + private TargetObjectRef ref; + + /** + * Set focus for the current ref + * + * @param manager the manager to execute the command + * @param scope in most cases the root object (must be an ancestor for the ref) + * @param ref the desired focus + */ + public DbgRequestFocusCommand(DbgManagerImpl manager, DbgModelTargetFocusScope scope, + TargetObjectRef ref) { + super(manager); + this.scope = scope; + this.ref = ref; + } + + @Override + public void invoke() { + scope.doRequestFocus(ref); + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgCommandDoneEvent.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgCommandDoneEvent.java index 04d703ad8a..b8ca0bd86e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgCommandDoneEvent.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgCommandDoneEvent.java @@ -15,6 +15,7 @@ */ package agent.dbgeng.manager.evt; +import agent.dbgeng.manager.DbgCommand; import agent.dbgeng.manager.DbgState; /** @@ -22,6 +23,8 @@ import agent.dbgeng.manager.DbgState; */ public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent { + private DbgCommand cmd; + /** * Construct a new event, parsing the tail for information */ @@ -29,8 +32,9 @@ public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent { super(); } - public DbgCommandDoneEvent(String info) { - super(info); + public DbgCommandDoneEvent(DbgCommand cmd) { + super(cmd.toString()); + this.cmd = cmd; } @Override @@ -38,4 +42,8 @@ public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent { return DbgState.STOPPED; } + public DbgCommand getCmd() { + return cmd; + } + } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgStateChangedEvent.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgStateChangedEvent.java index a642200b63..a3ae5848e6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgStateChangedEvent.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/evt/DbgStateChangedEvent.java @@ -17,8 +17,8 @@ package agent.dbgeng.manager.evt; import agent.dbgeng.dbgeng.DebugClient.ChangeEngineState; import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgStackFrameImpl; -import agent.dbgeng.manager.impl.DbgThreadImpl; import ghidra.comm.util.BitmaskSet; public class DbgStateChangedEvent extends AbstractDbgEvent> { @@ -38,7 +38,7 @@ public class DbgStateChangedEvent extends AbstractDbgEvent { private final DebugThreadId id; private DbgState state; - private DbgThreadImpl thread; + private DbgThread thread; private DbgStackFrameImpl frame; /** @@ -35,7 +36,7 @@ public class DbgThreadSelectedEvent extends AbstractDbgEvent { * @param frame * @param id dbgeng-provided id */ - public DbgThreadSelectedEvent(DbgState state, DbgThreadImpl thread, DbgStackFrameImpl frame) { + public DbgThreadSelectedEvent(DbgState state, DbgThread thread, DbgStackFrameImpl frame) { super(thread.getId()); this.id = thread.getId(); this.state = state; @@ -57,7 +58,7 @@ public class DbgThreadSelectedEvent extends AbstractDbgEvent { } public DbgThreadImpl getThread() { - return thread; + return (DbgThreadImpl) thread; } public DbgStackFrameImpl getFrame() { 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 09a299f6eb..2f8f3d9620 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 @@ -15,7 +15,7 @@ */ package agent.dbgeng.manager.impl; -import static ghidra.async.AsyncUtils.sequence; +import static ghidra.async.AsyncUtils.*; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -40,9 +40,11 @@ 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.DbgModelTargetFocusScope; import ghidra.async.*; +import ghidra.async.seq.AsyncSequenceHandlerForRunner; import ghidra.comm.util.BitmaskSet; -import ghidra.dbg.error.DebuggerModelAccessException; +import ghidra.dbg.attributes.TargetObjectRef; import ghidra.dbg.util.HandlerMap; import ghidra.lifecycle.Internal; import ghidra.util.Msg; @@ -99,6 +101,12 @@ public class DbgManagerImpl implements DbgManager { new ListenerSet<>(DbgEventsListener.class); private DebugEventInformation lastEventInformation; + private DbgSession currentSession; + private DbgProcess currentProcess; + private DbgThread currentThread; + private DbgSession eventSession; + private DbgProcess eventProcess; + private DbgThread eventThread; private volatile boolean waiting = false; private boolean kernelMode = false; @@ -411,28 +419,44 @@ public class DbgManagerImpl implements DbgManager { assert cmd != null; checkStarted(); DbgPendingCommand pcmd = new DbgPendingCommand<>(cmd); - if (isWaiting()) { - throw new DebuggerModelAccessException( - "Cannot process command " + cmd.toString() + " while engine is waiting for events"); + //if (isWaiting()) { + // throw new DebuggerModelAccessException( + // "Cannot process command " + cmd.toString() + " while engine is waiting for events"); + //} + + if (engThread.isCurrentThread()) { + sequence(TypeSpec.VOID).then((seq) -> { + addCommand(cmd, pcmd, seq); + seq.exit(); + }).finish().exceptionally((exc) -> { + pcmd.completeExceptionally(exc); + return null; + }); + } + else { + sequence(TypeSpec.VOID).then(engThread, (seq) -> { + addCommand(cmd, pcmd, seq); + seq.exit(); + }).finish().exceptionally((exc) -> { + pcmd.completeExceptionally(exc); + return null; + }); } - sequence(TypeSpec.VOID).then(engThread, (seq) -> { - synchronized (this) { - if (!cmd.validInState(state.get())) { - throw new DbgCommandError( - "Command " + cmd + " is not valid while " + state.get()); - } - activeCmds.add(pcmd); - } - cmd.invoke(); - processEvent(new DbgCommandDoneEvent(cmd.toString())); - seq.exit(); - }).finish().exceptionally((exc) -> { - pcmd.completeExceptionally(exc); - return null; - }); return pcmd; } + private void addCommand(DbgCommand cmd, DbgPendingCommand pcmd, + AsyncSequenceHandlerForRunner seq) { + synchronized (this) { + if (!cmd.validInState(state.get())) { + throw new DbgCommandError("Command " + cmd + " is not valid while " + state.get()); + } + activeCmds.add(pcmd); + } + cmd.invoke(); + processEvent(new DbgCommandDoneEvent(cmd)); + } + /*@Override public DbgPendingCommand execute1(DbgCommand cmd) { assert cmd != null; @@ -586,9 +610,13 @@ public class DbgManagerImpl implements DbgManager { lastEventInformation = control.getLastEventInformation(); lastEventInformation.setSession(esid); lastEventInformation.setExecutingProcessorType(execType); - DbgThreadImpl eventThread = threads.get(etid); + currentSession = eventSession = getSessionComputeIfAbsent(esid); + currentProcess = + eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId()); + currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess, + so.getCurrentThreadSystemId()); if (eventThread != null) { - eventThread.setInfo(lastEventInformation); + ((DbgThreadImpl) eventThread).setInfo(lastEventInformation); } return etid; } @@ -658,8 +686,7 @@ public class DbgManagerImpl implements DbgManager { DebugThreadId eventId = updateState(); DbgProcessImpl process = getCurrentProcess(); int tid = so.getCurrentThreadSystemId(); - DbgThreadImpl thread = new DbgThreadImpl(this, process, eventId, tid); - thread.add(); + DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid); getEventListeners().fire.threadSelected(thread, null, evt.getCause()); String key = Integer.toHexString(eventId.id); @@ -703,9 +730,9 @@ public class DbgManagerImpl implements DbgManager { protected DebugStatus processThreadSelected(DbgThreadSelectedEvent evt, Void v) { DebugThreadId eventId = updateState(); - DbgThreadImpl thread = evt.getThread(); - thread.setState(evt.getState(), evt.getCause(), evt.getReason()); - getEventListeners().fire.threadSelected(thread, evt.getFrame(), evt.getCause()); + currentThread = evt.getThread(); + currentThread.setState(evt.getState(), evt.getCause(), evt.getReason()); + getEventListeners().fire.threadSelected(currentThread, evt.getFrame(), evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -722,6 +749,7 @@ public class DbgManagerImpl implements DbgManager { * @return retval handling/break status */ protected DebugStatus processProcessCreated(DbgProcessCreatedEvent evt, Void v) { + DebugThreadId eventId = updateState(); DebugClient dbgeng = engThread.getClient(); DebugSystemObjects so = dbgeng.getSystemObjects(); @@ -730,8 +758,7 @@ public class DbgManagerImpl implements DbgManager { DebugProcessId id = so.getProcessIdByHandle(handle); so.setCurrentProcessId(id); int pid = so.getCurrentProcessSystemId(); - DbgProcessImpl proc = new DbgProcessImpl(this, id, pid); - proc.add(); + DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid); getEventListeners().fire.processSelected(proc, evt.getCause()); handle = info.initialThreadInfo.handle; @@ -742,10 +769,8 @@ public class DbgManagerImpl implements DbgManager { getEventListeners().fire.threadCreated(thread, evt.getCause()); getEventListeners().fire.threadSelected(thread, null, evt.getCause()); - DebugModuleInfo moduleInfo = info.moduleInfo; - String moduleName = moduleInfo.moduleName; - proc.moduleLoaded(moduleName, moduleInfo); - getEventListeners().fire.moduleLoaded(proc, moduleName, evt.getCause()); + proc.moduleLoaded(info.moduleInfo); + getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause()); String key = Integer.toHexString(id.id); if (statusByNameMap.containsKey(key)) { @@ -795,8 +820,8 @@ public class DbgManagerImpl implements DbgManager { protected DebugStatus processProcessSelected(DbgProcessSelectedEvent evt, Void v) { DebugThreadId eventId = updateState(); - DbgProcessImpl process = evt.getProcess(); - getEventListeners().fire.processSelected(process, evt.getCause()); + currentProcess = evt.getProcess(); + getEventListeners().fire.processSelected(currentProcess, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -816,9 +841,8 @@ public class DbgManagerImpl implements DbgManager { updateState(); DbgProcessImpl process = getCurrentProcess(); DebugModuleInfo info = evt.getInfo(); - String moduleName = info.moduleName; - process.moduleLoaded(moduleName, info); - getEventListeners().fire.moduleLoaded(process, moduleName, evt.getCause()); + process.moduleLoaded(info); + getEventListeners().fire.moduleLoaded(process, info, evt.getCause()); String key = info.moduleName; if (statusByNameMap.containsKey(key)) { @@ -838,9 +862,8 @@ public class DbgManagerImpl implements DbgManager { updateState(); DbgProcessImpl process = getCurrentProcess(); DebugModuleInfo info = evt.getInfo(); - String moduleName = info.moduleName; - process.moduleUnloaded(moduleName); - getEventListeners().fire.moduleUnloaded(process, moduleName, evt.getCause()); + process.moduleUnloaded(info); + getEventListeners().fire.moduleUnloaded(process, info, evt.getCause()); String key = info.moduleName; if (statusByNameMap.containsKey(key)) { @@ -872,23 +895,23 @@ public class DbgManagerImpl implements DbgManager { if (!threads.isEmpty()) { //DbgSessionImpl session = getCurrentSession(); //DbgProcessImpl process = getCurrentProcess(); - DbgThreadImpl thread = getCurrentThread(); + eventThread = getCurrentThread(); DbgState dbgState = null; - if (thread != null) { + if (eventThread != null) { if (status.threadState.equals(ExecutionState.STOPPED)) { dbgState = DbgState.STOPPED; //System.err.println("STOPPED " + id); - processEvent(new DbgStoppedEvent(thread.getId())); + processEvent(new DbgStoppedEvent(eventThread.getId())); } if (status.threadState.equals(ExecutionState.RUNNING)) { //System.err.println("RUNNING " + id); dbgState = DbgState.RUNNING; - processEvent(new DbgRunningEvent(thread.getId())); + processEvent(new DbgRunningEvent(eventThread.getId())); } // Don't fire if (dbgState != null) { - processEvent( - new DbgThreadSelectedEvent(dbgState, thread, evt.getFrame(thread))); + processEvent(new DbgThreadSelectedEvent(dbgState, eventThread, + evt.getFrame(eventThread))); } return DebugStatus.NO_CHANGE; } @@ -934,8 +957,8 @@ public class DbgManagerImpl implements DbgManager { protected DebugStatus processSessionSelected(DbgSessionSelectedEvent evt, Void v) { DebugThreadId eventId = updateState(); - DbgSessionImpl session = evt.getSession(); - getEventListeners().fire.sessionSelected(session, evt.getCause()); + currentSession = evt.getSession(); + getEventListeners().fire.sessionSelected(currentSession, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -1335,77 +1358,53 @@ public class DbgManagerImpl implements DbgManager { } public DbgThreadImpl getCurrentThread() { - synchronized (threads) { - DebugEventInformation info = getLastEventInformation(); - if (info == null) { - return null; - } - return threads.get(info.getThreadId()); - } + return (DbgThreadImpl) (currentThread != null ? currentThread : eventThread); + } + + public void setCurrentThread(DbgThreadImpl thread) { + currentThread = thread; } public DbgProcessImpl getCurrentProcess() { - synchronized (processes) { - DebugEventInformation info = getLastEventInformation(); - if (info == null) { - return null; - } - return processes.get(info.getProcessId()); - } + return (DbgProcessImpl) (currentProcess != null ? currentProcess : eventProcess); } public DbgSessionImpl getCurrentSession() { - synchronized (sessions) { - DebugEventInformation info = getLastEventInformation(); - if (info == null) { - return null; - } - return sessions.get(info.getSessionId()); - } + return (DbgSessionImpl) (currentSession != null ? currentSession : eventSession); } public DbgThreadImpl getEventThread() { - synchronized (threads) { - DebugSystemObjects so = getSystemObjects(); - DebugThreadId id = so.getEventThread(); - return threads.get(id); - } + return (DbgThreadImpl) eventThread; } public DbgProcessImpl getEventProcess() { - synchronized (processes) { - DebugSystemObjects so = getSystemObjects(); - DebugProcessId id = so.getEventProcess(); - return processes.get(id); - } + return (DbgProcessImpl) eventProcess; } public DbgSessionImpl getEventSession() { - synchronized (sessions) { - DebugSystemObjects so = getSystemObjects(); - DebugSessionId id = so.getEventSystem(); - return sessions.get(id); - } + return (DbgSessionImpl) eventSession; } - public CompletableFuture selectThread(DbgThreadImpl thread) { - DebugEventInformation info = getLastEventInformation(); - info.setThread(thread.getId()); + public CompletableFuture selectThread(DbgThread thread) { + currentThread = thread; return execute(new DbgThreadSelectCommand(this, thread, null)); } - public CompletableFuture selectProcess(DbgProcessImpl process) { - DebugEventInformation info = getLastEventInformation(); - info.setProcess(process.getId()); + public CompletableFuture selectProcess(DbgProcess process) { + currentProcess = process; return execute(new DbgProcessSelectCommand(this, process)); } - public CompletableFuture selectSession(DbgSessionImpl session) { - DebugEventInformation info = getLastEventInformation(); - info.setSession(session.getId()); + public CompletableFuture selectSession(DbgSession session) { + currentSession = session; return execute(new DbgSessionSelectCommand(this, session)); } + public CompletableFuture requestFocus(DbgModelTargetFocusScope scope, + TargetObjectRef ref) { + return execute(new DbgRequestFocusCommand(this, scope, ref)); + } + @Override public CompletableFuture console(String command) { return execute( diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleImpl.java index 9709193449..071ad3f589 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleImpl.java @@ -40,10 +40,11 @@ public class DbgModuleImpl implements DbgModule { * @param process the process to which the module belongs * @param id the dbgeng-assigned module ID */ - public DbgModuleImpl(DbgManagerImpl manager, DbgProcessImpl process, String name) { + public DbgModuleImpl(DbgManagerImpl manager, DbgProcessImpl process, DebugModuleInfo info) { this.manager = manager; this.process = process; - this.name = name; + this.info = info; + this.name = info.moduleName; } @Override @@ -56,7 +57,7 @@ public class DbgModuleImpl implements DbgModule { */ public void add() { process.addModule(this); - manager.getEventListeners().fire.moduleLoaded(process, name, Causes.UNCLAIMED); + manager.getEventListeners().fire.moduleLoaded(process, info, Causes.UNCLAIMED); } /** @@ -64,7 +65,7 @@ public class DbgModuleImpl implements DbgModule { */ public void remove() { process.removeModule(name); - manager.getEventListeners().fire.moduleUnloaded(process, name, Causes.UNCLAIMED); + manager.getEventListeners().fire.moduleUnloaded(process, info, Causes.UNCLAIMED); } @Override @@ -103,8 +104,8 @@ public class DbgModuleImpl implements DbgModule { return minimalSymbols.request(); } - public void setInfo(DebugModuleInfo info) { - this.info = info; + public DebugModuleInfo getInfo() { + return info; } } 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 3ee7b3bc84..96f897963e 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 @@ -169,11 +169,11 @@ public class DbgProcessImpl implements DbgProcess { * @param module the thread to add */ public void addModule(DbgModuleImpl module) { - DbgModuleImpl exists = modules.get(module.getName()); + DbgModuleImpl exists = modules.get(module.getInfo().toString()); if (exists != null) { throw new IllegalArgumentException("There is already module " + exists); } - modules.put(module.getName(), module); + modules.put(module.getInfo().toString(), module); } @@ -233,7 +233,7 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture select() { - return manager.execute(new DbgProcessSelectCommand(manager, this)); + return manager.selectProcess(this); } @Override @@ -353,17 +353,15 @@ public class DbgProcessImpl implements DbgProcess { return null; } - protected DbgModuleImpl createModule(String name) { - return new DbgModuleImpl(manager, this, name); + protected void moduleLoaded(DebugModuleInfo info) { + if (!modules.containsKey(info.moduleName)) { + DbgModuleImpl module = new DbgModuleImpl(manager, this, info); + modules.put(info.toString(), module); + } } - protected void moduleLoaded(String name, DebugModuleInfo info) { - DbgModuleImpl module = modules.computeIfAbsent(name, this::createModule); - module.setInfo(info); - } - - protected void moduleUnloaded(String name) { - modules.remove(name); + protected void moduleUnloaded(DebugModuleInfo info) { + modules.remove(info.toString()); } protected void threadCreated(DbgThreadImpl thread) { 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 a68e307339..c0ac221c8c 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 @@ -125,7 +125,7 @@ public class DbgStackFrameImpl implements DbgStackFrame { @Override public CompletableFuture select() { - return manager.execute(new DbgThreadSelectCommand(manager, thread, level)); + return thread.select(); } @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 d70bca3a66..d2f6ce112b 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 @@ -132,7 +132,7 @@ public class DbgThreadImpl implements DbgThread { @Override public CompletableFuture select() { - return manager.execute(new DbgThreadSelectCommand(manager, this, null)); + return manager.selectThread(this); } @Override 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 83500336a9..06a032cfd7 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 @@ -16,12 +16,10 @@ package agent.dbgeng.model.iface1; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; import agent.dbgeng.model.iface2.DbgModelTargetObject; import ghidra.async.AsyncUtils; -import ghidra.async.TypeSpec; -import ghidra.dbg.DebugModelConventions; +import ghidra.dbg.agent.AbstractTargetObject; import ghidra.dbg.attributes.TargetObjectRef; import ghidra.dbg.error.DebuggerIllegalArgumentException; import ghidra.dbg.target.TargetFocusScope; @@ -48,6 +46,10 @@ public interface DbgModelTargetFocusScope> // (but, of course, may then cause change in state) @Override public default CompletableFuture requestFocus(TargetObjectRef ref) { + return getManager().requestFocus(this, ref); + } + + public default CompletableFuture doRequestFocus(TargetObjectRef ref) { if (getManager().isWaiting()) { return CompletableFuture.completedFuture(null); } @@ -58,32 +60,23 @@ public interface DbgModelTargetFocusScope> if (!PathUtils.isAncestor(this.getPath(), ref.getPath())) { throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope"); } - return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { - ref.fetch().handle(seq::next); - }, TypeSpec.cls(TargetObject.class)).then((obj, seq) -> { + return ref.fetch().thenCompose(obj -> { TargetObject cur = obj; while (cur != null) { if (cur instanceof DbgModelSelectableObject) { DbgModelSelectableObject sel = (DbgModelSelectableObject) cur; - sel.select().handle(seq::exit); - AtomicReference> scope = new AtomicReference<>(); - AsyncUtils.sequence(TypeSpec.VOID).then(seqx -> { - DebugModelConventions.findSuitable(DbgModelTargetFocusScope.class, sel) - .handle(seqx::next); - }, scope).then(seqx -> { - scope.get().setFocus(sel); - }).finish(); - break; + setFocus(sel); + return sel.select(); } - if (cur instanceof DbgModelTargetObject) { - DbgModelTargetObject def = (DbgModelTargetObject) cur; + if (cur instanceof AbstractTargetObject) { + AbstractTargetObject def = (AbstractTargetObject) cur; cur = def.getImplParent(); continue; } throw new AssertionError(); } - seq.exit(); - }).finish(); + return AsyncUtils.NIL; + }); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointSpec.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointSpec.java index f137de9785..436cfe0012 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointSpec.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetBreakpointSpec.java @@ -108,6 +108,7 @@ public interface DbgModelTargetBreakpointSpec extends // } map.put(AFFECTS_ATTRIBUTE_NAME, doGetAffects()); map.put(SPEC_ATTRIBUTE_NAME, this); + map.put(EXPRESSION_ATTRIBUTE_NAME, addstr); map.put(KINDS_ATTRIBUTE_NAME, getKinds()); map.put(BPT_INDEX_ATTRIBUTE_NAME, Long.decode(idstr)); map.put(ENABLED_ATTRIBUTE_NAME, enstr.equals("-1")); 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 722d4fc89e..a1e2a020ea 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 @@ -21,7 +21,6 @@ import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgProcess; -import agent.dbgeng.manager.cmd.DbgProcessSelectCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.*; import ghidra.dbg.target.TargetAggregate; @@ -77,6 +76,6 @@ public interface DbgModelTargetProcess extends // if (process == null) { process = manager.getEventProcess(); } - return manager.execute(new DbgProcessSelectCommand(manager, process)); + return manager.selectProcess(process); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java index 75c6b978c1..e462228c91 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterBank.java @@ -24,10 +24,10 @@ import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.*; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; -import ghidra.dbg.error.DebuggerModelAccessException; import ghidra.dbg.error.DebuggerRegisterAccessException; import ghidra.dbg.target.TargetRegisterBank; import ghidra.dbg.util.ConversionUtils; +import ghidra.util.Msg; import ghidra.util.datastruct.ListenerSet; public interface DbgModelTargetRegisterBank @@ -40,7 +40,7 @@ public interface DbgModelTargetRegisterBank Collection names) { DbgManagerImpl manager = getManager(); if (manager.isWaiting()) { - throw new DebuggerModelAccessException( + Msg.warn(this, "Cannot process command readRegistersNamed while engine is waiting for events"); } 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 8e8a61825a..d3ea9fe6e6 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 @@ -21,7 +21,6 @@ import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags; import agent.dbgeng.dbgeng.DebugSessionId; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgSession; -import agent.dbgeng.manager.cmd.DbgSessionSelectCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.*; import ghidra.dbg.target.TargetAggregate; @@ -80,6 +79,6 @@ public interface DbgModelTargetSession extends // if (session == null) { session = manager.getEventSession(); } - return manager.execute(new DbgSessionSelectCommand(manager, session)); + return manager.selectSession(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 5ce2855475..c22ecbcfc9 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 @@ -20,7 +20,6 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgStackFrame; -import agent.dbgeng.manager.cmd.DbgThreadSelectCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgThreadImpl; import agent.dbgeng.model.iface1.DbgModelSelectableObject; @@ -53,7 +52,7 @@ public interface DbgModelTargetStackFrame extends // public default CompletableFuture select() { DbgManagerImpl manager = getManager(); DbgThreadImpl thread = manager.getCurrentThread(); - return manager.execute(new DbgThreadSelectCommand(manager, thread, null)); + return manager.selectThread(thread); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java index 8fad13fd68..f2cd5895c3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java @@ -95,7 +95,7 @@ public class DbgModelImpl extends AbstractDbgModel { public TargetObjectSchema getRootSchema() { return root.getSchema(); } - + @Override public CompletableFuture fetchModelRoot() { return completedRoot; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java index 939571288d..dcfa6524d2 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointSpecImpl.java @@ -61,6 +61,7 @@ public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl LENGTH_ATTRIBUTE_NAME, info.getSize(), // AFFECTS_ATTRIBUTE_NAME, doGetAffects(), // SPEC_ATTRIBUTE_NAME, this, // + EXPRESSION_ATTRIBUTE_NAME, info.getLocation(), // KINDS_ATTRIBUTE_NAME, getKinds() // ), reason); this.changeAttributes(List.of(), List.of(), Map.of( // diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java index eba3c1aeb3..db964fa429 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetMemoryContainerImpl.java @@ -138,7 +138,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl ByteBuffer buf = ByteBuffer.allocate(length); long offset = address.getOffset(); if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) { - return readVirtualMemory(address, length); + return manager.execute(new DbgReadMemoryCommand(manager, offset, buf, buf.remaining())) + .thenApply(set -> { + return readAssist(address, buf, offset, set); + }); } if (address.getAddressSpace().getName().equals("phys")) { return manager @@ -199,7 +202,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl ByteBuffer buf = ByteBuffer.wrap(data); long offset = address.getOffset(); if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) { - return writeVirtualMemory(address, data); + return manager.execute(new DbgWriteMemoryCommand(manager, offset, buf, buf.remaining())) + .thenAccept(___ -> { + writeAssist(address, data); + }); } if (address.getAddressSpace().getName().equals("phys")) { return manager diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java index bacb85b724..ef36e9f64e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java @@ -77,6 +77,9 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl @Override @Internal public void libraryUnloaded(String name) { + if (!modulesByName.containsKey(name)) { + return; + } modulesByName.get(name).thenAccept(mod -> { getListeners().fire(TargetEventScopeListener.class) .event(this, null, TargetEventType.MODULE_UNLOADED, diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java index fbf5ce15ff..98a751c5e9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessContainerImpl.java @@ -20,13 +20,12 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import agent.dbgeng.dbgeng.DebugProcessId; -import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.*; import agent.dbgeng.manager.*; import agent.dbgeng.model.iface2.*; import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility; -import ghidra.dbg.target.schema.*; import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.schema.*; import ghidra.util.datastruct.WeakValueHashMap; @TargetObjectSchemaInfo(name = "ProcessContainer", elements = { // @@ -106,15 +105,15 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl } @Override - public void moduleLoaded(DbgProcess proc, String name, DbgCause cause) { + public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { DbgModelTargetProcess process = getTargetProcess(proc); - process.getModules().libraryLoaded(name); + process.getModules().libraryLoaded(info.toString()); } @Override - public void moduleUnloaded(DbgProcess proc, String name, DbgCause cause) { + public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { DbgModelTargetProcess process = getTargetProcess(proc); - process.getModules().libraryUnloaded(name); + process.getModules().libraryUnloaded(info.toString()); } @Override 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 3ae45ac129..00e736c1fe 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 @@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicReference; import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.manager.*; -import agent.dbgeng.manager.cmd.DbgProcessSelectCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import agent.dbgeng.model.iface2.*; @@ -51,7 +50,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl public static final String PID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "pid"; public static final String EXIT_CODE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "exit_code"; - protected static final TargetAttachKindSet SUPPORTED_KINDS = TargetAttachKindSet.of( // + public static final TargetAttachKindSet SUPPORTED_KINDS = TargetAttachKindSet.of( // TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID); protected static String indexProcess(DebugProcessId debugProcessId) { @@ -226,7 +225,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl @Override public CompletableFuture select() { DbgManagerImpl manager = getManager(); - return manager.execute(new DbgProcessSelectCommand(manager, process)); + return manager.selectProcess(process); } @Override 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 fa0a240833..bacd10354f 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 @@ -28,6 +28,7 @@ import ghidra.async.TypeSpec; import ghidra.dbg.error.DebuggerUserException; import ghidra.dbg.target.*; import ghidra.dbg.target.schema.*; +import ghidra.dbg.util.PathUtils; @TargetObjectSchemaInfo(name = "Debugger", elements = { // @TargetElementType(type = Void.class) // @@ -61,7 +62,10 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot connectors, // sessions // ), Map.of( // + ACCESSIBLE_ATTRIBUTE_NAME, true, // DISPLAY_ATTRIBUTE_NAME, "Debugger", // + FOCUS_ATTRIBUTE_NAME, this, // + SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, DbgModelTargetProcessImpl.SUPPORTED_KINDS, // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // // ARCH_ATTRIBUTE_NAME, "x86_64", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // @@ -90,17 +94,7 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot if (doFire && focus != null) { List focusPath = focus.getPath(); List selPath = sel.getPath(); - for (int i = 0; i < focusPath.size(); i++) { - if (i >= selPath.size()) { - doFire = false; - break; - } - if (!focusPath.get(i).equals(selPath.get(i))) { - doFire = true; - break; - } - } - //doFire = !focusPath.containsAll(selPath); + doFire = !PathUtils.isAncestor(selPath, focusPath); } } if (doFire) { 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 e2df364122..f40abbd3b7 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 @@ -22,7 +22,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import agent.dbgeng.manager.*; -import agent.dbgeng.manager.cmd.DbgThreadSelectCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import agent.dbgeng.model.iface2.*; @@ -151,8 +150,7 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl @Override public CompletableFuture select() { DbgManagerImpl manager = getManager(); - return manager - .execute(new DbgThreadSelectCommand(manager, thread.getThread(), frame.getLevel())); + return manager.selectThread(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 3dce54358a..ee508079b4 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 @@ -44,7 +44,7 @@ import ghidra.dbg.util.PathUtils; public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl implements DbgModelTargetThread { - protected static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( // + public static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( // TargetStepKind.ADVANCE, // TargetStepKind.FINISH, // TargetStepKind.LINE, // diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java index 1eb7ab48ba..37eb55f78e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java @@ -27,8 +27,8 @@ import agent.dbgmodel.dbgmodel.UnknownEx; import agent.dbgmodel.dbgmodel.datamodel.DataModelManager1; import agent.dbgmodel.dbgmodel.debughost.DebugHostContext; import agent.dbgmodel.dbgmodel.debughost.DebugHostType1; -import agent.dbgmodel.jna.dbgmodel.IUnknownEx; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.*; +import agent.dbgmodel.jna.dbgmodel.IUnknownEx; import agent.dbgmodel.jna.dbgmodel.main.IModelObject; /** @@ -130,6 +130,8 @@ public interface ModelObject extends UnknownEx { ModelMethod getMethod(String name); + String getOriginalKey(); + String getSearchKey(); void setSearchKey(String key); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java index 2679c4f5f3..16ba3a4c62 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java @@ -82,7 +82,7 @@ public class HDMAUtil { public Map getAttributes(List path) { ModelObject target = getTerminalModelObject(path); if (target == null) { - System.err.println("(A) Null target for path=" + path); + //System.err.println("(A) Null target for path=" + path); return new HashMap(); } ModelObjectKind kind = target.getKind(); @@ -102,7 +102,7 @@ public class HDMAUtil { public List getElements(List path) { ModelObject target = getTerminalModelObject(path); if (target == null) { - System.err.println("(C) Null target for path=" + path); + //System.err.println("(C) Null target for path=" + path); return new ArrayList(); } ModelObjectKind kind = target.getKind(); @@ -127,9 +127,11 @@ public class HDMAUtil { public ModelObject getTerminalModelObject(List path) { //System.err.println(path); ModelObject target = getRootNamespace(); + boolean found; for (String str : path) { //System.err.println(":" + str); String indexStr = null; + found = false; if (str.endsWith(")")) { target = evaluatePredicate(target, str); if (target.getKind().equals(ModelObjectKind.OBJECT_ERROR)) { @@ -143,11 +145,13 @@ public class HDMAUtil { Map keyMap = target.getKeyValueMap(); if (keyMap.containsKey(str)) { target = keyMap.get(str); + found = true; } else { Map rawMap = target.getRawValueMap(); if (rawMap.containsKey(str)) { target = rawMap.get(str); + found = true; } } if (indexStr != null) { @@ -155,9 +159,13 @@ public class HDMAUtil { for (ModelObject child : children) { if (indexStr.equals(child.getSearchKey())) { target = child; + found = true; } } } + if (found == false) { + return null; + } } return target; } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java index 417b9fe46d..5064c145f3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java @@ -898,6 +898,19 @@ public class ModelObjectImpl implements ModelObjectInternal { @Override public String getSearchKey() { + if (key == null) { + throw new RuntimeException("null key for " + this); + } + Map map = getKeyValueMap(); + if (map.containsKey("BaseAddress")) { + String valueString = map.get("BaseAddress").getValueString(); + return valueString; + } + return key; + } + + @Override + public String getOriginalKey() { if (key == null) { throw new RuntimeException("null key for " + this); } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListAttributesCommand.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListAttributesCommand.java index 2741887e15..70cdb8c11f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListAttributesCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListAttributesCommand.java @@ -23,8 +23,7 @@ import agent.dbgeng.model.iface2.DbgModelTargetObject; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.manager.DbgManager2Impl; -import agent.dbgmodel.model.impl.DbgModel2TargetObjectImpl; -import agent.dbgmodel.model.impl.DelegateDbgModel2TargetObject; +import agent.dbgmodel.model.impl.*; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; public class DbgListAttributesCommand extends AbstractDbgCommand> { @@ -54,20 +53,19 @@ public class DbgListAttributesCommand extends AbstractDbgCommand> Map map = access.getAttributes(path); Map existingAttributes = targetObject.getCachedAttributes(); for (String key : map.keySet()) { - DbgModelTargetObject proxyAttribute; + DbgModel2TargetProxy proxyAttribute; ModelObject obj = map.get(key); - Object object = existingAttributes.get(key); + String atKey = obj.getSearchKey(); + Object object = existingAttributes.get(atKey); if (object != null && (object instanceof DbgModelTargetObject)) { - proxyAttribute = (DbgModelTargetObject) object; - DelegateDbgModel2TargetObject delegate = - DelegateDbgModel2TargetObject.getDelegate(proxyAttribute); + proxyAttribute = (DbgModel2TargetProxy) object; + DelegateDbgModel2TargetObject delegate = proxyAttribute.getDelegate(); delegate.setModelObject(obj); updatedAttributes.put(key, proxyAttribute); } else { - String atKey = obj.getSearchKey(); - proxyAttribute = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(), - targetObject, atKey, obj); + proxyAttribute = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject + .makeProxy(targetObject.getModel(), targetObject, atKey, obj); updatedAttributes.put(key, proxyAttribute); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListElementsCommand.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListElementsCommand.java index bb6561e6c0..5ecbae4b5c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListElementsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/jna/cmd/DbgListElementsCommand.java @@ -19,14 +19,13 @@ import java.util.*; import agent.dbgeng.manager.cmd.AbstractDbgCommand; import agent.dbgeng.manager.cmd.DbgPendingCommand; -import agent.dbgeng.model.iface2.DbgModelTargetObject; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.manager.DbgManager2Impl; -import agent.dbgmodel.model.impl.DbgModel2TargetObjectImpl; -import agent.dbgmodel.model.impl.DelegateDbgModel2TargetObject; +import agent.dbgmodel.model.impl.*; import ghidra.dbg.attributes.TargetObjectRef; import ghidra.dbg.target.TargetObject; +import ghidra.dbg.util.PathUtils; public class DbgListElementsCommand extends AbstractDbgCommand> { @@ -51,23 +50,27 @@ public class DbgListElementsCommand extends AbstractDbgCommand(); - List list = access.getElements(path); - Map existingElements = targetObject.getCachedElements(); - for (ModelObject obj : list) { - DbgModelTargetObject proxyElement; - if (existingElements.containsKey(obj.getSearchKey())) { - proxyElement = (DbgModelTargetObject) existingElements.get(obj.getSearchKey()); - DelegateDbgModel2TargetObject delegate = - DelegateDbgModel2TargetObject.getDelegate(proxyElement); - delegate.setModelObject(obj); + synchronized (access) { + updatedElements = new ArrayList<>(); + List list = access.getElements(path); + Map existingElements = + targetObject.getCachedElements(); + + for (ModelObject obj : list) { + DbgModel2TargetProxy proxyElement; + String searchKey = obj.getSearchKey(); + String elKey = PathUtils.makeKey(searchKey); + if (existingElements.containsKey(searchKey)) { + proxyElement = (DbgModel2TargetProxy) existingElements.get(searchKey); + DelegateDbgModel2TargetObject delegate = proxyElement.getDelegate(); + delegate.setModelObject(obj); + } + else { + proxyElement = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject + .makeProxy(targetObject.getModel(), targetObject, elKey, obj); + } + updatedElements.add(proxyElement); } - else { - String elKey = DbgModel2TargetObjectImpl.keyObject(obj); - proxyElement = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(), - targetObject, elKey, obj); - } - updatedElements.add(proxyElement); } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/manager/DbgManager2Impl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/manager/DbgManager2Impl.java index f836df955c..dbe4df879e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/manager/DbgManager2Impl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/manager/DbgManager2Impl.java @@ -22,12 +22,11 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import agent.dbgeng.dbgeng.*; +import agent.dbgeng.dbgeng.DebugClient; import agent.dbgeng.manager.DbgCause.Causes; import agent.dbgeng.manager.DbgState; -import agent.dbgeng.manager.impl.*; +import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgmodel.dbgmodel.DbgModel; -import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.gadp.impl.DbgModelClientThreadExecutor; import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.jna.cmd.*; @@ -108,6 +107,7 @@ public class DbgManager2Impl extends DbgManagerImpl { return execute(new DbgGetRegisterMapCommand(this, path)); } + /* @Override public DbgSessionImpl getCurrentSession() { ModelObject currentSession = dbgmodel.getUtil().getCurrentSession(); @@ -117,7 +117,7 @@ public class DbgManager2Impl extends DbgManagerImpl { curSession = getSessionComputeIfAbsent(sid); return curSession; } - + @Override public DbgProcessImpl getCurrentProcess() { synchronized (processes) { @@ -125,7 +125,7 @@ public class DbgManager2Impl extends DbgManagerImpl { return processes.get(id); } } - + @Override public DbgThreadImpl getCurrentThread() { synchronized (threads) { @@ -133,5 +133,6 @@ public class DbgManager2Impl extends DbgManagerImpl { return threads.get(id); } } + */ } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java index 2a1c0d1cac..69c59a2c12 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java @@ -27,7 +27,6 @@ import agent.dbgmodel.manager.DbgManager2Impl; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.target.schema.XmlSchemaContext; -import ghidra.framework.Application; import ghidra.program.model.address.*; public class DbgModel2Impl extends AbstractDbgModel { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java index 85985d3383..01323cceab 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java @@ -25,7 +25,7 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.iface1.DbgModelSelectableObject; import agent.dbgeng.model.iface2.*; -import agent.dbgeng.model.impl.DbgModelTargetMemoryContainerImpl; +import agent.dbgeng.model.impl.*; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.ModelObjectKind; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.TypeKind; @@ -37,6 +37,7 @@ import ghidra.dbg.target.TargetBreakpointContainer.TargetBreakpointKindSet; import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; import ghidra.dbg.target.schema.TargetObjectSchema; +import ghidra.dbg.util.CollectionUtils.Delta; import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; import ghidra.util.Msg; @@ -58,6 +59,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject requestElements(boolean refresh) { - List nlist = new ArrayList<>(); - return requestNativeElements().thenCompose(list -> { - for (TargetObject element : elements.values()) { - if (!list.contains(element)) { - if (element instanceof DbgStateListener) { - getManager().removeStateListener((DbgStateListener) element); - } - if (element instanceof DbgEventsListener) { - getManager().removeEventsListener((DbgEventsListener) element); + synchronized (elements) { + List nlist = new ArrayList<>(); + return requestNativeElements().thenCompose(list -> { + for (TargetObject element : elements.values()) { + if (!list.contains(element)) { + if (element instanceof DbgStateListener) { + getManager().removeStateListener((DbgStateListener) element); + } + if (element instanceof DbgEventsListener) { + getManager().removeEventsListener((DbgEventsListener) element); + } } } - } - nlist.addAll(list); - int order = 0; - for (TargetObject targetObject : nlist) { - DbgModelTargetObject to = (DbgModelTargetObject) targetObject; - to.changeAttributes(List.of(), Map.of( // - ORDER_ATTRIBUTE_NAME, order++ // - ), "Initialized"); - } - return processModelObjectElements(nlist); - }).thenAccept(__ -> { - setElements(nlist, Map.of(), "Refreshed"); - }); + nlist.addAll(list); + return processModelObjectElements(nlist); + }).thenAccept(__ -> { + setElements(nlist, Map.of(), "Refreshed"); + }); + } } @Override public CompletableFuture requestAttributes(boolean refresh) { + fireAttributesChanged = true; Map nmap = new HashMap<>(); return requestNativeAttributes().thenCompose(map -> { - if (map != null) { - Collection values = map.values(); - for (Object attribute : attributes.values()) { - if (!values.contains(attribute)) { - if (attribute instanceof DbgStateListener) { - getManager().removeStateListener((DbgStateListener) attribute); - } - if (attribute instanceof DbgEventsListener) { - getManager().removeEventsListener((DbgEventsListener) attribute); + synchronized (attributes) { + if (map != null) { + Collection values = map.values(); + for (Object attribute : attributes.values()) { + if (!values.contains(attribute)) { + if (attribute instanceof DbgStateListener) { + getManager().removeStateListener((DbgStateListener) attribute); + } + if (attribute instanceof DbgEventsListener) { + getManager().removeEventsListener((DbgEventsListener) attribute); + } } } + nmap.putAll(map); } - nmap.putAll(map); + return addModelObjectAttributes(nmap); } - return addModelObjectAttributes(nmap); }).thenAccept(__ -> { setAttributes(List.of(), nmap, "Refreshed"); }); @@ -161,9 +162,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject processElement(TargetObject targetObject) { if (targetObject instanceof DbgModelTargetObject) { - DbgModelTargetObject proxy = (DbgModelTargetObject) targetObject; - DelegateDbgModel2TargetObject delegate = - DelegateDbgModel2TargetObject.getDelegate(proxy); + DbgModel2TargetProxy proxy = (DbgModel2TargetProxy) targetObject; + DelegateDbgModel2TargetObject delegate = proxy.getDelegate(); if (proxy instanceof TargetStackFrame || // proxy instanceof TargetModule || // proxy instanceof TargetBreakpointSpec) { @@ -193,10 +193,12 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject stateful = (TargetExecutionStateful) proxy; TargetExecutionState state = stateful.getExecutionState(); attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state); } + if (proxy instanceof TargetAttacher) { + attrs.put(TargetAttacher.SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, + DbgModelTargetProcessImpl.SUPPORTED_KINDS); + } + if (proxy instanceof TargetSteppable) { + attrs.put(TargetSteppable.SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, + DbgModelTargetThreadImpl.SUPPORTED_KINDS); + } if (proxy instanceof TargetInterpreter) { attrs.put(TargetInterpreter.PROMPT_ATTRIBUTE_NAME, DBG_PROMPT); } @@ -230,6 +244,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject fetchChild(final String key) { - if (key.startsWith("[") && key.endsWith("]")) { - String trimKey = key.substring(1, key.length() - 1); - if (elements.containsKey(trimKey)) { - return CompletableFuture.completedFuture(elements.get(trimKey)); + synchronized (elements) { + if (key.startsWith("[") && key.endsWith("]")) { + String trimKey = key.substring(1, key.length() - 1); + if (elements.containsKey(trimKey)) { + return CompletableFuture.completedFuture(elements.get(trimKey)); + } + return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey)); } - return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey)); } - if (attributes.containsKey(key)) { - return CompletableFuture.completedFuture(attributes.get(key)); + synchronized (attributes) { + if (attributes.containsKey(key)) { + return CompletableFuture.completedFuture(attributes.get(key)); + } + if (key.endsWith(")")) { + DbgManager2Impl manager2 = (DbgManager2Impl) getManager(); + List pathX = PathUtils.extend(List.of("Debugger"), path); + pathX = PathUtils.extend(pathX, key); + return manager2.applyMethods(pathX, this).thenApply(obj -> { + changeAttributes(List.of(), List.of(), Map.of( // + key, obj // + ), "Initialized"); + return obj; + }); + } + return requestAttributes(true).thenApply(__ -> getCachedAttribute(key)); } - if (key.endsWith(")")) { - DbgManager2Impl manager2 = (DbgManager2Impl) getManager(); - List pathX = PathUtils.extend(List.of("Debugger"), path); - pathX = PathUtils.extend(pathX, key); - return manager2.applyMethods(pathX, this).thenApply(obj -> { - changeAttributes(List.of(), List.of(), Map.of( // - key, obj // - ), "Initialized"); - return obj; - }); - } - return requestAttributes(true).thenApply(__ -> getCachedAttribute(key)); } //@Override @@ -378,9 +398,55 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject setAttributes(Map attributes, String reason) { + Delta delta; + synchronized (this.attributes) { + delta = Delta.computeAndSet(this.attributes, attributes, Delta.EQUAL); + } + TargetObjectSchema schemax = getSchema(); + if (schemax != null) { + schemax.validateAttributeDelta(getPath(), delta, enforcesStrictSchema()); + } + doInvalidateAttributes(delta.removed, reason); + if (parent == null && !delta.isEmpty()) { + listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); + return delta; + } + if (fireAttributesChanged && !delta.isEmpty()) { + listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); + } + return delta; + } + + @Override + public Delta changeAttributes(List remove, Map add, String reason) { + Delta delta; + synchronized (attributes) { + delta = Delta.apply(this.attributes, remove, add, Delta.EQUAL); + } + TargetObjectSchema schemax = getSchema(); + if (schemax != null) { + schemax.validateAttributeDelta(getPath(), delta, enforcesStrictSchema()); + } + doInvalidateAttributes(delta.removed, reason); + if (fireAttributesChanged && !delta.isEmpty()) { + listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added); + } + return delta; + } + + @Override + protected boolean enforcesStrictSchema() { + return false; + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetProxy.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetProxy.java new file mode 100644 index 0000000000..53e3badca9 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetProxy.java @@ -0,0 +1,24 @@ +/* ### + * 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.dbgmodel.model.impl; + +import agent.dbgeng.model.iface2.DbgModelTargetObject; + +public interface DbgModel2TargetProxy extends DbgModelTargetObject { + + public DelegateDbgModel2TargetObject getDelegate(); + +} 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 9908e9509d..55dc1f5429 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 @@ -26,6 +26,7 @@ import agent.dbgeng.model.iface1.DbgModelSelectableObject; import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.impl.DbgModelTargetConnectorContainerImpl; +import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.manager.DbgManager2Impl; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; @@ -59,7 +60,9 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot connectors, // systemMarker // ), Map.of( // + ACCESSIBLE_ATTRIBUTE_NAME, true, // DISPLAY_ATTRIBUTE_NAME, "Debugger", // + FOCUS_ATTRIBUTE_NAME, this, // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // // ARCH_ATTRIBUTE_NAME, "x86_64", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // @@ -82,7 +85,9 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot connectors, // systemMarker // ), Map.of( // + ACCESSIBLE_ATTRIBUTE_NAME, true, // DISPLAY_ATTRIBUTE_NAME, "Debugger", // + FOCUS_ATTRIBUTE_NAME, this, // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // // ARCH_ATTRIBUTE_NAME, "x86_64", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // @@ -99,21 +104,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot if (doFire && focus != null) { List focusPath = focus.getPath(); List selPath = sel.getPath(); - for (int i = 0; i < focusPath.size(); i++) { - if (i >= selPath.size()) { - doFire = false; - break; - } - if (!focusPath.get(i).equals(selPath.get(i))) { - doFire = true; - break; - } - } - //doFire = !focusPath.containsAll(selPath); + doFire = !PathUtils.isAncestor(selPath, focusPath); } } if (doFire) { this.focus = sel; + fireAttributesChanged = true; changeAttributes(List.of(), List.of(), Map.of( // TargetFocusScope.FOCUS_ATTRIBUTE_NAME, focus // ), "Focus changed"); @@ -201,28 +197,28 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot } @Override - public void moduleLoaded(DbgProcess proc, String name, DbgCause cause) { - getObject(proc, List.of("Modules"), name).thenAccept(obj -> { + public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { + getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> { DbgModelTargetModule mod = (DbgModelTargetModule) obj; if (mod == null) { return; } getListeners().fire(TargetEventScopeListener.class) - .event(this, null, TargetEventType.MODULE_LOADED, "Library " + name + " loaded", - List.of(mod)); + .event(this, null, TargetEventType.MODULE_LOADED, + "Library " + info.moduleName + " loaded", List.of(mod)); }); } @Override - public void moduleUnloaded(DbgProcess proc, String name, DbgCause cause) { - getObject(proc, List.of("Modules"), name).thenAccept(obj -> { + public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { + getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> { DbgModelTargetModule mod = (DbgModelTargetModule) obj; if (mod == null) { return; } getListeners().fire(TargetEventScopeListener.class) .event(this, null, TargetEventType.MODULE_UNLOADED, - "Library " + name + " unloaded", List.of(mod)); + "Library " + info.moduleName + " unloaded", List.of(mod)); }); } @@ -241,8 +237,8 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot }).finish(); } - private CompletableFuture getObject(Object object, List ext, - String name) { + private CompletableFuture getObjectRevisited(Object object, + List ext, Object info) { List objPath = findObject(object); if (objPath == null) { return CompletableFuture.completedFuture(null); @@ -257,19 +253,23 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot seq.exit(); return; } - DbgModelTargetObject proxy = (DbgModelTargetObject) pobj; - DelegateDbgModel2TargetObject delegate = - DelegateDbgModel2TargetObject.getDelegate(proxy); - delegate.requestElements(true).thenAccept(__ -> { - Map cachedElements = delegate.getCachedElements(); - for (TargetObject val : cachedElements.values()) { - DbgModelTargetObject obj = (DbgModelTargetObject) val; - if (obj.getDisplay().contains(name)) { - seq.exit(obj); - } + DbgModel2TargetProxy proxy = (DbgModel2TargetProxy) pobj; + DelegateDbgModel2TargetObject delegate = proxy.getDelegate(); + + xpath.add(0, "Debugger"); + DbgManager2Impl manager = (DbgManager2Impl) getManager(); + List list = manager.getAccess().getElements(xpath); + for (ModelObject obj : list) { + String searchKey = obj.getSearchKey(); + if (searchKey.equals(info.toString())) { + String elKey = PathUtils.makeKey(searchKey); + DbgModel2TargetProxy proxyElement = + (DbgModel2TargetProxy) DelegateDbgModel2TargetObject + .makeProxy(delegate.getModel(), delegate, elKey, obj); + delegate.changeElements(List.of(), List.of(proxyElement), "Created"); + seq.exit(proxyElement); } - seq.exit((DbgModelTargetObject) null); - }); + } }).finish(); } @@ -350,17 +350,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot public void breakpointCreated(DbgBreakpointInfo info, DbgCause cause) { int id = info.getDebugBreakpoint().getId(); bptInfoMap.put(id, info); - getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); - /* - getObject(info).thenAccept(obj -> { - DbgModelTargetBreakpointSpec bpt = (DbgModelTargetBreakpointSpec) obj; - if (bpt == null) { - return; - } - bpt.setBreakpointInfo(info); - bpt.setEnabled(true, "Created"); - }); - */ + getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info); } @Override @@ -368,20 +358,19 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DbgCause cause) { int id = newInfo.getDebugBreakpoint().getId(); bptInfoMap.put(id, newInfo); - getObject(newInfo.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); + getObjectRevisited(newInfo.getProc(), List.of("Debug", "Breakpoints"), newInfo); } @Override public void breakpointDeleted(DbgBreakpointInfo info, DbgCause cause) { int id = info.getDebugBreakpoint().getId(); bptInfoMap.remove(id); - getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); + getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info); } @Override public void breakpointHit(DbgBreakpointInfo info, DbgCause cause) { - int id = info.getDebugBreakpoint().getId(); - getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)) + getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info) .thenAccept(obj -> { DbgModelTargetBreakpointSpec bpt = (DbgModelTargetBreakpointSpec) obj; if (bpt == null) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java index 8905cf4c71..e27a309aab 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java @@ -39,7 +39,7 @@ import utilities.util.ProxyUtilities; public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl implements // DbgModelTargetAccessConditioned, // DbgModelTargetExecutionStateful, // - DbgModelTargetBptHelper { + DbgModel2TargetProxy, DbgModelTargetBptHelper { // Probably don-t need any of the handler-map or annotation stuff protected final DbgStateListener accessListener = this::checkExited; @@ -163,12 +163,6 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp return new DelegateDbgModel2TargetObject(model, parent, key, object, mixins).proxy; } - private static Map map = new HashMap<>(); - - public static DelegateDbgModel2TargetObject getDelegate(DbgModelTargetObject proxy) { - return map.get(proxy); - } - protected static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); // NOTE: The Cleanable stuff is the replacement for overriding Object.finalize(), which @@ -201,15 +195,27 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp getManager().addStateListener(accessListener); + mixins.add(DbgModel2TargetProxy.class); this.proxy = ProxyUtilities.composeOnDelegate(DbgModelTargetObject.class, this, mixins, LOOKUP); - map.put(proxy, this); if (proxy instanceof DbgEventsListener) { model.getManager().addEventsListener((DbgEventsListener) proxy); } setModelObject(modelObject); } + public DelegateDbgModel2TargetObject clone(String key, ModelObject modelObject) { + DbgModelTargetObject p = (DbgModelTargetObject) getImplParent(); + List> mixins = new ArrayList<>(); + Class mixin = lookupWrapperType(key, p.getName()); + if (mixin != null) { + mixins.add(mixin); + } + DelegateDbgModel2TargetObject delegate = + new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject, mixins); + return delegate; + } + @Override public > T as(Class iface) { return DebuggerObjectModel.requireIface(iface, proxy, getPath()); @@ -348,6 +354,10 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } } + public DelegateDbgModel2TargetObject getDelegate() { + return this; + } + // Methods required for DbgModelTargetBreakpointSpec mixin @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml index 43f298c67d..7dcc3f47fe 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/resources/agent/dbgmodel/model/impl/dbgmodel_schema.xml @@ -17,7 +17,6 @@