diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java index c8658bf505..eeee2a6942 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgProcess.java @@ -236,4 +236,9 @@ public interface DbgProcess extends DbgMemoryOperations { */ CompletableFuture remove(); + /** + * Get the address of the associated process structure + */ + Long getOffset(); + } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java index ae20f29ee9..08a4c50717 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgThread.java @@ -158,9 +158,12 @@ public interface DbgThread /** * Get the effective architecture for the executing thread - * - * @return a future that completes when GDB has executed the command */ Machine getExecutingProcessorType(); -} \ No newline at end of file + /** + * Get the address of the associated thread structure + */ + Long getOffset(); + +} 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 new file mode 100644 index 0000000000..4130229377 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveProcessCommand.java @@ -0,0 +1,104 @@ +/* ### + * 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 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; +import agent.dbgeng.manager.evt.DbgConsoleOutputEvent; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgProcessImpl; +import ghidra.util.Msg; + +public class DbgResolveProcessCommand extends AbstractDbgCommand { + + private DbgProcessImpl process; + private Long offset; + + /** + * Adjust the process contents to include both pid and offset + * NB: should only be used in kernel-mode against the current process (i.e. id==offset) + * + * @param manager the manager to execute the command + * @param process the desired process + */ + public DbgResolveProcessCommand(DbgManagerImpl manager, DbgProcess process) { + super(manager); + this.process = (DbgProcessImpl) process; + } + + @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 DbgProcess complete(DbgPendingCommand pending) { + StringBuilder builder = new StringBuilder(); + for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) { + builder.append(out.getOutput()); + } + parse(builder.toString()); + return process; + } + + private void parse(String result) { + String[] lines = result.split("\n"); + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line.contains("PROCESS")) { + String[] fields = line.trim().split("\\s+"); + if (fields.length > 1 && fields[0].equals("PROCESS")) { + BigInteger val = new BigInteger(fields[1], 16); + offset = val.longValue(); + process.setOffset(offset); + } + } + 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); + process.setPid(pid); + } + break; + } + } + if (offset == null) { + Msg.error(this, result); + } + } + + @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"); + } + } + } +} 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 new file mode 100644 index 0000000000..917e163cfe --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgResolveThreadCommand.java @@ -0,0 +1,102 @@ +/* ### + * 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 agent.dbgeng.dbgeng.DebugControl; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgThread; +import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; +import agent.dbgeng.manager.evt.DbgConsoleOutputEvent; +import agent.dbgeng.manager.impl.DbgManagerImpl; +import agent.dbgeng.manager.impl.DbgThreadImpl; +import ghidra.util.Msg; + +public class DbgResolveThreadCommand extends AbstractDbgCommand { + + private DbgThreadImpl thread; + private Long offset; + + /** + * Adjust the thread contents to include both tid and offset + * NB: should only be used in kernel-mode against the current thread (i.e. id==offset) + * + * @param manager the manager to execute the command + * @param thread the desired thread + * @param frameId the desired frame level + */ + public DbgResolveThreadCommand(DbgManagerImpl manager, DbgThread thread) { + super(manager); + this.thread = (DbgThreadImpl) 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 DbgThread complete(DbgPendingCommand pending) { + StringBuilder builder = new StringBuilder(); + for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) { + builder.append(out.getOutput()); + } + parse(builder.toString()); + return thread; + } + + private void parse(String result) { + String[] lines = result.split("\n"); + 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 > 4 && fields[0].equals("THREAD")) { + BigInteger val = new BigInteger(fields[1], 16); + offset = val.longValue(); + thread.setOffset(offset); + String[] split = fields[3].split("\\."); + if (split.length == 2) { + //Long pid = Long.parseLong(split[0], 16); + Long tid = Long.parseLong(split[1], 16); + thread.setTid(tid); + } + } + break; + } + } + if (offset == null) { + Msg.error(this, result); + } + } + + @Override + public void invoke() { + DebugThreadId id = thread.getId(); + if (id != null) { + DebugControl control = manager.getControl(); + control.execute("!thread "+Long.toHexString(id.id)+" 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 e8162e18b8..c91d2cce81 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 @@ -93,10 +93,9 @@ public class DbgSetActiveProcessCommand extends AbstractDbgCommand { offset = process.getOffset(); if (offset == null || offset == 0L) { DebugControl control = manager.getControl(); - control.execute("!process "+Long.toHexString(process.getPid())); + control.execute("!process "+Long.toHexString(process.getPid())+" 0"); } - } - else { + } else { so.setCurrentProcessId(id); DebugProcessId currentProcessId = so.getCurrentProcessId(); if (id.id != currentProcessId.id) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java index 2ce79ca96c..621c85e198 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgSetActiveThreadCommand.java @@ -91,12 +91,11 @@ public class DbgSetActiveThreadCommand extends AbstractDbgCommand { if (id != null) { if (!manager.isKernelMode()) { manager.getSystemObjects().setCurrentThreadId(id); - } - else { + } else { offset = thread.getOffset(); if (offset == null || offset == 0L) { DebugControl control = manager.getControl(); - control.execute("!thread -t "+Long.toHexString(thread.getTid())); + control.execute("!thread -t "+Long.toHexString(thread.getTid())+" 0"); } } if (frameId != null) { 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 3e5f31a431..f8680d7b80 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 @@ -103,10 +103,11 @@ import agent.dbgeng.manager.cmd.DbgRemoveProcessCommand; import agent.dbgeng.manager.cmd.DbgRemoveSessionCommand; import agent.dbgeng.manager.cmd.DbgRequestActivationCommand; import agent.dbgeng.manager.cmd.DbgRequestFocusCommand; +import agent.dbgeng.manager.cmd.DbgResolveProcessCommand; +import agent.dbgeng.manager.cmd.DbgResolveThreadCommand; import agent.dbgeng.manager.cmd.DbgSetActiveProcessCommand; import agent.dbgeng.manager.cmd.DbgSetActiveSessionCommand; import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand; -import agent.dbgeng.manager.cmd.DbgSetCurrentState; import agent.dbgeng.manager.evt.AbstractDbgEvent; import agent.dbgeng.manager.evt.DbgBreakpointCreatedEvent; import agent.dbgeng.manager.evt.DbgBreakpointDeletedEvent; @@ -251,9 +252,7 @@ public class DbgManagerImpl implements DbgManager { synchronized (threads) { if (threads.containsKey(id)) { DbgThreadImpl existingThread = threads.get(id); - if (existingThread.getTid() == tid) { - return existingThread; - } + return existingThread; } DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid); thread.add(); @@ -325,24 +324,11 @@ public class DbgManagerImpl implements DbgManager { } } - public DbgProcessImpl getProcessComputeIfAbsent(String key, boolean fire) { - String index = PathUtils.parseIndex(key); - Integer pid = Integer.decode(index); - DebugProcessId id = getSystemObjects().getProcessIdBySystemId(pid); - if (id == null) { - id = new DebugProcessId(pid); - return getProcessComputeIfAbsent(id, pid, fire); - } - return getProcessComputeIfAbsent(id, pid, fire); - } - public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, long pid, boolean fire) { synchronized (processes) { if (processes.containsKey(id)) { DbgProcessImpl existingProc = processes.get(id); - if (existingProc.getPid() == pid) { - return existingProc; - } + return existingProc; } DbgProcessImpl process = new DbgProcessImpl(this, id, pid); process.add(); @@ -598,7 +584,7 @@ public class DbgManagerImpl implements DbgManager { } return pcmd; } - + private void addCommand(DbgCommand cmd, DbgPendingCommand pcmd) { synchronized (this) { if (!cmd.validInState(state.get())) { @@ -610,42 +596,6 @@ public class DbgManagerImpl implements DbgManager { processEvent(new DbgCommandDoneEvent(cmd)); } - /*@Override - public DbgPendingCommand execute1(DbgCommand cmd) { - assert cmd != null; - checkStarted(); - DbgPendingCommand pcmd = new DbgPendingCommand<>(cmd); - sequence(TypeSpec.VOID).then((seq) -> { - Msg.debug(this, "WAITING cmdLock: " + pcmd); - cmdLock.acquire(null).handle(seq::next); - }, cmdLockHold).then((seq) -> { - Msg.debug(this, "ACQUIRED cmdLock: " + pcmd); - synchronized (this) { - if (curCmd != null) { - throw new AssertionError("Cannot execute more than one command at a time"); - } - if (!cmd.validInState(state.get())) { - throw new DbgCommandError( - "Command " + cmd + " is not valid while " + state.get()); - } - curCmd = pcmd; - } - cmd.invoke(); - processEvent(new DbgCommandDoneEvent(cmd.toString())); - seq.exit(); - }).finish().exceptionally((exc) -> { - pcmd.completeExceptionally(exc); - Msg.debug(this, "ON_EXCEPTION: CURCMD = " + curCmd); - curCmd = null; - Msg.debug(this, "SET CURCMD = null"); - Msg.debug(this, "RELEASING cmdLock"); - cmdLockHold.getAndSet(null).release(); - return null; - }); - return pcmd; - } - */ - public DebugStatus processEvent(DbgEvent evt) { if (state.get() == DbgState.STARTING) { state.set(DbgState.STOPPED, Causes.UNCLAIMED); @@ -777,7 +727,7 @@ public class DbgManagerImpl implements DbgManager { if (eventThread != null) { ((DbgThreadImpl) eventThread).setInfo(lastEventInformation); } - return currentThread.getId(); + return currentThread == null ? new DebugThreadId(-1) : currentThread.getId(); } /** @@ -889,6 +839,11 @@ public class DbgManagerImpl implements DbgManager { * @return retval handling/break status */ protected DebugStatus processThreadSelected(DbgThreadSelectedEvent evt, Void v) { + if (evt.getState() == DbgState.RUNNING) { + currentThread = evt.getThread(); + currentThread.setState(evt.getState(), evt.getCause(), evt.getReason()); + return statusMap.get(evt.getClass()); + } DebugThreadId eventId = updateState(); currentThread = evt.getThread(); @@ -1627,6 +1582,10 @@ public class DbgManagerImpl implements DbgManager { return (DbgProcessImpl) (currentProcess != null ? currentProcess : eventProcess); } + public void setCurrentProcess(DbgProcessImpl process) { + currentProcess = process; + } + public DbgSessionImpl getCurrentSession() { return (DbgSessionImpl) (currentSession != null ? currentSession : eventSession); } @@ -1650,7 +1609,7 @@ public class DbgManagerImpl implements DbgManager { } public CompletableFuture setActiveThread(DbgThread thread) { - if (thread == null) { + if (thread == null || thread.getTid().equals(currentThread.getTid())) { return CompletableFuture.completedFuture(null); } currentThread = thread; @@ -1659,7 +1618,7 @@ public class DbgManagerImpl implements DbgManager { } public CompletableFuture setActiveProcess(DbgProcess process) { - if (process == null) { + if (process == null || process.getPid().equals(currentProcess.getPid())) { return CompletableFuture.completedFuture(null); } currentProcess = process; @@ -1799,12 +1758,7 @@ public class DbgManagerImpl implements DbgManager { DebugSystemObjects so = getSystemObjects(); DebugProcessId id = so.getProcessIdByHandle(info.handle); if (kernelMode) { -// try { -// return (DbgProcessImpl) execute(new DbgSetCurrentState(this)).get().getProcess(); -// } catch (Exception e) { -// e.printStackTrace(); -// return null; -// } + // Unnecessary? Are these events transmitted in kernel-mode? return null; } else { int pid = so.getCurrentProcessSystemId(); @@ -1816,12 +1770,7 @@ public class DbgManagerImpl implements DbgManager { DebugSystemObjects so = getSystemObjects(); DebugThreadId id = so.getThreadIdByHandle(info.handle); if (kernelMode) { -// try { -// return (DbgThreadImpl) execute(new DbgSetCurrentState(this)).get(); -// } catch (Exception e) { -// e.printStackTrace(); -// return null; -// } + // Unnecessary? Are these events transmitted in kernel-mode? return null; } else { int pid = so.getCurrentThreadSystemId(); @@ -1833,10 +1782,32 @@ public class DbgManagerImpl implements DbgManager { DebugSystemObjects so = getSystemObjects(); currentSession = eventSession = getSessionComputeIfAbsent(esid, true); if (kernelMode) { - execute(new DbgSetCurrentState(this)).thenAccept(thread -> { - currentThread = eventThread = thread; - currentProcess = eventProcess = thread.getProcess(); - }); + long poffset = so.getCurrentProcessDataOffset(); + currentProcess = eventProcess = getProcessComputeIfAbsent(new DebugProcessId(poffset), -1, true); + if (currentProcess.getPid() < 0) { + 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); + if (mirror != null) { + mirror.setOffset(currentProcess.getOffset()); + getEventListeners().fire.processSelected(eventProcess, Causes.UNCLAIMED); + } + }); + } + long toffset = so.getCurrentThreadDataOffset(); + currentThread = eventThread = getThreadComputeIfAbsent(new DebugThreadId(toffset), (DbgProcessImpl) eventProcess, -1, false); + if (currentThread.getTid() < 0) { + 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); + if (mirror != null) { + mirror.setOffset(currentThread.getOffset()); + getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED); + } + }); + } } else { currentProcess = eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true); 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 83de1257a0..cf8233fa09 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 @@ -383,4 +383,8 @@ public class DbgProcessImpl implements DbgProcess { this.offset = offset; } + public void setPid(Long pid) { + this.pid = pid; + } + } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java index 1635f38cdd..ba47864e13 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgThreadImpl.java @@ -294,4 +294,8 @@ public class DbgThreadImpl implements DbgThread { this.offset = offset; } + public void setTid(Long tid) { + this.tid = tid; + } + } 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 203ef0b661..90ad99adb4 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,10 +18,22 @@ package agent.dbgeng.model.iface2; import java.util.concurrent.CompletableFuture; import agent.dbgeng.dbgeng.DebugProcessId; -import agent.dbgeng.dbgeng.DebugSystemObjects; -import agent.dbgeng.manager.*; +import agent.dbgeng.manager.DbgEventsListenerAdapter; +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.*; +import agent.dbgeng.model.iface1.DbgModelSelectableObject; +import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned; +import agent.dbgeng.model.iface1.DbgModelTargetAttachable; +import agent.dbgeng.model.iface1.DbgModelTargetAttacher; +import agent.dbgeng.model.iface1.DbgModelTargetDeletable; +import agent.dbgeng.model.iface1.DbgModelTargetDetachable; +import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; +import agent.dbgeng.model.iface1.DbgModelTargetInterruptible; +import agent.dbgeng.model.iface1.DbgModelTargetKillable; +import agent.dbgeng.model.iface1.DbgModelTargetResumable; +import agent.dbgeng.model.iface1.DbgModelTargetSteppable; import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetProcess; import ghidra.dbg.util.PathUtils; @@ -59,7 +71,10 @@ public interface DbgModelTargetProcess extends // public default DbgProcess getProcess(boolean fire) { DbgManagerImpl manager = getManager(); try { - return manager.getProcessComputeIfAbsent(getName(), fire); + String index = PathUtils.parseIndex(getName()); + Long pid = Long.decode(index); + DebugProcessId id = new DebugProcessId(pid); + return manager.getProcessComputeIfAbsent(id, pid, fire); } catch (IllegalArgumentException e) { return manager.getCurrentProcess(); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetThread.java index 4331e899ce..33105b982a 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 @@ -17,11 +17,18 @@ package agent.dbgeng.model.iface2; import java.util.concurrent.CompletableFuture; -import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.dbgeng.DebugThreadId; -import agent.dbgeng.manager.*; -import agent.dbgeng.manager.impl.*; -import agent.dbgeng.model.iface1.*; +import agent.dbgeng.manager.DbgEventsListenerAdapter; +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.impl.DbgThreadImpl; +import agent.dbgeng.model.iface1.DbgModelSelectableObject; +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.util.PathUtils; @@ -45,7 +52,10 @@ public interface DbgModelTargetThread extends // try { DbgModelTargetProcess parentProcess = getParentProcess(); DbgProcessImpl process = parentProcess == null ? null : (DbgProcessImpl) parentProcess.getProcess(); - DbgThreadImpl thread = manager.getThreadComputeIfAbsent(getName(), process, fire); + String index = PathUtils.parseIndex(getName()); + Long tid = Long.decode(index); + DebugThreadId id = new DebugThreadId(tid); + DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, fire); return thread; } catch (IllegalArgumentException e) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java index 37eb55f78e..cde26e90cb 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/dbgmodel/main/ModelObject.java @@ -113,12 +113,15 @@ public interface ModelObject extends UnknownEx { void setIndexer(ModelObject indexer); List getElements(); + ModelObject getElement(String key); ModelObject getChild(DataModelManager1 manager, VARIANT v); Map getKeyValueMap(); + ModelObject getKeyValueByEnum(String key); Map getRawValueMap(); + ModelObject getRawValueByEnum(String key); Object getValue(); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java index fb0e06ade9..257789ae97 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/bridge/HDMAUtil.java @@ -130,11 +130,8 @@ public class HDMAUtil { public ModelObject getTerminalModelObject(List path) { //System.err.println(path); ModelObject target = getRootNamespace(); - boolean found; for (String str : path) { - //System.err.println(":" + str); String indexStr = null; - found = false; if (str.endsWith(")")) { target = evaluatePredicate(target, str); if (target.getKind().equals(ModelObjectKind.OBJECT_ERROR)) { @@ -145,30 +142,28 @@ public class HDMAUtil { indexStr = str.substring(str.indexOf("[") + 1, str.indexOf("]")); str = str.substring(0, str.indexOf("[")); } - Map keyMap = target.getKeyValueMap(); - if (keyMap.containsKey(str)) { - target = keyMap.get(str); - found = true; - } - else { - Map rawMap = target.getRawValueMap(); - if (rawMap.containsKey(str)) { - target = rawMap.get(str); - found = true; + if (!str.equals("")) { + ModelObject keyValue = target.getKeyValueByEnum(str); + if (keyValue != null) { + target = keyValue; + continue; } - } - if (indexStr != null) { - List children = target.getElements(); - for (ModelObject child : children) { - if (indexStr.equals(child.getSearchKey())) { - target = child; - found = true; + else { + ModelObject rawValue = target.getRawValueByEnum(str); + if (rawValue != null) { + target = rawValue; + continue; } } } - if (found == false) { - return null; + if (indexStr != null) { + ModelObject element = target.getElement(indexStr); + if (element != null) { + target = element; + continue; + } } + return null; } return target; } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java index c9ee3ea870..acf74189cb 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/impl/dbgmodel/main/ModelObjectImpl.java @@ -723,6 +723,39 @@ public class ModelObjectImpl implements ModelObjectInternal { return list; } + @Override + public ModelObject getElement(String key) { + REFIID ref = new REFIID(IIterableConcept.IID_IITERABLE_CONCEPT); + IterableConcept concept = (IterableConcept) this.getConcept(ref); + if (concept == null) { + return null; + } + + ModelIterator iterator = concept.getIterator(this); + //long dim = concept.getDefaultIndexDimensionality(this); + if (iterator != null) { + ModelObject next; + int i = 0; + while ((next = iterator.getNext(1)) != null) { + ModelObject index = iterator.getIndexers(); + if (index != null) { + next.setIndexer(index); + if (next.getSearchKey().equals(key)) { + return next; + } + } + else { + next.setSearchKey(Integer.toHexString(i)); + if (Integer.toHexString(i).equals(key)) { + return next; + } + } + i++; + } + } + return null; + } + @Override public ModelObject getChild(DataModelManager1 manager, VARIANT v) { REFIID ref = new REFIID(IIndexableConcept.IID_IINDEXABLE_CONCEPT); @@ -820,6 +853,22 @@ public class ModelObjectImpl implements ModelObjectInternal { return map; } + @Override + public synchronized ModelObject getKeyValueByEnum(String key) { + String kstr; + KeyEnumerator enumerator = this.enumerateKeys(); + while ((kstr = enumerator.getNext()) != null) { + if (kstr.equals(key)) { + ModelObject value = this.getKeyValue(kstr); + if (value != null) { + value.setSearchKey(kstr); + return value; + } + } + } + return null; + } + @Override public synchronized Map getRawValueMap() { TreeMap map = new TreeMap(); @@ -863,6 +912,43 @@ public class ModelObjectImpl implements ModelObjectInternal { return map; } + @Override + public synchronized ModelObject getRawValueByEnum(String key) { + TypeKind typeKind = getTypeKind(); + if (typeKind == null) { + return null; + } + SymbolKind kind = null; + switch (typeKind) { + case TYPE_UDT: + kind = SymbolKind.SYMBOL_FIELD; + break; + case TYPE_POINTER: + kind = SymbolKind.SYMBOL_BASE_CLASS; + try { + ModelObject dereference = this.dereference(); + return dereference.getRawValueByEnum(key); + } + catch (Exception e) { + kind = null; + break; + } + case TYPE_INTRINSIC: + case TYPE_ARRAY: + break; + default: + System.err.println(this.getSearchKey() + ":" + typeKind); + break; + } String kstr; + RawEnumerator enumerator = this.enumerateRawValues(kind.ordinal(), 0); + while ((kstr = enumerator.getNext()) != null) { + ModelObject value = enumerator.getValue(); + value.setSearchKey(kstr); + return value; + } + return null; + } + @Override public TypeKind getTypeKind() { ModelObjectKind modelKind = getKind(); @@ -909,14 +995,14 @@ public class ModelObjectImpl implements ModelObjectInternal { if (key == null) { throw new RuntimeException("null key for " + this); } - Map map = getKeyValueMap(); - if (map.containsKey("BaseAddress")) { - String valueString = map.get("BaseAddress").getValueString(); - return valueString; + ModelObject keyValue = getKeyValueByEnum("BaseAddress"); + if (keyValue != null) { + return keyValue.getValueString(); } - if (map.containsKey("UniqueID") && map.containsKey("Id")) { - String valueString = map.get("Id").getValueString(); - return valueString; + keyValue = getKeyValueByEnum("Id"); + ModelObject keyValue2 = getKeyValueByEnum("UniqueID"); + if (keyValue != null && keyValue2 != null) { + return keyValue.getValueString(); } return key; } diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java index 5c7a329935..3c5b9d8e5d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DbgModel2TargetObjectImpl.java @@ -15,8 +15,14 @@ */ package agent.dbgmodel.model.impl; -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.Map.Entry; +import java.util.Objects; +import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -24,18 +30,47 @@ import agent.dbgeng.manager.*; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.iface1.DbgModelSelectableObject; -import agent.dbgeng.model.iface2.*; -import agent.dbgeng.model.impl.*; +import agent.dbgeng.model.iface2.DbgModelTargetBreakpointSpec; +import agent.dbgeng.model.iface2.DbgModelTargetDebugContainer; +import agent.dbgeng.model.iface2.DbgModelTargetEventContainer; +import agent.dbgeng.model.iface2.DbgModelTargetExceptionContainer; +import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer; +import agent.dbgeng.model.iface2.DbgModelTargetModule; +import agent.dbgeng.model.iface2.DbgModelTargetObject; +import agent.dbgeng.model.iface2.DbgModelTargetProcess; +import agent.dbgeng.model.iface2.DbgModelTargetSession; +import agent.dbgeng.model.iface2.DbgModelTargetStackFrame; +import agent.dbgeng.model.iface2.DbgModelTargetTTD; +import agent.dbgeng.model.iface2.DbgModelTargetThread; +import agent.dbgeng.model.impl.DbgModelTargetEventContainerImpl; +import agent.dbgeng.model.impl.DbgModelTargetExceptionContainerImpl; +import agent.dbgeng.model.impl.DbgModelTargetMemoryContainerImpl; +import agent.dbgeng.model.impl.DbgModelTargetProcessImpl; +import agent.dbgeng.model.impl.DbgModelTargetThreadImpl; import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.ModelObjectKind; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.TypeKind; import agent.dbgmodel.manager.DbgManager2Impl; import ghidra.async.AsyncUtils; import ghidra.dbg.agent.DefaultTargetObject; -import ghidra.dbg.target.*; +import ghidra.dbg.target.TargetAccessConditioned; +import ghidra.dbg.target.TargetAttacher; +import ghidra.dbg.target.TargetBreakpointSpec; import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; +import ghidra.dbg.target.TargetBreakpointSpecContainer; import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet; +import ghidra.dbg.target.TargetEnvironment; +import ghidra.dbg.target.TargetExecutionStateful; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; +import ghidra.dbg.target.TargetInterpreter; +import ghidra.dbg.target.TargetModule; +import ghidra.dbg.target.TargetObject; +import ghidra.dbg.target.TargetProcess; +import ghidra.dbg.target.TargetRegister; +import ghidra.dbg.target.TargetRegisterBank; +import ghidra.dbg.target.TargetStackFrame; +import ghidra.dbg.target.TargetSteppable; +import ghidra.dbg.target.TargetThread; import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; @@ -250,11 +285,6 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject { - if (obj instanceof DbgModelSelectableObject) { - setFocus((DbgModelSelectableObject) obj); - } - }).exceptionally(ex -> { - Msg.error("Could not set focus on selected object: " + PathUtils.toString(objPath), ex); - return null; - }); - */ } @Override @@ -190,6 +216,21 @@ 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(true); + } + } + @Override public void threadCreated(DbgThread thread, DbgCause cause) { getObject(thread).thenAccept(obj -> { @@ -211,6 +252,21 @@ 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(true); + } + } + @Override public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> { @@ -534,6 +590,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot DbgProcess process = thread.getProcess(); tkey = PathUtils.makeKey("0x" + Long.toHexString(thread.getTid())); pkey = PathUtils.makeKey("0x" + Long.toHexString(process.getPid())); + if (getManager().isKernelMode()) { + if (tkey.equals("[0x0]")) { + // Weird, but necessary... + pkey = "[0x0]"; + } + } } if (obj instanceof DbgStackFrame) { DbgStackFrame frame = (DbgStackFrame) obj; diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java index 77f2fef03d..478c351000 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel/src/main/java/agent/dbgmodel/model/impl/DelegateDbgModel2TargetObject.java @@ -26,10 +26,13 @@ import java.util.Map; import agent.dbgeng.manager.DbgCause; import agent.dbgeng.manager.DbgEventsListener; +import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.DbgReason; import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgStateListener; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; +import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned; import agent.dbgeng.model.iface1.DbgModelTargetBptHelper; import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; @@ -105,92 +108,87 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } } - protected static Class lookupWrapperType(String type, - String parentName) { + protected static Class lookupWrapperType(String type, String parentName) { switch (type) { - case "Available": - return DbgModelTargetAvailableContainer.class; - case "Sessions": - return DbgModelTargetSessionContainer.class; - case "Processes": - return DbgModelTargetProcessContainer.class; - case "Threads": - return DbgModelTargetThreadContainer.class; - case "Modules": - return DbgModelTargetModuleContainer.class; - case "Frames": - return DbgModelTargetStack.class; - case "Registers": - return DbgModelTargetRegisterContainer.class; - case "Attributes": - return DbgModelTargetSessionAttributes.class; - case "Breakpoints": - return DbgModelTargetBreakpointContainer.class; - case "cursession": - return DbgModelTargetSession.class; - case "curprocess": - return DbgModelTargetProcess.class; - case "curthread": - return DbgModelTargetThread.class; - case "curframe": - return DbgModelTargetStackFrame.class; - case "User": - return DbgModelTargetRegisterBank.class; - case "TTD": - return DbgModelTargetTTD.class; - case "Debug": - return DbgModelTargetDebugContainer.class; + case "Available": + return DbgModelTargetAvailableContainer.class; + case "Sessions": + return DbgModelTargetSessionContainer.class; + case "Processes": + return DbgModelTargetProcessContainer.class; + case "Threads": + return DbgModelTargetThreadContainer.class; + case "Modules": + return DbgModelTargetModuleContainer.class; + case "Frames": + return DbgModelTargetStack.class; + case "Registers": + return DbgModelTargetRegisterContainer.class; + case "Attributes": + return DbgModelTargetSessionAttributes.class; + case "Breakpoints": + return DbgModelTargetBreakpointContainer.class; + case "cursession": + return DbgModelTargetSession.class; + case "curprocess": + return DbgModelTargetProcess.class; + case "curthread": + return DbgModelTargetThread.class; + case "curframe": + return DbgModelTargetStackFrame.class; + case "User": + return DbgModelTargetRegisterBank.class; + case "TTD": + return DbgModelTargetTTD.class; + case "Debug": + return DbgModelTargetDebugContainer.class; } if (parentName != null) { switch (parentName) { - case "Available": - return DbgModelTargetAvailable.class; - case "Sessions": - return DbgModelTargetSession.class; - case "Processes": - return DbgModelTargetProcess.class; - case "Threads": - return DbgModelTargetThread.class; - case "Modules": - return DbgModelTargetModule.class; - case "Frames": - return DbgModelTargetStackFrame.class; - case "Breakpoints": - return DbgModelTargetBreakpointSpec.class; - //case "Registers": - // return DbgModelTargetRegisterBank.class; - case "FloatingPoint": - case "Kernel": - case "SIMD": - case "VFP": - case "User": - return DbgModelTargetRegister.class; + case "Available": + return DbgModelTargetAvailable.class; + case "Sessions": + return DbgModelTargetSession.class; + case "Processes": + return DbgModelTargetProcess.class; + case "Threads": + return DbgModelTargetThread.class; + case "Modules": + return DbgModelTargetModule.class; + case "Frames": + return DbgModelTargetStackFrame.class; + case "Breakpoints": + return DbgModelTargetBreakpointSpec.class; + // case "Registers": + // return DbgModelTargetRegisterBank.class; + case "FloatingPoint": + case "Kernel": + case "SIMD": + case "VFP": + case "User": + return DbgModelTargetRegister.class; } } return null; } - public static DbgModelTargetObject makeProxy(DbgModel2Impl model, DbgModelTargetObject parent, - String key, ModelObject object) { + public static DbgModelTargetObject makeProxy(DbgModel2Impl model, DbgModelTargetObject parent, String key, + ModelObject object) { List> mixins = new ArrayList<>(); String lkey = key; String pname = parent.getName(); /* - if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD) || lkey.contains(")")) { - mixins.add(DbgModelTargetMethod.class); - // NB: We're passing the parent's mixin model to the method on the assumption - // the init methods will need to know that the method's children have various - // properties. - lkey = pname; - pname = ""; - } - */ + * if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD) || + * lkey.contains(")")) { mixins.add(DbgModelTargetMethod.class); // NB: We're + * passing the parent's mixin model to the method on the assumption // the init + * methods will need to know that the method's children have various // + * properties. lkey = pname; pname = ""; } + */ if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD)) { mixins.add(DbgModelTargetMethod.class); - } - else { + } else { Class mixin = lookupWrapperType(lkey, pname); if (mixin != null) { mixins.add(mixin); @@ -201,30 +199,32 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp protected static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - // NOTE: The Cleanable stuff is the replacement for overriding Object.finalize(), which + // NOTE: The Cleanable stuff is the replacement for overriding + // Object.finalize(), which // is now deprecated. protected final ProxyState state; protected final Cleanable cleanable; private boolean breakpointEnabled; - private final ListenerSet breakpointActions = - new ListenerSet<>(TargetBreakpointAction.class) { - // Use strong references on actions - protected Map createMap() { - return Collections.synchronizedMap(new LinkedHashMap<>()); - }; + private final ListenerSet breakpointActions = new ListenerSet<>( + TargetBreakpointAction.class) { + // Use strong references on actions + protected Map createMap() { + return Collections.synchronizedMap(new LinkedHashMap<>()); }; + }; - // Extending DefaultTargetObject may spare you from listeners, elements, and attributes - //protected final ListenerSet listeners = - // new ListenerSet<>(TargetObjectListener.class); + // Extending DefaultTargetObject may spare you from listeners, elements, and + // attributes + // protected final ListenerSet listeners = + // new ListenerSet<>(TargetObjectListener.class); // any other fields you need to support your impl - public DelegateDbgModel2TargetObject(DbgModel2Impl model, DbgModelTargetObject parent, - String key, ModelObject modelObject, List> mixins) { + public DelegateDbgModel2TargetObject(DbgModel2Impl model, DbgModelTargetObject parent, String key, + ModelObject modelObject, List> mixins) { super(model, mixins, model, parent.getProxy(), key, getHintForObject(modelObject)); - //System.err.println(this); + // System.err.println(this); this.state = new ProxyState(model, modelObject); this.cleanable = CLEANER.register(this, state); @@ -244,8 +244,8 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp if (mixin != null) { mixins.add(mixin); } - DelegateDbgModel2TargetObject delegate = - new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject, mixins); + DelegateDbgModel2TargetObject delegate = new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject, + mixins); return delegate; } @@ -272,43 +272,45 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp protected void checkExited(DbgState state, DbgCause cause) { TargetExecutionState exec = TargetExecutionState.INACTIVE; switch (state) { - case NOT_STARTED: { - exec = TargetExecutionState.INACTIVE; - break; - } - case STARTING: { - exec = TargetExecutionState.ALIVE; - break; - } - case RUNNING: { - exec = TargetExecutionState.RUNNING; - resetModified(); - onRunning(); - break; - } - case STOPPED: { - exec = TargetExecutionState.STOPPED; - onStopped(); - break; - } - case EXIT: { - exec = TargetExecutionState.TERMINATED; - onExit(); - break; - } - case SESSION_EXIT: { - getModel().close(); - return; - } + case NOT_STARTED: { + exec = TargetExecutionState.INACTIVE; + break; + } + case STARTING: { + exec = TargetExecutionState.ALIVE; + break; + } + case RUNNING: { + exec = TargetExecutionState.RUNNING; + resetModified(); + onRunning(); + break; + } + case STOPPED: { + exec = TargetExecutionState.STOPPED; + onStopped(); + break; + } + case EXIT: { + exec = TargetExecutionState.TERMINATED; + onExit(); + break; + } + case SESSION_EXIT: { + getModel().close(); + return; + } } if (proxy instanceof TargetExecutionStateful) { if (proxy instanceof DbgModelTargetSession) { if (state != DbgState.EXIT) { setExecutionState(exec, "Refreshed"); } - } - else { - setExecutionState(exec, "Refreshed"); + } else { + TargetExecutionState previous = this.getExecutionState(); + if (!previous.equals(TargetExecutionState.INACTIVE)) { + setExecutionState(exec, "Refreshed"); + } } } } @@ -321,7 +323,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp proxy instanceof DbgModelTargetStackFrame || // proxy instanceof DbgModelTargetStack || // proxy instanceof DbgModelTargetTTD) { - //listeners.fire.invalidateCacheRequested(proxy); + // listeners.fire.invalidateCacheRequested(proxy); return; } } @@ -330,30 +332,37 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) { return; } + DbgManagerImpl manager = getModel().getManager(); + boolean kernelMode = manager.isKernelMode(); if (proxy instanceof DbgModelTargetSession) { DbgModelTargetSession targetSession = (DbgModelTargetSession) proxy; targetSession.getSession(false); } if (proxy instanceof DbgModelTargetProcess) { DbgModelTargetProcess targetProcess = (DbgModelTargetProcess) proxy; - targetProcess.getProcess(false); + DbgProcess process = targetProcess.getProcess(false); + if (kernelMode) { + Long offset = process.getOffset(); + if (offset == null) { + return; + } + } } if (proxy instanceof DbgModelTargetThread) { DbgModelTargetThread targetThread = (DbgModelTargetThread) proxy; - targetThread.getThread(false); - } - - boolean kernelMode = getModel().getManager().isKernelMode(); - if (kernelMode) { - if (proxy instanceof DbgModelTargetProcess || // - proxy instanceof DbgModelTargetThread) { - return; + DbgThread thread = targetThread.getThread(false); + if (kernelMode) { + Long offset = thread.getOffset(); + if (offset == null) { + return; + } } } + if (getModel().isSuppressDescent()) { return; } - + if (proxy instanceof DbgModelTargetSession || // proxy instanceof DbgModelTargetProcess || // proxy instanceof DbgModelTargetThread) { @@ -362,8 +371,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } if (proxy instanceof DbgModelTargetRegisterContainer || // proxy instanceof DbgModelTargetRegisterBank || // - proxy.getName().equals("Stack") || - proxy.getName().equals("Debug")) { + proxy.getName().equals("Stack") || proxy.getName().equals("Debug")) { requestAttributes(false); return; } @@ -405,7 +413,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } if (proxy instanceof TargetAccessConditioned) { changeAttributes(List.of(), List.of(), Map.of( // - TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME, accessible // + TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME, accessible // ), "Accessibility changed"); } } @@ -455,21 +463,18 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } if (proxy instanceof TargetThread) { List delegates = new ArrayList<>(); - TargetObject stack = - (TargetObject) getCachedAttribute("Stack"); + TargetObject stack = (TargetObject) getCachedAttribute("Stack"); if (stack != null) { - DbgModelTargetStack frames = - (DbgModelTargetStack) stack.getCachedAttribute("Frames"); + DbgModelTargetStack frames = (DbgModelTargetStack) stack.getCachedAttribute("Frames"); delegates.add((DelegateDbgModel2TargetObject) frames.getDelegate()); } - DbgModelTargetRegisterContainer container = - (DbgModelTargetRegisterContainer) getCachedAttribute("Registers"); + DbgModelTargetRegisterContainer container = (DbgModelTargetRegisterContainer) getCachedAttribute( + "Registers"); if (container == null) { return; } delegates.add((DelegateDbgModel2TargetObject) container.getDelegate()); - DbgModelTargetRegisterBank bank = - (DbgModelTargetRegisterBank) container.getCachedAttribute("User"); + DbgModelTargetRegisterBank bank = (DbgModelTargetRegisterBank) container.getCachedAttribute("User"); if (bank == null) { return; } @@ -486,7 +491,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp } if (proxy instanceof TargetRegisterBank) { TargetRegisterBank bank = (TargetRegisterBank) proxy; - //requestElements(false); + // requestElements(false); requestAttributes(false).thenAccept(__ -> { bank.readRegistersNamed(getCachedAttributes().keySet()); }); @@ -497,8 +502,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp for (TargetObject obj : getCachedElements().values()) { if (obj instanceof TargetStackFrame) { DbgModelTargetObject frame = (DbgModelTargetObject) obj; - DelegateDbgModel2TargetObject delegate = - (DelegateDbgModel2TargetObject) frame.getDelegate(); + DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) frame.getDelegate(); delegate.threadStateChangedSpecific(state, reason); } } diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetThread.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetThread.java index da767ef6f8..834d9f8c05 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetThread.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetThread.java @@ -31,7 +31,7 @@ public interface TargetThread extends TargetObject { String TID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "tid"; @TargetAttributeType(name = TID_ATTRIBUTE_NAME, hidden = true) - public default Integer getTid() { - return getTypedAttributeNowByName(TID_ATTRIBUTE_NAME, Integer.class, null); + public default Long getTid() { + return getTypedAttributeNowByName(TID_ATTRIBUTE_NAME, Long.class, null); } }