GP-3984: Have gdb connector delay section info until asked.

This commit is contained in:
Dan 2024-02-01 08:50:27 -05:00
parent 683dfc6da3
commit 644e2c53e5
22 changed files with 301 additions and 141 deletions

View file

@ -23,8 +23,8 @@ import ghidra.debug.api.tracermi.*;
import ghidra.trace.model.Trace;
public record RecordRemoteMethod(TraceRmiHandler handler, String name, ActionName action,
String description, Map<String, RemoteParameter> parameters, SchemaName retType)
implements RemoteMethod {
String display, String description, Map<String, RemoteParameter> parameters,
SchemaName retType) implements RemoteMethod {
@Override
public DefaultRemoteAsyncResult invokeAsync(Map<String, Object> arguments) {
Trace trace = validate(arguments);

View file

@ -484,10 +484,10 @@ public class TraceRmiHandler implements TraceRmiConnection {
RootMessage.Builder dispatch(RootMessage req, RootMessage.Builder rep) throws Exception;
default RootMessage handle(RootMessage req) {
String desc = toString(req);
/*String desc = toString(req);
if (desc != null) {
TimedMsg.debug(this, "HANDLING: " + desc);
}
}*/
RootMessage.Builder rep = RootMessage.newBuilder();
try {
rep = dispatch(req, rep);
@ -814,7 +814,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
protected ReplyActivate handleActivate(RequestActivate req) {
OpenTrace open = requireOpenTrace(req.getOid());
TraceObject object = open.getObject(req.getObject(), true);
TraceObject object = open.getObject(req.getObject(), false);
DebuggerCoordinates coords = traceManager.getCurrent();
if (coords.getTrace() != open.trace) {
coords = DebuggerCoordinates.NOWHERE;
@ -822,7 +822,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
if (open.lastSnapshot != null && followsPresent(open.trace)) {
coords = coords.snap(open.lastSnapshot.getKey());
}
DebuggerCoordinates finalCoords = coords.object(object);
DebuggerCoordinates finalCoords = object == null ? coords : coords.object(object);
Swing.runLater(() -> {
if (!traceManager.getOpenTraces().contains(open.trace)) {
traceManager.openTrace(open.trace);
@ -1031,7 +1031,7 @@ public class TraceRmiHandler implements TraceRmiConnection {
}
for (Method m : req.getMethodsList()) {
RemoteMethod rm = new RecordRemoteMethod(this, m.getName(),
ActionName.name(m.getAction()),
ActionName.name(m.getAction()), m.getDisplay(),
m.getDescription(), m.getParametersList()
.stream()
.collect(Collectors.toMap(MethodParameter::getName, this::makeParameter)),

View file

@ -240,6 +240,16 @@ public class TraceRmiTarget extends AbstractTarget {
}
}
protected long computeSpecificity(Map<String, Object> args) {
long score = 0;
for (Object o : args.values()) {
if (o instanceof TraceObject obj) {
score += obj.getCanonicalPath().getKeyList().size();
}
}
return score;
}
protected BooleanSupplier chooseEnabler(RemoteMethod method, Map<String, Object> args) {
ActionName name = method.action();
SchemaContext ctx = getSchemaContext();
@ -282,7 +292,7 @@ public class TraceRmiTarget extends AbstractTarget {
private Map<String, Object> promptArgs(RemoteMethod method, Map<String, Object> defaults) {
SchemaContext ctx = getSchemaContext();
RemoteMethodInvocationDialog dialog = new RemoteMethodInvocationDialog(tool,
method.name(), method.name(), null);
method.display(), method.display(), null);
while (true) {
for (RemoteParameter param : method.parameters().values()) {
Object val = defaults.get(param.name());
@ -325,8 +335,9 @@ public class TraceRmiTarget extends AbstractTarget {
Map<String, Object> args = collectArguments(method, context, allowContextObject,
allowCoordsObject, allowSuitableObject);
boolean requiresPrompt = args.values().contains(Missing.MISSING);
return new ActionEntry(method.name(), method.action(), method.description(), requiresPrompt,
chooseEnabler(method, args), prompt -> invokeMethod(prompt, method, args));
return new ActionEntry(method.display(), method.action(), method.description(),
requiresPrompt, computeSpecificity(args), chooseEnabler(method, args),
prompt -> invokeMethod(prompt, method, args));
}
protected Map<String, ActionEntry> collectFromMethods(Collection<RemoteMethod> methods,
@ -415,6 +426,11 @@ public class TraceRmiTarget extends AbstractTarget {
return collectByName(ActionName.STEP_EXT, context);
}
@Override
protected Map<String, ActionEntry> collectRefreshActions(ActionContext context) {
return collectByName(ActionName.REFRESH, context);
}
@Override
public boolean isSupportsFocus() {
TargetObjectSchema schema = trace.getObjectManager().getRootSchema();

View file

@ -22,6 +22,7 @@ import org.apache.commons.lang3.ArrayUtils;
import ghidra.program.model.address.*;
import ghidra.rmi.trace.TraceRmi.*;
import ghidra.util.NumericUtilities;
public interface ValueDecoder {
ValueDecoder DEFAULT = new ValueDecoder() {};
@ -104,7 +105,8 @@ public interface ValueDecoder {
case STRING_VALUE -> value.getStringValue();
case BOOL_ARR_VALUE -> ArrayUtils.toPrimitive(
value.getBoolArrValue().getArrList().stream().toArray(Boolean[]::new));
case BYTES_VALUE -> value.getBytesValue().toByteArray();
case BYTES_VALUE -> NumericUtilities
.convertBytesToString(value.getBytesValue().toByteArray(), ":");
case CHAR_ARR_VALUE -> value.getCharArrValue().toCharArray();
case SHORT_ARR_VALUE -> ArrayUtils.toPrimitive(
value.getShortArrValue()

View file

@ -417,11 +417,12 @@ message MethodArgument {
message Method {
string name = 1;
string action = 2;
string description = 3;
repeated MethodParameter parameters = 4;
string display = 3;
string description = 4;
repeated MethodParameter parameters = 5;
// I'd like to make them all void, but I think executing a command and capturing its output
// justifies being able to return a result. It should be used very sparingly.
ValueType return_type = 5;
ValueType return_type = 6;
}
message RequestNegotiate {

View file

@ -425,6 +425,7 @@ class ParamDesc:
class RemoteMethod:
name: str
action: str
display: str
description: str
parameters: List[RemoteParameter]
return_schema: sch.Schema
@ -484,11 +485,14 @@ class MethodRegistry(object):
cls._to_display(p.annotation), cls._to_description(p.annotation))
@classmethod
def create_method(cls, function, name=None, action=None, description=None) -> RemoteMethod:
def create_method(cls, function, name=None, action=None, display=None,
description=None) -> RemoteMethod:
if name is None:
name = function.__name__
if action is None:
action = name
if display is None:
display = name
if description is None:
description = function.__doc__ or ''
sig = inspect.signature(function)
@ -496,14 +500,16 @@ class MethodRegistry(object):
for p in sig.parameters.values():
params.append(cls._make_param(p))
return_schema = cls._to_schema(sig, sig.return_annotation)
return RemoteMethod(name, action, description, params, return_schema, function)
return RemoteMethod(name, action, display, description, params,
return_schema, function)
def method(self, func=None, *, name=None, action=None, description='',
condition=True):
def method(self, func=None, *, name=None, action=None, display=None,
description='', condition=True):
def _method(func):
if condition:
method = self.create_method(func, name, action, description)
method = self.create_method(func, name, action, display,
description)
self.register_method(method)
return func
@ -669,6 +675,7 @@ class Client(object):
def _write_method(to: bufs.Method, method: RemoteMethod):
to.name = method.name
to.action = method.action
to.display = method.display
to.description = method.description
Client._write_parameters(to.parameters, method.parameters)
to.return_type.name = method.return_schema.name

View file

@ -48,19 +48,19 @@ public class TestTraceRmiConnection implements TraceRmiConnection {
}
}
public record TestRemoteMethod(String name, ActionName action, String description,
Map<String, RemoteParameter> parameters, SchemaName retType,
public record TestRemoteMethod(String name, ActionName action, String display,
String description, Map<String, RemoteParameter> parameters, SchemaName retType,
AsyncPairingQueue<Map<String, Object>> argQueue, AsyncPairingQueue<Object> retQueue)
implements RemoteMethod {
public TestRemoteMethod(String name, ActionName action, String description,
public TestRemoteMethod(String name, ActionName action, String display, String description,
Map<String, RemoteParameter> parameters, SchemaName retType) {
this(name, action, description, parameters, retType, new AsyncPairingQueue<>(),
this(name, action, display, description, parameters, retType, new AsyncPairingQueue<>(),
new AsyncPairingQueue<>());
}
public TestRemoteMethod(String name, ActionName action, String description,
public TestRemoteMethod(String name, ActionName action, String display, String description,
SchemaName retType, RemoteParameter... parameters) {
this(name, action, description, Stream.of(parameters)
this(name, action, display, description, Stream.of(parameters)
.collect(Collectors.toMap(RemoteParameter::name, p -> p)),
retType);
}