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

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

View file

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

View file

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

View file

@ -130,7 +130,7 @@ public interface DbgEventsListener {
* @param name the name of the module on the target
* @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
@ -139,7 +139,7 @@ public interface DbgEventsListener {
* @param name the name of the module on the target
* @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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,6 @@ package agent.dbgeng.manager.cmd;
import java.util.*;
import agent.dbgeng.dbgeng.*;
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
import agent.dbgeng.manager.DbgModule;
import agent.dbgeng.manager.impl.*;
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
Msg.warn(this, "Resync: Was missing module: " + id);
DbgModuleImpl module = new DbgModuleImpl(manager, process, id);
module.setInfo(moduleInfo.get(updatedModules.get(id)));
DebugModuleInfo info = moduleInfo.get(updatedModules.get(id));
DbgModuleImpl module = new DbgModuleImpl(manager, process, info);
module.add();
}
for (String id : new ArrayList<>(cur)) {
@ -63,7 +62,7 @@ public class DbgListModulesCommand extends AbstractDbgCommand<Map<String, DbgMod
DebugSymbols symbols = manager.getSymbols();
for (DebugModule module : symbols.iterateModules(0)) {
DebugModuleInfo info = symbols.getModuleParameters(1, module.getIndex());
updatedModules.put(module.getName(DebugModuleName.MODULE), module);
updatedModules.put(info.toString(), module);
moduleInfo.put(module, info);
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.manager.cmd;
import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import ghidra.dbg.attributes.TargetObjectRef;
public class DbgRequestFocusCommand extends AbstractDbgCommand<Void> {
private DbgModelTargetFocusScope<?> scope;
private TargetObjectRef ref;
/**
* Set focus for the current ref
*
* @param manager the manager to execute the command
* @param scope in most cases the root object (must be an ancestor for the ref)
* @param ref the desired focus
*/
public DbgRequestFocusCommand(DbgManagerImpl manager, DbgModelTargetFocusScope<?> scope,
TargetObjectRef ref) {
super(manager);
this.scope = scope;
this.ref = ref;
}
@Override
public void invoke() {
scope.doRequestFocus(ref);
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -40,10 +40,11 @@ public class DbgModuleImpl implements DbgModule {
* @param process the process to which the module belongs
* @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.process = process;
this.name = name;
this.info = info;
this.name = info.moduleName;
}
@Override
@ -56,7 +57,7 @@ public class DbgModuleImpl implements DbgModule {
*/
public void add() {
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() {
process.removeModule(name);
manager.getEventListeners().fire.moduleUnloaded(process, name, Causes.UNCLAIMED);
manager.getEventListeners().fire.moduleUnloaded(process, info, Causes.UNCLAIMED);
}
@Override
@ -103,8 +104,8 @@ public class DbgModuleImpl implements DbgModule {
return minimalSymbols.request();
}
public void setInfo(DebugModuleInfo info) {
this.info = info;
public DebugModuleInfo getInfo() {
return info;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -138,7 +138,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
ByteBuffer buf = ByteBuffer.allocate(length);
long offset = address.getOffset();
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")) {
return manager
@ -199,7 +202,10 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
ByteBuffer buf = ByteBuffer.wrap(data);
long offset = address.getOffset();
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")) {
return manager

View file

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

View file

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

View file

@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicReference;
import agent.dbgeng.dbgeng.DebugProcessId;
import agent.dbgeng.manager.*;
import agent.dbgeng.manager.cmd.DbgProcessSelectCommand;
import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
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 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);
protected static String indexProcess(DebugProcessId debugProcessId) {
@ -226,7 +225,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
@Override
public CompletableFuture<Void> select() {
DbgManagerImpl manager = getManager();
return manager.execute(new DbgProcessSelectCommand(manager, process));
return manager.selectProcess(process);
}
@Override

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -898,6 +898,19 @@ public class ModelObjectImpl implements ModelObjectInternal {
@Override
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) {
throw new RuntimeException("null key for " + this);
}

View file

@ -23,8 +23,7 @@ import agent.dbgeng.model.iface2.DbgModelTargetObject;
import agent.dbgmodel.dbgmodel.main.ModelObject;
import agent.dbgmodel.gadp.impl.WrappedDbgModel;
import agent.dbgmodel.manager.DbgManager2Impl;
import agent.dbgmodel.model.impl.DbgModel2TargetObjectImpl;
import agent.dbgmodel.model.impl.DelegateDbgModel2TargetObject;
import agent.dbgmodel.model.impl.*;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
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, ?> existingAttributes = targetObject.getCachedAttributes();
for (String key : map.keySet()) {
DbgModelTargetObject proxyAttribute;
DbgModel2TargetProxy proxyAttribute;
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)) {
proxyAttribute = (DbgModelTargetObject) object;
DelegateDbgModel2TargetObject delegate =
DelegateDbgModel2TargetObject.getDelegate(proxyAttribute);
proxyAttribute = (DbgModel2TargetProxy) object;
DelegateDbgModel2TargetObject delegate = proxyAttribute.getDelegate();
delegate.setModelObject(obj);
updatedAttributes.put(key, proxyAttribute);
}
else {
String atKey = obj.getSearchKey();
proxyAttribute = DelegateDbgModel2TargetObject.makeProxy(targetObject.getModel(),
targetObject, atKey, obj);
proxyAttribute = (DbgModel2TargetProxy) DelegateDbgModel2TargetObject
.makeProxy(targetObject.getModel(), targetObject, atKey, obj);
updatedAttributes.put(key, proxyAttribute);
}
}

View file

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

View file

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

View file

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

View file

@ -25,7 +25,7 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
import agent.dbgeng.model.AbstractDbgModel;
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
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.jna.dbgmodel.DbgModelNative.ModelObjectKind;
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.TargetExecutionStateful.TargetExecutionState;
import ghidra.dbg.target.schema.TargetObjectSchema;
import ghidra.dbg.util.CollectionUtils.Delta;
import ghidra.dbg.util.PathUtils;
import ghidra.dbg.util.PathUtils.TargetObjectKeyComparator;
import ghidra.util.Msg;
@ -58,6 +59,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
protected String DBG_PROMPT = "(kd2)"; // Used by DbgModelTargetEnvironment
protected boolean fireAttributesChanged = false;
protected static String indexObject(ModelObject obj) {
return obj.getSearchKey();
}
@ -101,6 +104,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override
public CompletableFuture<Void> requestElements(boolean refresh) {
synchronized (elements) {
List<TargetObject> nlist = new ArrayList<>();
return requestNativeElements().thenCompose(list -> {
for (TargetObject element : elements.values()) {
@ -114,23 +118,19 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
}
}
nlist.addAll(list);
int order = 0;
for (TargetObject targetObject : nlist) {
DbgModelTargetObject to = (DbgModelTargetObject) targetObject;
to.changeAttributes(List.of(), Map.of( //
ORDER_ATTRIBUTE_NAME, order++ //
), "Initialized");
}
return processModelObjectElements(nlist);
}).thenAccept(__ -> {
setElements(nlist, Map.of(), "Refreshed");
});
}
}
@Override
public CompletableFuture<Void> requestAttributes(boolean refresh) {
fireAttributesChanged = true;
Map<String, Object> nmap = new HashMap<>();
return requestNativeAttributes().thenCompose(map -> {
synchronized (attributes) {
if (map != null) {
Collection<?> values = map.values();
for (Object attribute : attributes.values()) {
@ -146,6 +146,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
nmap.putAll(map);
}
return addModelObjectAttributes(nmap);
}
}).thenAccept(__ -> {
setAttributes(List.of(), nmap, "Refreshed");
});
@ -161,9 +162,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
private CompletableFuture<Void> processElement(TargetObject targetObject) {
if (targetObject instanceof DbgModelTargetObject) {
DbgModelTargetObject proxy = (DbgModelTargetObject) targetObject;
DelegateDbgModel2TargetObject delegate =
DelegateDbgModel2TargetObject.getDelegate(proxy);
DbgModel2TargetProxy proxy = (DbgModel2TargetProxy) targetObject;
DelegateDbgModel2TargetObject delegate = proxy.getDelegate();
if (proxy instanceof TargetStackFrame || //
proxy instanceof TargetModule || //
proxy instanceof TargetBreakpointSpec) {
@ -193,11 +193,13 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (value != null && !value.equals("")) {
attrs.put(VALUE_ATTRIBUTE_NAME, value);
if (!kind.equals(ModelObjectKind.OBJECT_PROPERTY_ACCESSOR)) {
synchronized (attributes) {
String oldval = (String) attributes.get(DISPLAY_ATTRIBUTE_NAME);
String newval = getName() + " : " + value;
attrs.put(DISPLAY_ATTRIBUTE_NAME, newval);
setModified(attrs, !newval.equals(oldval));
}
}
if (tk == null) {
Object val = modelObject.getIntrinsicValue();
if (val != null) {
@ -208,11 +210,23 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
if (this instanceof DelegateDbgModel2TargetObject) {
DelegateDbgModel2TargetObject delegate = (DelegateDbgModel2TargetObject) this;
TargetObject proxy = delegate.getProxy();
if (proxy instanceof TargetAccessConditioned) {
attrs.put(TargetAccessConditioned.ACCESSIBLE_ATTRIBUTE_NAME,
accessibility == TargetAccessibility.ACCESSIBLE);
}
if (proxy instanceof TargetExecutionStateful) {
TargetExecutionStateful<?> stateful = (TargetExecutionStateful<?>) proxy;
TargetExecutionState state = stateful.getExecutionState();
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) {
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");
}
if (proxy instanceof TargetModule) {
//attrs.put(TargetObject.ORDER_ATTRIBUTE_NAME,
// Integer.decode(modelObject.getOriginalKey()));
DbgModelTargetModule module = (DbgModelTargetModule) proxy;
return module.init(attrs);
}
@ -272,6 +288,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override
public CompletableFuture<?> fetchChild(final String key) {
synchronized (elements) {
if (key.startsWith("[") && key.endsWith("]")) {
String trimKey = key.substring(1, key.length() - 1);
if (elements.containsKey(trimKey)) {
@ -279,6 +296,8 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
}
return requestElements(true).thenApply(__ -> getCachedElements().get(trimKey));
}
}
synchronized (attributes) {
if (attributes.containsKey(key)) {
return CompletableFuture.completedFuture(attributes.get(key));
}
@ -295,6 +314,7 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
}
return requestAttributes(true).thenApply(__ -> getCachedAttribute(key));
}
}
//@Override
//public TargetAccessibility getAccessibility() {
@ -378,9 +398,55 @@ public class DbgModel2TargetObjectImpl extends DefaultTargetObject<TargetObject,
@Override
public void resetModified() {
if (getCachedAttribute(MODIFIED_ATTRIBUTE_NAME) != null) {
changeAttributes(List.of(), List.of(), Map.of( //
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;
}
}

View file

@ -0,0 +1,24 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgmodel.model.impl;
import agent.dbgeng.model.iface2.DbgModelTargetObject;
public interface DbgModel2TargetProxy extends DbgModelTargetObject {
public DelegateDbgModel2TargetObject getDelegate();
}

View file

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

View file

@ -39,7 +39,7 @@ import utilities.util.ProxyUtilities;
public class DelegateDbgModel2TargetObject extends DbgModel2TargetObjectImpl implements //
DbgModelTargetAccessConditioned<DelegateDbgModel2TargetObject>, //
DbgModelTargetExecutionStateful<DelegateDbgModel2TargetObject>, //
DbgModelTargetBptHelper {
DbgModel2TargetProxy, DbgModelTargetBptHelper {
// Probably don-t need any of the handler-map or annotation stuff
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;
}
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();
// 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);
mixins.add(DbgModel2TargetProxy.class);
this.proxy =
ProxyUtilities.composeOnDelegate(DbgModelTargetObject.class, this, mixins, LOOKUP);
map.put(proxy, this);
if (proxy instanceof DbgEventsListener) {
model.getManager().addEventsListener((DbgEventsListener) proxy);
}
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
public <T extends TypedTargetObject<T>> T as(Class<T> iface) {
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
@Override

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -103,12 +103,12 @@ public abstract class AbstractTargetObject<P extends TargetObject>
* there is no guarantee of consistency after an exception is thrown. In general, models without
* explicit schemas should not fail validation, since objects will likely be assigned
* {@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.
*/
protected boolean enforcesStrictSchema() {
return true;
return false;
}
@Override

View file

@ -330,7 +330,14 @@ public class DefaultTargetObject<E extends TargetObject, P extends TargetObject>
}
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

View file

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

View file

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