mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-10-01 07:54:25 +00:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
b2a553073f
|
@ -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>" +
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) + '"';
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue