Merge remote-tracking branch 'origin/GP-2089_Dan_supportGdb12--SQUASHED'

(Closes #4297)
This commit is contained in:
Ryan Kurtz 2022-06-16 01:54:40 -04:00
commit cbeca0c544
5 changed files with 124 additions and 27 deletions

View File

@ -40,12 +40,22 @@ import ghidra.util.Msg;
* The implementation of {@link GdbInferior}
*/
public class GdbInferiorImpl implements GdbInferior {
protected static final Pattern MEMORY_MAPPING_LINE_PATTERN = Pattern.compile("\\s*" + //
"0x(?<start>[0-9,A-F,a-f]+)\\s+" + //
"0x(?<end>[0-9,A-F,a-f]+)\\s+" + //
"0x(?<size>[0-9,A-F,a-f]+)\\s+" + //
"0x(?<offset>[0-9,A-F,a-f]+)\\s*" + //
"(?<file>\\S*)\\s*");
protected static final Pattern MEMORY_MAPPING_WOUT_FLAGS_LINE_PATTERN =
Pattern.compile("\\s*" +
"0x(?<start>[0-9,A-F,a-f]+)\\s+" +
"0x(?<end>[0-9,A-F,a-f]+)\\s+" +
"0x(?<size>[0-9,A-F,a-f]+)\\s+" +
"0x(?<offset>[0-9,A-F,a-f]+)\\s+" +
"(?<file>\\S*)\\s*");
protected static final Pattern MEMORY_MAPPING_LINE_PATTERN =
Pattern.compile("\\s*" + //
"0x(?<start>[0-9,A-F,a-f]+)\\s+" +
"0x(?<end>[0-9,A-F,a-f]+)\\s+" +
"0x(?<size>[0-9,A-F,a-f]+)\\s+" +
"0x(?<offset>[0-9,A-F,a-f]+)\\s+" +
"(?<flags>[rwsxp\\-]+)\\s+" +
"(?<file>\\S*)\\s*");
private final GdbManagerImpl manager;
private final int id;
@ -367,21 +377,47 @@ public class GdbInferiorImpl implements GdbInferior {
.thenApply(this::parseMappings);
}
protected GdbMemoryMapping parseMappingLine(String line) throws NumberFormatException {
Matcher mappingMatcher = MEMORY_MAPPING_LINE_PATTERN.matcher(line);
if (!mappingMatcher.matches()) {
return null;
}
BigInteger start = new BigInteger(mappingMatcher.group("start"), 16);
BigInteger end = new BigInteger(mappingMatcher.group("end"), 16);
BigInteger size = new BigInteger(mappingMatcher.group("size"), 16);
BigInteger offset = new BigInteger(mappingMatcher.group("offset"), 16);
String flags = mappingMatcher.group("flags");
String objfile = mappingMatcher.group("file");
return new GdbMemoryMapping(start, end, size, offset, flags, objfile);
}
protected GdbMemoryMapping parseMappingsLineWOutFlags(String line)
throws NumberFormatException {
Matcher mappingMatcher = MEMORY_MAPPING_WOUT_FLAGS_LINE_PATTERN.matcher(line);
if (!mappingMatcher.matches()) {
return null;
}
BigInteger start = new BigInteger(mappingMatcher.group("start"), 16);
BigInteger end = new BigInteger(mappingMatcher.group("end"), 16);
BigInteger size = new BigInteger(mappingMatcher.group("size"), 16);
BigInteger offset = new BigInteger(mappingMatcher.group("offset"), 16);
String objfile = mappingMatcher.group("file");
return new GdbMemoryMapping(start, end, size, offset, "rwx", objfile);
}
protected Map<BigInteger, GdbMemoryMapping> parseMappings(String out) {
Set<BigInteger> startsSeen = new TreeSet<>();
for (String line : out.split("\n")) {
Matcher mappingMatcher = MEMORY_MAPPING_LINE_PATTERN.matcher(line);
if (!mappingMatcher.matches()) {
continue;
}
try {
BigInteger start = new BigInteger(mappingMatcher.group("start"), 16);
BigInteger end = new BigInteger(mappingMatcher.group("end"), 16);
BigInteger size = new BigInteger(mappingMatcher.group("size"), 16);
BigInteger offset = new BigInteger(mappingMatcher.group("offset"), 16);
String objfile = mappingMatcher.group("file");
startsSeen.add(start);
mappings.put(start, new GdbMemoryMapping(start, end, size, offset, objfile));
GdbMemoryMapping mapping = parseMappingLine(line);
if (mapping == null) {
mapping = parseMappingsLineWOutFlags(line);
}
if (mapping == null) { // still, so it matches neither pattern
continue; // It's just a throw-away line, or the format changed again.
}
startsSeen.add(mapping.getStart());
mappings.put(mapping.getStart(), mapping);
}
catch (NumberFormatException e) {
Msg.error(this, "Could not parse mapping entry: " + line, e);

View File

@ -18,40 +18,96 @@ package agent.gdb.manager.impl;
import java.math.BigInteger;
import java.util.Objects;
/**
* The abstraction for a line of output from {@code info proc mappings}
*/
public class GdbMemoryMapping {
private final BigInteger start;
private final BigInteger end;
private final BigInteger size;
private final BigInteger offset;
private final String flags;
private final String objfile;
/**
* Construct a memory mapping
*
* @param start the start offset
* @param end the end offset
* @param size the size (must be end - start)
* @param offset if backed by a file, the offset into that file
* @param flags the flags: rwxsp for read, write, execute, shared, private. If not known, the
* default "rwx" should be used.
* @param objfile if backed by a file, the name of that file
*/
public GdbMemoryMapping(BigInteger start, BigInteger end, BigInteger size, BigInteger offset,
String objfile) {
String flags, String objfile) {
this.start = start;
this.end = end;
this.size = size;
this.offset = offset;
this.flags = flags;
this.objfile = objfile;
assert Objects.equals(start.add(size), end);
}
/**
* The start offset
*
* @return the offset
*/
public BigInteger getStart() {
return start;
}
/**
* The end offset
*
* @return the end
*/
public BigInteger getEnd() {
return end;
}
/**
* The size
*
* @return the size
*/
public BigInteger getSize() {
return size;
}
/**
* If backed by a file, the offset into that file
*
* @return the offset
*/
public BigInteger getOffset() {
return offset;
}
/**
* The flags
*
* <p>
* As of gdb-12.1, this is a four-character string, e.g., r--p, where the first three indicate
* <b>r</b>ead, <b>w</b>rite, and e<b>x</b>ecute. Each position is either the character
* indicating the flag is present, or a dash indicating the flag is absent. The final position
* is either {@code s} or {@code p} to indicate shared or private.
*
* @return the flags
*/
public String getFlags() {
return flags;
}
/**
* If backed by a file, the name of that file
*
* @return the file
*/
public String getObjfile() {
return objfile;
}

View File

@ -59,6 +59,7 @@ public class GdbModelTargetMemoryRegion
}
protected AddressRangeImpl range;
protected final String flags;
protected final String objfile;
protected final long offset;
protected final String display;
@ -76,6 +77,7 @@ public class GdbModelTargetMemoryRegion
catch (AddressFormatException | AddressOverflowException e) {
throw new AssertionError(e);
}
this.flags = mapping.getFlags();
changeAttributes(List.of(), Map.of( //
MEMORY_ATTRIBUTE_NAME, memory, //
RANGE_ATTRIBUTE_NAME, range, //
@ -111,19 +113,20 @@ public class GdbModelTargetMemoryRegion
@Override
public boolean isReadable() {
// It can be done if debugging locally on Linux, by reading /proc/[PID]/maps
// The sections listing will give the initial protections.
return true; // TODO
// This was added at or near gdb-12.1
return flags.contains("r");
}
@Override
public boolean isWritable() {
return true; // TODO
// This was added at or near gdb-12.1
return flags.contains("w");
}
@Override
public boolean isExecutable() {
return true; // TODO
// This was added at or near gdb-12.1
return flags.contains("x");
}
@TargetAttributeType(

View File

@ -76,16 +76,16 @@ public class GdbModelTargetProcessMemory
if (end.longValue() < 0) {
BigInteger split = BigInteger.valueOf(Long.MAX_VALUE);
GdbMemoryMapping lmem = new GdbMemoryMapping(start, split,
split.subtract(start), start.subtract(start), "defaultLow");
split.subtract(start), start.subtract(start), "rwx", "defaultLow");
defaultMap.put(start, lmem);
split = split.add(BigInteger.valueOf(1));
GdbMemoryMapping hmem = new GdbMemoryMapping(split, end,
end.subtract(split), split.subtract(split), "defaultHigh");
end.subtract(split), split.subtract(split), "rwx", "defaultHigh");
defaultMap.put(split, hmem);
}
else {
GdbMemoryMapping mem = new GdbMemoryMapping(start, end,
end.subtract(start), start.subtract(start), "default");
end.subtract(start), start.subtract(start), "rwx", "default");
defaultMap.put(start, mem);
}
regions =
@ -104,7 +104,7 @@ public class GdbModelTargetProcessMemory
// Can't use refresh getKnownMappings is only populated by listMappings
return doRefresh();
}
protected CompletableFuture<Void> doRefresh() {
if (inferior.getPid() == null) {
setElements(List.of(), "Refreshed (while no process)");

View File

@ -37,6 +37,8 @@ import ghidra.util.Msg;
*/
public abstract class AbstractDebuggerModelScenarioMemoryTest extends AbstractDebuggerModelTest {
// TODO: Something for expected flags, permissions?
/**
* This specimen must perform some observable action, which can be affected by a memory write
*