mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-648: Dbgmodel speed-up, and focus issues.
This commit is contained in:
parent
f5ec74f2c3
commit
2ed29f5693
53 changed files with 650 additions and 473 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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");
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (engThread.isCurrentThread()) {
|
||||||
|
sequence(TypeSpec.VOID).then((seq) -> {
|
||||||
|
addCommand(cmd, pcmd, seq);
|
||||||
|
seq.exit();
|
||||||
|
}).finish().exceptionally((exc) -> {
|
||||||
|
pcmd.completeExceptionally(exc);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sequence(TypeSpec.VOID).then(engThread, (seq) -> {
|
||||||
|
addCommand(cmd, pcmd, seq);
|
||||||
|
seq.exit();
|
||||||
|
}).finish().exceptionally((exc) -> {
|
||||||
|
pcmd.completeExceptionally(exc);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
sequence(TypeSpec.VOID).then(engThread, (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.toString()));
|
|
||||||
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;
|
public void setCurrentThread(DbgThreadImpl thread) {
|
||||||
}
|
currentThread = thread;
|
||||||
return threads.get(info.getThreadId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class DbgModelImpl extends AbstractDbgModel {
|
||||||
public TargetObjectSchema getRootSchema() {
|
public TargetObjectSchema getRootSchema() {
|
||||||
return root.getSchema();
|
return root.getSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<? extends TargetObject> fetchModelRoot() {
|
public CompletableFuture<? extends TargetObject> fetchModelRoot() {
|
||||||
return completedRoot;
|
return completedRoot;
|
||||||
|
|
|
@ -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( //
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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, //
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
updatedElements = new ArrayList<>();
|
synchronized (access) {
|
||||||
List<ModelObject> list = access.getElements(path);
|
updatedElements = new ArrayList<>();
|
||||||
Map<String, ? extends TargetObjectRef> existingElements = targetObject.getCachedElements();
|
List<ModelObject> list = access.getElements(path);
|
||||||
for (ModelObject obj : list) {
|
Map<String, ? extends TargetObjectRef> existingElements =
|
||||||
DbgModelTargetObject proxyElement;
|
targetObject.getCachedElements();
|
||||||
if (existingElements.containsKey(obj.getSearchKey())) {
|
|
||||||
proxyElement = (DbgModelTargetObject) existingElements.get(obj.getSearchKey());
|
for (ModelObject obj : list) {
|
||||||
DelegateDbgModel2TargetObject delegate =
|
DbgModel2TargetProxy proxyElement;
|
||||||
DelegateDbgModel2TargetObject.getDelegate(proxyElement);
|
String searchKey = obj.getSearchKey();
|
||||||
delegate.setModelObject(obj);
|
String elKey = PathUtils.makeKey(searchKey);
|
||||||
|
if (existingElements.containsKey(searchKey)) {
|
||||||
|
proxyElement = (DbgModel2TargetProxy) existingElements.get(searchKey);
|
||||||
|
DelegateDbgModel2TargetObject delegate = proxyElement.getDelegate();
|
||||||
|
delegate.setModelObject(obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
proxyElement = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject
|
||||||
|
.makeProxy(targetObject.getModel(), targetObject, elKey, obj);
|
||||||
|
}
|
||||||
|
updatedElements.add(proxyElement);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
String elKey = DbgModel2TargetObjectImpl.keyObject(obj);
|
|
||||||
proxyElement = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(),
|
|
||||||
targetObject, elKey, obj);
|
|
||||||
}
|
|
||||||
updatedElements.add(proxyElement);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -117,7 +117,7 @@ public class DbgManager2Impl extends DbgManagerImpl {
|
||||||
curSession = getSessionComputeIfAbsent(sid);
|
curSession = getSessionComputeIfAbsent(sid);
|
||||||
return curSession;
|
return curSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DbgProcessImpl getCurrentProcess() {
|
public DbgProcessImpl getCurrentProcess() {
|
||||||
synchronized (processes) {
|
synchronized (processes) {
|
||||||
|
@ -125,7 +125,7 @@ public class DbgManager2Impl extends DbgManagerImpl {
|
||||||
return processes.get(id);
|
return processes.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DbgThreadImpl getCurrentThread() {
|
public DbgThreadImpl getCurrentThread() {
|
||||||
synchronized (threads) {
|
synchronized (threads) {
|
||||||
|
@ -133,5 +133,6 @@ public class DbgManager2Impl extends DbgManagerImpl {
|
||||||
return threads.get(id);
|
return threads.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,51 +104,49 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> requestElements(boolean refresh) {
|
public CompletableFuture<Void> requestElements(boolean refresh) {
|
||||||
List<TargetObject> nlist = new ArrayList<>();
|
synchronized (elements) {
|
||||||
return requestNativeElements().thenCompose(list -> {
|
List<TargetObject> nlist = new ArrayList<>();
|
||||||
for (TargetObject element : elements.values()) {
|
return requestNativeElements().thenCompose(list -> {
|
||||||
if (!list.contains(element)) {
|
for (TargetObject element : elements.values()) {
|
||||||
if (element instanceof DbgStateListener) {
|
if (!list.contains(element)) {
|
||||||
getManager().removeStateListener((DbgStateListener) element);
|
if (element instanceof DbgStateListener) {
|
||||||
}
|
getManager().removeStateListener((DbgStateListener) element);
|
||||||
if (element instanceof DbgEventsListener) {
|
}
|
||||||
getManager().removeEventsListener((DbgEventsListener) element);
|
if (element instanceof DbgEventsListener) {
|
||||||
|
getManager().removeEventsListener((DbgEventsListener) element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
nlist.addAll(list);
|
||||||
nlist.addAll(list);
|
return processModelObjectElements(nlist);
|
||||||
int order = 0;
|
}).thenAccept(__ -> {
|
||||||
for (TargetObject targetObject : nlist) {
|
setElements(nlist, Map.of(), "Refreshed");
|
||||||
DbgModelTargetObject to = (DbgModelTargetObject) targetObject;
|
});
|
||||||
to.changeAttributes(List.of(), Map.of( //
|
}
|
||||||
ORDER_ATTRIBUTE_NAME, order++ //
|
|
||||||
), "Initialized");
|
|
||||||
}
|
|
||||||
return processModelObjectElements(nlist);
|
|
||||||
}).thenAccept(__ -> {
|
|
||||||
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 -> {
|
||||||
if (map != null) {
|
synchronized (attributes) {
|
||||||
Collection<?> values = map.values();
|
if (map != null) {
|
||||||
for (Object attribute : attributes.values()) {
|
Collection<?> values = map.values();
|
||||||
if (!values.contains(attribute)) {
|
for (Object attribute : attributes.values()) {
|
||||||
if (attribute instanceof DbgStateListener) {
|
if (!values.contains(attribute)) {
|
||||||
getManager().removeStateListener((DbgStateListener) attribute);
|
if (attribute instanceof DbgStateListener) {
|
||||||
}
|
getManager().removeStateListener((DbgStateListener) attribute);
|
||||||
if (attribute instanceof DbgEventsListener) {
|
}
|
||||||
getManager().removeEventsListener((DbgEventsListener) attribute);
|
if (attribute instanceof DbgEventsListener) {
|
||||||
|
getManager().removeEventsListener((DbgEventsListener) attribute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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,10 +193,12 @@ 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)) {
|
||||||
String oldval = (String) attributes.get(DISPLAY_ATTRIBUTE_NAME);
|
synchronized (attributes) {
|
||||||
String newval = getName() + " : " + value;
|
String oldval = (String) attributes.get(DISPLAY_ATTRIBUTE_NAME);
|
||||||
attrs.put(DISPLAY_ATTRIBUTE_NAME, newval);
|
String newval = getName() + " : " + value;
|
||||||
setModified(attrs, !newval.equals(oldval));
|
attrs.put(DISPLAY_ATTRIBUTE_NAME, newval);
|
||||||
|
setModified(attrs, !newval.equals(oldval));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tk == null) {
|
if (tk == null) {
|
||||||
Object val = modelObject.getIntrinsicValue();
|
Object val = modelObject.getIntrinsicValue();
|
||||||
|
@ -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,28 +288,32 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> fetchChild(final String key) {
|
public CompletableFuture<?> fetchChild(final String key) {
|
||||||
if (key.startsWith("[") && key.endsWith("]")) {
|
synchronized (elements) {
|
||||||
String trimKey = key.substring(1, key.length() - 1);
|
if (key.startsWith("[") && key.endsWith("]")) {
|
||||||
if (elements.containsKey(trimKey)) {
|
String trimKey = key.substring(1, key.length() - 1);
|
||||||
return CompletableFuture.completedFuture(elements.get(trimKey));
|
if (elements.containsKey(trimKey)) {
|
||||||
|
return CompletableFuture.completedFuture(elements.get(trimKey));
|
||||||
|
}
|
||||||
|
return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey));
|
||||||
}
|
}
|
||||||
return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey));
|
|
||||||
}
|
}
|
||||||
if (attributes.containsKey(key)) {
|
synchronized (attributes) {
|
||||||
return CompletableFuture.completedFuture(attributes.get(key));
|
if (attributes.containsKey(key)) {
|
||||||
|
return CompletableFuture.completedFuture(attributes.get(key));
|
||||||
|
}
|
||||||
|
if (key.endsWith(")")) {
|
||||||
|
DbgManager2Impl manager2 = (DbgManager2Impl) getManager();
|
||||||
|
List<String> pathX = PathUtils.extend(List.of("Debugger"), path);
|
||||||
|
pathX = PathUtils.extend(pathX, key);
|
||||||
|
return manager2.applyMethods(pathX, this).thenApply(obj -> {
|
||||||
|
changeAttributes(List.of(), List.of(), Map.of( //
|
||||||
|
key, obj //
|
||||||
|
), "Initialized");
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return requestAttributes(true).thenApply(__ -> getCachedAttribute(key));
|
||||||
}
|
}
|
||||||
if (key.endsWith(")")) {
|
|
||||||
DbgManager2Impl manager2 = (DbgManager2Impl) getManager();
|
|
||||||
List<String> pathX = PathUtils.extend(List.of("Debugger"), path);
|
|
||||||
pathX = PathUtils.extend(pathX, key);
|
|
||||||
return manager2.applyMethods(pathX, this).thenApply(obj -> {
|
|
||||||
changeAttributes(List.of(), List.of(), Map.of( //
|
|
||||||
key, obj //
|
|
||||||
), "Initialized");
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return requestAttributes(true).thenApply(__ -> getCachedAttribute(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Override
|
//@Override
|
||||||
|
@ -378,9 +398,55 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetModified() {
|
public void resetModified() {
|
||||||
changeAttributes(List.of(), List.of(), Map.of( //
|
if (getCachedAttribute(MODIFIED_ATTRIBUTE_NAME) != null) {
|
||||||
MODIFIED_ATTRIBUTE_NAME, false //
|
changeAttributes(List.of(), List.of(), Map.of( //
|
||||||
), "Refreshed");
|
MODIFIED_ATTRIBUTE_NAME, false //
|
||||||
|
), "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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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" />
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
<attribute name="Settings" schema="OBJECT" />
|
<attribute name="Settings" schema="OBJECT" />
|
||||||
<attribute name="State" schema="OBJECT" />
|
<attribute name="State" schema="OBJECT" />
|
||||||
<attribute name="Utility" schema="OBJECT" />
|
<attribute name="Utility" schema="OBJECT" />
|
||||||
<attribute schema="VOID" />
|
<attribute schema="VOID" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="SessionContainer" canonical="yes">
|
<schema name="SessionContainer" canonical="yes">
|
||||||
<element schema="Session" />
|
<element schema="Session" />
|
||||||
|
@ -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" />
|
||||||
|
@ -360,11 +358,11 @@
|
||||||
<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="Registers" schema="RegisterContainer" required="yes" fixed="yes" />
|
<attribute name="Registers" schema="RegisterContainer" required="yes" fixed="yes" />
|
||||||
<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" />
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
TreePath[] selectionPaths = tree.getSelectionPaths();
|
||||||
}
|
if (e.getEventOrigin() == EventOrigin.API_GENERATED) {
|
||||||
else {
|
if (currentSelectionPaths != null && currentSelectionPaths.length > 0) {
|
||||||
TreePath[] selectionPaths = tree.getSelectionPaths();
|
if (selectionPaths != null && selectionPaths.length > 0) {
|
||||||
if (currentSelectionPaths != null && currentSelectionPaths.length > 0) {
|
TreePath currentPath = currentSelectionPaths[0];
|
||||||
if (selectionPaths != null && selectionPaths.length > 0) {
|
TreePath selectedPath = selectionPaths[0];
|
||||||
TreePath currentPath = currentSelectionPaths[0];
|
// NB. isDescendant == has a descendent
|
||||||
TreePath selectedPath = selectionPaths[0];
|
if (selectedPath.isDescendant(currentPath)) {
|
||||||
// NB. isDescendant == has a descendent
|
return;
|
||||||
if (currentPath.isDescendant(selectedPath)) {
|
|
||||||
currentSelectionPaths = selectionPaths;
|
|
||||||
currentViewPosition = tree.getViewPosition();
|
|
||||||
}
|
|
||||||
else if (!selectedPath.isDescendant(currentPath)) {
|
|
||||||
currentSelectionPaths = selectionPaths;
|
|
||||||
currentViewPosition = tree.getViewPosition();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
currentSelectionPaths = selectionPaths;
|
||||||
|
currentExpandedPaths = tree.getExpandedPaths();
|
||||||
|
currentViewPosition = tree.getViewPosition();
|
||||||
restoreTreeStateManager.updateLater();
|
restoreTreeStateManager.updateLater();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -137,23 +132,27 @@ 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;
|
||||||
node.markExpanded();
|
if (!node.isExpanded()) {
|
||||||
|
//currentExpandedPaths = tree.getExpandedPaths();
|
||||||
|
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;
|
||||||
node.markCollapsed();
|
if (node.isExpanded()) {
|
||||||
|
//currentExpandedPaths = tree.getExpandedPaths();
|
||||||
|
node.markCollapsed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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) {
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue