diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java index fab30f2456..075f719bf5 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java @@ -24,7 +24,7 @@ import org.apache.commons.lang3.tuple.Pair; import agent.dbgeng.dbgeng.*; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointInsertions; -import agent.dbgeng.manager.impl.*; +import agent.dbgeng.manager.impl.DbgManagerImpl; public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { @@ -217,8 +217,6 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ CompletableFuture addProcess(); - public void addProcess(DbgProcessImpl process, DbgCause cause); - /** * Remove a process * @@ -234,8 +232,6 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ CompletableFuture addSession(); - public void addSession(DbgSessionImpl session, DbgCause cause); - /** * Remove a session * diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMappingsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMappingsCommand.java index 24ab85ef28..da486dae13 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMappingsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMappingsCommand.java @@ -46,7 +46,8 @@ public class DbgListMappingsCommand extends AbstractDbgCommand(cur)) { if (updatedThreadIds.contains(id)) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListProcessesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListProcessesCommand.java index 3e0da3bdff..089ca8930d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListProcessesCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListProcessesCommand.java @@ -23,7 +23,6 @@ import agent.dbgeng.manager.DbgCause.Causes; import agent.dbgeng.manager.DbgManager; import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.manager.impl.DbgProcessImpl; import ghidra.util.Msg; /** @@ -49,7 +48,7 @@ public class DbgListProcessesCommand extends AbstractDbgCommand(cur)) { if (updatedProcessIds.contains(id)) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSessionsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSessionsCommand.java index be767249ec..40655b4c9a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSessionsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSessionsCommand.java @@ -23,7 +23,6 @@ import agent.dbgeng.manager.DbgCause.Causes; import agent.dbgeng.manager.DbgManager; import agent.dbgeng.manager.DbgSession; import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.manager.impl.DbgSessionImpl; import ghidra.util.Msg; /** @@ -46,7 +45,7 @@ public class DbgListSessionsCommand extends AbstractDbgCommand(cur)) { if (updatedSessionIds.contains(id)) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListThreadsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListThreadsCommand.java index 1c406a3ec1..8087c2645d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListThreadsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListThreadsCommand.java @@ -45,7 +45,8 @@ public class DbgListThreadsCommand extends AbstractDbgCommand(cur)) { if (updatedThreadIds.contains(id)) { 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 e77bf5e55c..3c7c5b71fb 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 @@ -79,7 +79,6 @@ public class DbgManagerImpl implements DbgManager { Collections.unmodifiableMap(sessions); protected final Map processes = new LinkedHashMap<>(); - protected DbgProcessImpl curProcess = null; private final Map unmodifiableProcesses = Collections.unmodifiableMap(processes); @@ -96,7 +95,7 @@ public class DbgManagerImpl implements DbgManager { private final HandlerMap, Void, DebugStatus> handlerMap = new HandlerMap<>(); private final Map, DebugStatus> statusMap = new LinkedHashMap<>(); private final Map statusByNameMap = new LinkedHashMap<>(); - protected final ListenerSet listenersEvent = + private final ListenerSet listenersEvent = new ListenerSet<>(DbgEventsListener.class); private DebugEventInformation lastEventInformation; @@ -114,24 +113,18 @@ public class DbgManagerImpl implements DbgManager { //TODO: this.dbgSrvTransport = dbgSrvTransport; } - /** - * Use {@link DbgThreadImpl#add()} instead - * - * @param thread the thread to add - */ - public void addThread(DbgThreadImpl thread) { - DbgThreadImpl exists = threads.get(thread.getId()); - if (exists != null) { - threads.remove(thread.getId()); - Msg.debug(this, "Replacing process " + thread.getId() + " (" + thread.getTid() + ")"); - //throw new IllegalArgumentException("There is already thread " + exists); - } - threads.put(thread.getId(), thread); - } - @Override public DbgThreadImpl getThread(DebugThreadId tid) { - return threads.get(tid); + synchronized (threads) { + return threads.get(tid); + } + } + + public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process, + int tid) { + synchronized (threads) { + return threads.computeIfAbsent(id, i -> new DbgThreadImpl(this, process, id, tid)); + } } /** @@ -140,49 +133,13 @@ public class DbgManagerImpl implements DbgManager { * @param id the thread ID to remove */ public void removeThread(DebugThreadId id) { - if (threads.remove(id) == null) { - throw new IllegalArgumentException("There is no thread with id " + id); + synchronized (threads) { + if (threads.remove(id) == null) { + throw new IllegalArgumentException("There is no thread with id " + id); + } } } - /** - * Use {@link DbgProcessImpl#add(DbgCause)} instead - * - * @param process the process to add - * @param cause the cause of the new process - */ - @Override - @Internal - public void addProcess(DbgProcessImpl process, DbgCause cause) { - DbgProcessImpl exists = processes.get(process.getId()); - if (exists != null) { - processes.remove(process.getId()); - Msg.debug(this, "Replacing process " + process.getId() + " (" + process.getPid() + ")"); - //throw new IllegalArgumentException("There is already process " + exists); - } - processes.put(process.getId(), process); - listenersEvent.fire.processAdded(process, cause); - } - - /** - * Use {@link DbgSessionImpl#add(DbgCause)} instead - * - * @param session the session to add - * @param cause the cause of the new session - */ - @Override - @Internal - public void addSession(DbgSessionImpl session, DbgCause cause) { - DbgSession exists = sessions.get(session.getId()); - if (exists != null) { - sessions.remove(session.getId()); - Msg.debug(this, "Replacing session " + session.getId()); - //throw new IllegalArgumentException("There is already process " + exists); - } - sessions.put(session.getId(), session); - listenersEvent.fire.sessionAdded(session, cause); - } - /** * Use {@link DbgProcessImpl#remove(DbgCause)} instead * @@ -191,10 +148,23 @@ public class DbgManagerImpl implements DbgManager { */ @Internal public void removeProcess(DebugProcessId id, DbgCause cause) { - if (processes.remove(id) == null) { - throw new IllegalArgumentException("There is no process with id " + id); + synchronized (processes) { + DbgProcessImpl proc = processes.remove(id); + if (proc == null) { + throw new IllegalArgumentException("There is no process with id " + id); + } + Set toRemove = new HashSet<>(); + for (DebugThreadId tid : threads.keySet()) { + DbgThreadImpl thread = threads.get(tid); + if (thread.getProcess().getId().equals(id)) { + toRemove.add(tid); + } + } + for (DebugThreadId tid : toRemove) { + removeThread(tid); + } + getEventListeners().fire.processRemoved(id, cause); } - listenersEvent.fire.processRemoved(id, cause); } /** @@ -205,29 +175,21 @@ public class DbgManagerImpl implements DbgManager { * @param fire signal listeners * @return success status */ - protected boolean updateCurrentProcess(DbgProcessImpl process, DbgCause cause, boolean fire) { - // dbgeng will not permit removing all processes, so one is guaranteed to exist - // dbgeng may actually have already selected it, but without generating events - if (process == null) { - process = processes.values().iterator().next(); - } - if (curProcess != process) { - curProcess = process; - if (fire) { - listenersEvent.fire.processSelected(process, cause); - } - return true; - } - return false; - } - @Override public DbgProcessImpl getProcess(DebugProcessId id) { - DbgProcessImpl result = processes.get(id); - if (result == null) { - throw new IllegalArgumentException("There is no process with id " + id); + synchronized (processes) { + DbgProcessImpl result = processes.get(id); + if (result == null) { + throw new IllegalArgumentException("There is no process with id " + id); + } + return result; + } + } + + public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, int pid) { + synchronized (processes) { + return processes.computeIfAbsent(id, i -> new DbgProcessImpl(this, id, pid)); } - return result; } /** @@ -238,19 +200,29 @@ public class DbgManagerImpl implements DbgManager { */ @Internal public void removeSession(DebugSessionId id, DbgCause cause) { - if (sessions.remove(id) == null) { - throw new IllegalArgumentException("There is no session with id " + id); + synchronized (sessions) { + if (sessions.remove(id) == null) { + throw new IllegalArgumentException("There is no session with id " + id); + } + getEventListeners().fire.sessionRemoved(id, cause); } - listenersEvent.fire.sessionRemoved(id, cause); } @Override public DbgSession getSession(DebugSessionId id) { - DbgSession result = sessions.get(id); - if (result == null) { - throw new IllegalArgumentException("There is no session with id " + id); + synchronized (sessions) { + DbgSession result = sessions.get(id); + if (result == null) { + throw new IllegalArgumentException("There is no session with id " + id); + } + return result; + } + } + + public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id) { + synchronized (sessions) { + return sessions.computeIfAbsent(id, i -> new DbgSessionImpl(this, id)); } - return result; } @Override @@ -530,14 +502,18 @@ public class DbgManagerImpl implements DbgManager { state.removeChangeListener(listener); } + public ListenerSet getEventListeners() { + return listenersEvent; + } + @Override public void addEventsListener(DbgEventsListener listener) { - listenersEvent.add(listener); + getEventListeners().add(listener); } @Override public void removeEventsListener(DbgEventsListener listener) { - listenersEvent.remove(listener); + getEventListeners().remove(listener); } private DbgState stateFilter(DbgState cur, DbgState set, DbgCause cause) { @@ -629,7 +605,7 @@ public class DbgManagerImpl implements DbgManager { DebugBreakpoint bp = evt.getInfo(); DbgBreakpointInfo info = new DbgBreakpointInfo(bp, getEventProcess(), getEventThread()); - listenersEvent.fire.breakpointHit(info, evt.getCause()); + getEventListeners().fire.breakpointHit(info, evt.getCause()); String key = Integer.toHexString(bp.getId()); if (statusByNameMap.containsKey(key)) { @@ -672,8 +648,8 @@ public class DbgManagerImpl implements DbgManager { int tid = so.getCurrentThreadSystemId(); DbgThreadImpl thread = new DbgThreadImpl(this, process, eventId, tid); thread.add(); - listenersEvent.fire.threadCreated(thread, evt.getCause()); - listenersEvent.fire.threadSelected(thread, null, evt.getCause()); + getEventListeners().fire.threadCreated(thread, evt.getCause()); + getEventListeners().fire.threadSelected(thread, null, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -697,7 +673,7 @@ public class DbgManagerImpl implements DbgManager { thread.remove(); } process.threadExited(eventId); - listenersEvent.fire.threadExited(eventId, process, evt.getCause()); + getEventListeners().fire.threadExited(eventId, process, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -718,7 +694,7 @@ public class DbgManagerImpl implements DbgManager { DbgThreadImpl thread = evt.getThread(); thread.setState(evt.getState(), evt.getCause(), evt.getReason()); - listenersEvent.fire.threadSelected(thread, evt.getFrame(), evt.getCause()); + getEventListeners().fire.threadSelected(thread, evt.getFrame(), evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -745,21 +721,21 @@ public class DbgManagerImpl implements DbgManager { int pid = so.getCurrentProcessSystemId(); DbgProcessImpl proc = new DbgProcessImpl(this, id, pid); proc.add(evt.getCause()); - listenersEvent.fire.processAdded(proc, evt.getCause()); - listenersEvent.fire.processSelected(proc, evt.getCause()); + getEventListeners().fire.processAdded(proc, evt.getCause()); + getEventListeners().fire.processSelected(proc, evt.getCause()); handle = info.initialThreadInfo.handle; DebugThreadId idt = so.getThreadIdByHandle(handle); int tid = so.getCurrentThreadSystemId(); DbgThreadImpl thread = new DbgThreadImpl(this, proc, idt, tid); thread.add(); - listenersEvent.fire.threadCreated(thread, evt.getCause()); - listenersEvent.fire.threadSelected(thread, null, evt.getCause()); + 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); - listenersEvent.fire.moduleLoaded(proc, moduleName, evt.getCause()); + getEventListeners().fire.moduleLoaded(proc, moduleName, evt.getCause()); String key = Integer.toHexString(id.id); if (statusByNameMap.containsKey(key)) { @@ -780,13 +756,13 @@ public class DbgManagerImpl implements DbgManager { DbgProcessImpl process = getCurrentProcess(); process.remove(evt.getCause()); - listenersEvent.fire.processRemoved(process.getId(), evt.getCause()); + getEventListeners().fire.processRemoved(process.getId(), evt.getCause()); DbgThreadImpl thread = getCurrentThread(); if (thread != null) { thread.remove(); } - listenersEvent.fire.threadExited(eventId, process, evt.getCause()); + getEventListeners().fire.threadExited(eventId, process, evt.getCause()); for (DebugBreakpoint bpt : getBreakpoints()) { breaksById.remove(bpt.getId()); @@ -810,7 +786,7 @@ public class DbgManagerImpl implements DbgManager { DebugThreadId eventId = updateState(); DbgProcessImpl process = evt.getProcess(); - listenersEvent.fire.processSelected(process, evt.getCause()); + getEventListeners().fire.processSelected(process, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -832,7 +808,7 @@ public class DbgManagerImpl implements DbgManager { DebugModuleInfo info = evt.getInfo(); String moduleName = info.moduleName; process.moduleLoaded(moduleName, info); - listenersEvent.fire.moduleLoaded(process, moduleName, evt.getCause()); + getEventListeners().fire.moduleLoaded(process, moduleName, evt.getCause()); String key = info.moduleName; if (statusByNameMap.containsKey(key)) { @@ -854,7 +830,7 @@ public class DbgManagerImpl implements DbgManager { DebugModuleInfo info = evt.getInfo(); String moduleName = info.moduleName; process.moduleUnloaded(moduleName); - listenersEvent.fire.moduleUnloaded(process, moduleName, evt.getCause()); + getEventListeners().fire.moduleUnloaded(process, moduleName, evt.getCause()); String key = info.moduleName; if (statusByNameMap.containsKey(key)) { @@ -949,7 +925,7 @@ public class DbgManagerImpl implements DbgManager { DebugThreadId eventId = updateState(); DbgSessionImpl session = evt.getSession(); - listenersEvent.fire.sessionSelected(session, evt.getCause()); + getEventListeners().fire.sessionSelected(session, evt.getCause()); String key = Integer.toHexString(eventId.id); if (statusByNameMap.containsKey(key)) { @@ -980,7 +956,7 @@ public class DbgManagerImpl implements DbgManager { } protected void processConsoleOutput(DbgConsoleOutputEvent evt, Void v) { - listenersEvent.fire.consoleOutput(evt.getInfo(), evt.getMask()); + getEventListeners().fire.consoleOutput(evt.getInfo(), evt.getMask()); } /** @@ -1043,7 +1019,7 @@ public class DbgManagerImpl implements DbgManager { @Internal public void doBreakpointCreated(DbgBreakpointInfo newInfo, DbgCause cause) { addKnownBreakpoint(newInfo, false); - listenersEvent.fire.breakpointCreated(newInfo, cause); + getEventListeners().fire.breakpointCreated(newInfo, cause); } /** @@ -1055,7 +1031,7 @@ public class DbgManagerImpl implements DbgManager { @Internal public void doBreakpointModified(DbgBreakpointInfo newInfo, DbgCause cause) { DbgBreakpointInfo oldInfo = addKnownBreakpoint(newInfo, true); - listenersEvent.fire.breakpointModified(newInfo, oldInfo, cause); + getEventListeners().fire.breakpointModified(newInfo, oldInfo, cause); } /** @@ -1070,7 +1046,7 @@ public class DbgManagerImpl implements DbgManager { if (oldInfo == null) { return; } - listenersEvent.fire.breakpointDeleted(oldInfo, cause); + getEventListeners().fire.breakpointDeleted(oldInfo, cause); } protected void doBreakpointModifiedSameLocations(DbgBreakpointInfo newInfo, @@ -1078,7 +1054,7 @@ public class DbgManagerImpl implements DbgManager { if (Objects.equals(newInfo, oldInfo)) { return; } - listenersEvent.fire.breakpointModified(newInfo, oldInfo, cause); + getEventListeners().fire.breakpointModified(newInfo, oldInfo, cause); } @Internal @@ -1353,19 +1329,12 @@ public class DbgManagerImpl implements DbgManager { if (info == null) { return null; } - DbgThreadImpl thread = threads.get(info.getThreadId()); - if (thread != null) { - return thread; - } DebugSystemObjects so = getSystemObjects(); - DbgProcessImpl process = getCurrentProcess(); int tid = so.getCurrentThreadSystemId(); if (tid < 0) { return null; } - thread = new DbgThreadImpl(this, process, info.getThreadId(), tid, info); - addThread(thread); - return thread; + return threads.get(info.getThreadId()); } public DbgProcessImpl getCurrentProcess() { @@ -1373,15 +1342,7 @@ public class DbgManagerImpl implements DbgManager { if (info == null) { return null; } - DbgProcessImpl process = processes.get(info.getProcessId()); - if (process != null) { - return process; - } - DebugSystemObjects so = getSystemObjects(); - int pid = so.getCurrentProcessSystemId(); - process = new DbgProcessImpl(this, info.getProcessId(), pid); - addProcess(process, DbgCause.Causes.UNCLAIMED); - return process; + return processes.get(info.getProcessId()); } public DbgSessionImpl getCurrentSession() { @@ -1389,13 +1350,7 @@ public class DbgManagerImpl implements DbgManager { if (info == null) { return null; } - DbgSessionImpl session = sessions.get(info.getSessionId()); - if (session != null) { - return session; - } - session = new DbgSessionImpl(this, info.getSessionId()); - addSession(session, DbgCause.Causes.UNCLAIMED); - return session; + return sessions.get(info.getSessionId()); } public DbgThreadImpl getEventThread() { @@ -1448,7 +1403,7 @@ public class DbgManagerImpl implements DbgManager { } public void fireThreadExited(DebugThreadId id, DbgProcessImpl process, DbgCause cause) { - listenersEvent.fire.threadExited(id, process, cause); + getEventListeners().fire.threadExited(id, process, cause); } @Override 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 ddaa0cd3e3..b2357d4b25 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 @@ -56,7 +56,7 @@ public class DbgModuleImpl implements DbgModule { */ public void add() { process.addModule(this); - manager.listenersEvent.fire.moduleLoaded(process, name, Causes.UNCLAIMED); + manager.getEventListeners().fire.moduleLoaded(process, name, Causes.UNCLAIMED); } /** @@ -64,7 +64,7 @@ public class DbgModuleImpl implements DbgModule { */ public void remove() { process.removeModule(name); - manager.listenersEvent.fire.moduleUnloaded(process, name, Causes.UNCLAIMED); + manager.getEventListeners().fire.moduleUnloaded(process, name, Causes.UNCLAIMED); } @Override 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 f30be4a8d2..aea223b616 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 @@ -63,6 +63,8 @@ public class DbgProcessImpl implements DbgProcess { this.manager = manager; this.id = id; this.pid = pid; + manager.processes.put(id, this); + manager.getEventListeners().fire.processAdded(this, DbgCause.Causes.UNCLAIMED); } public DbgProcessImpl(DbgManagerImpl manager) { @@ -108,7 +110,7 @@ public class DbgProcessImpl implements DbgProcess { * @param cause the cause of the new inferior */ public void add(DbgCause cause) { - manager.addProcess(this, cause); + //manager.addProcess(this, cause); } /** diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgSessionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgSessionImpl.java index 9c887ca693..8f11641152 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgSessionImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgSessionImpl.java @@ -42,6 +42,8 @@ public class DbgSessionImpl implements DbgSession { public DbgSessionImpl(DbgManagerImpl manager, DebugSessionId id) { this.manager = manager; this.id = id; + manager.sessions.put(id, this); + manager.getEventListeners().fire.sessionAdded(this, DbgCause.Causes.UNCLAIMED); } public DbgSessionImpl(DbgManagerImpl manager) { @@ -82,7 +84,7 @@ public class DbgSessionImpl implements DbgSession { * @param cause the cause of the new inferior */ public void add(DbgCause cause) { - manager.addSession(this, cause); + //manager.addSession(this, cause); } /** 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 07d1778467..f19b5af591 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 @@ -64,6 +64,8 @@ public class DbgThreadImpl implements DbgThread { this.process = process; this.id = id; this.tid = tid; + manager.threads.put(id, this); + manager.getEventListeners().fire.threadCreated(this, DbgCause.Causes.UNCLAIMED); } public DbgThreadImpl(DbgManagerImpl manager, DbgProcessImpl process, DebugThreadId id, long tid, @@ -97,9 +99,8 @@ public class DbgThreadImpl implements DbgThread { */ public void add() { process.addThread(this); - manager.addThread(this); state.addChangeListener((oldState, newState, pair) -> { - this.manager.listenersEvent.fire.threadStateChanged(this, newState, pair.cause, + this.manager.getEventListeners().fire.threadStateChanged(this, newState, pair.cause, pair.reason); }); } 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 74b25702bc..722d4fc89e 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 @@ -19,12 +19,10 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugSystemObjects; -import agent.dbgeng.manager.DbgCause.Causes; 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.manager.impl.DbgProcessImpl; import agent.dbgeng.model.iface1.*; import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetProcess; @@ -65,12 +63,7 @@ public interface DbgModelTargetProcess extends // if (id == null) { id = so.getCurrentProcessId(); } - DbgProcessImpl process = manager.getProcess(id); - if (process == null) { - process = new DbgProcessImpl(manager, id, pid); - manager.addProcess(process, Causes.UNCLAIMED); - } - return process; + return manager.getProcessComputeIfAbsent(id, pid); } catch (IllegalArgumentException e) { return manager.getCurrentProcess(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainer.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainer.java index 3836ead6c5..29c0180c7b 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainer.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainer.java @@ -15,113 +15,12 @@ */ package agent.dbgeng.model.iface2; -import java.math.BigInteger; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; - -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 agent.dbgeng.manager.impl.DbgRegister; import ghidra.dbg.target.TargetRegisterContainer; -import ghidra.dbg.util.ConversionUtils; -import ghidra.util.datastruct.ListenerSet; public interface DbgModelTargetRegisterContainer - extends DbgModelTargetObject, TargetRegisterContainer, - TargetRegisterBank { + extends DbgModelTargetObject, TargetRegisterContainer { public DbgModelTargetRegister getTargetRegister(DbgRegister register); - @Override - public default CompletableFuture> readRegistersNamed( - Collection names) { - DbgManagerImpl manager = getManager(); - if (manager.isWaiting()) { - throw new DebuggerModelAccessException( - "Cannot process command readRegistersNamed while engine is waiting for events"); - } - - // THESE ARE NOT CURRENLY USED - SEE DbgModelTargetRegisterBank - - AtomicReference> read = new AtomicReference<>(); - return getManager().getRegisterMap(getPath()).thenCompose(valueMap -> { - Map regs = getCachedAttributes(); - Map map = - new HashMap(); - - for (String regname : names) { - Object x = regs.get(regname); - if (!(x instanceof DbgModelTargetRegister)) { - continue; - } - if (!valueMap.containsKey(regname)) { - continue; - } - DbgModelTargetRegister reg = (DbgModelTargetRegister) x; - DbgRegister register = (DbgRegister) valueMap.get(regname); - if (register != null) { - map.put(register, reg); - } - } - read.set(map); - return getParentThread().getThread().readRegisters(map.keySet()); - }).thenApply(vals -> { - Map result = new LinkedHashMap<>(); - for (DbgRegister dbgReg : vals.keySet()) { - DbgModelTargetRegister reg = read.get().get(dbgReg); - String oldval = (String) reg.getCachedAttributes().get(VALUE_ATTRIBUTE_NAME); - BigInteger value = vals.get(dbgReg); - byte[] bytes = ConversionUtils.bigIntegerToBytes(dbgReg.getSize(), value); - result.put(dbgReg.getName(), bytes); - reg.changeAttributes(List.of(), Map.of( // - VALUE_ATTRIBUTE_NAME, value.toString(16) // - ), "Refreshed"); - if (value.longValue() != 0) { - String newval = reg.getName() + " : " + value.toString(16); - reg.changeAttributes(List.of(), Map.of( // - DISPLAY_ATTRIBUTE_NAME, newval // - ), "Refreshed"); - reg.setModified(value.toString(16).equals(oldval)); - } - } - ListenerSet listeners = getListeners(); - if (listeners != null) { - listeners.fire(TargetRegisterBankListener.class).registersUpdated(this, result); - } - return result; - }); - } - - @Override - public default CompletableFuture writeRegistersNamed(Map values) { - DbgThread thread = getParentThread().getThread(); - return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { - fetchElements().handle(seq::nextIgnore); - }).then(seq -> { - thread.listRegisters().handle(seq::next); - }, TypeSpec.cls(DbgRegisterSet.class)).then((regset, seq) -> { - Map regs = getCachedAttributes(); - Map toWrite = new LinkedHashMap<>(); - for (Map.Entry ent : values.entrySet()) { - String regname = ent.getKey(); - DbgModelTargetRegister reg = (DbgModelTargetRegister) regs.get(regname); - if (reg == null) { - throw new DebuggerRegisterAccessException("No such register: " + regname); - } - BigInteger val = new BigInteger(1, ent.getValue()); - DbgRegister dbgreg = regset.get(regname); - toWrite.put(dbgreg, val); - } - getParentThread().getThread().writeRegisters(toWrite).handle(seq::next); - // TODO: Should probably filter only effective and normalized writes in the callback - }).then(seq -> { - getListeners().fire(TargetRegisterBankListener.class).registersUpdated(this, values); - seq.exit(); - }).finish(); - } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainerAndBank.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainerAndBank.java new file mode 100644 index 0000000000..726c9b6c07 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetRegisterContainerAndBank.java @@ -0,0 +1,28 @@ +/* ### + * 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.iface2; + +import agent.dbgeng.manager.impl.DbgRegister; +import ghidra.dbg.target.TargetRegisterBank; +import ghidra.dbg.target.TargetRegisterContainer; + +public interface DbgModelTargetRegisterContainerAndBank extends DbgModelTargetObject, // + TargetRegisterContainer, // + TargetRegisterBank { + + public DbgModelTargetRegister getTargetRegister(DbgRegister register); + +} 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 32b7792ea4..8e8a61825a 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 @@ -19,12 +19,10 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags; import agent.dbgeng.dbgeng.DebugSessionId; -import agent.dbgeng.manager.DbgCause.Causes; 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.manager.impl.DbgSessionImpl; import agent.dbgeng.model.iface1.*; import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetConsole; @@ -52,12 +50,7 @@ public interface DbgModelTargetSession extends // String index = PathUtils.parseIndex(getName()); Integer sid = Integer.decode(index); DebugSessionId id = new DebugSessionId(sid); - DbgSessionImpl session = (DbgSessionImpl) manager.getSession(id); - if (session == null) { - session = new DbgSessionImpl(manager, id); - manager.addSession(session, Causes.UNCLAIMED); - } - return session; + return manager.getSessionComputeIfAbsent(id); } catch (IllegalArgumentException e) { return manager.getCurrentSession(); 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 1f8008a6d2..a432be03df 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 @@ -45,14 +45,9 @@ public interface DbgModelTargetThread extends // if (id == null) { id = so.getCurrentThreadId(); } - DbgThreadImpl thread = manager.getThread(id); - if (thread == null) { - DbgModelTargetProcess parentProcess = getParentProcess(); - DbgProcessImpl process = (DbgProcessImpl) parentProcess.getProcess(); - thread = new DbgThreadImpl(manager, process, id, tid); - manager.addThread(thread); - - } + DbgModelTargetProcess parentProcess = getParentProcess(); + DbgProcessImpl process = (DbgProcessImpl) parentProcess.getProcess(); + DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid); return thread; } catch (IllegalArgumentException e) { @@ -69,8 +64,6 @@ public interface DbgModelTargetThread extends // return manager.execute(new DbgThreadSelectCommand(manager, thread, null)); } - public DbgModelTargetRegisterContainer getRegisters(); - public DbgModelTargetStackImpl getStack(); public String getExecutingProcessorType(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetObjectImpl.java index 840736690e..41cbbea3d4 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetObjectImpl.java @@ -48,6 +48,12 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject traces = new HashMap<>(); protected Trace currentTrace; protected DebuggerObjectModel currentModel; - private TraceRecorder recorder; + // NB: We're getting rid of this because the ObjectsProvider is beating the trace + // to the punch and causing the pattern-matcher to fail + // private TraceRecorder recorder; protected Runnable repeatLastSet = () -> { }; @@ -1327,7 +1329,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements if (rec == null) { return; // Cancelled } - this.recorder = rec; + //this.recorder = rec; Trace trace = rec.getTrace(); traceManager.openTrace(trace); traceManager.activateTrace(trace); @@ -1335,9 +1337,11 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements } public void addListener(TargetObject targetObject) { + /* if (recorder != null) { recorder.getListenerForRecord().addListener(targetObject); } + */ } public void stopRecording(TargetObject targetObject) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java index 0f55024cbc..406a5ca403 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/ObjectContainer.java @@ -250,8 +250,13 @@ public class ObjectContainer implements Comparable { Object val = attributesAdded.get(key); ObjectContainer child = DebuggerObjectsProvider.buildContainerFromObject(targetObject, key, val, true); - attributeMap.put(key, val); - result.add(child); + if (child == null) { + Msg.error(this, "Null container for " + key); + } + else { + attributeMap.put(key, val); + result.add(child); + } } } currentChildren = result; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerRegisterMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerRegisterMapper.java index 1b99d3050e..003bdc3594 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerRegisterMapper.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerRegisterMapper.java @@ -56,7 +56,7 @@ public class DefaultDebuggerRegisterMapper implements DebuggerRegisterMapper { return lReg.isBaseRegister(); } - protected void collectFilteredLanguageRegs() { + protected synchronized void collectFilteredLanguageRegs() { for (Register lReg : language.getRegisters()) { if (!testTraceRegister(lReg)) { continue; @@ -65,7 +65,7 @@ public class DefaultDebuggerRegisterMapper implements DebuggerRegisterMapper { } } - protected Register considerRegister(TargetRegister tReg) { + protected synchronized Register considerRegister(TargetRegister tReg) { String name = normalizeName(tReg.getIndex()); Register lReg = filtLanguageRegs.get(name); if (lReg == null) { @@ -76,7 +76,7 @@ public class DefaultDebuggerRegisterMapper implements DebuggerRegisterMapper { return lReg; } - protected Register removeRegister(TargetRegister tReg) { + protected synchronized Register removeRegister(TargetRegister tReg) { String name = normalizeName(tReg.getIndex()); Register lReg = filtLanguageRegs.get(name); if (lReg == null) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/LargestSubDebuggerRegisterMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/LargestSubDebuggerRegisterMapper.java index ec4ae35fbc..d84d9ed673 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/LargestSubDebuggerRegisterMapper.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/LargestSubDebuggerRegisterMapper.java @@ -45,32 +45,32 @@ public class LargestSubDebuggerRegisterMapper extends DefaultDebuggerRegisterMap } @Override - protected Register considerRegister(TargetRegister tReg) { + protected synchronized Register considerRegister(TargetRegister tReg) { Register lReg = super.considerRegister(tReg); if (lReg == null) { return null; } - synchronized (present) { - present.computeIfAbsent(lReg.getBaseRegister(), - r -> new TreeSet<>(LENGTH_COMPARATOR)).add(lReg); - } + //synchronized (present) { + present.computeIfAbsent(lReg.getBaseRegister(), r -> new TreeSet<>(LENGTH_COMPARATOR)) + .add(lReg); + //} return lReg; } @Override - protected Register removeRegister(TargetRegister tReg) { + protected synchronized Register removeRegister(TargetRegister tReg) { Register lReg = super.removeRegister(tReg); - synchronized (present) { - if (lReg == null) { - return null; - } - Register lbReg = lReg.getBaseRegister(); - TreeSet set = present.get(lbReg); - set.remove(lReg); - if (set.isEmpty()) { - present.remove(lbReg); - } + //synchronized (present) { + if (lReg == null) { + return null; } + Register lbReg = lReg.getBaseRegister(); + TreeSet set = present.get(lbReg); + set.remove(lReg); + if (set.isEmpty()) { + present.remove(lbReg); + } + //} return lReg; } @@ -84,7 +84,7 @@ public class LargestSubDebuggerRegisterMapper extends DefaultDebuggerRegisterMap } @Override - public Map.Entry traceToTarget(RegisterValue registerValue) { + public synchronized Map.Entry traceToTarget(RegisterValue registerValue) { Register lbReg = registerValue.getRegister(); if (!lbReg.isBaseRegister()) { throw new IllegalArgumentException(); @@ -114,7 +114,7 @@ public class LargestSubDebuggerRegisterMapper extends DefaultDebuggerRegisterMap } @Override - public RegisterValue targetToTrace(String tRegName, byte[] value) { + public synchronized RegisterValue targetToTrace(String tRegName, byte[] value) { if (value == null) { return null; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorder.java index 07a6075770..6a4228fcd5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorder.java @@ -104,7 +104,7 @@ public class DefaultTraceRecorder implements TraceRecorder { addPattern(PathUtils.parse("Sessions[].Attributes")); addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Stack.Frames[]")); addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].TTD.Position")); - addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Registers.User[]")); + addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Registers.User.")); // Paths for JDI addPattern(PathUtils.parse("VirtualMachines[]")); @@ -457,7 +457,8 @@ public class DefaultTraceRecorder implements TraceRecorder { protected TargetRegister pcReg; protected TargetRegister spReg; protected Map> regs = new HashMap<>(); - protected NavigableMap> stack = new TreeMap<>(); + protected NavigableMap> stack = + Collections.synchronizedNavigableMap(new TreeMap<>()); protected final ComposedMemory threadMemory = new ComposedMemory(processMemory); protected TargetBreakpointContainer threadBreakpointContainer; protected TargetExecutionState state = TargetExecutionState.ALIVE; @@ -492,9 +493,9 @@ public class DefaultTraceRecorder implements TraceRecorder { * thread? This seems counter to the model's flexibility. Traces allow polyglot * disassembly, but not polyglot register spaces. */ - if (regMapper != null) { + /*if (regMapper != null) { return AsyncUtils.NIL; - } + }*/ return regMappers.get(registers).thenAccept(rm -> { synchronized (this) { regMapper = rm; @@ -533,12 +534,16 @@ public class DefaultTraceRecorder implements TraceRecorder { if (regMapper != rm) { return; } - if (pcReg == null) { - pcReg = regMapper.traceToTarget(trace.getBaseLanguage().getProgramCounter()); + TargetRegister newPcReg = + regMapper.traceToTarget(trace.getBaseLanguage().getProgramCounter()); + if (pcReg != newPcReg) { + pcReg = newPcReg; doUpdateRegs |= pcReg != null; } - if (spReg == null) { - spReg = regMapper.traceToTarget(trace.getBaseCompilerSpec().getStackPointer()); + TargetRegister newSpReg = + regMapper.traceToTarget(trace.getBaseCompilerSpec().getStackPointer()); + if (spReg != newSpReg) { + spReg = newSpReg; doUpdateRegs |= spReg != null; } if (mapper.getExtraRegNames().contains(name)) { @@ -592,18 +597,34 @@ public class DefaultTraceRecorder implements TraceRecorder { return 0; } - protected void offerRegisters(TargetRegisterBank newRegs) { - if (regs.isEmpty()) { - newRegs.getDescriptions().fetch().thenCompose(descs -> { - return initRegMapper(descs); - }).thenAccept(__ -> { - listeners.fire.registerBankMapped(DefaultTraceRecorder.this); - }).exceptionally(ex -> { - Msg.error(this, "Could not intialize register mapper", ex); - return null; - }); + CompletableFuture doFetchAndInitRegMapper(TargetRegisterBank bank) { + int frameLevel = getSuccessorFrameLevel(bank); + TypedTargetObjectRef> descsRef = + bank.getDescriptions(); + if (descsRef == null) { + Msg.error(this, "Cannot create mapper, yet: Descriptions is null."); + return AsyncUtils.NIL; } + return descsRef.fetch().thenCompose(descs -> { + return initRegMapper(descs); + }).thenAccept(__ -> { + if (frameLevel == 0) { + recordRegisterValues(bank, bank.getCachedRegisters()); + updateRegsMem(null); + } + listeners.fire.registerBankMapped(DefaultTraceRecorder.this); + }).exceptionally(ex -> { + Msg.error(this, "Could not intialize register mapper", ex); + return null; + }); + } + + protected void offerRegisters(TargetRegisterBank newRegs) { int frameLevel = getSuccessorFrameLevel(newRegs); + if (regs.isEmpty()) { + // TODO: Technically, each frame may need its own mapper.... + doFetchAndInitRegMapper(newRegs); + } TargetRegisterBank oldRegs = regs.put(frameLevel, newRegs); if (oldRegs == newRegs) { @@ -620,11 +641,6 @@ public class DefaultTraceRecorder implements TraceRecorder { return null; }); } - - if (frameLevel == 0) { - recordRegisterValues(newRegs, newRegs.getCachedRegisters()); - updateRegsMem(null); - } } protected void offerStackFrame(TargetStackFrame frame) { @@ -1343,6 +1359,14 @@ public class DefaultTraceRecorder implements TraceRecorder { framePcUpdated((TargetStackFrame) parent); } } + if (parent instanceof TargetRegisterBank) { + if (added.containsKey(TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME)) { + ThreadRecorder rec = threadMap.getForSuccessor(parent); + if (rec != null) { + rec.doFetchAndInitRegMapper((TargetRegisterBank) parent); + } + } + } // This should be fixed at construction. /*if (parent instanceof TargetModule) { if (added.containsKey(TargetModule.BASE_ATTRIBUTE_NAME)) { 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 59f7b91436..0bfe185c35 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 @@ -528,6 +528,7 @@ public enum DebugModelConventions { } private void doInvalidated(TargetObject object, String reason) { + List removed = new ArrayList<>(); synchronized (objects) { if (disposed) { return; @@ -537,7 +538,6 @@ public enum DebugModelConventions { * ConcurrentModificationException, even if removal is via the iterator... */ List path = object.getPath(); - List removed = new ArrayList<>(); while (true) { Entry, TargetObject> ent = objects.ceilingEntry(path); if (ent == null || !PathUtils.isAncestor(path, ent.getKey())) { @@ -548,9 +548,9 @@ public enum DebugModelConventions { succ.removeListener(this); removed.add(succ); } - for (TargetObject r : removed) { - objectRemovedSafe(r); - } + } + for (TargetObject r : removed) { + objectRemovedSafe(r); } } @@ -576,7 +576,12 @@ public enum DebugModelConventions { if (!checkDescend(ref)) { return; } - ref.fetch().thenAcceptAsync(this::addListenerAndConsiderSuccessors); + ref.fetch() + .thenAcceptAsync(this::addListenerAndConsiderSuccessors) + .exceptionally(ex -> { + Msg.error(this, "Could not fetch a ref: " + ref, ex); + return null; + }); } private void considerElements(TargetObject parent, @@ -650,8 +655,18 @@ public enum DebugModelConventions { public boolean addListenerAndConsiderSuccessors(TargetObject obj) { boolean result = addListener(obj); if (result && checkDescend(obj)) { - obj.fetchElements().thenAcceptAsync(elems -> considerElements(obj, elems)); - obj.fetchAttributes().thenAcceptAsync(attrs -> considerAttributes(obj, attrs)); + obj.fetchElements() + .thenAcceptAsync(elems -> considerElements(obj, elems)) + .exceptionally(ex -> { + Msg.error(this, "Could not fetch elements of obj: " + obj, ex); + return null; + }); + obj.fetchAttributes() + .thenAcceptAsync(attrs -> considerAttributes(obj, attrs)) + .exceptionally(ex -> { + Msg.error(this, "Could not fetch attributes of obj: " + obj, ex); + return null; + }); } return result; }