mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch
'origin/GP-5678_Dan_fixWow64AutoReads--SQUASHED' into Ghidra_11.4 (Closes #8155)
This commit is contained in:
commit
284980b60b
20 changed files with 482 additions and 456 deletions
|
@ -16,6 +16,7 @@
|
|||
package ghidra.app.services;
|
||||
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.listing.MultiBlendedListingBackgroundColorModel;
|
||||
import ghidra.framework.plugintool.ServiceInfo;
|
||||
|
@ -50,12 +51,19 @@ public interface DebuggerListingService extends CodeViewerService {
|
|||
void setTrackingSpec(LocationTrackingSpec spec);
|
||||
|
||||
/**
|
||||
* Get the tracking specification of the listing.
|
||||
* Get the tracking specification of the main listing.
|
||||
*
|
||||
* @return the current specification
|
||||
*/
|
||||
LocationTrackingSpec getTrackingSpec();
|
||||
|
||||
/**
|
||||
* Get the auto-read memory specification of the main listing.
|
||||
*
|
||||
* @return the current specification
|
||||
*/
|
||||
AutoReadMemorySpec getAutoReadMemorySpec();
|
||||
|
||||
/**
|
||||
* Add a listener for changes to the tracking specification.
|
||||
*
|
||||
|
|
|
@ -13,58 +13,33 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
package ghidra.debug.api.action;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.control.TargetActionTask;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.debug.api.action.InstanceUtils;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* An interface for specifying how to automatically read target memory.
|
||||
*/
|
||||
public interface AutoReadMemorySpec extends ExtensionPoint {
|
||||
class Private {
|
||||
private final Map<String, AutoReadMemorySpec> specsByName = new TreeMap<>();
|
||||
private final ChangeListener classListener = this::classesChanged;
|
||||
|
||||
private Private() {
|
||||
ClassSearcher.addChangeListener(classListener);
|
||||
classesChanged(null);
|
||||
}
|
||||
|
||||
private synchronized void classesChanged(ChangeEvent evt) {
|
||||
InstanceUtils.collectUniqueInstances(AutoReadMemorySpec.class, specsByName,
|
||||
AutoReadMemorySpec::getConfigName);
|
||||
}
|
||||
}
|
||||
|
||||
Private PRIVATE = new Private();
|
||||
public interface AutoReadMemorySpec {
|
||||
|
||||
/**
|
||||
* Codec for saving/restoring the auto-read specification
|
||||
*/
|
||||
public static class AutoReadMemorySpecConfigFieldCodec
|
||||
implements ConfigFieldCodec<AutoReadMemorySpec> {
|
||||
@Override
|
||||
public AutoReadMemorySpec read(SaveState state, String name,
|
||||
AutoReadMemorySpec current) {
|
||||
String specName = state.getString(name, null);
|
||||
return fromConfigName(specName);
|
||||
return AutoReadMemorySpecFactory.fromConfigName(specName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,31 +48,43 @@ public interface AutoReadMemorySpec extends ExtensionPoint {
|
|||
}
|
||||
}
|
||||
|
||||
static AutoReadMemorySpec fromConfigName(String name) {
|
||||
synchronized (PRIVATE) {
|
||||
return PRIVATE.specsByName.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, AutoReadMemorySpec> allSpecs() {
|
||||
synchronized (PRIVATE) {
|
||||
return new TreeMap<>(PRIVATE.specsByName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration name
|
||||
*
|
||||
* <p>
|
||||
* This is the value stored in configuration files to identify this specification
|
||||
*
|
||||
* @return the configuration name
|
||||
*/
|
||||
String getConfigName();
|
||||
|
||||
/**
|
||||
* A human-readable name for this specification
|
||||
*
|
||||
* <p>
|
||||
* This is the text displayed in menus
|
||||
*
|
||||
* @return the menu name, or null to omit from menus
|
||||
*/
|
||||
String getMenuName();
|
||||
|
||||
/**
|
||||
* Get the icon for this specification
|
||||
*
|
||||
* @return the icon
|
||||
*/
|
||||
Icon getMenuIcon();
|
||||
|
||||
default AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace != null && ProgramEmulationUtils.isEmulatedProgram(trace)) {
|
||||
return LoadEmulatorAutoReadMemorySpec.INSTANCE;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Get the "effective" specification.
|
||||
* <p>
|
||||
* This allows a specification to defer to some other (possibly hidden) specification, depending
|
||||
* on the coordinates.
|
||||
*
|
||||
* @param coordinates the current coordinates
|
||||
* @return the specification
|
||||
*/
|
||||
AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates);
|
||||
|
||||
/**
|
||||
* Perform the automatic read, if applicable
|
||||
|
@ -120,18 +107,4 @@ public interface AutoReadMemorySpec extends ExtensionPoint {
|
|||
*/
|
||||
CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible);
|
||||
|
||||
/**
|
||||
* A convenience for performing target memory reads with progress displayed
|
||||
*
|
||||
* @param tool the tool for displaying progress
|
||||
* @param reader the method to perform the read, asynchronously
|
||||
* @return a future which returns true if the read completes
|
||||
*/
|
||||
default CompletableFuture<Boolean> doRead(PluginTool tool,
|
||||
Function<TaskMonitor, CompletableFuture<Void>> reader) {
|
||||
return TargetActionTask
|
||||
.executeTask(tool, getMenuName(), true, true, false, m -> reader.apply(m))
|
||||
.thenApply(__ -> true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.debug.api.action;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
|
||||
/**
|
||||
* A discoverable factory of auto-read memory specifications
|
||||
*/
|
||||
public interface AutoReadMemorySpecFactory extends ExtensionPoint {
|
||||
|
||||
/**
|
||||
* Get the specification for the given configuration name
|
||||
*
|
||||
* @param name the name
|
||||
* @return the spec, or null
|
||||
*/
|
||||
static AutoReadMemorySpec fromConfigName(String name) {
|
||||
for (AutoReadMemorySpecFactory factory : ClassSearcher
|
||||
.getInstances(AutoReadMemorySpecFactory.class)) {
|
||||
AutoReadMemorySpec spec = factory.parseSpec(name);
|
||||
if (spec != null) {
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of all the known and visible specifications
|
||||
*
|
||||
* @param tool the plugin tool or context
|
||||
* @return the specifications by configuration name
|
||||
*/
|
||||
static Map<String, AutoReadMemorySpec> allSuggested(PluginTool tool) {
|
||||
Map<String, AutoReadMemorySpec> all = new TreeMap<>();
|
||||
for (AutoReadMemorySpecFactory factory : ClassSearcher
|
||||
.getInstances(AutoReadMemorySpecFactory.class)) {
|
||||
for (AutoReadMemorySpec spec : factory.getSuggested(tool)) {
|
||||
if (spec.getMenuName() != null) {
|
||||
all.put(spec.getConfigName(), spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the specifications currently suggested by this factory
|
||||
*
|
||||
* @param tool the plugin tool or context
|
||||
* @return the list of suggested specifications
|
||||
*/
|
||||
List<AutoReadMemorySpec> getSuggested(PluginTool tool);
|
||||
|
||||
/**
|
||||
* Attempt to parse the given configuration name as a specification
|
||||
*
|
||||
* @param name the configuration name, usually including a prefix unique to each factory
|
||||
* @return the specification, or null if this factory cannot parse it
|
||||
*/
|
||||
AutoReadMemorySpec parseSpec(String name);
|
||||
}
|
|
@ -46,6 +46,7 @@ public interface LocationTrackingSpecFactory extends ExtensionPoint {
|
|||
/**
|
||||
* Get a copy of all the known specifications
|
||||
*
|
||||
* @param tool the plugin tool or context
|
||||
* @return the specifications by configuration name
|
||||
*/
|
||||
static Map<String, LocationTrackingSpec> allSuggested(PluginTool tool) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
AutoMapSpec
|
||||
AutoReadMemorySpec
|
||||
DebuggerBot
|
||||
AutoReadMemorySpecFactory
|
||||
DebuggerMappingOpinion
|
||||
DebuggerModelFactory
|
||||
DebuggerPcodeEmulatorFactory
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.control.TargetActionTask;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.app.plugin.core.debug.utils.AbstractMappedMemoryBytesVisitor;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public enum BasicAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
/**
|
||||
* Never automatically read memory
|
||||
*/
|
||||
NONE("0_READ_NONE", AutoReadMemoryAction.NAME_NONE, AutoReadMemoryAction.ICON_NONE) {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates, AddressSetView visible) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Automatically read all visible memory
|
||||
*/
|
||||
VISIBLE("1_READ_VISIBLE", AutoReadMemoryAction.NAME_VISIBLE, AutoReadMemoryAction.ICON_VISIBLE) {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Target target = coordinates.getTarget();
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown = mm.getAddressesWithState(coordinates.getSnap(), visible,
|
||||
s -> s == TraceMemoryState.KNOWN || s == TraceMemoryState.ERROR);
|
||||
AddressSet toRead = visible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
return doRead(tool, monitor -> target.readMemoryAsync(toRead, monitor));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Automatically read all visible memory, unless it is read-only, in which case, only read it if
|
||||
* it has not already been read.
|
||||
*/
|
||||
VIS_RO_ONCE("2_READ_VIS_RO_ONCE", AutoReadMemoryAction.NAME_VIS_RO_ONCE, AutoReadMemoryAction.ICON_VIS_RO_ONCE) {
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Target target = coordinates.getTarget();
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
long snap = coordinates.getSnap();
|
||||
AddressSetView alreadyKnown = mm.getAddressesWithState(snap, visible,
|
||||
s -> s == TraceMemoryState.KNOWN || s == TraceMemoryState.ERROR);
|
||||
AddressSet toRead = visible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
AddressSet everKnown = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : mm.getMostRecentStates(
|
||||
snap,
|
||||
range)) {
|
||||
everKnown.add(ent.getKey().getRange());
|
||||
}
|
||||
}
|
||||
AddressSet readOnly = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (TraceMemoryRegion region : mm.getRegionsIntersecting(Lifespan.at(snap),
|
||||
range)) {
|
||||
if (region.isWrite(snap)) {
|
||||
continue;
|
||||
}
|
||||
readOnly.add(region.getRange(snap));
|
||||
}
|
||||
}
|
||||
toRead.delete(everKnown.intersect(readOnly));
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
return doRead(tool, monitor -> target.readMemoryAsync(toRead, monitor));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Load memory from programs for "pure" emulation traces.
|
||||
*/
|
||||
LOAD_EMULATOR(null, null, null) {
|
||||
protected AddressSetView quantize(int blockBits, AddressSetView set) {
|
||||
if (blockBits == 1) {
|
||||
return set;
|
||||
}
|
||||
long blockMask = -1L << blockBits;
|
||||
AddressSet result = new AddressSet();
|
||||
// Not terribly efficient, but this is one range most of the time
|
||||
for (AddressRange range : set) {
|
||||
AddressSpace space = range.getAddressSpace();
|
||||
Address min = space.getAddress(range.getMinAddress().getOffset() & blockMask);
|
||||
Address max = space.getAddress(range.getMaxAddress().getOffset() | ~blockMask);
|
||||
result.add(new AddressRangeImpl(min, max));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool,
|
||||
DebuggerCoordinates coordinates, AddressSetView visible) {
|
||||
DebuggerStaticMappingService mappingService =
|
||||
tool.getService(DebuggerStaticMappingService.class);
|
||||
if (mappingService == null) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null || coordinates.isAlive() ||
|
||||
!ProgramEmulationUtils.isEmulatedProgram(trace)) {
|
||||
// Never interfere with a live target
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
TraceMemoryManager mm = trace.getMemoryManager();
|
||||
AddressSet toRead = new AddressSet(quantize(12, visible));
|
||||
for (Lifespan span : coordinates.getView().getViewport().getOrderedSpans()) {
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(span.lmin(), visible,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
toRead.delete(alreadyKnown);
|
||||
if (span.lmax() != span.lmin() || toRead.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
long snap = coordinates.getSnap();
|
||||
ByteBuffer buf = ByteBuffer.allocate(4096);
|
||||
try (Transaction tx = trace.openTransaction("Load Visible")) {
|
||||
new AbstractMappedMemoryBytesVisitor(mappingService, buf.array()) {
|
||||
@Override
|
||||
protected void visitData(Address hostAddr, byte[] data, int size) {
|
||||
buf.position(0);
|
||||
buf.limit(size);
|
||||
mm.putBytes(snap, hostAddr, buf);
|
||||
}
|
||||
}.visit(trace, snap, toRead);
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final String configName;
|
||||
private final String menuName;
|
||||
private final Icon menuIcon;
|
||||
|
||||
private BasicAutoReadMemorySpec(String configName, String menuName, Icon menuIcon) {
|
||||
this.configName = configName;
|
||||
this.menuName = menuName;
|
||||
this.menuIcon = menuIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return menuName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return menuIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace != null && ProgramEmulationUtils.isEmulatedProgram(trace)) {
|
||||
return LOAD_EMULATOR;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience for performing target memory reads with progress displayed
|
||||
*
|
||||
* @param tool the tool for displaying progress
|
||||
* @param reader the method to perform the read, asynchronously
|
||||
* @return a future which returns true if the read completes
|
||||
*/
|
||||
protected CompletableFuture<Boolean> doRead(PluginTool tool,
|
||||
Function<TaskMonitor, CompletableFuture<Void>> reader) {
|
||||
return TargetActionTask
|
||||
.executeTask(tool, getMenuName(), true, true, false, m -> reader.apply(m))
|
||||
.thenApply(__ -> true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpecFactory;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
||||
public class BasicAutoReadMemorySpecFactory implements AutoReadMemorySpecFactory {
|
||||
public static final List<AutoReadMemorySpec> ALL = List.of(BasicAutoReadMemorySpec.values());
|
||||
public static final Map<String, AutoReadMemorySpec> BY_CONFIG_NAME = ALL.stream()
|
||||
.filter(s -> s.getConfigName() != null)
|
||||
.collect(Collectors.toUnmodifiableMap(
|
||||
AutoReadMemorySpec::getConfigName,
|
||||
Function.identity()));
|
||||
|
||||
@Override
|
||||
public List<AutoReadMemorySpec> getSuggested(PluginTool tool) {
|
||||
return ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoReadMemorySpec parseSpec(String name) {
|
||||
return BY_CONFIG_NAME.get(name);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.debug.gui.action;
|
|||
|
||||
import docking.action.builder.MultiStateActionBuilder;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpecFactory;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
public interface DebuggerAutoReadMemoryAction extends AutoReadMemoryAction {
|
||||
|
@ -24,7 +26,8 @@ public interface DebuggerAutoReadMemoryAction extends AutoReadMemoryAction {
|
|||
static MultiStateActionBuilder<AutoReadMemorySpec> builder(Plugin owner) {
|
||||
MultiStateActionBuilder<AutoReadMemorySpec> builder = AutoReadMemoryAction.builder(owner);
|
||||
builder.toolBarGroup(NAME);
|
||||
for (AutoReadMemorySpec spec : AutoReadMemorySpec.allSpecs().values()) {
|
||||
for (AutoReadMemorySpec spec : AutoReadMemorySpecFactory.allSuggested(owner.getTool())
|
||||
.values()) {
|
||||
builder.addState(spec.getMenuName(), spec.getMenuIcon(), spec);
|
||||
}
|
||||
return builder;
|
||||
|
|
|
@ -29,9 +29,10 @@ import docking.menu.MultiStateDockingAction;
|
|||
import docking.widgets.EventTrigger;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRefreshSelectedMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.gui.control.TargetActionTask;
|
||||
import ghidra.app.util.viewer.listingpanel.AddressSetDisplayListener;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||
|
@ -149,8 +150,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
|||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoRead;
|
||||
protected RefreshSelectedMemoryAction actionRefreshSelected;
|
||||
|
||||
private final AutoReadMemorySpec defaultAutoSpec =
|
||||
AutoReadMemorySpec.fromConfigName(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
private final AutoReadMemorySpec defaultAutoSpec = BasicAutoReadMemorySpec.VIS_RO_ONCE;
|
||||
|
||||
@AutoConfigStateField(codec = AutoReadMemorySpecConfigFieldCodec.class)
|
||||
protected AutoReadMemorySpec autoSpec = defaultAutoSpec;
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import db.Transaction;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils;
|
||||
import ghidra.app.plugin.core.debug.utils.AbstractMappedMemoryBytesVisitor;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.TraceMemoryManager;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
|
||||
enum LoadEmulatorAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected AddressSetView quantize(int blockBits, AddressSetView set) {
|
||||
if (blockBits == 1) {
|
||||
return set;
|
||||
}
|
||||
long blockMask = -1L << blockBits;
|
||||
AddressSet result = new AddressSet();
|
||||
// Not terribly efficient, but this is one range most of the time
|
||||
for (AddressRange range : set) {
|
||||
AddressSpace space = range.getAddressSpace();
|
||||
Address min = space.getAddress(range.getMinAddress().getOffset() & blockMask);
|
||||
Address max = space.getAddress(range.getMaxAddress().getOffset() | ~blockMask);
|
||||
result.add(new AddressRangeImpl(min, max));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
DebuggerStaticMappingService mappingService =
|
||||
tool.getService(DebuggerStaticMappingService.class);
|
||||
if (mappingService == null) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null || coordinates.isAlive() ||
|
||||
!ProgramEmulationUtils.isEmulatedProgram(trace)) {
|
||||
// Never interfere with a live target
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
TraceMemoryManager mm = trace.getMemoryManager();
|
||||
AddressSet toRead = new AddressSet(quantize(12, visible));
|
||||
for (Lifespan span : coordinates.getView().getViewport().getOrderedSpans()) {
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(span.lmin(), visible, s -> s == TraceMemoryState.KNOWN);
|
||||
toRead.delete(alreadyKnown);
|
||||
if (span.lmax() != span.lmin() || toRead.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
long snap = coordinates.getSnap();
|
||||
ByteBuffer buf = ByteBuffer.allocate(4096);
|
||||
try (Transaction tx = trace.openTransaction("Load Visible")) {
|
||||
new AbstractMappedMemoryBytesVisitor(mappingService, buf.array()) {
|
||||
@Override
|
||||
protected void visitData(Address hostAddr, byte[] data, int size) {
|
||||
buf.position(0);
|
||||
buf.limit(size);
|
||||
mm.putBytes(snap, hostAddr, buf);
|
||||
}
|
||||
}.visit(trace, snap, toRead);
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
|
||||
public class NoneAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "0_READ_NONE";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this.getClass() == obj.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return AutoReadMemoryAction.NAME_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return AutoReadMemoryAction.ICON_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoReadMemorySpec getEffective(DebuggerCoordinates coordinates) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.trace.model.memory.TraceMemoryManager;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
|
||||
public class VisibleAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "1_READ_VISIBLE";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this.getClass() == obj.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return AutoReadMemoryAction.NAME_VISIBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return AutoReadMemoryAction.ICON_VISIBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Target target = coordinates.getTarget();
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown = mm.getAddressesWithState(coordinates.getSnap(), visible,
|
||||
s -> s == TraceMemoryState.KNOWN || s == TraceMemoryState.ERROR);
|
||||
AddressSet toRead = visible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
return doRead(tool, monitor -> target.readMemoryAsync(toRead, monitor));
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.*;
|
||||
|
||||
public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "1_READ_VIS_RO_ONCE";
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this.getClass() == obj.getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return AutoReadMemoryAction.NAME_VIS_RO_ONCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return AutoReadMemoryAction.ICON_VIS_RO_ONCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
Target target = coordinates.getTarget();
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
long snap = coordinates.getSnap();
|
||||
AddressSetView alreadyKnown = mm.getAddressesWithState(snap, visible,
|
||||
s -> s == TraceMemoryState.KNOWN || s == TraceMemoryState.ERROR);
|
||||
AddressSet toRead = visible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
AddressSet everKnown = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : mm.getMostRecentStates(snap,
|
||||
range)) {
|
||||
everKnown.add(ent.getKey().getRange());
|
||||
}
|
||||
}
|
||||
AddressSet readOnly = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (TraceMemoryRegion region : mm.getRegionsIntersecting(Lifespan.at(snap), range)) {
|
||||
if (region.isWrite(snap)) {
|
||||
continue;
|
||||
}
|
||||
readOnly.add(region.getRange(snap));
|
||||
}
|
||||
}
|
||||
toRead.delete(everKnown.intersect(readOnly));
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
|
||||
return doRead(tool, monitor -> target.readMemoryAsync(toRead, monitor));
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.listing;
|
||||
|
||||
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.GROUP_TRANSIENT_VIEWS;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -32,11 +32,11 @@ import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
|||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.event.*;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractNewListingAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.DebuggerProgramLocationActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.action.NoneLocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.listing.MultiBlendedListingBackgroundColorModel;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
|
@ -81,8 +81,7 @@ import ghidra.trace.model.program.TraceProgramView;
|
|||
},
|
||||
servicesProvided = {
|
||||
DebuggerListingService.class,
|
||||
}
|
||||
)
|
||||
})
|
||||
public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerListingProvider>
|
||||
implements DebuggerListingService {
|
||||
private static final String KEY_CONNECTED_PROVIDER = "connectedProvider";
|
||||
|
@ -332,6 +331,11 @@ public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerLis
|
|||
connectedProvider.removeTrackingSpecChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoReadMemorySpec getAutoReadMemorySpec() {
|
||||
return connectedProvider.getAutoReadMemorySpec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSelection(ProgramSelection selection) {
|
||||
connectedProvider.setSelection(selection);
|
||||
|
|
|
@ -66,8 +66,7 @@ import ghidra.app.util.viewer.format.FormatManager;
|
|||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.async.AsyncDebouncer;
|
||||
import ghidra.async.AsyncTimer;
|
||||
import ghidra.debug.api.action.GoToInput;
|
||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.action.*;
|
||||
import ghidra.debug.api.control.ControlMode;
|
||||
import ghidra.debug.api.listing.MultiBlendedListingBackgroundColorModel;
|
||||
import ghidra.debug.api.modules.DebuggerStaticMappingChangeListener;
|
||||
|
|
|
@ -43,12 +43,11 @@ import ghidra.app.plugin.core.debug.event.*;
|
|||
import ghidra.app.plugin.core.debug.gui.*;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.format.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
|
||||
import ghidra.debug.api.action.GoToInput;
|
||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.action.*;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.features.base.memsearch.bytesource.AddressableByteSource;
|
||||
import ghidra.features.base.memsearch.bytesource.EmptyByteSource;
|
||||
|
@ -216,8 +215,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
}
|
||||
}
|
||||
|
||||
private final AutoReadMemorySpec defaultReadMemorySpec =
|
||||
AutoReadMemorySpec.fromConfigName(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
private final AutoReadMemorySpec defaultReadMemorySpec = BasicAutoReadMemorySpec.VIS_RO_ONCE;
|
||||
|
||||
private final DebuggerMemoryBytesPlugin myPlugin;
|
||||
|
||||
|
|
|
@ -22,13 +22,15 @@ import java.util.concurrent.*;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.plugin.core.debug.disassemble.DisassemblyInject;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.action.PCLocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.mapping.*;
|
||||
import ghidra.app.services.DebuggerTargetService;
|
||||
import ghidra.app.services.*;
|
||||
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.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.platform.DebuggerPlatformMapper;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
|
@ -42,7 +44,6 @@ import ghidra.trace.model.guest.TracePlatform;
|
|||
import ghidra.trace.model.modules.TraceModule;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpinion {
|
||||
protected static final LanguageID LANG_ID_X86_64 = new LanguageID("x86:LE:64:default");
|
||||
|
@ -55,34 +56,54 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
|
|||
X64, X86, UNK;
|
||||
|
||||
static Mode computeFor(PluginTool tool, Trace trace, Address address, long snap) {
|
||||
DebuggerListingService listing = tool.getService(DebuggerListingService.class);
|
||||
AutoReadMemorySpec readSpec = listing.getAutoReadMemorySpec();
|
||||
|
||||
DebuggerTargetService targetService = tool.getService(DebuggerTargetService.class);
|
||||
Target target = targetService == null ? null : targetService.getTarget(trace);
|
||||
DebuggerCoordinates coords = DebuggerCoordinates.NOWHERE
|
||||
// force host platform, or else we'll recurse and blow the stack
|
||||
.platform(trace.getPlatformManager().getHostPlatform())
|
||||
.snap(snap)
|
||||
.target(target);
|
||||
|
||||
Collection<? extends TraceModule> modules =
|
||||
trace.getModuleManager().getModulesAt(snap, address);
|
||||
Msg.debug(Mode.class, "Disassembling in modules: " +
|
||||
Msg.debug(Mode.class, "Computing mode from modules: " +
|
||||
modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")));
|
||||
Set<Mode> modes = modules.stream()
|
||||
.map(m -> modeForModule(target, trace, snap, m))
|
||||
.map(m -> modeForModule(tool, readSpec, coords, m))
|
||||
.filter(m -> m != UNK)
|
||||
.collect(Collectors.toSet());
|
||||
Msg.debug(Mode.class, "Disassembling in mode(s): " + modes);
|
||||
Msg.debug(Mode.class, " Got 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();
|
||||
static Mode modeForModule(PluginTool tool, AutoReadMemorySpec readSpec,
|
||||
DebuggerCoordinates coords, TraceModule module) {
|
||||
AddressSet set = new AddressSet();
|
||||
Trace trace = coords.getTrace();
|
||||
long snap = coords.getSnap();
|
||||
Address base = module.getBase(snap);
|
||||
set.add(base, base); // Recorder should read page
|
||||
try {
|
||||
readSpec.readMemory(tool, coords, set).get(1, TimeUnit.SECONDS);
|
||||
trace.flushEvents();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
DebuggerConsoleService console = tool.getService(DebuggerConsoleService.class);
|
||||
String message = "Could not read PE header of %s to determine x86 vs x64 mode"
|
||||
.formatted(module.getName(snap));
|
||||
if (console != null) {
|
||||
console.log(DebuggerResources.ICON_LOG_ERROR, message, e);
|
||||
}
|
||||
catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
throw new AssertionError(e);
|
||||
else {
|
||||
Msg.error(Mode.class, message, e);
|
||||
}
|
||||
// Let it fall through in case stale memory is still accurate
|
||||
}
|
||||
MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap));
|
||||
try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) {
|
||||
|
@ -111,7 +132,7 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
|
|||
CompilerSpec cSpec) {
|
||||
super(tool, trace, cSpec);
|
||||
}
|
||||
// TODO: Map registers: efl,rfl,rflags->eflags
|
||||
// LATER: Map registers: efl,rfl,rflags->eflags
|
||||
|
||||
@Override
|
||||
protected TracePlatform getDisassemblyPlatform(TraceObject object, Address start,
|
||||
|
@ -165,7 +186,7 @@ public class DbgengDebuggerPlatformOpinion extends AbstractDebuggerPlatformOpini
|
|||
}
|
||||
|
||||
enum Offer implements DebuggerPlatformOffer {
|
||||
// TODO: X86?
|
||||
// LATER: X86, as in a 32-bit host? Not likely.
|
||||
X64 {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
|
|
|
@ -45,7 +45,7 @@ import docking.widgets.tree.GTree;
|
|||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.GhidraTestApplicationLayout;
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.action.BasicAutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
|
||||
import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueObjectPropertyColumn;
|
||||
import ghidra.app.plugin.core.debug.service.target.DebuggerTargetServicePlugin;
|
||||
|
@ -53,8 +53,7 @@ import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerService
|
|||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.async.AsyncTestUtils;
|
||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.action.LocationTrackingSpecFactory;
|
||||
import ghidra.debug.api.action.*;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
@ -600,15 +599,15 @@ public abstract class AbstractGhidraHeadedDebuggerTest
|
|||
}
|
||||
|
||||
protected static AutoReadMemorySpec getAutoReadMemorySpec(String name) {
|
||||
return AutoReadMemorySpec.fromConfigName(name);
|
||||
return AutoReadMemorySpecFactory.fromConfigName(name);
|
||||
}
|
||||
|
||||
protected final AutoReadMemorySpec readNone =
|
||||
getAutoReadMemorySpec(NoneAutoReadMemorySpec.CONFIG_NAME);
|
||||
getAutoReadMemorySpec(BasicAutoReadMemorySpec.NONE.getConfigName());
|
||||
protected final AutoReadMemorySpec readVisible =
|
||||
getAutoReadMemorySpec(VisibleAutoReadMemorySpec.CONFIG_NAME);
|
||||
getAutoReadMemorySpec(BasicAutoReadMemorySpec.VISIBLE.getConfigName());
|
||||
protected final AutoReadMemorySpec readVisROOnce =
|
||||
getAutoReadMemorySpec(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
getAutoReadMemorySpec(BasicAutoReadMemorySpec.VIS_RO_ONCE.getConfigName());
|
||||
|
||||
protected TestEnv env;
|
||||
protected PluginTool tool;
|
||||
|
|
|
@ -28,8 +28,7 @@ import docking.action.DockingActionIf;
|
|||
import generic.Unique;
|
||||
import generic.test.category.NightlyCategory;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.NoneAutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.BasicAutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.copying.DebuggerCopyIntoProgramDialog.RangeEntry;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
|
||||
|
@ -442,8 +441,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerI
|
|||
TraceObject process = tb.obj("Processes[1]");
|
||||
rmiCx.publishTarget(tool, tb.trace);
|
||||
|
||||
listingProvider.setAutoReadMemorySpec(
|
||||
AutoReadMemorySpec.fromConfigName(NoneAutoReadMemorySpec.CONFIG_NAME));
|
||||
listingProvider.setAutoReadMemorySpec(BasicAutoReadMemorySpec.NONE);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
assertDisabled(copyActionsPlugin.actionCopyIntoNewProgram);
|
||||
|
|
|
@ -50,6 +50,7 @@ import ghidra.app.services.DebuggerControlService;
|
|||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.async.SwingExecutorService;
|
||||
import ghidra.debug.api.action.AutoReadMemorySpec;
|
||||
import ghidra.debug.api.control.ControlMode;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.program.model.address.*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue