diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugDataSpaces.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugDataSpaces.java index 4fe1e9684f..797f0b1a3f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugDataSpaces.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugDataSpaces.java @@ -224,6 +224,8 @@ public interface DebugDataSpaces { DebugMemoryBasicInformation queryVirtual(long offset); + long virtualToPhysical(long offset); + /** * A shortcut for iterating over virtual memory regions. * @@ -276,6 +278,9 @@ public interface DebugDataSpaces { public DebugMemoryBasicInformation next() { DebugMemoryBasicInformation ret = next; next = getNext(); + if (ret.equals(next)) { + next = null; + } return ret; } }; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl1.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl1.java index 865fb7fd97..124bee8f0b 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl1.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl1.java @@ -268,4 +268,9 @@ public class DebugDataSpacesImpl1 implements DebugDataSpacesInternal { return read; } + @Override + public long virtualToPhysical(long offset) { + throw new UnsupportedOperationException("Not implemented in this interface"); + } + } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl2.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl2.java index 6517b798dd..88e45fffb0 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl2.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/dataspaces/DebugDataSpacesImpl2.java @@ -16,6 +16,7 @@ package agent.dbgeng.impl.dbgeng.dataspaces; import com.sun.jna.platform.win32.WinDef.ULONGLONG; +import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference; import com.sun.jna.platform.win32.WinNT.HRESULT; import com.sun.jna.platform.win32.COM.COMUtils; @@ -40,6 +41,9 @@ public class DebugDataSpacesImpl2 extends DebugDataSpacesImpl1 { if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { return null; } + if (hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) { + return null; + } COMUtils.checkRC(hr); return new DebugMemoryBasicInformation(pInfo.BaseAddress.longValue(), @@ -49,4 +53,14 @@ public class DebugDataSpacesImpl2 extends DebugDataSpacesImpl1 { new BitmaskSet<>(PageProtection.class, pInfo.Protect.intValue()), PageType.byValue(pInfo.Type.intValue())); } + + @Override + public long virtualToPhysical(long offsetV) { + ULONGLONG ullOffset = new ULONGLONG(offsetV); + ULONGLONGByReference pulOffset = new ULONGLONGByReference(); + HRESULT hr = jnaData.VirtualToPhysical(ullOffset, pulOffset); + COMUtils.checkRC(hr); + + return pulOffset.getValue().longValue(); + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/IDebugDataSpaces2.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/IDebugDataSpaces2.java index 2931c94b0b..cef7c7fdee 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/IDebugDataSpaces2.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/IDebugDataSpaces2.java @@ -17,6 +17,7 @@ package agent.dbgeng.jna.dbgeng.dataspaces; import com.sun.jna.platform.win32.Guid.IID; import com.sun.jna.platform.win32.WinDef.ULONGLONG; +import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference; import com.sun.jna.platform.win32.WinNT.HRESULT; import agent.dbgeng.jna.dbgeng.UnknownWithUtils.VTableIndex; @@ -43,4 +44,6 @@ public interface IDebugDataSpaces2 extends IDebugDataSpaces { } HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info); + + HRESULT VirtualToPhysical(ULONGLONG OffsetVirtual, ULONGLONGByReference OffsetPhysical); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/WrapIDebugDataSpaces2.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/WrapIDebugDataSpaces2.java index ff37757742..9411f07e7e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/WrapIDebugDataSpaces2.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/jna/dbgeng/dataspaces/WrapIDebugDataSpaces2.java @@ -18,6 +18,7 @@ package agent.dbgeng.jna.dbgeng.dataspaces; import com.sun.jna.Pointer; import com.sun.jna.Structure; import com.sun.jna.platform.win32.WinDef.ULONGLONG; +import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference; import com.sun.jna.platform.win32.WinNT.HRESULT; import agent.dbgeng.jna.dbgeng.WinNTExtra.MEMORY_BASIC_INFORMATION64; @@ -39,4 +40,11 @@ public class WrapIDebugDataSpaces2 extends WrapIDebugDataSpaces implements IDebu public HRESULT QueryVirtual(ULONGLONG Offset, MEMORY_BASIC_INFORMATION64.ByReference Info) { return _invokeHR(VTIndices2.QUERY_VIRTUAL, getPointer(), Offset, Info); } + + @Override + public HRESULT VirtualToPhysical(ULONGLONG OffsetVirtual, ULONGLONGByReference OffsetPhysical) { + return _invokeHR(VTIndices2.VIRTUAL_TO_PHYSICAL, getPointer(), OffsetVirtual, + OffsetPhysical); + } + } 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 d0548ffa99..bf7ec1d309 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 @@ -371,4 +371,6 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { DebugEventInformation getLastEventInformation(); + DbgSession getSessionComputeIfAbsent(DebugSessionId debugSessionId, boolean b); + } 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 5d4b273f05..f7d75a80eb 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,7 @@ 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/DbgListMemoryRegionsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommand.java index 53b1f2faef..941a2be218 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 @@ -40,12 +40,16 @@ public class DbgListMemoryRegionsCommand extends AbstractDbgCommand complete(DbgPendingCommand pending) { Map memory = manager.getKnownMemoryRegions(); + if (memoryRegions.isEmpty()) { + Msg.error(this, "Switching to !address for memory"); + manager.setAltMemoryQuery(true); + } for (DbgModuleMemory region : memoryRegions) { if (memory.containsValue(region)) { continue; // Do nothing, we're in sync } if (!memory.isEmpty()) { - Msg.warn(this, "Resync: Was missing memory: " + region.getId()); + Msg.warn(this, "Resync: Was missing memory: " + Long.toHexString(region.getId())); } manager.addMemory(region); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommandAlt.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommandAlt.java new file mode 100644 index 0000000000..44ea5a38ac --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListMemoryRegionsCommandAlt.java @@ -0,0 +1,115 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package agent.dbgeng.manager.cmd; + +import java.util.*; +import java.util.Map.Entry; + +import agent.dbgeng.dbgeng.DebugControl; +import agent.dbgeng.dbgeng.DebugDataSpaces.PageState; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgModuleMemory; +import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; +import agent.dbgeng.manager.evt.DbgConsoleOutputEvent; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgModuleMemoryImpl; +import ghidra.util.Msg; + +public class DbgListMemoryRegionsCommandAlt extends AbstractDbgCommand> { + + private List memoryRegions = new ArrayList<>(); + + public DbgListMemoryRegionsCommandAlt(DbgManagerImpl manager) { + super(manager); + } + + @Override + public boolean handle(DbgEvent evt, DbgPendingCommand pending) { + if (evt instanceof AbstractDbgCompletedCommandEvent && pending.getCommand().equals(this)) { + return true; + } + else if (evt instanceof DbgConsoleOutputEvent) { + pending.steal(evt); + } + return false; + } + + @Override + public List complete(DbgPendingCommand pending) { + StringBuilder builder = new StringBuilder(); + for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) { + builder.append(out.getOutput()); + } + parse(builder.toString()); + + Map memory = manager.getKnownMemoryRegions(); + for (DbgModuleMemory region : memoryRegions) { + if (memory.containsValue(region)) { + continue; // Do nothing, we're in sync + } + if (!memory.isEmpty()) { + Msg.warn(this, "Resync: Was missing memory: " + Long.toHexString(region.getId())); + } + manager.addMemory(region); + } + List toRemove = new ArrayList<>(); + for (Entry entry : memory.entrySet()) { + if (memoryRegions.contains(entry.getValue())) { + continue; // Do nothing, we're in sync + } + toRemove.add(entry.getKey()); + } + for (Long key : toRemove) { + manager.removeMemory(key); + } + return memoryRegions; + } + + private void parse(String result) { + String[] lines = result.split("\n"); + for (String line : lines) { + if (line.startsWith("Mapping")) { + continue; + } + String[] fields = line.trim().split("\\s+"); + if (fields.length < 4) { + continue; + } + String start = fields[0].replaceAll("`", ""); + String end = fields[1].replaceAll("`", ""); + long startVal, endVal; + try { + startVal = Long.parseUnsignedLong(start, 16); + endVal = Long.parseUnsignedLong(end, 16); + } + catch (Exception e) { + continue; + } + String name = fields[3]; + ArrayList protect = new ArrayList(); + DbgModuleMemoryImpl region = new DbgModuleMemoryImpl(start, startVal, endVal, startVal, + protect, protect, PageState.COMMIT, name, true, true, true); + memoryRegions.add(region); + } + } + + @Override + public void invoke() { + DebugControl control = manager.getControl(); + control.execute("!address"); + } + +} 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 089ca8930d..11614cdcff 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 @@ -48,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 40655b4c9a..96e85ab505 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 @@ -45,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 73c84bdd74..802b396191 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 @@ -46,7 +46,7 @@ public class DbgListThreadsCommand extends AbstractDbgCommand(cur)) { if (updatedThreadIds.contains(id)) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadMemoryCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadMemoryCommand.java index 1608ed517d..b093aa2c4f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadMemoryCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadMemoryCommand.java @@ -19,6 +19,7 @@ import java.nio.ByteBuffer; import com.google.common.collect.*; +import agent.dbgeng.dbgeng.DebugDataSpaces; import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgManagerImpl; @@ -49,6 +50,7 @@ public class DbgReadMemoryCommand extends AbstractDbgCommand> { @Override public void invoke() { - readLen = manager.getDataSpaces().readVirtual(addr, buf, len); + DebugDataSpaces dataSpaces = manager.getDataSpaces(); + readLen = dataSpaces.readVirtual(addr, buf, len); } } 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 7ff9bced81..70f9c2bf2d 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 @@ -116,6 +116,7 @@ public class DbgManagerImpl implements DbgManager { private DbgThread eventThread; private volatile boolean waiting = false; private boolean kernelMode = false; + private boolean altMemoryQuery = false; private boolean ignoreEventThread = false; private CompletableFuture continuation; private long processCount = 0; @@ -139,11 +140,16 @@ public class DbgManagerImpl implements DbgManager { } public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process, - int tid) { + int tid, boolean fire) { synchronized (threads) { if (!threads.containsKey(id)) { DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid); thread.add(); + if (fire) { + Causes cause = DbgCause.Causes.UNCLAIMED; + getEventListeners().fire.threadCreated(thread, cause); + getEventListeners().fire.threadSelected(thread, null, cause); + } } return threads.get(id); } @@ -208,11 +214,14 @@ public class DbgManagerImpl implements DbgManager { } } - public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, int pid) { + public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, int pid, boolean fire) { synchronized (processes) { if (!processes.containsKey(id)) { DbgProcessImpl process = new DbgProcessImpl(this, id, pid); process.add(); + if (fire) { + getEventListeners().fire.processAdded(process, DbgCause.Causes.UNCLAIMED); + } } return processes.get(id); } @@ -245,11 +254,14 @@ public class DbgManagerImpl implements DbgManager { } } - public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id) { + public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id, boolean fire) { synchronized (sessions) { if (!sessions.containsKey(id) && id.id >= 0) { DbgSessionImpl session = new DbgSessionImpl(this, id); session.add(); + if (fire) { + getEventListeners().fire.sessionAdded(session, DbgCause.Causes.UNCLAIMED); + } } return sessions.get(id); } @@ -635,11 +647,11 @@ public class DbgManagerImpl implements DbgManager { lastEventInformation = control.getLastEventInformation(); lastEventInformation.setSession(esid); lastEventInformation.setExecutingProcessorType(execType); - currentSession = eventSession = getSessionComputeIfAbsent(esid); + currentSession = eventSession = getSessionComputeIfAbsent(esid, true); currentProcess = - eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId()); + eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true); currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess, - so.getCurrentThreadSystemId()); + so.getCurrentThreadSystemId(), false); if (eventThread != null) { ((DbgThreadImpl) eventThread).setInfo(lastEventInformation); } @@ -714,9 +726,9 @@ public class DbgManagerImpl implements DbgManager { DebugThreadId eventId = updateState(); DbgProcessImpl process = getCurrentProcess(); int tid = so.getCurrentThreadSystemId(); - DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid); + DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid, true); getEventListeners().fire.eventSelected(evt, evt.getCause()); - getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED); + //getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED); getEventListeners().fire.threadSelected(thread, null, evt.getCause()); String key = Integer.toHexString(eventId.id); @@ -789,7 +801,7 @@ public class DbgManagerImpl implements DbgManager { DebugProcessId id = so.getProcessIdByHandle(handle); //so.setCurrentProcessId(id); int pid = so.getCurrentProcessSystemId(); - DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid); + DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid, true); getEventListeners().fire.eventSelected(evt, evt.getCause()); getEventListeners().fire.processAdded(proc, evt.getCause()); getEventListeners().fire.processSelected(proc, evt.getCause()); @@ -797,9 +809,9 @@ public class DbgManagerImpl implements DbgManager { 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()); + getThreadComputeIfAbsent(idt, proc, tid, true); + //getEventListeners().fire.threadCreated(thread, evt.getCause()); + //getEventListeners().fire.threadSelected(thread, null, evt.getCause()); //proc.moduleLoaded(info.moduleInfo); //getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause()); @@ -1606,6 +1618,14 @@ public class DbgManagerImpl implements DbgManager { this.kernelMode = kernelMode; } + public boolean useAltMemoryQuery() { + return altMemoryQuery; + } + + public void setAltMemoryQuery(boolean altMemoryQuery) { + this.altMemoryQuery = altMemoryQuery; + } + public void setContinuation(CompletableFuture continuation) { this.continuation = continuation; } 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 74cdab2fb8..9a27eaf9c6 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 @@ -83,7 +83,7 @@ public class DbgSessionImpl implements DbgSession { */ public void add() { manager.sessions.put(id, this); - manager.getEventListeners().fire.sessionAdded(this, DbgCause.Causes.UNCLAIMED); + //manager.getEventListeners().fire.sessionAdded(this, DbgCause.Causes.UNCLAIMED); //manager.addSession(this, cause); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/AbstractDbgModel.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/AbstractDbgModel.java index a93feae241..0cc494fd98 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/AbstractDbgModel.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/AbstractDbgModel.java @@ -44,4 +44,6 @@ public abstract class AbstractDbgModel extends AbstractDebuggerObjectModel { public abstract void deleteModelObject(Object object); + public abstract boolean isSuppressDescent(); + } 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 fe70a1c952..b500a8686f 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 @@ -53,6 +53,10 @@ public interface DbgModelTargetProcess extends // public void threadStateChangedSpecific(DbgThread thread, DbgState state); public default DbgProcess getProcess() { + return getProcess(true); + } + + public default DbgProcess getProcess(boolean fire) { DbgManagerImpl manager = getManager(); DebugSystemObjects so = manager.getSystemObjects(); try { @@ -62,7 +66,7 @@ public interface DbgModelTargetProcess extends // if (id == null) { id = so.getCurrentProcessId(); } - return manager.getProcessComputeIfAbsent(id, pid); + return manager.getProcessComputeIfAbsent(id, pid, fire); } catch (IllegalArgumentException e) { return manager.getCurrentProcess(); 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 2c626abee2..7ef618bd6d 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 @@ -44,12 +44,16 @@ public interface DbgModelTargetSession extends // DbgModelTargetProcessContainer getProcesses(); public default DbgSession getSession() { + return getSession(true); + } + + public default DbgSession getSession(boolean fire) { DbgManagerImpl manager = getManager(); try { String index = PathUtils.parseIndex(getName()); Integer sid = Integer.decode(index); DebugSessionId id = new DebugSessionId(sid); - return manager.getSessionComputeIfAbsent(id); + return manager.getSessionComputeIfAbsent(id, fire); } 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 4067fa2059..9cf4c824d0 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 @@ -35,6 +35,10 @@ public interface DbgModelTargetThread extends // DbgModelSelectableObject { public default DbgThread getThread() { + return getThread(false); + } + + public default DbgThread getThread(boolean fire) { DbgManagerImpl manager = getManager(); DebugSystemObjects so = manager.getSystemObjects(); try { @@ -46,7 +50,7 @@ public interface DbgModelTargetThread extends // } DbgModelTargetProcess parentProcess = getParentProcess(); DbgProcessImpl process = (DbgProcessImpl) parentProcess.getProcess(); - DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid); + DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, fire); return thread; } catch (IllegalArgumentException e) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java index b030ff7c7e..c6a951c951 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelImpl.java @@ -25,8 +25,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; import agent.dbgeng.dbgeng.DebugSessionId; import agent.dbgeng.manager.DbgManager; -import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.manager.impl.DbgSessionImpl; +import agent.dbgeng.manager.DbgSession; import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.iface2.*; import ghidra.async.AsyncUtils; @@ -61,14 +60,14 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode protected final CompletableFuture completedRoot; protected Map objectMap = new HashMap<>(); + private boolean suppressDescent = false; public DbgModelImpl() { this.dbg = DbgManager.newInstance(); //System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX)); this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA); this.completedRoot = CompletableFuture.completedFuture(root); - DbgSessionImpl s = new DbgSessionImpl((DbgManagerImpl) dbg, new DebugSessionId(0)); - s.add(); + DbgSession s = dbg.getSessionComputeIfAbsent(new DebugSessionId(0), true); DbgModelTargetSessionContainer sessions = root.sessions; this.session = (DbgModelTargetSessionImpl) sessions.getTargetSession(s); addModelRoot(root); @@ -121,8 +120,8 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode } @Override - public DbgManagerImpl getManager() { - return (DbgManagerImpl) dbg; + public DbgManager getManager() { + return dbg; } @Override @@ -180,4 +179,13 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode return ExceptionUtils.rethrow(ex); }); } + + @Override + public boolean isSuppressDescent() { + return suppressDescent; + } + + public void setSuppressDescent(boolean suppressDescent) { + this.suppressDescent = suppressDescent; + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetEventContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetEventContainerImpl.java index 893b2b6c8e..e24eee767d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetEventContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetEventContainerImpl.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import agent.dbgeng.manager.DbgEventFilter; import agent.dbgeng.manager.cmd.DbgListEventFiltersCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; import agent.dbgeng.model.iface2.*; import ghidra.async.AsyncUtils; import ghidra.dbg.target.TargetObject; @@ -53,7 +54,9 @@ public class DbgModelTargetEventContainerImpl extends DbgModelTargetObjectImpl @Override public CompletableFuture requestElements(boolean refresh) { DbgModelTargetProcess targetProcess = getParentProcess(); - if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) { + DbgProcessImpl currentProcess = getManager().getCurrentProcess(); + if (!refresh || + (currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) { return AsyncUtils.NIL; } return listEventFilters().thenAccept(byName -> { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExceptionContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExceptionContainerImpl.java index 4a85bd3f5e..b6b7deff76 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExceptionContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExceptionContainerImpl.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import agent.dbgeng.manager.DbgExceptionFilter; import agent.dbgeng.manager.cmd.DbgListExceptionFiltersCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; import agent.dbgeng.model.iface2.*; import ghidra.async.AsyncUtils; import ghidra.dbg.target.TargetObject; @@ -53,7 +54,9 @@ public class DbgModelTargetExceptionContainerImpl extends DbgModelTargetObjectIm @Override public CompletableFuture requestElements(boolean refresh) { DbgModelTargetProcess targetProcess = getParentProcess(); - if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) { + DbgProcessImpl currentProcess = getManager().getCurrentProcess(); + if (!refresh || + (currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) { return AsyncUtils.NIL; } return listExceptionFilters().thenAccept(byName -> { 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 cd96e0b6c6..74f5c47c9b 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 @@ -26,6 +26,7 @@ import com.google.common.collect.RangeSet; import agent.dbgeng.manager.DbgModuleMemory; import agent.dbgeng.manager.cmd.*; import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; import agent.dbgeng.model.iface2.*; import ghidra.async.AsyncUtils; import ghidra.dbg.error.DebuggerMemoryAccessException; @@ -53,13 +54,17 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl public DbgModelTargetMemoryContainerImpl(DbgModelTargetProcess process) { super(process.getModel(), process, "Memory", "MemoryContainer"); this.process = process; - requestElements(true); + if (!getModel().isSuppressDescent()) { + requestElements(true); + } } @Override public CompletableFuture requestElements(boolean refresh) { DbgModelTargetProcess targetProcess = getParentProcess(); - if (!refresh || !targetProcess.getProcess().equals(getManager().getCurrentProcess())) { + DbgProcessImpl currentProcess = getManager().getCurrentProcess(); + if (!refresh || + (currentProcess != null && !currentProcess.equals(targetProcess.getProcess()))) { return AsyncUtils.NIL; } return listMemory().thenAccept(byName -> { @@ -90,6 +95,9 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl if (manager.isKernelMode()) { return manager.execute(new DbgListKernelMemoryRegionsCommand(manager)); } + if (manager.useAltMemoryQuery()) { + return manager.execute(new DbgListMemoryRegionsCommandAlt(manager)); + } return manager.execute(new DbgListMemoryRegionsCommand(manager)); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java index d5833593de..3a267508b9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetModuleContainerImpl.java @@ -45,7 +45,9 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl super(process.getModel(), process, "Modules", "ModuleContainer"); this.targetProcess = process; this.process = process.process; - requestElements(false); + if (!getModel().isSuppressDescent()) { + 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 435223dda0..348de016ec 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 @@ -121,7 +121,11 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl return "[kernel]"; } - String pidstr = Long.toString(process.getPid(), base); + Long pid = process.getPid(); + if (pid < 0) { + return "[" + process.getId().id + "]"; + } + String pidstr = Long.toString(pid, base); if (base == 16) { pidstr = "0x" + pidstr; } 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 db6a2f9f5c..5c7aa075bb 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 @@ -55,10 +55,12 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp super(thread.getModel(), thread, "Registers", "RegisterContainer"); this.thread = thread.getThread(); - requestElements(false); - changeAttributes(List.of(), List.of(), Map.of( // - TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, this // - ), "Initialized"); + if (!getModel().isSuppressDescent()) { + requestElements(false); + changeAttributes(List.of(), List.of(), Map.of( // + TargetRegisterBank.DESCRIPTIONS_ATTRIBUTE_NAME, this // + ), "Initialized"); + } } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java index 9822d50a3c..532a150890 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadContainerImpl.java @@ -48,7 +48,9 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized"); getManager().addEventsListener(this); - requestElements(false); + if (!getModel().isSuppressDescent()) { + requestElements(false); + } } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java index 0df542100d..4b1d1d949f 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 @@ -109,7 +109,11 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl if (getManager().isKernelMode()) { return "[PR" + thread.getId().id + "]"; } - String tidstr = Long.toString(thread.getTid(), base); + Long tid = thread.getTid(); + if (tid < 0) { + return "[" + thread.getId().id + "]"; + } + String tidstr = Long.toString(tid, base); if (base == 16) { tidstr = "0x" + tidstr; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java index b8e9eeefa8..b1ce758899 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetTraceOrDumpConnectorImpl.java @@ -18,6 +18,7 @@ package agent.dbgeng.model.impl; import java.util.*; import java.util.concurrent.CompletableFuture; +import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface2.DbgModelTargetConnector; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; @@ -79,7 +80,12 @@ public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObject @Override public CompletableFuture launch(Map args) { return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { - getManager().openFile(args).handle(seq::nextIgnore); + DbgManagerImpl manager = getManager(); + Boolean qv = (Boolean) args.get("UseQueryVirtual"); + if (qv != null) { + manager.setAltMemoryQuery(!qv); + } + manager.openFile(args).handle(seq::nextIgnore); }).finish().exceptionally((exc) -> { throw new DebuggerUserException("Launch failed for " + args); }); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java new file mode 100644 index 0000000000..f9ab0962db --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java @@ -0,0 +1,161 @@ +/* ### + * 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. + */ +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.google.common.collect.Range; + +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.model.AbstractDbgModel; +import ghidra.app.script.GhidraScript; +import ghidra.app.services.DebuggerModelService; +import ghidra.app.services.DebuggerTraceManagerService; +import ghidra.dbg.DebuggerObjectModel; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.Language; +import ghidra.trace.model.Trace; +import ghidra.trace.model.memory.*; +import ghidra.util.LockHold; +import ghidra.util.Msg; +import ghidra.util.database.UndoableTransaction; +import ghidra.util.exception.DuplicateNameException; + +/** + * This script populates a trace database with memory derived from "!address". This is particularly + * useful for dump files and other cases where QueryVirtual fails. + * + *

+ * Your current tool had better be the "TraceBrowser"! The demonstration serves two purposes. 1) It + * puts interesting data into the TraceBrowser and leaves some annotations as an exercise. 2) It + * demonstrates how a decent portion the Trace API works. + * + *

+ * A Trace is basically a collection of observations of memory and registers over the lifetime of an + * application or computer system. In Ghidra, the Trace object also supports many of the same + * annotations as does Program. In the same way that Program brings knowledge markup to an image of + * bytes, Trace brings knowledge markup to bytes observed over time. + * + */ +public class BangAddressToMemory extends GhidraScript { + + /** + * The Memory APIs all use Java NIO ByteBuffer. While it has it can sometimes be annoying, it + * provides most of the conveniences you'd need for packing arbitrary data into a memory buffer. + * I'll allocate one here large enough to write a couple values at a time. + */ + private ByteBuffer buf = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN); + + private Language lang; + private Trace trace; + private TraceMemoryManager memory; + + private AddressSpace defaultSpace; + + + private DebuggerModelService modelService; + private DebuggerTraceManagerService managerService; + + /** + * Create an address in the processor's (x86_64) default space. + * + * @param offset the byte offset + * @return the address + */ + protected Address addr(long offset) { + return defaultSpace.getAddress(offset); + } + + /** + * Create an address range in the processor's default space. + * + * @param min the minimum byte offset + * @param max the maximum (inclusive) byte offset + * @return the range + */ + protected AddressRange rng(long min, long max) { + return new AddressRangeImpl(addr(min), addr(max)); + } + + @Override + protected void run() throws Exception { + + modelService = state.getTool().getService(DebuggerModelService.class); + if (modelService == null) { + throw new RuntimeException("Unable to find DebuggerMemviewPlugin"); + } + + DebuggerObjectModel model = modelService.getCurrentModel(); + if (!(model instanceof AbstractDbgModel)) { + throw new RuntimeException("Current model must be an AbstractDbgModel"); + } + AbstractDbgModel dbgmodel = (AbstractDbgModel) model; + DbgManagerImpl manager = (DbgManagerImpl) dbgmodel.getManager(); + //client = manager.getClient(); + + managerService = state.getTool().getService(DebuggerTraceManagerService.class); + trace = managerService.getCurrentTrace(); + if (trace == null) { + throw new RuntimeException("Script requires an active trace"); + } + memory = trace.getMemoryManager(); + + lang = currentProgram.getLanguage(); + defaultSpace = lang.getAddressFactory().getDefaultAddressSpace(); + + manager.consoleCapture("!address").thenAccept(result -> { + parse(result); + }); + } + + private void parse(String result) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate memory", true); + LockHold hold = trace.lockWrite();) { + //Pattern pattern = Pattern.compile("\\s+(*)\\s+(*)\\s+"); + //Matcher matcher = pattern.matcher(fullclassname); + String[] lines = result.split("\n"); + for (String line : lines) { + if (line.startsWith("Mapping")) { + continue; + } + String[] fields = line.trim().split("\\s+"); + if (fields.length < 4) { + continue; + } + String startStr = fields[0].replaceAll("`", ""); + String endStr = fields[1].replaceAll("`", ""); + long start, end; + try { + start = Long.parseUnsignedLong(startStr, 16); + end = Long.parseUnsignedLong(endStr, 16); + } + catch (Exception e) { + continue; + } + String name = fields[3]; + AddressRange rng = rng(start, end - 1); + try { + TraceMemoryRegion region = + memory.addRegion(startStr, Range.atLeast(0L), rng, TraceMemoryFlag.READ, + TraceMemoryFlag.WRITE, TraceMemoryFlag.EXECUTE); + region.setName(name); + } + catch (TraceOverlappedRegionException | DuplicateNameException e) { + Msg.info(this, "Duplicate range at " + start); + } + } + } + } +} 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 5913f3768a..a4bb74794b 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 @@ -338,6 +338,11 @@ public class WrappedDbgModel return client.getDataSpaces().queryVirtual(offset); } + @Override + public long virtualToPhysical(long offset) { + return client.getDataSpaces().virtualToPhysical(offset); + } + // REGISTERS INTERFACE public DebugRegisterDescription getRegisterDescription(int i) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/KeyEnumeratorImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/KeyEnumeratorImpl.java index 37bca0dd50..c4cf51a2fd 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/KeyEnumeratorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/KeyEnumeratorImpl.java @@ -28,6 +28,7 @@ import agent.dbgmodel.dbgmodel.DbgModel; import agent.dbgmodel.dbgmodel.DbgModel.OpaqueCleanable; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.jna.dbgmodel.main.IKeyEnumerator; +import ghidra.util.Msg; public class KeyEnumeratorImpl implements KeyEnumeratorInternal { @SuppressWarnings("unused") @@ -56,12 +57,17 @@ public class KeyEnumeratorImpl implements KeyEnumeratorInternal { BSTRByReference bref = new BSTRByReference(); PointerByReference ppValue = new PointerByReference(); PointerByReference ppMetaData = new PointerByReference(); - HRESULT hr = jnaData.GetNext(bref, ppValue, ppMetaData); - if (hr.equals(COMUtilsExtra.E_BOUNDS) || hr.equals(COMUtilsExtra.E_FAIL)) { - //System.err.println("ret null"); - return null; + try { + HRESULT hr = jnaData.GetNext(bref, ppValue, ppMetaData); + if (hr.equals(COMUtilsExtra.E_BOUNDS) || hr.equals(COMUtilsExtra.E_FAIL)) { + //System.err.println("ret null"); + return null; + } + COMUtils.checkRC(hr); + } + catch (Error e) { + Msg.error(this, e.getMessage()); } - COMUtils.checkRC(hr); Pointer val = ppValue.getValue(); if (val != null) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java index f213f48027..fe94db20e7 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java @@ -152,6 +152,10 @@ public class ModelObjectImpl implements ModelObjectInternal { Msg.debug(this, searchKey + " scope not found"); return null; } + if (hr.equals(COMUtilsExtra.E_CANNOT_READ)) { + Msg.debug(this, searchKey + " cannot be read"); + return null; + } COMUtils.checkRC(hr); ModelObject retval = getObjectWithMetadata(ppObject, ppMetadata); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java index 48b4900954..51ede57815 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2Impl.java @@ -72,6 +72,7 @@ public class DbgModel2Impl extends AbstractDbgModel protected DbgModelTargetSession session; protected Map objectMap = new HashMap<>(); + private boolean suppressDescent = false; public DbgModel2Impl() { this.dbg = new DbgManager2Impl(); @@ -198,4 +199,13 @@ public class DbgModel2Impl extends AbstractDbgModel return ExceptionUtils.rethrow(ex); }); } + + @Override + public boolean isSuppressDescent() { + return suppressDescent; + } + + public void setSuppressDescent(boolean suppressDescent) { + this.suppressDescent = suppressDescent; + } } 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 67cfa33ca0..ead97cf1a3 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 @@ -250,9 +250,14 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject - + diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index 9871f7df36..ee652cabd3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -248,6 +248,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter private ToggleDockingAction actionToggleSelectionOnly; private ToggleDockingAction actionToggleIgnoreState; private ToggleDockingAction actionToggleUpdateWhileRunning; + private ToggleDockingAction actionSuppressDescent; @AutoConfigStateField private boolean autoRecord = true; @@ -259,6 +260,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter private boolean ignoreState = false; @AutoConfigStateField private boolean updateWhileRunning = true; + @AutoConfigStateField + private boolean suppressDescent = false; Set configurables = new HashSet<>(); private String lastMethod = ""; @@ -1002,6 +1005,19 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter .enabled(true) .buildAndInstallLocal(this); + groupTargetIndex++; + + /* + actionSuppressDescent = new ToggleActionBuilder("Automatically populate containers", plugin.getName()) + .menuPath("Maintenance","&Auto-populate") + .menuGroup(DebuggerResources.GROUP_TARGET, "M" + groupTargetIndex) + .helpLocation(new HelpLocation(plugin.getName(), "auto-populate containers")) + .onAction(ctx -> performToggleAutoPopulateContainers(ctx)) + .selected(isUpdateWhileRunning()) + .enabled(true) + .buildAndInstallLocal(this); + */ + groupTargetIndex = 0; new ActionBuilder("Quick Launch", plugin.getName()) @@ -1434,6 +1450,16 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter refresh(""); } + /* + public void performToggleAutoPopulateContainers(ActionContext context) { + suppressDescent = !actionSuppressDescent.isSelected(); + if (currentModel != null) { + currentModel.setSuppressDescent(suppressDescent); + } + refresh(""); + } + */ + protected void performAction(ActionContext context, boolean fallbackRoot, Class cls, Function> func, String errorMsg) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java index d64f1ed587..b08681a407 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java @@ -228,11 +228,13 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg val); } } - ProgramUserData userData = program.getProgramUserData(); - try (UndoableTransaction tid = UndoableTransaction.start(userData)) { - Element element = state.saveToXml(); - userData.setStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, - XmlUtilities.toString(element)); + if (program != null) { + ProgramUserData userData = program.getProgramUserData(); + try (UndoableTransaction tid = UndoableTransaction.start(userData)) { + Element element = state.saveToXml(); + userData.setStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, + XmlUtilities.toString(element)); + } } } @@ -253,6 +255,9 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg */ protected Map generateDefaultLauncherArgs( Map> params) { + if (program == null) { + return Map.of(); + } return Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, program.getExecutablePath()); } @@ -303,34 +308,44 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg * TODO: Supposedly, per-program, per-user config stuff is being generalized for analyzers. * Re-examine this if/when that gets merged */ - ProgramUserData userData = program.getProgramUserData(); - String property = userData.getStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, null); - if (property != null) { - try { - Element element = XmlUtilities.fromString(property); - SaveState state = new SaveState(element); - Map args = new LinkedHashMap<>(); - for (ParameterDescription param : params.values()) { - args.put(param.name, - ConfigStateField.getState(state, param.type, param.name)); + if (program != null) { + ProgramUserData userData = program.getProgramUserData(); + String property = + userData.getStringProperty(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, null); + if (property != null) { + try { + Element element = XmlUtilities.fromString(property); + SaveState state = new SaveState(element); + Map args = new LinkedHashMap<>(); + for (ParameterDescription param : params.values()) { + Object configState = + ConfigStateField.getState(state, param.type, param.name); + if (configState != null) { + args.put(param.name, configState); + } + } + if (!args.isEmpty()) { + return args; + } } - return args; - } - catch (JDOMException | IOException e) { - if (!forPrompt) { - throw new RuntimeException( - "Saved launcher args are corrupt, or launcher parameters changed. Not launching.", + catch (JDOMException | IOException e) { + if (!forPrompt) { + throw new RuntimeException( + "Saved launcher args are corrupt, or launcher parameters changed. Not launching.", + e); + } + Msg.error(this, + "Saved launcher args are corrup, or launcher parameters changed. Defaulting.", e); } - Msg.error(this, - "Saved launcher args are corrup, or launcher parameters changed. Defaulting.", - e); } + Map args = generateDefaultLauncherArgs(params); + saveLauncherArgs(args, params); + return args; } - Map args = generateDefaultLauncherArgs(params); - saveLauncherArgs(args, params); - return args; + return new LinkedHashMap<>(); + } /** diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebuggerObjectModel.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebuggerObjectModel.java index 2f4a665df2..b6e3d0de4e 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebuggerObjectModel.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/DebuggerObjectModel.java @@ -580,4 +580,5 @@ public interface DebuggerObjectModel { * @return a future which completes when all queued callbacks have been invoked */ CompletableFuture flushEvents(); + }