From 96902546169fe0fd618033006805d17a7fdba4f2 Mon Sep 17 00:00:00 2001 From: d-millar <33498836+d-millar@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:54:40 -0400 Subject: [PATCH] GP-3142: fix for read registers GP-3142: adding Populate to schema GP-3142: adding session id to the records GP-3142: post-review id->record GP-3142: post-review id->record GP-3142: post-review adds to interface GP-3142: post-review try-finally (missed two) GP-3142: post-review try-finally (missed one) GP-3142: post-review try-finally; clearer reset logic GP-3142: post-review better use of TargetMethod.Export GP-3142: minor fixes GP-3142: first pass at dbgeng kernel mods GP-3142: temp holdGP-3142: mods to differentiate system and engine idsGP-3142: fixes for bad system/engine differentationGP-3142: fixes for bad pid/tid <0 testGP-3142: fixes for selection logicGP-3142: attempting to mininize work done, esp. by expensive callsGP-3142: fix for stack framesGP-3142: minor bug fix for sys threadsGP-3142: better register/stack reads for non-system threadsGP-3142: warningsGP-3142: post-squash and rebaseGP-3142: missed a few RefreshBehavior candidatesGP-3142: miscellaneous fixesGP-3142: minimize workloadGP-3142: display fixes; refresh==true for resolved process/threadGP-3142: added re-populate methodsGP-3142: better kernel/user code re-useGP-3142: re-fix for fact that thread 0 belongs to process 0 --- .../dbgeng/dbgeng/DebugEventInformation.java | 4 +- .../agent/dbgeng/dbgeng/DebugProcessId.java | 37 +---- .../dbgeng/dbgeng/DebugProcessRecord.java | 34 ++++ .../agent/dbgeng/dbgeng/DebugSessionId.java | 37 +---- .../dbgeng/dbgeng/DebugSessionRecord.java | 34 ++++ .../dbgeng/DebugSystemProcessRecord.java | 34 ++++ .../dbgeng/DebugSystemSessionRecord.java | 34 ++++ .../dbgeng/DebugSystemThreadRecord.java | 34 ++++ .../agent/dbgeng/dbgeng/DebugThreadId.java | 36 +---- .../dbgeng/dbgeng/DebugThreadRecord.java | 34 ++++ .../dbgeng/advanced/DebugAdvancedImpl2.java | 2 +- .../sysobj/DebugSystemObjectsImpl1.java | 49 +++--- .../sysobj/DebugSystemObjectsImpl3.java | 17 +- .../java/agent/dbgeng/manager/DbgManager.java | 24 +++ .../manager/cmd/AbstractDbgCommand.java | 63 +++++++- .../cmd/AbstractDbgExecToAddressCommand.java | 2 +- .../manager/cmd/DbgListModulesCommand.java | 32 ++-- ...ava => DbgListOSMemoryRegionsCommand.java} | 4 +- .../cmd/DbgListOSProcessesCommand.java | 100 ++++++++++++ ...tate.java => DbgListOSThreadsCommand.java} | 60 ++++--- .../manager/cmd/DbgListProcessesCommand.java | 31 +++- .../manager/cmd/DbgListSymbolsCommand.java | 22 +-- .../manager/cmd/DbgListThreadsCommand.java | 45 ++++-- .../manager/cmd/DbgReadRegistersCommand.java | 38 ++--- .../manager/cmd/DbgResolveProcessCommand.java | 9 +- .../manager/cmd/DbgResolveThreadCommand.java | 8 +- .../cmd/DbgSetActiveProcessCommand.java | 2 +- .../cmd/DbgStackListFramesCommand.java | 46 +++--- .../cmd/DbgStackListOSFramesCommand.java | 119 ++++++++++++++ .../dbgeng/manager/cmd/DbgStepCommand.java | 2 +- .../dbgeng/manager/impl/DbgManagerImpl.java | 110 ++++++------- .../dbgeng/manager/impl/DbgProcessImpl.java | 4 + .../model/iface2/DbgModelTargetProcess.java | 3 +- .../iface2/DbgModelTargetRegisterBank.java | 5 +- .../model/iface2/DbgModelTargetSession.java | 10 +- .../model/iface2/DbgModelTargetThread.java | 7 +- .../agent/dbgeng/model/impl/DbgModelImpl.java | 14 +- .../DbgModelTargetMemoryContainerImpl.java | 50 +++++- .../DbgModelTargetModuleContainerImpl.java | 12 +- .../model/impl/DbgModelTargetObjectImpl.java | 15 +- .../DbgModelTargetProcessContainerImpl.java | 51 +++++- .../model/impl/DbgModelTargetProcessImpl.java | 68 +++++--- .../DbgModelTargetRegisterContainerImpl.java | 7 +- .../model/impl/DbgModelTargetRootImpl.java | 146 +++++++++++++++++- .../model/impl/DbgModelTargetSessionImpl.java | 2 +- .../impl/DbgModelTargetStackFrameImpl.java | 2 +- .../DbgModelTargetThreadContainerImpl.java | 56 +++++-- .../model/impl/DbgModelTargetThreadImpl.java | 54 ++++--- .../dbgmodel/gadp/impl/WrappedDbgModel.java | 47 +++++- .../model/impl/DbgModel2TargetRootImpl.java | 86 +++++------ .../dbgmodel/DbgModelSetContextMWETest.java | 22 +-- .../dbg/gadp/client/GadpClientTest.java | 3 +- .../gui/objects/DebuggerObjectsProvider.java | 123 +++++++++++++-- .../actions/DisplayFilteredAction.java | 3 +- .../java/ghidra/dbg/DebuggerObjectModel.java | 6 +- .../dbg/agent/SpiDebuggerObjectModel.java | 64 ++++++-- 56 files changed, 1469 insertions(+), 494 deletions(-) create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessRecord.java create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionRecord.java create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemProcessRecord.java create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemSessionRecord.java create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemThreadRecord.java create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadRecord.java rename Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/{DbgListMemoryRegionsCommandAlt.java => DbgListOSMemoryRegionsCommand.java} (95%) create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSProcessesCommand.java rename Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/{DbgSetCurrentState.java => DbgListOSThreadsCommand.java} (60%) create mode 100644 Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListOSFramesCommand.java diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugEventInformation.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugEventInformation.java index 753fb45cc8..12918fe060 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugEventInformation.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugEventInformation.java @@ -27,8 +27,8 @@ public class DebugEventInformation { public DebugEventInformation(int type, int pid, int tid) { this.type = type; - this.pid = new DebugProcessId(pid); - this.tid = new DebugThreadId(tid); + this.pid = new DebugProcessRecord(pid); + this.tid = new DebugThreadRecord(tid); } public int getType() { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessId.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessId.java index 705edbe095..bd30def161 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessId.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessId.java @@ -25,37 +25,14 @@ package agent.dbgeng.dbgeng; * with other integral values. In particular, this prevents confusion of engine PIDs with system * PIDs. */ -public class DebugProcessId implements Comparable { - public final long id; - - public DebugProcessId(long id) { - this.id = id; - } +public interface DebugProcessId extends Comparable { + public String id(); + public long value(); + public boolean isSystem(); + @Override - public int hashCode() { - return Long.hashCode(id); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof DebugProcessId)) { - return false; - } - DebugProcessId that = (DebugProcessId) obj; - if (this.id != that.id) { - return false; - } - return true; - } - - @Override - public int compareTo(DebugProcessId that) { - return Long.compare(this.id, that.id); - } - - @Override - public String toString() { - return ""; + public default int compareTo(DebugProcessId that) { + return this.id().compareTo(that.id()); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessRecord.java new file mode 100644 index 0000000000..8421c27885 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugProcessRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugProcessRecord(long value) implements DebugProcessId { + + @Override + public boolean isSystem() { + return false; + } + + @Override + public String id() { + return Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionId.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionId.java index 84d1757a0e..93035b5b3c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionId.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionId.java @@ -25,37 +25,14 @@ package agent.dbgeng.dbgeng; * with other integral values. In particular, this prevents confusion of engine PIDs with system * PIDs. */ -public class DebugSessionId implements Comparable { - public final int id; - - public DebugSessionId(int id) { - this.id = id; - } +public interface DebugSessionId extends Comparable { + public String id(); + public long value(); + public boolean isSystem(); + @Override - public int hashCode() { - return Integer.hashCode(id); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof DebugSessionId)) { - return false; - } - DebugSessionId that = (DebugSessionId) obj; - if (this.id != that.id) { - return false; - } - return true; - } - - @Override - public int compareTo(DebugSessionId that) { - return Integer.compare(this.id, that.id); - } - - @Override - public String toString() { - return ""; + public default int compareTo(DebugSessionId that) { + return this.id().compareTo(that.id()); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionRecord.java new file mode 100644 index 0000000000..cb9373367e --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSessionRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugSessionRecord(long value) implements DebugSessionId { + + @Override + public boolean isSystem() { + return false; + } + + @Override + public String id() { + return Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemProcessRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemProcessRecord.java new file mode 100644 index 0000000000..a6994a4a7c --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemProcessRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugSystemProcessRecord(long value) implements DebugProcessId { + + @Override + public boolean isSystem() { + return true; + } + + @Override + public String id() { + return "SYS"+Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemSessionRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemSessionRecord.java new file mode 100644 index 0000000000..2832002392 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemSessionRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugSystemSessionRecord(long value) implements DebugSessionId { + + @Override + public boolean isSystem() { + return true; + } + + @Override + public String id() { + return "SYS"+Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemThreadRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemThreadRecord.java new file mode 100644 index 0000000000..ddb2cc9aec --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugSystemThreadRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugSystemThreadRecord(long value) implements DebugThreadId { + + @Override + public boolean isSystem() { + return true; + } + + @Override + public String id() { + return "PCR"+Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadId.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadId.java index d1b9e2b943..cc5bf04ec4 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadId.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadId.java @@ -25,37 +25,15 @@ package agent.dbgeng.dbgeng; * with other integral values. In particular, this prevents confusion of engine TIDs with system * TIDs. */ -public class DebugThreadId implements Comparable { - public final long id; - - public DebugThreadId(long id) { - this.id = id; - } +public interface DebugThreadId extends Comparable { + public String id(); + public long value(); + public boolean isSystem(); + @Override - public int hashCode() { - return Long.hashCode(id); + public default int compareTo(DebugThreadId that) { + return this.id().compareTo(that.id()); } - @Override - public boolean equals(Object obj) { - if (!(obj instanceof DebugThreadId)) { - return false; - } - DebugThreadId that = (DebugThreadId) obj; - if (this.id != that.id) { - return false; - } - return true; - } - - @Override - public int compareTo(DebugThreadId that) { - return Long.compare(this.id, that.id); - } - - @Override - public String toString() { - return ""; - } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadRecord.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadRecord.java new file mode 100644 index 0000000000..8a4798f074 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugThreadRecord.java @@ -0,0 +1,34 @@ +/* ### + * 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.dbgeng; + +public record DebugThreadRecord(long value) implements DebugThreadId { + + @Override + public boolean isSystem() { + return false; + } + + @Override + public String id() { + return Long.toHexString(value); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/advanced/DebugAdvancedImpl2.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/advanced/DebugAdvancedImpl2.java index 13dc3b97aa..275e4f80ca 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/advanced/DebugAdvancedImpl2.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/advanced/DebugAdvancedImpl2.java @@ -38,7 +38,7 @@ public class DebugAdvancedImpl2 extends DebugAdvancedImpl1 { public DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid) { ULONG ulWhich = new ULONG(WhichSystemObjectInformation.THREAD_BASIC_INFORMATION.ordinal()); ULONGLONG ullUnused = new ULONGLONG(0); - ULONG ulThreadId = new ULONG(tid.id); + ULONG ulThreadId = new ULONG(tid.value()); DEBUG_THREAD_BASIC_INFORMATION sInfo = new DEBUG_THREAD_BASIC_INFORMATION(); ULONG ulBufferSize = new ULONG(sInfo.size()); COMUtils.checkRC(jnaAdvanced.GetSystemObjectInformation(ulWhich, ullUnused, ulThreadId, diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl1.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl1.java index b27094d5b9..8577ac0e85 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl1.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl1.java @@ -15,14 +15,25 @@ */ package agent.dbgeng.impl.dbgeng.sysobj; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; -import com.sun.jna.platform.win32.WinDef.*; +import com.sun.jna.platform.win32.WinDef.ULONG; +import com.sun.jna.platform.win32.WinDef.ULONGByReference; +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; -import agent.dbgeng.dbgeng.*; +import agent.dbgeng.dbgeng.COMUtilsExtra; +import agent.dbgeng.dbgeng.DbgEng; import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable; +import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugProcessRecord; +import agent.dbgeng.dbgeng.DebugSessionId; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.DebugThreadRecord; import agent.dbgeng.jna.dbgeng.sysobj.IDebugSystemObjects; public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { @@ -40,10 +51,10 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetEventThread(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugThreadId(-1); + return new DebugThreadRecord(-1); } COMUtils.checkRC(hr); - return new DebugThreadId(pulId.getValue().intValue()); + return new DebugThreadRecord(pulId.getValue().intValue()); } @Override @@ -51,10 +62,10 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetEventProcess(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugProcessId(-1); + return new DebugProcessRecord(-1); } COMUtils.checkRC(hr); - return new DebugProcessId(pulId.getValue().intValue()); + return new DebugProcessRecord(pulId.getValue().intValue()); } @Override @@ -62,15 +73,15 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetCurrentThreadId(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugThreadId(-1); + return new DebugThreadRecord(-1); } COMUtils.checkRC(hr); - return new DebugThreadId(pulId.getValue().intValue()); + return new DebugThreadRecord(pulId.getValue().intValue()); } @Override public void setCurrentThreadId(DebugThreadId id) { - HRESULT hr = jnaSysobj.SetCurrentThreadId(new ULONG(id.id)); + HRESULT hr = jnaSysobj.SetCurrentThreadId(new ULONG(id.value())); if (!hr.equals(COMUtilsExtra.E_UNEXPECTED) && !hr.equals(COMUtilsExtra.E_NOINTERFACE)) { COMUtils.checkRC(hr); } @@ -81,15 +92,15 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetCurrentProcessId(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugProcessId(-1); + return new DebugProcessRecord(-1); } COMUtils.checkRC(hr); - return new DebugProcessId(pulId.getValue().intValue()); + return new DebugProcessRecord(pulId.getValue().intValue()); } @Override public void setCurrentProcessId(DebugProcessId id) { - HRESULT hr = jnaSysobj.SetCurrentProcessId(new ULONG(id.id)); + HRESULT hr = jnaSysobj.SetCurrentProcessId(new ULONG(id.value())); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { //System.err.println("Failure on setCurrentProcessId(" + id + ")"); return; @@ -131,7 +142,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { COMUtils.checkRC(jnaSysobj.GetThreadIdsByIndex(ulStart, ulCount, aulIds, null)); List result = new ArrayList<>(count); for (int i = 0; i < count; i++) { - result.add(new DebugThreadId(aulIds[i].intValue())); + result.add(new DebugThreadRecord(aulIds[i].intValue())); } return result; } @@ -141,7 +152,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGLONG ullHandle = new ULONGLONG(handle); ULONGByReference pulId = new ULONGByReference(); COMUtils.checkRC(jnaSysobj.GetThreadIdByHandle(ullHandle, pulId)); - return new DebugThreadId(pulId.getValue().intValue()); + return new DebugThreadRecord(pulId.getValue().intValue()); } @Override @@ -154,7 +165,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { return null; } COMUtils.checkRC(hr); - return new DebugThreadId(pulId.getValue().intValue()); + return new DebugThreadRecord(pulId.getValue().intValue()); } @Override @@ -162,7 +173,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { ULONGLONG ullHandle = new ULONGLONG(handle); ULONGByReference pulId = new ULONGByReference(); COMUtils.checkRC(jnaSysobj.GetProcessIdByHandle(ullHandle, pulId)); - return new DebugProcessId(pulId.getValue().intValue()); + return new DebugProcessRecord(pulId.getValue().intValue()); } @Override @@ -175,7 +186,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { return null; } COMUtils.checkRC(hr); - return new DebugProcessId(pulId.getValue().intValue()); + return new DebugProcessRecord(pulId.getValue().intValue()); } @Override @@ -201,7 +212,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal { COMUtils.checkRC(jnaSysobj.GetProcessIdsByIndex(ulStart, ulCount, aulIds, null)); List result = new ArrayList<>(count); for (int i = 0; i < count; i++) { - result.add(new DebugProcessId(aulIds[i].intValue())); + result.add(new DebugProcessRecord(aulIds[i].intValue())); } return result; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl3.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl3.java index f3d252e090..70a89e3852 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl3.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/sysobj/DebugSystemObjectsImpl3.java @@ -15,7 +15,9 @@ */ package agent.dbgeng.impl.dbgeng.sysobj; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import com.sun.jna.platform.win32.WinDef.ULONG; import com.sun.jna.platform.win32.WinDef.ULONGByReference; @@ -24,6 +26,7 @@ import com.sun.jna.platform.win32.COM.COMUtils; import agent.dbgeng.dbgeng.COMUtilsExtra; import agent.dbgeng.dbgeng.DebugSessionId; +import agent.dbgeng.dbgeng.DebugSessionRecord; import agent.dbgeng.jna.dbgeng.sysobj.IDebugSystemObjects3; public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 { @@ -40,10 +43,10 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetEventSystem(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugSessionId(-1); + return new DebugSessionRecord(-1); } COMUtils.checkRC(hr); - return new DebugSessionId(pulId.getValue().intValue()); + return new DebugSessionRecord(pulId.getValue().intValue()); } @Override @@ -51,15 +54,15 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 { ULONGByReference pulId = new ULONGByReference(); HRESULT hr = jnaSysobj.GetCurrentSystemId(pulId); if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) { - return new DebugSessionId(-1); + return new DebugSessionRecord(-1); } COMUtils.checkRC(hr); - return new DebugSessionId(pulId.getValue().intValue()); + return new DebugSessionRecord(pulId.getValue().intValue()); } @Override public void setCurrentSystemId(DebugSessionId id) { - HRESULT hr = jnaSysobj.SetCurrentSystemId(new ULONG(id.id)); + HRESULT hr = jnaSysobj.SetCurrentSystemId(new ULONG(id.value())); if (!hr.equals(COMUtilsExtra.E_UNEXPECTED)) { COMUtils.checkRC(hr); } @@ -88,7 +91,7 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 { COMUtils.checkRC(jnaSysobj.GetSystemIdsByIndex(ulStart, ulCount, aulIds, null)); List result = new ArrayList<>(count); for (int i = 0; i < count; i++) { - result.add(new DebugSessionId(aulIds[i].intValue())); + result.add(new DebugSessionRecord(aulIds[i].intValue())); } return result; } 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 bf7ec1d309..743ee3ef06 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java @@ -24,7 +24,10 @@ import org.apache.commons.lang3.tuple.Pair; import agent.dbgeng.dbgeng.*; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointInsertions; +import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand; +import agent.dbgeng.manager.cmd.DbgListOSProcessesCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { @@ -297,6 +300,27 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ CompletableFuture> listProcesses(); + /** + * List dbgeng's processes + * + * @return a future that completes with a kernel-mode map of process IDs to process handles + */ + CompletableFuture> listOSProcesses(); + + /** + * List dbgeng's processes + * + * @return a future that completes with a kernel-mode list of process memory + */ + CompletableFuture> listOSMemory(); + + /** + * List dbgeng's threads + * + * @return a future that completes with a kernel-mode map of thread IDs to thread handles + */ + CompletableFuture> listOSThreads(DbgProcessImpl proc); + /** * List the available processes on target * diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java index d072b8837b..08c1c4223f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgCommand.java @@ -15,7 +15,14 @@ */ package agent.dbgeng.manager.cmd; -import agent.dbgeng.manager.*; +import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.manager.DbgCommand; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.evt.DbgCommandDoneEvent; import agent.dbgeng.manager.impl.DbgManagerImpl; @@ -26,6 +33,12 @@ import agent.dbgeng.manager.impl.DbgManagerImpl; */ public abstract class AbstractDbgCommand implements DbgCommand { protected final DbgManagerImpl manager; + DbgProcess previousProcess; + Long previousProcessOffset; + DebugProcessId previousProcessId; + DbgThread previousThread; + Long previousThreadOffset; + DebugThreadId previousThreadId; /** * Construct a new command to be executed by the given manager @@ -60,4 +73,52 @@ public abstract class AbstractDbgCommand implements DbgCommand { public void invoke() { // Nothing } + + public void setProcess(DbgProcess process) { + DebugSystemObjects so = manager.getSystemObjects(); + previousProcess = process; + if (manager.isKernelMode() && !process.getId().isSystem()) { + previousProcessOffset = so.getCurrentProcessDataOffset(); + so.setImplicitProcessDataOffset(process.getOffset()); + } + else { + previousProcessId = so.getCurrentProcessId(); + so.setCurrentProcessId(process.getId()); + } + } + + + public void resetProcess() { + DebugSystemObjects so = manager.getSystemObjects(); + if (manager.isKernelMode() && !previousProcess.getId().isSystem()) { + so.setImplicitProcessDataOffset(previousProcessOffset); + } + else { + so.setCurrentProcessId(previousProcessId); + } + } + + public void setThread(DbgThread thread) { + DebugSystemObjects so = manager.getSystemObjects(); + previousThread = thread; + if (manager.isKernelMode() && !thread.getId().isSystem()) { + previousThreadOffset = so.getCurrentThreadDataOffset(); + so.setImplicitThreadDataOffset(thread.getOffset()); + } + else { + previousThreadId = so.getCurrentThreadId(); + so.setCurrentThreadId(thread.getId()); + } + } + + + public void resetThread() { + DebugSystemObjects so = manager.getSystemObjects(); + if (manager.isKernelMode() && !previousThread.getId().isSystem()) { + so.setImplicitThreadDataOffset(previousThreadOffset); + } + else { + so.setCurrentThreadId((DebugThreadId) previousThreadId); + } + } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgExecToAddressCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgExecToAddressCommand.java index 093c777994..7113295461 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgExecToAddressCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/AbstractDbgExecToAddressCommand.java @@ -54,7 +54,7 @@ public abstract class AbstractDbgExecToAddressCommand extends AbstractDbgCommand @Override public void invoke() { String cmd = generateCommand(address); - String prefix = id == null ? "" : "~" + id.id + " "; + String prefix = id == null ? "" : "~" + id.id() + " "; DebugControl control = manager.getControl(); DbgThreadImpl eventThread = manager.getEventThread(); if (eventThread != null && eventThread.getId().equals(id)) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java index 3b435cc0da..703fee1a14 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListModulesCommand.java @@ -58,17 +58,27 @@ public class DbgListModulesCommand extends AbstractDbgCommand> { +public class DbgListOSMemoryRegionsCommand extends AbstractDbgCommand> { private List memoryRegions = new ArrayList<>(); - public DbgListMemoryRegionsCommandAlt(DbgManagerImpl manager) { + public DbgListOSMemoryRegionsCommand(DbgManagerImpl manager) { super(manager); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSProcessesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSProcessesCommand.java new file mode 100644 index 0000000000..9082938b6c --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSProcessesCommand.java @@ -0,0 +1,100 @@ +/* ### + * 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.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import agent.dbgeng.dbgeng.DebugControl; +import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugProcessRecord; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgManager; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; +import agent.dbgeng.manager.evt.DbgConsoleOutputEvent; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; +import ghidra.util.Msg; + +/** + * Implementation of {@link DbgManager#listProcesses()} + */ +public class DbgListOSProcessesCommand extends AbstractDbgCommand> { + private List updatedProcessIds = new ArrayList<>(); + + public DbgListOSProcessesCommand(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 Map complete(DbgPendingCommand pending) { + StringBuilder builder = new StringBuilder(); + for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) { + builder.append(out.getOutput()); + } + parse(builder.toString()); + Msg.warn(this, "Completed OS process list"); + return manager.getKnownProcesses(); + } + + private void parse(String result) { + String[] lines = result.split("\n"); + Long offset = null; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line.contains("PROCESS")) { + offset = null; + String[] fields = line.trim().split("\\s+"); + if (fields.length > 1 && fields[0].equals("PROCESS")) { + BigInteger val = new BigInteger(fields[1], 16); + offset = val.longValue(); + } + } + if (line.contains("Cid:")) { + String[] fields = line.trim().split("\\s+"); + if (fields.length > 3 && fields[2].equals("Cid:")) { + Long pid = Long.parseLong(fields[3], 16); + DbgProcessImpl mirror = manager.getProcessComputeIfAbsent(new DebugProcessRecord(pid), pid, false); + if (offset != null) { + mirror.setOffset(offset); + updatedProcessIds.add(mirror.getId()); + } + } + } + } + } + + @Override + public void invoke() { + Msg.warn(this, "Retrieving OS process list"); + DebugControl control = manager.getControl(); + control.execute("!process 0 0"); + } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetCurrentState.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSThreadsCommand.java similarity index 60% rename from Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetCurrentState.java rename to Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSThreadsCommand.java index 7ce45f5d66..d1783dde55 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetCurrentState.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListOSThreadsCommand.java @@ -15,10 +15,14 @@ */ package agent.dbgeng.manager.cmd; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import agent.dbgeng.dbgeng.DebugControl; -import agent.dbgeng.dbgeng.DebugProcessId; -import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.DebugThreadRecord; import agent.dbgeng.manager.DbgEvent; import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; @@ -28,15 +32,13 @@ import agent.dbgeng.manager.impl.DbgProcessImpl; import agent.dbgeng.manager.impl.DbgThreadImpl; import ghidra.util.Msg; -public class DbgSetCurrentState extends AbstractDbgCommand { +public class DbgListOSThreadsCommand extends AbstractDbgCommand> { + protected final DbgProcessImpl process; + private List updatedThreadIds = new ArrayList<>();; - private long pid; - private long tid; - private DebugProcessId pID; - private DebugThreadId tID; - - public DbgSetCurrentState(DbgManagerImpl manager) { + public DbgListOSThreadsCommand(DbgManagerImpl manager, DbgProcessImpl process) { super(manager); + this.process = process; } @Override @@ -51,52 +53,46 @@ public class DbgSetCurrentState extends AbstractDbgCommand { } @Override - public DbgThread complete(DbgPendingCommand pending) { + public Map complete(DbgPendingCommand pending) { StringBuilder builder = new StringBuilder(); for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) { builder.append(out.getOutput()); } parse(builder.toString()); - - if (pID == null) { - return null; - } - DbgProcessImpl proc = manager.getProcessComputeIfAbsent(pID, pid, true); - DbgThreadImpl thread = manager.getThreadComputeIfAbsent(tID, proc, tid, true); - try { - DebugSystemObjects so = manager.getSystemObjects(); - proc.setOffset(so.getCurrentProcessDataOffset()); - thread.setOffset(so.getCurrentThreadDataOffset()); - } catch (Exception e) { - Msg.error(this, e.getMessage()); - } - return thread; + Msg.warn(this, "Completed OS thread list for pid="+Long.toHexString(process.getPid())); + Map threads = process.getKnownThreads(); + return threads; } private void parse(String result) { String[] lines = result.split("\n"); + Long offset = null; for (int i = 0; i < lines.length; i++) { String line = lines[i]; if (line.contains("THREAD")) { String[] fields = line.trim().split("\\s+"); - if (fields.length > 3 && fields[2].equals("Cid")) { + if (fields.length > 4 && fields[0].equals("THREAD")) { + BigInteger val = new BigInteger(fields[1], 16); + offset = val.longValue(); String[] split = fields[3].split("\\."); if (split.length == 2) { - pid = Long.parseLong(split[0], 16); - tid = Long.parseLong(split[1], 16); - pID = new DebugProcessId(pid); - tID = new DebugThreadId(tid); + Long tid = Long.parseLong(split[1], 16); + DbgThreadImpl mirror = manager.getThreadComputeIfAbsent(new DebugThreadRecord(tid), process, tid, false); + if (offset != null) { + mirror.setOffset(offset); + updatedThreadIds.add(mirror.getId()); + } } } - break; - } + } } } @Override public void invoke() { + Msg.warn(this, "Retrieving OS thread list for pid="+Long.toHexString(process.getPid())); DebugControl control = manager.getControl(); - control.execute("!thread"); + control.execute("!process "+Long.toHexString(process.getOffset())+" 2"); } } 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 11614cdcff..ce848eb0be 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 @@ -15,14 +15,19 @@ */ package agent.dbgeng.manager.cmd; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugSystemProcessRecord; import agent.dbgeng.manager.DbgCause.Causes; import agent.dbgeng.manager.DbgManager; import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; import ghidra.util.Msg; /** @@ -44,19 +49,29 @@ public class DbgListProcessesCommand extends AbstractDbgCommand(cur)) { if (updatedProcessIds.contains(id)) { continue; // Do nothing, we're in sync } - // Need to remove the inferior as if we received =thread-group-removed - Msg.warn(this, "Resync: Had extra group: i" + id); - manager.removeProcess(id, Causes.UNCLAIMED); + if (!manager.isKernelMode()) { + Msg.warn(this, "Resync: Had extra group: i" + id); + manager.removeProcess(id, Causes.UNCLAIMED); + } } return allProcesses; } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSymbolsCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSymbolsCommand.java index c59cb0540d..63a29310df 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSymbolsCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgListSymbolsCommand.java @@ -48,16 +48,20 @@ public class DbgListSymbolsCommand extends AbstractDbgCommand symbolIdsByName = symbols.getSymbolIdsByName(symbol.name); - for (DebugSymbolId symbolId : symbolIdsByName) { - DebugSymbolEntry symbolEntry = symbols.getSymbolEntry(symbolId); - symbolEntries.put(symbolId, symbolEntry); + try { + setProcess(process); + DebugSymbols symbols = manager.getSymbols(); + + for (DebugSymbolName symbol : symbols.iterateSymbolMatches(module.getName() + "!*")) { + List symbolIdsByName = symbols.getSymbolIdsByName(symbol.name); + for (DebugSymbolId symbolId : symbolIdsByName) { + DebugSymbolEntry symbolEntry = symbols.getSymbolEntry(symbolId); + symbolEntries.put(symbolId, symbolEntry); + } } + } + finally { + resetProcess(); } } } 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 802b396191..c1b1b5e9ce 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 @@ -15,13 +15,18 @@ */ package agent.dbgeng.manager.cmd; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugSystemThreadRecord; import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgProcessImpl; +import agent.dbgeng.manager.impl.DbgThreadImpl; import ghidra.util.Msg; public class DbgListThreadsCommand extends AbstractDbgCommand> { @@ -41,30 +46,44 @@ public class DbgListThreadsCommand extends AbstractDbgCommand(cur)) { if (updatedThreadIds.contains(id)) { continue; // Do nothing, we're in sync } - // Need to remove the thread as if we received =thread-exited - Msg.warn(this, "Resync: Had extra thread: " + id); - process.removeThread(id); - manager.removeThread(id); + if (!manager.isKernelMode()) { + Msg.warn(this, "Resync: Had extra thread: " + id); + process.removeThread(id); + manager.removeThread(id); + } } return process.getKnownThreads(); } @Override public void invoke() { - DebugSystemObjects so = manager.getSystemObjects(); - so.setCurrentProcessId(process.getId()); - updatedThreadIds = so.getThreads(); + try { + setProcess(process); + DebugSystemObjects so = manager.getSystemObjects(); + updatedThreadIds = so.getThreads(); + } + finally { + resetProcess(); + } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadRegistersCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadRegistersCommand.java index 59b0646041..9b8ec6204e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadRegistersCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgReadRegistersCommand.java @@ -30,7 +30,7 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand regs; private DebugRegisters registers; - private DebugThreadId previous; + private Map result = new LinkedHashMap<>(); public DbgReadRegistersCommand(DbgManagerImpl manager, DbgThreadImpl thread, Integer frameId, Set regs) { @@ -41,31 +41,31 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand complete(DbgPendingCommand pending) { - DebugSystemObjects so = manager.getSystemObjects(); if (regs.isEmpty()) { return Collections.emptyMap(); } - Map result = new LinkedHashMap<>(); - if (registers != null) { - for (DbgRegister r : regs) { - if (r.isBaseRegister()) { - DebugValue value = registers.getValueByName(r.getName()); - if (value != null) { - BigInteger bval = new BigInteger(value.encodeAsBytes()); - result.put(r, bval); - } - } - } - } - so.setCurrentThreadId(previous); return result; } @Override public void invoke() { - DebugSystemObjects so = manager.getSystemObjects(); - previous = so.getCurrentThreadId(); - so.setCurrentThreadId(thread.getId()); - registers = manager.getClient().getRegisters(); + try { + setThread(thread); + registers = manager.getClient().getRegisters(); + if (registers != null) { + for (DbgRegister r : regs) { + if (r.isBaseRegister()) { + DebugValue value = registers.getValueByName(r.getName()); + if (value != null) { + BigInteger bval = new BigInteger(value.encodeAsBytes()); + result.put(r, bval); + } + } + } + } + } + finally { + resetThread(); + } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveProcessCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveProcessCommand.java index 4130229377..1047e50dd9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveProcessCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveProcessCommand.java @@ -18,7 +18,6 @@ package agent.dbgeng.manager.cmd; import java.math.BigInteger; import agent.dbgeng.dbgeng.DebugControl; -import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.manager.DbgEvent; import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; @@ -94,11 +93,9 @@ public class DbgResolveProcessCommand extends AbstractDbgCommand { @Override public void invoke() { if (process != null) { - DebugProcessId id = process.getId(); - if (id != null) { - DebugControl control = manager.getControl(); - control.execute("!process "+Long.toHexString(id.id)+" 0"); - } + DebugControl control = manager.getControl(); + Long key = process.getOffset() != null ? process.getOffset() : process.getPid(); + control.execute("!process "+Long.toHexString(key)+" 0"); } } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveThreadCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveThreadCommand.java index 917e163cfe..c765984474 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveThreadCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveThreadCommand.java @@ -93,10 +93,8 @@ public class DbgResolveThreadCommand extends AbstractDbgCommand { @Override public void invoke() { - DebugThreadId id = thread.getId(); - if (id != null) { - DebugControl control = manager.getControl(); - control.execute("!thread "+Long.toHexString(id.id)+" 0"); - } + DebugControl control = manager.getControl(); + Long key = thread.getOffset() != null ? thread.getOffset() : thread.getTid(); + control.execute("!thread "+Long.toHexString(key)+" 0"); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java index c91d2cce81..800eea4843 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveProcessCommand.java @@ -98,7 +98,7 @@ public class DbgSetActiveProcessCommand extends AbstractDbgCommand { } else { so.setCurrentProcessId(id); DebugProcessId currentProcessId = so.getCurrentProcessId(); - if (id.id != currentProcessId.id) { + if (!id.id().equals(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 f5e799150a..8db659677b 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 @@ -41,28 +41,30 @@ public class DbgStackListFramesCommand extends AbstractDbgCommand(); - DebugSystemObjects so = manager.getSystemObjects(); - DebugThreadId previous = so.getCurrentThreadId(); - so.setCurrentThreadId(thread.getId()); - DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L); - for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) { - DEBUG_STACK_FRAME tf = stackTrace.getFrame(i); - //DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(), - // new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null); - DbgStackFrame frame = new DbgStackFrameImpl(thread, // - tf.FrameNumber.intValue(), // - new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), // - tf.FuncTableEntry.longValue(), // - tf.FrameOffset.longValue(), // - tf.ReturnOffset.longValue(), // - tf.StackOffset.longValue(), // - tf.Virtual.booleanValue(), // - tf.Params[0].longValue(), // - tf.Params[1].longValue(), // - tf.Params[2].longValue(), // - tf.Params[3].longValue()); - result.add(frame); + try { + setThread(thread); + DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L); + for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) { + DEBUG_STACK_FRAME tf = stackTrace.getFrame(i); + //DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(), + // new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null); + DbgStackFrame frame = new DbgStackFrameImpl(thread, // + tf.FrameNumber.intValue(), // + new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), // + tf.FuncTableEntry.longValue(), // + tf.FrameOffset.longValue(), // + tf.ReturnOffset.longValue(), // + tf.StackOffset.longValue(), // + tf.Virtual.booleanValue(), // + tf.Params[0].longValue(), // + tf.Params[1].longValue(), // + tf.Params[2].longValue(), // + tf.Params[3].longValue()); + result.add(frame); + } + } + finally { + resetThread(); } - so.setCurrentThreadId(previous); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListOSFramesCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListOSFramesCommand.java new file mode 100644 index 0000000000..416a2f6ff0 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStackListOSFramesCommand.java @@ -0,0 +1,119 @@ +/* ### + * 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.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import agent.dbgeng.dbgeng.DebugControl; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgStackFrame; +import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; +import agent.dbgeng.manager.evt.DbgConsoleOutputEvent; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgStackFrameImpl; +import agent.dbgeng.manager.impl.DbgThreadImpl; + +public class DbgStackListOSFramesCommand extends AbstractDbgCommand> { + protected final DbgThreadImpl thread; + private List result = new ArrayList<>(); + + public DbgStackListOSFramesCommand(DbgManagerImpl manager, DbgThreadImpl thread) { + super(manager); + this.thread = thread; + } + + @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()); + return result; + } + + private void parse(String output) { + String[] lines = output.split("\n"); + int fcount = 0; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line.contains(" : ") && !line.startsWith("Child") && !line.startsWith("THREAD")) { + String[] fields = line.trim().split("\\s+"); + DbgStackFrame frame = new DbgStackFrameImpl(thread, // + fcount++, // + parseToBig(fields[1]), // return + fields.length > 8 ? fields[8] : "" + ); + result.add(frame); + } + } + } + + private BigInteger parseToBig(String lval) { + if (lval.contains("`")) { + lval = lval.replaceAll("`", ""); + } + return new BigInteger(lval, 16); + } + + @Override + public void invoke() { + DebugControl control = manager.getControl(); + control.execute("!thread "+Long.toHexString(thread.getOffset())+" 6"); + + } + +// @Override +// public void invoke() { +// result = new ArrayList<>(); +// DebugSystemObjects so = manager.getSystemObjects(); +// DebugThreadId previous = so.getCurrentThreadId(); +// so.setCurrentThreadId(thread.getId()); +// DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L); +// for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) { +// DEBUG_STACK_FRAME tf = stackTrace.getFrame(i); +// //DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(), +// // new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null); +// DbgStackFrame frame = new DbgStackFrameImpl(thread, // +// tf.FrameNumber.intValue(), // +// new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), // +// tf.FuncTableEntry.longValue(), // +// tf.FrameOffset.longValue(), // +// tf.ReturnOffset.longValue(), // +// tf.StackOffset.longValue(), // +// tf.Virtual.booleanValue(), // +// tf.Params[0].longValue(), // +// tf.Params[1].longValue(), // +// tf.Params[2].longValue(), // +// tf.Params[3].longValue()); +// result.add(frame); +// } +// so.setCurrentThreadId(previous); +// } +} diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStepCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStepCommand.java index d55c84e56c..2789329d0e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStepCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgStepCommand.java @@ -73,7 +73,7 @@ public class DbgStepCommand extends AbstractDbgCommand { @Override public void invoke() { String cmd = ""; - String prefix = id == null ? "" : "~" + id.id + " "; + String prefix = id == null ? "" : "~" + id.id() + " "; DebugControl control = manager.getControl(); if (suffix.equals(ExecSuffix.STEP_INSTRUCTION)) { cmd = "t"; 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 f8680d7b80..3ad65fa0af 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 @@ -60,12 +60,16 @@ import agent.dbgeng.dbgeng.DebugExceptionRecord64; import agent.dbgeng.dbgeng.DebugModuleInfo; import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugProcessInfo; +import agent.dbgeng.dbgeng.DebugProcessRecord; import agent.dbgeng.dbgeng.DebugRegisters; import agent.dbgeng.dbgeng.DebugSessionId; import agent.dbgeng.dbgeng.DebugSymbols; import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugSystemProcessRecord; +import agent.dbgeng.dbgeng.DebugSystemThreadRecord; import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.dbgeng.DebugThreadInfo; +import agent.dbgeng.dbgeng.DebugThreadRecord; import agent.dbgeng.gadp.impl.AbstractClientThreadExecutor; import agent.dbgeng.gadp.impl.DbgEngClientThreadExecutor; import agent.dbgeng.impl.dbgeng.DbgEngUtil; @@ -96,6 +100,9 @@ import agent.dbgeng.manager.cmd.DbgInsertBreakpointCommand; import agent.dbgeng.manager.cmd.DbgLaunchProcessCommand; import agent.dbgeng.manager.cmd.DbgListAvailableProcessesCommand; import agent.dbgeng.manager.cmd.DbgListBreakpointsCommand; +import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand; +import agent.dbgeng.manager.cmd.DbgListOSProcessesCommand; +import agent.dbgeng.manager.cmd.DbgListOSThreadsCommand; import agent.dbgeng.manager.cmd.DbgListProcessesCommand; import agent.dbgeng.manager.cmd.DbgOpenDumpCommand; import agent.dbgeng.manager.cmd.DbgPendingCommand; @@ -145,7 +152,6 @@ import ghidra.dbg.target.TargetLauncher.CmdLineParser; import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.HandlerMap; -import ghidra.dbg.util.PathUtils; import ghidra.lifecycle.Internal; import ghidra.util.Msg; import ghidra.util.datastruct.ListenerSet; @@ -236,17 +242,6 @@ public class DbgManagerImpl implements DbgManager { } } - public DbgThreadImpl getThreadComputeIfAbsent(String key, DbgProcessImpl proc, boolean fire) { - String index = PathUtils.parseIndex(key); - Integer tid = Integer.decode(index); - DebugThreadId id = getSystemObjects().getThreadIdBySystemId(tid); - if (id == null) { - id = new DebugThreadId(tid); - return getThreadComputeIfAbsent(id, proc, tid, fire); - } - return getThreadComputeIfAbsent(id, proc, tid, fire); - } - public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process, long tid, boolean fire) { synchronized (threads) { @@ -368,7 +363,7 @@ public class DbgManagerImpl implements DbgManager { public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id, boolean fire) { synchronized (sessions) { - if (!sessions.containsKey(id) && id.id >= 0) { + if (!sessions.containsKey(id) && id.value() >= 0) { DbgSessionImpl session = new DbgSessionImpl(this, id); session.add(); if (fire) { @@ -727,7 +722,7 @@ public class DbgManagerImpl implements DbgManager { if (eventThread != null) { ((DbgThreadImpl) eventThread).setInfo(lastEventInformation); } - return currentThread == null ? new DebugThreadId(-1) : currentThread.getId(); + return currentThread == null ? new DebugThreadRecord(-1) : currentThread.getId(); } /** @@ -799,7 +794,7 @@ public class DbgManagerImpl implements DbgManager { getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED); getEventListeners().fire.threadSelected(thread, null, evt.getCause()); - String key = Long.toHexString(eventId.id); + String key = eventId.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -824,7 +819,7 @@ public class DbgManagerImpl implements DbgManager { getEventListeners().fire.eventSelected(evt, evt.getCause()); getEventListeners().fire.threadExited(eventId, process, evt.getCause()); - String key = Long.toHexString(eventId.id); + String key = eventId.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -846,11 +841,11 @@ public class DbgManagerImpl implements DbgManager { } DebugThreadId eventId = updateState(); - currentThread = evt.getThread(); + //currentThread = evt.getThread(); currentThread.setState(evt.getState(), evt.getCause(), evt.getReason()); getEventListeners().fire.threadSelected(currentThread, evt.getFrame(), evt.getCause()); - String key = Long.toHexString(eventId.id); + String key = eventId.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -878,7 +873,7 @@ public class DbgManagerImpl implements DbgManager { //proc.moduleLoaded(info.moduleInfo); //getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause()); - String key = Long.toHexString(proc.getId().id); + String key = proc.getId().id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -911,7 +906,7 @@ public class DbgManagerImpl implements DbgManager { process.remove(evt.getCause()); getEventListeners().fire.processRemoved(process.getId(), evt.getCause()); - String key = Long.toHexString(process.getId().id); + String key = process.getId().id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -931,7 +926,7 @@ public class DbgManagerImpl implements DbgManager { currentProcess = evt.getProcess(); getEventListeners().fire.processSelected(currentProcess, evt.getCause()); - String key = Long.toHexString(eventId.id); + String key = eventId.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -1059,7 +1054,7 @@ public class DbgManagerImpl implements DbgManager { if (flags.contains(ChangeEngineState.CURRENT_THREAD)) { long id = evt.getArgument(); for (DebugThreadId key : getThreads()) { - if (key.id == id) { + if (key.value() == id) { DbgThread thread = getThread(key); if (thread != null) { getEventListeners().fire.threadSelected(thread, null, evt.getCause()); @@ -1088,7 +1083,7 @@ public class DbgManagerImpl implements DbgManager { currentSession = evt.getSession(); getEventListeners().fire.sessionSelected(currentSession, evt.getCause()); - String key = Long.toHexString(eventId.id); + String key = eventId.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -1113,9 +1108,9 @@ public class DbgManagerImpl implements DbgManager { else { processCount--; } - DebugProcessId id = new DebugProcessId(info.intValue()); + DebugProcessId id = new DebugProcessRecord(info.intValue()); - String key = Long.toHexString(id.id); + String key = id.id(); if (statusByNameMap.containsKey(key)) { return statusByNameMap.get(key); } @@ -1316,32 +1311,13 @@ public class DbgManagerImpl implements DbgManager { if (tag == null) { for (DebugThreadId tid : tids) { Msg.debug(this, "TRAP Added: " + id + " on " + tid); - if (!claimsBreakpointAdded.satisfy(tid)) { - /* - AbstractSctlTrapSpec spec = - server.getDialect().create(AbstractSctlTrapSpec.class); - spec.setActionStop(); - spec.setAddress(newOffset); - synth.synthSetTrap(null, tid.id, spec, id); - */ - } - else { + if (claimsBreakpointAdded.satisfy(tid)) { Msg.debug(this, " claimed"); } breaksById.put(id, new BreakpointTag(newOffset)); } } else if (tag.offset != newOffset) { - /* - for (DebugThreadId tid : tids) { - synth.synthClearTrap(null, tid.id, id); - AbstractSctlTrapSpec spec = - server.getDialect().create(AbstractSctlTrapSpec.class); - spec.setActionStop(); - spec.setAddress(newOffset); - synth.synthSetTrap(null, tid.id, spec, id); - } - */ tag.offset = newOffset; } // else the breakpoint is unchanged } @@ -1353,12 +1329,7 @@ public class DbgManagerImpl implements DbgManager { } for (DebugThreadId tid : tids) { Msg.debug(this, "TRAP Removed: " + id + " on " + tid); - if (!claimsBreakpointRemoved.satisfy(new BreakId(tid, id))) { - /* - synth.synthClearTrap(null, tid.id, id); - */ - } - else { + if (claimsBreakpointRemoved.satisfy(new BreakId(tid, id))) { Msg.debug(this, " claimed"); } } @@ -1376,6 +1347,21 @@ public class DbgManagerImpl implements DbgManager { return execute(new DbgListProcessesCommand(this)); } + @Override + public CompletableFuture> listOSProcesses() { + return execute(new DbgListOSProcessesCommand(this)); + } + + @Override + public CompletableFuture> listOSMemory() { + return execute(new DbgListOSMemoryRegionsCommand(this)); + } + + @Override + public CompletableFuture> listOSThreads(DbgProcessImpl proc) { + return execute(new DbgListOSThreadsCommand(this, proc)); + } + @Override public CompletableFuture>> listAvailableProcesses() { return execute(new DbgListAvailableProcessesCommand(this)); @@ -1682,7 +1668,6 @@ public class DbgManagerImpl implements DbgManager { //System.err.println("EXIT"); waiting = false; updateState(); - getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED); return CompletableFuture.completedFuture(null); } @@ -1782,28 +1767,32 @@ public class DbgManagerImpl implements DbgManager { DebugSystemObjects so = getSystemObjects(); currentSession = eventSession = getSessionComputeIfAbsent(esid, true); if (kernelMode) { - long poffset = so.getCurrentProcessDataOffset(); - currentProcess = eventProcess = getProcessComputeIfAbsent(new DebugProcessId(poffset), -1, true); - if (currentProcess.getPid() < 0) { + DbgProcessImpl cp = getProcessComputeIfAbsent(new DebugSystemProcessRecord(epid.value()), -1, true); + cp.setOffset(so.getCurrentProcessDataOffset()); + currentProcess = eventProcess = cp; + if (currentProcess.getId().isSystem()) { execute(new DbgResolveProcessCommand(this, currentProcess)).thenAccept(proc -> { currentProcess = eventProcess = proc; // As you now have both pid & offset, update the id==pid version - DbgProcessImpl mirror = getProcessComputeIfAbsent(new DebugProcessId(proc.getPid()), -1, false); + DbgProcessImpl mirror = getProcessComputeIfAbsent(new DebugProcessRecord(proc.getPid()), proc.getPid(), true); if (mirror != null) { mirror.setOffset(currentProcess.getOffset()); + currentProcess = eventProcess = mirror; getEventListeners().fire.processSelected(eventProcess, Causes.UNCLAIMED); } }); } - long toffset = so.getCurrentThreadDataOffset(); - currentThread = eventThread = getThreadComputeIfAbsent(new DebugThreadId(toffset), (DbgProcessImpl) eventProcess, -1, false); - if (currentThread.getTid() < 0) { + DbgThreadImpl ct = getThreadComputeIfAbsent(new DebugSystemThreadRecord(etid.value()), cp, -1, false); + ct.setOffset(so.getCurrentThreadDataOffset()); + currentThread = eventThread = ct; + if (currentThread.getId().isSystem()) { execute(new DbgResolveThreadCommand(this, currentThread)).thenAccept(thread -> { currentThread = eventThread = thread; // As you now have both tid & offset, update the id==tid version - DbgThreadImpl mirror = getThreadComputeIfAbsent(new DebugThreadId(thread.getTid()), (DbgProcessImpl) eventProcess, -1, false); + DbgThreadImpl mirror = getThreadComputeIfAbsent(new DebugThreadRecord(thread.getTid()), (DbgProcessImpl) eventProcess, thread.getTid(), true); if (mirror != null) { mirror.setOffset(currentThread.getOffset()); + currentThread = eventThread = mirror; getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED); } }); @@ -1813,6 +1802,7 @@ public class DbgManagerImpl implements DbgManager { eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true); currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess, so.getCurrentThreadSystemId(), false); + getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED); } } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java index cf8233fa09..b3b9efcc60 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgProcessImpl.java @@ -133,6 +133,7 @@ public class DbgProcessImpl implements DbgProcess { * @param thread the thread to add */ public void addThread(DbgThreadImpl thread) { + assert(thread.getProcess().equals(this)); DbgThreadImpl exists = threads.get(thread.getId()); if (exists != null) { Msg.warn(this, "Adding pre-existing thread " + exists); @@ -207,6 +208,9 @@ public class DbgProcessImpl implements DbgProcess { @Override public CompletableFuture> listThreads() { + if (manager.isKernelMode() && !id.isSystem()) { + return CompletableFuture.completedFuture(getKnownThreads()); + } return manager.execute(new DbgListThreadsCommand(manager, this)); } 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 90ad99adb4..e42207db37 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 @@ -18,6 +18,7 @@ package agent.dbgeng.model.iface2; import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugProcessRecord; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.DbgState; @@ -73,7 +74,7 @@ public interface DbgModelTargetProcess extends // try { String index = PathUtils.parseIndex(getName()); Long pid = Long.decode(index); - DebugProcessId id = new DebugProcessId(pid); + DebugProcessId id = new DebugProcessRecord(pid); return manager.getProcessComputeIfAbsent(id, pid, fire); } catch (IllegalArgumentException e) { 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 10dd9a8938..edb8157a52 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 @@ -82,11 +82,12 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target VALUE_ATTRIBUTE_NAME, value.toString(16) // ), "Refreshed"); if (value.longValue() != 0) { - String newval = reg.getName() + " : " + value.toString(16); + String valstr = Long.toUnsignedString(value.longValue(), 16); //value.toString(16); + String newval = reg.getName() + " : " + valstr; reg.changeAttributes(List.of(), Map.of( // DISPLAY_ATTRIBUTE_NAME, newval // ), "Refreshed"); - reg.setModified(value.toString(16).equals(oldval)); + reg.setModified(valstr.equals(oldval)); } } 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 e70d744dc7..88537fe152 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java @@ -21,10 +21,16 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags; import agent.dbgeng.dbgeng.DebugSessionId; +import agent.dbgeng.dbgeng.DebugSessionRecord; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgSession; import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.model.iface1.*; +import agent.dbgeng.model.iface1.DbgModelSelectableObject; +import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned; +import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; +import agent.dbgeng.model.iface1.DbgModelTargetInterpreter; +import agent.dbgeng.model.iface1.DbgModelTargetInterruptible; +import agent.dbgeng.model.iface1.DbgModelTargetResumable; import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetConsole; import ghidra.dbg.target.TargetConsole.Channel; @@ -52,7 +58,7 @@ public interface DbgModelTargetSession extends // try { String index = PathUtils.parseIndex(getName()); Integer sid = Integer.decode(index); - DebugSessionId id = new DebugSessionId(sid); + DebugSessionId id = new DebugSessionRecord(sid); return manager.getSessionComputeIfAbsent(id, fire); } catch (IllegalArgumentException e) { 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 33105b982a..1da8310710 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 @@ -18,6 +18,7 @@ package agent.dbgeng.model.iface2; import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.DebugThreadRecord; import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgReason; import agent.dbgeng.manager.DbgState; @@ -30,7 +31,9 @@ import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned; import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; import agent.dbgeng.model.iface1.DbgModelTargetSteppable; import agent.dbgeng.model.impl.DbgModelTargetStackImpl; -import ghidra.dbg.target.*; +import ghidra.dbg.target.TargetAggregate; +import ghidra.dbg.target.TargetMethod; +import ghidra.dbg.target.TargetThread; import ghidra.dbg.util.PathUtils; import ghidra.program.model.address.Address; @@ -54,7 +57,7 @@ public interface DbgModelTargetThread extends // DbgProcessImpl process = parentProcess == null ? null : (DbgProcessImpl) parentProcess.getProcess(); String index = PathUtils.parseIndex(getName()); Long tid = Long.decode(index); - DebugThreadId id = new DebugThreadId(tid); + DebugThreadId id = new DebugThreadRecord(tid); DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, fire); return thread; } 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 c6a951c951..383eccc8a8 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 @@ -23,11 +23,13 @@ import java.util.concurrent.RejectedExecutionException; import org.apache.commons.lang3.exception.ExceptionUtils; -import agent.dbgeng.dbgeng.DebugSessionId; +import agent.dbgeng.dbgeng.DebugSessionRecord; import agent.dbgeng.manager.DbgManager; import agent.dbgeng.manager.DbgSession; import agent.dbgeng.model.AbstractDbgModel; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; +import agent.dbgeng.model.iface2.DbgModelTargetSession; +import agent.dbgeng.model.iface2.DbgModelTargetSessionContainer; import ghidra.async.AsyncUtils; import ghidra.dbg.DebuggerModelClosedReason; import ghidra.dbg.DebuggerObjectModelWithMemory; @@ -36,7 +38,11 @@ import ghidra.dbg.target.TargetMemory; import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.schema.AnnotatedSchemaContext; import ghidra.dbg.target.schema.TargetObjectSchema; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressFactory; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.DefaultAddressFactory; +import ghidra.program.model.address.GenericAddressSpace; public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectModelWithMemory { // TODO: Need some minimal memory modeling per architecture on the model/agent side. @@ -67,7 +73,7 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode //System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX)); this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA); this.completedRoot = CompletableFuture.completedFuture(root); - DbgSession s = dbg.getSessionComputeIfAbsent(new DebugSessionId(0), true); + DbgSession s = dbg.getSessionComputeIfAbsent(new DebugSessionRecord(0), true); DbgModelTargetSessionContainer sessions = root.sessions; this.session = (DbgModelTargetSessionImpl) sessions.getTargetSession(s); addModelRoot(root); 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 35144ddfa5..182ecd0fac 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 @@ -15,24 +15,46 @@ */ package agent.dbgeng.model.impl; +import java.lang.invoke.MethodHandles; import java.nio.ByteBuffer; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import agent.dbgeng.manager.DbgModuleMemory; -import agent.dbgeng.manager.cmd.*; +import agent.dbgeng.manager.cmd.DbgListKernelMemoryRegionsCommand; +import agent.dbgeng.manager.cmd.DbgListMemoryRegionsCommand; +import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand; +import agent.dbgeng.manager.cmd.DbgReadBusDataCommand; +import agent.dbgeng.manager.cmd.DbgReadControlCommand; +import agent.dbgeng.manager.cmd.DbgReadDebuggerDataCommand; +import agent.dbgeng.manager.cmd.DbgReadIoCommand; +import agent.dbgeng.manager.cmd.DbgReadMemoryCommand; +import agent.dbgeng.manager.cmd.DbgReadPhysicalMemoryCommand; +import agent.dbgeng.manager.cmd.DbgWriteBusDataCommand; +import agent.dbgeng.manager.cmd.DbgWriteControlCommand; +import agent.dbgeng.manager.cmd.DbgWriteIoCommand; +import agent.dbgeng.manager.cmd.DbgWriteMemoryCommand; +import agent.dbgeng.manager.cmd.DbgWritePhysicalMemoryCommand; import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgProcessImpl; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer; +import agent.dbgeng.model.iface2.DbgModelTargetMemoryRegion; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; import generic.ULongSpan; import generic.ULongSpan.ULongSpanSet; import ghidra.async.AsyncUtils; import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.error.DebuggerMemoryAccessException; import ghidra.dbg.error.DebuggerModelAccessException; +import ghidra.dbg.target.TargetMethod; +import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod; import ghidra.dbg.target.TargetObject; -import ghidra.dbg.target.schema.*; +import ghidra.dbg.target.schema.TargetAttributeType; +import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.program.model.address.Address; import ghidra.util.datastruct.WeakValueHashMap; @@ -41,6 +63,7 @@ import ghidra.util.datastruct.WeakValueHashMap; elements = { @TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) }, attributes = { + @TargetAttributeType(name = "Populate", type = TargetMethod.class), @TargetAttributeType(type = Void.class) }, canonicalContainer = true) public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl @@ -57,6 +80,12 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl if (!getModel().isSuppressDescent()) { requestElements(RefreshBehavior.REFRESH_ALWAYS); } + DbgManagerImpl manager = getManager(); + if (manager.isKernelMode()) { + changeAttributes(List.of(), List.of(), + AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), getModel(), this), + "Methods"); + } } @Override @@ -96,7 +125,7 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl return manager.execute(new DbgListKernelMemoryRegionsCommand(manager)); } if (manager.useAltMemoryQuery()) { - return manager.execute(new DbgListMemoryRegionsCommandAlt(manager)); + return manager.execute(new DbgListOSMemoryRegionsCommand(manager)); } return manager.execute(new DbgListMemoryRegionsCommand(manager)); } @@ -271,4 +300,13 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl return CompletableFuture.completedFuture(null); } -} + @TargetMethod.Export("Populate") + public CompletableFuture populate() { + return getManager().listOSMemory().thenAccept(byName -> { + List sections; + synchronized (this) { + sections = byName.stream().map(this::getTargetMemory).collect(Collectors.toList()); + } + setElements(sections, Map.of(), "Refreshed"); + }); + }} 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 d229d432cf..0ef65f415f 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 @@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture; import agent.dbgeng.manager.DbgModule; import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface2.DbgModelTargetModule; import agent.dbgeng.model.iface2.DbgModelTargetModuleContainer; import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; @@ -49,9 +50,16 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl super(process.getModel(), process, "Modules", "ModuleContainer"); this.targetProcess = process; this.process = process.process; - if (!getModel().isSuppressDescent()) { - requestElements(RefreshBehavior.REFRESH_NEVER); + DbgManagerImpl manager = getManager(); + if (manager.isKernelMode()) { + if (!this.process.getId().isSystem()) { + return; + } } + if (getModel().isSuppressDescent()) { + return; + } + requestElements(RefreshBehavior.REFRESH_NEVER); } @Override 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 c1056b76f8..0f5d63de1b 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 @@ -125,9 +125,18 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject requestElements(RefreshBehavior refresh) { - return getManager().listProcesses().thenAccept(byIID -> { + DbgManagerImpl manager = getManager(); + return manager.listProcesses().thenAccept(byIID -> { List processes; synchronized (this) { processes = byIID.values() @@ -188,4 +214,15 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl return AsyncUtils.NIL; } + @TargetMethod.Export("Populate") + public CompletableFuture populate() { + return getManager().listOSProcesses().thenAccept(byPID -> { + List processes; + synchronized (this) { + processes = + byPID.values().stream().map(this::getTargetProcess).collect(Collectors.toList()); + } + setElements(processes, Map.of(), "Refreshed"); + }); + } } 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 719cde64c2..9bfc40b1d5 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 @@ -20,14 +20,24 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugProcessId; -import agent.dbgeng.manager.*; +import agent.dbgeng.manager.DbgCause; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface2.DbgModelTargetDebugContainer; +import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer; +import agent.dbgeng.model.iface2.DbgModelTargetModuleContainer; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; +import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer; +import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer; import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; -import ghidra.dbg.target.*; +import ghidra.dbg.target.TargetAttachable; import ghidra.dbg.target.TargetEventScope.TargetEventType; -import ghidra.dbg.target.schema.*; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.schema.TargetAttributeType; +import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.dbg.util.PathUtils; @TargetObjectSchemaInfo( @@ -69,7 +79,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID); protected static String indexProcess(DebugProcessId debugProcessId) { - return PathUtils.makeIndex(debugProcessId.id); + return debugProcessId.id(); } protected static String indexProcess(DbgProcess process) { @@ -111,32 +121,42 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS, // SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, DbgModelTargetThreadImpl.SUPPORTED_KINDS // ), "Initialized"); - setExecutionState(TargetExecutionState.ALIVE, "Initialized"); + if (getManager().isKernelMode()) { + TargetExecutionState state = process.getPid() > 0 ? + TargetExecutionState.INACTIVE : TargetExecutionState.ALIVE; + setExecutionState(state, "Initialized"); + } + else { + setExecutionState(TargetExecutionState.ALIVE, "Initialized"); + } getManager().addEventsListener(this); } @Override public String getDisplay() { - if (getManager().isKernelMode()) { - return "[kernel]"; - } - + DebugProcessId id = process.getId(); Long pid = process.getPid(); - if (pid < 0) { - return "[" + process.getId().id + "]"; + if (getManager().isKernelMode()) { + if (id.isSystem()) { + return "["+id.id()+"]"; + } + String pidstr = Long.toString(pid, base); + if (base == 16) { + pidstr = "0x" + pidstr; + } + Long offset = process.getOffset(); + return offset == null ? "[" + pidstr + "]" : "[" + pidstr + " : " + Long.toHexString(offset) + "]"; } - String pidstr = Long.toString(pid, base); - if (base == 16) { - pidstr = "0x" + pidstr; - } - return "[" + process.getId().id + ":" + pidstr + "]"; - } - - @Override - public void processSelected(DbgProcess eventProcess, DbgCause cause) { - if (eventProcess.equals(process)) { - ((DbgModelTargetFocusScope) searchForSuitable(TargetFocusScope.class)).setFocus(this); + else { + if (pid < 0) { + return "[" + id.id() + "]"; + } + String pidstr = Long.toString(pid, base); + if (base == 16) { + pidstr = "0x" + pidstr; + } + return "[" + id.id() + ":" + 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 05c962192f..7825bff3c5 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 @@ -170,13 +170,14 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp private void changeAttrs(DbgModelTargetRegister reg, BigInteger value) { String oldval = (String) reg.getCachedAttributes().get(VALUE_ATTRIBUTE_NAME); + String valstr = Long.toUnsignedString(value.longValue(), 16); //value.toString(16); String newval = (value.longValue() == 0) ? reg.getName() - : reg.getName() + " : " + value.toString(16); + : reg.getName() + " : " + valstr; reg.changeAttributes(List.of(), Map.of( // - VALUE_ATTRIBUTE_NAME, value.toString(16), // + VALUE_ATTRIBUTE_NAME, valstr, // DISPLAY_ATTRIBUTE_NAME, newval // ), "Refreshed"); - reg.setModified(!value.toString(16).equals(oldval)); + reg.setModified(!valstr.equals(oldval)); } @Override diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java index 0a596e8c1a..ce3e6fb477 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetRootImpl.java @@ -15,16 +15,41 @@ */ package agent.dbgeng.model.impl; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.CompletableFuture; -import agent.dbgeng.manager.*; +import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.manager.DbgCause; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.DbgReason; +import agent.dbgeng.manager.DbgSession; +import agent.dbgeng.manager.DbgStackFrame; +import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; +import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgProcessImpl; +import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.iface1.DbgModelSelectableObject; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; +import agent.dbgeng.model.iface2.DbgModelTargetConnector; +import agent.dbgeng.model.iface2.DbgModelTargetRoot; +import agent.dbgeng.model.iface2.DbgModelTargetThread; +import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.error.DebuggerUserException; -import ghidra.dbg.target.*; -import ghidra.dbg.target.schema.*; +import ghidra.dbg.target.TargetEventScope; +import ghidra.dbg.target.TargetExecutionStateful; +import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; +import ghidra.dbg.target.TargetFocusScope; +import ghidra.dbg.target.TargetMethod; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.schema.TargetAttributeType; +import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.TargetObjectSchema; +import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.dbg.util.PathUtils; @TargetObjectSchemaInfo( @@ -142,6 +167,117 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot } } + @Override + public void processSelected(DbgProcess process, DbgCause cause) { + if (process != null) { + objectSelected(process); + } + } + + @Override + public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) { + if (thread != null) { + objectSelected(thread); + if (frame != null) { + objectSelected(frame); + } + } + } + + public void objectSelected(Object object) { + AbstractDbgModel model = getModel(); + List objPath = findObject(object); + model.fetchModelObject(objPath, RefreshBehavior.REFRESH_WHEN_ABSENT).thenAccept(obj -> + update(obj) + ); + } + + private List findObject(Object obj) { + DbgManagerImpl manager = getManager(); + List objpath = new ArrayList<>(); + if (obj == null) { + return objpath; + } + DbgSession session = manager.getCurrentSession(); + if (obj instanceof DbgSession) { + session = (DbgSession) obj; + } + if (session == null) { + return objpath; + } + String skey = DbgModelTargetSessionImpl.keySession(session); + if (obj instanceof DbgSession || obj instanceof String) { + objpath = List.of("Sessions", skey); + return objpath; + } + + DbgProcess process = manager.getCurrentProcess(); + if (obj instanceof DbgProcess) { + process = (DbgProcess) obj; + } + if (process == null) { + return objpath; + } + String pkey = DbgModelTargetProcessImpl.keyProcess(process); + if (obj instanceof DbgProcess || obj instanceof DebugProcessId) { + objpath = List.of("Sessions", skey, "Processes", pkey); + return objpath; + } + + DbgThread thread = manager.getCurrentThread(); + if (obj instanceof DbgThread) { + thread = (DbgThread) obj; + process = thread.getProcess(); + pkey = DbgModelTargetProcessImpl.keyProcess(process); + } + if (thread == null) { + return objpath; + } + String tkey = DbgModelTargetThreadImpl.keyThread(thread); + if (getManager().isKernelMode()) { + if (tkey.equals("[0x0]")) { + // Weird, but necessary... + pkey = "[0x0]"; + } + } + if (obj instanceof DbgThread || obj instanceof DebugThreadId) { + objpath = List.of("Sessions", skey, "Processes", pkey, "Threads", tkey); + return objpath; + } + + if (obj instanceof DbgStackFrame) { + DbgStackFrame frame = (DbgStackFrame) obj; + thread = frame.getThread(); + process = thread.getProcess(); + String fkey = DbgModelTargetStackFrameImpl.keyFrame(frame); + tkey = DbgModelTargetThreadImpl.keyThread(thread); + pkey = DbgModelTargetProcessImpl.keyProcess(process); + objpath = List.of("Sessions", skey, "Processes", pkey, "Threads", tkey, "Stack", + "Frames", fkey); + return objpath; + } + return objpath; + } + + private void update(TargetObject obj) { + if (obj instanceof DbgModelSelectableObject) { + setFocus((DbgModelSelectableObject) obj); + } + if (obj instanceof DbgModelTargetExecutionStateful) { + activate((DbgModelTargetExecutionStateful) obj); + } + } + + private void activate(DbgModelTargetExecutionStateful stateful) { + TargetExecutionState state = stateful.getExecutionState(); + if (state.equals(TargetExecutionState.INACTIVE)) { + stateful.changeAttributes(List.of(), Map.of( // + TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE // + ), "Selected"); + stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS); + } + } + @Override public boolean isAccessible() { return accessible; diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java index c1ef8d19c0..005f18d3f8 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java @@ -52,7 +52,7 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl // NB: This should almost certainly always be implemented by the root of the object tree protected static String indexSession(DebugSessionId debugSystemId) { - return PathUtils.makeIndex(debugSystemId.id); + return debugSystemId.id(); } protected static String indexSession(DbgSession session) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java index 83334b8136..0a974f8eb1 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetStackFrameImpl.java @@ -109,7 +109,7 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl if (frame.getFunction() == null) { return String.format("#%d 0x%s", frame.getLevel(), frame.getAddress().toString(16)); } - return String.format("#%d 0x%s in %s ()", frame.getLevel(), frame.getAddress().toString(16), + return String.format("#%d 0x%s in %s", frame.getLevel(), frame.getAddress().toString(16), frame.getFunction()); } 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 d983430648..251315f832 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 @@ -15,30 +15,47 @@ */ package agent.dbgeng.model.impl; +import java.lang.invoke.MethodHandles; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import agent.dbgeng.dbgeng.DebugThreadId; -import agent.dbgeng.manager.*; -import agent.dbgeng.manager.reason.*; +import agent.dbgeng.manager.DbgCause; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.DbgReason; +import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; +import agent.dbgeng.manager.reason.DbgEndSteppingRangeReason; +import agent.dbgeng.manager.reason.DbgExitNormallyReason; +import agent.dbgeng.manager.reason.DbgExitedReason; +import agent.dbgeng.manager.reason.DbgSignalReceivedReason; import agent.dbgeng.model.iface1.DbgModelTargetConfigurable; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; +import agent.dbgeng.model.iface2.DbgModelTargetThread; +import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer; import ghidra.async.AsyncUtils; import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.error.DebuggerIllegalArgumentException; import ghidra.dbg.target.TargetConfigurable; +import ghidra.dbg.target.TargetMethod; +import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod; import ghidra.dbg.target.TargetObject; -import ghidra.dbg.target.schema.*; +import ghidra.dbg.target.schema.TargetAttributeType; +import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.TargetObjectSchemaInfo; @TargetObjectSchemaInfo( name = "ThreadContainer", elements = { @TargetElementType(type = DbgModelTargetThreadImpl.class) - }, + }, attributes = { @TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class), + @TargetAttributeType(name = "Populate", type = TargetMethod.class), @TargetAttributeType(type = Void.class) }, canonicalContainer = true) @@ -50,11 +67,16 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl public DbgModelTargetThreadContainerImpl(DbgModelTargetProcessImpl process) { super(process.getModel(), process, "Threads", "ThreadContainer"); this.process = process.process; - this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized"); + this.changeAttributes(List.of(), Map.of( + BASE_ATTRIBUTE_NAME, 16 // + ), "Initialized"); - getManager().addEventsListener(this); - if (!getModel().isSuppressDescent()) { - requestElements(RefreshBehavior.REFRESH_NEVER); + DbgManagerImpl manager = getManager(); + manager.addEventsListener(this); + if (manager.isKernelMode() && !process.getProcess().getId().isSystem()) { + changeAttributes(List.of(), List.of(), + AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), getModel(), this), + "Methods"); } } @@ -71,6 +93,9 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl @Override public void threadStateChanged(DbgThread thread, DbgState state, DbgCause cause, DbgReason reason) { + if (!thread.getProcess().equals(process)) { + return; + } DbgModelTargetThread targetThread = getTargetThread(thread); TargetEventType eventType = getEventType(state, cause, reason); broadcast().event(getProxy(), targetThread, eventType, @@ -163,4 +188,17 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl } return AsyncUtils.NIL; } + + @TargetMethod.Export("Populate") + public CompletableFuture populate() { + return getManager().listOSThreads((DbgProcessImpl) process).thenAccept(byTID -> { + List threads; + synchronized (this) { + threads = + byTID.values().stream().map(this::getTargetThread).collect(Collectors.toList()); + } + setElements(threads, Map.of(), "Refreshed"); + }); + } + } 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 e38554375b..3a722598d3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetThreadImpl.java @@ -21,14 +21,19 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugThreadId; -import agent.dbgeng.manager.*; +import agent.dbgeng.manager.DbgReason; +import agent.dbgeng.manager.DbgState; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.impl.DbgManagerImpl; -import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; -import agent.dbgeng.model.iface2.*; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; +import agent.dbgeng.model.iface2.DbgModelTargetRegisterContainerAndBank; +import agent.dbgeng.model.iface2.DbgModelTargetThread; +import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer; import ghidra.dbg.target.TargetEnvironment; -import ghidra.dbg.target.TargetFocusScope; import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod; -import ghidra.dbg.target.schema.*; +import ghidra.dbg.target.schema.TargetAttributeType; +import ghidra.dbg.target.schema.TargetElementType; +import ghidra.dbg.target.schema.TargetObjectSchemaInfo; import ghidra.dbg.util.PathUtils; @TargetObjectSchemaInfo( @@ -61,7 +66,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl TargetStepKind.EXTENDED); protected static String indexThread(DebugThreadId debugThreadId) { - return PathUtils.makeIndex(debugThreadId.id); + return debugThreadId.id(); } protected static String indexThread(DbgThread thread) { @@ -110,24 +115,31 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl @Override public String getDisplay() { - if (getManager().isKernelMode()) { - return "[PR" + thread.getId().id + "]"; + if (thread == null) { + return "[unknown]"; } + DebugThreadId id = thread.getId(); Long tid = thread.getTid(); - if (tid < 0) { - return "[" + thread.getId().id + "]"; + if (getManager().isKernelMode()) { + if (id.isSystem()) { + return "[" + id.id() + "]"; + } + String tidstr = Long.toString(tid, base); + if (base == 16) { + tidstr = "0x" + tidstr; + } + Long offset = thread.getOffset(); + return offset == null ? "[" + tidstr + "]" : "[" + tidstr + " : " + Long.toHexString(offset) + "]"; } - String tidstr = Long.toString(tid, base); - if (base == 16) { - tidstr = "0x" + tidstr; - } - return "[" + thread.getId().id + ":" + tidstr + "]"; - } - - @Override - public void threadSelected(DbgThread eventThread, DbgStackFrame frame, DbgCause cause) { - if (eventThread.equals(thread)) { - ((DbgModelTargetFocusScope) searchForSuitable(TargetFocusScope.class)).setFocus(this); + else { + if (tid < 0) { + return "[" + id.id() + "]"; + } + String tidstr = Long.toString(tid, base); + if (base == 16) { + tidstr = "0x" + tidstr; + } + return "[" + id.id() + ":" + tidstr + "]"; } } 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 8429c315a6..733507b4db 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 @@ -16,17 +16,52 @@ package agent.dbgmodel.gadp.impl; import java.nio.ByteBuffer; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import com.sun.jna.platform.win32.WinDef.ULONGLONG; import com.sun.jna.platform.win32.COM.COMException; -import agent.dbgeng.dbgeng.*; +import agent.dbgeng.dbgeng.DebugAdvanced; +import agent.dbgeng.dbgeng.DebugClient; +import agent.dbgeng.dbgeng.DebugControl; +import agent.dbgeng.dbgeng.DebugDataSpaces; +import agent.dbgeng.dbgeng.DebugEventCallbacks; +import agent.dbgeng.dbgeng.DebugInputCallbacks; +import agent.dbgeng.dbgeng.DebugModule; +import agent.dbgeng.dbgeng.DebugModuleInfo; +import agent.dbgeng.dbgeng.DebugOutputCallbacks; +import agent.dbgeng.dbgeng.DebugProcessId; +import agent.dbgeng.dbgeng.DebugProcessRecord; +import agent.dbgeng.dbgeng.DebugRegisters; +import agent.dbgeng.dbgeng.DebugRunningProcess; import agent.dbgeng.dbgeng.DebugRunningProcess.Description; import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags; -import agent.dbgeng.dbgeng.DebugValue.*; +import agent.dbgeng.dbgeng.DebugServerId; +import agent.dbgeng.dbgeng.DebugSessionId; +import agent.dbgeng.dbgeng.DebugSymbolEntry; +import agent.dbgeng.dbgeng.DebugSymbolId; +import agent.dbgeng.dbgeng.DebugSymbolName; +import agent.dbgeng.dbgeng.DebugSymbols; +import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.DebugValue; +import agent.dbgeng.dbgeng.DebugValue.DebugInt16Value; +import agent.dbgeng.dbgeng.DebugValue.DebugInt32Value; +import agent.dbgeng.dbgeng.DebugValue.DebugInt64Value; +import agent.dbgeng.dbgeng.DebugValue.DebugValueType; import agent.dbgmodel.dbgmodel.bridge.HostDataModelAccess; -import agent.dbgmodel.dbgmodel.debughost.*; +import agent.dbgmodel.dbgmodel.debughost.DebugHost; +import agent.dbgmodel.dbgmodel.debughost.DebugHostContext; +import agent.dbgmodel.dbgmodel.debughost.DebugHostMemory1; +import agent.dbgmodel.dbgmodel.debughost.DebugHostModule1; +import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbol1; +import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbolEnumerator; +import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbols; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.impl.dbgmodel.DebugRunningProcessImpl; import agent.dbgmodel.impl.dbgmodel.bridge.HDMAUtil; @@ -592,7 +627,7 @@ public class WrappedDbgModel public void setCurrentThreadId(DebugThreadId dti) { DebugSystemObjects so = client.getSystemObjects(); DebugThreadId currentThreadId = so.getCurrentThreadId(); - if (dti.id != currentThreadId.id) { + if (!dti.id().equals(currentThreadId.id())) { so.setCurrentThreadId(dti); } /* @@ -919,7 +954,7 @@ public class WrappedDbgModel } int pid = Integer.decode(id); if (pid == 0) { - return new DebugProcessId(-1); + return new DebugProcessRecord(-1); } DebugProcessId dpi = client.getSystemObjects().getProcessIdBySystemId(pid); addObj(dpi, id); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java index d28fc0caf8..71d7bbc43e 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetRootImpl.java @@ -164,30 +164,26 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot @Override public void processSelected(DbgProcess process, DbgCause cause) { - objectSelected(process); - if (getManager().isKernelMode()) { - processActivated(process); + if (process != null) { + objectSelected(process); } } @Override public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) { - objectSelected(thread); - if (getManager().isKernelMode() && thread != null) { - processActivated(thread.getProcess()); - threadActivated(thread); - } - if (frame != null) { - objectSelected(frame); + if (thread != null) { + objectSelected(thread); + if (frame != null) { + objectSelected(frame); + } } } public void objectSelected(Object object) { List objPath = findObject(object); - TargetObject obj = getModel().getModelObject(objPath); - if (obj instanceof DbgModelSelectableObject) { - setFocus((DbgModelSelectableObject) obj); - } + model.fetchModelObject(objPath, RefreshBehavior.REFRESH_WHEN_ABSENT).thenAccept(obj -> + update(obj) + ); } @Override @@ -217,21 +213,6 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot }); } - public void processActivated(DbgProcess proc) { - List objPath = findObject(proc); - DbgModelTargetExecutionStateful stateful = (DbgModelTargetExecutionStateful) getModel().getModelObject(objPath); - if (stateful == null) { - return; - } - TargetExecutionState state = stateful.getExecutionState(); - if (state.equals(TargetExecutionState.INACTIVE)) { - stateful.changeAttributes(List.of(), Map.of( // - TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE // - ), "Selected"); - stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS); - } - } - @Override public void threadCreated(DbgThread thread, DbgCause cause) { getObject(thread).thenAccept(obj -> { @@ -253,21 +234,6 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot }); } - public void threadActivated(DbgThread thread) { - List objPath = findObject(thread); - DbgModelTargetExecutionStateful stateful = (DbgModelTargetExecutionStateful) getModel().getModelObject(objPath); - if (stateful == null) { - return; - } - TargetExecutionState state = stateful.getExecutionState(); - if (state.equals(TargetExecutionState.INACTIVE)) { - stateful.changeAttributes(List.of(), Map.of( // - TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE // - ), "Selected"); - stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS); - } - } - @Override public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> { @@ -340,7 +306,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot xpath.addAll(ext); // NB: fetchModelObject may have to be called with false return AsyncUtils.sequence(TypeSpec.cls(DbgModelTargetObject.class)).then(seq -> { - getModel().fetchModelObject(xpath, false).handle(seq::next); + getModel().fetchModelObject(xpath, RefreshBehavior.REFRESH_NEVER).handle(seq::next); }, TypeSpec.cls(TargetObject.class)).then((pobj, seq) -> { if (pobj == null) { seq.exit(); @@ -564,11 +530,11 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DebugSystemObjects so = getManager().getSystemObjects(); List objpath = new ArrayList<>(); DebugSessionId sid = so.getCurrentSystemId(); - String skey = sid.id < 0 ? PathUtils.makeKey("0x0") - : PathUtils.makeKey("0x" + Integer.toHexString(sid.id)); + String skey = sid.value() < 0 ? PathUtils.makeKey("0x0") + : PathUtils.makeKey("0x" + sid.id()); if (obj instanceof DbgSession) { DbgSession session = (DbgSession) obj; - skey = PathUtils.makeKey("0x" + Long.toHexString(session.getId().id)); + skey = PathUtils.makeKey("0x" + session.getId().id()); } if (obj instanceof DbgSession || obj instanceof String) { objpath = List.of("Sessions", skey); @@ -615,6 +581,30 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot return objpath; } + private void update(TargetObject obj) { + if (obj instanceof DbgModelSelectableObject) { + setFocus((DbgModelSelectableObject) obj); + } + if (obj instanceof DbgModelTargetExecutionStateful) { + activate((DbgModelTargetExecutionStateful) obj); + // OK, this sucks, but not all threads are parented to activated objects + DbgModelTargetProcess parentProcess = ((DbgModelTargetObject) obj).getParentProcess(); + if (obj instanceof DbgModelTargetExecutionStateful) { + activate(parentProcess); + } + } + } + + private void activate(DbgModelTargetExecutionStateful stateful) { + TargetExecutionState state = stateful.getExecutionState(); + if (state.equals(TargetExecutionState.INACTIVE)) { + stateful.changeAttributes(List.of(), Map.of( // + TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE // + ), "Selected"); + stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS); + } + } + private TargetEventType getEventType(DbgState state, DbgCause cause, DbgReason reason) { switch (state) { case RUNNING: diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/test/java/agent/dbgmodel/dbgmodel/DbgModelSetContextMWETest.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/test/java/agent/dbgmodel/dbgmodel/DbgModelSetContextMWETest.java index e1dec4da49..e7bb33f51d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/test/java/agent/dbgmodel/dbgmodel/DbgModelSetContextMWETest.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/test/java/agent/dbgmodel/dbgmodel/DbgModelSetContextMWETest.java @@ -83,7 +83,7 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration private void dumpRegsViaDX() { DebugThreadId id = so.getCurrentThreadId(); - if (id.id == -1) { + if (id.value() == -1) { return; } @@ -102,7 +102,7 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration private void dumpFrame0ViaDX() { DebugThreadId id = so.getCurrentThreadId(); - if (id.id == -1) { + if (id.value() == -1) { return; } @@ -135,44 +135,44 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration private void dumpFrame0ViaK() { DebugThreadId id = so.getCurrentThreadId(); - if (id.id == -1) { + if (id.value() == -1) { return; } try { DebugStackInformation stackInfo = control.getStackTrace(0, 0, 0); if (stackInfo.getNumberOfFrames() == 0) { - Msg.info(this, "t" + id.id + ".Stack is empty?"); + Msg.info(this, "t" + id.id() + ".Stack is empty?"); } else { DEBUG_STACK_FRAME frame = stackInfo.getFrame(0); Msg.info(this, - String.format("t%d.Frame[0].io=%08x", id.id, + String.format("t%d.Frame[0].io=%08x", id.id(), frame.InstructionOffset.longValue())); } } catch (Exception e) { - Msg.info(this, "Could not read t" + id.id + ".Frame[0].io: " + e); + Msg.info(this, "Could not read t" + id.id() + ".Frame[0].io: " + e); } } private void dumpPCViaRegsAPI() { DebugThreadId id = so.getCurrentThreadId(); - if (id.id == -1) { + if (id.value() == -1) { return; } try { - Msg.info(this, String.format("t%d.rip=%s", id.id, + Msg.info(this, String.format("t%d.rip=%s", id.id(), registers.getValueByName("rip"))); } catch (Exception e) { - Msg.info(this, "Could not read t" + id.id + ".RIP: " + e); + Msg.info(this, "Could not read t" + id.id() + ".RIP: " + e); } try { - Msg.info(this, String.format("t%d.eip=%s", id.id, + Msg.info(this, String.format("t%d.eip=%s", id.id(), registers.getValueByName("eip"))); } catch (Exception e) { - Msg.info(this, "Could not read t" + id.id + ".EIP: " + e); + Msg.info(this, "Could not read t" + id.id() + ".EIP: " + e); } } diff --git a/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/client/GadpClientTest.java b/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/client/GadpClientTest.java index a0a46c374e..64692b0622 100644 --- a/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/client/GadpClientTest.java +++ b/Ghidra/Debug/Debugger-gadp/src/test/java/ghidra/dbg/gadp/client/GadpClientTest.java @@ -31,6 +31,7 @@ import java.util.concurrent.TimeoutException; import org.junit.Test; import ghidra.async.*; +import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.gadp.GadpVersion; import ghidra.dbg.gadp.protocol.Gadp; import ghidra.dbg.gadp.util.AsyncProtobufMessageChannel; @@ -400,7 +401,7 @@ public class GadpClientTest implements AsyncTestUtils { assertEquals(HELLO_WORLD, waitOn(fetchVal1)); assertEquals(HELLO_WORLD, waitOn(fetchVal2)); - CompletableFuture fetchVal3 = client.fetchModelValue(PathUtils.parse("value"), true); + CompletableFuture fetchVal3 = client.fetchModelValue(PathUtils.parse("value"), RefreshBehavior.REFRESH_ALWAYS); srv.handleResyncAttributes(List.of(), true, null, Map.of("value", "Hi")); assertEquals("Hi", waitOn(fetchVal3)); } 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 ccddc4156a..b1341614e9 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 @@ -20,8 +20,14 @@ import java.awt.Color; import java.awt.event.MouseEvent; import java.io.PrintWriter; import java.lang.invoke.MethodHandles; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -36,7 +42,10 @@ import org.apache.commons.lang3.StringUtils; import docking.ActionContext; import docking.WindowPosition; -import docking.action.*; +import docking.action.DockingAction; +import docking.action.DockingActionIf; +import docking.action.MenuData; +import docking.action.ToggleDockingAction; import docking.action.builder.ActionBuilder; import docking.action.builder.ToggleActionBuilder; import docking.widgets.OptionDialog; @@ -47,29 +56,107 @@ import generic.theme.GColor; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.gui.DebuggerResources; -import ghidra.app.plugin.core.debug.gui.DebuggerResources.*; -import ghidra.app.plugin.core.debug.gui.objects.actions.*; -import ghidra.app.plugin.core.debug.gui.objects.components.*; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractAttachAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractConsoleAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractDetachAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractInterruptAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractKillAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractLaunchAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractQuickLaunchAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRecordAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRefreshAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractResumeAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSetBreakpointAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepFinishAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepIntoAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepLastAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepOverAction; +import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractToggleAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsGraphAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsTableAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsTreeAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsXMLAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredGraphAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredTableAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredTreeAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredXMLAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayMethodsAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.ExportAsFactsAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.ExportAsXMLAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.ImportFromFactsAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.ImportFromXMLAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.OpenWinDbgTraceAction; +import ghidra.app.plugin.core.debug.gui.objects.actions.SetTimeoutAction; +import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerAttachDialog; +import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerBreakpointDialog; +import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog; +import ghidra.app.plugin.core.debug.gui.objects.components.DummyTargetObject; +import ghidra.app.plugin.core.debug.gui.objects.components.GenericDebuggerProgramLaunchOffer; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectAttributeColumn; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectAttributeRow; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectElementColumn; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectElementRow; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectEnumeratedColumnTableModel; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectNode; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectPane; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectTable; +import ghidra.app.plugin.core.debug.gui.objects.components.ObjectTree; import ghidra.app.plugin.core.debug.mapping.DebuggerMemoryMapper; -import ghidra.app.script.*; -import ghidra.app.services.*; +import ghidra.app.script.GhidraScript; +import ghidra.app.script.GhidraScriptLoadException; +import ghidra.app.script.GhidraScriptProvider; +import ghidra.app.script.GhidraScriptUtil; +import ghidra.app.script.GhidraState; +import ghidra.app.services.ConsoleService; +import ghidra.app.services.DebuggerListingService; +import ghidra.app.services.DebuggerModelService; +import ghidra.app.services.DebuggerStaticMappingService; +import ghidra.app.services.DebuggerTraceManagerService; import ghidra.app.services.DebuggerTraceManagerService.ActivationCause; -import ghidra.async.*; -import ghidra.dbg.*; +import ghidra.app.services.GraphDisplayBroker; +import ghidra.app.services.TraceRecorder; +import ghidra.async.AsyncFence; +import ghidra.async.AsyncUtils; +import ghidra.async.TypeSpec; +import ghidra.dbg.AnnotatedDebuggerAttributeListener; +import ghidra.dbg.DebugModelConventions; +import ghidra.dbg.DebuggerModelListener; +import ghidra.dbg.DebuggerObjectModel; import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.error.DebuggerMemoryAccessException; -import ghidra.dbg.target.*; +import ghidra.dbg.target.TargetAccessConditioned; +import ghidra.dbg.target.TargetAttachable; +import ghidra.dbg.target.TargetAttacher; +import ghidra.dbg.target.TargetBreakpointSpec; +import ghidra.dbg.target.TargetBreakpointSpecContainer; +import ghidra.dbg.target.TargetConfigurable; import ghidra.dbg.target.TargetConsole.Channel; +import ghidra.dbg.target.TargetDetachable; +import ghidra.dbg.target.TargetExecutionStateful; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; +import ghidra.dbg.target.TargetFocusScope; +import ghidra.dbg.target.TargetInterpreter; +import ghidra.dbg.target.TargetInterruptible; +import ghidra.dbg.target.TargetKillable; +import ghidra.dbg.target.TargetLauncher; +import ghidra.dbg.target.TargetMethod; import ghidra.dbg.target.TargetMethod.ParameterDescription; +import ghidra.dbg.target.TargetMethod.TargetParameterMap; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.TargetProcess; +import ghidra.dbg.target.TargetResumable; +import ghidra.dbg.target.TargetSteppable; import ghidra.dbg.target.TargetSteppable.TargetStepKind; +import ghidra.dbg.target.TargetTogglable; import ghidra.dbg.util.DebuggerCallbackReorderer; import ghidra.dbg.util.PathUtils; import ghidra.framework.model.Project; import ghidra.framework.options.AutoOptions; import ghidra.framework.options.SaveState; import ghidra.framework.options.annotation.AutoOptionDefined; -import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.AutoConfigState; +import ghidra.framework.plugintool.AutoService; +import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.annotation.AutoConfigStateField; import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.program.model.address.Address; @@ -79,7 +166,9 @@ import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.trace.model.Trace; import ghidra.trace.model.thread.TraceThread; -import ghidra.util.*; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; +import ghidra.util.Swing; import ghidra.util.datastruct.PrivatelyQueuedListener; import ghidra.util.table.GhidraTable; import ghidra.util.task.TaskMonitor; @@ -1412,7 +1501,15 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter list.toArray(new String[] {}), lastMethod, OptionDialog.QUESTION_MESSAGE); if (choice != null) { TargetMethod method = (TargetMethod) attributes.get(choice); - Map args = methodDialog.promptArguments(method.getParameters()); + TargetParameterMap parameters = method.getParameters(); + if (parameters.isEmpty()) { + method.invoke(new HashMap()); + if (!choice.equals("unload")) { + lastMethod = choice; + } + return; + } + Map args = methodDialog.promptArguments(parameters); if (args != null) { String script = (String) args.get("Script"); if (script != null && !script.isEmpty()) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredAction.java index 1530420cab..30afe4e3a6 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredAction.java @@ -27,6 +27,7 @@ import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.script.AskDialog; import ghidra.dbg.DebuggerObjectModel; +import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.target.TargetObject; import ghidra.framework.plugintool.PluginTool; @@ -77,7 +78,7 @@ public abstract class DisplayFilteredAction extends DockingAction { final List path) { TargetObject to = container.getTargetObject(); DebuggerObjectModel model = to.getModel(); - model.fetchModelObject(path, true).thenAccept(obj -> { + model.fetchModelObject(path, RefreshBehavior.REFRESH_ALWAYS).thenAccept(obj -> { container.setTargetObject(obj); finishGetOffspring(container, path); }); 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 b5732f1b32..229449f320 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 @@ -353,7 +353,7 @@ public interface DebuggerObjectModel { * @param refresh true to refresh caches * @return the found value, or {@code null} if it does not exist */ - public CompletableFuture fetchModelValue(List path, boolean refresh); + public CompletableFuture fetchModelValue(List path, RefreshBehavior refresh); /** * @see #fetchModelValue(List) @@ -406,7 +406,7 @@ public interface DebuggerObjectModel { * @throws DebuggerModelTypeException if the value at the path is not a {@link TargetObject} */ public default CompletableFuture fetchModelObject(List path, - boolean refresh) { + RefreshBehavior refresh) { return fetchModelValue(path, refresh).thenApply(v -> { if (v == null) { return null; @@ -431,7 +431,7 @@ public interface DebuggerObjectModel { */ @Deprecated public default CompletableFuture fetchModelObject(List path) { - return fetchModelObject(path, false); + return fetchModelObject(path, RefreshBehavior.REFRESH_NEVER); } /** diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiDebuggerObjectModel.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiDebuggerObjectModel.java index 3d2824887f..5cc918b800 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiDebuggerObjectModel.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/SpiDebuggerObjectModel.java @@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture; import ghidra.async.AsyncUtils; import ghidra.dbg.DebuggerObjectModel; -import ghidra.dbg.DebuggerObjectModel.RefreshBehavior; import ghidra.dbg.error.DebuggerModelTypeException; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.PathUtils; @@ -50,17 +49,26 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel { } public static CompletableFuture fetchSuccessorValue(TargetObject obj, - List path, boolean refresh, boolean followLinks) { + List path, RefreshBehavior refresh, boolean followLinks) { if (path.isEmpty()) { return CompletableFuture.completedFuture(obj); } String key = path.get(0); CompletableFuture futureChild; - if (refresh) { - futureChild = fetchFreshChild(obj, key); - } - else { - futureChild = obj.fetchChild(key); + switch (refresh) { + case REFRESH_ALWAYS: + futureChild = fetchFreshChild(obj, key); + break; + case REFRESH_NEVER: + futureChild = obj.fetchChild(key); + break; + case REFRESH_WHEN_ABSENT: + default: + CompletableFuture futureChild0 = obj.fetchChild(key); + futureChild = futureChild0.thenCompose(c -> { + return c == null ? fetchFreshChild(obj, key) : CompletableFuture.completedFuture(c); + }); + break; } return futureChild.thenCompose(c -> { if (c == null) { @@ -91,7 +99,7 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel { } @Override - public default CompletableFuture fetchModelValue(List path, boolean refresh) { + public default CompletableFuture fetchModelValue(List path, RefreshBehavior refresh) { return fetchModelRoot().thenCompose(root -> { return fetchSuccessorValue(root, path, refresh, true); }); @@ -99,7 +107,45 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel { @Override public default CompletableFuture fetchModelValue(List path) { - return fetchModelValue(path, false); + return fetchModelValue(path, RefreshBehavior.REFRESH_NEVER); + } + + public static CompletableFuture fetchSuccessorValueUsingAvailableCache(TargetObject obj, + List path, boolean followLinks) { + if (path.isEmpty()) { + return CompletableFuture.completedFuture(obj); + } + String key = path.get(0); + CompletableFuture futureChild = obj.fetchChild(key); + CompletableFuture ffutureChild = futureChild.thenCompose(c -> { + return c == null ? fetchFreshChild(obj, key) : CompletableFuture.completedFuture(c); + }); + return ffutureChild.thenCompose(c -> { + if (c == null) { + return AsyncUtils.nil(); + } + if (!(c instanceof TargetObject)) { + if (path.size() == 1) { + return CompletableFuture.completedFuture(c); + } + else { + List p = PathUtils.extend(obj.getPath(), key); + throw DebuggerModelTypeException.typeRequired(c, p, TargetObject.class); + } + } + TargetObject child = (TargetObject) c; + if (PathUtils.isLink(obj.getPath(), key, child.getPath()) && !followLinks) { + if (path.size() == 1) { + return CompletableFuture.completedFuture(c); + } + else { + List p = PathUtils.extend(obj.getPath(), key); + throw DebuggerModelTypeException.linkForbidden(child, p); + } + } + List remains = path.subList(1, path.size()); + return fetchSuccessorValueUsingAvailableCache(child, remains, followLinks); + }); } @Override