mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GP-3087_Dan_excludeExternalInEmulation--SQUASHED'
This commit is contained in:
commit
0565d03e69
8 changed files with 113 additions and 63 deletions
|
@ -34,6 +34,7 @@ import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
||||||
import ghidra.util.MathUtilities;
|
import ghidra.util.MathUtilities;
|
||||||
|
import ghidra.util.MessageType;
|
||||||
import ghidra.util.layout.PairLayout;
|
import ghidra.util.layout.PairLayout;
|
||||||
|
|
||||||
public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
||||||
|
@ -52,7 +53,7 @@ public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
||||||
private final GSpanField fieldSpan = new GSpanField();
|
private final GSpanField fieldSpan = new GSpanField();
|
||||||
|
|
||||||
public DebuggerAddMappingDialog() {
|
public DebuggerAddMappingDialog() {
|
||||||
super("Add Static Mapping", false, false, true, false);
|
super("Add Static Mapping", false, true, true, false);
|
||||||
|
|
||||||
populateComponents();
|
populateComponents();
|
||||||
}
|
}
|
||||||
|
@ -103,6 +104,8 @@ public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
||||||
rigFocusAndEnter(fieldLength, this::lengthChanged);
|
rigFocusAndEnter(fieldLength, this::lengthChanged);
|
||||||
rigFocusAndEnter(fieldSpan, this::spanChanged);
|
rigFocusAndEnter(fieldSpan, this::spanChanged);
|
||||||
|
|
||||||
|
fieldSpan.setLifespan(Lifespan.nowOn(0));
|
||||||
|
|
||||||
addWorkPanel(panel);
|
addWorkPanel(panel);
|
||||||
|
|
||||||
addApplyButton();
|
addApplyButton();
|
||||||
|
@ -287,6 +290,12 @@ public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
||||||
return bi.longValue(); // Do not use exact. It checks bitLength again, and considers sign.
|
return bi.longValue(); // Do not use exact. It checks bitLength again, and considers sign.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dialogShown() {
|
||||||
|
super.dialogShown();
|
||||||
|
setStatusText("");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyCallback() {
|
protected void applyCallback() {
|
||||||
TraceLocation from = new DefaultTraceLocation(trace, null, fieldSpan.getLifespan(),
|
TraceLocation from = new DefaultTraceLocation(trace, null, fieldSpan.getLifespan(),
|
||||||
|
@ -295,13 +304,20 @@ public class DebuggerAddMappingDialog extends ReusableDialogComponentProvider {
|
||||||
fieldProgRange.getRange().getMinAddress());
|
fieldProgRange.getRange().getMinAddress());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mappingService.addMapping(from, to, getLength(), true);
|
mappingService.addMapping(from, to, getLength(), false);
|
||||||
|
setStatusText("");
|
||||||
}
|
}
|
||||||
catch (TraceConflictedMappingException e) {
|
catch (TraceConflictedMappingException e) {
|
||||||
throw new AssertionError(e); // I said truncateExisting
|
setStatusText(e.getMessage(), MessageType.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dismissCallback() {
|
||||||
|
setStatusText("");
|
||||||
|
super.dismissCallback();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the values of the fields
|
* Set the values of the fields
|
||||||
*
|
*
|
||||||
|
|
|
@ -659,8 +659,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
if (currentProgram == null || current.getTrace() == null) {
|
if (currentProgram == null || current.getTrace() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
staticMappingService.addIdentityMapping(current.getTrace(), currentProgram,
|
try {
|
||||||
Lifespan.nowOn(traceManager.getCurrentSnap()), true);
|
staticMappingService.addIdentityMapping(current.getTrace(), currentProgram,
|
||||||
|
Lifespan.nowOn(traceManager.getCurrentSnap()), false);
|
||||||
|
}
|
||||||
|
catch (TraceConflictedMappingException e) {
|
||||||
|
Msg.showError(this, null, "Map Identically", e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapManually(ActionContext ignored) {
|
private void activatedMapManually(ActionContext ignored) {
|
||||||
|
|
|
@ -291,11 +291,11 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter
|
||||||
: traceLen == 0 ? progLen : MathUtilities.unsignedMin(progLen, traceLen);
|
: traceLen == 0 ? progLen : MathUtilities.unsignedMin(progLen, traceLen);
|
||||||
Address progStart = progLen != 0 ? progSel.getMinAddress() : progLoc.getAddress();
|
Address progStart = progLen != 0 ? progSel.getMinAddress() : progLoc.getAddress();
|
||||||
Address traceStart = traceLen != 0 ? traceSel.getMinAddress() : traceLoc.getAddress();
|
Address traceStart = traceLen != 0 ? traceSel.getMinAddress() : traceLoc.getAddress();
|
||||||
TraceProgramView view = (TraceProgramView) traceLoc.getProgram();
|
long snap = traceManager.getCurrentSnap();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addMappingDialog.setValues(progLoc.getProgram(), currentTrace, progStart, traceStart,
|
addMappingDialog.setValues(progLoc.getProgram(), currentTrace, progStart, traceStart,
|
||||||
length, Lifespan.nowOn(view.getSnap()));
|
length, Lifespan.nowOn(snap));
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
Msg.showError(this, null, "Add Mapping", "Error populating dialog");
|
Msg.showError(this, null, "Add Mapping", "Error populating dialog");
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
||||||
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils.Extrema;
|
||||||
import ghidra.app.services.DebuggerEmulationService;
|
import ghidra.app.services.DebuggerEmulationService;
|
||||||
import ghidra.dbg.target.*;
|
import ghidra.dbg.target.*;
|
||||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||||
|
@ -41,7 +42,8 @@ import ghidra.trace.model.target.TraceObject;
|
||||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||||
import ghidra.trace.model.thread.*;
|
import ghidra.trace.model.thread.*;
|
||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
import ghidra.util.*;
|
import ghidra.util.DifferenceAddressSetView;
|
||||||
|
import ghidra.util.NumericUtilities;
|
||||||
import ghidra.util.database.UndoableTransaction;
|
import ghidra.util.database.UndoableTransaction;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
@ -116,18 +118,6 @@ public enum ProgramEmulationUtils {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Extrema {
|
|
||||||
Address min = null;
|
|
||||||
Address max = null;
|
|
||||||
|
|
||||||
void consider(AddressRange range) {
|
|
||||||
min = min == null ? range.getMinAddress()
|
|
||||||
: ComparatorMath.cmin(min, range.getMinAddress());
|
|
||||||
max = max == null ? range.getMaxAddress()
|
|
||||||
: ComparatorMath.cmax(max, range.getMaxAddress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create regions for each block in a program, without relocation, and map the program in
|
* Create regions for each block in a program, without relocation, and map the program in
|
||||||
*
|
*
|
||||||
|
@ -149,10 +139,7 @@ public enum ProgramEmulationUtils {
|
||||||
Map<AddressSpace, Extrema> extremaBySpace = new HashMap<>();
|
Map<AddressSpace, Extrema> extremaBySpace = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
||||||
if (!block.isLoaded()) {
|
if (!DebuggerStaticMappingUtils.isReal(block)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (block.isOverlay()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AddressRange range = new AddressRangeImpl(block.getStart(), block.getEnd());
|
AddressRange range = new AddressRangeImpl(block.getStart(), block.getEnd());
|
||||||
|
@ -170,9 +157,8 @@ public enum ProgramEmulationUtils {
|
||||||
for (Extrema extrema : extremaBySpace.values()) {
|
for (Extrema extrema : extremaBySpace.values()) {
|
||||||
DebuggerStaticMappingUtils.addMapping(
|
DebuggerStaticMappingUtils.addMapping(
|
||||||
new DefaultTraceLocation(trace, null, Lifespan.nowOn(snapshot.getKey()),
|
new DefaultTraceLocation(trace, null, Lifespan.nowOn(snapshot.getKey()),
|
||||||
extrema.min),
|
extrema.getMin()),
|
||||||
new ProgramLocation(program, extrema.min),
|
new ProgramLocation(program, extrema.getMin()), extrema.getLength(), false);
|
||||||
extrema.max.subtract(extrema.min), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (TraceOverlappedRegionException | DuplicateNameException
|
catch (TraceOverlappedRegionException | DuplicateNameException
|
||||||
|
|
|
@ -25,11 +25,13 @@ import ghidra.framework.model.ProjectData;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Library;
|
import ghidra.program.model.listing.Library;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.model.symbol.ExternalManager;
|
import ghidra.program.model.symbol.ExternalManager;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.modules.*;
|
import ghidra.trace.model.modules.*;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
|
import ghidra.util.ComparatorMath;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public enum DebuggerStaticMappingUtils {
|
public enum DebuggerStaticMappingUtils {
|
||||||
|
@ -153,42 +155,72 @@ public enum DebuggerStaticMappingUtils {
|
||||||
addMapping(fromLoc, toLoc, length, truncateExisting);
|
addMapping(fromLoc, toLoc, length, truncateExisting);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addIdentityMapping(Trace from, Program toProgram, Lifespan lifespan,
|
public static class Extrema {
|
||||||
boolean truncateExisting) {
|
private Address min = null;
|
||||||
Map<String, Address> mins = new HashMap<>();
|
private Address max = null;
|
||||||
Map<String, Address> maxs = new HashMap<>();
|
|
||||||
for (AddressRange range : toProgram.getMemory().getAddressRanges()) {
|
public void consider(AddressRange range) {
|
||||||
mins.compute(range.getAddressSpace().getName(), (n, min) -> {
|
min = min == null ? range.getMinAddress()
|
||||||
Address can = range.getMinAddress();
|
: ComparatorMath.cmin(min, range.getMinAddress());
|
||||||
if (min == null || can.compareTo(min) < 0) {
|
max = max == null ? range.getMaxAddress()
|
||||||
return can;
|
: ComparatorMath.cmax(max, range.getMaxAddress());
|
||||||
}
|
|
||||||
return min;
|
|
||||||
});
|
|
||||||
maxs.compute(range.getAddressSpace().getName(), (n, max) -> {
|
|
||||||
Address can = range.getMaxAddress();
|
|
||||||
if (max == null || can.compareTo(max) > 0) {
|
|
||||||
return can;
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
for (String name : mins.keySet()) {
|
|
||||||
AddressRange range = clippedRange(from, name, mins.get(name).getOffset(),
|
public Address getMin() {
|
||||||
maxs.get(name).getOffset());
|
return min;
|
||||||
if (range == null) {
|
}
|
||||||
|
|
||||||
|
public Address getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLength() {
|
||||||
|
return max.subtract(min) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isReal(MemoryBlock block) {
|
||||||
|
return block.isLoaded() && !block.isOverlay() && !block.isExternalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addIdentityMapping(Trace from, Program toProgram, Lifespan lifespan,
|
||||||
|
boolean truncateExisting) throws TraceConflictedMappingException {
|
||||||
|
AddressSet failures = new AddressSet();
|
||||||
|
Set<TraceStaticMapping> conflicts = new HashSet<>();
|
||||||
|
Map<AddressSpace, Extrema> extremaBySpace = new HashMap<>();
|
||||||
|
for (MemoryBlock block : toProgram.getMemory().getBlocks()) {
|
||||||
|
if (!isReal(block)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddressRange range = new AddressRangeImpl(block.getStart(), block.getEnd());
|
||||||
|
extremaBySpace.computeIfAbsent(range.getAddressSpace(), s -> new Extrema())
|
||||||
|
.consider(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Extrema extrema : extremaBySpace.values()) {
|
||||||
|
AddressRange fromRange =
|
||||||
|
clippedRange(from, extrema.getMin().getAddressSpace().getName(),
|
||||||
|
extrema.getMin().getOffset(), extrema.getMax().getOffset());
|
||||||
|
if (fromRange == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
addMapping(new DefaultTraceLocation(from, null, lifespan, range.getMinAddress()),
|
addMapping(
|
||||||
new ProgramLocation(toProgram, mins.get(name)), range.getLength(),
|
new DefaultTraceLocation(from, null, lifespan, fromRange.getMinAddress()),
|
||||||
|
new ProgramLocation(toProgram, extrema.getMin()), fromRange.getLength(),
|
||||||
truncateExisting);
|
truncateExisting);
|
||||||
}
|
}
|
||||||
catch (TraceConflictedMappingException e) {
|
catch (TraceConflictedMappingException e) {
|
||||||
|
failures.add(fromRange);
|
||||||
|
conflicts.addAll(e.getConflicts());
|
||||||
Msg.error(DebuggerStaticMappingUtils.class,
|
Msg.error(DebuggerStaticMappingUtils.class,
|
||||||
"Could not add identity mapping " + range + ": " + e.getMessage());
|
"Could not add identity mapping " + fromRange + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!failures.isEmpty()) {
|
||||||
|
throw new TraceConflictedMappingException("Conflicting mappings for " + failures,
|
||||||
|
conflicts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static AddressRange clippedRange(Trace trace, String spaceName, long min,
|
protected static AddressRange clippedRange(Trace trace, String spaceName, long min,
|
||||||
|
|
|
@ -112,6 +112,13 @@ public class DBTraceStaticMapping extends DBAnnotatedObject
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"Mapping: dynamic=%s,program=%s,address=%s,length=0x%x,shift=0x%x,lifespan=%s",
|
||||||
|
traceAddress, staticProgramURL, staticAddress, length, shift, lifespan);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fresh(boolean created) throws IOException {
|
protected void fresh(boolean created) throws IOException {
|
||||||
if (created) {
|
if (created) {
|
||||||
|
|
|
@ -85,8 +85,9 @@ public class DBTraceStaticMappingManager implements TraceStaticMappingManager, D
|
||||||
DBTraceStaticMapping conflict =
|
DBTraceStaticMapping conflict =
|
||||||
findAnyConflicting(range, lifespan, toProgramURL, toAddress);
|
findAnyConflicting(range, lifespan, toProgramURL, toAddress);
|
||||||
if (conflict != null) {
|
if (conflict != null) {
|
||||||
|
// TODO: Find all conflicts?
|
||||||
throw new TraceConflictedMappingException("Another mapping would conflict",
|
throw new TraceConflictedMappingException("Another mapping would conflict",
|
||||||
conflict);
|
Set.of(conflict));
|
||||||
}
|
}
|
||||||
// TODO: A more sophisticated coverage check?
|
// TODO: A more sophisticated coverage check?
|
||||||
// TODO: Better coalescing
|
// TODO: Better coalescing
|
||||||
|
@ -133,8 +134,7 @@ public class DBTraceStaticMappingManager implements TraceStaticMappingManager, D
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceStaticMapping findAnyConflicting(AddressRange range, Lifespan lifespan,
|
public DBTraceStaticMapping findAnyConflicting(AddressRange range, Lifespan lifespan,
|
||||||
URL toProgramURL,
|
URL toProgramURL, String toAddress) {
|
||||||
String toAddress) {
|
|
||||||
for (DBTraceStaticMapping mapping : mappingsByAddress.head(range.getMaxAddress(),
|
for (DBTraceStaticMapping mapping : mappingsByAddress.head(range.getMaxAddress(),
|
||||||
true).descending().values()) {
|
true).descending().values()) {
|
||||||
if (!mapping.conflictsWith(range, lifespan, toProgramURL, toAddress)) {
|
if (!mapping.conflictsWith(range, lifespan, toProgramURL, toAddress)) {
|
||||||
|
|
|
@ -15,15 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.model.modules;
|
package ghidra.trace.model.modules;
|
||||||
|
|
||||||
public class TraceConflictedMappingException extends Exception {
|
import java.util.Collection;
|
||||||
private final TraceStaticMapping conflict;
|
import java.util.Set;
|
||||||
|
|
||||||
public TraceConflictedMappingException(String message, TraceStaticMapping conflict) {
|
public class TraceConflictedMappingException extends RuntimeException {
|
||||||
super(message);
|
private final Set<TraceStaticMapping> conflicts;
|
||||||
this.conflict = conflict;
|
|
||||||
|
public TraceConflictedMappingException(String message,
|
||||||
|
Collection<TraceStaticMapping> conflicts) {
|
||||||
|
super(message + ": " + conflicts);
|
||||||
|
this.conflicts = Set.copyOf(conflicts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TraceStaticMapping getConflict() {
|
public Set<TraceStaticMapping> getConflicts() {
|
||||||
return conflict;
|
return conflicts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue