GP-1768A: limits on initial loads; fix for possible id/pid/tid mismatch

GP-1768A: check for symbols; misc fixes

GP-1768A: suppress descent for kernel mode

GP-1768A: undoing a few things

GP-1768A: undoing a few things again

GP-1768A: added data offset methods intending to replace pids/tids for kernel lookups

GP-1768A: resorting to CLI for state

GP-1768A: resorting to CLI for state

GP-1768A: add ability to set implicit thread/process

GP-1768A: cleanup

GP-1768A: default to ALIVE ofr kernel

GP-1768A: better setActive implementations

GP-1768B: new faster utility methods for model

GP-1768B: one more use

GP-1768A: NPE fix

GP-1768: faster SetCurrentState; minimize calls

GP-1768B: better autorecord

GP-1768B: reverting a few things

GP-1768C: first pass at offset/pid resolution

GP-1768C: paired proc/thread logic in place

GP-1768C: make only selected items ACTIVE; update only !INACTIVE

GP-1768C: activate process/thread on event
This commit is contained in:
d-millar
2023-02-24 12:45:30 -05:00
parent b4de95f4f5
commit 6b5d7a6ad6
18 changed files with 684 additions and 288 deletions
@@ -236,4 +236,9 @@ public interface DbgProcess extends DbgMemoryOperations {
*/ */
CompletableFuture<Void> remove(); CompletableFuture<Void> remove();
/**
* Get the address of the associated process structure
*/
Long getOffset();
} }
@@ -158,9 +158,12 @@ public interface DbgThread
/** /**
* Get the effective architecture for the executing thread * Get the effective architecture for the executing thread
*
* @return a future that completes when GDB has executed the command
*/ */
Machine getExecutingProcessorType(); Machine getExecutingProcessorType();
} /**
* Get the address of the associated thread structure
*/
Long getOffset();
}
@@ -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<DbgProcess> {
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");
}
}
}
}
@@ -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<DbgThread> {
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");
}
}
}
@@ -93,10 +93,9 @@ public class DbgSetActiveProcessCommand extends AbstractDbgCommand<Void> {
offset = process.getOffset(); offset = process.getOffset();
if (offset == null || offset == 0L) { if (offset == null || offset == 0L) {
DebugControl control = manager.getControl(); DebugControl control = manager.getControl();
control.execute("!process "+Long.toHexString(process.getPid())); control.execute("!process "+Long.toHexString(process.getPid())+" 0");
} }
} } else {
else {
so.setCurrentProcessId(id); so.setCurrentProcessId(id);
DebugProcessId currentProcessId = so.getCurrentProcessId(); DebugProcessId currentProcessId = so.getCurrentProcessId();
if (id.id != currentProcessId.id) { if (id.id != currentProcessId.id) {
@@ -91,12 +91,11 @@ public class DbgSetActiveThreadCommand extends AbstractDbgCommand<Void> {
if (id != null) { if (id != null) {
if (!manager.isKernelMode()) { if (!manager.isKernelMode()) {
manager.getSystemObjects().setCurrentThreadId(id); manager.getSystemObjects().setCurrentThreadId(id);
} } else {
else {
offset = thread.getOffset(); offset = thread.getOffset();
if (offset == null || offset == 0L) { if (offset == null || offset == 0L) {
DebugControl control = manager.getControl(); DebugControl control = manager.getControl();
control.execute("!thread -t "+Long.toHexString(thread.getTid())); control.execute("!thread -t "+Long.toHexString(thread.getTid())+" 0");
} }
} }
if (frameId != null) { if (frameId != null) {
@@ -103,10 +103,11 @@ import agent.dbgeng.manager.cmd.DbgRemoveProcessCommand;
import agent.dbgeng.manager.cmd.DbgRemoveSessionCommand; import agent.dbgeng.manager.cmd.DbgRemoveSessionCommand;
import agent.dbgeng.manager.cmd.DbgRequestActivationCommand; import agent.dbgeng.manager.cmd.DbgRequestActivationCommand;
import agent.dbgeng.manager.cmd.DbgRequestFocusCommand; 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.DbgSetActiveProcessCommand;
import agent.dbgeng.manager.cmd.DbgSetActiveSessionCommand; import agent.dbgeng.manager.cmd.DbgSetActiveSessionCommand;
import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand; import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand;
import agent.dbgeng.manager.cmd.DbgSetCurrentState;
import agent.dbgeng.manager.evt.AbstractDbgEvent; import agent.dbgeng.manager.evt.AbstractDbgEvent;
import agent.dbgeng.manager.evt.DbgBreakpointCreatedEvent; import agent.dbgeng.manager.evt.DbgBreakpointCreatedEvent;
import agent.dbgeng.manager.evt.DbgBreakpointDeletedEvent; import agent.dbgeng.manager.evt.DbgBreakpointDeletedEvent;
@@ -251,9 +252,7 @@ public class DbgManagerImpl implements DbgManager {
synchronized (threads) { synchronized (threads) {
if (threads.containsKey(id)) { if (threads.containsKey(id)) {
DbgThreadImpl existingThread = threads.get(id); DbgThreadImpl existingThread = threads.get(id);
if (existingThread.getTid() == tid) { return existingThread;
return existingThread;
}
} }
DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid); DbgThreadImpl thread = new DbgThreadImpl(this, process, id, tid);
thread.add(); 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) { public DbgProcessImpl getProcessComputeIfAbsent(DebugProcessId id, long pid, boolean fire) {
synchronized (processes) { synchronized (processes) {
if (processes.containsKey(id)) { if (processes.containsKey(id)) {
DbgProcessImpl existingProc = processes.get(id); DbgProcessImpl existingProc = processes.get(id);
if (existingProc.getPid() == pid) { return existingProc;
return existingProc;
}
} }
DbgProcessImpl process = new DbgProcessImpl(this, id, pid); DbgProcessImpl process = new DbgProcessImpl(this, id, pid);
process.add(); process.add();
@@ -598,7 +584,7 @@ public class DbgManagerImpl implements DbgManager {
} }
return pcmd; return pcmd;
} }
private <T> void addCommand(DbgCommand<? extends T> cmd, DbgPendingCommand<T> pcmd) { private <T> void addCommand(DbgCommand<? extends T> cmd, DbgPendingCommand<T> pcmd) {
synchronized (this) { synchronized (this) {
if (!cmd.validInState(state.get())) { if (!cmd.validInState(state.get())) {
@@ -610,42 +596,6 @@ public class DbgManagerImpl implements DbgManager {
processEvent(new DbgCommandDoneEvent(cmd)); processEvent(new DbgCommandDoneEvent(cmd));
} }
/*@Override
public <T> DbgPendingCommand<T> execute1(DbgCommand<? extends T> cmd) {
assert cmd != null;
checkStarted();
DbgPendingCommand<T> 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) { public DebugStatus processEvent(DbgEvent<?> evt) {
if (state.get() == DbgState.STARTING) { if (state.get() == DbgState.STARTING) {
state.set(DbgState.STOPPED, Causes.UNCLAIMED); state.set(DbgState.STOPPED, Causes.UNCLAIMED);
@@ -777,7 +727,7 @@ public class DbgManagerImpl implements DbgManager {
if (eventThread != null) { if (eventThread != null) {
((DbgThreadImpl) eventThread).setInfo(lastEventInformation); ((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 * @return retval handling/break status
*/ */
protected DebugStatus processThreadSelected(DbgThreadSelectedEvent evt, Void v) { 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(); DebugThreadId eventId = updateState();
currentThread = evt.getThread(); currentThread = evt.getThread();
@@ -1627,6 +1582,10 @@ public class DbgManagerImpl implements DbgManager {
return (DbgProcessImpl) (currentProcess != null ? currentProcess : eventProcess); return (DbgProcessImpl) (currentProcess != null ? currentProcess : eventProcess);
} }
public void setCurrentProcess(DbgProcessImpl process) {
currentProcess = process;
}
public DbgSessionImpl getCurrentSession() { public DbgSessionImpl getCurrentSession() {
return (DbgSessionImpl) (currentSession != null ? currentSession : eventSession); return (DbgSessionImpl) (currentSession != null ? currentSession : eventSession);
} }
@@ -1650,7 +1609,7 @@ public class DbgManagerImpl implements DbgManager {
} }
public CompletableFuture<Void> setActiveThread(DbgThread thread) { public CompletableFuture<Void> setActiveThread(DbgThread thread) {
if (thread == null) { if (thread == null || thread.getTid().equals(currentThread.getTid())) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
currentThread = thread; currentThread = thread;
@@ -1659,7 +1618,7 @@ public class DbgManagerImpl implements DbgManager {
} }
public CompletableFuture<Void> setActiveProcess(DbgProcess process) { public CompletableFuture<Void> setActiveProcess(DbgProcess process) {
if (process == null) { if (process == null || process.getPid().equals(currentProcess.getPid())) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
currentProcess = process; currentProcess = process;
@@ -1799,12 +1758,7 @@ public class DbgManagerImpl implements DbgManager {
DebugSystemObjects so = getSystemObjects(); DebugSystemObjects so = getSystemObjects();
DebugProcessId id = so.getProcessIdByHandle(info.handle); DebugProcessId id = so.getProcessIdByHandle(info.handle);
if (kernelMode) { if (kernelMode) {
// try { // Unnecessary? Are these events transmitted in kernel-mode?
// return (DbgProcessImpl) execute(new DbgSetCurrentState(this)).get().getProcess();
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
return null; return null;
} else { } else {
int pid = so.getCurrentProcessSystemId(); int pid = so.getCurrentProcessSystemId();
@@ -1816,12 +1770,7 @@ public class DbgManagerImpl implements DbgManager {
DebugSystemObjects so = getSystemObjects(); DebugSystemObjects so = getSystemObjects();
DebugThreadId id = so.getThreadIdByHandle(info.handle); DebugThreadId id = so.getThreadIdByHandle(info.handle);
if (kernelMode) { if (kernelMode) {
// try { // Unnecessary? Are these events transmitted in kernel-mode?
// return (DbgThreadImpl) execute(new DbgSetCurrentState(this)).get();
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
return null; return null;
} else { } else {
int pid = so.getCurrentThreadSystemId(); int pid = so.getCurrentThreadSystemId();
@@ -1833,10 +1782,32 @@ public class DbgManagerImpl implements DbgManager {
DebugSystemObjects so = getSystemObjects(); DebugSystemObjects so = getSystemObjects();
currentSession = eventSession = getSessionComputeIfAbsent(esid, true); currentSession = eventSession = getSessionComputeIfAbsent(esid, true);
if (kernelMode) { if (kernelMode) {
execute(new DbgSetCurrentState(this)).thenAccept(thread -> { long poffset = so.getCurrentProcessDataOffset();
currentThread = eventThread = thread; currentProcess = eventProcess = getProcessComputeIfAbsent(new DebugProcessId(poffset), -1, true);
currentProcess = eventProcess = thread.getProcess(); 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 { } else {
currentProcess = currentProcess =
eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true); eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true);
@@ -383,4 +383,8 @@ public class DbgProcessImpl implements DbgProcess {
this.offset = offset; this.offset = offset;
} }
public void setPid(Long pid) {
this.pid = pid;
}
} }
@@ -294,4 +294,8 @@ public class DbgThreadImpl implements DbgThread {
this.offset = offset; this.offset = offset;
} }
public void setTid(Long tid) {
this.tid = tid;
}
} }
@@ -18,10 +18,22 @@ package agent.dbgeng.model.iface2;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugProcessId;
import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.manager.DbgEventsListenerAdapter;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.DbgProcess;
import agent.dbgeng.manager.DbgState;
import agent.dbgeng.manager.DbgThread;
import agent.dbgeng.manager.impl.DbgManagerImpl; 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.TargetAggregate;
import ghidra.dbg.target.TargetProcess; import ghidra.dbg.target.TargetProcess;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
@@ -59,7 +71,10 @@ public interface DbgModelTargetProcess extends //
public default DbgProcess getProcess(boolean fire) { public default DbgProcess getProcess(boolean fire) {
DbgManagerImpl manager = getManager(); DbgManagerImpl manager = getManager();
try { 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) { catch (IllegalArgumentException e) {
return manager.getCurrentProcess(); return manager.getCurrentProcess();
@@ -17,11 +17,18 @@ package agent.dbgeng.model.iface2;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import agent.dbgeng.dbgeng.DebugSystemObjects;
import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.dbgeng.DebugThreadId;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.DbgEventsListenerAdapter;
import agent.dbgeng.manager.impl.*; import agent.dbgeng.manager.DbgReason;
import agent.dbgeng.model.iface1.*; 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 agent.dbgeng.model.impl.DbgModelTargetStackImpl;
import ghidra.dbg.target.*; import ghidra.dbg.target.*;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
@@ -45,7 +52,10 @@ public interface DbgModelTargetThread extends //
try { try {
DbgModelTargetProcess parentProcess = getParentProcess(); DbgModelTargetProcess parentProcess = getParentProcess();
DbgProcessImpl process = parentProcess == null ? null : (DbgProcessImpl) parentProcess.getProcess(); 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; return thread;
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
@@ -113,12 +113,15 @@ public interface ModelObject extends UnknownEx {
void setIndexer(ModelObject indexer); void setIndexer(ModelObject indexer);
List<ModelObject> getElements(); List<ModelObject> getElements();
ModelObject getElement(String key);
ModelObject getChild(DataModelManager1 manager, VARIANT v); ModelObject getChild(DataModelManager1 manager, VARIANT v);
Map<String, ModelObject> getKeyValueMap(); Map<String, ModelObject> getKeyValueMap();
ModelObject getKeyValueByEnum(String key);
Map<String, ModelObject> getRawValueMap(); Map<String, ModelObject> getRawValueMap();
ModelObject getRawValueByEnum(String key);
Object getValue(); Object getValue();
@@ -130,11 +130,8 @@ public class HDMAUtil {
public ModelObject getTerminalModelObject(List<String> path) { public ModelObject getTerminalModelObject(List<String> path) {
//System.err.println(path); //System.err.println(path);
ModelObject target = getRootNamespace(); ModelObject target = getRootNamespace();
boolean found;
for (String str : path) { for (String str : path) {
//System.err.println(":" + str);
String indexStr = null; String indexStr = null;
found = false;
if (str.endsWith(")")) { if (str.endsWith(")")) {
target = evaluatePredicate(target, str); target = evaluatePredicate(target, str);
if (target.getKind().equals(ModelObjectKind.OBJECT_ERROR)) { if (target.getKind().equals(ModelObjectKind.OBJECT_ERROR)) {
@@ -145,30 +142,28 @@ public class HDMAUtil {
indexStr = str.substring(str.indexOf("[") + 1, str.indexOf("]")); indexStr = str.substring(str.indexOf("[") + 1, str.indexOf("]"));
str = str.substring(0, str.indexOf("[")); str = str.substring(0, str.indexOf("["));
} }
Map<String, ModelObject> keyMap = target.getKeyValueMap(); if (!str.equals("")) {
if (keyMap.containsKey(str)) { ModelObject keyValue = target.getKeyValueByEnum(str);
target = keyMap.get(str); if (keyValue != null) {
found = true; target = keyValue;
} continue;
else {
Map<String, ModelObject> rawMap = target.getRawValueMap();
if (rawMap.containsKey(str)) {
target = rawMap.get(str);
found = true;
} }
} else {
if (indexStr != null) { ModelObject rawValue = target.getRawValueByEnum(str);
List<ModelObject> children = target.getElements(); if (rawValue != null) {
for (ModelObject child : children) { target = rawValue;
if (indexStr.equals(child.getSearchKey())) { continue;
target = child;
found = true;
} }
} }
} }
if (found == false) { if (indexStr != null) {
return null; ModelObject element = target.getElement(indexStr);
if (element != null) {
target = element;
continue;
}
} }
return null;
} }
return target; return target;
} }
@@ -723,6 +723,39 @@ public class ModelObjectImpl implements ModelObjectInternal {
return list; 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 @Override
public ModelObject getChild(DataModelManager1 manager, VARIANT v) { public ModelObject getChild(DataModelManager1 manager, VARIANT v) {
REFIID ref = new REFIID(IIndexableConcept.IID_IINDEXABLE_CONCEPT); REFIID ref = new REFIID(IIndexableConcept.IID_IINDEXABLE_CONCEPT);
@@ -820,6 +853,22 @@ public class ModelObjectImpl implements ModelObjectInternal {
return map; 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 @Override
public synchronized Map<String, ModelObject> getRawValueMap() { public synchronized Map<String, ModelObject> getRawValueMap() {
TreeMap<String, ModelObject> map = new TreeMap<String, ModelObject>(); TreeMap<String, ModelObject> map = new TreeMap<String, ModelObject>();
@@ -863,6 +912,43 @@ public class ModelObjectImpl implements ModelObjectInternal {
return map; 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 @Override
public TypeKind getTypeKind() { public TypeKind getTypeKind() {
ModelObjectKind modelKind = getKind(); ModelObjectKind modelKind = getKind();
@@ -909,14 +995,14 @@ public class ModelObjectImpl implements ModelObjectInternal {
if (key == null) { if (key == null) {
throw new RuntimeException("null key for " + this); throw new RuntimeException("null key for " + this);
} }
Map<String, ModelObject> map = getKeyValueMap(); ModelObject keyValue = getKeyValueByEnum("BaseAddress");
if (map.containsKey("BaseAddress")) { if (keyValue != null) {
String valueString = map.get("BaseAddress").getValueString(); return keyValue.getValueString();
return valueString;
} }
if (map.containsKey("UniqueID") && map.containsKey("Id")) { keyValue = getKeyValueByEnum("Id");
String valueString = map.get("Id").getValueString(); ModelObject keyValue2 = getKeyValueByEnum("UniqueID");
return valueString; if (keyValue != null && keyValue2 != null) {
return keyValue.getValueString();
} }
return key; return key;
} }
@@ -15,8 +15,14 @@
*/ */
package agent.dbgmodel.model.impl; 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.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,18 +30,47 @@ import agent.dbgeng.manager.*;
import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.model.AbstractDbgModel; import agent.dbgeng.model.AbstractDbgModel;
import agent.dbgeng.model.iface1.DbgModelSelectableObject; import agent.dbgeng.model.iface1.DbgModelSelectableObject;
import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.iface2.DbgModelTargetBreakpointSpec;
import agent.dbgeng.model.impl.*; 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.dbgmodel.main.ModelObject;
import agent.dbgmodel.jna.dbgmodel.DbgModelNative.ModelObjectKind; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.ModelObjectKind;
import agent.dbgmodel.jna.dbgmodel.DbgModelNative.TypeKind; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.TypeKind;
import agent.dbgmodel.manager.DbgManager2Impl; import agent.dbgmodel.manager.DbgManager2Impl;
import ghidra.async.AsyncUtils; import ghidra.async.AsyncUtils;
import ghidra.dbg.agent.DefaultTargetObject; 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.TargetBreakpointSpec.TargetBreakpointKind;
import ghidra.dbg.target.TargetBreakpointSpecContainer;
import ghidra.dbg.target.TargetBreakpointSpecContainer.TargetBreakpointKindSet; 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.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.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
@@ -250,11 +285,6 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (isValid()) { if (isValid()) {
TargetExecutionStateful stateful = (TargetExecutionStateful) proxy; TargetExecutionStateful stateful = (TargetExecutionStateful) proxy;
TargetExecutionState state = stateful.getExecutionState(); TargetExecutionState state = stateful.getExecutionState();
if (getManager().isKernelMode()) {
if (state.equals(TargetExecutionState.INACTIVE)) {
state = TargetExecutionState.ALIVE;
}
}
attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state); attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state);
} }
} }
@@ -15,24 +15,53 @@
*/ */
package agent.dbgmodel.model.impl; package agent.dbgmodel.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 java.util.concurrent.CompletableFuture;
import agent.dbgeng.dbgeng.*; import agent.dbgeng.dbgeng.DebugModuleInfo;
import agent.dbgeng.manager.*; import agent.dbgeng.dbgeng.DebugProcessId;
import agent.dbgeng.dbgeng.DebugSessionId;
import agent.dbgeng.dbgeng.DebugSystemObjects;
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.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.manager.reason.*; 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.DbgModelSelectableObject; import agent.dbgeng.model.iface1.DbgModelSelectableObject;
import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful;
import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.iface2.DbgModelTargetBreakpointSpec;
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
import agent.dbgeng.model.iface2.DbgModelTargetModule;
import agent.dbgeng.model.iface2.DbgModelTargetObject;
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer;
import agent.dbgeng.model.iface2.DbgModelTargetRoot;
import agent.dbgeng.model.iface2.DbgModelTargetThread;
import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer;
import agent.dbgeng.model.impl.DbgModelTargetConnectorContainerImpl; import agent.dbgeng.model.impl.DbgModelTargetConnectorContainerImpl;
import agent.dbgeng.model.impl.DbgModelTargetProcessImpl; import agent.dbgeng.model.impl.DbgModelTargetProcessImpl;
import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.dbgmodel.main.ModelObject;
import agent.dbgmodel.manager.DbgManager2Impl; import agent.dbgmodel.manager.DbgManager2Impl;
import ghidra.async.AsyncUtils; import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec; import ghidra.async.TypeSpec;
import ghidra.dbg.target.*; import ghidra.dbg.target.TargetEventScope;
import ghidra.dbg.target.TargetExecutionStateful;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; 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.TargetThread;
import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
import ghidra.util.Msg; import ghidra.util.Msg;
@@ -135,11 +164,18 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
@Override @Override
public void processSelected(DbgProcess process, DbgCause cause) { public void processSelected(DbgProcess process, DbgCause cause) {
objectSelected(process); objectSelected(process);
if (getManager().isKernelMode()) {
processActivated(process);
}
} }
@Override @Override
public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) { public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) {
objectSelected(thread); objectSelected(thread);
if (getManager().isKernelMode() && thread != null) {
processActivated(thread.getProcess());
threadActivated(thread);
}
if (frame != null) { if (frame != null) {
objectSelected(frame); objectSelected(frame);
} }
@@ -151,16 +187,6 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
if (obj instanceof DbgModelSelectableObject) { if (obj instanceof DbgModelSelectableObject) {
setFocus((DbgModelSelectableObject) obj); setFocus((DbgModelSelectableObject) obj);
} }
/*
getModel().fetchModelValue(objPath, true).thenAccept(obj -> {
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 @Override
@@ -190,6 +216,21 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
}); });
} }
public void processActivated(DbgProcess proc) {
List<String> 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 @Override
public void threadCreated(DbgThread thread, DbgCause cause) { public void threadCreated(DbgThread thread, DbgCause cause) {
getObject(thread).thenAccept(obj -> { getObject(thread).thenAccept(obj -> {
@@ -211,6 +252,21 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
}); });
} }
public void threadActivated(DbgThread thread) {
List<String> 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 @Override
public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) { public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> { getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> {
@@ -534,6 +590,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
DbgProcess process = thread.getProcess(); DbgProcess process = thread.getProcess();
tkey = PathUtils.makeKey("0x" + Long.toHexString(thread.getTid())); tkey = PathUtils.makeKey("0x" + Long.toHexString(thread.getTid()));
pkey = PathUtils.makeKey("0x" + Long.toHexString(process.getPid())); pkey = PathUtils.makeKey("0x" + Long.toHexString(process.getPid()));
if (getManager().isKernelMode()) {
if (tkey.equals("[0x0]")) {
// Weird, but necessary...
pkey = "[0x0]";
}
}
} }
if (obj instanceof DbgStackFrame) { if (obj instanceof DbgStackFrame) {
DbgStackFrame frame = (DbgStackFrame) obj; DbgStackFrame frame = (DbgStackFrame) obj;
@@ -26,10 +26,13 @@ import java.util.Map;
import agent.dbgeng.manager.DbgCause; import agent.dbgeng.manager.DbgCause;
import agent.dbgeng.manager.DbgEventsListener; import agent.dbgeng.manager.DbgEventsListener;
import agent.dbgeng.manager.DbgProcess;
import agent.dbgeng.manager.DbgReason; import agent.dbgeng.manager.DbgReason;
import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgState;
import agent.dbgeng.manager.DbgStateListener; import agent.dbgeng.manager.DbgStateListener;
import agent.dbgeng.manager.DbgThread;
import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo; import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned; import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned;
import agent.dbgeng.model.iface1.DbgModelTargetBptHelper; import agent.dbgeng.model.iface1.DbgModelTargetBptHelper;
import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful; import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful;
@@ -105,92 +108,87 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
} }
protected static Class<? extends DbgModelTargetObject> lookupWrapperType(String type, protected static Class<? extends DbgModelTargetObject> lookupWrapperType(String type, String parentName) {
String parentName) {
switch (type) { switch (type) {
case "Available": case "Available":
return DbgModelTargetAvailableContainer.class; return DbgModelTargetAvailableContainer.class;
case "Sessions": case "Sessions":
return DbgModelTargetSessionContainer.class; return DbgModelTargetSessionContainer.class;
case "Processes": case "Processes":
return DbgModelTargetProcessContainer.class; return DbgModelTargetProcessContainer.class;
case "Threads": case "Threads":
return DbgModelTargetThreadContainer.class; return DbgModelTargetThreadContainer.class;
case "Modules": case "Modules":
return DbgModelTargetModuleContainer.class; return DbgModelTargetModuleContainer.class;
case "Frames": case "Frames":
return DbgModelTargetStack.class; return DbgModelTargetStack.class;
case "Registers": case "Registers":
return DbgModelTargetRegisterContainer.class; return DbgModelTargetRegisterContainer.class;
case "Attributes": case "Attributes":
return DbgModelTargetSessionAttributes.class; return DbgModelTargetSessionAttributes.class;
case "Breakpoints": case "Breakpoints":
return DbgModelTargetBreakpointContainer.class; return DbgModelTargetBreakpointContainer.class;
case "cursession": case "cursession":
return DbgModelTargetSession.class; return DbgModelTargetSession.class;
case "curprocess": case "curprocess":
return DbgModelTargetProcess.class; return DbgModelTargetProcess.class;
case "curthread": case "curthread":
return DbgModelTargetThread.class; return DbgModelTargetThread.class;
case "curframe": case "curframe":
return DbgModelTargetStackFrame.class; return DbgModelTargetStackFrame.class;
case "User": case "User":
return DbgModelTargetRegisterBank.class; return DbgModelTargetRegisterBank.class;
case "TTD": case "TTD":
return DbgModelTargetTTD.class; return DbgModelTargetTTD.class;
case "Debug": case "Debug":
return DbgModelTargetDebugContainer.class; return DbgModelTargetDebugContainer.class;
} }
if (parentName != null) { if (parentName != null) {
switch (parentName) { switch (parentName) {
case "Available": case "Available":
return DbgModelTargetAvailable.class; return DbgModelTargetAvailable.class;
case "Sessions": case "Sessions":
return DbgModelTargetSession.class; return DbgModelTargetSession.class;
case "Processes": case "Processes":
return DbgModelTargetProcess.class; return DbgModelTargetProcess.class;
case "Threads": case "Threads":
return DbgModelTargetThread.class; return DbgModelTargetThread.class;
case "Modules": case "Modules":
return DbgModelTargetModule.class; return DbgModelTargetModule.class;
case "Frames": case "Frames":
return DbgModelTargetStackFrame.class; return DbgModelTargetStackFrame.class;
case "Breakpoints": case "Breakpoints":
return DbgModelTargetBreakpointSpec.class; return DbgModelTargetBreakpointSpec.class;
//case "Registers": // case "Registers":
// return DbgModelTargetRegisterBank.class; // return DbgModelTargetRegisterBank.class;
case "FloatingPoint": case "FloatingPoint":
case "Kernel": case "Kernel":
case "SIMD": case "SIMD":
case "VFP": case "VFP":
case "User": case "User":
return DbgModelTargetRegister.class; return DbgModelTargetRegister.class;
} }
} }
return null; return null;
} }
public static DbgModelTargetObject makeProxy(DbgModel2Impl model, DbgModelTargetObject parent, public static DbgModelTargetObject makeProxy(DbgModel2Impl model, DbgModelTargetObject parent, String key,
String key, ModelObject object) { ModelObject object) {
List<Class<? extends TargetObject>> mixins = new ArrayList<>(); List<Class<? extends TargetObject>> mixins = new ArrayList<>();
String lkey = key; String lkey = key;
String pname = parent.getName(); String pname = parent.getName();
/* /*
if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD) || lkey.contains(")")) { * if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD) ||
mixins.add(DbgModelTargetMethod.class); * lkey.contains(")")) { mixins.add(DbgModelTargetMethod.class); // NB: We're
// NB: We're passing the parent's mixin model to the method on the assumption * passing the parent's mixin model to the method on the assumption // the init
// the init methods will need to know that the method's children have various * methods will need to know that the method's children have various //
// properties. * properties. lkey = pname; pname = ""; }
lkey = pname; */
pname = "";
}
*/
if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD)) { if (object.getKind().equals(ModelObjectKind.OBJECT_METHOD)) {
mixins.add(DbgModelTargetMethod.class); mixins.add(DbgModelTargetMethod.class);
} } else {
else {
Class<? extends DbgModelTargetObject> mixin = lookupWrapperType(lkey, pname); Class<? extends DbgModelTargetObject> mixin = lookupWrapperType(lkey, pname);
if (mixin != null) { if (mixin != null) {
mixins.add(mixin); mixins.add(mixin);
@@ -201,30 +199,32 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
protected static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 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. // is now deprecated.
protected final ProxyState state; protected final ProxyState state;
protected final Cleanable cleanable; protected final Cleanable cleanable;
private boolean breakpointEnabled; private boolean breakpointEnabled;
private final ListenerSet<TargetBreakpointAction> breakpointActions = private final ListenerSet<TargetBreakpointAction> breakpointActions = new ListenerSet<>(
new ListenerSet<>(TargetBreakpointAction.class) { TargetBreakpointAction.class) {
// Use strong references on actions // Use strong references on actions
protected Map<TargetBreakpointAction, TargetBreakpointAction> createMap() { protected Map<TargetBreakpointAction, TargetBreakpointAction> createMap() {
return Collections.synchronizedMap(new LinkedHashMap<>()); return Collections.synchronizedMap(new LinkedHashMap<>());
};
}; };
};
// Extending DefaultTargetObject may spare you from listeners, elements, and attributes // Extending DefaultTargetObject may spare you from listeners, elements, and
//protected final ListenerSet<TargetObjectListener> listeners = // attributes
// new ListenerSet<>(TargetObjectListener.class); // protected final ListenerSet<TargetObjectListener> listeners =
// new ListenerSet<>(TargetObjectListener.class);
// any other fields you need to support your impl // any other fields you need to support your impl
public DelegateDbgModel2TargetObject(DbgModel2Impl model, DbgModelTargetObject parent, public DelegateDbgModel2TargetObject(DbgModel2Impl model, DbgModelTargetObject parent, String key,
String key, ModelObject modelObject, List<Class<? extends TargetObject>> mixins) { ModelObject modelObject, List<Class<? extends TargetObject>> mixins) {
super(model, mixins, model, parent.getProxy(), key, getHintForObject(modelObject)); super(model, mixins, model, parent.getProxy(), key, getHintForObject(modelObject));
//System.err.println(this); // System.err.println(this);
this.state = new ProxyState(model, modelObject); this.state = new ProxyState(model, modelObject);
this.cleanable = CLEANER.register(this, state); this.cleanable = CLEANER.register(this, state);
@@ -244,8 +244,8 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
if (mixin != null) { if (mixin != null) {
mixins.add(mixin); mixins.add(mixin);
} }
DelegateDbgModel2TargetObject delegate = DelegateDbgModel2TargetObject delegate = new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject,
new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject, mixins); mixins);
return delegate; return delegate;
} }
@@ -272,43 +272,45 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
protected void checkExited(DbgState state, DbgCause cause) { protected void checkExited(DbgState state, DbgCause cause) {
TargetExecutionState exec = TargetExecutionState.INACTIVE; TargetExecutionState exec = TargetExecutionState.INACTIVE;
switch (state) { switch (state) {
case NOT_STARTED: { case NOT_STARTED: {
exec = TargetExecutionState.INACTIVE; exec = TargetExecutionState.INACTIVE;
break; break;
} }
case STARTING: { case STARTING: {
exec = TargetExecutionState.ALIVE; exec = TargetExecutionState.ALIVE;
break; break;
} }
case RUNNING: { case RUNNING: {
exec = TargetExecutionState.RUNNING; exec = TargetExecutionState.RUNNING;
resetModified(); resetModified();
onRunning(); onRunning();
break; break;
} }
case STOPPED: { case STOPPED: {
exec = TargetExecutionState.STOPPED; exec = TargetExecutionState.STOPPED;
onStopped(); onStopped();
break; break;
} }
case EXIT: { case EXIT: {
exec = TargetExecutionState.TERMINATED; exec = TargetExecutionState.TERMINATED;
onExit(); onExit();
break; break;
} }
case SESSION_EXIT: { case SESSION_EXIT: {
getModel().close(); getModel().close();
return; return;
} }
} }
if (proxy instanceof TargetExecutionStateful) { if (proxy instanceof TargetExecutionStateful) {
if (proxy instanceof DbgModelTargetSession) { if (proxy instanceof DbgModelTargetSession) {
if (state != DbgState.EXIT) { if (state != DbgState.EXIT) {
setExecutionState(exec, "Refreshed"); setExecutionState(exec, "Refreshed");
} }
} } else {
else { TargetExecutionState previous = this.getExecutionState();
setExecutionState(exec, "Refreshed"); if (!previous.equals(TargetExecutionState.INACTIVE)) {
setExecutionState(exec, "Refreshed");
}
} }
} }
} }
@@ -321,7 +323,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
proxy instanceof DbgModelTargetStackFrame || // proxy instanceof DbgModelTargetStackFrame || //
proxy instanceof DbgModelTargetStack || // proxy instanceof DbgModelTargetStack || //
proxy instanceof DbgModelTargetTTD) { proxy instanceof DbgModelTargetTTD) {
//listeners.fire.invalidateCacheRequested(proxy); // listeners.fire.invalidateCacheRequested(proxy);
return; return;
} }
} }
@@ -330,30 +332,37 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) { if (PathUtils.isLink(parent.getPath(), proxy.getName(), proxy.getPath())) {
return; return;
} }
DbgManagerImpl manager = getModel().getManager();
boolean kernelMode = manager.isKernelMode();
if (proxy instanceof DbgModelTargetSession) { if (proxy instanceof DbgModelTargetSession) {
DbgModelTargetSession targetSession = (DbgModelTargetSession) proxy; DbgModelTargetSession targetSession = (DbgModelTargetSession) proxy;
targetSession.getSession(false); targetSession.getSession(false);
} }
if (proxy instanceof DbgModelTargetProcess) { if (proxy instanceof DbgModelTargetProcess) {
DbgModelTargetProcess targetProcess = (DbgModelTargetProcess) proxy; 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) { if (proxy instanceof DbgModelTargetThread) {
DbgModelTargetThread targetThread = (DbgModelTargetThread) proxy; DbgModelTargetThread targetThread = (DbgModelTargetThread) proxy;
targetThread.getThread(false); DbgThread thread = targetThread.getThread(false);
} if (kernelMode) {
Long offset = thread.getOffset();
boolean kernelMode = getModel().getManager().isKernelMode(); if (offset == null) {
if (kernelMode) { return;
if (proxy instanceof DbgModelTargetProcess || // }
proxy instanceof DbgModelTargetThread) {
return;
} }
} }
if (getModel().isSuppressDescent()) { if (getModel().isSuppressDescent()) {
return; return;
} }
if (proxy instanceof DbgModelTargetSession || // if (proxy instanceof DbgModelTargetSession || //
proxy instanceof DbgModelTargetProcess || // proxy instanceof DbgModelTargetProcess || //
proxy instanceof DbgModelTargetThread) { proxy instanceof DbgModelTargetThread) {
@@ -362,8 +371,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
if (proxy instanceof DbgModelTargetRegisterContainer || // if (proxy instanceof DbgModelTargetRegisterContainer || //
proxy instanceof DbgModelTargetRegisterBank || // proxy instanceof DbgModelTargetRegisterBank || //
proxy.getName().equals("Stack") || proxy.getName().equals("Stack") || proxy.getName().equals("Debug")) {
proxy.getName().equals("Debug")) {
requestAttributes(false); requestAttributes(false);
return; return;
} }
@@ -405,7 +413,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
if (proxy instanceof TargetAccessConditioned) { if (proxy instanceof TargetAccessConditioned) {
changeAttributes(List.of(), List.of(), Map.of( // changeAttributes(List.of(), List.of(), Map.of( //
TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME, accessible // TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME, accessible //
), "Accessibility changed"); ), "Accessibility changed");
} }
} }
@@ -455,21 +463,18 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
if (proxy instanceof TargetThread) { if (proxy instanceof TargetThread) {
List<DelegateDbgModel2TargetObject> delegates = new ArrayList<>(); List<DelegateDbgModel2TargetObject> delegates = new ArrayList<>();
TargetObject stack = TargetObject stack = (TargetObject) getCachedAttribute("Stack");
(TargetObject) getCachedAttribute("Stack");
if (stack != null) { if (stack != null) {
DbgModelTargetStack frames = DbgModelTargetStack frames = (DbgModelTargetStack) stack.getCachedAttribute("Frames");
(DbgModelTargetStack) stack.getCachedAttribute("Frames");
delegates.add((DelegateDbgModel2TargetObject) frames.getDelegate()); delegates.add((DelegateDbgModel2TargetObject) frames.getDelegate());
} }
DbgModelTargetRegisterContainer container = DbgModelTargetRegisterContainer container = (DbgModelTargetRegisterContainer) getCachedAttribute(
(DbgModelTargetRegisterContainer) getCachedAttribute("Registers"); "Registers");
if (container == null) { if (container == null) {
return; return;
} }
delegates.add((DelegateDbgModel2TargetObject) container.getDelegate()); delegates.add((DelegateDbgModel2TargetObject) container.getDelegate());
DbgModelTargetRegisterBank bank = DbgModelTargetRegisterBank bank = (DbgModelTargetRegisterBank) container.getCachedAttribute("User");
(DbgModelTargetRegisterBank) container.getCachedAttribute("User");
if (bank == null) { if (bank == null) {
return; return;
} }
@@ -486,7 +491,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
if (proxy instanceof TargetRegisterBank) { if (proxy instanceof TargetRegisterBank) {
TargetRegisterBank bank = (TargetRegisterBank) proxy; TargetRegisterBank bank = (TargetRegisterBank) proxy;
//requestElements(false); // requestElements(false);
requestAttributes(false).thenAccept(__ -> { requestAttributes(false).thenAccept(__ -> {
bank.readRegistersNamed(getCachedAttributes().keySet()); bank.readRegistersNamed(getCachedAttributes().keySet());
}); });
@@ -497,8 +502,7 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
for (TargetObject obj : getCachedElements().values()) { for (TargetObject obj : getCachedElements().values()) {
if (obj instanceof TargetStackFrame) { if (obj instanceof TargetStackFrame) {
DbgModelTargetObject frame = (DbgModelTargetObject) obj; DbgModelTargetObject frame = (DbgModelTargetObject) obj;
DelegateDbgModel2TargetObject delegate = DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) frame.getDelegate();
(DelegateDbgModel2TargetObject) frame.getDelegate();
delegate.threadStateChangedSpecific(state, reason); delegate.threadStateChangedSpecific(state, reason);
} }
} }
@@ -31,7 +31,7 @@ public interface TargetThread extends TargetObject {
String TID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "tid"; String TID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "tid";
@TargetAttributeType(name = TID_ATTRIBUTE_NAME, hidden = true) @TargetAttributeType(name = TID_ATTRIBUTE_NAME, hidden = true)
public default Integer getTid() { public default Long getTid() {
return getTypedAttributeNowByName(TID_ATTRIBUTE_NAME, Integer.class, null); return getTypedAttributeNowByName(TID_ATTRIBUTE_NAME, Long.class, null);
} }
} }