Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2021-10-20 08:48:35 -04:00
commit b2a553073f
6 changed files with 66 additions and 26 deletions

View File

@ -72,6 +72,7 @@ import sun.misc.SignalHandler;
*/
public class GdbManagerImpl implements GdbManager {
private static final String GDB_IS_TERMINATING = "GDB is terminating";
public static final int MAX_CMD_LEN = 4094; // Account for longest possible line end
private static final String PTY_DIALOG_MESSAGE_PATTERN =
"<html><p>Please enter:</p>" +

View File

@ -19,9 +19,6 @@ import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.RangeSet;
@ -34,8 +31,7 @@ import agent.gdb.manager.impl.cmd.GdbConsoleExecCommand.CompletesWithRunning;
import agent.gdb.manager.parsing.GdbCValueParser;
import agent.gdb.manager.parsing.GdbParsingUtils.GdbParseError;
import agent.gdb.manager.reason.GdbReason;
import ghidra.async.AsyncLazyValue;
import ghidra.async.AsyncReference;
import ghidra.async.*;
/**
* The implementation of {@link GdbThread}
@ -159,6 +155,46 @@ public class GdbThreadImpl implements GdbThread {
return registers.request();
}
private List<String> generateEvaluateSizesParts(Collection<String> names) {
List<String> result = new ArrayList<>();
StringBuffer buf = new StringBuffer("{");
for (String n : names) {
String toAdd = "sizeof($" + n + "),";
if (buf.length() + toAdd.length() > GdbEvaluateCommand.MAX_EXPR_LEN) {
assert buf.length() > 0;
// Remove trailing comma
result.add(buf.substring(0, buf.length() - 1) + "}");
buf.delete(1, buf.length()); // Leave leading brace
}
buf.append(toAdd);
}
if (buf.length() > 0) {
result.add(buf.substring(0, buf.length() - 1) + "}");
}
return result;
}
private CompletableFuture<List<String>> doEvaluateSizesInParts(Collection<String> names) {
List<String> parts = generateEvaluateSizesParts(names);
if (parts.isEmpty()) {
// I guess names was empty
return CompletableFuture.completedFuture(List.of());
}
if (parts.size() == 1) {
return evaluate(parts.get(0)).thenApply(List::of);
}
AsyncFence fence = new AsyncFence();
String[] result = new String[parts.size()];
for (int i = 0; i < result.length; i++) {
String p = parts.get(i);
final int j = i;
fence.include(evaluate(p).thenAccept(r -> {
result[j] = r;
}));
}
return fence.ready().thenApply(__ -> Arrays.asList(result));
}
private CompletableFuture<GdbRegisterSet> doListRegisters() {
Map<Integer, String> namesByNumber = new TreeMap<>();
return execute(new GdbListRegisterNamesCommand(manager, id)).thenCompose(names -> {
@ -169,20 +205,17 @@ public class GdbThreadImpl implements GdbThread {
}
namesByNumber.put(i, n);
}
List<String> sizeofNames = namesByNumber.values()
.stream()
.map(n -> "sizeof($" + n + ")")
.collect(Collectors.toList());
String expr = "{" + StringUtils.join(sizeofNames, ",") + "}";
return evaluate(expr);
}).thenApply(value -> {
return doEvaluateSizesInParts(namesByNumber.values());
}).thenApply(values -> {
List<GdbRegister> regs = new ArrayList<>();
List<Integer> sizes;
try {
sizes = GdbCValueParser.parseArray(value).expectInts();
}
catch (GdbParseError e) {
throw new AssertionError("GDB did not give an integer array!");
List<Integer> sizes = new ArrayList<>();
for (String v : values) {
try {
sizes.addAll(GdbCValueParser.parseArray(v).expectInts());
}
catch (GdbParseError e) {
throw new AssertionError("GDB did not give an integer array!");
}
}
if (sizes.size() != namesByNumber.size()) {
throw new AssertionError("GDB did not give all the sizes!");

View File

@ -25,6 +25,7 @@ import agent.gdb.manager.impl.GdbManagerImpl;
*/
public abstract class AbstractGdbCommandWithThreadAndFrameId<T>
extends AbstractGdbCommandWithThreadId<T> {
protected static final String MI2_FRAME_PREFIX = " --frame ";
protected final Integer frameId;
/**
@ -41,7 +42,7 @@ public abstract class AbstractGdbCommandWithThreadAndFrameId<T>
}
protected String makeFramePart() {
return frameId == null ? "" : " --frame " + frameId;
return frameId == null ? "" : MI2_FRAME_PREFIX + frameId;
}
/**

View File

@ -23,6 +23,7 @@ import agent.gdb.manager.impl.GdbManagerImpl;
* @param <T> the type of object "returned" by the command
*/
public abstract class AbstractGdbCommandWithThreadId<T> extends AbstractGdbCommand<T> {
protected static final String MI2_THREAD_PREFIX = " --thread ";
protected final Integer threadId;
/**
@ -37,7 +38,7 @@ public abstract class AbstractGdbCommandWithThreadId<T> extends AbstractGdbComma
}
protected String makeThreadPart() {
return threadId == null ? "" : " --thread " + threadId;
return threadId == null ? "" : MI2_THREAD_PREFIX + threadId;
}
@Override

View File

@ -26,6 +26,10 @@ import agent.gdb.manager.impl.GdbPendingCommand;
* Implementation of {@link GdbInferior#evaluate(String)}
*/
public class GdbEvaluateCommand extends AbstractGdbCommandWithThreadAndFrameId<String> {
private static final String MI2_CMD = "-data-evaluate-expression";
// 6 accounts for digits in threadId and frameId. 999 each should be plenty....
public static final int MAX_EXPR_LEN = GdbManagerImpl.MAX_CMD_LEN - MI2_CMD.length() -
MI2_THREAD_PREFIX.length() - MI2_FRAME_PREFIX.length() - 6;
private final String expression;
public GdbEvaluateCommand(GdbManagerImpl manager, Integer threadId, Integer frameId,
@ -36,7 +40,7 @@ public class GdbEvaluateCommand extends AbstractGdbCommandWithThreadAndFrameId<S
@Override
protected String encode(String threadPart, String framePart) {
return "-data-evaluate-expression" + threadPart + framePart + " \"" +
return MI2_CMD + threadPart + framePart + " \"" +
StringEscapeUtils.escapeJava(expression) + '"';
}

View File

@ -30,8 +30,11 @@ import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakValueHashMap;
@TargetObjectSchemaInfo(name = "RegisterContainer", attributes = {
@TargetAttributeType(type = Void.class) }, canonicalContainer = true)
@TargetObjectSchemaInfo(
name = "RegisterContainer",
attributes = {
@TargetAttributeType(type = Void.class) },
canonicalContainer = true)
public class GdbModelTargetRegisterContainer
extends DefaultTargetObject<GdbModelTargetRegister, GdbModelTargetInferior>
implements TargetRegisterContainer {
@ -86,9 +89,6 @@ public class GdbModelTargetRegisterContainer
}
public CompletableFuture<Void> refreshInternal() {
if (!isObserved()) {
return AsyncUtils.NIL;
}
return doRefresh().exceptionally(ex -> {
Msg.error(this, "Problem refreshing inferior's register descriptions", ex);
return null;