mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-30 16:11:04 +00:00
GP-2223: Better strategy for computing module base with GDB.
This commit is contained in:
parent
c32b6d6bdb
commit
215cd7c4f3
@ -16,8 +16,7 @@
|
||||
package agent.gdb.manager;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.gdb.manager.GdbManager.StepCmd;
|
||||
@ -133,14 +132,14 @@ public interface GdbInferior extends GdbConsoleOperations, GdbMemoryOperations {
|
||||
*
|
||||
* @return a map of start addresses to mapped memory regions
|
||||
*/
|
||||
Map<BigInteger, GdbMemoryMapping> getKnownMappings();
|
||||
NavigableMap<BigInteger, GdbMemoryMapping> getKnownMappings();
|
||||
|
||||
/**
|
||||
* List the memory mappings of this inferior's process
|
||||
*
|
||||
* @return a future that completes with a map of start addresses to mapped memory regions
|
||||
*/
|
||||
CompletableFuture<Map<BigInteger, GdbMemoryMapping>> listMappings();
|
||||
CompletableFuture<NavigableMap<BigInteger, GdbMemoryMapping>> listMappings();
|
||||
|
||||
/**
|
||||
* Change CLI focus to this inferior
|
||||
|
@ -252,9 +252,12 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
}
|
||||
|
||||
protected CompletableFuture<Map<String, GdbModule>> doListModules() {
|
||||
return manager.execMaintInfoSectionsAllObjects(this).thenApply(lines -> {
|
||||
parseAndUpdateAllModuleSections(lines);
|
||||
return unmodifiableModules;
|
||||
return manager.execMaintInfoSectionsAllObjects(this).thenCompose(lines -> {
|
||||
return listMappings().thenApply(mappings -> {
|
||||
GdbMemoryMapping.Index index = new GdbMemoryMapping.Index(mappings);
|
||||
parseAndUpdateAllModuleSections(lines, index);
|
||||
return unmodifiableModules;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -297,7 +300,7 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void parseAndUpdateAllModuleSections(String[] lines) {
|
||||
protected void parseAndUpdateAllModuleSections(String[] lines, GdbMemoryMapping.Index index) {
|
||||
Set<String> modNamesSeen = new HashSet<>();
|
||||
Set<String> secNamesSeen = new HashSet<>();
|
||||
GdbModuleImpl curModule = null;
|
||||
@ -312,7 +315,7 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
curModule = modules.computeIfAbsent(name, this::resyncCreateModule);
|
||||
}
|
||||
else if (curModule != null) {
|
||||
curModule.processSectionLine(line, secNamesSeen);
|
||||
curModule.processSectionLine(line, secNamesSeen, index);
|
||||
}
|
||||
}
|
||||
if (curModule != null) {
|
||||
@ -323,12 +326,12 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BigInteger, GdbMemoryMapping> getKnownMappings() {
|
||||
public NavigableMap<BigInteger, GdbMemoryMapping> getKnownMappings() {
|
||||
return unmodifiableMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Map<BigInteger, GdbMemoryMapping>> listMappings() {
|
||||
public CompletableFuture<NavigableMap<BigInteger, GdbMemoryMapping>> listMappings() {
|
||||
return consoleCapture("info proc mappings", CompletesWithRunning.CANNOT)
|
||||
.thenApply(this::parseMappings);
|
||||
}
|
||||
@ -361,7 +364,7 @@ public class GdbInferiorImpl implements GdbInferior {
|
||||
return new GdbMemoryMapping(start, end, size, offset, "rwx", objfile);
|
||||
}
|
||||
|
||||
protected Map<BigInteger, GdbMemoryMapping> parseMappings(String out) {
|
||||
protected NavigableMap<BigInteger, GdbMemoryMapping> parseMappings(String out) {
|
||||
Set<BigInteger> startsSeen = new TreeSet<>();
|
||||
for (String line : out.split("\n")) {
|
||||
try {
|
||||
|
@ -16,12 +16,51 @@
|
||||
package agent.gdb.manager.impl;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* The abstraction for a line of output from {@code info proc mappings}
|
||||
*/
|
||||
public class GdbMemoryMapping {
|
||||
|
||||
static class Index {
|
||||
final NavigableMap<BigInteger, GdbMemoryMapping> mappings;
|
||||
final Map<String, BigInteger> bases;
|
||||
|
||||
public Index(NavigableMap<BigInteger, GdbMemoryMapping> mappings) {
|
||||
this.mappings = mappings;
|
||||
this.bases = new HashMap<>();
|
||||
for (GdbMemoryMapping mapping : mappings.values()) {
|
||||
if (mapping.objfile == null || mapping.objfile.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
// Values should be ordered ascending by address
|
||||
if (bases.containsKey(mapping.objfile)) {
|
||||
continue;
|
||||
}
|
||||
bases.put(mapping.objfile, mapping.start);
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger computeBase(BigInteger vma) {
|
||||
Entry<BigInteger, GdbMemoryMapping> floor = mappings.floorEntry(vma);
|
||||
if (floor == null) {
|
||||
return vma;
|
||||
}
|
||||
GdbMemoryMapping mapping = floor.getValue();
|
||||
// NB. Ends given by GDB are exclusive
|
||||
if (mapping.objfile.isBlank() || mapping.end.compareTo(vma) <= 0) {
|
||||
return vma;
|
||||
}
|
||||
return Objects.requireNonNull(bases.get(mapping.objfile));
|
||||
}
|
||||
|
||||
public long computeBase(long vma) {
|
||||
return computeBase(BigInteger.valueOf(vma)).longValueExact();
|
||||
}
|
||||
}
|
||||
|
||||
private final BigInteger start;
|
||||
private final BigInteger end;
|
||||
private final BigInteger size;
|
||||
|
@ -150,7 +150,8 @@ public class GdbModuleImpl implements GdbModule {
|
||||
return minimalSymbols.request();
|
||||
}
|
||||
|
||||
protected void processSectionLine(String line, Set<String> namesSeen) {
|
||||
protected void processSectionLine(String line, Set<String> namesSeen,
|
||||
GdbMemoryMapping.Index index) {
|
||||
Matcher matcher = inferior.manager.matchSectionLine(line);
|
||||
if (matcher != null) {
|
||||
try {
|
||||
@ -167,7 +168,7 @@ public class GdbModuleImpl implements GdbModule {
|
||||
}
|
||||
}
|
||||
if (attrs.contains("ALLOC")) {
|
||||
long b = vmaStart - offset;
|
||||
long b = index.computeBase(vmaStart);
|
||||
base = base == null ? b : MathUtilities.unsignedMin(base, b);
|
||||
max = max == null ? b : MathUtilities.unsignedMax(max, vmaEnd);
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ public class GdbModelTargetProcessMemory
|
||||
}
|
||||
return inferior.listMappings().exceptionally(ex -> {
|
||||
Msg.error(this, "Could not list regions. Using default.");
|
||||
return Map.of(); // empty map will be replaced with default
|
||||
// empty map will be replaced with default
|
||||
return new TreeMap<>();
|
||||
}).thenAccept(this::updateUsingMappings);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user