GP-1808: Added 'Run to Address'-type actions to right-click menu for some connectors.

This commit is contained in:
Dan 2023-02-07 12:23:16 -05:00
parent 44d7c4f031
commit bde529b4d5
39 changed files with 1663 additions and 136 deletions

View file

@ -120,6 +120,22 @@ public interface DbgThread
*/
CompletableFuture<Void> step(Map<String, ?> args);
/**
* Step (over) the thread until the specified address is reached
*
* @param address the stop address
* @return a future that completes once the thread is running
*/
CompletableFuture<Void> stepToAddress(String address);
/**
* Trace (step into) the thread until the specified address is reached
*
* @param address the stop address
* @return a future that completes once the thread is running
*/
CompletableFuture<Void> traceToAddress(String address);
/**
* Detach from the entire process
*

View file

@ -0,0 +1,73 @@
/* ###
* 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.dbgeng.DebugControl;
import agent.dbgeng.dbgeng.DebugThreadId;
import agent.dbgeng.manager.DbgEvent;
import agent.dbgeng.manager.evt.*;
import agent.dbgeng.manager.impl.DbgManagerImpl;
import agent.dbgeng.manager.impl.DbgThreadImpl;
import ghidra.util.Msg;
public abstract class AbstractDbgExecToAddressCommand extends AbstractDbgCommand<Void> {
private final DebugThreadId id;
private final String address;
public AbstractDbgExecToAddressCommand(DbgManagerImpl manager, DebugThreadId id,
String address) {
super(manager);
this.id = id;
this.address = address;
}
@Override
public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) {
if (evt instanceof AbstractDbgCompletedCommandEvent && pending.getCommand().equals(this)) {
return evt instanceof DbgCommandErrorEvent ||
!pending.findAllOf(DbgRunningEvent.class).isEmpty();
}
else if (evt instanceof DbgRunningEvent) {
// Event happens no matter which interpreter received the command
pending.claim(evt);
return !pending.findAllOf(AbstractDbgCompletedCommandEvent.class).isEmpty();
}
return false;
}
protected abstract String generateCommand(String address);
@Override
public void invoke() {
String cmd = generateCommand(address);
String prefix = id == null ? "" : "~" + id.id + " ";
DebugControl control = manager.getControl();
DbgThreadImpl eventThread = manager.getEventThread();
if (eventThread != null && eventThread.getId().equals(id)) {
control.execute(cmd);
}
else {
if (manager.isKernelMode()) {
Msg.info(this, "Thread-specific steppign is ignored in kernel-mode");
control.execute(cmd);
}
else {
control.execute(prefix + cmd);
}
}
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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.dbgeng.DebugThreadId;
import agent.dbgeng.manager.impl.DbgManagerImpl;
public class DbgStepToAddressCommand extends AbstractDbgExecToAddressCommand {
public DbgStepToAddressCommand(DbgManagerImpl manager, DebugThreadId id, String address) {
super(manager, id, address);
}
@Override
protected String generateCommand(String address) {
return "pa " + address;
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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.dbgeng.DebugThreadId;
import agent.dbgeng.manager.impl.DbgManagerImpl;
public class DbgTraceToAddressCommand extends AbstractDbgExecToAddressCommand {
public DbgTraceToAddressCommand(DbgManagerImpl manager, DebugThreadId id, String address) {
super(manager, id, address);
}
@Override
protected String generateCommand(String address) {
return "ta " + address;
}
}

View file

@ -225,6 +225,20 @@ public class DbgThreadImpl implements DbgThread {
});
}
@Override
public CompletableFuture<Void> stepToAddress(String address) {
return setActive().thenCompose(__ -> {
return manager.execute(new DbgStepToAddressCommand(manager, id, address));
});
}
@Override
public CompletableFuture<Void> traceToAddress(String address) {
return setActive().thenCompose(__ -> {
return manager.execute(new DbgTraceToAddressCommand(manager, id, address));
});
}
@Override
public CompletableFuture<Void> kill() {
return setActive().thenCompose(__ -> {

View file

@ -61,8 +61,6 @@ public interface DbgModelTargetSteppable extends DbgModelTargetObject, TargetSte
switch (kind) {
case SKIP:
throw new UnsupportedOperationException(kind.name());
case ADVANCE: // Why no exec-advance in dbgeng?
return thread.console("advance");
default:
if (this instanceof DbgModelTargetThread) {
DbgModelTargetThread targetThread = (DbgModelTargetThread) this;

View file

@ -23,11 +23,13 @@ import agent.dbgeng.manager.*;
import agent.dbgeng.manager.impl.*;
import agent.dbgeng.model.iface1.*;
import agent.dbgeng.model.impl.DbgModelTargetStackImpl;
import ghidra.dbg.target.TargetThread;
import ghidra.dbg.target.*;
import ghidra.dbg.util.PathUtils;
import ghidra.program.model.address.Address;
public interface DbgModelTargetThread extends //
TargetThread, //
TargetAggregate, //
DbgModelTargetAccessConditioned, //
DbgModelTargetExecutionStateful, //
DbgModelTargetSteppable, //
@ -58,6 +60,24 @@ public interface DbgModelTargetThread extends //
}
}
@TargetMethod.Export("Step to Address (pa)")
public default CompletableFuture<Void> stepToAddress(
@TargetMethod.Param(
description = "The target address",
display = "StopAddress",
name = "address") Address address) {
return getModel().gateFuture(getThread().stepToAddress(address.toString(false)));
}
@TargetMethod.Export("Trace to Address (ta)")
public default CompletableFuture<Void> traceToAddress(
@TargetMethod.Param(
description = "The target address",
display = "StopAddress",
name = "address") Address address) {
return getModel().gateFuture(getThread().traceToAddress(address.toString(false)));
}
@Override
public default CompletableFuture<Void> setActive() {
DbgManagerImpl manager = getManager();

View file

@ -183,8 +183,6 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
switch (kind) {
case SKIP:
throw new UnsupportedOperationException(kind.name());
case ADVANCE: // Why no exec-advance in dbgeng?
throw new UnsupportedOperationException(kind.name());
default:
return model.gateFuture(process.step(convertToDbg(kind)));
}

View file

@ -15,6 +15,7 @@
*/
package agent.dbgeng.model.impl;
import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@ -26,6 +27,7 @@ import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
import agent.dbgeng.model.iface2.*;
import ghidra.dbg.target.TargetEnvironment;
import ghidra.dbg.target.TargetFocusScope;
import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
@ -50,7 +52,6 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetThread {
public static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( //
TargetStepKind.ADVANCE, //
TargetStepKind.FINISH, //
TargetStepKind.LINE, //
TargetStepKind.OVER, //
@ -90,6 +91,9 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
this.registers = new DbgModelTargetRegisterContainerImpl(this);
this.stack = new DbgModelTargetStackImpl(this, process);
changeAttributes(List.of(), List.of(),
AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), threads.getModel(), this),
"Methods");
changeAttributes(List.of(), List.of( //
registers, //
stack //
@ -145,8 +149,6 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
switch (kind) {
case SKIP:
throw new UnsupportedOperationException(kind.name());
case ADVANCE: // Why no exec-advance in GDB/MI?
return thread.console("advance");
default:
return model.gateFuture(thread.step(convertToDbg(kind)));
}