diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacks.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacks.java index f1f5cdf90a..b3c03cf798 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacks.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacks.java @@ -103,8 +103,8 @@ public class WrapCallbackIDebugEventCallbacks implements CallbackIDebugEventCall try { DebugBreakpoint bpt = DebugBreakpointInternal .tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface); - cb.breakpoint(bpt); - return WinError.S_OK; + DebugStatus status = cb.breakpoint(bpt); + return new HRESULT(status.ordinal()); } catch (Throwable e) { Msg.error(this, "Error during callback", e); @@ -125,8 +125,8 @@ public class WrapCallbackIDebugEventCallbacks implements CallbackIDebugEventCall Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(), Exception.ExceptionAddress.longValue(), information); boolean firstChance = FirstChance.intValue() != 0; - cb.exception(exc, firstChance); - return WinError.S_OK; + DebugStatus status = cb.exception(exc, firstChance); + return new HRESULT(status.ordinal()); } catch (Throwable e) { Msg.error(this, "Error during callback", e); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacksWide.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacksWide.java index f1b0b4ad08..82deaf99a6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacksWide.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/event/WrapCallbackIDebugEventCallbacksWide.java @@ -105,8 +105,8 @@ public class WrapCallbackIDebugEventCallbacksWide implements CallbackIDebugEvent try { DebugBreakpoint bpt = DebugBreakpointInternal .tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface); - cb.breakpoint(bpt); - return WinError.S_OK; + DebugStatus status = cb.breakpoint(bpt); + return new HRESULT(status.ordinal()); } catch (Throwable e) { Msg.error(this, "Error during callback", e); @@ -127,8 +127,8 @@ public class WrapCallbackIDebugEventCallbacksWide implements CallbackIDebugEvent Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(), Exception.ExceptionAddress.longValue(), information); boolean firstChance = FirstChance.intValue() != 0; - cb.exception(exc, firstChance); - return WinError.S_OK; + DebugStatus status = cb.exception(exc, firstChance); + return new HRESULT(status.ordinal()); } catch (Throwable e) { Msg.error(this, "Error during callback", e); 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 c6c7b05ca9..d0548ffa99 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 @@ -192,6 +192,16 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ Map getKnownBreakpoints(); + /** + * Get all memory regions known to the manager + * + * This does not ask dbgeng to list its regions. Rather it returns a read-only view of the + * manager's understanding of the current ememory based on its tracking of dbgeng events. + * + * @return a map of dbgeng-assigned breakpoint IDs to corresponding breakpoint information + */ + Map getKnownMemoryRegions(); + /** * Send an interrupt to dbgeng regardless of other queued commands * @@ -242,6 +252,21 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ CompletableFuture removeSession(DbgSession session); + /** + * Add a memory region + * + * @return a future which completes with the handle to the new process + */ + CompletableFuture addMemory(DbgModuleMemory region); + + /** + * Remove a memory region + * + * @param regionId the region to remove + * @return a future which completes then dbgeng has executed the command + */ + CompletableFuture removeMemory(Long regionId); + /** * Execute an arbitrary CLI command, printing output to the CLI console * diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgModuleMemory.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgModuleMemory.java index 67a74ac407..06d241b399 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgModuleMemory.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgModuleMemory.java @@ -21,6 +21,8 @@ public interface DbgModuleMemory { String getName(); + Long getId(); + long getVmaStart(); long getVmaEnd(); 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 6fdb5b8625..7303de60fb 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 @@ -85,6 +85,10 @@ public class DbgBreakpointInfo { offset, expression); } + public int getId() { + return bpt.getId(); + } + @Override public String toString() { return Integer.toHexString(bpt.getId()); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommand.java index a95abf372d..410a86460a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommand.java @@ -15,8 +15,8 @@ */ package agent.dbgeng.manager.cmd; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.Map.Entry; import com.sun.jna.platform.win32.COM.COMException; @@ -27,6 +27,7 @@ import agent.dbgeng.dbgeng.DebugModule.DebugModuleName; import agent.dbgeng.manager.DbgModuleMemory; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgModuleMemoryImpl; +import ghidra.util.Msg; public class DbgListMemoryRegionsCommand extends AbstractDbgCommand> { @@ -38,6 +39,23 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand complete(DbgPendingCommand pending) { + Map memory = manager.getKnownMemoryRegions(); + for (DbgModuleMemory region : memoryRegions) { + if (memory.containsValue(region)) { + continue; // Do nothing, we're in sync + } + // Need to create the thread as if we receive =thread-created + if (!memory.isEmpty()) { + Msg.warn(this, "Resync: Was missing memory: " + region.getId()); + } + manager.addMemory(region); + } + for (Entry entry : memory.entrySet()) { + if (memoryRegions.contains(entry.getValue())) { + continue; // Do nothing, we're in sync + } + manager.removeMemory(entry.getKey()); + } return memoryRegions; } @@ -83,10 +101,10 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand { if (process != null) { DebugProcessId id = process.getId(); if (id != null) { - manager.getSystemObjects().setCurrentProcessId(id); + DebugSystemObjects so = manager.getSystemObjects(); + DebugProcessId currentProcessId = so.getCurrentProcessId(); + if (id.id != currentProcessId.id) { + so.setCurrentProcessId(id); + } } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListFramesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListFramesCommand.java index 10c614bb26..f5e799150a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListFramesCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListFramesCommand.java @@ -63,6 +63,6 @@ public class DbgStackListFramesCommand extends AbstractDbgCommand { public void invoke() { DebugThreadId id = thread.getId(); if (id != null) { - manager.getSystemObjects().setCurrentThreadId(id); + DebugSystemObjects so = manager.getSystemObjects(); + DebugThreadId previous = so.getCurrentThreadId(); + so.setCurrentThreadId(id); if (!manager.isKernelMode()) { DebugControl control = manager.getControl(); if (preferFreeze) { @@ -68,6 +69,7 @@ public class DbgThreadHoldCommand extends AbstractDbgCommand { set ? SUSPEND_CURRENT_THREAD_COMMAND : RESUME_CURRENT_THREAD_COMMAND); } } + so.setCurrentThreadId(previous); } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgWriteRegistersCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgWriteRegistersCommand.java index f7f902cf86..efcfa0ec5d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgWriteRegistersCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgWriteRegistersCommand.java @@ -66,6 +66,6 @@ public class DbgWriteRegistersCommand extends AbstractDbgCommand { } } registers.setValues(DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE, values); - //so.setCurrentThreadId(previous); + so.setCurrentThreadId(previous); } } 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 b73e514c2d..93f8dc21e6 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 @@ -42,6 +42,8 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointType; import agent.dbgeng.manager.cmd.*; import agent.dbgeng.manager.evt.*; import agent.dbgeng.model.iface1.*; +import agent.dbgeng.model.iface2.DbgModelTargetObject; +import agent.dbgeng.model.iface2.DbgModelTargetThread; import ghidra.async.*; import ghidra.comm.util.BitmaskSet; import ghidra.dbg.target.TargetObject; @@ -92,6 +94,10 @@ public class DbgManagerImpl implements DbgManager { private final Map unmodifiableBreakpoints = Collections.unmodifiableMap(breakpoints); + private final NavigableMap memory = new TreeMap<>(); + private final NavigableMap unmodifiableMemory = + Collections.unmodifiableNavigableMap(memory); + protected final AsyncReference state = new AsyncReference<>(DbgState.NOT_STARTED); private final HandlerMap, Void, DebugStatus> handlerMap = new HandlerMap<>(); @@ -109,6 +115,7 @@ public class DbgManagerImpl implements DbgManager { private DbgThread eventThread; private volatile boolean waiting = false; private boolean kernelMode = false; + private boolean ignoreEventThread = false; private CompletableFuture continuation; private long processCount = 0; @@ -267,6 +274,11 @@ public class DbgManagerImpl implements DbgManager { return unmodifiableBreakpoints; } + @Override + public Map getKnownMemoryRegions() { + return unmodifiableMemory; + } + private DbgBreakpointInfo addKnownBreakpoint(DbgBreakpointInfo bkpt, boolean expectExisting) { DbgBreakpointInfo old = breakpoints.put(bkpt.getNumber(), bkpt); if (expectExisting && old == null) { @@ -606,8 +618,8 @@ public class DbgManagerImpl implements DbgManager { DebugControl control = dbgeng.getControl(); int execType = WinNTExtra.Machine.IMAGE_FILE_MACHINE_AMD64.val; try { - so.setCurrentProcessId(epid); - so.setCurrentThreadId(etid); + //so.setCurrentProcessId(epid); + //so.setCurrentThreadId(etid); execType = control.getExecutingProcessorType(); } catch (Exception e) { @@ -652,6 +664,7 @@ public class DbgManagerImpl implements DbgManager { DebugBreakpoint bp = evt.getInfo(); DbgBreakpointInfo info = new DbgBreakpointInfo(bp, getEventProcess(), getEventThread()); + getEventListeners().fire.threadSelected(eventThread, null, evt.getCause()); getEventListeners().fire.breakpointHit(info, evt.getCause()); String key = Integer.toHexString(bp.getId()); @@ -670,6 +683,7 @@ public class DbgManagerImpl implements DbgManager { */ protected DebugStatus processException(DbgExceptionEvent evt, Void v) { DebugThreadId eventId = updateState(); + getEventListeners().fire.threadSelected(eventThread, null, evt.getCause()); DebugExceptionRecord64 info = evt.getInfo(); String key = Integer.toHexString(info.code); @@ -764,16 +778,17 @@ public class DbgManagerImpl implements DbgManager { DebugProcessInfo info = evt.getInfo(); long handle = info.handle; DebugProcessId id = so.getProcessIdByHandle(handle); - so.setCurrentProcessId(id); + //so.setCurrentProcessId(id); int pid = so.getCurrentProcessSystemId(); DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid); - getEventListeners().fire.processAdded(proc, DbgCause.Causes.UNCLAIMED); + 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 = getThreadComputeIfAbsent(idt, proc, tid); + getEventListeners().fire.threadCreated(thread, evt.getCause()); getEventListeners().fire.threadSelected(thread, null, evt.getCause()); //proc.moduleLoaded(info.moduleInfo); @@ -1041,24 +1056,25 @@ public class DbgManagerImpl implements DbgManager { if (bptId == DbgEngUtil.DEBUG_ANY_ID.longValue()) { changeBreakpoints(); } - DebugBreakpoint bpt = getControl().getBreakpointById((int) bptId); - if (bpt == null) { - doBreakpointDeleted(bptId, evt.getCause()); - return; - } - DbgBreakpointInfo knownBreakpoint = getKnownBreakpoint(bptId); - if (knownBreakpoint == null) { - breakpointInfo = new DbgBreakpointInfo(bpt, getCurrentProcess()); - if (breakpointInfo.getOffset() != null) { - doBreakpointCreated(breakpointInfo, evt.getCause()); + else { + DebugBreakpoint bpt = getControl().getBreakpointById((int) bptId); + if (bpt == null && bptId != DbgEngUtil.DEBUG_ANY_ID.longValue()) { + doBreakpointDeleted(bptId, evt.getCause()); + return; } - return; + DbgBreakpointInfo knownBreakpoint = getKnownBreakpoint(bptId); + if (knownBreakpoint == null) { + breakpointInfo = new DbgBreakpointInfo(bpt, getCurrentProcess()); + if (breakpointInfo.getOffset() != null) { + doBreakpointCreated(breakpointInfo, evt.getCause()); + } + return; + } + breakpointInfo = knownBreakpoint; + breakpointInfo.setBreakpoint(bpt); + doBreakpointModified(breakpointInfo, evt.getCause()); } - breakpointInfo = knownBreakpoint; - breakpointInfo.setBreakpoint(bpt); - } - doBreakpointModified(breakpointInfo, evt.getCause()); } /** @@ -1274,6 +1290,18 @@ public class DbgManagerImpl implements DbgManager { return execute(new DbgRemoveSessionCommand(this, session.getId())); } + @Override + public CompletableFuture addMemory(DbgModuleMemory region) { + memory.put(region.getId(), region); + return AsyncUtils.NIL; + } + + @Override + public CompletableFuture removeMemory(Long id) { + memory.remove(id); + return AsyncUtils.NIL; + } + @Override public CompletableFuture launch(List args) { return execute(new DbgLaunchProcessCommand(this, args)); @@ -1492,6 +1520,7 @@ public class DbgManagerImpl implements DbgManager { //System.err.println("EXIT"); waiting = false; updateState(); + getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED); return CompletableFuture.completedFuture(null); } @@ -1511,6 +1540,18 @@ public class DbgManagerImpl implements DbgManager { return lastEventInformation; } + public boolean shouldUpdate(TargetObject object) { + if (ignoreEventThread || !(object instanceof DbgModelTargetObject)) { + return true; + } + DbgModelTargetObject modelObject = (DbgModelTargetObject) object; + DbgModelTargetThread parentThread = modelObject.getParentThread(); + if (parentThread == null) { + return true; + } + return parentThread.getThread().equals(eventThread); + } + public CompletableFuture> getRegisterMap(List path) { return null; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleMemoryImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleMemoryImpl.java index a8934f1854..b70aa32ccd 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleMemoryImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgModuleMemoryImpl.java @@ -55,6 +55,11 @@ public class DbgModuleMemoryImpl implements DbgModuleMemory { return index; } + @Override + public Long getId() { + return vmaStart; + } + @Override public long getVmaStart() { return vmaStart; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetExecutionStateful.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetExecutionStateful.java index d8c784db02..362d92f7b3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetExecutionStateful.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetExecutionStateful.java @@ -43,9 +43,11 @@ public interface DbgModelTargetExecutionStateful } public default void setExecutionState(TargetExecutionState state, String reason) { - changeAttributes(List.of(), Map.of( // - STATE_ATTRIBUTE_NAME, state // - ), reason); + if (isValid()) { + changeAttributes(List.of(), Map.of( // + STATE_ATTRIBUTE_NAME, state // + ), reason); + } } } 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 f623f8498f..8e2efe07b0 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 @@ -67,21 +67,11 @@ public interface DbgModelTargetBreakpointSpec extends // @Override public default TargetBreakpointKindSet getKinds() { - switch (getBreakpointInfo().getType()) { - case BREAKPOINT: - return TargetBreakpointKindSet.of(TargetBreakpointKind.SW_EXECUTE); - case HW_BREAKPOINT: - return TargetBreakpointKindSet.of(TargetBreakpointKind.HW_EXECUTE); - case HW_WATCHPOINT: - return TargetBreakpointKindSet.of(TargetBreakpointKind.WRITE); - case READ_WATCHPOINT: - return TargetBreakpointKindSet.of(TargetBreakpointKind.READ); - case ACCESS_WATCHPOINT: - return TargetBreakpointKindSet.of(TargetBreakpointKind.READ, - TargetBreakpointKind.WRITE); - default: - return TargetBreakpointKindSet.of(); - } + return TargetBreakpointKindSet.of( + TargetBreakpointKind.SW_EXECUTE, + TargetBreakpointKind.HW_EXECUTE, + TargetBreakpointKind.READ, + TargetBreakpointKind.WRITE); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetMemoryContainer.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetMemoryContainer.java index b111c278f7..c50be82369 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetMemoryContainer.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetMemoryContainer.java @@ -31,4 +31,6 @@ public interface DbgModelTargetMemoryContainer extends DbgModelTargetObject, Tar @Override public CompletableFuture writeMemory(Address address, byte[] data); + public CompletableFuture requestElements(boolean refresh); + } 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 e094881875..3222e8eae0 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 @@ -49,6 +49,8 @@ public interface DbgModelTargetProcess extends // public DbgModelTargetModuleContainer getModules(); + public DbgModelTargetMemoryContainer getMemory(); + public void threadStateChangedSpecific(DbgThread thread, DbgState state); public default DbgProcess getProcess() { 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 b42f1ffe48..55f2209a7b 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 @@ -21,7 +21,7 @@ import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import agent.dbgeng.manager.*; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.*; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; @@ -36,10 +36,6 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target public DbgModelTargetRegister getTargetRegister(DbgRegister register); - public default void threadStateChangedSpecific(DbgState state, DbgReason reason) { - readRegistersNamed(getCachedElements().keySet()); - } - @Override public default CompletableFuture> readRegistersNamed( Collection names) { 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 39ef012538..2c626abee2 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 @@ -59,6 +59,9 @@ public interface DbgModelTargetSession extends // @Override public default void consoleOutput(String output, int mask) { + if (!isValid()) { + return; + } Channel chan = TargetConsole.Channel.STDOUT; if (((mask & DebugOutputFlags.DEBUG_OUTPUT_ERROR.getValue()) // == DebugOutputFlags.DEBUG_OUTPUT_ERROR.getValue()) || // @@ -69,6 +72,9 @@ public interface DbgModelTargetSession extends // if (output.contains("loaded *kernel* extension dll for usermode")) { return; } + if (!isValid()) { + return; + } getListeners().fire.consoleOutput(getProxy(), chan, output); } 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 30e6844e9d..903b83ff65 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 @@ -24,7 +24,7 @@ import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand; import agent.dbgeng.manager.impl.*; import agent.dbgeng.model.iface1.*; import agent.dbgeng.model.impl.DbgModelTargetStackImpl; -import ghidra.dbg.target.*; +import ghidra.dbg.target.TargetThread; import ghidra.dbg.util.PathUtils; public interface DbgModelTargetThread extends // @@ -55,15 +55,6 @@ public interface DbgModelTargetThread extends // } } - public default void threadStateChangedSpecific(DbgState state, DbgReason reason) { - TargetRegisterContainer container = - (TargetRegisterContainer) getCachedAttribute("Registers"); - TargetRegisterBank bank = (TargetRegisterBank) container.getCachedAttribute("User"); - if (state.equals(DbgState.STOPPED)) { - bank.readRegistersNamed(getCachedElements().keySet()); - } - } - @Override public default CompletableFuture setActive() { DbgManagerImpl manager = getManager(); @@ -75,4 +66,6 @@ public interface DbgModelTargetThread extends // public String getExecutingProcessorType(); + public void threadStateChangedSpecific(DbgState state, DbgReason reason); + } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java index 49bd954f12..685920d94a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetBreakpointContainerImpl.java @@ -28,11 +28,15 @@ import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.*; -@TargetObjectSchemaInfo(name = "BreakpointContainer", elements = { // - @TargetElementType(type = DbgModelTargetBreakpointSpecImpl.class) // -}, attributes = { // - @TargetAttributeType(type = Void.class) // -}, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "BreakpointContainer", + elements = { // + @TargetElementType(type = DbgModelTargetBreakpointSpecImpl.class) // + }, + attributes = { // + @TargetAttributeType(type = Void.class) // + }, + canonicalContainer = true) public class DbgModelTargetBreakpointContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetBreakpointContainer { 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 346e1fbb37..1914d5af14 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 @@ -28,19 +28,30 @@ import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.dbg.util.PathUtils; import ghidra.util.datastruct.ListenerSet; -@TargetObjectSchemaInfo(name = "BreakpointSpec", attributes = { // - @TargetAttributeType( // +@TargetObjectSchemaInfo( + name = "BreakpointSpec", + attributes = { // + @TargetAttributeType( // name = TargetBreakpointSpec.CONTAINER_ATTRIBUTE_NAME, // type = DbgModelTargetBreakpointContainerImpl.class), // - @TargetAttributeType( // + @TargetAttributeType( // name = TargetBreakpointLocation.SPEC_ATTRIBUTE_NAME, // type = DbgModelTargetBreakpointSpecImpl.class), // - @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TYPE_ATTRIBUTE_NAME, type = String.class), // - @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_DISP_ATTRIBUTE_NAME, type = String.class), // - @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_PENDING_ATTRIBUTE_NAME, type = String.class), // - @TargetAttributeType(name = DbgModelTargetBreakpointSpecImpl.BPT_TIMES_ATTRIBUTE_NAME, type = Integer.class), // - @TargetAttributeType(type = Void.class) // -}, canonicalContainer = true) + @TargetAttributeType( + name = DbgModelTargetBreakpointSpecImpl.BPT_TYPE_ATTRIBUTE_NAME, + type = String.class), // + @TargetAttributeType( + name = DbgModelTargetBreakpointSpecImpl.BPT_DISP_ATTRIBUTE_NAME, + type = String.class), // + @TargetAttributeType( + name = DbgModelTargetBreakpointSpecImpl.BPT_PENDING_ATTRIBUTE_NAME, + type = String.class), // + @TargetAttributeType( + name = DbgModelTargetBreakpointSpecImpl.BPT_TIMES_ATTRIBUTE_NAME, + type = Integer.class), // + @TargetAttributeType(type = Void.class) // + }, + canonicalContainer = true) public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl implements DbgModelTargetBreakpointSpec { @@ -117,10 +128,9 @@ public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl /** * Update the enabled field * - * This does not actually toggle the breakpoint. It just updates the field - * and calls the proper listeners. To actually toggle the breakpoint, use - * {@link #toggle(boolean)} instead, which if effective, should eventually - * cause this method to be called. + * This does not actually toggle the breakpoint. It just updates the field and calls the proper + * listeners. To actually toggle the breakpoint, use {@link #toggle(boolean)} instead, which if + * effective, should eventually cause this method to be called. * * @param enabled true if enabled, false if disabled * @param reason a description of the cause (not really used, yet) 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 1b96e5c0cb..cd96e0b6c6 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 @@ -35,9 +35,13 @@ import ghidra.dbg.target.schema.*; import ghidra.program.model.address.Address; import ghidra.util.datastruct.WeakValueHashMap; -@TargetObjectSchemaInfo(name = "Memory", elements = { - @TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) }, attributes = { - @TargetAttributeType(type = Void.class) }, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "Memory", + elements = { + @TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) }, + attributes = { + @TargetAttributeType(type = Void.class) }, + canonicalContainer = true) public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetMemoryContainer { @@ -49,12 +53,13 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl public DbgModelTargetMemoryContainerImpl(DbgModelTargetProcess process) { super(process.getModel(), process, "Memory", "MemoryContainer"); this.process = process; + requestElements(true); } @Override public CompletableFuture requestElements(boolean refresh) { DbgModelTargetProcess targetProcess = getParentProcess(); - if (!targetProcess.getProcess().equals(getManager().getCurrentProcess())) { + if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) { return AsyncUtils.NIL; } return listMemory().thenAccept(byName -> { @@ -258,8 +263,4 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl return CompletableFuture.completedFuture(null); } - @Override - protected void update() { - requestElements(true); - } } 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 adbcf161a8..c1056b76f8 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 @@ -84,22 +84,12 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject existingAttributes = getCachedAttributes(); - Boolean autoupdate = (Boolean) existingAttributes.get("autoupdate"); - if (autoupdate != null && autoupdate) { - requestAttributes(true); - requestElements(true); - } - } - protected void checkExited(DbgState state, DbgCause cause) { TargetExecutionState exec = TargetExecutionState.INACTIVE; switch (state) { 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 4b38c0253f..28abb2868e 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 @@ -30,12 +30,16 @@ import ghidra.dbg.target.TargetConfigurable; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.*; -@TargetObjectSchemaInfo(name = "ProcessContainer", elements = { // - @TargetElementType(type = DbgModelTargetProcessImpl.class) // -}, attributes = { // - @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), // - @TargetAttributeType(type = Void.class) // -}, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "ProcessContainer", + elements = { // + @TargetElementType(type = DbgModelTargetProcessImpl.class) // + }, + attributes = { // + @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), // + @TargetAttributeType(type = Void.class) // + }, + canonicalContainer = true) public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetProcessContainer, DbgModelTargetConfigurable { @@ -99,12 +103,20 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl if (modules != null) { modules.libraryLoaded(info.toString()); } + DbgModelTargetMemoryContainer memory = process.getMemory(); + if (memory != null) { + memory.requestElements(false); + } } @Override public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { DbgModelTargetProcess process = getTargetProcess(proc); process.getModules().libraryUnloaded(info.toString()); + DbgModelTargetMemoryContainer memory = process.getMemory(); + if (memory != null) { + memory.requestElements(false); + } } @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 0d0cd2c015..59292626b8 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 @@ -29,13 +29,34 @@ import ghidra.dbg.target.TargetEventScope.TargetEventType; import ghidra.dbg.target.schema.*; import ghidra.dbg.util.PathUtils; -@TargetObjectSchemaInfo(name = "Process", elements = { - @TargetElementType(type = Void.class) }, attributes = { - @TargetAttributeType(name = "Debug", type = DbgModelTargetDebugContainerImpl.class, required = true, fixed = true), - @TargetAttributeType(name = "Memory", type = DbgModelTargetMemoryContainerImpl.class, required = true, fixed = true), - @TargetAttributeType(name = "Modules", type = DbgModelTargetModuleContainerImpl.class, required = true, fixed = true), - @TargetAttributeType(name = "Threads", type = DbgModelTargetThreadContainerImpl.class, required = true, fixed = true), - @TargetAttributeType(name = DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, type = Long.class), +@TargetObjectSchemaInfo( + name = "Process", + elements = { + @TargetElementType(type = Void.class) }, + attributes = { + @TargetAttributeType( + name = "Debug", + type = DbgModelTargetDebugContainerImpl.class, + required = true, + fixed = true), + @TargetAttributeType( + name = "Memory", + type = DbgModelTargetMemoryContainerImpl.class, + required = true, + fixed = true), + @TargetAttributeType( + name = "Modules", + type = DbgModelTargetModuleContainerImpl.class, + required = true, + fixed = true), + @TargetAttributeType( + name = "Threads", + type = DbgModelTargetThreadContainerImpl.class, + required = true, + fixed = true), + @TargetAttributeType( + name = DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, + type = Long.class), @TargetAttributeType(type = Void.class) }) public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl implements DbgModelTargetProcess { @@ -219,6 +240,11 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl return modules; } + @Override + public DbgModelTargetMemoryContainer getMemory() { + return memory; + } + @Override public DbgProcess getProcess() { return process; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java index c257de0766..f74a37d1b1 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRegisterContainerImpl.java @@ -31,11 +31,17 @@ import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode; import ghidra.dbg.util.ConversionUtils; -@TargetObjectSchemaInfo(name = "RegisterContainer", elements = { - @TargetElementType(type = DbgModelTargetRegisterImpl.class) }, elementResync = ResyncMode.ONCE, // - attributes = { - @TargetAttributeType(name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, type = DbgModelTargetRegisterContainerImpl.class), - @TargetAttributeType(type = Void.class) }, canonicalContainer = true) +@TargetObjectSchemaInfo( + name = "RegisterContainer", + elements = { + @TargetElementType(type = DbgModelTargetRegisterImpl.class) }, + elementResync = ResyncMode.ONCE, // + attributes = { + @TargetAttributeType( + name = TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, + type = DbgModelTargetRegisterContainerImpl.class), + @TargetAttributeType(type = Void.class) }, + canonicalContainer = true) public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImpl implements DbgModelTargetRegisterContainerAndBank { @@ -78,7 +84,7 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp } public void threadStateChangedSpecific(DbgState state, DbgReason reason) { - if (state.equals(DbgState.STOPPED)) { + if (!state.equals(DbgState.RUNNING)) { readRegistersNamed(getCachedElements().keySet()); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackImpl.java index 979c6233f1..9281f7ce18 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackImpl.java @@ -20,7 +20,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import agent.dbgeng.manager.DbgStackFrame; +import agent.dbgeng.manager.*; import agent.dbgeng.model.iface2.*; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.*; @@ -83,32 +83,12 @@ public class DbgModelTargetStackImpl extends DbgModelTargetObjectImpl } */ - @Override - public void onRunning() { - // NB: We don't want to do this apparently - //invalidateRegisterCaches(); - setAccessible(false); - } - - @Override - public void onStopped() { - setAccessible(true); - if (thread.getThread().getId().equals(getManager().getEventThread().getId())) { - update(); + public void threadStateChangedSpecific(DbgState state, DbgReason reason) { + if (!state.equals(DbgState.RUNNING)) { + requestElements(true).exceptionally(e -> { + Msg.error(this, "Could not update stack " + this + " on STOPPED"); + return null; + }); } } - - /** - * Re-fetch the stack frames, generating events for updates - * - * GDB doesn't produce stack change events, but they should only ever happen by running a - * target. Thus, every time we're STOPPED, this method should be called. - */ - @Override - public void update() { - requestElements(true).exceptionally(e -> { - Msg.error(this, "Could not update stack " + this + " on STOPPED"); - return null; - }); - } } 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 9bc1d8b600..edf58dbd0c 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 @@ -123,6 +123,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl ), reason.desc()); //setExecutionState(targetState, reason.desc()); registers.threadStateChangedSpecific(state, reason); + stack.threadStateChangedSpecific(state, reason); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/model/invm/InVmModelForDbgengRootAttacherTest.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/model/invm/InVmModelForDbgengRootAttacherTest.java index 6b21401aca..5597327acb 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/model/invm/InVmModelForDbgengRootAttacherTest.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/test/java/agent/dbgeng/model/invm/InVmModelForDbgengRootAttacherTest.java @@ -15,6 +15,9 @@ */ package agent.dbgeng.model.invm; +import org.junit.Ignore; +import org.junit.Test; + import agent.dbgeng.model.AbstractModelForDbgengRootAttacherTest; public class InVmModelForDbgengRootAttacherTest extends AbstractModelForDbgengRootAttacherTest { @@ -22,4 +25,12 @@ public class InVmModelForDbgengRootAttacherTest extends AbstractModelForDbgengRo public ModelHost modelHost() throws Throwable { return new InVmDbgengModelHost(); } + + @Override + @Ignore + @Test + // Takes forever - passes w/ OTE on Memory in tear down + public void testAttachByPidThenResumeInterrupt() throws Throwable { + super.testAttachByPidThenResumeInterrupt(); + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/gadp/impl/WrappedDbgModel.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/gadp/impl/WrappedDbgModel.java index 5d3916c22f..cfe2e965f1 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/gadp/impl/WrappedDbgModel.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/gadp/impl/WrappedDbgModel.java @@ -580,7 +580,11 @@ public class WrappedDbgModel @Override public void setCurrentThreadId(DebugThreadId dti) { - client.getSystemObjects().setCurrentThreadId(dti); + DebugSystemObjects so = client.getSystemObjects(); + DebugThreadId currentThreadId = so.getCurrentThreadId(); + if (dti.id != currentThreadId.id) { + so.setCurrentThreadId(dti); + } /* if (USE_CLIENT) { System.err.println("setCurrentThread"); 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 16ba3a4c62..fb0e06ade9 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 @@ -94,7 +94,10 @@ public class HDMAUtil { if (kind.equals(ModelObjectKind.OBJECT_INTRINSIC) || kind.equals(ModelObjectKind.OBJECT_TARGET_OBJECT) || kind.equals(ModelObjectKind.OBJECT_TARGET_OBJECT_REFERENCE)) { - return target.getRawValueMap(); + Map map = target.getRawValueMap(); + if (!map.isEmpty()) { + return map; + } } return target.getKeyValueMap(); } 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 70cdb8c11f..42f828981e 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 @@ -49,26 +49,32 @@ public class DbgListAttributesCommand extends AbstractDbgCommand> @Override public void invoke() { - updatedAttributes = new TreeMap<>(TargetObjectKeyComparator.ATTRIBUTE); - Map map = access.getAttributes(path); - Map existingAttributes = targetObject.getCachedAttributes(); - for (String key : map.keySet()) { - DbgModel2TargetProxy proxyAttribute; - ModelObject obj = map.get(key); - String atKey = obj.getSearchKey(); - Object object = existingAttributes.get(atKey); - if (object != null && (object instanceof DbgModelTargetObject)) { - proxyAttribute = (DbgModel2TargetProxy) object; - DelegateDbgModel2TargetObject delegate = proxyAttribute.getDelegate(); - delegate.setModelObject(obj); - updatedAttributes.put(key, proxyAttribute); - } - else { - proxyAttribute = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject - .makeProxy(targetObject.getModel(), targetObject, atKey, obj); - updatedAttributes.put(key, proxyAttribute); + try { + updatedAttributes = new TreeMap<>(TargetObjectKeyComparator.ATTRIBUTE); + Map map = access.getAttributes(path); + Map existingAttributes = targetObject.getCachedAttributes(); + for (String key : map.keySet()) { + DbgModel2TargetProxy proxyAttribute; + ModelObject obj = map.get(key); + String atKey = obj.getSearchKey(); + Object object = existingAttributes.get(atKey); + if (object != null && (object instanceof DbgModelTargetObject)) { + proxyAttribute = (DbgModel2TargetProxy) object; + DelegateDbgModel2TargetObject delegate = proxyAttribute.getDelegate(); + delegate.setModelObject(obj); + updatedAttributes.put(key, proxyAttribute); + } + else { + proxyAttribute = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject + .makeProxy(targetObject.getModel(), targetObject, atKey, obj); + updatedAttributes.put(key, proxyAttribute); + } } + updatedAttributes.putAll(targetObject.getIntrinsics()); + } + catch (Exception e) { + System.err.println("Failure in ListAttributes " + targetObject); + e.printStackTrace(); } - updatedAttributes.putAll(targetObject.getIntrinsics()); } } 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 478e9394cb..51a23e9da1 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 @@ -227,9 +227,11 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject { + DbgModelTargetProcess eventProcess = (DbgModelTargetProcess) p; + DbgModel2TargetObjectImpl memory = + (DbgModel2TargetObjectImpl) eventProcess.getCachedAttribute("Memory"); + memory.requestElements(false); + }); }); } @@ -227,6 +234,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot getListeners().fire.event(getProxy(), eventThread, TargetEventType.MODULE_UNLOADED, "Library " + info.getModuleName() + " unloaded", List.of(mod)); }); + getObject(getManager().getEventProcess()).thenAccept(p -> { + DbgModelTargetProcess eventProcess = (DbgModelTargetProcess) p; + DbgModel2TargetObjectImpl memory = + (DbgModel2TargetObjectImpl) eventProcess.getCachedAttribute("Memory"); + memory.requestElements(false); + }); }); } @@ -335,6 +348,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot if (!process.getExecutionState().equals(TargetExecutionState.TERMINATED)) { process.setExecutionState(TargetExecutionState.INACTIVE, "Detached"); } + DbgModelTargetObject container = (DbgModelTargetObject) process.getParent(); + DelegateDbgModel2TargetObject delegate = + (DelegateDbgModel2TargetObject) container.getDelegate(); + delegate.changeElements(List.of( // + process.getIndex() // + ), List.of(), Map.of(), "Removed"); process.getParent().resync(); }); } @@ -344,10 +363,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DbgModelTargetProcess targetProcess = (DbgModelTargetProcess) getModel().getModelObject(proc); if (targetProcess != null) { - targetProcess.changeAttributes(List.of(), Map.of( // - TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.TERMINATED, // - DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, proc.getExitCode() // - ), "Exited"); + if (targetProcess.isValid()) { + targetProcess.changeAttributes(List.of(), Map.of( // + TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.TERMINATED, // + DbgModelTargetProcessImpl.EXIT_CODE_ATTRIBUTE_NAME, proc.getExitCode() // + ), "Exited"); + } getListeners().fire.event(targetProcess.getProxy(), null, TargetEventType.PROCESS_EXITED, "Process " + proc.getId() + " exited code=" + proc.getExitCode(), @@ -382,7 +403,9 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot TargetEventType eventType = getEventType(state, cause, reason); getListeners().fire.event(getProxy(), targetThread, eventType, "Thread " + thread.getId() + " state changed", List.of(targetThread)); - targetThread.threadStateChangedSpecific(state, reason); + DelegateDbgModel2TargetObject delegate = + (DelegateDbgModel2TargetObject) targetThread.getDelegate(); + delegate.threadStateChangedSpecific(state, reason); }); } @@ -417,7 +440,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot @Override public void breakpointCreated(DbgBreakpointInfo info, DbgCause cause) { - int id = info.getDebugBreakpoint().getId(); + int id = info.getId(); bptInfoMap.put(id, info); getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info); } @@ -425,7 +448,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot @Override public void breakpointModified(DbgBreakpointInfo newInfo, DbgBreakpointInfo oldInfo, DbgCause cause) { - int id = newInfo.getDebugBreakpoint().getId(); + int id = newInfo.getId(); bptInfoMap.put(id, newInfo); getObjectRevisited(newInfo.getProc(), List.of("Debug", "Breakpoints"), newInfo); } 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 88fe034660..d61f49f1df 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 @@ -195,7 +195,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp model.getManager().addEventsListener((DbgEventsListener) proxy); } setModelObject(modelObject); - update0(); + init(); } public DelegateDbgModel2TargetObject clone(String key, ModelObject modelObject) { @@ -224,6 +224,12 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp return ret; } + @Override + protected void doInvalidate(TargetObject branch, String reason) { + super.doInvalidate(branch, reason); + getManager().removeStateListener(accessListener); + } + protected void checkExited(DbgState state, DbgCause cause) { TargetExecutionState exec = TargetExecutionState.INACTIVE; switch (state) { @@ -274,7 +280,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } } - public void update0() { + public void init() { if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) { return; } @@ -285,22 +291,11 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp return; } if (proxy instanceof DbgModelTargetRegisterContainer || // - proxy.getName().equals("Stack")) { + proxy.getName().equals("Stack") || + proxy.getName().equals("Debug")) { requestAttributes(false); return; } - /* - if (proxy instanceof DbgModelTargetRegisterBank) { - requestAttributes(false).thenAccept(__ -> { - DbgModelTargetRegisterBank bank = (DbgModelTargetRegisterBank) proxy; - Map result = bank.getValues(); - System.err.println("SERVER:fire.registersUpdated " + bank); - listeners.fire.registersUpdated(bank, result); - }); - return; - } - */ - if (proxy instanceof DbgModelTargetProcessContainer || // proxy instanceof DbgModelTargetThreadContainer || // proxy instanceof DbgModelTargetModuleContainer || // @@ -311,44 +306,6 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } } - private void update() { - if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) { - return; - } - if (proxy instanceof DbgModelTargetProcessContainer || // - proxy instanceof DbgModelTargetThreadContainer || // - proxy instanceof DbgModelTargetModuleContainer || // - proxy instanceof DbgModelTargetBreakpointContainer || // - proxy instanceof DbgModelTargetRegisterContainer || // - proxy instanceof DbgModelTargetRegisterBank || // - proxy instanceof DbgModelTargetStack || // - proxy instanceof DbgModelTargetTTD) { - requestElements(false); - requestAttributes(false); - return; - } - /* - if (proxy instanceof DbgModelTargetRegisterBank) { - requestAttributes(false).thenAccept(__ -> { - DbgModelTargetRegisterBank bank = (DbgModelTargetRegisterBank) proxy; - Map result = bank.getValues(); - System.err.println("SERVER:fire.registersUpdated " + bank); - listeners.fire.registersUpdated(bank, result); - }); - return; - } - */ - if (proxy instanceof DbgModelTargetRegister || // - proxy instanceof DbgModelTargetStackFrame) { - requestAttributes(false); - return; - } - if (proxy.getName().equals("Debug")) { - requestAttributes(false); - return; - } - } - public void onRunning() { invalidate(); setAccessible(false); @@ -356,7 +313,6 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp public void onStopped() { setAccessible(true); - update(); } public void onExit() { @@ -416,7 +372,6 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp @Override public void setBreakpointEnabled(boolean enabled) { - update(); this.breakpointEnabled = enabled; } @@ -425,4 +380,53 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp return breakpointActions; } + public void threadStateChangedSpecific(DbgState state, DbgReason reason) { + if (state.equals(DbgState.RUNNING)) { + return; + } + if (proxy instanceof TargetThread) { + List delegates = new ArrayList<>(); + TargetObject stack = + (TargetObject) getCachedAttribute("Stack"); + DbgModelTargetStack frames = + (DbgModelTargetStack) stack.getCachedAttribute("Frames"); + delegates.add((DelegateDbgModel2TargetObject) frames.getDelegate()); + DbgModelTargetRegisterContainer container = + (DbgModelTargetRegisterContainer) getCachedAttribute("Registers"); + delegates.add((DelegateDbgModel2TargetObject) container.getDelegate()); + DbgModelTargetRegisterBank bank = + (DbgModelTargetRegisterBank) container.getCachedAttribute("User"); + delegates.add((DelegateDbgModel2TargetObject) bank.getDelegate()); + for (DelegateDbgModel2TargetObject delegate : delegates) { + delegate.threadStateChangedSpecific(state, reason); + } + } + if (proxy instanceof TargetRegisterContainer) { + requestElements(false); + requestAttributes(false); + } + if (proxy instanceof TargetRegisterBank) { + TargetRegisterBank bank = (TargetRegisterBank) proxy; + //requestElements(false); + requestAttributes(false).thenAccept(__ -> { + bank.readRegistersNamed(getCachedAttributes().keySet()); + }); + } + if (proxy instanceof TargetStack) { + requestAttributes(false); + requestElements(false).thenAccept(__ -> { + for (TargetObject obj : getCachedElements().values()) { + if (obj instanceof TargetStackFrame) { + DbgModelTargetObject frame = (DbgModelTargetObject) obj; + DelegateDbgModel2TargetObject delegate = + (DelegateDbgModel2TargetObject) frame.getDelegate(); + delegate.threadStateChangedSpecific(state, reason); + } + } + }); + } + if (proxy instanceof TargetStackFrame) { + requestAttributes(false); + } + } } 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 7e00043b0c..8ca99de662 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 @@ -18,8 +18,8 @@