GP-648: Dbgmodel speed-up, and focus issues.

This commit is contained in:
d-millar 2021-01-29 21:53:35 +00:00 committed by Dan
parent f5ec74f2c3
commit 2ed29f5693
53 changed files with 650 additions and 473 deletions

View file

@ -41,4 +41,8 @@ public class DebugModuleInfo {
this.checkSum = checkSum; this.checkSum = checkSum;
this.timeDateStamp = timeDateStamp; // TODO: Convert to DateTime? this.timeDateStamp = timeDateStamp; // TODO: Convert to DateTime?
} }
public String toString() {
return Long.toHexString(baseOffset);
}
} }

View file

@ -217,6 +217,10 @@ public abstract class AbstractClientThreadExecutor extends AbstractExecutorServi
} }
} }
public boolean isCurrentThread() {
return thread.equals(Thread.currentThread());
}
/** /**
* Schedule a task with the given priority, taking a reference to the client. * Schedule a task with the given priority, taking a reference to the client.
* *

View file

@ -130,7 +130,7 @@ public interface DbgEventsListener {
* @param name the name of the module on the target * @param name the name of the module on the target
* @param cause the cause of this event * @param cause the cause of this event
*/ */
void moduleLoaded(DbgProcess process, String name, DbgCause cause); void moduleLoaded(DbgProcess process, DebugModuleInfo info, DbgCause cause);
/** /**
* A module has been unloaded from an process * A module has been unloaded from an process
@ -139,7 +139,7 @@ public interface DbgEventsListener {
* @param name the name of the module on the target * @param name the name of the module on the target
* @param cause the cause of this event * @param cause the cause of this event
*/ */
void moduleUnloaded(DbgProcess process, String name, DbgCause cause); void moduleUnloaded(DbgProcess process, DebugModuleInfo info, DbgCause cause);
/** /**
* A breakpoint has been created in the session * A breakpoint has been created in the session

View file

@ -83,12 +83,12 @@ public interface DbgEventsListenerAdapter extends DbgEventsListener {
} }
@Override @Override
public default void moduleLoaded(DbgProcess process, String name, DbgCause cause) { public default void moduleLoaded(DbgProcess process, DebugModuleInfo info, DbgCause cause) {
// Extension point // Extension point
} }
@Override @Override
public default void moduleUnloaded(DbgProcess process, String name, DbgCause cause) { public default void moduleUnloaded(DbgProcess process, DebugModuleInfo info, DbgCause cause) {
// Extension point // Extension point
} }

View file

@ -86,12 +86,17 @@ public class DbgBreakpointInfo {
return Objects.hash(number, bptType, getFlags(), location, enabled, access, size); return Objects.hash(number, bptType, getFlags(), location, enabled, access, size);
} }
public String toString() {
return Integer.toHexString(bpt.getId());
}
/*
@Override @Override
public String toString() { public String toString() {
return "<DbgBreakpointInfo number=" + number + ",type=" + getType() + ",flags=" + return "<DbgBreakpointInfo number=" + number + ",type=" + getType() + ",flags=" +
getFlags() + ",addr=" + location + ",times=" + getTimes() + ",size=" + getSize() + getFlags() + ",addr=" + location + ",times=" + getTimes() + ",size=" + getSize() +
",access=" + getAccess() + ">"; ",access=" + getAccess() + ">";
} }
*/
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {

View file

@ -16,7 +16,7 @@
package agent.dbgeng.manager.cmd; package agent.dbgeng.manager.cmd;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.*;
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; import agent.dbgeng.manager.evt.DbgCommandDoneEvent;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
/** /**
@ -43,8 +43,8 @@ public abstract class AbstractDbgCommand<T> implements DbgCommand<T> {
@Override @Override
public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) { public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) {
if (evt instanceof AbstractDbgCompletedCommandEvent) { if (evt instanceof DbgCommandDoneEvent) {
if (pending.getCommand().equals(this)) { if (pending.getCommand().equals(((DbgCommandDoneEvent) evt).getCmd())) {
return true; return true;
} }
} }

View file

@ -18,7 +18,6 @@ package agent.dbgeng.manager.cmd;
import java.util.*; import java.util.*;
import agent.dbgeng.dbgeng.*; import agent.dbgeng.dbgeng.*;
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
import agent.dbgeng.manager.DbgModule; import agent.dbgeng.manager.DbgModule;
import agent.dbgeng.manager.impl.*; import agent.dbgeng.manager.impl.*;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -43,8 +42,8 @@ public class DbgListModulesCommand extends AbstractDbgCommand<Map<String, DbgMod
} }
// Need to create the thread as if we receive =thread-created // Need to create the thread as if we receive =thread-created
Msg.warn(this, "Resync: Was missing module: " + id); Msg.warn(this, "Resync: Was missing module: " + id);
DbgModuleImpl module = new DbgModuleImpl(manager, process, id); DebugModuleInfo info = moduleInfo.get(updatedModules.get(id));
module.setInfo(moduleInfo.get(updatedModules.get(id))); DbgModuleImpl module = new DbgModuleImpl(manager, process, info);
module.add(); module.add();
} }
for (String id : new ArrayList<>(cur)) { for (String id : new ArrayList<>(cur)) {
@ -63,7 +62,7 @@ public class DbgListModulesCommand extends AbstractDbgCommand<Map<String, DbgMod
DebugSymbols symbols = manager.getSymbols(); DebugSymbols symbols = manager.getSymbols();
for (DebugModule module : symbols.iterateModules(0)) { for (DebugModule module : symbols.iterateModules(0)) {
DebugModuleInfo info = symbols.getModuleParameters(1, module.getIndex()); DebugModuleInfo info = symbols.getModuleParameters(1, module.getIndex());
updatedModules.put(module.getName(DebugModuleName.MODULE), module); updatedModules.put(info.toString(), module);
moduleInfo.put(module, info); moduleInfo.put(module, info);
} }
} }

View file

@ -0,0 +1,45 @@
/* ###
* 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 agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import ghidra.dbg.attributes.TargetObjectRef;
public class DbgRequestFocusCommand extends AbstractDbgCommand<Void> {
private DbgModelTargetFocusScope<?> scope;
private TargetObjectRef ref;
/**
* Set focus for the current ref
*
* @param manager the manager to execute the command
* @param scope in most cases the root object (must be an ancestor for the ref)
* @param ref the desired focus
*/
public DbgRequestFocusCommand(DbgManagerImpl manager, DbgModelTargetFocusScope<?> scope,
TargetObjectRef ref) {
super(manager);
this.scope = scope;
this.ref = ref;
}
@Override
public void invoke() {
scope.doRequestFocus(ref);
}
}

View file

@ -15,6 +15,7 @@
*/ */
package agent.dbgeng.manager.evt; package agent.dbgeng.manager.evt;
import agent.dbgeng.manager.DbgCommand;
import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgState;
/** /**
@ -22,6 +23,8 @@ import agent.dbgeng.manager.DbgState;
*/ */
public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent { public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent {
private DbgCommand<?> cmd;
/** /**
* Construct a new event, parsing the tail for information * Construct a new event, parsing the tail for information
*/ */
@ -29,8 +32,9 @@ public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent {
super(); super();
} }
public DbgCommandDoneEvent(String info) { public DbgCommandDoneEvent(DbgCommand<?> cmd) {
super(info); super(cmd.toString());
this.cmd = cmd;
} }
@Override @Override
@ -38,4 +42,8 @@ public class DbgCommandDoneEvent extends AbstractDbgCompletedCommandEvent {
return DbgState.STOPPED; return DbgState.STOPPED;
} }
public DbgCommand<?> getCmd() {
return cmd;
}
} }

View file

@ -17,8 +17,8 @@ package agent.dbgeng.manager.evt;
import agent.dbgeng.dbgeng.DebugClient.ChangeEngineState; import agent.dbgeng.dbgeng.DebugClient.ChangeEngineState;
import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgState;
import agent.dbgeng.manager.DbgThread;
import agent.dbgeng.manager.impl.DbgStackFrameImpl; import agent.dbgeng.manager.impl.DbgStackFrameImpl;
import agent.dbgeng.manager.impl.DbgThreadImpl;
import ghidra.comm.util.BitmaskSet; import ghidra.comm.util.BitmaskSet;
public class DbgStateChangedEvent extends AbstractDbgEvent<BitmaskSet<ChangeEngineState>> { public class DbgStateChangedEvent extends AbstractDbgEvent<BitmaskSet<ChangeEngineState>> {
@ -38,7 +38,7 @@ public class DbgStateChangedEvent extends AbstractDbgEvent<BitmaskSet<ChangeEngi
this.argument = argument; this.argument = argument;
} }
public DbgStackFrameImpl getFrame(DbgThreadImpl thread) { public DbgStackFrameImpl getFrame(DbgThread thread) {
return null; return null;
} }

View file

@ -17,6 +17,7 @@ package agent.dbgeng.manager.evt;
import agent.dbgeng.dbgeng.DebugThreadId; import agent.dbgeng.dbgeng.DebugThreadId;
import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgState;
import agent.dbgeng.manager.DbgThread;
import agent.dbgeng.manager.impl.DbgStackFrameImpl; import agent.dbgeng.manager.impl.DbgStackFrameImpl;
import agent.dbgeng.manager.impl.DbgThreadImpl; import agent.dbgeng.manager.impl.DbgThreadImpl;
@ -26,7 +27,7 @@ import agent.dbgeng.manager.impl.DbgThreadImpl;
public class DbgThreadSelectedEvent extends AbstractDbgEvent<DebugThreadId> { public class DbgThreadSelectedEvent extends AbstractDbgEvent<DebugThreadId> {
private final DebugThreadId id; private final DebugThreadId id;
private DbgState state; private DbgState state;
private DbgThreadImpl thread; private DbgThread thread;
private DbgStackFrameImpl frame; private DbgStackFrameImpl frame;
/** /**
@ -35,7 +36,7 @@ public class DbgThreadSelectedEvent extends AbstractDbgEvent<DebugThreadId> {
* @param frame * @param frame
* @param id dbgeng-provided id * @param id dbgeng-provided id
*/ */
public DbgThreadSelectedEvent(DbgState state, DbgThreadImpl thread, DbgStackFrameImpl frame) { public DbgThreadSelectedEvent(DbgState state, DbgThread thread, DbgStackFrameImpl frame) {
super(thread.getId()); super(thread.getId());
this.id = thread.getId(); this.id = thread.getId();
this.state = state; this.state = state;
@ -57,7 +58,7 @@ public class DbgThreadSelectedEvent extends AbstractDbgEvent<DebugThreadId> {
} }
public DbgThreadImpl getThread() { public DbgThreadImpl getThread() {
return thread; return (DbgThreadImpl) thread;
} }
public DbgStackFrameImpl getFrame() { public DbgStackFrameImpl getFrame() {

View file

@ -15,7 +15,7 @@
*/ */
package agent.dbgeng.manager.impl; package agent.dbgeng.manager.impl;
import static ghidra.async.AsyncUtils.sequence; import static ghidra.async.AsyncUtils.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -40,9 +40,11 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.manager.breakpoint.DbgBreakpointType; import agent.dbgeng.manager.breakpoint.DbgBreakpointType;
import agent.dbgeng.manager.cmd.*; import agent.dbgeng.manager.cmd.*;
import agent.dbgeng.manager.evt.*; import agent.dbgeng.manager.evt.*;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import ghidra.async.*; import ghidra.async.*;
import ghidra.async.seq.AsyncSequenceHandlerForRunner;
import ghidra.comm.util.BitmaskSet; import ghidra.comm.util.BitmaskSet;
import ghidra.dbg.error.DebuggerModelAccessException; import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.util.HandlerMap; import ghidra.dbg.util.HandlerMap;
import ghidra.lifecycle.Internal; import ghidra.lifecycle.Internal;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -99,6 +101,12 @@ public class DbgManagerImpl implements DbgManager {
new ListenerSet<>(DbgEventsListener.class); new ListenerSet<>(DbgEventsListener.class);
private DebugEventInformation lastEventInformation; private DebugEventInformation lastEventInformation;
private DbgSession currentSession;
private DbgProcess currentProcess;
private DbgThread currentThread;
private DbgSession eventSession;
private DbgProcess eventProcess;
private DbgThread eventThread;
private volatile boolean waiting = false; private volatile boolean waiting = false;
private boolean kernelMode = false; private boolean kernelMode = false;
@ -411,28 +419,44 @@ public class DbgManagerImpl implements DbgManager {
assert cmd != null; assert cmd != null;
checkStarted(); checkStarted();
DbgPendingCommand<T> pcmd = new DbgPendingCommand<>(cmd); DbgPendingCommand<T> pcmd = new DbgPendingCommand<>(cmd);
if (isWaiting()) { //if (isWaiting()) {
throw new DebuggerModelAccessException( // throw new DebuggerModelAccessException(
"Cannot process command " + cmd.toString() + " while engine is waiting for events"); // "Cannot process command " + cmd.toString() + " while engine is waiting for events");
} //}
sequence(TypeSpec.VOID).then(engThread, (seq) -> {
synchronized (this) { if (engThread.isCurrentThread()) {
if (!cmd.validInState(state.get())) { sequence(TypeSpec.VOID).then((seq) -> {
throw new DbgCommandError( addCommand(cmd, pcmd, seq);
"Command " + cmd + " is not valid while " + state.get());
}
activeCmds.add(pcmd);
}
cmd.invoke();
processEvent(new DbgCommandDoneEvent(cmd.toString()));
seq.exit(); seq.exit();
}).finish().exceptionally((exc) -> { }).finish().exceptionally((exc) -> {
pcmd.completeExceptionally(exc); pcmd.completeExceptionally(exc);
return null; return null;
}); });
}
else {
sequence(TypeSpec.VOID).then(engThread, (seq) -> {
addCommand(cmd, pcmd, seq);
seq.exit();
}).finish().exceptionally((exc) -> {
pcmd.completeExceptionally(exc);
return null;
});
}
return pcmd; return pcmd;
} }
private <T> void addCommand(DbgCommand<? extends T> cmd, DbgPendingCommand<T> pcmd,
AsyncSequenceHandlerForRunner<Void> seq) {
synchronized (this) {
if (!cmd.validInState(state.get())) {
throw new DbgCommandError("Command " + cmd + " is not valid while " + state.get());
}
activeCmds.add(pcmd);
}
cmd.invoke();
processEvent(new DbgCommandDoneEvent(cmd));
}
/*@Override /*@Override
public <T> DbgPendingCommand<T> execute1(DbgCommand<? extends T> cmd) { public <T> DbgPendingCommand<T> execute1(DbgCommand<? extends T> cmd) {
assert cmd != null; assert cmd != null;
@ -586,9 +610,13 @@ public class DbgManagerImpl implements DbgManager {
lastEventInformation = control.getLastEventInformation(); lastEventInformation = control.getLastEventInformation();
lastEventInformation.setSession(esid); lastEventInformation.setSession(esid);
lastEventInformation.setExecutingProcessorType(execType); lastEventInformation.setExecutingProcessorType(execType);
DbgThreadImpl eventThread = threads.get(etid); currentSession = eventSession = getSessionComputeIfAbsent(esid);
currentProcess =
eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId());
currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess,
so.getCurrentThreadSystemId());
if (eventThread != null) { if (eventThread != null) {
eventThread.setInfo(lastEventInformation); ((DbgThreadImpl) eventThread).setInfo(lastEventInformation);
} }
return etid; return etid;
} }
@ -658,8 +686,7 @@ public class DbgManagerImpl implements DbgManager {
DebugThreadId eventId = updateState(); DebugThreadId eventId = updateState();
DbgProcessImpl process = getCurrentProcess(); DbgProcessImpl process = getCurrentProcess();
int tid = so.getCurrentThreadSystemId(); int tid = so.getCurrentThreadSystemId();
DbgThreadImpl thread = new DbgThreadImpl(this, process, eventId, tid); DbgThreadImpl thread = getThreadComputeIfAbsent(eventId, process, tid);
thread.add();
getEventListeners().fire.threadSelected(thread, null, evt.getCause()); getEventListeners().fire.threadSelected(thread, null, evt.getCause());
String key = Integer.toHexString(eventId.id); String key = Integer.toHexString(eventId.id);
@ -703,9 +730,9 @@ public class DbgManagerImpl implements DbgManager {
protected DebugStatus processThreadSelected(DbgThreadSelectedEvent evt, Void v) { protected DebugStatus processThreadSelected(DbgThreadSelectedEvent evt, Void v) {
DebugThreadId eventId = updateState(); DebugThreadId eventId = updateState();
DbgThreadImpl thread = evt.getThread(); currentThread = evt.getThread();
thread.setState(evt.getState(), evt.getCause(), evt.getReason()); currentThread.setState(evt.getState(), evt.getCause(), evt.getReason());
getEventListeners().fire.threadSelected(thread, evt.getFrame(), evt.getCause()); getEventListeners().fire.threadSelected(currentThread, evt.getFrame(), evt.getCause());
String key = Integer.toHexString(eventId.id); String key = Integer.toHexString(eventId.id);
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -722,6 +749,7 @@ public class DbgManagerImpl implements DbgManager {
* @return retval handling/break status * @return retval handling/break status
*/ */
protected DebugStatus processProcessCreated(DbgProcessCreatedEvent evt, Void v) { protected DebugStatus processProcessCreated(DbgProcessCreatedEvent evt, Void v) {
DebugThreadId eventId = updateState();
DebugClient dbgeng = engThread.getClient(); DebugClient dbgeng = engThread.getClient();
DebugSystemObjects so = dbgeng.getSystemObjects(); DebugSystemObjects so = dbgeng.getSystemObjects();
@ -730,8 +758,7 @@ public class DbgManagerImpl implements DbgManager {
DebugProcessId id = so.getProcessIdByHandle(handle); DebugProcessId id = so.getProcessIdByHandle(handle);
so.setCurrentProcessId(id); so.setCurrentProcessId(id);
int pid = so.getCurrentProcessSystemId(); int pid = so.getCurrentProcessSystemId();
DbgProcessImpl proc = new DbgProcessImpl(this, id, pid); DbgProcessImpl proc = getProcessComputeIfAbsent(id, pid);
proc.add();
getEventListeners().fire.processSelected(proc, evt.getCause()); getEventListeners().fire.processSelected(proc, evt.getCause());
handle = info.initialThreadInfo.handle; handle = info.initialThreadInfo.handle;
@ -742,10 +769,8 @@ public class DbgManagerImpl implements DbgManager {
getEventListeners().fire.threadCreated(thread, evt.getCause()); getEventListeners().fire.threadCreated(thread, evt.getCause());
getEventListeners().fire.threadSelected(thread, null, evt.getCause()); getEventListeners().fire.threadSelected(thread, null, evt.getCause());
DebugModuleInfo moduleInfo = info.moduleInfo; proc.moduleLoaded(info.moduleInfo);
String moduleName = moduleInfo.moduleName; getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause());
proc.moduleLoaded(moduleName, moduleInfo);
getEventListeners().fire.moduleLoaded(proc, moduleName, evt.getCause());
String key = Integer.toHexString(id.id); String key = Integer.toHexString(id.id);
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -795,8 +820,8 @@ public class DbgManagerImpl implements DbgManager {
protected DebugStatus processProcessSelected(DbgProcessSelectedEvent evt, Void v) { protected DebugStatus processProcessSelected(DbgProcessSelectedEvent evt, Void v) {
DebugThreadId eventId = updateState(); DebugThreadId eventId = updateState();
DbgProcessImpl process = evt.getProcess(); currentProcess = evt.getProcess();
getEventListeners().fire.processSelected(process, evt.getCause()); getEventListeners().fire.processSelected(currentProcess, evt.getCause());
String key = Integer.toHexString(eventId.id); String key = Integer.toHexString(eventId.id);
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -816,9 +841,8 @@ public class DbgManagerImpl implements DbgManager {
updateState(); updateState();
DbgProcessImpl process = getCurrentProcess(); DbgProcessImpl process = getCurrentProcess();
DebugModuleInfo info = evt.getInfo(); DebugModuleInfo info = evt.getInfo();
String moduleName = info.moduleName; process.moduleLoaded(info);
process.moduleLoaded(moduleName, info); getEventListeners().fire.moduleLoaded(process, info, evt.getCause());
getEventListeners().fire.moduleLoaded(process, moduleName, evt.getCause());
String key = info.moduleName; String key = info.moduleName;
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -838,9 +862,8 @@ public class DbgManagerImpl implements DbgManager {
updateState(); updateState();
DbgProcessImpl process = getCurrentProcess(); DbgProcessImpl process = getCurrentProcess();
DebugModuleInfo info = evt.getInfo(); DebugModuleInfo info = evt.getInfo();
String moduleName = info.moduleName; process.moduleUnloaded(info);
process.moduleUnloaded(moduleName); getEventListeners().fire.moduleUnloaded(process, info, evt.getCause());
getEventListeners().fire.moduleUnloaded(process, moduleName, evt.getCause());
String key = info.moduleName; String key = info.moduleName;
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -872,23 +895,23 @@ public class DbgManagerImpl implements DbgManager {
if (!threads.isEmpty()) { if (!threads.isEmpty()) {
//DbgSessionImpl session = getCurrentSession(); //DbgSessionImpl session = getCurrentSession();
//DbgProcessImpl process = getCurrentProcess(); //DbgProcessImpl process = getCurrentProcess();
DbgThreadImpl thread = getCurrentThread(); eventThread = getCurrentThread();
DbgState dbgState = null; DbgState dbgState = null;
if (thread != null) { if (eventThread != null) {
if (status.threadState.equals(ExecutionState.STOPPED)) { if (status.threadState.equals(ExecutionState.STOPPED)) {
dbgState = DbgState.STOPPED; dbgState = DbgState.STOPPED;
//System.err.println("STOPPED " + id); //System.err.println("STOPPED " + id);
processEvent(new DbgStoppedEvent(thread.getId())); processEvent(new DbgStoppedEvent(eventThread.getId()));
} }
if (status.threadState.equals(ExecutionState.RUNNING)) { if (status.threadState.equals(ExecutionState.RUNNING)) {
//System.err.println("RUNNING " + id); //System.err.println("RUNNING " + id);
dbgState = DbgState.RUNNING; dbgState = DbgState.RUNNING;
processEvent(new DbgRunningEvent(thread.getId())); processEvent(new DbgRunningEvent(eventThread.getId()));
} }
// Don't fire // Don't fire
if (dbgState != null) { if (dbgState != null) {
processEvent( processEvent(new DbgThreadSelectedEvent(dbgState, eventThread,
new DbgThreadSelectedEvent(dbgState, thread, evt.getFrame(thread))); evt.getFrame(eventThread)));
} }
return DebugStatus.NO_CHANGE; return DebugStatus.NO_CHANGE;
} }
@ -934,8 +957,8 @@ public class DbgManagerImpl implements DbgManager {
protected DebugStatus processSessionSelected(DbgSessionSelectedEvent evt, Void v) { protected DebugStatus processSessionSelected(DbgSessionSelectedEvent evt, Void v) {
DebugThreadId eventId = updateState(); DebugThreadId eventId = updateState();
DbgSessionImpl session = evt.getSession(); currentSession = evt.getSession();
getEventListeners().fire.sessionSelected(session, evt.getCause()); getEventListeners().fire.sessionSelected(currentSession, evt.getCause());
String key = Integer.toHexString(eventId.id); String key = Integer.toHexString(eventId.id);
if (statusByNameMap.containsKey(key)) { if (statusByNameMap.containsKey(key)) {
@ -1335,77 +1358,53 @@ public class DbgManagerImpl implements DbgManager {
} }
public DbgThreadImpl getCurrentThread() { public DbgThreadImpl getCurrentThread() {
synchronized (threads) { return (DbgThreadImpl) (currentThread != null ? currentThread : eventThread);
DebugEventInformation info = getLastEventInformation();
if (info == null) {
return null;
}
return threads.get(info.getThreadId());
} }
public void setCurrentThread(DbgThreadImpl thread) {
currentThread = thread;
} }
public DbgProcessImpl getCurrentProcess() { public DbgProcessImpl getCurrentProcess() {
synchronized (processes) { return (DbgProcessImpl) (currentProcess != null ? currentProcess : eventProcess);
DebugEventInformation info = getLastEventInformation();
if (info == null) {
return null;
}
return processes.get(info.getProcessId());
}
} }
public DbgSessionImpl getCurrentSession() { public DbgSessionImpl getCurrentSession() {
synchronized (sessions) { return (DbgSessionImpl) (currentSession != null ? currentSession : eventSession);
DebugEventInformation info = getLastEventInformation();
if (info == null) {
return null;
}
return sessions.get(info.getSessionId());
}
} }
public DbgThreadImpl getEventThread() { public DbgThreadImpl getEventThread() {
synchronized (threads) { return (DbgThreadImpl) eventThread;
DebugSystemObjects so = getSystemObjects();
DebugThreadId id = so.getEventThread();
return threads.get(id);
}
} }
public DbgProcessImpl getEventProcess() { public DbgProcessImpl getEventProcess() {
synchronized (processes) { return (DbgProcessImpl) eventProcess;
DebugSystemObjects so = getSystemObjects();
DebugProcessId id = so.getEventProcess();
return processes.get(id);
}
} }
public DbgSessionImpl getEventSession() { public DbgSessionImpl getEventSession() {
synchronized (sessions) { return (DbgSessionImpl) eventSession;
DebugSystemObjects so = getSystemObjects();
DebugSessionId id = so.getEventSystem();
return sessions.get(id);
}
} }
public CompletableFuture<Void> selectThread(DbgThreadImpl thread) { public CompletableFuture<Void> selectThread(DbgThread thread) {
DebugEventInformation info = getLastEventInformation(); currentThread = thread;
info.setThread(thread.getId());
return execute(new DbgThreadSelectCommand(this, thread, null)); return execute(new DbgThreadSelectCommand(this, thread, null));
} }
public CompletableFuture<Void> selectProcess(DbgProcessImpl process) { public CompletableFuture<Void> selectProcess(DbgProcess process) {
DebugEventInformation info = getLastEventInformation(); currentProcess = process;
info.setProcess(process.getId());
return execute(new DbgProcessSelectCommand(this, process)); return execute(new DbgProcessSelectCommand(this, process));
} }
public CompletableFuture<Void> selectSession(DbgSessionImpl session) { public CompletableFuture<Void> selectSession(DbgSession session) {
DebugEventInformation info = getLastEventInformation(); currentSession = session;
info.setSession(session.getId());
return execute(new DbgSessionSelectCommand(this, session)); return execute(new DbgSessionSelectCommand(this, session));
} }
public CompletableFuture<Void> requestFocus(DbgModelTargetFocusScope<?> scope,
TargetObjectRef ref) {
return execute(new DbgRequestFocusCommand(this, scope, ref));
}
@Override @Override
public CompletableFuture<Void> console(String command) { public CompletableFuture<Void> console(String command) {
return execute( return execute(

View file

@ -40,10 +40,11 @@ public class DbgModuleImpl implements DbgModule {
* @param process the process to which the module belongs * @param process the process to which the module belongs
* @param id the dbgeng-assigned module ID * @param id the dbgeng-assigned module ID
*/ */
public DbgModuleImpl(DbgManagerImpl manager, DbgProcessImpl process, String name) { public DbgModuleImpl(DbgManagerImpl manager, DbgProcessImpl process, DebugModuleInfo info) {
this.manager = manager; this.manager = manager;
this.process = process; this.process = process;
this.name = name; this.info = info;
this.name = info.moduleName;
} }
@Override @Override
@ -56,7 +57,7 @@ public class DbgModuleImpl implements DbgModule {
*/ */
public void add() { public void add() {
process.addModule(this); process.addModule(this);
manager.getEventListeners().fire.moduleLoaded(process, name, Causes.UNCLAIMED); manager.getEventListeners().fire.moduleLoaded(process, info, Causes.UNCLAIMED);
} }
/** /**
@ -64,7 +65,7 @@ public class DbgModuleImpl implements DbgModule {
*/ */
public void remove() { public void remove() {
process.removeModule(name); process.removeModule(name);
manager.getEventListeners().fire.moduleUnloaded(process, name, Causes.UNCLAIMED); manager.getEventListeners().fire.moduleUnloaded(process, info, Causes.UNCLAIMED);
} }
@Override @Override
@ -103,8 +104,8 @@ public class DbgModuleImpl implements DbgModule {
return minimalSymbols.request(); return minimalSymbols.request();
} }
public void setInfo(DebugModuleInfo info) { public DebugModuleInfo getInfo() {
this.info = info; return info;
} }
} }

View file

@ -169,11 +169,11 @@ public class DbgProcessImpl implements DbgProcess {
* @param module the thread to add * @param module the thread to add
*/ */
public void addModule(DbgModuleImpl module) { public void addModule(DbgModuleImpl module) {
DbgModuleImpl exists = modules.get(module.getName()); DbgModuleImpl exists = modules.get(module.getInfo().toString());
if (exists != null) { if (exists != null) {
throw new IllegalArgumentException("There is already module " + exists); throw new IllegalArgumentException("There is already module " + exists);
} }
modules.put(module.getName(), module); modules.put(module.getInfo().toString(), module);
} }
@ -233,7 +233,7 @@ public class DbgProcessImpl implements DbgProcess {
@Override @Override
public CompletableFuture<Void> select() { public CompletableFuture<Void> select() {
return manager.execute(new DbgProcessSelectCommand(manager, this)); return manager.selectProcess(this);
} }
@Override @Override
@ -353,17 +353,15 @@ public class DbgProcessImpl implements DbgProcess {
return null; return null;
} }
protected DbgModuleImpl createModule(String name) { protected void moduleLoaded(DebugModuleInfo info) {
return new DbgModuleImpl(manager, this, name); if (!modules.containsKey(info.moduleName)) {
DbgModuleImpl module = new DbgModuleImpl(manager, this, info);
modules.put(info.toString(), module);
}
} }
protected void moduleLoaded(String name, DebugModuleInfo info) { protected void moduleUnloaded(DebugModuleInfo info) {
DbgModuleImpl module = modules.computeIfAbsent(name, this::createModule); modules.remove(info.toString());
module.setInfo(info);
}
protected void moduleUnloaded(String name) {
modules.remove(name);
} }
protected void threadCreated(DbgThreadImpl thread) { protected void threadCreated(DbgThreadImpl thread) {

View file

@ -125,7 +125,7 @@ public class DbgStackFrameImpl implements DbgStackFrame {
@Override @Override
public CompletableFuture<Void> select() { public CompletableFuture<Void> select() {
return manager.execute(new DbgThreadSelectCommand(manager, thread, level)); return thread.select();
} }
@Override @Override

View file

@ -132,7 +132,7 @@ public class DbgThreadImpl implements DbgThread {
@Override @Override
public CompletableFuture<Void> select() { public CompletableFuture<Void> select() {
return manager.execute(new DbgThreadSelectCommand(manager, this, null)); return manager.selectThread(this);
} }
@Override @Override

View file

@ -16,12 +16,10 @@
package agent.dbgeng.model.iface1; package agent.dbgeng.model.iface1;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import agent.dbgeng.model.iface2.DbgModelTargetObject; import agent.dbgeng.model.iface2.DbgModelTargetObject;
import ghidra.async.AsyncUtils; import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec; import ghidra.dbg.agent.AbstractTargetObject;
import ghidra.dbg.DebugModelConventions;
import ghidra.dbg.attributes.TargetObjectRef; import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.error.DebuggerIllegalArgumentException; import ghidra.dbg.error.DebuggerIllegalArgumentException;
import ghidra.dbg.target.TargetFocusScope; import ghidra.dbg.target.TargetFocusScope;
@ -48,6 +46,10 @@ public interface DbgModelTargetFocusScope<T extends TargetFocusScope<T>>
// (but, of course, may then cause change in state) // (but, of course, may then cause change in state)
@Override @Override
public default CompletableFuture<Void> requestFocus(TargetObjectRef ref) { public default CompletableFuture<Void> requestFocus(TargetObjectRef ref) {
return getManager().requestFocus(this, ref);
}
public default CompletableFuture<Void> doRequestFocus(TargetObjectRef ref) {
if (getManager().isWaiting()) { if (getManager().isWaiting()) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
@ -58,32 +60,23 @@ public interface DbgModelTargetFocusScope<T extends TargetFocusScope<T>>
if (!PathUtils.isAncestor(this.getPath(), ref.getPath())) { if (!PathUtils.isAncestor(this.getPath(), ref.getPath())) {
throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope"); throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope");
} }
return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { return ref.fetch().thenCompose(obj -> {
ref.fetch().handle(seq::next);
}, TypeSpec.cls(TargetObject.class)).then((obj, seq) -> {
TargetObject cur = obj; TargetObject cur = obj;
while (cur != null) { while (cur != null) {
if (cur instanceof DbgModelSelectableObject) { if (cur instanceof DbgModelSelectableObject) {
DbgModelSelectableObject sel = (DbgModelSelectableObject) cur; DbgModelSelectableObject sel = (DbgModelSelectableObject) cur;
sel.select().handle(seq::exit); setFocus(sel);
AtomicReference<DbgModelTargetFocusScope<?>> scope = new AtomicReference<>(); return sel.select();
AsyncUtils.sequence(TypeSpec.VOID).then(seqx -> {
DebugModelConventions.findSuitable(DbgModelTargetFocusScope.class, sel)
.handle(seqx::next);
}, scope).then(seqx -> {
scope.get().setFocus(sel);
}).finish();
break;
} }
if (cur instanceof DbgModelTargetObject) { if (cur instanceof AbstractTargetObject) {
DbgModelTargetObject def = (DbgModelTargetObject) cur; AbstractTargetObject<?> def = (AbstractTargetObject<?>) cur;
cur = def.getImplParent(); cur = def.getImplParent();
continue; continue;
} }
throw new AssertionError(); throw new AssertionError();
} }
seq.exit(); return AsyncUtils.NIL;
}).finish(); });
} }
} }

View file

@ -108,6 +108,7 @@ public interface DbgModelTargetBreakpointSpec extends //
} }
map.put(AFFECTS_ATTRIBUTE_NAME, doGetAffects()); map.put(AFFECTS_ATTRIBUTE_NAME, doGetAffects());
map.put(SPEC_ATTRIBUTE_NAME, this); map.put(SPEC_ATTRIBUTE_NAME, this);
map.put(EXPRESSION_ATTRIBUTE_NAME, addstr);
map.put(KINDS_ATTRIBUTE_NAME, getKinds()); map.put(KINDS_ATTRIBUTE_NAME, getKinds());
map.put(BPT_INDEX_ATTRIBUTE_NAME, Long.decode(idstr)); map.put(BPT_INDEX_ATTRIBUTE_NAME, Long.decode(idstr));
map.put(ENABLED_ATTRIBUTE_NAME, enstr.equals("-1")); map.put(ENABLED_ATTRIBUTE_NAME, enstr.equals("-1"));

View file

@ -21,7 +21,6 @@ import agent.dbgeng.dbgeng.DebugProcessId;
import agent.dbgeng.dbgeng.DebugSystemObjects; import agent.dbgeng.dbgeng.DebugSystemObjects;
import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgEventsListenerAdapter;
import agent.dbgeng.manager.DbgProcess; import agent.dbgeng.manager.DbgProcess;
import agent.dbgeng.manager.cmd.DbgProcessSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.*; import agent.dbgeng.model.iface1.*;
import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetAggregate;
@ -77,6 +76,6 @@ public interface DbgModelTargetProcess extends //
if (process == null) { if (process == null) {
process = manager.getEventProcess(); process = manager.getEventProcess();
} }
return manager.execute(new DbgProcessSelectCommand(manager, process)); return manager.selectProcess(process);
} }
} }

View file

@ -24,10 +24,10 @@ import agent.dbgeng.manager.DbgThread;
import agent.dbgeng.manager.impl.*; import agent.dbgeng.manager.impl.*;
import ghidra.async.AsyncUtils; import ghidra.async.AsyncUtils;
import ghidra.async.TypeSpec; import ghidra.async.TypeSpec;
import ghidra.dbg.error.DebuggerModelAccessException;
import ghidra.dbg.error.DebuggerRegisterAccessException; import ghidra.dbg.error.DebuggerRegisterAccessException;
import ghidra.dbg.target.TargetRegisterBank; import ghidra.dbg.target.TargetRegisterBank;
import ghidra.dbg.util.ConversionUtils; import ghidra.dbg.util.ConversionUtils;
import ghidra.util.Msg;
import ghidra.util.datastruct.ListenerSet; import ghidra.util.datastruct.ListenerSet;
public interface DbgModelTargetRegisterBank public interface DbgModelTargetRegisterBank
@ -40,7 +40,7 @@ public interface DbgModelTargetRegisterBank
Collection<String> names) { Collection<String> names) {
DbgManagerImpl manager = getManager(); DbgManagerImpl manager = getManager();
if (manager.isWaiting()) { if (manager.isWaiting()) {
throw new DebuggerModelAccessException( Msg.warn(this,
"Cannot process command readRegistersNamed while engine is waiting for events"); "Cannot process command readRegistersNamed while engine is waiting for events");
} }

View file

@ -21,7 +21,6 @@ import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags;
import agent.dbgeng.dbgeng.DebugSessionId; import agent.dbgeng.dbgeng.DebugSessionId;
import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgEventsListenerAdapter;
import agent.dbgeng.manager.DbgSession; import agent.dbgeng.manager.DbgSession;
import agent.dbgeng.manager.cmd.DbgSessionSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.*; import agent.dbgeng.model.iface1.*;
import ghidra.dbg.target.TargetAggregate; import ghidra.dbg.target.TargetAggregate;
@ -80,6 +79,6 @@ public interface DbgModelTargetSession extends //
if (session == null) { if (session == null) {
session = manager.getEventSession(); session = manager.getEventSession();
} }
return manager.execute(new DbgSessionSelectCommand(manager, session)); return manager.selectSession(session);
} }
} }

View file

@ -20,7 +20,6 @@ import java.util.concurrent.CompletableFuture;
import agent.dbgeng.manager.DbgEventsListenerAdapter; import agent.dbgeng.manager.DbgEventsListenerAdapter;
import agent.dbgeng.manager.DbgStackFrame; import agent.dbgeng.manager.DbgStackFrame;
import agent.dbgeng.manager.cmd.DbgThreadSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.manager.impl.DbgThreadImpl; import agent.dbgeng.manager.impl.DbgThreadImpl;
import agent.dbgeng.model.iface1.DbgModelSelectableObject; import agent.dbgeng.model.iface1.DbgModelSelectableObject;
@ -53,7 +52,7 @@ public interface DbgModelTargetStackFrame extends //
public default CompletableFuture<Void> select() { public default CompletableFuture<Void> select() {
DbgManagerImpl manager = getManager(); DbgManagerImpl manager = getManager();
DbgThreadImpl thread = manager.getCurrentThread(); DbgThreadImpl thread = manager.getCurrentThread();
return manager.execute(new DbgThreadSelectCommand(manager, thread, null)); return manager.selectThread(thread);
} }
@Override @Override

View file

@ -61,6 +61,7 @@ public class DbgModelTargetBreakpointSpecImpl extends DbgModelTargetObjectImpl
LENGTH_ATTRIBUTE_NAME, info.getSize(), // LENGTH_ATTRIBUTE_NAME, info.getSize(), //
AFFECTS_ATTRIBUTE_NAME, doGetAffects(), // AFFECTS_ATTRIBUTE_NAME, doGetAffects(), //
SPEC_ATTRIBUTE_NAME, this, // SPEC_ATTRIBUTE_NAME, this, //
EXPRESSION_ATTRIBUTE_NAME, info.getLocation(), //
KINDS_ATTRIBUTE_NAME, getKinds() // KINDS_ATTRIBUTE_NAME, getKinds() //
), reason); ), reason);
this.changeAttributes(List.of(), List.of(), Map.of( // this.changeAttributes(List.of(), List.of(), Map.of( //

View file

@ -138,7 +138,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
ByteBuffer buf = ByteBuffer.allocate(length); ByteBuffer buf = ByteBuffer.allocate(length);
long offset = address.getOffset(); long offset = address.getOffset();
if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) { if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) {
return readVirtualMemory(address, length); return manager.execute(new DbgReadMemoryCommand(manager, offset, buf, buf.remaining()))
.thenApply(set -> {
return readAssist(address, buf, offset, set);
});
} }
if (address.getAddressSpace().getName().equals("phys")) { if (address.getAddressSpace().getName().equals("phys")) {
return manager return manager
@ -199,7 +202,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
ByteBuffer buf = ByteBuffer.wrap(data); ByteBuffer buf = ByteBuffer.wrap(data);
long offset = address.getOffset(); long offset = address.getOffset();
if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) { if (!manager.isKernelMode() || address.getAddressSpace().getName().equals("ram")) {
return writeVirtualMemory(address, data); return manager.execute(new DbgWriteMemoryCommand(manager, offset, buf, buf.remaining()))
.thenAccept(___ -> {
writeAssist(address, data);
});
} }
if (address.getAddressSpace().getName().equals("phys")) { if (address.getAddressSpace().getName().equals("phys")) {
return manager return manager

View file

@ -77,6 +77,9 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl
@Override @Override
@Internal @Internal
public void libraryUnloaded(String name) { public void libraryUnloaded(String name) {
if (!modulesByName.containsKey(name)) {
return;
}
modulesByName.get(name).thenAccept(mod -> { modulesByName.get(name).thenAccept(mod -> {
getListeners().fire(TargetEventScopeListener.class) getListeners().fire(TargetEventScopeListener.class)
.event(this, null, TargetEventType.MODULE_UNLOADED, .event(this, null, TargetEventType.MODULE_UNLOADED,

View file

@ -20,13 +20,12 @@ import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.*;
import agent.dbgeng.dbgeng.DebugThreadId;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.*;
import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility; import ghidra.dbg.target.TargetAccessConditioned.TargetAccessibility;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.*;
import ghidra.util.datastruct.WeakValueHashMap; import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "ProcessContainer", elements = { // @TargetObjectSchemaInfo(name = "ProcessContainer", elements = { //
@ -106,15 +105,15 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
} }
@Override @Override
public void moduleLoaded(DbgProcess proc, String name, DbgCause cause) { public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
DbgModelTargetProcess process = getTargetProcess(proc); DbgModelTargetProcess process = getTargetProcess(proc);
process.getModules().libraryLoaded(name); process.getModules().libraryLoaded(info.toString());
} }
@Override @Override
public void moduleUnloaded(DbgProcess proc, String name, DbgCause cause) { public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
DbgModelTargetProcess process = getTargetProcess(proc); DbgModelTargetProcess process = getTargetProcess(proc);
process.getModules().libraryUnloaded(name); process.getModules().libraryUnloaded(info.toString());
} }
@Override @Override

View file

@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicReference;
import agent.dbgeng.dbgeng.DebugProcessId; import agent.dbgeng.dbgeng.DebugProcessId;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.*;
import agent.dbgeng.manager.cmd.DbgProcessSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.iface2.*;
@ -51,7 +50,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
public static final String PID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "pid"; public static final String PID_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "pid";
public static final String EXIT_CODE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "exit_code"; public static final String EXIT_CODE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "exit_code";
protected static final TargetAttachKindSet SUPPORTED_KINDS = TargetAttachKindSet.of( // public static final TargetAttachKindSet SUPPORTED_KINDS = TargetAttachKindSet.of( //
TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID); TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID);
protected static String indexProcess(DebugProcessId debugProcessId) { protected static String indexProcess(DebugProcessId debugProcessId) {
@ -226,7 +225,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
@Override @Override
public CompletableFuture<Void> select() { public CompletableFuture<Void> select() {
DbgManagerImpl manager = getManager(); DbgManagerImpl manager = getManager();
return manager.execute(new DbgProcessSelectCommand(manager, process)); return manager.selectProcess(process);
} }
@Override @Override

View file

@ -28,6 +28,7 @@ import ghidra.async.TypeSpec;
import ghidra.dbg.error.DebuggerUserException; import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.*; import ghidra.dbg.target.*;
import ghidra.dbg.target.schema.*; import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "Debugger", elements = { // @TargetObjectSchemaInfo(name = "Debugger", elements = { //
@TargetElementType(type = Void.class) // @TargetElementType(type = Void.class) //
@ -61,7 +62,10 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
connectors, // connectors, //
sessions // sessions //
), Map.of( // ), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, true, //
DISPLAY_ATTRIBUTE_NAME, "Debugger", // DISPLAY_ATTRIBUTE_NAME, "Debugger", //
FOCUS_ATTRIBUTE_NAME, this, //
SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, DbgModelTargetProcessImpl.SUPPORTED_KINDS, //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() //
// ARCH_ATTRIBUTE_NAME, "x86_64", // // ARCH_ATTRIBUTE_NAME, "x86_64", //
// DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", //
@ -90,17 +94,7 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
if (doFire && focus != null) { if (doFire && focus != null) {
List<String> focusPath = focus.getPath(); List<String> focusPath = focus.getPath();
List<String> selPath = sel.getPath(); List<String> selPath = sel.getPath();
for (int i = 0; i < focusPath.size(); i++) { doFire = !PathUtils.isAncestor(selPath, focusPath);
if (i >= selPath.size()) {
doFire = false;
break;
}
if (!focusPath.get(i).equals(selPath.get(i))) {
doFire = true;
break;
}
}
//doFire = !focusPath.containsAll(selPath);
} }
} }
if (doFire) { if (doFire) {

View file

@ -22,7 +22,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import agent.dbgeng.manager.*; import agent.dbgeng.manager.*;
import agent.dbgeng.manager.cmd.DbgThreadSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope; import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import agent.dbgeng.model.iface2.*; import agent.dbgeng.model.iface2.*;
@ -151,8 +150,7 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl
@Override @Override
public CompletableFuture<Void> select() { public CompletableFuture<Void> select() {
DbgManagerImpl manager = getManager(); DbgManagerImpl manager = getManager();
return manager return manager.selectThread(thread.getThread());
.execute(new DbgThreadSelectCommand(manager, thread.getThread(), frame.getLevel()));
} }
@Override @Override

View file

@ -44,7 +44,7 @@ import ghidra.dbg.util.PathUtils;
public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetThread { implements DbgModelTargetThread {
protected static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( // public static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( //
TargetStepKind.ADVANCE, // TargetStepKind.ADVANCE, //
TargetStepKind.FINISH, // TargetStepKind.FINISH, //
TargetStepKind.LINE, // TargetStepKind.LINE, //

View file

@ -27,8 +27,8 @@ import agent.dbgmodel.dbgmodel.UnknownEx;
import agent.dbgmodel.dbgmodel.datamodel.DataModelManager1; import agent.dbgmodel.dbgmodel.datamodel.DataModelManager1;
import agent.dbgmodel.dbgmodel.debughost.DebugHostContext; import agent.dbgmodel.dbgmodel.debughost.DebugHostContext;
import agent.dbgmodel.dbgmodel.debughost.DebugHostType1; import agent.dbgmodel.dbgmodel.debughost.DebugHostType1;
import agent.dbgmodel.jna.dbgmodel.IUnknownEx;
import agent.dbgmodel.jna.dbgmodel.DbgModelNative.*; import agent.dbgmodel.jna.dbgmodel.DbgModelNative.*;
import agent.dbgmodel.jna.dbgmodel.IUnknownEx;
import agent.dbgmodel.jna.dbgmodel.main.IModelObject; import agent.dbgmodel.jna.dbgmodel.main.IModelObject;
/** /**
@ -130,6 +130,8 @@ public interface ModelObject extends UnknownEx {
ModelMethod getMethod(String name); ModelMethod getMethod(String name);
String getOriginalKey();
String getSearchKey(); String getSearchKey();
void setSearchKey(String key); void setSearchKey(String key);

View file

@ -82,7 +82,7 @@ public class HDMAUtil {
public Map<String, ModelObject> getAttributes(List<String> path) { public Map<String, ModelObject> getAttributes(List<String> path) {
ModelObject target = getTerminalModelObject(path); ModelObject target = getTerminalModelObject(path);
if (target == null) { if (target == null) {
System.err.println("(A) Null target for path=" + path); //System.err.println("(A) Null target for path=" + path);
return new HashMap<String, ModelObject>(); return new HashMap<String, ModelObject>();
} }
ModelObjectKind kind = target.getKind(); ModelObjectKind kind = target.getKind();
@ -102,7 +102,7 @@ public class HDMAUtil {
public List<ModelObject> getElements(List<String> path) { public List<ModelObject> getElements(List<String> path) {
ModelObject target = getTerminalModelObject(path); ModelObject target = getTerminalModelObject(path);
if (target == null) { if (target == null) {
System.err.println("(C) Null target for path=" + path); //System.err.println("(C) Null target for path=" + path);
return new ArrayList<ModelObject>(); return new ArrayList<ModelObject>();
} }
ModelObjectKind kind = target.getKind(); ModelObjectKind kind = target.getKind();
@ -127,9 +127,11 @@ 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); //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)) {
@ -143,11 +145,13 @@ public class HDMAUtil {
Map<String, ModelObject> keyMap = target.getKeyValueMap(); Map<String, ModelObject> keyMap = target.getKeyValueMap();
if (keyMap.containsKey(str)) { if (keyMap.containsKey(str)) {
target = keyMap.get(str); target = keyMap.get(str);
found = true;
} }
else { else {
Map<String, ModelObject> rawMap = target.getRawValueMap(); Map<String, ModelObject> rawMap = target.getRawValueMap();
if (rawMap.containsKey(str)) { if (rawMap.containsKey(str)) {
target = rawMap.get(str); target = rawMap.get(str);
found = true;
} }
} }
if (indexStr != null) { if (indexStr != null) {
@ -155,9 +159,13 @@ public class HDMAUtil {
for (ModelObject child : children) { for (ModelObject child : children) {
if (indexStr.equals(child.getSearchKey())) { if (indexStr.equals(child.getSearchKey())) {
target = child; target = child;
found = true;
} }
} }
} }
if (found == false) {
return null;
}
} }
return target; return target;
} }

View file

@ -898,6 +898,19 @@ public class ModelObjectImpl implements ModelObjectInternal {
@Override @Override
public String getSearchKey() { public String getSearchKey() {
if (key == null) {
throw new RuntimeException("null key for " + this);
}
Map<String, ModelObject> map = getKeyValueMap();
if (map.containsKey("BaseAddress")) {
String valueString = map.get("BaseAddress").getValueString();
return valueString;
}
return key;
}
@Override
public String getOriginalKey() {
if (key == null) { if (key == null) {
throw new RuntimeException("null key for " + this); throw new RuntimeException("null key for " + this);
} }

View file

@ -23,8 +23,7 @@ import agent.dbgeng.model.iface2.DbgModelTargetObject;
import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.dbgmodel.main.ModelObject;
import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.gadp.impl.WrappedDbgModel;
import agent.dbgmodel.manager.DbgManager2Impl; import agent.dbgmodel.manager.DbgManager2Impl;
import agent.dbgmodel.model.impl.DbgModel2TargetObjectImpl; import agent.dbgmodel.model.impl.*;
import agent.dbgmodel.model.impl.DelegateDbgModel2TargetObject;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
public class DbgListAttributesCommand extends AbstractDbgCommand<Map<String, ?>> { public class DbgListAttributesCommand extends AbstractDbgCommand<Map<String, ?>> {
@ -54,20 +53,19 @@ public class DbgListAttributesCommand extends AbstractDbgCommand<Map<String, ?>>
Map<String, ModelObject> map = access.getAttributes(path); Map<String, ModelObject> map = access.getAttributes(path);
Map<String, ?> existingAttributes = targetObject.getCachedAttributes(); Map<String, ?> existingAttributes = targetObject.getCachedAttributes();
for (String key : map.keySet()) { for (String key : map.keySet()) {
DbgModelTargetObject proxyAttribute; DbgModel2TargetProxy proxyAttribute;
ModelObject obj = map.get(key); ModelObject obj = map.get(key);
Object object = existingAttributes.get(key); String atKey = obj.getSearchKey();
Object object = existingAttributes.get(atKey);
if (object != null && (object instanceof DbgModelTargetObject)) { if (object != null && (object instanceof DbgModelTargetObject)) {
proxyAttribute = (DbgModelTargetObject) object; proxyAttribute = (DbgModel2TargetProxy) object;
DelegateDbgModel2TargetObject delegate = DelegateDbgModel2TargetObject delegate = proxyAttribute.getDelegate();
DelegateDbgModel2TargetObject.getDelegate(proxyAttribute);
delegate.setModelObject(obj); delegate.setModelObject(obj);
updatedAttributes.put(key, proxyAttribute); updatedAttributes.put(key, proxyAttribute);
} }
else { else {
String atKey = obj.getSearchKey(); proxyAttribute = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject
proxyAttribute = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(), .makeProxy(targetObject.getModel(), targetObject, atKey, obj);
targetObject, atKey, obj);
updatedAttributes.put(key, proxyAttribute); updatedAttributes.put(key, proxyAttribute);
} }
} }

View file

@ -19,14 +19,13 @@ import java.util.*;
import agent.dbgeng.manager.cmd.AbstractDbgCommand; import agent.dbgeng.manager.cmd.AbstractDbgCommand;
import agent.dbgeng.manager.cmd.DbgPendingCommand; import agent.dbgeng.manager.cmd.DbgPendingCommand;
import agent.dbgeng.model.iface2.DbgModelTargetObject;
import agent.dbgmodel.dbgmodel.main.ModelObject; import agent.dbgmodel.dbgmodel.main.ModelObject;
import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.gadp.impl.WrappedDbgModel;
import agent.dbgmodel.manager.DbgManager2Impl; import agent.dbgmodel.manager.DbgManager2Impl;
import agent.dbgmodel.model.impl.DbgModel2TargetObjectImpl; import agent.dbgmodel.model.impl.*;
import agent.dbgmodel.model.impl.DelegateDbgModel2TargetObject;
import ghidra.dbg.attributes.TargetObjectRef; import ghidra.dbg.attributes.TargetObjectRef;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
import ghidra.dbg.util.PathUtils;
public class DbgListElementsCommand extends AbstractDbgCommand<List<TargetObject>> { public class DbgListElementsCommand extends AbstractDbgCommand<List<TargetObject>> {
@ -51,23 +50,27 @@ public class DbgListElementsCommand extends AbstractDbgCommand<List<TargetObject
@Override @Override
public void invoke() { public void invoke() {
synchronized (access) {
updatedElements = new ArrayList<>(); updatedElements = new ArrayList<>();
List<ModelObject> list = access.getElements(path); List<ModelObject> list = access.getElements(path);
Map<String, ? extends TargetObjectRef> existingElements = targetObject.getCachedElements(); Map<String, ? extends TargetObjectRef> existingElements =
targetObject.getCachedElements();
for (ModelObject obj : list) { for (ModelObject obj : list) {
DbgModelTargetObject proxyElement; DbgModel2TargetProxy proxyElement;
if (existingElements.containsKey(obj.getSearchKey())) { String searchKey = obj.getSearchKey();
proxyElement = (DbgModelTargetObject) existingElements.get(obj.getSearchKey()); String elKey = PathUtils.makeKey(searchKey);
DelegateDbgModel2TargetObject delegate = if (existingElements.containsKey(searchKey)) {
DelegateDbgModel2TargetObject.getDelegate(proxyElement); proxyElement = (DbgModel2TargetProxy) existingElements.get(searchKey);
DelegateDbgModel2TargetObject delegate = proxyElement.getDelegate();
delegate.setModelObject(obj); delegate.setModelObject(obj);
} }
else { else {
String elKey = DbgModel2TargetObjectImpl.keyObject(obj); proxyElement = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject
proxyElement = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(), .makeProxy(targetObject.getModel(), targetObject, elKey, obj);
targetObject, elKey, obj);
} }
updatedElements.add(proxyElement); updatedElements.add(proxyElement);
} }
} }
}
} }

View file

@ -22,12 +22,11 @@ import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import agent.dbgeng.dbgeng.*; import agent.dbgeng.dbgeng.DebugClient;
import agent.dbgeng.manager.DbgCause.Causes; import agent.dbgeng.manager.DbgCause.Causes;
import agent.dbgeng.manager.DbgState; import agent.dbgeng.manager.DbgState;
import agent.dbgeng.manager.impl.*; import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgmodel.dbgmodel.DbgModel; import agent.dbgmodel.dbgmodel.DbgModel;
import agent.dbgmodel.dbgmodel.main.ModelObject;
import agent.dbgmodel.gadp.impl.DbgModelClientThreadExecutor; import agent.dbgmodel.gadp.impl.DbgModelClientThreadExecutor;
import agent.dbgmodel.gadp.impl.WrappedDbgModel; import agent.dbgmodel.gadp.impl.WrappedDbgModel;
import agent.dbgmodel.jna.cmd.*; import agent.dbgmodel.jna.cmd.*;
@ -108,6 +107,7 @@ public class DbgManager2Impl extends DbgManagerImpl {
return execute(new DbgGetRegisterMapCommand(this, path)); return execute(new DbgGetRegisterMapCommand(this, path));
} }
/*
@Override @Override
public DbgSessionImpl getCurrentSession() { public DbgSessionImpl getCurrentSession() {
ModelObject currentSession = dbgmodel.getUtil().getCurrentSession(); ModelObject currentSession = dbgmodel.getUtil().getCurrentSession();
@ -133,5 +133,6 @@ public class DbgManager2Impl extends DbgManagerImpl {
return threads.get(id); return threads.get(id);
} }
} }
*/
} }

View file

@ -27,7 +27,6 @@ import agent.dbgmodel.manager.DbgManager2Impl;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.target.schema.XmlSchemaContext; import ghidra.dbg.target.schema.XmlSchemaContext;
import ghidra.framework.Application;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
public class DbgModel2Impl extends AbstractDbgModel { public class DbgModel2Impl extends AbstractDbgModel {

View file

@ -25,7 +25,7 @@ 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.*;
import agent.dbgeng.model.impl.DbgModelTargetMemoryContainerImpl; import agent.dbgeng.model.impl.*;
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;
@ -37,6 +37,7 @@ import ghidra.dbg.target.TargetBreakpointContainer.TargetBreakpointKindSet;
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind; import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.CollectionUtils.Delta;
import ghidra.dbg.util.PathUtils; import ghidra.dbg.util.PathUtils;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator; import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -58,6 +59,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
protected String DBG_PROMPT = "(kd2)"; // Used by DbgModelTargetEnvironment protected String DBG_PROMPT = "(kd2)"; // Used by DbgModelTargetEnvironment
protected boolean fireAttributesChanged = false;
protected static String indexObject(ModelObject obj) { protected static String indexObject(ModelObject obj) {
return obj.getSearchKey(); return obj.getSearchKey();
} }
@ -101,6 +104,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override @Override
public CompletableFuture<Void> requestElements(boolean refresh) { public CompletableFuture<Void> requestElements(boolean refresh) {
synchronized (elements) {
List<TargetObject> nlist = new ArrayList<>(); List<TargetObject> nlist = new ArrayList<>();
return requestNativeElements().thenCompose(list -> { return requestNativeElements().thenCompose(list -> {
for (TargetObject element : elements.values()) { for (TargetObject element : elements.values()) {
@ -114,23 +118,19 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
} }
} }
nlist.addAll(list); nlist.addAll(list);
int order = 0;
for (TargetObject targetObject : nlist) {
DbgModelTargetObject to = (DbgModelTargetObject) targetObject;
to.changeAttributes(List.of(), Map.of( //
ORDER_ATTRIBUTE_NAME, order++ //
), "Initialized");
}
return processModelObjectElements(nlist); return processModelObjectElements(nlist);
}).thenAccept(__ -> { }).thenAccept(__ -> {
setElements(nlist, Map.of(), "Refreshed"); setElements(nlist, Map.of(), "Refreshed");
}); });
} }
}
@Override @Override
public CompletableFuture<Void> requestAttributes(boolean refresh) { public CompletableFuture<Void> requestAttributes(boolean refresh) {
fireAttributesChanged = true;
Map<String, Object> nmap = new HashMap<>(); Map<String, Object> nmap = new HashMap<>();
return requestNativeAttributes().thenCompose(map -> { return requestNativeAttributes().thenCompose(map -> {
synchronized (attributes) {
if (map != null) { if (map != null) {
Collection<?> values = map.values(); Collection<?> values = map.values();
for (Object attribute : attributes.values()) { for (Object attribute : attributes.values()) {
@ -146,6 +146,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
nmap.putAll(map); nmap.putAll(map);
} }
return addModelObjectAttributes(nmap); return addModelObjectAttributes(nmap);
}
}).thenAccept(__ -> { }).thenAccept(__ -> {
setAttributes(List.of(), nmap, "Refreshed"); setAttributes(List.of(), nmap, "Refreshed");
}); });
@ -161,9 +162,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
private CompletableFuture<Void> processElement(TargetObject targetObject) { private CompletableFuture<Void> processElement(TargetObject targetObject) {
if (targetObject instanceof DbgModelTargetObject) { if (targetObject instanceof DbgModelTargetObject) {
DbgModelTargetObject proxy = (DbgModelTargetObject) targetObject; DbgModel2TargetProxy proxy = (DbgModel2TargetProxy) targetObject;
DelegateDbgModel2TargetObject delegate = DelegateDbgModel2TargetObject delegate = proxy.getDelegate();
DelegateDbgModel2TargetObject.getDelegate(proxy);
if (proxy instanceof TargetStackFrame || // if (proxy instanceof TargetStackFrame || //
proxy instanceof TargetModule || // proxy instanceof TargetModule || //
proxy instanceof TargetBreakpointSpec) { proxy instanceof TargetBreakpointSpec) {
@ -193,11 +193,13 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (value != null && !value.equals("")) { if (value != null && !value.equals("")) {
attrs.put(VALUE_ATTRIBUTE_NAME, value); attrs.put(VALUE_ATTRIBUTE_NAME, value);
if (!kind.equals(ModelObjectKind.OBJECT_PROPERTY_ACCESSOR)) { if (!kind.equals(ModelObjectKind.OBJECT_PROPERTY_ACCESSOR)) {
synchronized (attributes) {
String oldval = (String) attributes.get(DISPLAY_ATTRIBUTE_NAME); String oldval = (String) attributes.get(DISPLAY_ATTRIBUTE_NAME);
String newval = getName() + " : " + value; String newval = getName() + " : " + value;
attrs.put(DISPLAY_ATTRIBUTE_NAME, newval); attrs.put(DISPLAY_ATTRIBUTE_NAME, newval);
setModified(attrs, !newval.equals(oldval)); setModified(attrs, !newval.equals(oldval));
} }
}
if (tk == null) { if (tk == null) {
Object val = modelObject.getIntrinsicValue(); Object val = modelObject.getIntrinsicValue();
if (val != null) { if (val != null) {
@ -208,11 +210,23 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (this instanceof DelegateDbgModel2TargetObject) { if (this instanceof DelegateDbgModel2TargetObject) {
DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) this; DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) this;
TargetObject proxy = delegate.getProxy(); TargetObject proxy = delegate.getProxy();
if (proxy instanceof TargetAccessConditioned) {
attrs.put(TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME,
accessibility == TargetAccessibility.ACCESSIBLE);
}
if (proxy instanceof TargetExecutionStateful) { if (proxy instanceof TargetExecutionStateful) {
TargetExecutionStateful<?> stateful = (TargetExecutionStateful<?>) proxy; TargetExecutionStateful<?> stateful = (TargetExecutionStateful<?>) proxy;
TargetExecutionState state = stateful.getExecutionState(); TargetExecutionState state = stateful.getExecutionState();
attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state); attrs.put(TargetExecutionStateful.STATE_ATTRIBUTE_NAME, state);
} }
if (proxy instanceof TargetAttacher) {
attrs.put(TargetAttacher.SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME,
DbgModelTargetProcessImpl.SUPPORTED_KINDS);
}
if (proxy instanceof TargetSteppable) {
attrs.put(TargetSteppable.SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME,
DbgModelTargetThreadImpl.SUPPORTED_KINDS);
}
if (proxy instanceof TargetInterpreter) { if (proxy instanceof TargetInterpreter) {
attrs.put(TargetInterpreter.PROMPT_ATTRIBUTE_NAME, DBG_PROMPT); attrs.put(TargetInterpreter.PROMPT_ATTRIBUTE_NAME, DBG_PROMPT);
} }
@ -230,6 +244,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
attrs.put(TargetEnvironment.OS_ATTRIBUTE_NAME, "Windows"); attrs.put(TargetEnvironment.OS_ATTRIBUTE_NAME, "Windows");
} }
if (proxy instanceof TargetModule) { if (proxy instanceof TargetModule) {
//attrs.put(TargetObject.ORDER_ATTRIBUTE_NAME,
// Integer.decode(modelObject.getOriginalKey()));
DbgModelTargetModule module = (DbgModelTargetModule) proxy; DbgModelTargetModule module = (DbgModelTargetModule) proxy;
return module.init(attrs); return module.init(attrs);
} }
@ -272,6 +288,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override @Override
public CompletableFuture<?> fetchChild(final String key) { public CompletableFuture<?> fetchChild(final String key) {
synchronized (elements) {
if (key.startsWith("[") && key.endsWith("]")) { if (key.startsWith("[") && key.endsWith("]")) {
String trimKey = key.substring(1, key.length() - 1); String trimKey = key.substring(1, key.length() - 1);
if (elements.containsKey(trimKey)) { if (elements.containsKey(trimKey)) {
@ -279,6 +296,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
} }
return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey)); return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey));
} }
}
synchronized (attributes) {
if (attributes.containsKey(key)) { if (attributes.containsKey(key)) {
return CompletableFuture.completedFuture(attributes.get(key)); return CompletableFuture.completedFuture(attributes.get(key));
} }
@ -295,6 +314,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
} }
return requestAttributes(true).thenApply(__ -> getCachedAttribute(key)); return requestAttributes(true).thenApply(__ -> getCachedAttribute(key));
} }
}
//@Override //@Override
//public TargetAccessibility getAccessibility() { //public TargetAccessibility getAccessibility() {
@ -378,9 +398,55 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override @Override
public void resetModified() { public void resetModified() {
if (getCachedAttribute(MODIFIED_ATTRIBUTE_NAME) != null) {
changeAttributes(List.of(), List.of(), Map.of( // changeAttributes(List.of(), List.of(), Map.of( //
MODIFIED_ATTRIBUTE_NAME, false // MODIFIED_ATTRIBUTE_NAME, false //
), "Refreshed"); ), "Refreshed");
} }
}
// NB: We're overriding these to prevent events being added as newly added elements
// initialize and pull the attributes needed for their display
@Override
public Delta<?, ?> setAttributes(Map<String, ?> attributes, String reason) {
Delta<?, ?> delta;
synchronized (this.attributes) {
delta = Delta.computeAndSet(this.attributes, attributes, Delta.EQUAL);
}
TargetObjectSchema schemax = getSchema();
if (schemax != null) {
schemax.validateAttributeDelta(getPath(), delta, enforcesStrictSchema());
}
doInvalidateAttributes(delta.removed, reason);
if (parent == null && !delta.isEmpty()) {
listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added);
return delta;
}
if (fireAttributesChanged && !delta.isEmpty()) {
listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added);
}
return delta;
}
@Override
public Delta<?, ?> changeAttributes(List<String> remove, Map<String, ?> add, String reason) {
Delta<?, ?> delta;
synchronized (attributes) {
delta = Delta.apply(this.attributes, remove, add, Delta.EQUAL);
}
TargetObjectSchema schemax = getSchema();
if (schemax != null) {
schemax.validateAttributeDelta(getPath(), delta, enforcesStrictSchema());
}
doInvalidateAttributes(delta.removed, reason);
if (fireAttributesChanged && !delta.isEmpty()) {
listeners.fire.attributesChanged(getProxy(), delta.getKeysRemoved(), delta.added);
}
return delta;
}
@Override
protected boolean enforcesStrictSchema() {
return false;
}
} }

View file

@ -0,0 +1,24 @@
/* ###
* 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.dbgmodel.model.impl;
import agent.dbgeng.model.iface2.DbgModelTargetObject;
public interface DbgModel2TargetProxy extends DbgModelTargetObject {
public DelegateDbgModel2TargetObject getDelegate();
}

View file

@ -26,6 +26,7 @@ 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.*;
import agent.dbgeng.model.impl.DbgModelTargetConnectorContainerImpl; import agent.dbgeng.model.impl.DbgModelTargetConnectorContainerImpl;
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;
@ -59,7 +60,9 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
connectors, // connectors, //
systemMarker // systemMarker //
), Map.of( // ), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, true, //
DISPLAY_ATTRIBUTE_NAME, "Debugger", // DISPLAY_ATTRIBUTE_NAME, "Debugger", //
FOCUS_ATTRIBUTE_NAME, this, //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() //
// ARCH_ATTRIBUTE_NAME, "x86_64", // // ARCH_ATTRIBUTE_NAME, "x86_64", //
// DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", //
@ -82,7 +85,9 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
connectors, // connectors, //
systemMarker // systemMarker //
), Map.of( // ), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, true, //
DISPLAY_ATTRIBUTE_NAME, "Debugger", // DISPLAY_ATTRIBUTE_NAME, "Debugger", //
FOCUS_ATTRIBUTE_NAME, this, //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() // TargetMethod.PARAMETERS_ATTRIBUTE_NAME, defaultConnector.getParameters() //
// ARCH_ATTRIBUTE_NAME, "x86_64", // // ARCH_ATTRIBUTE_NAME, "x86_64", //
// DEBUGGER_ATTRIBUTE_NAME, "dbgeng", // // DEBUGGER_ATTRIBUTE_NAME, "dbgeng", //
@ -99,21 +104,12 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
if (doFire && focus != null) { if (doFire && focus != null) {
List<String> focusPath = focus.getPath(); List<String> focusPath = focus.getPath();
List<String> selPath = sel.getPath(); List<String> selPath = sel.getPath();
for (int i = 0; i < focusPath.size(); i++) { doFire = !PathUtils.isAncestor(selPath, focusPath);
if (i >= selPath.size()) {
doFire = false;
break;
}
if (!focusPath.get(i).equals(selPath.get(i))) {
doFire = true;
break;
}
}
//doFire = !focusPath.containsAll(selPath);
} }
} }
if (doFire) { if (doFire) {
this.focus = sel; this.focus = sel;
fireAttributesChanged = true;
changeAttributes(List.of(), List.of(), Map.of( // changeAttributes(List.of(), List.of(), Map.of( //
TargetFocusScope.FOCUS_ATTRIBUTE_NAME, focus // TargetFocusScope.FOCUS_ATTRIBUTE_NAME, focus //
), "Focus changed"); ), "Focus changed");
@ -201,28 +197,28 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
} }
@Override @Override
public void moduleLoaded(DbgProcess proc, String name, DbgCause cause) { public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
getObject(proc, List.of("Modules"), name).thenAccept(obj -> { getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> {
DbgModelTargetModule mod = (DbgModelTargetModule) obj; DbgModelTargetModule mod = (DbgModelTargetModule) obj;
if (mod == null) { if (mod == null) {
return; return;
} }
getListeners().fire(TargetEventScopeListener.class) getListeners().fire(TargetEventScopeListener.class)
.event(this, null, TargetEventType.MODULE_LOADED, "Library " + name + " loaded", .event(this, null, TargetEventType.MODULE_LOADED,
List.of(mod)); "Library " + info.moduleName + " loaded", List.of(mod));
}); });
} }
@Override @Override
public void moduleUnloaded(DbgProcess proc, String name, DbgCause cause) { public void moduleUnloaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
getObject(proc, List.of("Modules"), name).thenAccept(obj -> { getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> {
DbgModelTargetModule mod = (DbgModelTargetModule) obj; DbgModelTargetModule mod = (DbgModelTargetModule) obj;
if (mod == null) { if (mod == null) {
return; return;
} }
getListeners().fire(TargetEventScopeListener.class) getListeners().fire(TargetEventScopeListener.class)
.event(this, null, TargetEventType.MODULE_UNLOADED, .event(this, null, TargetEventType.MODULE_UNLOADED,
"Library " + name + " unloaded", List.of(mod)); "Library " + info.moduleName + " unloaded", List.of(mod));
}); });
} }
@ -241,8 +237,8 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
}).finish(); }).finish();
} }
private CompletableFuture<DbgModelTargetObject> getObject(Object object, List<String> ext, private CompletableFuture<DbgModelTargetObject> getObjectRevisited(Object object,
String name) { List<String> ext, Object info) {
List<String> objPath = findObject(object); List<String> objPath = findObject(object);
if (objPath == null) { if (objPath == null) {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
@ -257,19 +253,23 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
seq.exit(); seq.exit();
return; return;
} }
DbgModelTargetObject proxy = (DbgModelTargetObject) pobj; DbgModel2TargetProxy proxy = (DbgModel2TargetProxy) pobj;
DelegateDbgModel2TargetObject delegate = DelegateDbgModel2TargetObject delegate = proxy.getDelegate();
DelegateDbgModel2TargetObject.getDelegate(proxy);
delegate.requestElements(true).thenAccept(__ -> { xpath.add(0, "Debugger");
Map<String, TargetObject> cachedElements = delegate.getCachedElements(); DbgManager2Impl manager = (DbgManager2Impl) getManager();
for (TargetObject val : cachedElements.values()) { List<ModelObject> list = manager.getAccess().getElements(xpath);
DbgModelTargetObject obj = (DbgModelTargetObject) val; for (ModelObject obj : list) {
if (obj.getDisplay().contains(name)) { String searchKey = obj.getSearchKey();
seq.exit(obj); if (searchKey.equals(info.toString())) {
String elKey = PathUtils.makeKey(searchKey);
DbgModel2TargetProxy proxyElement =
(DbgModel2TargetProxy) DelegateDbgModel2TargetObject
.makeProxy(delegate.getModel(), delegate, elKey, obj);
delegate.changeElements(List.of(), List.of(proxyElement), "Created");
seq.exit(proxyElement);
} }
} }
seq.exit((DbgModelTargetObject) null);
});
}).finish(); }).finish();
} }
@ -350,17 +350,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
public void breakpointCreated(DbgBreakpointInfo info, DbgCause cause) { public void breakpointCreated(DbgBreakpointInfo info, DbgCause cause) {
int id = info.getDebugBreakpoint().getId(); int id = info.getDebugBreakpoint().getId();
bptInfoMap.put(id, info); bptInfoMap.put(id, info);
getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info);
/*
getObject(info).thenAccept(obj -> {
DbgModelTargetBreakpointSpec bpt = (DbgModelTargetBreakpointSpec) obj;
if (bpt == null) {
return;
}
bpt.setBreakpointInfo(info);
bpt.setEnabled(true, "Created");
});
*/
} }
@Override @Override
@ -368,20 +358,19 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
DbgCause cause) { DbgCause cause) {
int id = newInfo.getDebugBreakpoint().getId(); int id = newInfo.getDebugBreakpoint().getId();
bptInfoMap.put(id, newInfo); bptInfoMap.put(id, newInfo);
getObject(newInfo.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); getObjectRevisited(newInfo.getProc(), List.of("Debug", "Breakpoints"), newInfo);
} }
@Override @Override
public void breakpointDeleted(DbgBreakpointInfo info, DbgCause cause) { public void breakpointDeleted(DbgBreakpointInfo info, DbgCause cause) {
int id = info.getDebugBreakpoint().getId(); int id = info.getDebugBreakpoint().getId();
bptInfoMap.remove(id); bptInfoMap.remove(id);
getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id)); getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info);
} }
@Override @Override
public void breakpointHit(DbgBreakpointInfo info, DbgCause cause) { public void breakpointHit(DbgBreakpointInfo info, DbgCause cause) {
int id = info.getDebugBreakpoint().getId(); getObjectRevisited(info.getProc(), List.of("Debug", "Breakpoints"), info)
getObject(info.getProc(), List.of("Debug", "Breakpoints"), Integer.toHexString(id))
.thenAccept(obj -> { .thenAccept(obj -> {
DbgModelTargetBreakpointSpec bpt = (DbgModelTargetBreakpointSpec) obj; DbgModelTargetBreakpointSpec bpt = (DbgModelTargetBreakpointSpec) obj;
if (bpt == null) { if (bpt == null) {

View file

@ -39,7 +39,7 @@ import utilities.util.ProxyUtilities;
public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl implements // public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl implements //
DbgModelTargetAccessConditioned<DelegateDbgModel2TargetObject>, // DbgModelTargetAccessConditioned<DelegateDbgModel2TargetObject>, //
DbgModelTargetExecutionStateful<DelegateDbgModel2TargetObject>, // DbgModelTargetExecutionStateful<DelegateDbgModel2TargetObject>, //
DbgModelTargetBptHelper { DbgModel2TargetProxy, DbgModelTargetBptHelper {
// Probably don-t need any of the handler-map or annotation stuff // Probably don-t need any of the handler-map or annotation stuff
protected final DbgStateListener accessListener = this::checkExited; protected final DbgStateListener accessListener = this::checkExited;
@ -163,12 +163,6 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
return new DelegateDbgModel2TargetObject(model, parent, key, object, mixins).proxy; return new DelegateDbgModel2TargetObject(model, parent, key, object, mixins).proxy;
} }
private static Map<DbgModelTargetObject, DelegateDbgModel2TargetObject> map = new HashMap<>();
public static DelegateDbgModel2TargetObject getDelegate(DbgModelTargetObject proxy) {
return map.get(proxy);
}
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
@ -201,15 +195,27 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
getManager().addStateListener(accessListener); getManager().addStateListener(accessListener);
mixins.add(DbgModel2TargetProxy.class);
this.proxy = this.proxy =
ProxyUtilities.composeOnDelegate(DbgModelTargetObject.class, this, mixins, LOOKUP); ProxyUtilities.composeOnDelegate(DbgModelTargetObject.class, this, mixins, LOOKUP);
map.put(proxy, this);
if (proxy instanceof DbgEventsListener) { if (proxy instanceof DbgEventsListener) {
model.getManager().addEventsListener((DbgEventsListener) proxy); model.getManager().addEventsListener((DbgEventsListener) proxy);
} }
setModelObject(modelObject); setModelObject(modelObject);
} }
public DelegateDbgModel2TargetObject clone(String key, ModelObject modelObject) {
DbgModelTargetObject p = (DbgModelTargetObject) getImplParent();
List<Class<? extends TargetObject>> mixins = new ArrayList<>();
Class<? extends DbgModelTargetObject> mixin = lookupWrapperType(key, p.getName());
if (mixin != null) {
mixins.add(mixin);
}
DelegateDbgModel2TargetObject delegate =
new DelegateDbgModel2TargetObject(getModel(), p, key, modelObject, mixins);
return delegate;
}
@Override @Override
public <T extends TypedTargetObject<T>> T as(Class<T> iface) { public <T extends TypedTargetObject<T>> T as(Class<T> iface) {
return DebuggerObjectModel.requireIface(iface, proxy, getPath()); return DebuggerObjectModel.requireIface(iface, proxy, getPath());
@ -348,6 +354,10 @@ public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl imp
} }
} }
public DelegateDbgModel2TargetObject getDelegate() {
return this;
}
// Methods required for DbgModelTargetBreakpointSpec mixin // Methods required for DbgModelTargetBreakpointSpec mixin
@Override @Override

View file

@ -17,7 +17,6 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_supported_attach_kinds" schema="SET_ATTACH_KIND" required="yes" hidden="yes" />
<attribute name="_event_process" schema="STRING" hidden="yes" /> <attribute name="_event_process" schema="STRING" hidden="yes" />
<attribute name="_event_thread" schema="STRING" hidden="yes" /> <attribute name="_event_thread" schema="STRING" hidden="yes" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" /> <attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
@ -41,7 +40,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="ConnectorContainer" canonical="yes"> <schema name="ConnectorContainer" canonical="yes">
<element schema="OBJECT" /> <element schema="OBJECT" />
@ -135,7 +134,7 @@
<interface name="Interruptible" /> <interface name="Interruptible" />
<interface name="Resumable" /> <interface name="Resumable" />
<element schema="VOID" /> <element schema="VOID" />
<attribute name="_accessible" schema="BOOL" required="yes" hidden="yes" /> <attribute name="_accessible" schema="BOOL" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" /> <attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" /> <attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" /> <attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -154,7 +153,7 @@
<schema name="Available"> <schema name="Available">
<interface name="Attachable" /> <interface name="Attachable" />
<element schema="VOID" /> <element schema="VOID" />
<attribute name="_pid" schema="LONG" hidden="yes" /> <attribute name="_pid" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" /> <attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" /> <attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" /> <attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -182,7 +181,7 @@
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Machine" schema="SessionAttributesMachine" fixed="yes" /> <attribute name="Machine" schema="SessionAttributesMachine" fixed="yes" />
<attribute name="Target" schema="OBJECT" /> <attribute name="Target" schema="OBJECT" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="ProcessContainer" canonical="yes"> <schema name="ProcessContainer" canonical="yes">
<interface name="EventScope" /> <interface name="EventScope" />
@ -197,7 +196,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="SessionAttributesMachine"> <schema name="SessionAttributesMachine">
<element schema="VOID" /> <element schema="VOID" />
@ -213,7 +212,7 @@
<attribute name="Debugger" schema="STRING" /> <attribute name="Debugger" schema="STRING" />
<attribute name="OS" schema="STRING" /> <attribute name="OS" schema="STRING" />
<attribute name="Mode" schema="STRING" /> <attribute name="Mode" schema="STRING" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="Process"> <schema name="Process">
<interface name="Aggregate" /> <interface name="Aggregate" />
@ -242,7 +241,6 @@
<attribute name="_state" schema="EXECUTION_STATE" required="yes" hidden="yes" /> <attribute name="_state" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute name="_accessible" schema="BOOL" required="yes" hidden="yes" /> <attribute name="_accessible" schema="BOOL" required="yes" hidden="yes" />
<attribute name="_supported_attach_kinds" schema="SET_ATTACH_KIND" required="yes" hidden="yes" /> <attribute name="_supported_attach_kinds" schema="SET_ATTACH_KIND" required="yes" hidden="yes" />
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
<attribute name="_supported_step_kinds" schema="SET_STEP_KIND" required="yes" fixed="yes" hidden="yes" /> <attribute name="_supported_step_kinds" schema="SET_STEP_KIND" required="yes" fixed="yes" hidden="yes" />
<attribute name="Debug" schema="DebugContainer" required="yes" fixed="yes" /> <attribute name="Debug" schema="DebugContainer" required="yes" fixed="yes" />
<attribute name="Memory" schema="Memory" required="yes" fixed="yes" /> <attribute name="Memory" schema="Memory" required="yes" fixed="yes" />
@ -253,8 +251,8 @@
<attribute name="Handle" schema="OBJECT" /> <attribute name="Handle" schema="OBJECT" />
<attribute name="Id" schema="OBJECT" /> <attribute name="Id" schema="OBJECT" />
<attribute name="Io" schema="OBJECT" /> <attribute name="Io" schema="OBJECT" />
<attribute name="Name" schema="STRING" /> <attribute name="Name" schema="OBJECT" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="Memory" canonical="yes"> <schema name="Memory" canonical="yes">
<interface name="Memory" /> <interface name="Memory" />
@ -267,7 +265,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="ModuleContainer" canonical="yes"> <schema name="ModuleContainer" canonical="yes">
<interface name="ModuleContainer" /> <interface name="ModuleContainer" />
@ -284,7 +282,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="DebugContainer" canonical="yes"> <schema name="DebugContainer" canonical="yes">
<element schema="OBJECT" /> <element schema="OBJECT" />
@ -297,7 +295,7 @@
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="yes" /> <attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="ThreadContainer" canonical="yes"> <schema name="ThreadContainer" canonical="yes">
<interface name="EventScope" /> <interface name="EventScope" />
@ -312,7 +310,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="MemoryRegion"> <schema name="MemoryRegion">
<interface name="MemoryRegion" /> <interface name="MemoryRegion" />
@ -362,9 +360,9 @@
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" /> <attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
<attribute name="Environment" schema="OBJECT" /> <attribute name="Environment" schema="OBJECT" />
<attribute name="Id" schema="OBJECT" /> <attribute name="Id" schema="OBJECT" />
<attribute name="Name" schema="STRING" /> <attribute name="Name" schema="OBJECT" />
<attribute name="_arch" schema="STRING" /> <attribute name="_arch" schema="STRING" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="Module"> <schema name="Module">
<interface name="Module" /> <interface name="Module" />
@ -379,12 +377,13 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Symbols" schema="SymbolContainer" required="yes" fixed="yes" /> <attribute name="BaseAddress" schema="OBJECT" />
<attribute name="BaseAddress" schema="ADDRESS" /> <attribute name="ImageName" schema="OBJECT" />
<attribute name="ImageName" schema="STRING" /> <attribute name="TimeStamp" schema="OBJECT" />
<attribute name="TimeStamp" schema="INT" /> <attribute name="Len" schema="OBJECT" />
<attribute name="Len" schema="STRING" /> <attribute name="Name" schema="OBJECT" />
<attribute schema="VOID" /> <attribute name="Size" schema="OBJECT" />
<attribute schema="ANY" />
</schema> </schema>
<schema name="BreakpointContainer" canonical="yes"> <schema name="BreakpointContainer" canonical="yes">
<interface name="BreakpointContainer" /> <interface name="BreakpointContainer" />
@ -398,7 +397,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="SymbolContainer" canonical="yes"> <schema name="SymbolContainer" canonical="yes">
<interface name="SymbolNamespace" /> <interface name="SymbolNamespace" />
@ -411,7 +410,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="RegisterContainer" canonical="yes"> <schema name="RegisterContainer" canonical="yes">
<interface name="RegisterContainer" /> <interface name="RegisterContainer" />
@ -430,7 +429,7 @@
<attribute name="SIMD" schema="OBJECT" /> <attribute name="SIMD" schema="OBJECT" />
<attribute name="User" schema="RegisterBank" /> <attribute name="User" schema="RegisterBank" />
<attribute name="VFP" schema="OBJECT" /> <attribute name="VFP" schema="OBJECT" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="RegisterBank"> <schema name="RegisterBank">
<interface name="RegisterBank" /> <interface name="RegisterBank" />
@ -447,6 +446,19 @@
<attribute schema="OBJECT" /> <attribute schema="OBJECT" />
</schema> </schema>
<schema name="Stack" canonical="yes"> <schema name="Stack" canonical="yes">
<element schema="VOID" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_update_mode" schema="UPDATE_MODE" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Frames" schema="Frames" />
<attribute schema="ANY" />
</schema>
<schema name="Frames" canonical="yes">
<interface name="Stack" /> <interface name="Stack" />
<element schema="StackFrame" /> <element schema="StackFrame" />
<attribute name="_modified" schema="BOOL" hidden="yes" /> <attribute name="_modified" schema="BOOL" hidden="yes" />
@ -457,7 +469,7 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="BreakpointSpec" canonical="yes"> <schema name="BreakpointSpec" canonical="yes">
<interface name="BreakpointSpec" /> <interface name="BreakpointSpec" />
@ -480,10 +492,10 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Type" schema="STRING" /> <attribute name="Type" schema="OBJECT" />
<attribute name="Disposition" schema="STRING" /> <attribute name="Disposition" schema="OBJECT" />
<attribute name="Pending" schema="STRING" /> <attribute name="Pending" schema="OBJECT" />
<attribute name="Times" schema="INT" /> <attribute name="Times" schema="OBJECT" />
<attribute schema="VOID" /> <attribute schema="VOID" />
</schema> </schema>
<schema name="StackFrame"> <schema name="StackFrame">
@ -499,11 +511,11 @@
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="Attributes" schema="StackFrameAttributes" /> <attribute name="Attributes" schema="StackFrameAttributes" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="StackFrameAttributes"> <schema name="StackFrameAttributes">
<element schema="VOID" /> <element schema="VOID" />
<attribute name="_pc" schema="ADDRESS" required="yes" hidden="yes" /> <attribute name="_pc" schema="ADDRESS" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" /> <attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" /> <attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" /> <attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
@ -512,14 +524,14 @@
<attribute name="_value" schema="ANY" hidden="yes" /> <attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" /> <attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" /> <attribute name="_order" schema="INT" hidden="yes" />
<attribute name="FrameNumber" schema="STRING" /> <attribute name="FrameNumber" schema="OBJECT" />
<attribute name="FrameOffset" schema="STRING" /> <attribute name="FrameOffset" schema="OBJECT" />
<attribute name="FuncTableEntry" schema="STRING" /> <attribute name="FuncTableEntry" schema="OBJECT" />
<attribute name="InstructionOffset" schema="STRING" /> <attribute name="InstructionOffset" schema="OBJECT" />
<attribute name="ReturnOffset" schema="STRING" /> <attribute name="ReturnOffset" schema="OBJECT" />
<attribute name="StackOffset" schema="STRING" /> <attribute name="StackOffset" schema="OBJECT" />
<attribute name="Virtual" schema="STRING" /> <attribute name="Virtual" schema="OBJECT" />
<attribute schema="VOID" /> <attribute schema="ANY" />
</schema> </schema>
<schema name="Symbol"> <schema name="Symbol">
<interface name="Symbol" /> <interface name="Symbol" />

View file

@ -665,7 +665,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter implements
Msg.error(this, "TargetMap corrupted"); Msg.error(this, "TargetMap corrupted");
} }
TargetObject targetObject = container.getTargetObject(); TargetObject targetObject = container.getTargetObject();
if (targetObject != null) { if (targetObject != null && !container.isLink()) {
String key = targetObject.getJoinedPath(PATH_JOIN_CHAR); String key = targetObject.getJoinedPath(PATH_JOIN_CHAR);
container.subscribe(); container.subscribe();
targetMap.put(key, container); targetMap.put(key, container);

View file

@ -216,6 +216,9 @@ public class ObjectContainer implements Comparable {
synchronized (elementMap) { synchronized (elementMap) {
for (ObjectContainer child : currentChildren) { for (ObjectContainer child : currentChildren) {
String name = child.getName(); String name = child.getName();
if (name.startsWith("[")) {
name = name.substring(1, name.length() - 1);
}
if (elementsRemoved.contains(name) && !elementsAdded.containsKey(name)) { if (elementsRemoved.contains(name) && !elementsAdded.containsKey(name)) {
elementMap.remove(name); elementMap.remove(name);
structureChanged = true; structureChanged = true;
@ -387,6 +390,7 @@ public class ObjectContainer implements Comparable {
public void setTargetObject(TargetObject rootObject) { public void setTargetObject(TargetObject rootObject) {
this.targetObject = rootObject; this.targetObject = rootObject;
this.targetObjectRef = rootObject; this.targetObjectRef = rootObject;
rebuildContainers(rootObject.getCachedElements(), rootObject.getCachedAttributes());
if (provider != null) { if (provider != null) {
provider.addTargetToMap(this); provider.addTargetToMap(this);
provider.update(this); provider.update(this);

View file

@ -16,8 +16,7 @@
package ghidra.app.plugin.core.debug.gui.objects.components; package ghidra.app.plugin.core.debug.gui.objects.components;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.*;
import java.util.concurrent.ExecutionException;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@ -85,17 +84,21 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
if (cf != null) { if (cf != null) {
// NB: We're allowed to do this because we're guaranteed to be // NB: We're allowed to do this because we're guaranteed to be
// in our own thread by the GTreeSlowLoadingNode // in our own thread by the GTreeSlowLoadingNode
ObjectContainer oc = cf.get(); ObjectContainer oc = cf.get(5, TimeUnit.SECONDS);
return tree.update(oc); return tree.update(oc);
} }
} }
catch (InterruptedException | ExecutionException e) { catch (InterruptedException | ExecutionException | TimeoutException e) {
// Ignore // Ignore
Msg.warn(this, e); Msg.warn(this, e);
//e.printStackTrace(); //e.printStackTrace();
} }
} }
return new ArrayList<>(); List<GTreeNode> list = new ArrayList<>();
if (oldChildren != null) {
list.addAll(oldChildren);
}
return list;
} }
public DebuggerObjectsProvider getProvider() { public DebuggerObjectsProvider getProvider() {
@ -206,22 +209,20 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
public void callUpdate() { public void callUpdate() {
// NB: this has to be in its own thread // NB: this has to be in its own thread
Thread thread = new Thread(new Runnable() { CompletableFuture.runAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
List<GTreeNode> updateNodes = tree.update(container); List<GTreeNode> updateNodes = tree.update(container);
if (isRestructured()) { if (isRestructured()) {
setChildren(updateNodes); setChildren(updateNodes);
} }
// Unnecessary: fireNodeStructureChanged(ObjectNode.this);
} }
}); });
thread.start();
} }
public void callModified() { public void callModified() {
// NB: this has to be in its own thread // NB: this has to be in its own thread
Thread thread = new Thread(new Runnable() { CompletableFuture.runAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
List<GTreeNode> updateNodes = tree.update(container); List<GTreeNode> updateNodes = tree.update(container);
@ -230,7 +231,6 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
} }
} }
}); });
thread.start();
} }
public boolean isRestructured() { public boolean isRestructured() {

View file

@ -93,31 +93,26 @@ public class ObjectTree implements ObjectPane {
} }
} }
provider.getTool().contextChanged(provider); provider.getTool().contextChanged(provider);
if (e.getEventOrigin() != EventOrigin.INTERNAL_GENERATED) { if (e.getEventOrigin() == EventOrigin.INTERNAL_GENERATED) {
currentExpandedPaths = tree.getExpandedPaths(); restoreTreeStateManager.updateLater();
if (e.getEventOrigin() == EventOrigin.USER_GENERATED) { return;
currentSelectionPaths = tree.getSelectionPaths();
currentViewPosition = tree.getViewPosition();
} }
else {
TreePath[] selectionPaths = tree.getSelectionPaths(); TreePath[] selectionPaths = tree.getSelectionPaths();
if (e.getEventOrigin() == EventOrigin.API_GENERATED) {
if (currentSelectionPaths != null && currentSelectionPaths.length > 0) { if (currentSelectionPaths != null && currentSelectionPaths.length > 0) {
if (selectionPaths != null && selectionPaths.length > 0) { if (selectionPaths != null && selectionPaths.length > 0) {
TreePath currentPath = currentSelectionPaths[0]; TreePath currentPath = currentSelectionPaths[0];
TreePath selectedPath = selectionPaths[0]; TreePath selectedPath = selectionPaths[0];
// NB. isDescendant == has a descendent // NB. isDescendant == has a descendent
if (currentPath.isDescendant(selectedPath)) { if (selectedPath.isDescendant(currentPath)) {
return;
}
}
}
}
currentSelectionPaths = selectionPaths; currentSelectionPaths = selectionPaths;
currentExpandedPaths = tree.getExpandedPaths();
currentViewPosition = tree.getViewPosition(); currentViewPosition = tree.getViewPosition();
}
else if (!selectedPath.isDescendant(currentPath)) {
currentSelectionPaths = selectionPaths;
currentViewPosition = tree.getViewPosition();
}
}
}
}
}
restoreTreeStateManager.updateLater(); restoreTreeStateManager.updateLater();
} }
}); });
@ -137,25 +132,29 @@ public class ObjectTree implements ObjectPane {
@Override @Override
public void treeExpanded(TreeExpansionEvent event) { public void treeExpanded(TreeExpansionEvent event) {
currentExpandedPaths = tree.getExpandedPaths();
TreePath expandedPath = event.getPath(); TreePath expandedPath = event.getPath();
Object last = expandedPath.getLastPathComponent(); Object last = expandedPath.getLastPathComponent();
if (last instanceof ObjectNode) { if (last instanceof ObjectNode) {
ObjectNode node = (ObjectNode) last; ObjectNode node = (ObjectNode) last;
if (!node.isExpanded()) {
//currentExpandedPaths = tree.getExpandedPaths();
node.markExpanded(); node.markExpanded();
} }
} }
}
@Override @Override
public void treeCollapsed(TreeExpansionEvent event) { public void treeCollapsed(TreeExpansionEvent event) {
currentExpandedPaths = tree.getExpandedPaths();
TreePath collapsedPath = event.getPath(); TreePath collapsedPath = event.getPath();
Object last = collapsedPath.getLastPathComponent(); Object last = collapsedPath.getLastPathComponent();
if (last instanceof ObjectNode) { if (last instanceof ObjectNode) {
ObjectNode node = (ObjectNode) last; ObjectNode node = (ObjectNode) last;
if (node.isExpanded()) {
//currentExpandedPaths = tree.getExpandedPaths();
node.markCollapsed(); node.markCollapsed();
} }
} }
}
}); });
tree.addMouseListener(new MouseAdapter() { tree.addMouseListener(new MouseAdapter() {
@ -406,6 +405,9 @@ public class ObjectTree implements ObjectPane {
protected void navigateToSelectedObject() { protected void navigateToSelectedObject() {
if (listingService != null) { if (listingService != null) {
TargetObject selectedObject = getSelectedObject(); TargetObject selectedObject = getSelectedObject();
if (selectedObject == null) {
return;
}
Object value = selectedObject.getCachedAttribute(TargetObject.VALUE_ATTRIBUTE_NAME); Object value = selectedObject.getCachedAttribute(TargetObject.VALUE_ATTRIBUTE_NAME);
Address addr = null; Address addr = null;
if (value instanceof Address) { if (value instanceof Address) {

View file

@ -98,7 +98,7 @@ public class DbgengX64DebuggerMappingOpinion implements DebuggerMappingOpinion {
protected Set<DebuggerMappingOffer> offersForEnv(TargetEnvironment<?> env, protected Set<DebuggerMappingOffer> offersForEnv(TargetEnvironment<?> env,
TargetProcess<?> process) { TargetProcess<?> process) {
if (!env.getDebugger().toLowerCase().contains("dbg")) { if (env == null || !env.getDebugger().toLowerCase().contains("dbg")) {
return Set.of(); return Set.of();
} }
boolean is64Bit = boolean is64Bit =

View file

@ -97,7 +97,8 @@ public interface DebuggerModelServiceInternal extends DebuggerModelService {
* @param focused the focused object * @param focused the focused object
*/ */
default void fireFocusEvent(TargetObjectRef focused) { default void fireFocusEvent(TargetObjectRef focused) {
firePluginEvent(new ModelObjectFocusedPluginEvent(getName(), focused)); Swing.runIfSwingOrRunLater(
() -> firePluginEvent(new ModelObjectFocusedPluginEvent(getName(), focused)));
} }
/** /**

View file

@ -103,12 +103,12 @@ public abstract class AbstractTargetObject<P extends TargetObject>
* there is no guarantee of consistency after an exception is thrown. In general, models without * there is no guarantee of consistency after an exception is thrown. In general, models without
* explicit schemas should not fail validation, since objects will likely be assigned * explicit schemas should not fail validation, since objects will likely be assigned
* {@link EnumerableTargetObjectSchema#ANY}. When developing a schema for an existing model, it * {@link EnumerableTargetObjectSchema#ANY}. When developing a schema for an existing model, it
* may be useful to override this to return false in the interim. * may be useful to override this to return true to fail fast.
* *
* @return true to throw exceptions on schema violations. * @return true to throw exceptions on schema violations.
*/ */
protected boolean enforcesStrictSchema() { protected boolean enforcesStrictSchema() {
return true; return false;
} }
@Override @Override

View file

@ -330,7 +330,14 @@ public class DefaultTargetObject<E extends TargetObject, P extends TargetObject>
} }
req = curAttrsRequest; req = curAttrsRequest;
} }
return req.thenApply(__ -> getCachedAttributes()); return req.thenApply(__ -> {
synchronized (attributes) {
if (schema != null) { // TODO: Remove this. Schema should never be null.
schema.validateRequiredAttributes(this, enforcesStrictSchema());
}
return getCachedAttributes();
}
});
} }
@Override @Override

View file

@ -437,20 +437,20 @@ public interface TargetObjectSchema {
getType() + " of schema " + this getType() + " of schema " + this
: "Value " + value + " for " + path + " does not conform to required type " + : "Value " + value + " for " + path + " does not conform to required type " +
getType() + " of schema " + this; getType() + " of schema " + this;
Msg.error(this, msg);
if (strict) { if (strict) {
throw new AssertionError(msg); throw new AssertionError(msg);
} }
Msg.error(this, msg);
} }
for (Class<? extends TargetObject> iface : getInterfaces()) { for (Class<? extends TargetObject> iface : getInterfaces()) {
if (!iface.isAssignableFrom(cls)) { if (!iface.isAssignableFrom(cls)) {
// TODO: Should this throw an exception, eventually? // TODO: Should this throw an exception, eventually?
String msg = "Value " + value + " does not implement required interface " + String msg = "Value " + value + " does not implement required interface " +
iface + " of schema " + this; iface + " of schema " + this;
Msg.error(this, msg);
if (strict) { if (strict) {
throw new AssertionError(msg); throw new AssertionError(msg);
} }
Msg.error(this, msg);
} }
} }
} }
@ -475,10 +475,10 @@ public interface TargetObjectSchema {
if (!missing.isEmpty()) { if (!missing.isEmpty()) {
String msg = "Object " + object + " is missing required attributes " + missing + String msg = "Object " + object + " is missing required attributes " + missing +
" of schema " + this; " of schema " + this;
Msg.error(this, msg);
if (strict) { if (strict) {
throw new AssertionError(msg); throw new AssertionError(msg);
} }
Msg.error(this, msg);
} }
} }
@ -505,13 +505,6 @@ public interface TargetObjectSchema {
AttributeSchema as = getAttributeSchema(key); AttributeSchema as = getAttributeSchema(key);
TargetObjectSchema schema = getContext().getSchema(as.getSchema()); TargetObjectSchema schema = getContext().getSchema(as.getSchema());
schema.validateTypeAndInterfaces(value, parentPath, key, strict); schema.validateTypeAndInterfaces(value, parentPath, key, strict);
if (value instanceof TargetObject) {
TargetObject ov = (TargetObject) value;
if (!PathUtils.isLink(parentPath, ent.getKey(), ov.getPath())) {
schema.validateRequiredAttributes(ov, strict);
}
}
} }
// TODO: Creating these sets *every* change could be costly // TODO: Creating these sets *every* change could be costly
@ -525,10 +518,10 @@ public interface TargetObjectSchema {
if (!violatesRequired.isEmpty()) { if (!violatesRequired.isEmpty()) {
String msg = "Object " + parentPath + " removed required attributes " + String msg = "Object " + parentPath + " removed required attributes " +
violatesRequired + " of schema " + this; violatesRequired + " of schema " + this;
Msg.error(this, msg);
if (strict) { if (strict) {
throw new AssertionError(msg); throw new AssertionError(msg);
} }
Msg.error(this, msg);
} }
// TODO: Another set.... // TODO: Another set....
// NB. "removed" includes changed things // NB. "removed" includes changed things
@ -543,10 +536,10 @@ public interface TargetObjectSchema {
if (!violatesFixed.isEmpty()) { if (!violatesFixed.isEmpty()) {
String msg = "Object " + parentPath + " modified or removed fixed attributes " + String msg = "Object " + parentPath + " modified or removed fixed attributes " +
violatesFixed + " of schema " + this; violatesFixed + " of schema " + this;
Msg.error(this, msg);
if (strict) { if (strict) {
throw new AssertionError(msg); throw new AssertionError(msg);
} }
Msg.error(this, msg);
} }
} }
@ -566,7 +559,6 @@ public interface TargetObjectSchema {
TargetObject element = ent.getValue(); TargetObject element = ent.getValue();
TargetObjectSchema schema = getContext().getSchema(getElementSchema(ent.getKey())); TargetObjectSchema schema = getContext().getSchema(getElementSchema(ent.getKey()));
schema.validateTypeAndInterfaces(element, parentPath, ent.getKey(), strict); schema.validateTypeAndInterfaces(element, parentPath, ent.getKey(), strict);
schema.validateRequiredAttributes(element, strict);
} }
} }
} }

View file

@ -20,7 +20,9 @@ import static org.junit.Assert.*;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Test; import org.junit.Test;
import ghidra.dbg.DebuggerObjectModel; import ghidra.dbg.DebuggerObjectModel;
@ -117,8 +119,13 @@ public class TargetObjectSchemaValidationTest {
} }
static class ValidatedObject extends DefaultTargetObject<TargetObject, TargetObject> { static class ValidatedObject extends DefaultTargetObject<TargetObject, TargetObject> {
public ValidatedObject(DebuggerObjectModel model, String key, TargetObjectSchema schema) { public ValidatedObject(DebuggerObjectModel model, TargetObject parent, String key,
super(model, null, key, "Object", schema); TargetObjectSchema schema) {
super(model, parent, key, "Object", schema);
}
public ValidatedObject(DebuggerObjectModel model, TargetObject parent, String key) {
super(model, parent, key, "Object");
} }
@Override @Override
@ -171,9 +178,8 @@ public class TargetObjectSchemaValidationTest {
return wreq; return wreq;
} }
protected DefaultTargetObject<?, ?> createWReqIncorrect(TargetObject root, String name) { protected ValidatedObject createWReqIncorrect(TargetObject root, String name) {
DefaultTargetObject<?, ?> wreq = ValidatedObject wreq = new ValidatedObject(model, root, name);
new DefaultTargetObject<>(model, root, name, "Default");
return wreq; return wreq;
} }
@ -185,10 +191,16 @@ public class TargetObjectSchemaValidationTest {
} }
@Test(expected = AssertionError.class) @Test(expected = AssertionError.class)
public void testAttributeValidationAtInsertViaSetAttributesErr() { public void testAttributeValidationViaFetchAttributesErr()
throws InterruptedException, ExecutionException {
DefaultTargetModelRoot root = createRootAttrWReq(); DefaultTargetModelRoot root = createRootAttrWReq();
DefaultTargetObject<?, ?> wreq = createWReqIncorrect(root, "my_attr"); DefaultTargetObject<?, ?> wreq = createWReqIncorrect(root, "my_attr");
root.setAttributes(List.of(wreq), Map.of(), "Initialized"); try {
wreq.fetchAttributes().get();
}
catch (ExecutionException e) {
ExceptionUtils.rethrow(e.getCause());
}
} }
@Test @Test
@ -198,13 +210,6 @@ public class TargetObjectSchemaValidationTest {
root.changeAttributes(List.of(), List.of(wreq), Map.of(), "Initialized"); root.changeAttributes(List.of(), List.of(wreq), Map.of(), "Initialized");
} }
@Test(expected = AssertionError.class)
public void testAttributeValidationAtInsertViaChangeAttributesErr() {
DefaultTargetModelRoot root = createRootAttrWReq();
DefaultTargetObject<?, ?> wreq = createWReqIncorrect(root, "my_attr");
root.changeAttributes(List.of(), List.of(wreq), Map.of(), "Initialized");
}
@Test @Test
public void testAttributeValidationAtInsertViaSetElements() { public void testAttributeValidationAtInsertViaSetElements() {
DefaultTargetModelRoot root = createRootElemWReq(); DefaultTargetModelRoot root = createRootElemWReq();
@ -212,13 +217,6 @@ public class TargetObjectSchemaValidationTest {
root.setElements(List.of(wreq), Map.of(), "Initialized"); root.setElements(List.of(wreq), Map.of(), "Initialized");
} }
@Test(expected = AssertionError.class)
public void testAttributeValidationAtInsertViaSetElementsErr() {
DefaultTargetModelRoot root = createRootElemWReq();
DefaultTargetObject<?, ?> wreq = createWReqIncorrect(root, "[1]");
root.setElements(List.of(wreq), Map.of(), "Initialized");
}
@Test @Test
public void testAttributeValidationAtInsertViaChangeElements() { public void testAttributeValidationAtInsertViaChangeElements() {
DefaultTargetModelRoot root = createRootElemWReq(); DefaultTargetModelRoot root = createRootElemWReq();
@ -226,20 +224,13 @@ public class TargetObjectSchemaValidationTest {
root.changeElements(List.of(), List.of(wreq), Map.of(), "Initialized"); root.changeElements(List.of(), List.of(wreq), Map.of(), "Initialized");
} }
@Test(expected = AssertionError.class)
public void testAttributeValidationAtInsertViaChangeElementsErr() {
DefaultTargetModelRoot root = createRootElemWReq();
DefaultTargetObject<?, ?> wreq = createWReqIncorrect(root, "[1]");
root.changeElements(List.of(), List.of(wreq), Map.of(), "Initialized");
}
@Test(expected = AssertionError.class) @Test(expected = AssertionError.class)
public void testValidateRequiredAttributeViaSetErr() { public void testValidateRequiredAttributeViaSetErr() {
TargetObjectSchema schema = ctx.builder(new SchemaName("test")) TargetObjectSchema schema = ctx.builder(new SchemaName("test"))
.addAttributeSchema(new DefaultAttributeSchema("req", .addAttributeSchema(new DefaultAttributeSchema("req",
EnumerableTargetObjectSchema.ANY.getName(), true, false, false), null) EnumerableTargetObjectSchema.ANY.getName(), true, false, false), null)
.buildAndAdd(); .buildAndAdd();
ValidatedObject obj = new ValidatedObject(model, "Test", schema); ValidatedObject obj = new ValidatedObject(model, null, "Test", schema);
obj.setAttributes(List.of(), Map.of("req", "Hello"), "Initialized"); obj.setAttributes(List.of(), Map.of("req", "Hello"), "Initialized");
obj.setAttributes(List.of(), Map.of(), "Test"); obj.setAttributes(List.of(), Map.of(), "Test");
@ -251,7 +242,7 @@ public class TargetObjectSchemaValidationTest {
.addAttributeSchema(new DefaultAttributeSchema("req", .addAttributeSchema(new DefaultAttributeSchema("req",
EnumerableTargetObjectSchema.ANY.getName(), true, false, false), null) EnumerableTargetObjectSchema.ANY.getName(), true, false, false), null)
.buildAndAdd(); .buildAndAdd();
ValidatedObject obj = new ValidatedObject(model, "Test", schema); ValidatedObject obj = new ValidatedObject(model, null, "Test", schema);
obj.setAttributes(List.of(), Map.of("req", "Hello"), "Initialized"); obj.setAttributes(List.of(), Map.of("req", "Hello"), "Initialized");
obj.changeAttributes(List.of("req"), List.of(), Map.of(), "Test"); obj.changeAttributes(List.of("req"), List.of(), Map.of(), "Test");
@ -263,7 +254,7 @@ public class TargetObjectSchemaValidationTest {
.addAttributeSchema(new DefaultAttributeSchema("fix", .addAttributeSchema(new DefaultAttributeSchema("fix",
EnumerableTargetObjectSchema.ANY.getName(), false, true, false), null) EnumerableTargetObjectSchema.ANY.getName(), false, true, false), null)
.buildAndAdd(); .buildAndAdd();
ValidatedObject obj = new ValidatedObject(model, "Test", schema); ValidatedObject obj = new ValidatedObject(model, null, "Test", schema);
obj.setAttributes(List.of(), Map.of("fix", "Hello"), "Initialized"); obj.setAttributes(List.of(), Map.of("fix", "Hello"), "Initialized");
obj.setAttributes(List.of(), Map.of("fix", "World"), "Test"); obj.setAttributes(List.of(), Map.of("fix", "World"), "Test");
@ -275,7 +266,7 @@ public class TargetObjectSchemaValidationTest {
.addAttributeSchema(new DefaultAttributeSchema("fix", .addAttributeSchema(new DefaultAttributeSchema("fix",
EnumerableTargetObjectSchema.ANY.getName(), false, true, false), null) EnumerableTargetObjectSchema.ANY.getName(), false, true, false), null)
.buildAndAdd(); .buildAndAdd();
ValidatedObject obj = new ValidatedObject(model, "Test", schema); ValidatedObject obj = new ValidatedObject(model, null, "Test", schema);
obj.setAttributes(List.of(), Map.of("fix", "Hello"), "Initialized"); obj.setAttributes(List.of(), Map.of("fix", "Hello"), "Initialized");
// Removal of fixed attr also forbidden after it's set // Removal of fixed attr also forbidden after it's set
@ -294,7 +285,7 @@ public class TargetObjectSchemaValidationTest {
EnumerableTargetObjectSchema.OBJECT.getName(), false, false, false), null) EnumerableTargetObjectSchema.OBJECT.getName(), false, false, false), null)
.setDefaultAttributeSchema(AttributeSchema.DEFAULT_VOID) .setDefaultAttributeSchema(AttributeSchema.DEFAULT_VOID)
.buildAndAdd(); .buildAndAdd();
ValidatedObject obj = new ValidatedObject(model, "Test", schema); ValidatedObject obj = new ValidatedObject(model, null, "Test", schema);
return obj; return obj;
} }