mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-616: Fix 32-bit pointer placement in WoW64 targets.
This commit is contained in:
parent
c75c852001
commit
ed48b0e452
37 changed files with 754 additions and 311 deletions
|
@ -65,9 +65,11 @@ public interface DebuggerPlatformService {
|
||||||
/**
|
/**
|
||||||
* Set the current mapper for the trace and initialize the trace for the mapper
|
* Set the current mapper for the trace and initialize the trace for the mapper
|
||||||
*
|
*
|
||||||
* @param trace the trace whose current mapper to set
|
* @param trace the trace whose mapper to assign and initialize
|
||||||
|
* @param focus the object of focus
|
||||||
* @param mapper the mapper
|
* @param mapper the mapper
|
||||||
* @param snap the snap for initializing the trace
|
* @param snap the snap for initializing the trace
|
||||||
*/
|
*/
|
||||||
void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap);
|
void setCurrentMapperFor(Trace trace, TraceObject focus, DebuggerPlatformMapper mapper,
|
||||||
|
long snap);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,40 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.TraceObject;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object for interpreting a trace according to a chosen platform
|
* An object for interpreting a trace according to a chosen platform
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Platform selection is a bit of a work in progress, but the idea is to allow the mapper to choose
|
||||||
|
* relevant languages, compiler specifications, data organization, etc., based on the current
|
||||||
|
* debugger context. Most of these are fairly straightforward and relatively static. If the back-end
|
||||||
|
* creates the trace with an actual language (non-DATA), then there's a default mapper for "known
|
||||||
|
* hosts," (but this can be out prioritized by more complex mappers). If the back-end creates a
|
||||||
|
* trace with a DATA language (usually indicating it doesn't recognize the target architecture),
|
||||||
|
* then some pluggable examine the name of the debugger and its reported architecture to try to map
|
||||||
|
* it on the front end. There may not be any good opinions, in which case, the user can override
|
||||||
|
* with any language. That's the "simple" cases.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* In more complex cases, e.g., WoW64, the mapper may need to adjust the recommended language based
|
||||||
|
* on, e.g., the current program counter and loaded modules. Essentially, it must determine the CPUs
|
||||||
|
* current ISA mode and adjust accordingly. There are currently two known situations: 1)
|
||||||
|
* Disassembly, and 2) Data (namely pointer) Organization, controlled by the Compiler Spec. The
|
||||||
|
* selection logic differs slightly between the two. For disassembly, we allow the mapper specific
|
||||||
|
* control of the selected platform, based on the starting address. For data placement, we allow the
|
||||||
|
* mapper specific control of the selected platform, based on the current PC. Note that the starting
|
||||||
|
* address of the data itself may not always be relevant. At the moment, because of limitations in
|
||||||
|
* the {@link Program} API, we actually cannot support selection based on placement address.
|
||||||
|
* Instead, at the time we ask the mapper to add a platform to the trace
|
||||||
|
* ({@link #addToTrace(TraceObject, long)}), we provide the current focus and snap, so that it can
|
||||||
|
* derive the PC or whatever other context is necessary to make its decision. The returned platform
|
||||||
|
* is immediately set as current, so that data actions heed the chosen platform.
|
||||||
*/
|
*/
|
||||||
public interface DebuggerPlatformMapper {
|
public interface DebuggerPlatformMapper {
|
||||||
|
|
||||||
|
@ -32,18 +60,20 @@ public interface DebuggerPlatformMapper {
|
||||||
* Get the compiler for a given object
|
* Get the compiler for a given object
|
||||||
*
|
*
|
||||||
* @param object the object
|
* @param object the object
|
||||||
|
* @param snap the snap
|
||||||
* @return the compiler spec
|
* @return the compiler spec
|
||||||
*/
|
*/
|
||||||
CompilerSpec getCompilerSpec(TraceObject object);
|
CompilerSpec getCompilerSpec(TraceObject object, long snap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the language for a given object
|
* Get the language for a given object
|
||||||
*
|
*
|
||||||
* @param object the object
|
* @param object the object
|
||||||
|
* @param snap the snap
|
||||||
* @return the language
|
* @return the language
|
||||||
*/
|
*/
|
||||||
default Language getLangauge(TraceObject object) {
|
default Language getLangauge(TraceObject object, long snap) {
|
||||||
CompilerSpec cSpec = getCompilerSpec(object);
|
CompilerSpec cSpec = getCompilerSpec(object, snap);
|
||||||
return cSpec == null ? null : cSpec.getLanguage();
|
return cSpec == null ? null : cSpec.getLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +84,11 @@ public interface DebuggerPlatformMapper {
|
||||||
* Likely, this will need to modify the trace database. It must start its own transaction for
|
* Likely, this will need to modify the trace database. It must start its own transaction for
|
||||||
* doing so.
|
* doing so.
|
||||||
*
|
*
|
||||||
* @param trace the trace
|
* @param newFocus the newly-focused object
|
||||||
* @param snap the snap
|
* @param snap the snap
|
||||||
|
* @return the resulting platform, which may have already existed
|
||||||
*/
|
*/
|
||||||
void addToTrace(long snap);
|
TracePlatform addToTrace(TraceObject newFocus, long snap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When focus changes, decide if this mapper should remain active
|
* When focus changes, decide if this mapper should remain active
|
||||||
|
@ -71,6 +102,10 @@ public interface DebuggerPlatformMapper {
|
||||||
/**
|
/**
|
||||||
* Disassemble starting at a given address and snap, limited to a given address set
|
* Disassemble starting at a given address and snap, limited to a given address set
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* Note that the mapper may use an alternative platform than that returned by
|
||||||
|
* {@link #addToTrace(TraceObject, long)}.
|
||||||
|
*
|
||||||
* @param thread the thread if applicable
|
* @param thread the thread if applicable
|
||||||
* @param object the object for platform context
|
* @param object the object for platform context
|
||||||
* @param start the starting address
|
* @param start the starting address
|
||||||
|
|
|
@ -128,13 +128,15 @@ public class DebuggerCoordinates {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof DebuggerCoordinates)) {
|
if (!(obj instanceof DebuggerCoordinates that)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DebuggerCoordinates that = (DebuggerCoordinates) obj;
|
|
||||||
if (!Objects.equals(this.trace, that.trace)) {
|
if (!Objects.equals(this.trace, that.trace)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!Objects.equals(this.platform, that.platform)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!Objects.equals(this.target, that.target)) {
|
if (!Objects.equals(this.target, that.target)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +438,6 @@ public class DebuggerCoordinates {
|
||||||
if (!Objects.equals(this.trace, that.trace)) {
|
if (!Objects.equals(this.trace, that.trace)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Objects.equals(this.platform, that.platform)) {
|
if (!Objects.equals(this.platform, that.platform)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1376,8 +1376,9 @@ class Receiver(Thread):
|
||||||
Client._write_value(
|
Client._write_value(
|
||||||
reply.xreply_invoke_method.return_value, result)
|
reply.xreply_invoke_method.return_value, result)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
print("Error caused by front end")
|
print(f"Error caused by front end: {e}")
|
||||||
traceback.print_exc()
|
# TODO: Add a field to error for stacktrace, log it at front-end
|
||||||
|
# traceback.print_exc()
|
||||||
reply.xreply_invoke_method.error = repr(e)
|
reply.xreply_invoke_method.error = repr(e)
|
||||||
self.client._send(reply)
|
self.client._send(reply)
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface ChooseMorePlatformsActon {
|
protected interface ChooseMorePlatformsAction {
|
||||||
String NAME = DebuggerResources.NAME_CHOOSE_MORE_PLATFORMS;
|
String NAME = DebuggerResources.NAME_CHOOSE_MORE_PLATFORMS;
|
||||||
String TITLE = DebuggerResources.TITLE_CHOOSE_MORE_PLATFORMS;
|
String TITLE = DebuggerResources.TITLE_CHOOSE_MORE_PLATFORMS;
|
||||||
String DESCRIPTION = DebuggerResources.DESCRIPTION_CHOOSE_MORE_PLATFORMS;
|
String DESCRIPTION = DebuggerResources.DESCRIPTION_CHOOSE_MORE_PLATFORMS;
|
||||||
|
@ -92,28 +92,13 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) {
|
|
||||||
if (!Objects.equals(a.getTrace(), b.getTrace())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Objects.equals(a.getTime(), b.getTime())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Objects.equals(a.getObject(), b.getObject())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class PlatformActionSet {
|
protected class PlatformActionSet {
|
||||||
private final Trace trace;
|
private final Trace trace;
|
||||||
private DebuggerCoordinates current;
|
|
||||||
private final Map<DebuggerPlatformOffer, ToggleDockingAction> actions =
|
private final Map<DebuggerPlatformOffer, ToggleDockingAction> actions =
|
||||||
new LinkedHashMap<>();
|
new LinkedHashMap<>();
|
||||||
|
|
||||||
public PlatformActionSet(Trace trace) {
|
public PlatformActionSet(Trace trace) {
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
this.current = traceManager.getCurrentFor(trace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<DebuggerPlatformOffer> computePlatformOffers(boolean includeOverrides) {
|
protected Set<DebuggerPlatformOffer> computePlatformOffers(boolean includeOverrides) {
|
||||||
|
@ -126,15 +111,16 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
ToggleDockingAction action = ChoosePlatformAction.builder(DebuggerPlatformPlugin.this)
|
ToggleDockingAction action = ChoosePlatformAction.builder(DebuggerPlatformPlugin.this)
|
||||||
.menuPath(DebuggerPluginPackage.NAME, ChoosePlatformAction.NAME,
|
.menuPath(DebuggerPluginPackage.NAME, ChoosePlatformAction.NAME,
|
||||||
offer.getDescription())
|
offer.getDescription())
|
||||||
.onAction(ctx -> activatePlatform(offer))
|
.onAction(ctx -> activatePlatformOffer(offer))
|
||||||
.build();
|
.build();
|
||||||
String[] path = action.getMenuBarData().getMenuPath();
|
String[] path = action.getMenuBarData().getMenuPath();
|
||||||
tool.setMenuGroup(Arrays.copyOf(path, path.length - 1), ChoosePlatformAction.GROUP);
|
tool.setMenuGroup(Arrays.copyOf(path, path.length - 1), ChoosePlatformAction.GROUP);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void activatePlatform(DebuggerPlatformOffer offer) {
|
protected void activatePlatformOffer(DebuggerPlatformOffer offer) {
|
||||||
platformService.setCurrentMapperFor(trace, offer.take(tool, trace), current.getSnap());
|
platformService.setCurrentMapperFor(trace, current.getObject(), offer.take(tool, trace),
|
||||||
|
current.getSnap());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void cleanOffers() {
|
protected void cleanOffers() {
|
||||||
|
@ -159,7 +145,7 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
protected void addChosenOffer(DebuggerPlatformOffer offer) {
|
protected void addChosenOffer(DebuggerPlatformOffer offer) {
|
||||||
ToggleDockingAction action = addOfferAction(offer);
|
ToggleDockingAction action = addOfferAction(offer);
|
||||||
// NB. PluginEvent will cause selections to update
|
// NB. PluginEvent will cause selections to update
|
||||||
if (currentTrace == trace) {
|
if (current.getTrace() == trace) {
|
||||||
tool.addAction(action);
|
tool.addAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,15 +162,6 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void coordinatesActivated(DebuggerCoordinates coordinates) {
|
|
||||||
if (sameCoordinates(current, coordinates)) {
|
|
||||||
current = coordinates;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current = coordinates;
|
|
||||||
updatePlatformOffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void mapperActivated(DebuggerPlatformMapper mapper) {
|
protected void mapperActivated(DebuggerPlatformMapper mapper) {
|
||||||
for (Entry<DebuggerPlatformOffer, ToggleDockingAction> ent : actions.entrySet()) {
|
for (Entry<DebuggerPlatformOffer, ToggleDockingAction> ent : actions.entrySet()) {
|
||||||
DebuggerPlatformOffer offer = ent.getKey();
|
DebuggerPlatformOffer offer = ent.getKey();
|
||||||
|
@ -201,7 +178,7 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Wiring autoServiceWiring;
|
private final Wiring autoServiceWiring;
|
||||||
|
|
||||||
private Trace currentTrace;
|
private DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||||
|
|
||||||
private final ChangeListener classChangeListener = evt -> this.classesChanged();
|
private final ChangeListener classChangeListener = evt -> this.classesChanged();
|
||||||
|
|
||||||
|
@ -221,18 +198,19 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void installActions() {
|
protected void installActions() {
|
||||||
if (currentTrace == null) {
|
Trace trace = current.getTrace();
|
||||||
|
if (trace == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PlatformActionSet actions =
|
PlatformActionSet actions =
|
||||||
actionsChoosePlatform.computeIfAbsent(currentTrace, PlatformActionSet::new);
|
actionsChoosePlatform.computeIfAbsent(trace, PlatformActionSet::new);
|
||||||
actions.updatePlatformOffers();
|
actions.updatePlatformOffers();
|
||||||
actions.mapperActivated(platformService.getCurrentMapperFor(currentTrace));
|
actions.mapperActivated(platformService.getCurrentMapperFor(trace));
|
||||||
actions.installActions();
|
actions.installActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void uninstallActions() {
|
protected void uninstallActions() {
|
||||||
PlatformActionSet actions = actionsChoosePlatform.get(currentTrace);
|
PlatformActionSet actions = actionsChoosePlatform.get(current.getTrace());
|
||||||
if (actions != null) {
|
if (actions != null) {
|
||||||
actions.uninstallActions();
|
actions.uninstallActions();
|
||||||
}
|
}
|
||||||
|
@ -240,8 +218,8 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
installActions();
|
installActions();
|
||||||
actionMore = ChooseMorePlatformsActon.builder(this)
|
actionMore = ChooseMorePlatformsAction.builder(this)
|
||||||
.enabledWhen(ctx -> currentTrace != null)
|
.enabledWhen(ctx -> current.getTrace() != null)
|
||||||
.onAction(this::activatedChooseMore)
|
.onAction(this::activatedChooseMore)
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
String[] path = actionMore.getMenuBarData().getMenuPath();
|
String[] path = actionMore.getMenuBarData().getMenuPath();
|
||||||
|
@ -254,13 +232,11 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
// Still initializing or finalizing
|
// Still initializing or finalizing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Sort of a backwards way to retrieve the current coordinates....
|
Trace trace = current.getTrace();
|
||||||
PlatformActionSet actions = actionsChoosePlatform.get(currentTrace);
|
PlatformActionSet actions = actionsChoosePlatform.get(trace);
|
||||||
if (actions == null) {
|
if (actions == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DebuggerCoordinates current = actions.current;
|
|
||||||
Trace trace = current.getTrace();
|
|
||||||
TraceObject object = current.getObject();
|
TraceObject object = current.getObject();
|
||||||
long snap = current.getSnap();
|
long snap = current.getSnap();
|
||||||
|
|
||||||
|
@ -268,7 +244,7 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
// Dialog allows Swing to do other things, so re-check platformService
|
// Dialog allows Swing to do other things, so re-check platformService
|
||||||
if (offer != null && platformService != null) {
|
if (offer != null && platformService != null) {
|
||||||
actions.addChosenOffer(offer);
|
actions.addChosenOffer(offer);
|
||||||
platformService.setCurrentMapperFor(trace, offer.take(tool, trace), snap);
|
platformService.setCurrentMapperFor(trace, object, offer.take(tool, trace), snap);
|
||||||
// NOTE: DebuggerPlatformPluginEvent will cause selection change
|
// NOTE: DebuggerPlatformPluginEvent will cause selection change
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,21 +258,24 @@ public class DebuggerPlatformPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void coordinatesActivated(DebuggerCoordinates coordinates) {
|
protected void coordinatesActivated(DebuggerCoordinates coordinates) {
|
||||||
|
if (Objects.equals(current, coordinates)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
uninstallActions();
|
uninstallActions();
|
||||||
this.currentTrace = coordinates.getTrace();
|
this.current = coordinates;
|
||||||
installActions();
|
installActions();
|
||||||
tool.contextChanged(null);
|
tool.contextChanged(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void traceClosed(Trace trace) {
|
protected void traceClosed(Trace trace) {
|
||||||
if (trace == currentTrace) {
|
if (trace == current.getTrace()) {
|
||||||
coordinatesActivated(DebuggerCoordinates.NOWHERE);
|
coordinatesActivated(DebuggerCoordinates.NOWHERE);
|
||||||
}
|
}
|
||||||
actionsChoosePlatform.remove(trace);
|
actionsChoosePlatform.remove(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void mapperActivated(Trace trace, DebuggerPlatformMapper mapper) {
|
protected void mapperActivated(Trace trace, DebuggerPlatformMapper mapper) {
|
||||||
if (trace != currentTrace) {
|
if (trace != current.getTrace()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PlatformActionSet actions = actionsChoosePlatform.get(trace);
|
PlatformActionSet actions = actionsChoosePlatform.get(trace);
|
||||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.app.plugin.core.debug.mapping;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
|
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
|
||||||
|
@ -28,7 +27,6 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Endian;
|
import ghidra.program.model.lang.Endian;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.TraceAddressSnapRange;
|
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.listing.TraceInstruction;
|
import ghidra.trace.model.listing.TraceInstruction;
|
||||||
import ghidra.trace.model.memory.TraceMemoryOperations;
|
import ghidra.trace.model.memory.TraceMemoryOperations;
|
||||||
|
@ -75,6 +73,10 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
|
||||||
TraceMemoryState.KNOWN);
|
TraceMemoryState.KNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TracePlatform getDisassemblyPlatform(TraceObject object, Address start, long snap) {
|
||||||
|
return trace.getPlatformManager().getPlatform(getCompilerSpec(object, snap));
|
||||||
|
}
|
||||||
|
|
||||||
protected Collection<DisassemblyInject> getDisassemblyInjections(TracePlatform platform) {
|
protected Collection<DisassemblyInject> getDisassemblyInjections(TracePlatform platform) {
|
||||||
return ClassSearcher.getInstances(DisassemblyInject.class)
|
return ClassSearcher.getInstances(DisassemblyInject.class)
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -89,8 +91,8 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
|
||||||
if (isCancelSilently(start, snap)) {
|
if (isCancelSilently(start, snap)) {
|
||||||
return DisassemblyResult.CANCELLED;
|
return DisassemblyResult.CANCELLED;
|
||||||
}
|
}
|
||||||
TracePlatform platform = trace.getPlatformManager().getPlatform(getCompilerSpec(object));
|
|
||||||
|
|
||||||
|
TracePlatform platform = getDisassemblyPlatform(object, start, snap);
|
||||||
Collection<DisassemblyInject> injects = getDisassemblyInjections(platform);
|
Collection<DisassemblyInject> injects = getDisassemblyInjections(platform);
|
||||||
TraceDisassembleCommand dis = new TraceDisassembleCommand(platform, start, restricted);
|
TraceDisassembleCommand dis = new TraceDisassembleCommand(platform, start, restricted);
|
||||||
AddressSet startSet = new AddressSet(start);
|
AddressSet startSet = new AddressSet(start);
|
||||||
|
|
|
@ -49,22 +49,26 @@ public class DefaultDebuggerPlatformMapper extends AbstractDebuggerPlatformMappe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompilerSpec getCompilerSpec(TraceObject object) {
|
public CompilerSpec getCompilerSpec(TraceObject object, long snap) {
|
||||||
return cSpec;
|
return cSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected TracePlatform addOrGetPlatform(CompilerSpec cSpec, long snap) {
|
||||||
public void addToTrace(long snap) {
|
|
||||||
String description = "Add guest " + cSpec.getLanguage().getLanguageDescription() + "/" +
|
String description = "Add guest " + cSpec.getLanguage().getLanguageDescription() + "/" +
|
||||||
cSpec.getCompilerSpecDescription();
|
cSpec.getCompilerSpecDescription();
|
||||||
try (Transaction tx = trace.openTransaction(description)) {
|
try (Transaction tx = trace.openTransaction(description)) {
|
||||||
TracePlatformManager platformManager = trace.getPlatformManager();
|
TracePlatformManager platformManager = trace.getPlatformManager();
|
||||||
TracePlatform platform = platformManager.getOrAddPlatform(cSpec);
|
TracePlatform platform = platformManager.getOrAddPlatform(cSpec);
|
||||||
if (platform.isHost()) {
|
if (!platform.isHost()) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
addMappedRanges((TraceGuestPlatform) platform);
|
addMappedRanges((TraceGuestPlatform) platform);
|
||||||
}
|
}
|
||||||
|
return platform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TracePlatform addToTrace(TraceObject newFocus, long snap) {
|
||||||
|
return addOrGetPlatform(cSpec, snap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.Processor;
|
import ghidra.program.model.lang.Processor;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.TraceObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +31,8 @@ import ghidra.trace.model.target.TraceObject;
|
||||||
* the real language must be mapped as a guest platform.
|
* the real language must be mapped as a guest platform.
|
||||||
*/
|
*/
|
||||||
public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
|
public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
|
||||||
|
// An alternative default had better mean it.
|
||||||
|
public static final int CONFIDENCE_HOST_KNOWN = 10000;
|
||||||
|
|
||||||
protected static class HostDebuggerPlatformMapper extends AbstractDebuggerPlatformMapper {
|
protected static class HostDebuggerPlatformMapper extends AbstractDebuggerPlatformMapper {
|
||||||
public HostDebuggerPlatformMapper(PluginTool tool, Trace trace) {
|
public HostDebuggerPlatformMapper(PluginTool tool, Trace trace) {
|
||||||
|
@ -37,13 +40,13 @@ public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompilerSpec getCompilerSpec(TraceObject object) {
|
public CompilerSpec getCompilerSpec(TraceObject object, long snap) {
|
||||||
return trace.getBaseCompilerSpec();
|
return trace.getBaseCompilerSpec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToTrace(long snap) {
|
public TracePlatform addToTrace(TraceObject newFocus, long snap) {
|
||||||
// Nothing to do
|
return trace.getPlatformManager().getHostPlatform();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,7 +82,7 @@ public class HostDebuggerPlatformOpinion implements DebuggerPlatformOpinion {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getConfidence() {
|
public int getConfidence() {
|
||||||
return 10000; // An alternative default had better mean it. Really.
|
return CONFIDENCE_HOST_KNOWN;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,47 +15,166 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.platform.dbgeng;
|
package ghidra.app.plugin.core.debug.platform.dbgeng;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
|
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.action.PCLocationTrackingSpec;
|
||||||
import ghidra.app.plugin.core.debug.mapping.*;
|
import ghidra.app.plugin.core.debug.mapping.*;
|
||||||
|
import ghidra.app.services.DebuggerTargetService;
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.MemBufferByteProvider;
|
||||||
|
import ghidra.app.util.bin.format.pe.*;
|
||||||
|
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||||
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
||||||
|
import ghidra.debug.api.target.Target;
|
||||||
|
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
|
import ghidra.trace.model.modules.TraceModule;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.TraceObject;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
|
public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
|
||||||
protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
|
protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
|
||||||
|
protected static final LanguageID LANG_ID_X86_64_32 = new LanguageID("x86:LE:64:compat32");
|
||||||
protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("windows");
|
protected static final CompilerSpecID COMP_ID_VS = new CompilerSpecID("windows");
|
||||||
protected static final Set<DisassemblyInject> INJECTS =
|
protected static final Set<DisassemblyInject> INJECTS =
|
||||||
Set.of(new DbgengX64DisassemblyInject());
|
Set.of(new DbgengX64DisassemblyInject());
|
||||||
|
|
||||||
protected static class DbgengX64DebuggerPlatformMapper extends DefaultDebuggerPlatformMapper {
|
enum Mode {
|
||||||
public DbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace, CompilerSpec cSpec) {
|
X64, X86, UNK;
|
||||||
|
|
||||||
|
static Mode computeFor(PluginTool tool, Trace trace, Address address, long snap) {
|
||||||
|
DebuggerTargetService targetService = tool.getService(DebuggerTargetService.class);
|
||||||
|
Target target = targetService == null ? null : targetService.getTarget(trace);
|
||||||
|
Collection<? extends TraceModule> modules =
|
||||||
|
trace.getModuleManager().getModulesAt(snap, address);
|
||||||
|
Msg.debug(Mode.class, "Disassembling in modules: " +
|
||||||
|
modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")));
|
||||||
|
Set<Mode> modes = modules.stream()
|
||||||
|
.map(m -> modeForModule(target, trace, snap, m))
|
||||||
|
.filter(m -> m != UNK)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Msg.debug(Mode.class, "Disassembling in mode(s): " + modes);
|
||||||
|
if (modes.size() != 1) {
|
||||||
|
return UNK;
|
||||||
|
}
|
||||||
|
return modes.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Mode modeForModule(Target target, Trace trace, long snap, TraceModule module) {
|
||||||
|
if (target != null && target.getSnap() == snap) {
|
||||||
|
AddressSet set = new AddressSet();
|
||||||
|
set.add(module.getBase(snap), module.getBase(snap)); // Recorder should read page
|
||||||
|
try {
|
||||||
|
target.readMemoryAsync(set, TaskMonitor.DUMMY).get(1, TimeUnit.SECONDS);
|
||||||
|
trace.flushEvents();
|
||||||
|
}
|
||||||
|
catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap));
|
||||||
|
try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) {
|
||||||
|
PortableExecutable pe =
|
||||||
|
new PortableExecutable(bp, SectionLayout.MEMORY, false, false);
|
||||||
|
NTHeader ntHeader = pe.getNTHeader();
|
||||||
|
if (ntHeader == null) {
|
||||||
|
return UNK;
|
||||||
|
}
|
||||||
|
OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
|
||||||
|
if (optionalHeader == null) {
|
||||||
|
return UNK; // Really shouldn't happen, but who knows?
|
||||||
|
}
|
||||||
|
return optionalHeader.is64bit() ? X64 : X86;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.warn(Mode.class, "Could not parse PE from trace: " + e);
|
||||||
|
return UNK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract static class AbstractDbgengX64DebuggerPlatformMapper
|
||||||
|
extends DefaultDebuggerPlatformMapper {
|
||||||
|
public AbstractDbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace,
|
||||||
|
CompilerSpec cSpec) {
|
||||||
super(tool, trace, cSpec);
|
super(tool, trace, cSpec);
|
||||||
}
|
}
|
||||||
// TODO: Map registers: efl,rfl,rflags->eflags
|
// TODO: Map registers: efl,rfl,rflags->eflags
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TracePlatform getDisassemblyPlatform(TraceObject object, Address start,
|
||||||
|
long snap) {
|
||||||
|
CompilerSpec x64cs = Offer.X64.getCompilerSpec();
|
||||||
|
return addOrGetPlatform(x64cs, snap);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection<DisassemblyInject> getDisassemblyInjections(TracePlatform platform) {
|
protected Collection<DisassemblyInject> getDisassemblyInjections(TracePlatform platform) {
|
||||||
return INJECTS;
|
return INJECTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Offers implements DebuggerPlatformOffer {
|
protected static class DbgengX64DebuggerPlatformMapper
|
||||||
|
extends AbstractDbgengX64DebuggerPlatformMapper {
|
||||||
|
public DbgengX64DebuggerPlatformMapper(PluginTool tool, Trace trace,
|
||||||
|
CompilerSpec cSpec) {
|
||||||
|
super(tool, trace, cSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class DbgengX64_32DebuggerPlatformMapper
|
||||||
|
extends AbstractDbgengX64DebuggerPlatformMapper {
|
||||||
|
public DbgengX64_32DebuggerPlatformMapper(PluginTool tool, Trace trace,
|
||||||
|
CompilerSpec cSpec) {
|
||||||
|
super(tool, trace, cSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class DbgengWoW64DebuggerPlatformMapper
|
||||||
|
extends AbstractDbgengX64DebuggerPlatformMapper {
|
||||||
|
public DbgengWoW64DebuggerPlatformMapper(PluginTool tool, Trace trace,
|
||||||
|
CompilerSpec cSpec) {
|
||||||
|
super(tool, trace, cSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TracePlatform addToTrace(TraceObject newFocus, long snap) {
|
||||||
|
DebuggerCoordinates coords = DebuggerCoordinates.NOWHERE.object(newFocus).snap(snap);
|
||||||
|
Address pc = PCLocationTrackingSpec.INSTANCE.computeTraceAddress(tool, coords);
|
||||||
|
if (pc == null) {
|
||||||
|
return addOrGetPlatform(Offer.X64_32.getCompilerSpec(), snap);
|
||||||
|
}
|
||||||
|
Offer sel = switch (Mode.computeFor(tool, trace, pc, snap)) {
|
||||||
|
case X64 -> Offer.X64;
|
||||||
|
default -> Offer.X64_32;
|
||||||
|
};
|
||||||
|
return addOrGetPlatform(sel.getCompilerSpec(), snap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Offer implements DebuggerPlatformOffer {
|
||||||
// TODO: X86?
|
// TODO: X86?
|
||||||
X64 {
|
X64 {
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return "Dbgeng on Windows x64";
|
return "Dbgeng x64 (64-bit module)";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getConfidence() {
|
public int getConfidence() {
|
||||||
return 100;
|
return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,7 +191,60 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
|
||||||
public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
|
public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
|
||||||
return mapper.getClass() == DbgengX64DebuggerPlatformMapper.class;
|
return mapper.getClass() == DbgengX64DebuggerPlatformMapper.class;
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
X64_32 {
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Dbgeng x64 (32-bit module)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConfidence() {
|
||||||
|
return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerSpec getCompilerSpec() {
|
||||||
|
return getCompilerSpec(LANG_ID_X86_64_32, COMP_ID_VS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
|
||||||
|
return new DbgengX64_32DebuggerPlatformMapper(tool, trace, getCompilerSpec());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
|
||||||
|
return mapper.getClass() == DbgengX64_32DebuggerPlatformMapper.class;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WOW64 {
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Dbgeng x64 (WoW64)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getConfidence() {
|
||||||
|
return HostDebuggerPlatformOpinion.CONFIDENCE_HOST_KNOWN + 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerSpec getCompilerSpec() {
|
||||||
|
// Report x86-32 in opinions, even though we mix
|
||||||
|
return getCompilerSpec(LANG_ID_X86_64_32, COMP_ID_VS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DebuggerPlatformMapper take(PluginTool tool, Trace trace) {
|
||||||
|
return new DbgengWoW64DebuggerPlatformMapper(tool, trace, getCompilerSpec());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCreatorOf(DebuggerPlatformMapper mapper) {
|
||||||
|
return mapper.getClass() == DbgengWoW64DebuggerPlatformMapper.class;
|
||||||
|
}
|
||||||
|
},;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -85,6 +257,6 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
|
||||||
if (!is64Bit) {
|
if (!is64Bit) {
|
||||||
return Set.of();
|
return Set.of();
|
||||||
}
|
}
|
||||||
return Set.of(Offers.X64);
|
return Set.of(Offer.X64, Offer.X64_32, Offer.WOW64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,32 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.platform.dbgeng;
|
package ghidra.app.plugin.core.debug.platform.dbgeng;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import ghidra.app.plugin.core.debug.disassemble.*;
|
import ghidra.app.plugin.core.debug.disassemble.*;
|
||||||
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInjectInfo.PlatformInfo;
|
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInjectInfo.PlatformInfo;
|
||||||
import ghidra.app.services.DebuggerTargetService;
|
import ghidra.app.plugin.core.debug.platform.dbgeng.DbgengDebuggerPlatformOpinion.Mode;
|
||||||
import ghidra.app.util.bin.ByteProvider;
|
|
||||||
import ghidra.app.util.bin.MemBufferByteProvider;
|
|
||||||
import ghidra.app.util.bin.format.pe.*;
|
|
||||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
|
||||||
import ghidra.debug.api.target.Target;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
|
||||||
import ghidra.program.util.ProgramContextImpl;
|
import ghidra.program.util.ProgramContextImpl;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.modules.TraceModule;
|
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
@DisassemblyInjectInfo(
|
@DisassemblyInjectInfo(
|
||||||
platforms = {
|
platforms = {
|
||||||
|
@ -48,11 +35,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
@PlatformInfo(langID = "x86:LE:64:default", compilerID = "clangwindows"),
|
@PlatformInfo(langID = "x86:LE:64:default", compilerID = "clangwindows"),
|
||||||
})
|
})
|
||||||
public class DbgengX64DisassemblyInject implements DisassemblyInject {
|
public class DbgengX64DisassemblyInject implements DisassemblyInject {
|
||||||
|
|
||||||
enum Mode {
|
|
||||||
X64, X86, UNK;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pre(PluginTool tool, TraceDisassembleCommand command, TracePlatform platform,
|
public void pre(PluginTool tool, TraceDisassembleCommand command, TracePlatform platform,
|
||||||
long snap, TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
|
long snap, TraceThread thread, AddressSetView startSet, AddressSetView restricted) {
|
||||||
|
@ -61,21 +43,11 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Trace trace = platform.getTrace();
|
Trace trace = platform.getTrace();
|
||||||
DebuggerTargetService targetService = tool.getService(DebuggerTargetService.class);
|
|
||||||
Target target = targetService == null ? null : targetService.getTarget(trace);
|
Mode mode = Mode.computeFor(tool, trace, first.getMinAddress(), snap);
|
||||||
Collection<? extends TraceModule> modules =
|
if (mode == Mode.UNK) {
|
||||||
trace.getModuleManager().getModulesAt(snap, first.getMinAddress());
|
|
||||||
Msg.debug(this, "Disassembling in modules: " +
|
|
||||||
modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")));
|
|
||||||
Set<Mode> modes = modules.stream()
|
|
||||||
.map(m -> modeForModule(target, trace, snap, m))
|
|
||||||
.filter(m -> m != Mode.UNK)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
Msg.debug(this, "Disassembling in mode(s): " + modes);
|
|
||||||
if (modes.size() != 1) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Mode mode = modes.iterator().next();
|
|
||||||
|
|
||||||
Language language = platform.getLanguage();
|
Language language = platform.getLanguage();
|
||||||
Register longModeReg = language.getRegister("longMode");
|
Register longModeReg = language.getRegister("longMode");
|
||||||
|
@ -96,36 +68,4 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject {
|
||||||
default -> throw new AssertionError();
|
default -> throw new AssertionError();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Mode modeForModule(Target target, Trace trace, long snap,
|
|
||||||
TraceModule module) {
|
|
||||||
if (target != null && target.getSnap() == snap) {
|
|
||||||
AddressSet set = new AddressSet();
|
|
||||||
set.add(module.getBase(snap), module.getBase(snap)); // Recorder should read page
|
|
||||||
try {
|
|
||||||
target.readMemory(set, TaskMonitor.DUMMY);
|
|
||||||
trace.flushEvents();
|
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap));
|
|
||||||
try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) {
|
|
||||||
PortableExecutable pe = new PortableExecutable(bp, SectionLayout.MEMORY, false, false);
|
|
||||||
NTHeader ntHeader = pe.getNTHeader();
|
|
||||||
if (ntHeader == null) {
|
|
||||||
return Mode.UNK;
|
|
||||||
}
|
|
||||||
OptionalHeader optionalHeader = ntHeader.getOptionalHeader();
|
|
||||||
if (optionalHeader == null) {
|
|
||||||
return Mode.UNK; // Really shouldn't happen, but who knows?
|
|
||||||
}
|
|
||||||
return optionalHeader.is64bit() ? Mode.X64 : Mode.X86;
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
Msg.warn(this, "Could not parse PE from trace: " + e);
|
|
||||||
return Mode.UNK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||||
import ghidra.app.plugin.core.debug.event.DebuggerPlatformPluginEvent;
|
import ghidra.app.plugin.core.debug.event.DebuggerPlatformPluginEvent;
|
||||||
import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
|
import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
|
||||||
import ghidra.app.plugin.core.debug.mapping.*;
|
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
|
||||||
|
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOpinion;
|
||||||
import ghidra.app.services.DebuggerPlatformService;
|
import ghidra.app.services.DebuggerPlatformService;
|
||||||
import ghidra.app.services.DebuggerTraceManagerService;
|
import ghidra.app.services.DebuggerTraceManagerService;
|
||||||
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
||||||
|
@ -29,6 +30,7 @@ import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.TraceObject;
|
||||||
|
|
||||||
@PluginInfo(
|
@PluginInfo(
|
||||||
|
@ -85,7 +87,6 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
|
||||||
}
|
}
|
||||||
mappersByTrace.put(trace, mapper);
|
mappersByTrace.put(trace, mapper);
|
||||||
}
|
}
|
||||||
mapper.addToTrace(snap);
|
|
||||||
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
|
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
|
||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +104,7 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCurrentMapperFor(Trace trace, DebuggerPlatformMapper mapper, long snap) {
|
public void setCurrentMapperFor(Trace trace, TraceObject focus, DebuggerPlatformMapper mapper, long snap) {
|
||||||
Objects.requireNonNull(trace);
|
Objects.requireNonNull(trace);
|
||||||
Objects.requireNonNull(mapper);
|
Objects.requireNonNull(mapper);
|
||||||
if (!traceManager.getOpenTraces().contains(trace)) {
|
if (!traceManager.getOpenTraces().contains(trace)) {
|
||||||
|
@ -112,8 +113,11 @@ public class DebuggerPlatformServicePlugin extends Plugin implements DebuggerPla
|
||||||
synchronized (mappersByTrace) {
|
synchronized (mappersByTrace) {
|
||||||
mappersByTrace.put(trace, mapper);
|
mappersByTrace.put(trace, mapper);
|
||||||
}
|
}
|
||||||
mapper.addToTrace(snap);
|
TracePlatform platform = mapper.addToTrace(focus, snap);
|
||||||
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
|
firePluginEvent(new DebuggerPlatformPluginEvent(getName(), trace, mapper));
|
||||||
|
if (traceManager.getCurrentTrace() == trace) {
|
||||||
|
traceManager.activatePlatform(platform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -535,8 +535,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
return coordinates;
|
return coordinates;
|
||||||
}
|
}
|
||||||
TracePlatform platform =
|
TracePlatform platform = mapper.addToTrace(coordinates.getObject(), coordinates.getSnap());
|
||||||
getPlatformForMapper(coordinates.getTrace(), coordinates.getObject(), mapper);
|
|
||||||
return coordinates.platform(platform);
|
return coordinates.platform(platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,22 +597,22 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
return mode.followsPresent();
|
return mode.followsPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TracePlatform getPlatformForMapper(Trace trace, TraceObject object,
|
|
||||||
DebuggerPlatformMapper mapper) {
|
|
||||||
return trace.getPlatformManager().getPlatform(mapper.getCompilerSpec(object));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doPlatformMapperSelected(Trace trace, DebuggerPlatformMapper mapper) {
|
protected void doPlatformMapperSelected(Trace trace, DebuggerPlatformMapper mapper) {
|
||||||
synchronized (listenersByTrace) {
|
synchronized (listenersByTrace) {
|
||||||
if (!listenersByTrace.containsKey(trace)) {
|
if (!listenersByTrace.containsKey(trace)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LastCoords cur = lastCoordsByTrace.getOrDefault(trace, LastCoords.NEVER);
|
LastCoords cur = lastCoordsByTrace.getOrDefault(trace, LastCoords.NEVER);
|
||||||
DebuggerCoordinates adj =
|
TracePlatform platform =
|
||||||
cur.coords.platform(getPlatformForMapper(trace, cur.coords.getObject(), mapper));
|
mapper.addToTrace(cur.coords.getObject(), cur.coords.getSnap());
|
||||||
|
if (cur.coords.getPlatform() == platform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DebuggerCoordinates adj = cur.coords.platform(platform);
|
||||||
lastCoordsByTrace.put(trace, cur.keepTime(adj));
|
lastCoordsByTrace.put(trace, cur.keepTime(adj));
|
||||||
if (trace == current.getTrace()) {
|
if (trace == current.getTrace()) {
|
||||||
current = adj;
|
current = adj;
|
||||||
|
trace.getProgramView().setPlatform(adj.getPlatform());
|
||||||
fireLocationEvent(adj, ActivationCause.MAPPER_CHANGED);
|
fireLocationEvent(adj, ActivationCause.MAPPER_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -789,6 +788,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
return; // We navigated elsewhere before emulation completed
|
return; // We navigated elsewhere before emulation completed
|
||||||
}
|
}
|
||||||
varView.setSnap(snap);
|
varView.setSnap(snap);
|
||||||
|
varView.setPlatform(coordinates.getPlatform());
|
||||||
fireLocationEvent(coordinates, cause);
|
fireLocationEvent(coordinates, cause);
|
||||||
}, cause == ActivationCause.EMU_STATE_EDIT
|
}, cause == ActivationCause.EMU_STATE_EDIT
|
||||||
? SwingExecutorService.MAYBE_NOW // ProgramView may call .get on Swing thread
|
? SwingExecutorService.MAYBE_NOW // ProgramView may call .get on Swing thread
|
||||||
|
@ -1167,7 +1167,9 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
if (current.getTrace() != newTrace) {
|
if (current.getTrace() != newTrace) {
|
||||||
// The snap needs to match upon re-activating this trace.
|
// The snap needs to match upon re-activating this trace.
|
||||||
try {
|
try {
|
||||||
newTrace.getProgramView().setSnap(coordinates.getViewSnap());
|
TraceVariableSnapProgramView view = newTrace.getProgramView();
|
||||||
|
view.setSnap(coordinates.getViewSnap());
|
||||||
|
view.setPlatform(coordinates.getPlatform());
|
||||||
}
|
}
|
||||||
catch (TraceClosedException e) {
|
catch (TraceClosedException e) {
|
||||||
// Presumably, a closed event is queued
|
// Presumably, a closed event is queued
|
||||||
|
|
|
@ -22,8 +22,8 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.bookmark.BookmarkNavigator;
|
import ghidra.app.plugin.core.bookmark.BookmarkNavigator;
|
||||||
import ghidra.app.services.DebuggerControlService.StateEditor;
|
import ghidra.app.services.DebuggerControlService.StateEditor;
|
||||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
|
||||||
import ghidra.app.services.DebuggerStaticMappingService;
|
import ghidra.app.services.DebuggerStaticMappingService;
|
||||||
|
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
||||||
import ghidra.pcode.exec.PcodeExecutorState;
|
import ghidra.pcode.exec.PcodeExecutorState;
|
||||||
|
@ -352,7 +352,7 @@ public class AnalysisUnwoundFrame<T> extends AbstractUnwoundFrame<T> {
|
||||||
spPlusParams.add(structure.getLength() - 1)), false, monitor);
|
spPlusParams.add(structure.getLength() - 1)), false, monitor);
|
||||||
TraceData frame = trace.getCodeManager()
|
TraceData frame = trace.getCodeManager()
|
||||||
.definedData()
|
.definedData()
|
||||||
.create(span, spPlusParams, structure);
|
.create(span, spPlusParams, platform, structure);
|
||||||
frame.setComment(CodeUnit.PRE_COMMENT, getDescription());
|
frame.setComment(CodeUnit.PRE_COMMENT, getDescription());
|
||||||
TraceReferenceManager refs = trace.getReferenceManager();
|
TraceReferenceManager refs = trace.getReferenceManager();
|
||||||
refs.clearReferencesFrom(span, frame.getRange());
|
refs.clearReferencesFrom(span, frame.getRange());
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerTest;
|
||||||
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
|
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
|
||||||
import ghidra.app.services.DebuggerPlatformService;
|
import ghidra.app.services.DebuggerPlatformService;
|
||||||
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
||||||
|
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||||
import ghidra.program.model.lang.LanguageID;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||||
|
|
||||||
|
@ -76,7 +77,9 @@ public class DebuggerPlatformPluginTest extends AbstractGhidraHeadedDebuggerTest
|
||||||
|
|
||||||
chooseLanguageIDViaMore(new LanguageID("Toy:BE:64:default"));
|
chooseLanguageIDViaMore(new LanguageID("Toy:BE:64:default"));
|
||||||
DebuggerPlatformMapper mapper = platformService.getCurrentMapperFor(tb.trace);
|
DebuggerPlatformMapper mapper = platformService.getCurrentMapperFor(tb.trace);
|
||||||
assertEquals(new LanguageID("Toy:BE:64:default"), mapper.getLangauge(null).getLanguageID());
|
DebuggerCoordinates current = traceManager.getCurrent();
|
||||||
|
assertEquals(new LanguageID("Toy:BE:64:default"),
|
||||||
|
mapper.getLangauge(current.getObject(), current.getSnap()).getLanguageID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -334,7 +334,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElse(null)
|
.orElse(null)
|
||||||
.take(tool, tb.trace);
|
.take(tool, tb.trace);
|
||||||
platformPlugin.setCurrentMapperFor(tb.trace, mapper, 0);
|
platformPlugin.setCurrentMapperFor(tb.trace, null, mapper, 0);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForPass(() -> assertEquals(x64, traceManager.getCurrentPlatform().getLanguage()));
|
waitForPass(() -> assertEquals(x64, traceManager.getCurrentPlatform().getLanguage()));
|
||||||
|
|
|
@ -335,10 +335,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTraceDataTypeManager createDataTypeManager()
|
protected DBTraceDataTypeManager createDataTypeManager(DBTracePlatformManager platformManager)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Data Type Manager", (openMode,
|
return createTraceManager("Data Type Manager", (openMode,
|
||||||
monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor, this));
|
monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor, this,
|
||||||
|
platformManager.getHostPlatform()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DependentService
|
@DependentService
|
||||||
|
@ -352,7 +353,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
@DependentService
|
@DependentService
|
||||||
protected DBTracePlatformManager createPlatformManager()
|
protected DBTracePlatformManager createPlatformManager()
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
return createTraceManager("Language Manager",
|
return createTraceManager("Platform Manager",
|
||||||
(openMode, monitor) -> new DBTracePlatformManager(dbh, openMode, rwLock, monitor,
|
(openMode, monitor) -> new DBTracePlatformManager(dbh, openMode, rwLock, monitor,
|
||||||
baseCompilerSpec, this));
|
baseCompilerSpec, this));
|
||||||
}
|
}
|
||||||
|
@ -514,7 +515,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceDataTypeManager getDataTypeManager() {
|
public DBTraceDataTypeManager getBaseDataTypeManager() {
|
||||||
return dataTypeManager;
|
return dataTypeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,8 +762,6 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Platform option?
|
|
||||||
|
|
||||||
public void setExecutablePath(String path) {
|
public void setExecutablePath(String path) {
|
||||||
getOptions(TRACE_INFO).setString(EXECUTABLE_PATH, path);
|
getOptions(TRACE_INFO).setString(EXECUTABLE_PATH, path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,12 @@ import ghidra.framework.data.OpenMode;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.*;
|
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceManager;
|
import ghidra.trace.database.DBTraceManager;
|
||||||
|
import ghidra.trace.database.guest.DBTraceGuestPlatform;
|
||||||
|
import ghidra.trace.database.guest.DBTracePlatformManager.DBTraceHostPlatform;
|
||||||
|
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.UniversalID;
|
import ghidra.util.UniversalID;
|
||||||
|
@ -41,35 +42,37 @@ import ghidra.util.task.TaskMonitor;
|
||||||
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||||
implements TraceBasedDataTypeManager, DBTraceManager {
|
implements TraceBasedDataTypeManager, DBTraceManager {
|
||||||
|
|
||||||
protected final ReadWriteLock lock; // TODO: This lock object is not used
|
/**
|
||||||
|
* NOTE: This "read-write" lock is actually just a compatibility wrapper around the
|
||||||
|
* {@link ghidra.util.Lock} for the entire trace database. There was a time when I dreamed of
|
||||||
|
* using an actual read-write lock (though it's not known if that'd actually achieve any
|
||||||
|
* appreciable speed up); however, inheriting the existing DataTypeManager implementation
|
||||||
|
* required its lock to be used throughout the database. Rather than convert all my code (and
|
||||||
|
* lose the distinction of where I need write vs. read locks), I just wrapped the API. So no,
|
||||||
|
* this code does not refer to the wrapper, but it does still use the lock. I keep a reference
|
||||||
|
* to it here in case I ever need it.
|
||||||
|
*/
|
||||||
|
protected final ReadWriteLock lock;
|
||||||
protected final DBTrace trace;
|
protected final DBTrace trace;
|
||||||
|
protected final InternalTracePlatform platform;
|
||||||
|
|
||||||
private static final String INSTANCE_TABLE_PREFIX = null; // placeholder only
|
private static String computePrefix(InternalTracePlatform platform) {
|
||||||
|
return switch (platform) {
|
||||||
|
case DBTraceHostPlatform host -> null;
|
||||||
|
case DBTraceGuestPlatform guest -> "Guest%d_".formatted(guest.getIntKey());
|
||||||
|
default -> throw new AssertionError();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public DBTraceDataTypeManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
public DBTraceDataTypeManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, DBTrace trace)
|
TaskMonitor monitor, DBTrace trace, InternalTracePlatform platform)
|
||||||
throws CancelledException, VersionException, IOException {
|
throws CancelledException, VersionException, IOException {
|
||||||
super(dbh, null, openMode, INSTANCE_TABLE_PREFIX, trace, trace.getLock(), monitor);
|
super(dbh, null, openMode, computePrefix(platform), trace, trace.getLock(), monitor);
|
||||||
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
|
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
|
this.platform = platform;
|
||||||
|
|
||||||
setProgramArchitecture(new ProgramArchitecture() {
|
setProgramArchitecture(platform, null, false, monitor);
|
||||||
|
|
||||||
@Override
|
|
||||||
public Language getLanguage() {
|
|
||||||
return trace.getBaseLanguage();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompilerSpec getCompilerSpec() {
|
|
||||||
return trace.getBaseCompilerSpec();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AddressFactory getAddressFactory() {
|
|
||||||
return trace.getBaseAddressFactory();
|
|
||||||
}
|
|
||||||
}, null, false, monitor);
|
|
||||||
|
|
||||||
if (openMode == OpenMode.CREATE) {
|
if (openMode == OpenMode.CREATE) {
|
||||||
saveDataOrganization();
|
saveDataOrganization();
|
||||||
|
@ -106,6 +109,11 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||||
categoryRenamed(CategoryPath.ROOT, getCategory(CategoryPath.ROOT));
|
categoryRenamed(CategoryPath.ROOT, getCategory(CategoryPath.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InternalTracePlatform getPlatform() {
|
||||||
|
return platform;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sourceArchiveChanged(UniversalID sourceArchiveID) {
|
public void sourceArchiveChanged(UniversalID sourceArchiveID) {
|
||||||
super.sourceArchiveChanged(sourceArchiveID);
|
super.sourceArchiveChanged(sourceArchiveID);
|
||||||
|
|
|
@ -22,7 +22,9 @@ import java.util.Map.Entry;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.app.util.PseudoInstruction;
|
import ghidra.app.util.PseudoInstruction;
|
||||||
|
import ghidra.framework.data.OpenMode;
|
||||||
import ghidra.lifecycle.Internal;
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
@ -32,8 +34,10 @@ import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.util.DefaultLanguageService;
|
import ghidra.program.util.DefaultLanguageService;
|
||||||
import ghidra.trace.database.DBTraceUtils.CompilerSpecIDDBFieldCodec;
|
import ghidra.trace.database.DBTraceUtils.CompilerSpecIDDBFieldCodec;
|
||||||
import ghidra.trace.database.DBTraceUtils.LanguageIDDBFieldCodec;
|
import ghidra.trace.database.DBTraceUtils.LanguageIDDBFieldCodec;
|
||||||
|
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
||||||
import ghidra.trace.model.Lifespan;
|
import ghidra.trace.model.Lifespan;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.trace.model.guest.TraceGuestPlatform;
|
import ghidra.trace.model.guest.TraceGuestPlatform;
|
||||||
import ghidra.trace.model.guest.TraceGuestPlatformMappedRange;
|
import ghidra.trace.model.guest.TraceGuestPlatformMappedRange;
|
||||||
import ghidra.trace.util.*;
|
import ghidra.trace.util.*;
|
||||||
|
@ -156,6 +160,8 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
|
||||||
new TreeMap<>();
|
new TreeMap<>();
|
||||||
protected final AddressSet guestAddressSet = new AddressSet();
|
protected final AddressSet guestAddressSet = new AddressSet();
|
||||||
|
|
||||||
|
protected DBTraceDataTypeManager dataTypeManager;
|
||||||
|
|
||||||
public DBTraceGuestPlatform(DBTracePlatformManager manager, DBCachedObjectStore<?> store,
|
public DBTraceGuestPlatform(DBTracePlatformManager manager, DBCachedObjectStore<?> store,
|
||||||
DBRecord record) {
|
DBRecord record) {
|
||||||
super(store, record);
|
super(store, record);
|
||||||
|
@ -187,6 +193,12 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void loadDataTypeManager(OpenMode openMode, TaskMonitor monitor)
|
||||||
|
throws CancelledException, VersionException, IOException {
|
||||||
|
this.dataTypeManager = new DBTraceDataTypeManager(manager.dbh, openMode, manager.lock,
|
||||||
|
monitor, manager.trace, this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Trace getTrace() {
|
public Trace getTrace() {
|
||||||
return manager.trace;
|
return manager.trace;
|
||||||
|
@ -235,6 +247,11 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
|
||||||
return compilerSpec;
|
return compilerSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TraceBasedDataTypeManager getDataTypeManager() {
|
||||||
|
return dataTypeManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(TaskMonitor monitor) throws CancelledException {
|
public void delete(TaskMonitor monitor) throws CancelledException {
|
||||||
manager.deleteGuestPlatform(this, monitor);
|
manager.deleteGuestPlatform(this, monitor);
|
||||||
|
@ -284,6 +301,12 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
|
||||||
return next.getMaxAddress().add(1);
|
return next.getMaxAddress().add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ResourceFile getSlaFile(Language language) {
|
||||||
|
SleighLanguageDescription desc =
|
||||||
|
(SleighLanguageDescription) language.getLanguageDescription();
|
||||||
|
return desc.getSlaFile();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceGuestPlatformMappedRange addMappedRegisterRange()
|
public TraceGuestPlatformMappedRange addMappedRegisterRange()
|
||||||
throws AddressOverflowException {
|
throws AddressOverflowException {
|
||||||
|
@ -292,8 +315,24 @@ public class DBTraceGuestPlatform extends DBAnnotatedObject
|
||||||
if (guestRange == null) {
|
if (guestRange == null) {
|
||||||
return null; // No registers, so we're mapped!
|
return null; // No registers, so we're mapped!
|
||||||
}
|
}
|
||||||
Address hostMin = manager.computeNextRegisterMin();
|
|
||||||
long size = guestRange.getLength();
|
long size = guestRange.getLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the two languages are really the same (have the same .sla file), then map
|
||||||
|
* registers identically. Such languages differ only in their default contextreg values.
|
||||||
|
*/
|
||||||
|
ResourceFile hostSla = getSlaFile(manager.hostPlatform.getLanguage());
|
||||||
|
ResourceFile guestSla = getSlaFile(getLanguage());
|
||||||
|
Address hostMin;
|
||||||
|
if (Objects.equals(hostSla, guestSla)) {
|
||||||
|
hostMin = manager.hostPlatform.getAddressFactory()
|
||||||
|
.getRegisterSpace()
|
||||||
|
.getAddress(guestRange.getMinAddress().getOffset());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hostMin = manager.computeNextRegisterMin();
|
||||||
|
}
|
||||||
|
|
||||||
return addMappedRange(hostMin, guestRange.getMinAddress(), size);
|
return addMappedRange(hostMin, guestRange.getMinAddress(), size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.DBTraceManager;
|
import ghidra.trace.database.DBTraceManager;
|
||||||
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
|
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.trace.model.guest.*;
|
import ghidra.trace.model.guest.*;
|
||||||
import ghidra.trace.util.TraceChangeRecord;
|
import ghidra.trace.util.TraceChangeRecord;
|
||||||
import ghidra.trace.util.TraceEvents;
|
import ghidra.trace.util.TraceEvents;
|
||||||
|
@ -61,7 +62,8 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
|
|
||||||
protected final DBCachedObjectStore<DBTraceGuestPlatformMappedRange> rangeMappingStore;
|
protected final DBCachedObjectStore<DBTraceGuestPlatformMappedRange> rangeMappingStore;
|
||||||
|
|
||||||
protected final InternalTracePlatform hostPlatform = new InternalTracePlatform() {
|
@Internal
|
||||||
|
public class DBTraceHostPlatform implements InternalTracePlatform {
|
||||||
@Override
|
@Override
|
||||||
public Trace getTrace() {
|
public Trace getTrace() {
|
||||||
return trace;
|
return trace;
|
||||||
|
@ -97,6 +99,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
return trace.getBaseAddressFactory();
|
return trace.getBaseAddressFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TraceBasedDataTypeManager getDataTypeManager() {
|
||||||
|
return trace.getBaseDataTypeManager();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getHostAddressSet() {
|
public AddressSetView getHostAddressSet() {
|
||||||
return trace.getBaseAddressFactory().getAddressSet();
|
return trace.getBaseAddressFactory().getAddressSet();
|
||||||
|
@ -146,11 +153,13 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
public InstructionSet mapGuestInstructionAddressesToHost(InstructionSet set) {
|
public InstructionSet mapGuestInstructionAddressesToHost(InstructionSet set) {
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
protected final InternalTracePlatform hostPlatform = new DBTraceHostPlatform();
|
||||||
|
|
||||||
public DBTracePlatformManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
public DBTracePlatformManager(DBHandle dbh, OpenMode openMode, ReadWriteLock lock,
|
||||||
TaskMonitor monitor, CompilerSpec baseCompilerSpec, DBTrace trace)
|
TaskMonitor monitor, CompilerSpec baseCompilerSpec, DBTrace trace)
|
||||||
throws VersionException, IOException {
|
throws VersionException, IOException, CancelledException {
|
||||||
this.dbh = dbh;
|
this.dbh = dbh;
|
||||||
this.lock = lock;
|
this.lock = lock;
|
||||||
this.baseLanguage = baseCompilerSpec.getLanguage();
|
this.baseLanguage = baseCompilerSpec.getLanguage();
|
||||||
|
@ -169,7 +178,7 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
(s, r) -> new DBTraceGuestPlatformMappedRange(this, s, r), true);
|
(s, r) -> new DBTraceGuestPlatformMappedRange(this, s, r), true);
|
||||||
|
|
||||||
loadLanguages();
|
loadLanguages();
|
||||||
loadPlatforms();
|
loadPlatforms(openMode, monitor);
|
||||||
loadPlatformMappings();
|
loadPlatformMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +188,10 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadPlatforms()
|
protected void loadPlatforms(OpenMode openMode, TaskMonitor monitor)
|
||||||
throws LanguageNotFoundException, CompilerSpecNotFoundException, VersionException {
|
throws VersionException, CancelledException, IOException {
|
||||||
for (DBTraceGuestPlatform platformEntry : platformStore.asMap().values()) {
|
for (DBTraceGuestPlatform platformEntry : platformStore.asMap().values()) {
|
||||||
|
platformEntry.loadDataTypeManager(openMode, monitor);
|
||||||
platformsByCompiler.put(platformEntry.getCompilerSpec(), platformEntry);
|
platformsByCompiler.put(platformEntry.getCompilerSpec(), platformEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,10 +273,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
platformsByCompiler.clear();
|
platformsByCompiler.clear();
|
||||||
try {
|
try {
|
||||||
loadLanguages();
|
loadLanguages();
|
||||||
loadPlatforms();
|
// TODO: Or IMMUTABLE, if that was the original, and supported
|
||||||
|
loadPlatforms(OpenMode.UPDATE, TaskMonitor.DUMMY);
|
||||||
loadPlatformMappings();
|
loadPlatformMappings();
|
||||||
}
|
}
|
||||||
catch (LanguageNotFoundException | CompilerSpecNotFoundException | VersionException e) {
|
catch (IOException | VersionException | CancelledException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,6 +311,12 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
protected DBTraceGuestPlatform doAddGuestPlatform(CompilerSpec compilerSpec) {
|
protected DBTraceGuestPlatform doAddGuestPlatform(CompilerSpec compilerSpec) {
|
||||||
DBTraceGuestPlatform platformEntry = platformStore.create();
|
DBTraceGuestPlatform platformEntry = platformStore.create();
|
||||||
platformEntry.set(compilerSpec);
|
platformEntry.set(compilerSpec);
|
||||||
|
try {
|
||||||
|
platformEntry.loadDataTypeManager(OpenMode.CREATE, TaskMonitor.DUMMY);
|
||||||
|
}
|
||||||
|
catch (CancelledException | VersionException | IOException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
platformsByCompiler.put(compilerSpec, platformEntry);
|
platformsByCompiler.put(compilerSpec, platformEntry);
|
||||||
return platformEntry;
|
return platformEntry;
|
||||||
}
|
}
|
||||||
|
@ -330,12 +347,11 @@ public class DBTracePlatformManager implements DBTraceManager, TracePlatformMana
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InternalTracePlatform getOrAddPlatform(CompilerSpec compilerSpec) {
|
public InternalTracePlatform getOrAddPlatform(CompilerSpec compilerSpec) {
|
||||||
if (compilerSpec.getCompilerSpecID()
|
|
||||||
.equals(trace.getBaseCompilerSpec().getCompilerSpecID())) {
|
|
||||||
return hostPlatform;
|
|
||||||
}
|
|
||||||
DBTraceGuestPlatform platform;
|
DBTraceGuestPlatform platform;
|
||||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||||
|
if (trace.getBaseCompilerSpec() == compilerSpec) {
|
||||||
|
return hostPlatform;
|
||||||
|
}
|
||||||
DBTraceGuestPlatform exists = platformsByCompiler.get(compilerSpec);
|
DBTraceGuestPlatform exists = platformsByCompiler.get(compilerSpec);
|
||||||
if (exists != null) {
|
if (exists != null) {
|
||||||
return exists;
|
return exists;
|
||||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.trace.database.guest;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.lang.Register;
|
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
|
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
|
@ -34,7 +33,7 @@ import ghidra.util.LockHold;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
public interface InternalTracePlatform extends TracePlatform {
|
public interface InternalTracePlatform extends TracePlatform, ProgramArchitecture {
|
||||||
String REG_MAP_BE = "__reg_map_be__";
|
String REG_MAP_BE = "__reg_map_be__";
|
||||||
String REG_MAP_LE = "__reg_map_le__";
|
String REG_MAP_LE = "__reg_map_le__";
|
||||||
|
|
||||||
|
@ -51,6 +50,11 @@ public interface InternalTracePlatform extends TracePlatform {
|
||||||
|
|
||||||
DBTraceGuestLanguage getLanguageEntry();
|
DBTraceGuestLanguage getLanguageEntry();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default AddressFactory getAddressFactory() {
|
||||||
|
return TracePlatform.super.getAddressFactory();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default AddressRange getConventionalRegisterRange(AddressSpace space, Register register) {
|
default AddressRange getConventionalRegisterRange(AddressSpace space, Register register) {
|
||||||
AddressRange result = mapGuestToHost(TraceRegisterUtils.rangeForRegister(register));
|
AddressRange result = mapGuestToHost(TraceRegisterUtils.rangeForRegister(register));
|
||||||
|
|
|
@ -28,8 +28,8 @@ import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.data.DBTraceDataTypeManager;
|
|
||||||
import ghidra.trace.database.guest.DBTraceGuestPlatform;
|
import ghidra.trace.database.guest.DBTraceGuestPlatform;
|
||||||
|
import ghidra.trace.database.guest.DBTracePlatformManager;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
|
||||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||||
|
@ -63,7 +63,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
|
||||||
protected final ReadWriteLock lock;
|
protected final ReadWriteLock lock;
|
||||||
protected final Language baseLanguage;
|
protected final Language baseLanguage;
|
||||||
protected final DBTrace trace;
|
protected final DBTrace trace;
|
||||||
protected final DBTraceDataTypeManager dataTypeManager;
|
protected final DBTracePlatformManager platformManager;
|
||||||
protected final DBTraceReferenceManager referenceManager;
|
protected final DBTraceReferenceManager referenceManager;
|
||||||
protected final AddressRange all;
|
protected final AddressRange all;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
|
||||||
this.lock = manager.getLock();
|
this.lock = manager.getLock();
|
||||||
this.baseLanguage = manager.getBaseLanguage();
|
this.baseLanguage = manager.getBaseLanguage();
|
||||||
this.trace = manager.getTrace();
|
this.trace = manager.getTrace();
|
||||||
this.dataTypeManager = manager.dataTypeManager;
|
this.platformManager = manager.platformManager;
|
||||||
this.referenceManager = manager.referenceManager;
|
this.referenceManager = manager.referenceManager;
|
||||||
this.all = new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress());
|
this.all = new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress());
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
|
||||||
if (reApply) {
|
if (reApply) {
|
||||||
try {
|
try {
|
||||||
definedData.create(Lifespan.span(unitStartSnap, unitEndSnap),
|
definedData.create(Lifespan.span(unitStartSnap, unitEndSnap),
|
||||||
unit.getAddress(), dataType, unit.getLength());
|
unit.getAddress(), unit.getPlatform(), dataType, unit.getLength());
|
||||||
}
|
}
|
||||||
catch (CodeUnitInsertionException e) {
|
catch (CodeUnitInsertionException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit<DBTraceData>
|
||||||
if (platform == null) {
|
if (platform == null) {
|
||||||
throw new IOException("Data table is corrupt. Missing platform: " + platformKey);
|
throw new IOException("Data table is corrupt. Missing platform: " + platformKey);
|
||||||
}
|
}
|
||||||
dataType = space.dataTypeManager.getDataType(dataTypeID);
|
dataType = platform.getDataTypeManager().getDataType(dataTypeID);
|
||||||
if (dataType == null) {
|
if (dataType == null) {
|
||||||
throw new IOException("Data table is corrupt. Missing datatype: " + dataTypeID);
|
throw new IOException("Data table is corrupt. Missing datatype: " + dataTypeID);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ public class DBTraceData extends AbstractDBTraceCodeUnit<DBTraceData>
|
||||||
|
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
// Use the stored dataType, not the given one, in case it's different
|
// Use the stored dataType, not the given one, in case it's different
|
||||||
this.dataType = space.dataTypeManager.getDataType(dataTypeID);
|
this.dataType = platform.getDataTypeManager().getDataType(dataTypeID);
|
||||||
assert this.dataType != null;
|
assert this.dataType != null;
|
||||||
this.defaultSettings = this.dataType.getDefaultSettings();
|
this.defaultSettings = this.dataType.getDefaultSettings();
|
||||||
this.baseDataType = getBaseDataType(this.dataType);
|
this.baseDataType = getBaseDataType(this.dataType);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.trace.model.Lifespan;
|
import ghidra.trace.model.Lifespan;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.listing.TraceCodeManager;
|
import ghidra.trace.model.listing.TraceCodeManager;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -52,15 +53,16 @@ public class DBTraceDefinedDataMemoryView
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType,
|
public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
int length) throws CodeUnitInsertionException {
|
DataType dataType, int length) throws CodeUnitInsertionException {
|
||||||
return delegateWrite(address.getAddressSpace(),
|
return delegateWrite(address.getAddressSpace(),
|
||||||
m -> m.create(lifespan, address, dataType, length));
|
m -> m.create(lifespan, address, platform, dataType, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
|
public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
throws CodeUnitInsertionException {
|
DataType dataType) throws CodeUnitInsertionException {
|
||||||
return delegateWrite(address.getAddressSpace(), m -> m.create(lifespan, address, dataType));
|
return delegateWrite(address.getAddressSpace(),
|
||||||
|
m -> m.create(lifespan, address, platform, dataType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,10 @@ import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
|
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||||
import ghidra.trace.util.TraceChangeRecord;
|
import ghidra.trace.util.TraceChangeRecord;
|
||||||
import ghidra.trace.util.TraceEvents;
|
import ghidra.trace.util.TraceEvents;
|
||||||
|
@ -41,9 +43,9 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // NOTE: "Adapter" because using DataType.DEFAULT gives UndefinedDBTraceData
|
@Override // NOTE: "Adapter" because using DataType.DEFAULT gives UndefinedDBTraceData
|
||||||
public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
|
public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
throws CodeUnitInsertionException {
|
DataType dataType) throws CodeUnitInsertionException {
|
||||||
return create(lifespan, address, dataType, dataType.getLength());
|
return create(lifespan, address, platform, dataType, dataType.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,9 +69,12 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// TODO: Probably add language parameter....
|
public DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
public DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType origType,
|
DataType origType, int origLength) throws CodeUnitInsertionException {
|
||||||
int origLength) throws CodeUnitInsertionException {
|
if (platform.getTrace() != getTrace() ||
|
||||||
|
!(platform instanceof InternalTracePlatform iPlatform)) {
|
||||||
|
throw new IllegalArgumentException("Platform is not part of this trace");
|
||||||
|
}
|
||||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||||
DBTraceMemorySpace memSpace = space.trace.getMemoryManager().get(space, true);
|
DBTraceMemorySpace memSpace = space.trace.getMemoryManager().get(space, true);
|
||||||
// NOTE: User-given length could be ignored....
|
// NOTE: User-given length could be ignored....
|
||||||
|
@ -97,12 +102,11 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
|
||||||
if (dataType == null) {
|
if (dataType == null) {
|
||||||
throw new CodeUnitInsertionException("Failed to resolve data type");
|
throw new CodeUnitInsertionException("Failed to resolve data type");
|
||||||
}
|
}
|
||||||
// TODO: This clone may need to be sensitive to the unit's language.
|
DataTypeManager dtm = platform.getDataTypeManager();
|
||||||
dataType = dataType.clone(space.dataTypeManager);
|
dataType = dataType.clone(dtm);
|
||||||
|
|
||||||
if (isFunctionDefinition(dataType)) {
|
if (isFunctionDefinition(dataType)) {
|
||||||
// TODO: This pointer will need to be sensitive to the unit's language.
|
dataType = new PointerDataType(dataType, dtm);
|
||||||
dataType = new PointerDataType(dataType, dataType.getDataTypeManager());
|
|
||||||
length = dataType.getLength();
|
length = dataType.getLength();
|
||||||
}
|
}
|
||||||
else if (dataType instanceof Dynamic) {
|
else if (dataType instanceof Dynamic) {
|
||||||
|
@ -112,8 +116,6 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
|
||||||
MemBuffer buffer = memSpace.getBufferAt(startSnap, address);
|
MemBuffer buffer = memSpace.getBufferAt(startSnap, address);
|
||||||
length = dyn.getLength(buffer, length);
|
length = dyn.getLength(buffer, length);
|
||||||
}
|
}
|
||||||
// TODO: Do I need to check for Pointer type here?
|
|
||||||
// Seems purpose is to adjust for language, but I think clone does that already
|
|
||||||
else {
|
else {
|
||||||
length = dataType.getLength();
|
length = dataType.getLength();
|
||||||
}
|
}
|
||||||
|
@ -143,10 +145,9 @@ public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<
|
||||||
return space.undefinedData.getAt(startSnap, address);
|
return space.undefinedData.getAt(startSnap, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
long dataTypeID = space.dataTypeManager.getResolvedID(dataType);
|
long dataTypeID = dtm.getResolvedID(dataType);
|
||||||
DBTraceData created = mapSpace.put(tasr, null);
|
DBTraceData created = mapSpace.put(tasr, null);
|
||||||
// TODO: data units with a guest platform
|
created.set(iPlatform, dataTypeID);
|
||||||
created.set(space.trace.getPlatformManager().getHostPlatform(), dataTypeID);
|
|
||||||
// TODO: Explicitly remove undefined from cache, or let weak refs take care of it?
|
// TODO: Explicitly remove undefined from cache, or let weak refs take care of it?
|
||||||
|
|
||||||
cacheForContaining.notifyNewEntry(tasr.getLifespan(), createdRange, created);
|
cacheForContaining.notifyNewEntry(tasr.getLifespan(), createdRange, created);
|
||||||
|
|
|
@ -15,24 +15,60 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.listing;
|
package ghidra.trace.database.listing;
|
||||||
|
|
||||||
|
import ghidra.lifecycle.Internal;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressRange;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.trace.model.Lifespan;
|
import ghidra.trace.model.Lifespan;
|
||||||
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.listing.TraceData;
|
import ghidra.trace.model.listing.TraceData;
|
||||||
import ghidra.trace.model.listing.TraceDefinedDataView;
|
import ghidra.trace.model.listing.TraceDefinedDataView;
|
||||||
import ghidra.trace.util.TraceRegisterUtils;
|
import ghidra.trace.util.TraceRegisterUtils;
|
||||||
|
|
||||||
|
@Internal
|
||||||
public interface InternalTraceDefinedDataView
|
public interface InternalTraceDefinedDataView
|
||||||
extends TraceDefinedDataView, InternalTraceBaseDefinedUnitsView<TraceData> {
|
extends TraceDefinedDataView, InternalTraceBaseDefinedUnitsView<TraceData> {
|
||||||
|
|
||||||
|
default TracePlatform getPlatformOf(DataType type) {
|
||||||
|
if (type.getDataTypeManager() instanceof TraceBasedDataTypeManager dtm &&
|
||||||
|
dtm.getTrace() == getTrace()) {
|
||||||
|
return dtm.getPlatform();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* TODO: Could we seek a nearest match in terms of data organization? Eh. Maybe not, because
|
||||||
|
* we'd also have to be concerned with whether there's a mapping at the desired address.
|
||||||
|
*/
|
||||||
|
return getTrace().getPlatformManager().getHostPlatform();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default TraceData create(TracePlatform platform, Lifespan lifespan, Register register,
|
DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
|
DataType dataType) throws CodeUnitInsertionException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DBTraceDataAdapter create(Lifespan lifespan, Address address, TracePlatform platform,
|
||||||
|
DataType dataType, int length) throws CodeUnitInsertionException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType,
|
||||||
|
int length) throws CodeUnitInsertionException {
|
||||||
|
return create(lifespan, address, getPlatformOf(dataType), dataType, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DBTraceDataAdapter create(Lifespan lifespan, Address address, DataType dataType)
|
||||||
|
throws CodeUnitInsertionException {
|
||||||
|
return create(lifespan, address, getPlatformOf(dataType), dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DBTraceDataAdapter create(TracePlatform platform, Lifespan lifespan, Register register,
|
||||||
DataType dataType) throws CodeUnitInsertionException {
|
DataType dataType) throws CodeUnitInsertionException {
|
||||||
TraceRegisterUtils.requireByteBound(register);
|
TraceRegisterUtils.requireByteBound(register);
|
||||||
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
||||||
return create(lifespan, range.getMinAddress(), dataType, (int) range.getLength());
|
return create(lifespan, range.getMinAddress(), platform, dataType, (int) range.getLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
import ghidra.program.model.util.PropertyMap;
|
import ghidra.program.model.util.PropertyMap;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.database.guest.InternalTracePlatform;
|
|
||||||
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry;
|
import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry;
|
||||||
|
@ -77,7 +76,6 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
|
|
||||||
protected final DBTraceProgramView program;
|
protected final DBTraceProgramView program;
|
||||||
protected final TraceCodeOperations codeOperations;
|
protected final TraceCodeOperations codeOperations;
|
||||||
protected final InternalTracePlatform platform;
|
|
||||||
|
|
||||||
protected final DBTraceProgramViewRootModule rootModule;
|
protected final DBTraceProgramViewRootModule rootModule;
|
||||||
protected final Map<TraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion =
|
protected final Map<TraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion =
|
||||||
|
@ -90,8 +88,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
TraceCodeOperations codeOperations) {
|
TraceCodeOperations codeOperations) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.codeOperations = codeOperations;
|
this.codeOperations = codeOperations;
|
||||||
// TODO: Guest platform views?
|
// TODO: Map addresses when platform is guest?
|
||||||
this.platform = program.trace.getPlatformManager().getHostPlatform();
|
|
||||||
|
|
||||||
this.rootModule = new DBTraceProgramViewRootModule(this);
|
this.rootModule = new DBTraceProgramViewRootModule(this);
|
||||||
}
|
}
|
||||||
|
@ -751,7 +748,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
range, s -> s == TraceMemoryState.KNOWN);
|
range, s -> s == TraceMemoryState.KNOWN);
|
||||||
long snap = mostRecent == null ? program.snap : mostRecent.getKey().getY2();
|
long snap = mostRecent == null ? program.snap : mostRecent.getKey().getY2();
|
||||||
return codeOperations.instructions()
|
return codeOperations.instructions()
|
||||||
.create(Lifespan.nowOn(snap), addr, platform, prototype, context,
|
.create(Lifespan.nowOn(snap), addr, program.platform, prototype, context,
|
||||||
forcedLengthOverride);
|
forcedLengthOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,7 +756,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
public AddressSetView addInstructions(InstructionSet instructionSet, boolean overwrite)
|
public AddressSetView addInstructions(InstructionSet instructionSet, boolean overwrite)
|
||||||
throws CodeUnitInsertionException {
|
throws CodeUnitInsertionException {
|
||||||
return codeOperations.instructions()
|
return codeOperations.instructions()
|
||||||
.addInstructionSet(Lifespan.nowOn(program.snap), platform, instructionSet,
|
.addInstructionSet(Lifespan.nowOn(program.snap), program.platform, instructionSet,
|
||||||
overwrite);
|
overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,12 +764,13 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
public Data createData(Address addr, DataType dataType, int length)
|
public Data createData(Address addr, DataType dataType, int length)
|
||||||
throws CodeUnitInsertionException {
|
throws CodeUnitInsertionException {
|
||||||
return codeOperations.definedData()
|
return codeOperations.definedData()
|
||||||
.create(Lifespan.nowOn(program.snap), addr, dataType, length);
|
.create(Lifespan.nowOn(program.snap), addr, program.platform, dataType, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Data createData(Address addr, DataType dataType) throws CodeUnitInsertionException {
|
public Data createData(Address addr, DataType dataType) throws CodeUnitInsertionException {
|
||||||
return codeOperations.definedData().create(Lifespan.nowOn(program.snap), addr, dataType);
|
return codeOperations.definedData()
|
||||||
|
.create(Lifespan.nowOn(program.snap), addr, program.platform, dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,6 +45,7 @@ import ghidra.program.model.util.AddressSetPropertyMap;
|
||||||
import ghidra.program.model.util.PropertyMapManager;
|
import ghidra.program.model.util.PropertyMapManager;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
import ghidra.trace.database.*;
|
import ghidra.trace.database.*;
|
||||||
|
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||||
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
||||||
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
|
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
|
@ -333,40 +334,40 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
range.getX1(), range.getX1(), null, null, null));
|
range.getX1(), range.getX1(), null, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentChanged(int commentType, TraceAddressSpace space,
|
private void commentChanged(CommentType commentType, TraceAddressSpace space,
|
||||||
TraceAddressSnapRange range, String oldValue, String newValue) {
|
TraceAddressSnapRange range, String oldValue, String newValue) {
|
||||||
DomainObjectEventQueues queues = isVisible(space, range);
|
DomainObjectEventQueues queues = isVisible(space, range);
|
||||||
if (queues == null) {
|
if (queues == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queues.fireEvent(
|
queues.fireEvent(
|
||||||
new CommentChangeRecord(commentType, range.getX1(), oldValue, newValue));
|
new CommentChangeRecord(commentType.ordinal(), range.getX1(), oldValue, newValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentEolChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void commentEolChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
String oldValue, String newValue) {
|
String oldValue, String newValue) {
|
||||||
commentChanged(CodeUnit.EOL_COMMENT, space, range, oldValue, newValue);
|
commentChanged(CommentType.EOL, space, range, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentPlateChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void commentPlateChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
String oldValue, String newValue) {
|
String oldValue, String newValue) {
|
||||||
commentChanged(CodeUnit.PLATE_COMMENT, space, range, oldValue, newValue);
|
commentChanged(CommentType.PLATE, space, range, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentPostChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void commentPostChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
String oldValue, String newValue) {
|
String oldValue, String newValue) {
|
||||||
commentChanged(CodeUnit.POST_COMMENT, space, range, oldValue, newValue);
|
commentChanged(CommentType.POST, space, range, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentPreChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void commentPreChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
String oldValue, String newValue) {
|
String oldValue, String newValue) {
|
||||||
commentChanged(CodeUnit.PRE_COMMENT, space, range, oldValue, newValue);
|
commentChanged(CommentType.PRE, space, range, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commentRepeatableChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void commentRepeatableChanged(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
String oldValue, String newValue) {
|
String oldValue, String newValue) {
|
||||||
// TODO: The "repeatable" semantics are not implemented, yet.
|
// TODO: The "repeatable" semantics are not implemented, yet.
|
||||||
commentChanged(CodeUnit.REPEATABLE_COMMENT, space, range, oldValue, newValue);
|
commentChanged(CommentType.REPEATABLE, space, range, oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compositeDataAdded(TraceAddressSpace space, TraceAddressSnapRange range,
|
private void compositeDataAdded(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
|
@ -697,6 +698,7 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
protected final Map<TraceThread, DBTraceProgramViewRegisters> regViewsByThread;
|
protected final Map<TraceThread, DBTraceProgramViewRegisters> regViewsByThread;
|
||||||
|
|
||||||
protected long snap;
|
protected long snap;
|
||||||
|
protected InternalTracePlatform platform;
|
||||||
protected final DBTraceTimeViewport viewport;
|
protected final DBTraceTimeViewport viewport;
|
||||||
protected final Runnable viewportChangeListener = this::viewportChanged;
|
protected final Runnable viewportChangeListener = this::viewportChanged;
|
||||||
|
|
||||||
|
@ -715,6 +717,9 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
this.viewport = trace.createTimeViewport();
|
this.viewport = trace.createTimeViewport();
|
||||||
this.viewport.setSnap(snap);
|
this.viewport.setSnap(snap);
|
||||||
|
|
||||||
|
// TODO: Initialize guest platform for fixed views?
|
||||||
|
this.platform = trace.getPlatformManager().getHostPlatform();
|
||||||
|
|
||||||
this.eventQueues = new DomainObjectEventQueues(this, TIME_INTERVAL, trace.getLock());
|
this.eventQueues = new DomainObjectEventQueues(this, TIME_INTERVAL, trace.getLock());
|
||||||
|
|
||||||
this.regViewsByThread = new WeakValueHashMap<>();
|
this.regViewsByThread = new WeakValueHashMap<>();
|
||||||
|
@ -833,7 +838,7 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TraceBasedDataTypeManager getDataTypeManager() {
|
public TraceBasedDataTypeManager getDataTypeManager() {
|
||||||
return trace.getDataTypeManager();
|
return platform.getDataTypeManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.trace.database.program;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.trace.database.DBTrace;
|
import ghidra.trace.database.DBTrace;
|
||||||
|
import ghidra.trace.database.guest.InternalTracePlatform;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.program.TraceVariableSnapProgramView;
|
import ghidra.trace.model.program.TraceVariableSnapProgramView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,4 +50,13 @@ public class DBTraceVariableSnapProgramView extends DBTraceProgramView
|
||||||
// TODO: I could be more particular, but this seems to work fast enough, now.
|
// TODO: I could be more particular, but this seems to work fast enough, now.
|
||||||
fireObjectRestored();
|
fireObjectRestored();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPlatform(TracePlatform platform) {
|
||||||
|
if (!(platform instanceof InternalTracePlatform iPlatform) ||
|
||||||
|
platform.getTrace() != trace) {
|
||||||
|
throw new IllegalArgumentException("Platform is not in this trace");
|
||||||
|
}
|
||||||
|
this.platform = iPlatform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import javax.swing.Icon;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.lifecycle.Transitional;
|
import ghidra.lifecycle.Transitional;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.data.DataTypeManagerDomainObject;
|
import ghidra.program.model.data.DataTypeManagerDomainObject;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
|
@ -31,6 +32,7 @@ import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointManager;
|
import ghidra.trace.model.breakpoint.TraceBreakpointManager;
|
||||||
import ghidra.trace.model.context.TraceRegisterContextManager;
|
import ghidra.trace.model.context.TraceRegisterContextManager;
|
||||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.guest.TracePlatformManager;
|
import ghidra.trace.model.guest.TracePlatformManager;
|
||||||
import ghidra.trace.model.listing.TraceCodeManager;
|
import ghidra.trace.model.listing.TraceCodeManager;
|
||||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||||
|
@ -95,8 +97,19 @@ public interface Trace extends DataTypeManagerDomainObject {
|
||||||
|
|
||||||
TraceCodeManager getCodeManager();
|
TraceCodeManager getCodeManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For traces, this gets the "base" or "host" {@link DataTypeManager}. For platform-specific
|
||||||
|
* managers, see {@link TracePlatform#getDataTypeManager()}.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
TraceBasedDataTypeManager getDataTypeManager();
|
default TraceBasedDataTypeManager getDataTypeManager() {
|
||||||
|
return getBaseDataTypeManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceBasedDataTypeManager getBaseDataTypeManager();
|
||||||
|
|
||||||
TraceEquateManager getEquateManager();
|
TraceEquateManager getEquateManager();
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.trace.model.data;
|
||||||
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +37,13 @@ public interface TraceBasedDataTypeManager extends ProgramBasedDataTypeManager {
|
||||||
*/
|
*/
|
||||||
Trace getTrace();
|
Trace getTrace();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the platform for which this data type manager is provided
|
||||||
|
*
|
||||||
|
* @return the platform
|
||||||
|
*/
|
||||||
|
TracePlatform getPlatform();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Petition to have this replace
|
* TODO: Petition to have this replace
|
||||||
* {@link TraceBasedDataTypeManager#resolve(DataType, DataTypeConflictHandler)}
|
* {@link TraceBasedDataTypeManager#resolve(DataType, DataTypeConflictHandler)}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.trace.model.memory.TraceObjectRegister;
|
import ghidra.trace.model.memory.TraceObjectRegister;
|
||||||
import ghidra.trace.model.symbol.TraceLabelSymbol;
|
import ghidra.trace.model.symbol.TraceLabelSymbol;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.TraceObject;
|
||||||
|
@ -83,10 +84,17 @@ public interface TracePlatform {
|
||||||
/**
|
/**
|
||||||
* Get the compiler of the guest platform
|
* Get the compiler of the guest platform
|
||||||
*
|
*
|
||||||
* @return the compiler spec
|
* @return the compiler specification
|
||||||
*/
|
*/
|
||||||
CompilerSpec getCompilerSpec();
|
CompilerSpec getCompilerSpec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data type manager for this platform.
|
||||||
|
*
|
||||||
|
* @return the data type manager
|
||||||
|
*/
|
||||||
|
TraceBasedDataTypeManager getDataTypeManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the addresses in the host which are mapped to somewhere in the guest
|
* Get the addresses in the host which are mapped to somewhere in the guest
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.trace.model.listing;
|
package ghidra.trace.model.listing;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.DataOrganization;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
|
@ -29,9 +30,14 @@ import ghidra.trace.model.guest.TracePlatform;
|
||||||
* This view excludes instructions and default / undefined data units.
|
* This view excludes instructions and default / undefined data units.
|
||||||
*/
|
*/
|
||||||
public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceData> {
|
public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceData> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a data unit starting at the given address
|
* Create a data unit starting at the given address
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* If the given type is already part of this trace, its platform is used as is. If not, then it
|
||||||
|
* is resolved to the host platform.
|
||||||
|
*
|
||||||
* @param lifespan the span for which the unit is effective
|
* @param lifespan the span for which the unit is effective
|
||||||
* @param address the starting address
|
* @param address the starting address
|
||||||
* @param dataType the data type for the unit
|
* @param dataType the data type for the unit
|
||||||
|
@ -42,12 +48,31 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceDat
|
||||||
TraceData create(Lifespan lifespan, Address address, DataType dataType, int length)
|
TraceData create(Lifespan lifespan, Address address, DataType dataType, int length)
|
||||||
throws CodeUnitInsertionException;
|
throws CodeUnitInsertionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a data unit starting at the given address
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The given type is resolved to the given platform, even if the type already exists in the
|
||||||
|
* trace by another platform.
|
||||||
|
*
|
||||||
|
* @param lifespan the span for which the unit is effective
|
||||||
|
* @param address the starting address
|
||||||
|
* @param platform the platform for the type's {@link DataOrganization}
|
||||||
|
* @param dataType the data type for the unit
|
||||||
|
* @param length the length of the unit, -1 for unspecified
|
||||||
|
* @return the new data unit
|
||||||
|
* @throws CodeUnitInsertionException if there's a conflict
|
||||||
|
*/
|
||||||
|
TraceData create(Lifespan lifespan, Address address, TracePlatform platform, DataType dataType,
|
||||||
|
int length) throws CodeUnitInsertionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a data unit of unspecified length starting at the given address
|
* Create a data unit of unspecified length starting at the given address
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The length will be determined by the data type, possibly by examining the bytes, e.g., a
|
* The length will be determined by the data type, possibly by examining the bytes, e.g., a
|
||||||
* null-terminated UTF-8 string.
|
* null-terminated UTF-8 string. If the given type is already part of this trace, its platform
|
||||||
|
* is used as is. If not, then it is resolved to the host platform.
|
||||||
*
|
*
|
||||||
* @param lifespan the span for which the unit is effective
|
* @param lifespan the span for which the unit is effective
|
||||||
* @param address the starting address
|
* @param address the starting address
|
||||||
|
@ -58,12 +83,31 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceDat
|
||||||
TraceData create(Lifespan lifespan, Address address, DataType dataType)
|
TraceData create(Lifespan lifespan, Address address, DataType dataType)
|
||||||
throws CodeUnitInsertionException;
|
throws CodeUnitInsertionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a data unit of unspecified length starting at the given address
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The length will be determined by the data type, possibly by examining the bytes, e.g., a
|
||||||
|
* null-terminated UTF-8 string. The given type is resolved to the given platform, even if the
|
||||||
|
* type already exists in the trace by another platform.
|
||||||
|
*
|
||||||
|
* @param lifespan the span for which the unit is effective
|
||||||
|
* @param address the starting address
|
||||||
|
* @param platform the platform for the type's {@link DataOrganization}
|
||||||
|
* @param dataType the data type for the unit
|
||||||
|
* @return the new data unit
|
||||||
|
* @throws CodeUnitInsertionException if there's a conflict
|
||||||
|
*/
|
||||||
|
TraceData create(Lifespan lifespan, Address address, TracePlatform platform, DataType dataType)
|
||||||
|
throws CodeUnitInsertionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a data unit on the given register
|
* Create a data unit on the given register
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If the register is memory mapped, this will delegate to the appropriate space. In those
|
* If the register is memory mapped, this will delegate to the appropriate space. In those
|
||||||
* cases, the assignment affects all threads.
|
* cases, the assignment affects all threads. The type is resolved to the host platform, even if
|
||||||
|
* it already exists in the trace by another platform.
|
||||||
*
|
*
|
||||||
* @param lifespan the span for which the unit is effective
|
* @param lifespan the span for which the unit is effective
|
||||||
* @param register the register to assign a data type
|
* @param register the register to assign a data type
|
||||||
|
@ -82,7 +126,8 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceDat
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If the register is memory mapped, this will delegate to the appropriate space. In those
|
* If the register is memory mapped, this will delegate to the appropriate space. In those
|
||||||
* cases, the assignment affects all threads.
|
* cases, the assignment affects all threads. The type is resolved to the given platform, even
|
||||||
|
* if it already exists in the trace by another platform.
|
||||||
*
|
*
|
||||||
* @param platform the platform whose language defines the register
|
* @param platform the platform whose language defines the register
|
||||||
* @param lifespan the span for which the unit is effective
|
* @param lifespan the span for which the unit is effective
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.model.program;
|
package ghidra.trace.model.program;
|
||||||
|
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
|
|
||||||
public interface TraceVariableSnapProgramView extends TraceProgramView {
|
public interface TraceVariableSnapProgramView extends TraceProgramView {
|
||||||
/**
|
/**
|
||||||
* Seek to a particular snap
|
* Seek to a particular snap
|
||||||
*
|
*
|
||||||
* @param snap
|
* @param snap the snap
|
||||||
*/
|
*/
|
||||||
void setSnap(long snap);
|
void setSnap(long snap);
|
||||||
|
|
||||||
|
@ -29,4 +31,11 @@ public interface TraceVariableSnapProgramView extends TraceProgramView {
|
||||||
default void seekLatest() {
|
default void seekLatest() {
|
||||||
setSnap(getMaxSnap());
|
setSnap(getMaxSnap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current platform, so that actions have context
|
||||||
|
*
|
||||||
|
* @param platform the platform
|
||||||
|
*/
|
||||||
|
void setPlatform(TracePlatform platform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -549,6 +549,23 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
return code.definedData().create(Lifespan.nowOn(snap), start, type, length);
|
return code.definedData().create(Lifespan.nowOn(snap), start, type, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a data unit
|
||||||
|
*
|
||||||
|
* @param snap the starting snap
|
||||||
|
* @param start the min address
|
||||||
|
* @param platform the platform for data organization
|
||||||
|
* @param type the data type of the unit
|
||||||
|
* @param length the length, or -1 for the type's default
|
||||||
|
* @return the new data unit
|
||||||
|
* @throws CodeUnitInsertionException if the unit cannot be created
|
||||||
|
*/
|
||||||
|
public DBTraceDataAdapter addData(long snap, Address start, TracePlatform platform,
|
||||||
|
DataType type, int length) throws CodeUnitInsertionException {
|
||||||
|
DBTraceCodeManager code = trace.getCodeManager();
|
||||||
|
return code.definedData().create(Lifespan.nowOn(snap), start, platform, type, length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a data unit, first placing the given bytes
|
* Create a data unit, first placing the given bytes
|
||||||
*
|
*
|
||||||
|
@ -569,6 +586,27 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a data unit, first placing the given bytes
|
||||||
|
*
|
||||||
|
* @param snap the starting snap
|
||||||
|
* @param start the min address
|
||||||
|
* @param platform the platform for data organization
|
||||||
|
* @param type the data type of the unit
|
||||||
|
* @param buf the bytes to place, which will become the unit's bytes
|
||||||
|
* @return the new data unit
|
||||||
|
* @throws CodeUnitInsertionException if the unit cannot be created
|
||||||
|
*/
|
||||||
|
public DBTraceDataAdapter addData(long snap, Address start, TracePlatform platform,
|
||||||
|
DataType type, ByteBuffer buf) throws CodeUnitInsertionException {
|
||||||
|
int length = buf.remaining();
|
||||||
|
DBTraceMemoryManager memory = trace.getMemoryManager();
|
||||||
|
memory.putBytes(snap, start, buf);
|
||||||
|
DBTraceDataAdapter data = addData(snap, start, platform, type, length);
|
||||||
|
assertEquals(length, data.getLength());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instruction unit by disassembling existing bytes
|
* Create an instruction unit by disassembling existing bytes
|
||||||
*
|
*
|
||||||
|
@ -838,6 +876,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
* Get an object by its path pattern intersecting the given lifespan
|
* Get an object by its path pattern intersecting the given lifespan
|
||||||
*
|
*
|
||||||
* @param path the path pattern
|
* @param path the path pattern
|
||||||
|
* @param span the lifespan to search
|
||||||
* @return the object or null
|
* @return the object or null
|
||||||
*/
|
*/
|
||||||
public TraceObject objAny(String path, Lifespan span) {
|
public TraceObject objAny(String path, Lifespan span) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio
|
||||||
.getLanguage(
|
.getLanguage(
|
||||||
new LanguageID("Toy:BE:64:default"));
|
new LanguageID("Toy:BE:64:default"));
|
||||||
trace = new DBTrace("Testing", toyLanguage.getDefaultCompilerSpec(), this);
|
trace = new DBTrace("Testing", toyLanguage.getDefaultCompilerSpec(), this);
|
||||||
dtm = trace.getDataTypeManager();
|
dtm = trace.getBaseDataTypeManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -1830,7 +1830,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
@Test
|
@Test
|
||||||
public void testAddGuestInstructionThenRemoveAndDelete() throws AddressOverflowException,
|
public void testAddGuestInstructionThenRemoveAndDelete() throws AddressOverflowException,
|
||||||
CodeUnitInsertionException, IOException, CancelledException {
|
CodeUnitInsertionException, IOException, CancelledException {
|
||||||
DBTracePlatformManager langMan = b.trace.getPlatformManager();
|
DBTracePlatformManager platMan = b.trace.getPlatformManager();
|
||||||
Language x86 = getSLEIGH_X86_LANGUAGE();
|
Language x86 = getSLEIGH_X86_LANGUAGE();
|
||||||
DBTraceGuestPlatform guest;
|
DBTraceGuestPlatform guest;
|
||||||
DBTraceGuestPlatformMappedRange mappedRange;
|
DBTraceGuestPlatformMappedRange mappedRange;
|
||||||
|
@ -1839,7 +1839,7 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
TraceInstruction i4001;
|
TraceInstruction i4001;
|
||||||
TraceData d4003;
|
TraceData d4003;
|
||||||
try (Transaction tx = b.startTransaction()) {
|
try (Transaction tx = b.startTransaction()) {
|
||||||
guest = langMan.addGuestPlatform(x86.getDefaultCompilerSpec());
|
guest = platMan.addGuestPlatform(x86.getDefaultCompilerSpec());
|
||||||
mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
|
mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
|
||||||
g4000 = b.addInstruction(0, b.addr(0x4000), guest, b.buf(0x90));
|
g4000 = b.addInstruction(0, b.addr(0x4000), guest, b.buf(0x90));
|
||||||
i4001 = b.addInstruction(0, b.addr(0x4001), b.host, b.buf(0xf4, 0));
|
i4001 = b.addInstruction(0, b.addr(0x4001), b.host, b.buf(0xf4, 0));
|
||||||
|
@ -1857,7 +1857,6 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
b.trace.undo();
|
b.trace.undo();
|
||||||
|
|
||||||
// NB. The range deletion also deletes the guest unit, so it'll have a new identity
|
// NB. The range deletion also deletes the guest unit, so it'll have a new identity
|
||||||
// TODO: Related to GP-479?
|
|
||||||
g4000 = manager.instructions().getAt(0, b.addr(0x4000));
|
g4000 = manager.instructions().getAt(0, b.addr(0x4000));
|
||||||
assertNotNull(g4000);
|
assertNotNull(g4000);
|
||||||
assertEquals(guest, g4000.getPlatform());
|
assertEquals(guest, g4000.getPlatform());
|
||||||
|
@ -1865,13 +1864,66 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
guest.delete(new ConsoleTaskMonitor());
|
guest.delete(new ConsoleTaskMonitor());
|
||||||
}
|
}
|
||||||
assertUndefinedWithAddr(b.addr(0x4000), manager.codeUnits().getAt(0, b.addr(0x4000)));
|
assertUndefinedWithAddr(b.addr(0x4000), manager.codeUnits().getAt(0, b.addr(0x4000)));
|
||||||
// TODO: Definitely part of GP-479. These should be able to keep their identities.
|
assertEquals(i4001, manager.codeUnits().getAt(0, b.addr(0x4001)));
|
||||||
//assertEquals(i4001, manager.codeUnits().getAt(0, b.addr(0x4001)));
|
assertEquals(d4003, manager.codeUnits().getAt(0, b.addr(0x4003)));
|
||||||
//assertEquals(d4003, manager.codeUnits().getAt(0, b.addr(0x4003)));
|
|
||||||
assertNotNull(manager.instructions().getAt(0, b.addr(0x4001)));
|
assertNotNull(manager.instructions().getAt(0, b.addr(0x4001)));
|
||||||
assertNotNull(manager.definedData().getAt(0, b.addr(0x4003)));
|
assertNotNull(manager.definedData().getAt(0, b.addr(0x4003)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddGuestDataThenRemoveAndDelete() throws Exception {
|
||||||
|
DBTracePlatformManager platMan = b.trace.getPlatformManager();
|
||||||
|
Language x86 = getSLEIGH_X86_LANGUAGE();
|
||||||
|
DBTraceGuestPlatform guest;
|
||||||
|
DBTraceGuestPlatformMappedRange mappedRange;
|
||||||
|
|
||||||
|
TraceData hd4000;
|
||||||
|
TraceData gd4008;
|
||||||
|
TraceData gd400c;
|
||||||
|
try (Transaction tx = b.startTransaction()) {
|
||||||
|
guest = platMan.addGuestPlatform(x86.getDefaultCompilerSpec());
|
||||||
|
mappedRange = guest.addMappedRange(b.addr(0x0000), b.addr(guest, 0x0000), 1L << 32);
|
||||||
|
hd4000 = b.addData(0, b.addr(0x4000), PointerDataType.dataType,
|
||||||
|
b.buf(0, 0, 0, 0, 0, 0, 0x40, 0x80));
|
||||||
|
gd4008 = b.addData(0, b.addr(0x4008), guest, PointerDataType.dataType,
|
||||||
|
b.buf(0x81, 0x40, 0, 0));
|
||||||
|
gd400c = b.addData(0, b.addr(0x400c), gd4008.getDataType(), b.buf(0x82, 0x40, 0, 0));
|
||||||
|
}
|
||||||
|
assertEquals(b.host, hd4000.getPlatform());
|
||||||
|
assertEquals(8, hd4000.getLength());
|
||||||
|
assertEquals(guest, gd4008.getPlatform());
|
||||||
|
assertEquals(4, gd4008.getLength());
|
||||||
|
assertEquals(guest, gd400c.getPlatform());
|
||||||
|
assertEquals(4, gd400c.getLength());
|
||||||
|
|
||||||
|
assertEquals(gd4008, manager.codeUnits().getAt(0, b.addr(0x4008)));
|
||||||
|
assertEquals(gd400c, manager.codeUnits().getAt(0, b.addr(0x400c)));
|
||||||
|
|
||||||
|
try (Transaction tx = b.startTransaction()) {
|
||||||
|
mappedRange.delete(new ConsoleTaskMonitor());
|
||||||
|
}
|
||||||
|
assertEquals(hd4000, manager.codeUnits().getAt(0, b.addr(0x4000)));
|
||||||
|
assertUndefinedWithAddr(b.addr(0x4008), manager.codeUnits().getAt(0, b.addr(0x4008)));
|
||||||
|
assertUndefinedWithAddr(b.addr(0x400c), manager.codeUnits().getAt(0, b.addr(0x400c)));
|
||||||
|
|
||||||
|
b.trace.undo();
|
||||||
|
|
||||||
|
// NB. The range deletion also deletes the guest units, so they'll have new identities
|
||||||
|
gd4008 = manager.definedData().getAt(0, b.addr(0x4008));
|
||||||
|
gd400c = manager.definedData().getAt(0, b.addr(0x400c));
|
||||||
|
assertNotNull(gd4008);
|
||||||
|
assertNotNull(gd400c);
|
||||||
|
assertEquals(guest, gd4008.getPlatform());
|
||||||
|
assertEquals(guest, gd400c.getPlatform());
|
||||||
|
try (Transaction tx = b.startTransaction()) {
|
||||||
|
guest.delete(new ConsoleTaskMonitor());
|
||||||
|
}
|
||||||
|
assertEquals(hd4000, manager.codeUnits().getAt(0, b.addr(0x4000)));
|
||||||
|
assertUndefinedWithAddr(b.addr(0x4008), manager.codeUnits().getAt(0, b.addr(0x4008)));
|
||||||
|
assertUndefinedWithAddr(b.addr(0x400c), manager.codeUnits().getAt(0, b.addr(0x400c)));
|
||||||
|
assertNotNull(manager.definedData().getAt(0, b.addr(0x4000)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSaveAndLoad() throws Exception {
|
public void testSaveAndLoad() throws Exception {
|
||||||
try (Transaction tx = b.startTransaction()) {
|
try (Transaction tx = b.startTransaction()) {
|
||||||
|
|
|
@ -17,7 +17,6 @@ package generic.depends;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import generic.depends.err.*;
|
import generic.depends.err.*;
|
||||||
|
|
||||||
|
@ -137,6 +136,7 @@ public class DependentServiceResolver<T> {
|
||||||
public void injectServices(T obj) throws ServiceConstructionException {
|
public void injectServices(T obj) throws ServiceConstructionException {
|
||||||
Map<Class<?>, Object> instancesByClass = new HashMap<>();
|
Map<Class<?>, Object> instancesByClass = new HashMap<>();
|
||||||
Map<Method, Object> constructed = new HashMap<>();
|
Map<Method, Object> constructed = new HashMap<>();
|
||||||
|
Map<Class<?>, Set<Field>> fieldsByClass = new HashMap<>(this.fieldsByClass);
|
||||||
for (DependentServiceConstructor<?> cons : ordered) {
|
for (DependentServiceConstructor<?> cons : ordered) {
|
||||||
Object service = constructed.get(cons.method);
|
Object service = constructed.get(cons.method);
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
|
@ -144,16 +144,18 @@ public class DependentServiceResolver<T> {
|
||||||
constructed.put(cons.method, service);
|
constructed.put(cons.method, service);
|
||||||
}
|
}
|
||||||
instancesByClass.put(cons.cls, service);
|
instancesByClass.put(cons.cls, service);
|
||||||
}
|
for (Field f : fieldsByClass.remove(cons.cls)) {
|
||||||
for (Entry<Class<?>, Set<Field>> entry : fieldsByClass.entrySet()) {
|
|
||||||
for (Field f : entry.getValue()) {
|
|
||||||
try {
|
try {
|
||||||
f.set(obj, instancesByClass.get(entry.getKey()));
|
f.set(obj, service);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | IllegalAccessException e) {
|
catch (IllegalArgumentException | IllegalAccessException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!fieldsByClass.isEmpty()) {
|
||||||
|
throw new ServiceConstructionException(
|
||||||
|
"No service constructor for " + fieldsByClass.keySet(), null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue