mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 20:59:58 +00:00
GP-844: Fixed focus issues, introduced "activation"
This commit is contained in:
parent
62bd317380
commit
997ab4d9a0
@ -133,7 +133,7 @@ public interface DbgProcess extends DbgMemoryOperations {
|
||||
*
|
||||
* @return a future that completes when dbgeng has executed the command
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Specify a binary image for execution and debug symbols
|
||||
|
@ -48,7 +48,7 @@ public interface DbgStackFrame extends DbgStackFrameOperations {
|
||||
*
|
||||
* @return a future that completes when the frame is the current frame
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Get the thread for this frame
|
||||
|
@ -61,7 +61,7 @@ public interface DbgThread
|
||||
*
|
||||
* @return a future that completes when the thread is the current thread
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Get the process to which this thread belongs
|
||||
|
@ -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.DbgModelTargetActiveScope;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
|
||||
public class DbgRequestActivationCommand extends AbstractDbgCommand<Void> {
|
||||
|
||||
private DbgModelTargetActiveScope activator;
|
||||
private TargetObject obj;
|
||||
|
||||
/**
|
||||
* Set focus for the current ref
|
||||
*
|
||||
* @param manager the manager to execute the command
|
||||
* @param activator in most cases the root object (must be an ancestor for the ref)
|
||||
* @param obj the desired object to be made active
|
||||
*/
|
||||
public DbgRequestActivationCommand(DbgManagerImpl manager, DbgModelTargetActiveScope activator,
|
||||
TargetObject obj) {
|
||||
super(manager);
|
||||
this.activator = activator;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
activator.doRequestActivation(obj);
|
||||
}
|
||||
}
|
@ -19,19 +19,17 @@ import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
public class DbgProcessSelectCommand extends AbstractDbgCommand<Void> {
|
||||
public class DbgSetActiveProcessCommand extends AbstractDbgCommand<Void> {
|
||||
|
||||
private DbgProcess process;
|
||||
|
||||
/**
|
||||
* Select the given thread and frame level
|
||||
*
|
||||
* To simply select a thread, you should use frame 0 as the default.
|
||||
* Set the active process
|
||||
*
|
||||
* @param manager the manager to execute the command
|
||||
* @param process the desired process
|
||||
*/
|
||||
public DbgProcessSelectCommand(DbgManagerImpl manager, DbgProcess process) {
|
||||
public DbgSetActiveProcessCommand(DbgManagerImpl manager, DbgProcess process) {
|
||||
super(manager);
|
||||
this.process = process;
|
||||
}
|
@ -19,18 +19,16 @@ import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.manager.DbgSession;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
public class DbgSessionSelectCommand extends AbstractDbgCommand<Void> {
|
||||
public class DbgSetActiveSessionCommand extends AbstractDbgCommand<Void> {
|
||||
private DbgSession session;
|
||||
|
||||
/**
|
||||
* Select the given thread and frame level
|
||||
*
|
||||
* To simply select a thread, you should use frame 0 as the default.
|
||||
* Set the active session
|
||||
*
|
||||
* @param manager the manager to execute the command
|
||||
* @param process the desired process
|
||||
*/
|
||||
public DbgSessionSelectCommand(DbgManagerImpl manager, DbgSession session) {
|
||||
public DbgSetActiveSessionCommand(DbgManagerImpl manager, DbgSession session) {
|
||||
super(manager);
|
||||
this.session = session;
|
||||
}
|
@ -19,20 +19,18 @@ import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
public class DbgThreadSelectCommand extends AbstractDbgCommand<Void> {
|
||||
public class DbgSetActiveThreadCommand extends AbstractDbgCommand<Void> {
|
||||
|
||||
private DbgThread thread;
|
||||
|
||||
/**
|
||||
* Select the given thread and frame level
|
||||
*
|
||||
* To simply select a thread, you should use frame 0 as the default.
|
||||
* Set the active thread
|
||||
*
|
||||
* @param manager the manager to execute the command
|
||||
* @param thread the desired thread
|
||||
* @param frameId the desired frame level
|
||||
*/
|
||||
public DbgThreadSelectCommand(DbgManagerImpl manager, DbgThread thread, Integer frameId) {
|
||||
public DbgSetActiveThreadCommand(DbgManagerImpl manager, DbgThread thread, Integer frameId) {
|
||||
super(manager);
|
||||
this.thread = thread;
|
||||
}
|
@ -41,6 +41,7 @@ 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.DbgModelTargetActiveScope;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
|
||||
import ghidra.async.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
@ -1402,25 +1403,30 @@ public class DbgManagerImpl implements DbgManager {
|
||||
return (DbgSessionImpl) eventSession;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> selectThread(DbgThread thread) {
|
||||
public CompletableFuture<Void> setActiveThread(DbgThread thread) {
|
||||
currentThread = thread;
|
||||
return execute(new DbgThreadSelectCommand(this, thread, null));
|
||||
return execute(new DbgSetActiveThreadCommand(this, thread, null));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> selectProcess(DbgProcess process) {
|
||||
public CompletableFuture<Void> setActiveProcess(DbgProcess process) {
|
||||
currentProcess = process;
|
||||
return execute(new DbgProcessSelectCommand(this, process));
|
||||
return execute(new DbgSetActiveProcessCommand(this, process));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> selectSession(DbgSession session) {
|
||||
public CompletableFuture<Void> setActiveSession(DbgSession session) {
|
||||
currentSession = session;
|
||||
return execute(new DbgSessionSelectCommand(this, session));
|
||||
return execute(new DbgSetActiveSessionCommand(this, session));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> requestFocus(DbgModelTargetFocusScope scope, TargetObject obj) {
|
||||
return execute(new DbgRequestFocusCommand(this, scope, obj));
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> requestActivation(DbgModelTargetActiveScope activator,
|
||||
TargetObject obj) {
|
||||
return execute(new DbgRequestActivationCommand(this, activator, obj));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> console(String command) {
|
||||
return execute(
|
||||
|
@ -231,14 +231,14 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
return manager.selectProcess(this);
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return manager.setActiveProcess(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> fileExecAndSymbols(String file) {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgFileExecAndSymbolsCommand(manager, file)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -247,7 +247,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<DbgThread> run() {
|
||||
return sequence(TypeSpec.cls(DbgThread.class)).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgRunCommand(manager)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -256,7 +256,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Set<DbgThread>> attach(long toPid) {
|
||||
return sequence(TypeSpec.cls(DbgThread.class).set()).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
pid = toPid; // TODO: Wait for successful completion?
|
||||
manager.execute(
|
||||
@ -268,7 +268,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Set<DbgThread>> reattach(TargetAttachable attachable) {
|
||||
return sequence(TypeSpec.cls(DbgThread.class).set()).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(
|
||||
new DbgAttachCommand(manager, this, BitmaskSet.of(DebugAttachFlags.EXISTING)))
|
||||
@ -279,7 +279,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Void> detach() {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgDetachCommand(manager, this)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -288,7 +288,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Void> kill() {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgKillCommand(manager)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -297,7 +297,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Void> cont() {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgContinueCommand(manager)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -306,7 +306,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Void> step(ExecSuffix suffix) {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgStepCommand(manager, null, suffix)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -315,7 +315,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
@Override
|
||||
public CompletableFuture<Void> step(Map<String, ?> args) {
|
||||
return sequence(TypeSpec.VOID).then((seq) -> {
|
||||
select().handle(seq::next);
|
||||
setActive().handle(seq::next);
|
||||
}).then((seq) -> {
|
||||
manager.execute(new DbgStepCommand(manager, null, args)).handle(seq::exit);
|
||||
}).finish();
|
||||
@ -328,7 +328,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
if (first.isPresent()) {
|
||||
return viaThread.apply(first.get());
|
||||
}
|
||||
return select().thenCompose(__ -> viaThis.get());
|
||||
return setActive().thenCompose(__ -> viaThis.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -124,8 +124,8 @@ public class DbgStackFrameImpl implements DbgStackFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
return thread.select();
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return thread.setActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,8 +130,8 @@ public class DbgThreadImpl implements DbgThread {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
return manager.selectThread(this);
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return manager.setActiveThread(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -207,35 +207,35 @@ public class DbgThreadImpl implements DbgThread {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> cont() {
|
||||
return select().thenCompose(__ -> {
|
||||
return setActive().thenCompose(__ -> {
|
||||
return manager.execute(new DbgContinueCommand(manager));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> step(ExecSuffix suffix) {
|
||||
return select().thenCompose(__ -> {
|
||||
return setActive().thenCompose(__ -> {
|
||||
return manager.execute(new DbgStepCommand(manager, id, suffix));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> step(Map<String, ?> args) {
|
||||
return select().thenCompose(__ -> {
|
||||
return setActive().thenCompose(__ -> {
|
||||
return manager.execute(new DbgStepCommand(manager, id, args));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> kill() {
|
||||
return select().thenCompose(__ -> {
|
||||
return setActive().thenCompose(__ -> {
|
||||
return manager.execute(new DbgKillCommand(manager));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> detach() {
|
||||
return select().thenCompose(__ -> {
|
||||
return setActive().thenCompose(__ -> {
|
||||
return manager.execute(new DbgDetachCommand(manager, process));
|
||||
});
|
||||
}
|
||||
|
@ -25,21 +25,21 @@ import ghidra.dbg.target.TargetObject;
|
||||
|
||||
public interface DbgModelSelectableObject extends DbgModelTargetObject {
|
||||
|
||||
public default CompletableFuture<Void> select() {
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
if (this instanceof DbgModelTargetSession) {
|
||||
DbgManagerImpl manager = getManager();
|
||||
DbgProcess process = manager.getCurrentProcess();
|
||||
return process.select();
|
||||
return process.setActive();
|
||||
}
|
||||
if (this instanceof DbgModelTargetProcess) {
|
||||
DbgModelTargetProcess tp = (DbgModelTargetProcess) this;
|
||||
DbgProcess process = tp.getProcess();
|
||||
return process.select();
|
||||
return process.setActive();
|
||||
}
|
||||
if (this instanceof DbgModelTargetThread) {
|
||||
DbgModelTargetThread tt = (DbgModelTargetThread) this;
|
||||
DbgThread thread = tt.getThread();
|
||||
return thread.select();
|
||||
return thread.setActive();
|
||||
}
|
||||
if (this instanceof DbgModelTargetStackFrame) {
|
||||
DbgModelTargetStackFrame tf = (DbgModelTargetStackFrame) this;
|
||||
@ -47,7 +47,7 @@ public interface DbgModelSelectableObject extends DbgModelTargetObject {
|
||||
if (ref instanceof DbgModelTargetThread) {
|
||||
DbgModelTargetThread tt = (DbgModelTargetThread) ref;
|
||||
DbgThread thread = tt.getThread();
|
||||
return thread.select();
|
||||
return thread.setActive();
|
||||
}
|
||||
}
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* 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.model.iface1;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetObject;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.error.DebuggerIllegalArgumentException;
|
||||
import ghidra.dbg.target.TargetActiveScope;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
/**
|
||||
* An interface which indicates this object is capable of launching targets.
|
||||
*
|
||||
* The targets this launcher creates ought to appear in its successors.
|
||||
*
|
||||
* @param <T> type for this
|
||||
*/
|
||||
public interface DbgModelTargetActiveScope extends DbgModelTargetObject, TargetActiveScope {
|
||||
|
||||
// NB: requesActivation request change in active object - propagates down to manager
|
||||
// (but, of course, may then cause change in state)
|
||||
@Override
|
||||
public default CompletableFuture<Void> requestActivation(TargetObject obj) {
|
||||
return getModel().gateFuture(getManager().requestActivation(this, obj));
|
||||
}
|
||||
|
||||
public default CompletableFuture<Void> doRequestActivation(TargetObject obj) {
|
||||
if (getManager().isWaiting()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
getModel().assertMine(TargetObject.class, obj);
|
||||
if (!PathUtils.isAncestor(this.getPath(), obj.getPath())) {
|
||||
throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope");
|
||||
}
|
||||
TargetObject cur = obj;
|
||||
while (cur != null) {
|
||||
if (cur instanceof DbgModelSelectableObject) {
|
||||
DbgModelSelectableObject sel = (DbgModelSelectableObject) cur;
|
||||
System.err.println("requestActivation " + obj);
|
||||
return sel.setActive();
|
||||
}
|
||||
if (cur instanceof DbgModelTargetObject) {
|
||||
DbgModelTargetObject def = (DbgModelTargetObject) cur;
|
||||
cur = def.getParent();
|
||||
continue;
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,7 @@ public interface DbgModelTargetFocusScope extends DbgModelTargetObject, TargetFo
|
||||
// NB: setFocus changes attributes - propagates up to client
|
||||
public boolean setFocus(DbgModelSelectableObject sel);
|
||||
|
||||
// NB: requestFocus request change in active object - propagates down to manager
|
||||
// NB: requestFocus request change in focused object - propagates down to manager
|
||||
// (but, of course, may then cause change in state)
|
||||
@Override
|
||||
public default CompletableFuture<Void> requestFocus(TargetObject obj) {
|
||||
@ -61,8 +61,9 @@ public interface DbgModelTargetFocusScope extends DbgModelTargetObject, TargetFo
|
||||
while (cur != null) {
|
||||
if (cur instanceof DbgModelSelectableObject) {
|
||||
DbgModelSelectableObject sel = (DbgModelSelectableObject) cur;
|
||||
System.err.println("requestFocus " + obj);
|
||||
setFocus(sel);
|
||||
return sel.select();
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
if (cur instanceof DbgModelTargetObject) {
|
||||
DbgModelTargetObject def = (DbgModelTargetObject) cur;
|
||||
|
@ -31,7 +31,7 @@ public interface DbgModelTargetConnector
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select();
|
||||
public CompletableFuture<Void> setActive();
|
||||
|
||||
@Override
|
||||
public TargetParameterMap getParameters();
|
||||
|
@ -69,13 +69,13 @@ public interface DbgModelTargetProcess extends //
|
||||
}
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<Void> select() {
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
DbgProcess process = getProcess();
|
||||
if (process == null) {
|
||||
process = manager.getEventProcess();
|
||||
}
|
||||
return manager.selectProcess(process);
|
||||
return manager.setActiveProcess(process);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public interface DbgModelTargetRoot extends //
|
||||
///DbgModelTargetObject,
|
||||
DbgModelTargetAccessConditioned, //
|
||||
DbgModelTargetAttacher, //
|
||||
DbgModelTargetActiveScope, //
|
||||
DbgModelTargetEventScope, //
|
||||
DbgModelTargetLauncher, //
|
||||
DbgModelTargetFocusScope, //
|
||||
@ -29,5 +30,6 @@ public interface DbgModelTargetRoot extends //
|
||||
|
||||
void setDefaultConnector(DbgModelTargetConnector defaultConnector);
|
||||
|
||||
// getActive & requestActivation implemented by DbgModelTargetObject & DbgModelTargetActiveScope
|
||||
// getFocus & requestFocus implemented by DbgModelTargetObject & DbgModelTargetFocusScope
|
||||
}
|
||||
|
@ -71,12 +71,12 @@ public interface DbgModelTargetSession extends //
|
||||
}
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<Void> select() {
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
DbgSession session = getSession();
|
||||
if (session == null) {
|
||||
session = manager.getEventSession();
|
||||
}
|
||||
return manager.selectSession(session);
|
||||
return manager.setActiveSession(session);
|
||||
}
|
||||
}
|
||||
|
@ -48,10 +48,10 @@ public interface DbgModelTargetStackFrame extends //
|
||||
public static final String FROM_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "from"; // TODO
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<Void> select() {
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
DbgThreadImpl thread = manager.getCurrentThread();
|
||||
return manager.selectThread(thread);
|
||||
return manager.setActiveThread(thread);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.cmd.DbgThreadSelectCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand;
|
||||
import agent.dbgeng.manager.impl.*;
|
||||
import agent.dbgeng.model.iface1.*;
|
||||
import agent.dbgeng.model.impl.DbgModelTargetStackImpl;
|
||||
@ -58,10 +58,10 @@ public interface DbgModelTargetThread extends //
|
||||
public void threadStateChangedSpecific(DbgState state, DbgReason reason);
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<Void> select() {
|
||||
public default CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
DbgThread thread = getThread();
|
||||
return manager.execute(new DbgThreadSelectCommand(manager, thread, null));
|
||||
return manager.execute(new DbgSetActiveThreadCommand(manager, thread, null));
|
||||
}
|
||||
|
||||
public DbgModelTargetStackImpl getStack();
|
||||
|
@ -55,7 +55,7 @@ public class DbgModelTargetKernelConnectorImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
connectors.setDefaultConnector(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class DbgModelTargetProcessAttachConnectorImpl extends DbgModelTargetObje
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
connectors.setDefaultConnector(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -197,9 +197,9 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
return manager.selectProcess(process);
|
||||
return manager.setActiveProcess(process);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,7 +54,7 @@ public class DbgModelTargetProcessLaunchConnectorImpl extends DbgModelTargetObje
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
connectors.setDefaultConnector(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -21,8 +21,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetRoot;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import ghidra.dbg.error.DebuggerUserException;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
@ -119,10 +118,10 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
|
||||
@Override
|
||||
public void threadStateChanged(DbgThread thread, DbgState state, DbgCause cause,
|
||||
DbgReason reason) {
|
||||
DbgProcess process = thread.getProcess();
|
||||
DbgModelTargetThread targetThread =
|
||||
(DbgModelTargetThread) getModel().getModelObject(thread);
|
||||
changeAttributes(List.of(), List.of(), Map.of( //
|
||||
TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, Long.toHexString(process.getPid()), //
|
||||
TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, Long.toHexString(thread.getTid()) //
|
||||
TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread //
|
||||
), reason.desc());
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
//DbgManagerImpl manager = getManager();
|
||||
//DbgProcessImpl process = manager.getCurrentProcess();
|
||||
//return manager.execute(new DbgProcessSelectCommand(manager, process));
|
||||
|
@ -138,9 +138,9 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
return manager.selectThread(thread.getThread());
|
||||
return manager.setActiveThread(thread.getThread());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.cmd.DbgThreadSelectCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgSetActiveThreadCommand;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
@ -138,9 +138,9 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
DbgManagerImpl manager = getManager();
|
||||
return manager.execute(new DbgThreadSelectCommand(manager, thread, null));
|
||||
return manager.execute(new DbgSetActiveThreadCommand(manager, thread, null));
|
||||
}
|
||||
|
||||
public DbgModelTargetRegisterContainerAndBank getRegisters() {
|
||||
|
@ -54,7 +54,7 @@ public class DbgModelTargetTraceOrDumpConnectorImpl extends DbgModelTargetObject
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
connectors.setDefaultConnector(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ public abstract class AbstractDbgManagerTest extends AbstractGhidraHeadlessInteg
|
||||
}).then(seq -> {
|
||||
mgr.waitForPrompt().handle(seq::next);
|
||||
}).then(seq -> {
|
||||
thread.get().select().handle(seq::next);
|
||||
thread.get().setActive().handle(seq::next);
|
||||
}).finish());
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
), "Focus changed");
|
||||
intrinsics.put(TargetFocusScope.FOCUS_ATTRIBUTE_NAME, focus);
|
||||
DbgModelTargetSession session = focus.getParentSession();
|
||||
session.select();
|
||||
session.setActive();
|
||||
}
|
||||
return doFire;
|
||||
}
|
||||
@ -314,15 +314,10 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
if (targetThread == null) {
|
||||
return;
|
||||
}
|
||||
DbgProcess process = thread.getProcess();
|
||||
changeAttributes(List.of(), List.of(), Map.of( //
|
||||
TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, Long.toHexString(process.getPid()), //
|
||||
TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, Long.toHexString(thread.getTid()) //
|
||||
TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread //
|
||||
), reason.desc());
|
||||
intrinsics.put(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME,
|
||||
Long.toHexString(process.getPid()));
|
||||
intrinsics.put(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME,
|
||||
Long.toHexString(thread.getTid()));
|
||||
intrinsics.put(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread);
|
||||
TargetEventType eventType = getEventType(state, cause, reason);
|
||||
getListeners().fire.event(getProxy(), targetThread, eventType,
|
||||
"Thread " + thread.getId() + " state changed", List.of(targetThread));
|
||||
|
@ -154,7 +154,7 @@ public interface GdbInferior extends GdbMemoryOperations {
|
||||
*
|
||||
* @return a future that completes when GDB has executed the command
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Specify a binary image for execution and debug symbols
|
||||
|
@ -258,7 +258,7 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
|
||||
/**
|
||||
* Get the inferior which currently has focus
|
||||
*
|
||||
* @see GdbInferior#select()
|
||||
* @see GdbInferior#setActive()
|
||||
* @return a handle to the inferior with focus
|
||||
*/
|
||||
GdbInferior currentInferior();
|
||||
|
@ -49,7 +49,7 @@ public interface GdbStackFrame extends GdbStackFrameOperations {
|
||||
*
|
||||
* @return a future that completes when the frame is the current frame
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Get the thread for this frame
|
||||
|
@ -70,7 +70,7 @@ public interface GdbThread
|
||||
*
|
||||
* @return a future that completes when the thread is the current thread
|
||||
*/
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
|
||||
/**
|
||||
* Set the value of an internal GDB variable
|
||||
|
@ -208,7 +208,7 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
* longer be current for the actual command execution. NB: The select command will cancel
|
||||
* itself if this inferior is already current.
|
||||
*/
|
||||
return select().thenCombine(manager.execute(cmd), (s, e) -> e);
|
||||
return setActive().thenCombine(manager.execute(cmd), (s, e) -> e);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -347,8 +347,8 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
return manager.selectInferior(this);
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return manager.setActiveInferior(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -957,7 +957,7 @@ public class GdbManagerImpl implements GdbManager {
|
||||
event(() -> listenersEvent.fire.inferiorSelected(cur, evt.getCause()),
|
||||
"groupRemoved-sel");
|
||||
// Also cause GDB to generate thread selection events, if applicable
|
||||
selectInferior(cur);
|
||||
setActiveInferior(cur);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1524,7 +1524,7 @@ public class GdbManagerImpl implements GdbManager {
|
||||
* @param inferior the inferior to select
|
||||
* @return a future that completes when GDB has executed the command
|
||||
*/
|
||||
CompletableFuture<Void> selectInferior(GdbInferior inferior) {
|
||||
CompletableFuture<Void> setActiveInferior(GdbInferior inferior) {
|
||||
return execute(new GdbInferiorSelectCommand(this, inferior.getId()));
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,8 @@ public class GdbStackFrameImpl implements GdbStackFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
return manager.execute(new GdbThreadSelectCommand(manager, thread.getId(), level));
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return manager.execute(new GdbSetActiveThreadCommand(manager, thread.getId(), level));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,7 +128,7 @@ public class GdbThreadImpl implements GdbThread {
|
||||
protected <T> CompletableFuture<T> execute(AbstractGdbCommand<T> cmd) {
|
||||
switch (cmd.getInterpreter()) {
|
||||
case CLI:
|
||||
return select().thenCombine(manager.execute(cmd), (__, v) -> v);
|
||||
return setActive().thenCombine(manager.execute(cmd), (__, v) -> v);
|
||||
case MI2:
|
||||
return manager.execute(cmd);
|
||||
default:
|
||||
@ -137,9 +137,9 @@ public class GdbThreadImpl implements GdbThread {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
// Bypass the select-me-first logic
|
||||
return manager.execute(new GdbThreadSelectCommand(manager, id, null));
|
||||
return manager.execute(new GdbSetActiveThreadCommand(manager, id, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,7 @@ import agent.gdb.manager.evt.*;
|
||||
import agent.gdb.manager.impl.*;
|
||||
import agent.gdb.manager.parsing.GdbMiParser.GdbMiFieldList;
|
||||
|
||||
public class GdbThreadSelectCommand extends AbstractGdbCommandWithThreadAndFrameId<Void> {
|
||||
public class GdbSetActiveThreadCommand extends AbstractGdbCommandWithThreadAndFrameId<Void> {
|
||||
/**
|
||||
* Select the given thread and frame level
|
||||
*
|
||||
@ -30,7 +30,7 @@ public class GdbThreadSelectCommand extends AbstractGdbCommandWithThreadAndFrame
|
||||
* @param threadId the desired thread Id
|
||||
* @param frameId the desired frame level
|
||||
*/
|
||||
public GdbThreadSelectCommand(GdbManagerImpl manager, int threadId, Integer frameId) {
|
||||
public GdbSetActiveThreadCommand(GdbManagerImpl manager, int threadId, Integer frameId) {
|
||||
super(manager, threadId, frameId);
|
||||
}
|
||||
|
@ -20,5 +20,5 @@ import java.util.concurrent.CompletableFuture;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
|
||||
interface GdbModelSelectableObject extends TargetObject {
|
||||
CompletableFuture<Void> select();
|
||||
CompletableFuture<Void> setActive();
|
||||
}
|
||||
|
@ -360,8 +360,8 @@ public class GdbModelTargetInferior
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
return impl.gateFuture(inferior.select());
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return impl.gateFuture(inferior.setActive());
|
||||
}
|
||||
|
||||
@TargetAttributeType(name = EXIT_CODE_ATTRIBUTE_NAME)
|
||||
|
@ -34,16 +34,13 @@ import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "Session",
|
||||
elements = {
|
||||
@TargetElementType(type = Void.class) },
|
||||
attributes = {
|
||||
@TargetObjectSchemaInfo(name = "Session", elements = {
|
||||
@TargetElementType(type = Void.class) }, attributes = {
|
||||
@TargetAttributeType(type = Void.class) })
|
||||
public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
implements TargetAccessConditioned, TargetAttacher, TargetFocusScope, TargetInterpreter,
|
||||
TargetInterruptible, TargetCmdLineLauncher, TargetEventScope, GdbConsoleOutputListener,
|
||||
GdbEventsListenerAdapter {
|
||||
implements TargetAccessConditioned, TargetAttacher, TargetInterpreter, TargetInterruptible,
|
||||
TargetCmdLineLauncher, TargetActiveScope, TargetEventScope, TargetFocusScope,
|
||||
GdbConsoleOutputListener, GdbEventsListenerAdapter {
|
||||
protected static final String GDB_PROMPT = "(gdb)";
|
||||
|
||||
protected final GdbModelImpl impl;
|
||||
@ -88,18 +85,12 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
return inferiors;
|
||||
}
|
||||
|
||||
@TargetAttributeType(
|
||||
name = GdbModelTargetAvailableContainer.NAME,
|
||||
required = true,
|
||||
fixed = true)
|
||||
@TargetAttributeType(name = GdbModelTargetAvailableContainer.NAME, required = true, fixed = true)
|
||||
public GdbModelTargetAvailableContainer getAvailable() {
|
||||
return available;
|
||||
}
|
||||
|
||||
@TargetAttributeType(
|
||||
name = GdbModelTargetBreakpointContainer.NAME,
|
||||
required = true,
|
||||
fixed = true)
|
||||
@TargetAttributeType(name = GdbModelTargetBreakpointContainer.NAME, required = true, fixed = true)
|
||||
public GdbModelTargetBreakpointContainer getBreakpoints() {
|
||||
return breakpoints;
|
||||
}
|
||||
@ -240,7 +231,8 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> requestFocus(TargetObject obj) {
|
||||
public CompletableFuture<Void> requestActivation(TargetObject obj) {
|
||||
System.err.println("requestActivation " + obj);
|
||||
impl.assertMine(TargetObject.class, obj);
|
||||
/**
|
||||
* Yes, this is pointless, since I'm the root, but do it right (TM), since this may change
|
||||
@ -253,13 +245,31 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
while (cur != null) {
|
||||
if (cur instanceof GdbModelSelectableObject) {
|
||||
GdbModelSelectableObject sel = (GdbModelSelectableObject) cur;
|
||||
/**
|
||||
* Have to call setFocus here, since the call to select() is considered
|
||||
* "internally-driven"
|
||||
*/
|
||||
return sel.select().thenRun(() -> {
|
||||
setFocus(sel);
|
||||
});
|
||||
return sel.setActive();
|
||||
}
|
||||
cur = cur.getParent();
|
||||
}
|
||||
return AsyncUtils.NIL;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> requestFocus(TargetObject obj) {
|
||||
System.err.println("requestFocus " + obj);
|
||||
impl.assertMine(TargetObject.class, obj);
|
||||
/**
|
||||
* Yes, this is pointless, since I'm the root, but do it right (TM), since this may change
|
||||
* or be used as an example for other implementations.
|
||||
*/
|
||||
if (!PathUtils.isAncestor(this.getPath(), obj.getPath())) {
|
||||
throw new DebuggerIllegalArgumentException("Can only focus a successor of the scope");
|
||||
}
|
||||
TargetObject cur = obj;
|
||||
while (cur != null) {
|
||||
if (cur instanceof GdbModelSelectableObject) {
|
||||
GdbModelSelectableObject sel = (GdbModelSelectableObject) cur;
|
||||
setFocus(sel);
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
cur = cur.getParent();
|
||||
}
|
||||
@ -292,9 +302,8 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
GdbStateChangeRecord sco =
|
||||
new GdbStateChangeRecord(inf, threads, state, thread, cause, reason);
|
||||
|
||||
CompletableFuture<Void> infUpdates = CompletableFuture.allOf(
|
||||
breakpoints.stateChanged(sco),
|
||||
inferiors.stateChanged(sco));
|
||||
CompletableFuture<Void> infUpdates =
|
||||
CompletableFuture.allOf(breakpoints.stateChanged(sco), inferiors.stateChanged(sco));
|
||||
infUpdates.whenComplete((v, t) -> {
|
||||
if (thread == null) {
|
||||
return;
|
||||
@ -303,10 +312,24 @@ public class GdbModelTargetSession extends DefaultTargetModelRoot
|
||||
* I have to do this for all inferiors, because I don't know in what order they will
|
||||
* complete.
|
||||
*/
|
||||
thread.select().exceptionally(ex -> {
|
||||
thread.setActive().exceptionally(ex -> {
|
||||
impl.reportError(this, "Could not restore event thread", ex);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadStateChanged(GdbThread thread, GdbState state, GdbCause cause,
|
||||
GdbReason reason) {
|
||||
|
||||
/* REQUIRES GP-762
|
||||
TargetThread targetThread = (TargetThread) impl.getModelObject(thread);
|
||||
changeAttributes(List.of(), List.of(), Map.of( //
|
||||
TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, targetThread //
|
||||
), reason.desc());
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -114,8 +114,8 @@ public class GdbModelTargetStackFrame extends DefaultTargetObject<TargetObject,
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
return impl.gateFuture(frame.select());
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return impl.gateFuture(frame.setActive());
|
||||
}
|
||||
|
||||
@TargetAttributeType(name = FUNC_ATTRIBUTE_NAME)
|
||||
|
@ -216,8 +216,8 @@ public class GdbModelTargetThread
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
return impl.gateFuture(thread.select());
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return impl.gateFuture(thread.setActive());
|
||||
}
|
||||
|
||||
public GdbModelTargetBreakpointLocation breakpointHit(GdbBreakpointHitReason reason) {
|
||||
|
@ -412,7 +412,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
|
||||
GdbThread thread = waitOn(mgr.currentInferior().run());
|
||||
waitOn(mgr.waitForState(GdbState.STOPPED));
|
||||
//waitOn(mgr.waitForPrompt());
|
||||
waitOn(thread.select());
|
||||
waitOn(thread.setActive());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ public enum GadpRegistry {
|
||||
registerInterface(TargetEnvironment.class, GadpClientTargetEnvironment.class);
|
||||
registerInterface(TargetEventScope.class, GadpClientTargetEventScope.class);
|
||||
registerInterface(TargetExecutionStateful.class, GadpClientTargetExecutionStateful.class);
|
||||
registerInterface(TargetActiveScope.class, GadpClientTargetActiveScope.class);
|
||||
registerInterface(TargetFocusScope.class, GadpClientTargetFocusScope.class);
|
||||
registerInterface(TargetInterpreter.class, GadpClientTargetInterpreter.class);
|
||||
registerInterface(TargetInterruptible.class, GadpClientTargetInterruptible.class);
|
||||
|
@ -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 ghidra.dbg.gadp.client;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import ghidra.dbg.error.DebuggerIllegalArgumentException;
|
||||
import ghidra.dbg.gadp.protocol.Gadp;
|
||||
import ghidra.dbg.target.TargetActiveScope;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
public interface GadpClientTargetActiveScope extends GadpClientTargetObject, TargetActiveScope {
|
||||
|
||||
@Override
|
||||
default CompletableFuture<Void> requestActivation(TargetObject obj) {
|
||||
getDelegate().assertValid();
|
||||
getModel().assertMine(TargetObject.class, obj);
|
||||
// The server should detect this error, but we can detect it here without sending a request
|
||||
if (!PathUtils.isAncestor(getPath(), obj.getPath())) {
|
||||
throw new DebuggerIllegalArgumentException(
|
||||
"Can only activate a successor of the scope");
|
||||
}
|
||||
return getModel()
|
||||
.sendChecked(
|
||||
Gadp.ActivationRequest.newBuilder()
|
||||
.setPath(GadpValueUtils.makePath(getPath()))
|
||||
.setActive(GadpValueUtils.makePath(obj.getPath())),
|
||||
Gadp.ActivationReply.getDefaultInstance())
|
||||
.thenApply(__ -> null);
|
||||
}
|
||||
}
|
@ -417,6 +417,8 @@ public class GadpClientHandler
|
||||
return processResume(msg.getSequence(), msg.getResumeRequest());
|
||||
case STEP_REQUEST:
|
||||
return processStep(msg.getSequence(), msg.getStepRequest());
|
||||
case ACTIVATION_REQUEST:
|
||||
return processActivation(msg.getSequence(), msg.getActivationRequest());
|
||||
default:
|
||||
throw new GadpErrorException(Gadp.ErrorCode.EC_BAD_REQUEST,
|
||||
"Unrecognized request: " + msg.getMsgCase());
|
||||
@ -466,8 +468,8 @@ public class GadpClientHandler
|
||||
return ref;
|
||||
}
|
||||
|
||||
protected <T extends TargetObject> CompletableFuture<Integer> sendDelta(
|
||||
List<String> parentPath, Delta<TargetObject, T> deltaE, Delta<?, ?> deltaA) {
|
||||
protected <T extends TargetObject> CompletableFuture<Integer> sendDelta(List<String> parentPath,
|
||||
Delta<TargetObject, T> deltaE, Delta<?, ?> deltaA) {
|
||||
return channel.write(Gadp.RootMessage.newBuilder()
|
||||
.setEventNotification(Gadp.EventNotification.newBuilder()
|
||||
.setPath(GadpValueUtils.makePath(parentPath))
|
||||
@ -627,6 +629,19 @@ public class GadpClientHandler
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<?> processActivation(int seqno, Gadp.ActivationRequest req) {
|
||||
TargetActiveScope scope = getObjectChecked(req.getPath()).as(TargetActiveScope.class);
|
||||
TargetObject active = getObjectChecked(req.getActive());
|
||||
return scope.requestActivation(active).thenCompose(__ -> {
|
||||
return model.flushEvents();
|
||||
}).thenCompose(__ -> {
|
||||
return channel.write(Gadp.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setActivationReply(Gadp.ActivationReply.getDefaultInstance())
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<?> processFocus(int seqno, Gadp.FocusRequest req) {
|
||||
TargetFocusScope scope = getObjectChecked(req.getPath()).as(TargetFocusScope.class);
|
||||
TargetObject focus = getObjectChecked(req.getFocus());
|
||||
@ -705,8 +720,7 @@ public class GadpClientHandler
|
||||
return channel.write(Gadp.RootMessage.newBuilder()
|
||||
.setSequence(seqno)
|
||||
.setMemoryReadReply(
|
||||
Gadp.MemoryReadReply.newBuilder()
|
||||
.setContent(ByteString.copyFrom(data)))
|
||||
Gadp.MemoryReadReply.newBuilder().setContent(ByteString.copyFrom(data)))
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
@ -435,6 +435,15 @@ message CacheInvalidateEvent {
|
||||
message CacheInvalidateReply {
|
||||
}
|
||||
|
||||
message ActivationRequest {
|
||||
Path path = 1;
|
||||
Path active = 2;
|
||||
}
|
||||
|
||||
message ActivationReply {
|
||||
}
|
||||
|
||||
|
||||
message FocusRequest {
|
||||
Path path = 1;
|
||||
Path focus = 2;
|
||||
@ -578,5 +587,9 @@ message RootMessage {
|
||||
|
||||
ResyncRequest resync_request = 125;
|
||||
ResyncReply resync_reply = 225;
|
||||
|
||||
ActivationRequest activation_request = 126;
|
||||
ActivationReply activation_reply = 226;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public class JdiModelTargetConnector extends JdiModelTargetObjectImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
connectors.setDefaultConnector(this);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public class JdiModelTargetProcess extends JdiModelTargetObjectImpl
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
///return thread.select();
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ public class JdiModelTargetStackFrame extends JdiModelTargetObjectImpl implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
///return frame.select();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ public class JdiModelTargetThread extends JdiModelTargetObjectReference implemen
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
@ -370,7 +370,7 @@ public class JdiModelTargetVM extends JdiModelTargetObjectImpl implements //
|
||||
|
||||
@Override
|
||||
@Internal
|
||||
public CompletableFuture<Void> select() {
|
||||
public CompletableFuture<Void> setActive() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,6 @@ import ghidra.dbg.jdi.model.iface2.JdiModelTargetObject;
|
||||
|
||||
public interface JdiModelSelectableObject extends JdiModelTargetObject {
|
||||
|
||||
public CompletableFuture<Void> select();
|
||||
public CompletableFuture<Void> setActive();
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public interface JdiModelTargetFocusScope extends JdiModelTargetObject, TargetFo
|
||||
if (cur instanceof JdiModelSelectableObject) {
|
||||
JdiModelSelectableObject sel = (JdiModelSelectableObject) cur;
|
||||
setFocus(sel);
|
||||
return sel.select();
|
||||
return sel.setActive();
|
||||
}
|
||||
cur = cur.getParent();
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
requestFocus();
|
||||
requestFocus(); // COMPONENT
|
||||
|
||||
ctrlPressed = false;
|
||||
currentRectangle = null;
|
||||
|
@ -481,7 +481,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||
public void modelActivated(DebuggerObjectModel model) {
|
||||
//TODO: what do we want here - change of focus, selection?
|
||||
if (model != null && model.equals(currentModel)) {
|
||||
this.requestFocus();
|
||||
this.requestFocus(); // COMPONENT
|
||||
this.toFront();
|
||||
}
|
||||
}
|
||||
|
@ -156,16 +156,10 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode
|
||||
if (provider != null) {
|
||||
ObjectContainer rootContainer = provider.getRoot();
|
||||
Map<String, Object> rootMap = rootContainer.getAttributeMap();
|
||||
String cname = container.getDecoratedName();
|
||||
if (rootMap.containsKey(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME)) {
|
||||
String id = (String) rootMap.get(TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME);
|
||||
if (cname.contains("0x" + id)) {
|
||||
return ICON_EVENT;
|
||||
}
|
||||
}
|
||||
if (rootMap.containsKey(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME)) {
|
||||
String id = (String) rootMap.get(TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME);
|
||||
if (cname.contains("0x" + id)) {
|
||||
if (rootMap.containsKey(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME)) {
|
||||
TargetThread targetProcess =
|
||||
(TargetThread) rootMap.get(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME);
|
||||
if (container.getTargetObject().equals(targetProcess)) {
|
||||
return ICON_EVENT;
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ public class ObjectTree implements ObjectPane {
|
||||
TargetObject targetObject = node.getTargetObject();
|
||||
if (targetObject != null && !(targetObject instanceof DummyTargetObject) &&
|
||||
e.getEventOrigin().equals(EventOrigin.USER_GENERATED)) {
|
||||
DebugModelConventions.requestActivation(targetObject).exceptionally(ex -> {
|
||||
Msg.error(this, "Could not activate " + targetObject, ex);
|
||||
return null;
|
||||
});
|
||||
DebugModelConventions.requestFocus(targetObject).exceptionally(ex -> {
|
||||
Msg.error(this, "Could not focus " + targetObject, ex);
|
||||
return null;
|
||||
|
@ -31,6 +31,7 @@ import docking.widgets.EventTrigger;
|
||||
import docking.widgets.HorizontalTabPanel;
|
||||
import docking.widgets.HorizontalTabPanel.TabListCellRenderer;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.timeline.TimelineListener;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
@ -39,6 +40,8 @@ import ghidra.app.plugin.core.debug.gui.DebuggerSnapActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.thread.DebuggerThreadsTimelinePanel.VetoableSnapRequestListener;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.services.DebuggerTraceManagerService.BooleanChangeAdapter;
|
||||
import ghidra.dbg.DebugModelConventions;
|
||||
import ghidra.dbg.target.TargetThread;
|
||||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.plugintool.AutoService;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
@ -345,6 +348,13 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
||||
|
||||
private ActionContext myActionContext;
|
||||
|
||||
private final TimelineListener timelineListener = new TimelineListener() {
|
||||
@Override
|
||||
public void itemActivated(int index) {
|
||||
timelineItemActivated(index);
|
||||
}
|
||||
};
|
||||
|
||||
DockingAction actionSaveTrace;
|
||||
StepSnapBackwardAction actionStepSnapBackward;
|
||||
StepTickBackwardAction actionStepTickBackward;
|
||||
@ -543,6 +553,23 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
||||
contextChanged();
|
||||
}
|
||||
|
||||
private void timelineItemActivated(int index) {
|
||||
ThreadRow row = threadTableModel.getRowObject(index);
|
||||
rowActivated(row);
|
||||
}
|
||||
|
||||
private void rowActivated(ThreadRow row) {
|
||||
TraceThread thread = row.getThread();
|
||||
Trace trace = thread.getTrace();
|
||||
TraceRecorder recorder = modelService.getRecorder(trace);
|
||||
if (recorder != null) {
|
||||
TargetThread targetThread = recorder.getTargetThread(thread);
|
||||
if (targetThread != null && targetThread.isValid()) {
|
||||
DebugModelConventions.requestActivation(targetThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void buildMainPanel() {
|
||||
traceTabPopupMenu = new JPopupMenu("Trace");
|
||||
|
||||
@ -566,6 +593,16 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
||||
threadTable.getSelectionModel().addListSelectionListener(this::threadRowSelected);
|
||||
threadTimeline.setSelectionModel(threadTable.getSelectionModel());
|
||||
threadTimeline.addSnapRequestedListener(snapListener);
|
||||
threadTimeline.addTimelineListener(timelineListener);
|
||||
|
||||
threadTable.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
int selectedRow = threadTable.getSelectedRow();
|
||||
ThreadRow row = threadTableModel.getRowObject(selectedRow);
|
||||
rowActivated(row);
|
||||
}
|
||||
});
|
||||
|
||||
mainPanel.add(splitPane, BorderLayout.CENTER);
|
||||
|
||||
@ -628,18 +665,15 @@ public class DebuggerThreadsProvider extends ComponentProviderAdapter {
|
||||
closeItem.addActionListener(evt -> {
|
||||
traceManager.closeTrace(trace);
|
||||
});
|
||||
JMenuItem closeOthers =
|
||||
new JMenuItem("Close Others", DebuggerResources.ICON_CLOSE);
|
||||
JMenuItem closeOthers = new JMenuItem("Close Others", DebuggerResources.ICON_CLOSE);
|
||||
closeOthers.addActionListener(evt -> {
|
||||
traceManager.closeOtherTraces(trace);
|
||||
});
|
||||
JMenuItem closeDead =
|
||||
new JMenuItem("Close Dead", DebuggerResources.ICON_CLOSE);
|
||||
JMenuItem closeDead = new JMenuItem("Close Dead", DebuggerResources.ICON_CLOSE);
|
||||
closeDead.addActionListener(evt -> {
|
||||
traceManager.closeDeadTraces();
|
||||
});
|
||||
JMenuItem closeAll =
|
||||
new JMenuItem("Close All", DebuggerResources.ICON_CLOSE);
|
||||
JMenuItem closeAll = new JMenuItem("Close All", DebuggerResources.ICON_CLOSE);
|
||||
closeAll.addActionListener(evt -> {
|
||||
for (Trace t : List.copyOf(traceManager.getOpenTraces())) {
|
||||
traceManager.closeTrace(t);
|
||||
|
@ -27,8 +27,9 @@ import com.google.common.collect.Range;
|
||||
import docking.widgets.*;
|
||||
import docking.widgets.RangeCursorPanel.Direction;
|
||||
import docking.widgets.table.RowObjectTableModel;
|
||||
import docking.widgets.timeline.TimelineListener;
|
||||
import docking.widgets.timeline.TimelinePanel;
|
||||
import docking.widgets.timeline.TimelineViewRangeListener;
|
||||
import ghidra.app.services.DebuggerModelService;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.datastruct.ListenerSet;
|
||||
|
||||
@ -56,8 +57,11 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane {
|
||||
}
|
||||
|
||||
protected class ThreadTimelinePanel extends TimelinePanel<ThreadRow, Long> {
|
||||
protected final RowObjectTableModel<ThreadRow> model;
|
||||
|
||||
public ThreadTimelinePanel(RowObjectTableModel<ThreadRow> model) {
|
||||
super(model, ThreadRow::getLifespan);
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,9 +99,17 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane {
|
||||
protected final ListenerSet<VetoableSnapRequestListener> listeners =
|
||||
new ListenerSet<>(VetoableSnapRequestListener.class);
|
||||
protected final RangeCursorValueListener valueListener = this::cursorValueChanged;
|
||||
protected final TimelineViewRangeListener viewRangeListener = this::viewRangeChanged;
|
||||
protected final TimelineListener timelineListener = new TimelineListener() {
|
||||
@Override
|
||||
public void viewRangeChanged(Range<Double> range) {
|
||||
timelineViewRangeChanged(range);
|
||||
}
|
||||
};
|
||||
private DebuggerModelService modelService;
|
||||
private RowObjectTableModel<ThreadRow> model;
|
||||
|
||||
public DebuggerThreadsTimelinePanel(RowObjectTableModel<ThreadRow> model) {
|
||||
this.model = model;
|
||||
setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
@ -106,7 +118,7 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane {
|
||||
setColumnHeaderView(topCursor);
|
||||
|
||||
topCursor.addValueListener(valueListener);
|
||||
timeline.addViewRangeListener(viewRangeListener);
|
||||
timeline.addTimelineListener(timelineListener);
|
||||
}
|
||||
|
||||
public void addSnapRequestedListener(VetoableSnapRequestListener listener) {
|
||||
@ -122,7 +134,7 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane {
|
||||
}
|
||||
}
|
||||
|
||||
private void viewRangeChanged(Range<Double> range) {
|
||||
private void timelineViewRangeChanged(Range<Double> range) {
|
||||
topCursor.setRange(range);
|
||||
}
|
||||
|
||||
@ -166,4 +178,8 @@ public class DebuggerThreadsTimelinePanel extends JScrollPane {
|
||||
}
|
||||
return timeline.getCellBounds(row);
|
||||
}
|
||||
|
||||
public void addTimelineListener(TimelineListener listener) {
|
||||
timeline.addTimelineListener(listener);
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +78,7 @@ import ghidra.util.task.*;
|
||||
ModelObjectFocusedPluginEvent.class,
|
||||
TraceRecorderAdvancedPluginEvent.class,
|
||||
},
|
||||
servicesRequired = {
|
||||
},
|
||||
servicesRequired = {},
|
||||
servicesProvided = {
|
||||
DebuggerTraceManagerService.class,
|
||||
})
|
||||
|
@ -105,11 +105,6 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator
|
||||
@Test
|
||||
public void testCaptureDebuggerObjectsPlugin() throws Throwable {
|
||||
mb.createTestModel("Debugger");
|
||||
mb.testModel.session.setAttributes(List.of(), Map.of(
|
||||
TargetEventScope.EVENT_PROCESS_ATTRIBUTE_NAME, "1a12", // Get arrow icon on process
|
||||
TargetEventScope.EVENT_THREAD_ATTRIBUTE_NAME, "1a34", // Get arrow icon on thread
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "Debugger"),
|
||||
"TestOverride");
|
||||
|
||||
DefaultTestTargetObject<?, ?> available =
|
||||
new DefaultTestTargetObject<>(mb.testModel.session, "Available", "");
|
||||
@ -135,8 +130,7 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator
|
||||
new DefaultTestTargetObject<>(process1a12, "Devices", "");
|
||||
DefaultTestTargetObject<?, ?> pEnvironment =
|
||||
new DefaultTestTargetObject<>(process1a12, "Environment", "");
|
||||
DefaultTestTargetObject<?, ?> pIo =
|
||||
new DefaultTestTargetObject<>(process1a12, "Io", "");
|
||||
DefaultTestTargetObject<?, ?> pIo = new DefaultTestTargetObject<>(process1a12, "Io", "");
|
||||
DefaultTestTargetObject<?, ?> pMemory =
|
||||
new DefaultTestTargetObject<>(process1a12, "Memory", "");
|
||||
DefaultTestTargetObject<?, ?> pModules =
|
||||
@ -147,6 +141,11 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator
|
||||
DefaultTestTargetObject<?, ?> thread1a34 =
|
||||
new ActionyTestTargetObject(pThreads, "[0x1a34]", "");
|
||||
|
||||
mb.testModel.session.setAttributes(List.of(),
|
||||
Map.of(TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME, thread1a34, // Get arrow icon on thread
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "Debugger"),
|
||||
"TestOverride");
|
||||
|
||||
DefaultTestTargetObject<?, ?> tEnvironment =
|
||||
new DefaultTestTargetObject<>(thread1a34, "Environment", "");
|
||||
|
||||
@ -155,81 +154,45 @@ public class DebuggerObjectsPluginScreenShots extends GhidraScreenShotGenerator
|
||||
|
||||
DefaultTestTargetObject<?, ?> activationContextStackPointer =
|
||||
new DefaultTestTargetObject<>(teEnvBlock, "ActivationContextStackPointer", "");
|
||||
activationContextStackPointer.setAttributes(List.of(), Map.of(
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActivationContextStackPointer : 789abc",
|
||||
"_modified", true),
|
||||
"Initialized");
|
||||
activationContextStackPointer
|
||||
.setAttributes(List.of(),
|
||||
Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME,
|
||||
"ActivationContextStackPointer : 789abc", "_modified", true),
|
||||
"Initialized");
|
||||
DefaultTestTargetObject<?, ?> activeFrame =
|
||||
new DefaultTestTargetObject<>(teEnvBlock, "ActiveFrame", "");
|
||||
activeFrame.setAttributes(List.of(), Map.of(
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActiveFrame : 0",
|
||||
"_modified", true),
|
||||
activeFrame.setAttributes(List.of(),
|
||||
Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "ActiveFrame : 0", "_modified", true),
|
||||
"Initialized");
|
||||
DefaultTestTargetObject<?, ?> bogusFocus =
|
||||
new DefaultTestTargetObject<>(teEnvBlock, "BOGUS FOCUS", "");
|
||||
teEnvBlock.setAttributes(
|
||||
List.of(
|
||||
activationContextStackPointer,
|
||||
activeFrame,
|
||||
bogusFocus),
|
||||
Map.of(
|
||||
"_kind", "OBJECT_TARGET_OBJECT"), // Makes it magenta
|
||||
teEnvBlock.setAttributes(List.of(activationContextStackPointer, activeFrame, bogusFocus),
|
||||
Map.of("_kind", "OBJECT_TARGET_OBJECT"), // Makes it magenta
|
||||
"Initialized");
|
||||
|
||||
tEnvironment.setAttributes(List.of(
|
||||
teEnvBlock),
|
||||
Map.of(), "Initialized");
|
||||
tEnvironment.setAttributes(List.of(teEnvBlock), Map.of(), "Initialized");
|
||||
|
||||
thread1a34.setAttributes(
|
||||
List.of(
|
||||
tEnvironment),
|
||||
Map.of(
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a34"),
|
||||
"Initialized");
|
||||
thread1a34.setAttributes(List.of(tEnvironment),
|
||||
Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a34"), "Initialized");
|
||||
|
||||
pThreads.setElements(List.of(
|
||||
thread1a34),
|
||||
Map.of(), "Initialized");
|
||||
pThreads.setElements(List.of(thread1a34), Map.of(), "Initialized");
|
||||
|
||||
process1a12.setAttributes(
|
||||
List.of(
|
||||
pDebug,
|
||||
pDevices,
|
||||
pEnvironment,
|
||||
pIo,
|
||||
pMemory,
|
||||
pModules,
|
||||
pThreads),
|
||||
Map.of(
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a12",
|
||||
"Handle", "321",
|
||||
"Id", "1a12",
|
||||
List.of(pDebug, pDevices, pEnvironment, pIo, pMemory, pModules, pThreads),
|
||||
Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x1a12", "Handle", "321", "Id", "1a12",
|
||||
"Name", "winmine.exe"),
|
||||
"Initialized");
|
||||
|
||||
sProcesses.setElements(List.of(
|
||||
process1a12),
|
||||
Map.of(), "Initialized");
|
||||
sProcesses.setElements(List.of(process1a12), Map.of(), "Initialized");
|
||||
|
||||
session0.setAttributes(
|
||||
List.of(
|
||||
sAttributes,
|
||||
sDevices,
|
||||
sProcesses),
|
||||
Map.of(
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x0",
|
||||
"Id", 0),
|
||||
session0.setAttributes(List.of(sAttributes, sDevices, sProcesses),
|
||||
Map.of(TargetObject.DISPLAY_ATTRIBUTE_NAME, "0x0", "Id", 0), "Initialized");
|
||||
|
||||
sessions.setElements(List.of(session0), Map.of(), "Initialized");
|
||||
|
||||
mb.testModel.session.changeAttributes(List.of(), List.of(available, sessions), Map.of(),
|
||||
"Initialized");
|
||||
|
||||
sessions.setElements(List.of(
|
||||
session0),
|
||||
Map.of(), "Initialized");
|
||||
|
||||
mb.testModel.session.changeAttributes(List.of(), List.of(
|
||||
available,
|
||||
sessions),
|
||||
Map.of(), "Initialized");
|
||||
|
||||
Swing.runNow(() -> {
|
||||
modelService.addModel(mb.testModel);
|
||||
modelService.activateModel(mb.testModel);
|
||||
|
@ -813,6 +813,26 @@ public enum DebugModelConventions {
|
||||
return collectAncestors.thenApply(AllRequiredAccess::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request activation of the given object in its nearest active scope
|
||||
*
|
||||
* <p>
|
||||
* Note if the object has no suitable active scope, this method fails silently.
|
||||
*
|
||||
* @param obj the object on which to request activation
|
||||
* @return a future which completes when activation is granted, or exceptionally
|
||||
*/
|
||||
public static CompletableFuture<Void> requestActivation(TargetObject obj) {
|
||||
CompletableFuture<? extends TargetActiveScope> futureActivator =
|
||||
DebugModelConventions.findSuitable(TargetActiveScope.class, obj);
|
||||
return futureActivator.thenCompose(activator -> {
|
||||
if (activator == null) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
return activator.requestActivation(obj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Request focus on the given object in its nearest focus scope
|
||||
*
|
||||
|
@ -0,0 +1,38 @@
|
||||
/* ###
|
||||
* 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 ghidra.dbg.target;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import ghidra.dbg.DebuggerTargetObjectIface;
|
||||
|
||||
/**
|
||||
* An object made active
|
||||
*
|
||||
* "Active" here describes which object in a given class the target should operate on
|
||||
*/
|
||||
@DebuggerTargetObjectIface("ActiveScope")
|
||||
public interface TargetActiveScope extends TargetObject {
|
||||
|
||||
/**
|
||||
* Set the given object as the target's active object for the given type
|
||||
*
|
||||
* @param obj the object to setActive
|
||||
* @return a future which completes upon successfully changing focus.
|
||||
*/
|
||||
CompletableFuture<Void> requestActivation(TargetObject obj);
|
||||
|
||||
}
|
@ -27,8 +27,7 @@ import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
@DebuggerTargetObjectIface("EventScope")
|
||||
public interface TargetEventScope extends TargetObject {
|
||||
|
||||
String EVENT_PROCESS_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_process";
|
||||
String EVENT_THREAD_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_thread";
|
||||
String EVENT_OBJECT_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "event_thread";
|
||||
|
||||
public enum TargetEventType {
|
||||
/**
|
||||
@ -116,33 +115,13 @@ public interface TargetEventScope extends TargetObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If applicable, get the process producing the last reported event
|
||||
*
|
||||
* <p>
|
||||
* TODO: This is currently the hexadecimal PID. It should really be a ref to the process object.
|
||||
*
|
||||
* <p>
|
||||
* TODO: Since the event thread will be a successor of the event process, this may not be
|
||||
* needed, but perhaps keep it for convenience.
|
||||
*
|
||||
* @return the process or reference
|
||||
*/
|
||||
@TargetAttributeType(name = EVENT_PROCESS_ATTRIBUTE_NAME, hidden = true)
|
||||
public default /*TODO: TargetProcess*/ String getEventProcess() {
|
||||
return getTypedAttributeNowByName(EVENT_PROCESS_ATTRIBUTE_NAME, String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* If applicable, get the thread producing the last reported event
|
||||
*
|
||||
* <p>
|
||||
* TODO: This is currently the hexadecimal TID. It should really be a ref to the thread object.
|
||||
*
|
||||
* @return the thread or reference
|
||||
*/
|
||||
@TargetAttributeType(name = EVENT_THREAD_ATTRIBUTE_NAME, hidden = true)
|
||||
public default /*TODO: TargetThread*/ String getEventThread() {
|
||||
return getTypedAttributeNowByName(EVENT_THREAD_ATTRIBUTE_NAME, String.class, null);
|
||||
@TargetAttributeType(name = EVENT_OBJECT_ATTRIBUTE_NAME, hidden = true)
|
||||
public default TargetThread getEventThread() {
|
||||
return getTypedAttributeNowByName(EVENT_OBJECT_ATTRIBUTE_NAME, TargetThread.class, null);
|
||||
}
|
||||
}
|
||||
|
@ -158,20 +158,21 @@ import ghidra.lifecycle.Internal;
|
||||
*/
|
||||
public interface TargetObject extends Comparable<TargetObject> {
|
||||
|
||||
Set<Class<? extends TargetObject>> ALL_INTERFACES = Set.of(TargetAccessConditioned.class,
|
||||
TargetAggregate.class, TargetAttachable.class, TargetAttacher.class,
|
||||
TargetBreakpointLocation.class, TargetBreakpointLocationContainer.class,
|
||||
TargetBreakpointSpec.class, TargetBreakpointSpecContainer.class, TargetConsole.class,
|
||||
TargetDataTypeMember.class, TargetDataTypeNamespace.class, TargetDeletable.class,
|
||||
TargetDetachable.class, TargetEnvironment.class, TargetEventScope.class,
|
||||
TargetExecutionStateful.class, TargetFocusScope.class, TargetInterpreter.class,
|
||||
TargetInterruptible.class, TargetKillable.class, TargetLauncher.class, TargetMemory.class,
|
||||
TargetMemoryRegion.class, TargetMethod.class, TargetModule.class,
|
||||
TargetModuleContainer.class, TargetNamedDataType.class, TargetProcess.class,
|
||||
TargetRegister.class, TargetRegisterBank.class, TargetRegisterContainer.class,
|
||||
TargetResumable.class, TargetSection.class, TargetSectionContainer.class, TargetStack.class,
|
||||
TargetStackFrame.class, TargetSteppable.class, TargetSymbol.class,
|
||||
TargetSymbolNamespace.class, TargetThread.class, TargetTogglable.class);
|
||||
Set<Class<? extends TargetObject>> ALL_INTERFACES =
|
||||
Set.of(TargetAccessConditioned.class, TargetAggregate.class, TargetAttachable.class,
|
||||
TargetAttacher.class, TargetBreakpointLocation.class,
|
||||
TargetBreakpointLocationContainer.class, TargetBreakpointSpec.class,
|
||||
TargetBreakpointSpecContainer.class, TargetConsole.class, TargetDataTypeMember.class,
|
||||
TargetDataTypeNamespace.class, TargetDeletable.class, TargetDetachable.class,
|
||||
TargetEnvironment.class, TargetEventScope.class, TargetExecutionStateful.class,
|
||||
TargetActiveScope.class, TargetFocusScope.class, TargetInterpreter.class,
|
||||
TargetInterruptible.class, TargetKillable.class, TargetLauncher.class,
|
||||
TargetMemory.class, TargetMemoryRegion.class, TargetMethod.class, TargetModule.class,
|
||||
TargetModuleContainer.class, TargetNamedDataType.class, TargetProcess.class,
|
||||
TargetRegister.class, TargetRegisterBank.class, TargetRegisterContainer.class,
|
||||
TargetResumable.class, TargetSection.class, TargetSectionContainer.class,
|
||||
TargetStack.class, TargetStackFrame.class, TargetSteppable.class, TargetSymbol.class,
|
||||
TargetSymbolNamespace.class, TargetThread.class, TargetTogglable.class);
|
||||
Map<String, Class<? extends TargetObject>> INTERFACES_BY_NAME = initInterfacesByName();
|
||||
|
||||
/**
|
||||
@ -300,8 +301,7 @@ public interface TargetObject extends Comparable<TargetObject> {
|
||||
return false;
|
||||
}
|
||||
TargetObject that = (TargetObject) obj;
|
||||
return this.getModel() == that.getModel() &&
|
||||
Objects.equals(this.getPath(), that.getPath());
|
||||
return this.getModel() == that.getModel() && Objects.equals(this.getPath(), that.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -371,8 +371,7 @@ public interface TargetObject extends Comparable<TargetObject> {
|
||||
}
|
||||
int result = thisModel.toString().compareTo(thatModel.toString());
|
||||
if (result == 0) {
|
||||
return Integer.compare(
|
||||
System.identityHashCode(thisModel),
|
||||
return Integer.compare(System.identityHashCode(thisModel),
|
||||
System.identityHashCode(thatModel));
|
||||
}
|
||||
return result;
|
||||
@ -707,8 +706,7 @@ public interface TargetObject extends Comparable<TargetObject> {
|
||||
* interface
|
||||
*/
|
||||
public default <T extends TargetObject> //
|
||||
CompletableFuture<? extends Map<String, ? extends T>> fetchChildrenSupporting(
|
||||
Class<T> iface) {
|
||||
CompletableFuture<? extends Map<String, ? extends T>> fetchChildrenSupporting(Class<T> iface) {
|
||||
return fetchChildren().thenApply(m -> m.entrySet()
|
||||
.stream()
|
||||
.filter(e -> iface.isAssignableFrom(e.getValue().getClass()))
|
||||
@ -793,8 +791,7 @@ public interface TargetObject extends Comparable<TargetObject> {
|
||||
/**
|
||||
* @see #fetchSubAttributes(List)
|
||||
*/
|
||||
public default CompletableFuture<? extends Map<String, ?>> fetchSubAttributes(
|
||||
String... sub) {
|
||||
public default CompletableFuture<? extends Map<String, ?>> fetchSubAttributes(String... sub) {
|
||||
return fetchSubAttributes(List.of(sub));
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@ package docking.widgets.timeline;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
public interface TimelineViewRangeListener {
|
||||
void viewRangeChanged(Range<Double> viewRange);
|
||||
public interface TimelineListener {
|
||||
default void viewRangeChanged(Range<Double> viewRange) {
|
||||
}
|
||||
|
||||
default void itemActivated(int index) {
|
||||
}
|
||||
}
|
@ -433,6 +433,7 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
}
|
||||
|
||||
protected class CellMouseListener extends MouseAdapter {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
Component cell = e.getComponent();
|
||||
@ -454,6 +455,7 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
else {
|
||||
selectionModel.setSelectionInterval(index, index);
|
||||
}
|
||||
timelineListeners.fire.itemActivated(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,8 +483,8 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
protected final ItemTracker rows = new ItemTracker();
|
||||
protected final List<TimelineTrack<T, N>> tracks = new ArrayList<>();
|
||||
protected final Map<T, TimelineTrack<T, N>> trackMap = new HashMap<>();
|
||||
protected final ListenerSet<TimelineViewRangeListener> viewRangeListeners =
|
||||
new ListenerSet<>(TimelineViewRangeListener.class);
|
||||
protected final ListenerSet<TimelineListener> timelineListeners =
|
||||
new ListenerSet<>(TimelineListener.class);
|
||||
protected final MouseListener mouseListener = new CellMouseListener();
|
||||
protected final FocusListener focusListener = new CellFocusListener();
|
||||
|
||||
@ -497,12 +499,12 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
setSelectionModel(new DefaultListSelectionModel());
|
||||
}
|
||||
|
||||
public void addViewRangeListener(TimelineViewRangeListener listener) {
|
||||
viewRangeListeners.add(listener);
|
||||
public void addTimelineListener(TimelineListener listener) {
|
||||
timelineListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeViewRangeListener(TimelineViewRangeListener listener) {
|
||||
viewRangeListeners.remove(listener);
|
||||
public void removeTimelineListener(TimelineListener listener) {
|
||||
timelineListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected Range<Double> computeViewRange() {
|
||||
@ -765,7 +767,7 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
track.setViewRange(newViewRange);
|
||||
}
|
||||
validate();
|
||||
viewRangeListeners.fire.viewRangeChanged(newViewRange);
|
||||
timelineListeners.fire.viewRangeChanged(newViewRange);
|
||||
}
|
||||
|
||||
public Range<Double> getViewRange() {
|
||||
@ -777,10 +779,8 @@ public class TimelinePanel<T, N extends Number & Comparable<N>> extends JPanel {
|
||||
UIManager.getDefaults()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(
|
||||
ent -> cls.isInstance(ent.getValue()))
|
||||
.forEach(
|
||||
ent -> sorted.put(ent.getKey(), cls.cast(ent.getValue())));
|
||||
.filter(ent -> cls.isInstance(ent.getValue()))
|
||||
.forEach(ent -> sorted.put(ent.getKey(), cls.cast(ent.getValue())));
|
||||
for (Entry<Object, C> ent : sorted.entrySet()) {
|
||||
System.out.println(String.format("%s=%s", ent.getKey(), fmt.apply(ent.getValue())));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user