mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 16:40:08 +00:00
GP-848: Refactored LocationTrackingSpec and AutoReadMemorySpec to be ExtensionPoints
This commit is contained in:
parent
ee2f01b53a
commit
3b058380a3
@ -1,5 +1,6 @@
|
||||
AutoReadMemorySpec
|
||||
DebuggerBot
|
||||
DebuggerMappingOpinion
|
||||
DebuggerModelFactory
|
||||
DisassemblyInject
|
||||
|
||||
LocationTrackingSpec
|
||||
|
@ -0,0 +1,99 @@
|
||||
/* ###
|
||||
* 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;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private synchronized void classesChanged(ChangeEvent evt) {
|
||||
MiscellaneousUtils.collectUniqueInstances(AutoReadMemorySpec.class, specsByName,
|
||||
AutoReadMemorySpec::getConfigName);
|
||||
}
|
||||
}
|
||||
|
||||
Private PRIVATE = new Private();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SaveState state, String name, AutoReadMemorySpec value) {
|
||||
state.putString(name, value.getConfigName());
|
||||
}
|
||||
}
|
||||
|
||||
static AutoReadMemorySpec fromConfigName(String name) {
|
||||
synchronized (PRIVATE) {
|
||||
return PRIVATE.specsByName.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, AutoReadMemorySpec> allSpecs() {
|
||||
synchronized (PRIVATE) {
|
||||
return Map.copyOf(PRIVATE.specsByName);
|
||||
}
|
||||
}
|
||||
|
||||
String getConfigName();
|
||||
|
||||
String getMenuName();
|
||||
|
||||
Icon getMenuIcon();
|
||||
|
||||
/**
|
||||
* Perform the automatic read, if applicable
|
||||
*
|
||||
* <p>
|
||||
* Note, the implementation should perform all the error handling. The returned future is for
|
||||
* follow-up purposes only, and should always complete normally.
|
||||
*
|
||||
* @param tool the tool containing the provider
|
||||
* @param coordinates the provider's current coordinates
|
||||
* @param visible the provider's visible addresses
|
||||
* @return a future that completes when the memory has been read
|
||||
*/
|
||||
CompletableFuture<?> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* ###
|
||||
* 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 docking.action.builder.MultiStateActionBuilder;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
public interface DebuggerAutoReadMemoryAction extends AutoReadMemoryAction {
|
||||
// TODO: Update the action when new specs enter the class path?
|
||||
static MultiStateActionBuilder<AutoReadMemorySpec> builder(Plugin owner) {
|
||||
MultiStateActionBuilder<AutoReadMemorySpec> builder = AutoReadMemoryAction.builder(owner);
|
||||
builder.toolBarGroup(NAME);
|
||||
builder.performActionOnButtonClick(true);
|
||||
for (AutoReadMemorySpec spec : AutoReadMemorySpec.allSpecs().values()) {
|
||||
builder.addState(spec.getMenuName(), spec.getMenuIcon(), spec);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* ###
|
||||
* 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 docking.action.builder.MultiStateActionBuilder;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
|
||||
public interface DebuggerTrackLocationAction extends TrackLocationAction {
|
||||
// TODO: Update the action when new specs enter the class path?
|
||||
static MultiStateActionBuilder<LocationTrackingSpec> builder(Plugin owner) {
|
||||
MultiStateActionBuilder<LocationTrackingSpec> builder = TrackLocationAction.builder(owner);
|
||||
builder.toolBarGroup(owner.getName());
|
||||
builder.performActionOnButtonClick(true);
|
||||
for (LocationTrackingSpec spec : LocationTrackingSpec.allSpecs().values()) {
|
||||
builder.addState(spec.getMenuName(), spec.getMenuIcon(), spec);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/* ###
|
||||
* 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;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.classfinder.ExtensionPoint;
|
||||
|
||||
/**
|
||||
* A "specification" for automatic navigation of the dynamic listing
|
||||
*
|
||||
* <p>
|
||||
* TODO: Some of these should be configurable, and permit multiple instances, so that common
|
||||
* configurations can be saved. The most obvious use case would be a SLEIGH expression. A user may
|
||||
* want 3 different common expressions readily available in the drop-down list.
|
||||
*/
|
||||
public interface LocationTrackingSpec extends ExtensionPoint {
|
||||
class Private {
|
||||
private final Map<String, LocationTrackingSpec> specsByName = new TreeMap<>();
|
||||
private final ChangeListener classListener = this::classesChanged;
|
||||
|
||||
private Private() {
|
||||
ClassSearcher.addChangeListener(classListener);
|
||||
}
|
||||
|
||||
private synchronized void classesChanged(ChangeEvent evt) {
|
||||
MiscellaneousUtils.collectUniqueInstances(LocationTrackingSpec.class, specsByName,
|
||||
LocationTrackingSpec::getConfigName);
|
||||
}
|
||||
}
|
||||
|
||||
Private PRIVATE = new Private();
|
||||
|
||||
public static class TrackingSpecConfigFieldCodec
|
||||
implements ConfigFieldCodec<LocationTrackingSpec> {
|
||||
@Override
|
||||
public LocationTrackingSpec read(SaveState state, String name,
|
||||
LocationTrackingSpec current) {
|
||||
String specName = state.getString(name, null);
|
||||
return fromConfigName(specName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SaveState state, String name, LocationTrackingSpec value) {
|
||||
state.putString(name, value.getConfigName());
|
||||
}
|
||||
}
|
||||
|
||||
static boolean changeIsCurrent(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||
DebuggerCoordinates current) {
|
||||
if (space == null || space.getThread() != current.getThread()) {
|
||||
return false;
|
||||
}
|
||||
if (space.getFrameLevel() != current.getFrame()) {
|
||||
return false;
|
||||
}
|
||||
if (!range.getLifespan().contains(current.getSnap())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static LocationTrackingSpec fromConfigName(String name) {
|
||||
synchronized (PRIVATE) {
|
||||
return PRIVATE.specsByName.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, LocationTrackingSpec> allSpecs() {
|
||||
synchronized (PRIVATE) {
|
||||
return Map.copyOf(PRIVATE.specsByName);
|
||||
}
|
||||
}
|
||||
|
||||
String getConfigName();
|
||||
|
||||
String getMenuName();
|
||||
|
||||
Icon getMenuIcon();
|
||||
|
||||
/**
|
||||
* Compute a title prefix to indicate this tracking specification
|
||||
*
|
||||
* @param thread the provider's current thread
|
||||
* @return a prefix, or {@code null} to use a default
|
||||
*/
|
||||
String computeTitle(DebuggerCoordinates coordinates);
|
||||
|
||||
/**
|
||||
* Compute the trace address to "goto"
|
||||
*
|
||||
* <p>
|
||||
* If the coordinates indicate emulation, i.e., the schedule is non-empty, the trace manager
|
||||
* will already have performed the emulation and stored the results in a "scratch" snap. In
|
||||
* general, the location should be computed using that snap (@code emuSnap) rather than the one
|
||||
* indicated in {@code coordinates}.
|
||||
*
|
||||
* @param tool the tool containing the provider
|
||||
* @param coordinates the trace, thread, snap, etc., of the tool
|
||||
* @param emuSnap the "scratch" snap storing emulated state
|
||||
* @return the address to navigate to
|
||||
*/
|
||||
Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates, long emuSnap);
|
||||
|
||||
// TODO: Is there a way to generalize these so that other dependencies need not
|
||||
// have their own bespoke methods?
|
||||
|
||||
/**
|
||||
* Check if the address should be recomputed given the indicated register value change
|
||||
*
|
||||
* @param space the space (address space, thread, frame) where the change occurred
|
||||
* @param range the range (time and space) where the change occurred
|
||||
* @param coordinates the provider's current coordinates
|
||||
* @return true if re-computation and "goto" is warranted
|
||||
*/
|
||||
boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates);
|
||||
|
||||
/**
|
||||
* Check if the address should be recomputed given the indicated stack change
|
||||
*
|
||||
* @param stack the stack that changed (usually it's PC / return offset)
|
||||
* @param coordinates the provider's current coordinates
|
||||
* @return true if re-computation and "goto" is warranted
|
||||
*/
|
||||
boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/* ###
|
||||
* 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.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
|
||||
public class NoneAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "READ_NONE";
|
||||
|
||||
@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 CompletableFuture<Void> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/* ###
|
||||
* 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 javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
|
||||
public class NoneLocationTrackingSpec implements LocationTrackingSpec {
|
||||
public static final String CONFIG_NAME = "TRACK_NONE";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return TrackLocationAction.NAME_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return TrackLocationAction.ICON_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeTitle(DebuggerCoordinates coordinates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
long emuSnap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/* ###
|
||||
* 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 javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.stack.TraceStackFrame;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class PCLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||
public static final String CONFIG_NAME = "TRACK_PC";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return TrackLocationAction.NAME_PC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return TrackLocationAction.ICON_PC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
return trace.getBaseLanguage().getProgramCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
||||
return coordinates.getTrace().getBaseLanguage().getDefaultSpace();
|
||||
}
|
||||
|
||||
public Address computePCViaStack(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
TraceThread thread = coordinates.getThread();
|
||||
long snap = coordinates.getSnap();
|
||||
TraceStack stack = trace.getStackManager().getLatestStack(thread, snap);
|
||||
if (stack == null) {
|
||||
return null;
|
||||
}
|
||||
int level = coordinates.getFrame();
|
||||
TraceStackFrame frame = stack.getFrame(level, false);
|
||||
if (frame == null) {
|
||||
return null;
|
||||
}
|
||||
return frame.getProgramCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
long emuSnap) {
|
||||
if (coordinates.getTime().isSnapOnly()) {
|
||||
Address pc = computePCViaStack(coordinates);
|
||||
if (pc != null) {
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
return RegisterLocationTrackingSpec.super.computeTraceAddress(tool, coordinates, emuSnap);
|
||||
}
|
||||
|
||||
// Note it does no good to override affectByRegChange. It must do what we'd avoid anyway.
|
||||
@Override
|
||||
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
if (stack.getThread() != coordinates.getThread()) {
|
||||
return false;
|
||||
}
|
||||
if (!coordinates.getTime().isSnapOnly()) {
|
||||
return false;
|
||||
}
|
||||
// TODO: Would be nice to have stack lifespan...
|
||||
TraceStack curStack = coordinates.getTrace()
|
||||
.getStackManager()
|
||||
.getLatestStack(stack.getThread(), coordinates.getSnap());
|
||||
if (stack != curStack) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegisterSpace;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
|
||||
// TODO: Use this, or allow arbitrary expressions
|
||||
public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||
Register computeRegister(DebuggerCoordinates coordinates);
|
||||
|
||||
AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates);
|
||||
|
||||
@Override
|
||||
default String computeTitle(DebuggerCoordinates coordinates) {
|
||||
Register register = computeRegister(coordinates);
|
||||
if (register == null) {
|
||||
return null;
|
||||
}
|
||||
return register.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
long emuSnap) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
TraceThread thread = coordinates.getThread();
|
||||
long snap = coordinates.getSnap();
|
||||
int frame = coordinates.getFrame();
|
||||
Register reg = computeRegister(coordinates);
|
||||
if (reg == null) {
|
||||
return null;
|
||||
}
|
||||
if (!thread.getLifespan().contains(snap)) {
|
||||
return null;
|
||||
}
|
||||
TraceMemoryRegisterSpace regs =
|
||||
trace.getMemoryManager().getMemoryRegisterSpace(thread, frame, false);
|
||||
if (regs == null) {
|
||||
return null;
|
||||
}
|
||||
RegisterValue value;
|
||||
if (regs.getState(emuSnap, reg) == TraceMemoryState.KNOWN) {
|
||||
value = regs.getValue(emuSnap, reg);
|
||||
}
|
||||
else {
|
||||
value = regs.getValue(snap, reg);
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
// TODO: Action to select the address space
|
||||
// Could use code unit, but that can't specify space, yet, either....
|
||||
return computeDefaultAddressSpace(coordinates)
|
||||
.getAddress(value.getUnsignedValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates) {
|
||||
if (!LocationTrackingSpec.changeIsCurrent(space, range, coordinates)) {
|
||||
return false;
|
||||
}
|
||||
Register register = computeRegister(coordinates);
|
||||
AddressRange regRng = TraceRegisterUtils.rangeForRegister(register);
|
||||
return range.getRange().intersects(regRng);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/* ###
|
||||
* 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 javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class SPLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||
public static final String CONFIG_NAME = "TRACK_SP";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuName() {
|
||||
return TrackLocationAction.NAME_SP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getMenuIcon() {
|
||||
return TrackLocationAction.ICON_SP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
return trace.getBaseCompilerSpec().getStackPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
||||
return coordinates.getTrace().getBaseLanguage().getDefaultDataSpace();
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/* ###
|
||||
* 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.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.async.AsyncUtils;
|
||||
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;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class VisibleAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "READ_VISIBLE";
|
||||
|
||||
@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<?> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
TraceRecorder recorder = coordinates.getRecorder();
|
||||
AddressSet visibleAccessible =
|
||||
recorder.getAccessibleProcessMemory().intersect(visible);
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
AddressSet toRead = visibleAccessible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* ###
|
||||
* 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 com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec {
|
||||
public static final String CONFIG_NAME = "READ_VIS_RO_ONCE";
|
||||
|
||||
@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<?> readMemory(PluginTool tool, DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
TraceRecorder recorder = coordinates.getRecorder();
|
||||
AddressSet visibleAccessible =
|
||||
recorder.getAccessibleProcessMemory().intersect(visible);
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
AddressSet toRead = visibleAccessible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
AddressSet everKnown = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : mm
|
||||
.getMostRecentStates(coordinates.getSnap(), range)) {
|
||||
everKnown.add(ent.getKey().getRange());
|
||||
}
|
||||
}
|
||||
AddressSet readOnly = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (TraceMemoryRegion region : mm
|
||||
.getRegionsIntersecting(Range.singleton(coordinates.getSnap()), range)) {
|
||||
if (region.isWrite()) {
|
||||
continue;
|
||||
}
|
||||
readOnly.add(region.getRange());
|
||||
}
|
||||
}
|
||||
toRead.delete(everKnown.intersect(readOnly));
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
@ -1,190 +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.listing;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import docking.action.builder.MultiStateActionBuilder;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AutoReadMemoryAction;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public interface DebuggerListingAutoReadMemoryAction extends AutoReadMemoryAction {
|
||||
public interface AutoReadMemorySpec {
|
||||
AutoReadMemorySpec READ_NONE = new ReadNoneMemorySpec();
|
||||
AutoReadMemorySpec READ_VISIBLE = new ReadVisibleMemorySpec();
|
||||
AutoReadMemorySpec READ_VIS_RO_ONCE = new ReadVisibleROOnceMemorySpec();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SaveState state, String name, AutoReadMemorySpec value) {
|
||||
state.putString(name, value.getConfigName());
|
||||
}
|
||||
}
|
||||
|
||||
static AutoReadMemorySpec fromConfigName(String spec) {
|
||||
switch (spec) {
|
||||
default:
|
||||
case "READ_VIS_RO_ONCE":
|
||||
return READ_VIS_RO_ONCE;
|
||||
}
|
||||
}
|
||||
|
||||
String getConfigName();
|
||||
|
||||
/**
|
||||
* Perform the automatic read, if applicable
|
||||
*
|
||||
* <p>
|
||||
* Note, the implementation should perform all the error handling. The returned future is
|
||||
* for follow-up purposes only, and should always complete normally.
|
||||
*
|
||||
* @param coordinates the listing's current coordinates
|
||||
* @param visible the listing's visible addresses
|
||||
* @return a future that completes when the memory has been read
|
||||
*/
|
||||
CompletableFuture<?> readMemory(DebuggerCoordinates coordinates, AddressSetView visible);
|
||||
}
|
||||
|
||||
class ReadNoneMemorySpec implements AutoReadMemorySpec {
|
||||
static final String CONFIG_NAME = "READ_NONE";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> readMemory(DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
}
|
||||
|
||||
class ReadVisibleMemorySpec implements AutoReadMemorySpec {
|
||||
static final String CONFIG_NAME = "READ_VISIBLE";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> readMemory(DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
TraceRecorder recorder = coordinates.getRecorder();
|
||||
AddressSet visibleAccessible =
|
||||
recorder.getAccessibleProcessMemory().intersect(visible);
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
AddressSet toRead = visibleAccessible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
class ReadVisibleROOnceMemorySpec implements AutoReadMemorySpec {
|
||||
static final String CONFIG_NAME = "READ_VIS_RO_ONCE";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> readMemory(DebuggerCoordinates coordinates,
|
||||
AddressSetView visible) {
|
||||
if (!coordinates.isAliveAndReadsPresent()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
TraceRecorder recorder = coordinates.getRecorder();
|
||||
AddressSet visibleAccessible =
|
||||
recorder.getAccessibleProcessMemory().intersect(visible);
|
||||
TraceMemoryManager mm = coordinates.getTrace().getMemoryManager();
|
||||
AddressSetView alreadyKnown =
|
||||
mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible,
|
||||
s -> s == TraceMemoryState.KNOWN);
|
||||
AddressSet toRead = visibleAccessible.subtract(alreadyKnown);
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
AddressSet everKnown = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : mm
|
||||
.getMostRecentStates(coordinates.getSnap(), range)) {
|
||||
everKnown.add(ent.getKey().getRange());
|
||||
}
|
||||
}
|
||||
AddressSet readOnly = new AddressSet();
|
||||
for (AddressRange range : visible) {
|
||||
for (TraceMemoryRegion region : mm
|
||||
.getRegionsIntersecting(Range.singleton(coordinates.getSnap()), range)) {
|
||||
if (region.isWrite()) {
|
||||
continue;
|
||||
}
|
||||
readOnly.add(region.getRange());
|
||||
}
|
||||
}
|
||||
toRead.delete(everKnown.intersect(readOnly));
|
||||
|
||||
if (toRead.isEmpty()) {
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
return recorder.captureProcessMemory(toRead, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
static MultiStateActionBuilder<AutoReadMemorySpec> builder(Plugin owner) {
|
||||
MultiStateActionBuilder<AutoReadMemorySpec> builder = AutoReadMemoryAction.builder(owner);
|
||||
return builder
|
||||
.toolBarGroup(NAME)
|
||||
.performActionOnButtonClick(true)
|
||||
.addState(NAME_NONE, ICON_NONE, AutoReadMemorySpec.READ_NONE)
|
||||
.addState(NAME_VISIBLE, ICON_VISIBLE, AutoReadMemorySpec.READ_VISIBLE)
|
||||
.addState(NAME_VIS_RO_ONCE, ICON_VIS_RO_ONCE, AutoReadMemorySpec.READ_VIS_RO_ONCE);
|
||||
}
|
||||
}
|
@ -34,7 +34,8 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
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.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.NoneLocationTrackingSpec;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.framework.options.AutoOptions;
|
||||
@ -426,7 +427,8 @@ public class DebuggerListingPlugin extends CodeBrowserPlugin implements Debugger
|
||||
provider.readConfigState(providerState); // Yes, config
|
||||
}
|
||||
else {
|
||||
provider.setTrackingSpec(LocationTrackingSpec.TRACK_NONE);
|
||||
provider.setTrackingSpec(
|
||||
LocationTrackingSpec.fromConfigName(NoneLocationTrackingSpec.CONFIG_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,10 +46,9 @@ import ghidra.app.plugin.core.codebrowser.MarkerServiceBackgroundColorModel;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingAutoReadMemoryAction.AutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingAutoReadMemoryAction.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec.TrackingSpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec.TrackingSpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.utils.BackgroundUtils;
|
||||
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||
import ghidra.app.plugin.core.exporter.ExporterDialog;
|
||||
@ -92,9 +91,7 @@ import utilities.util.SuppressableCallback;
|
||||
import utilities.util.SuppressableCallback.Suppression;
|
||||
|
||||
public class DebuggerListingProvider extends CodeViewerProvider implements ListingDisplayListener {
|
||||
private static final LocationTrackingSpec DEFAULT_TRACKING_SPEC = LocationTrackingSpec.TRACK_PC;
|
||||
private static final AutoReadMemorySpec DEFAULT_READ_MEMORY_SPEC =
|
||||
AutoReadMemorySpec.READ_VIS_RO_ONCE;
|
||||
|
||||
private static final AutoConfigState.ClassHandler<DebuggerListingProvider> CONFIG_STATE_HANDLER =
|
||||
AutoConfigState.wireHandler(DebuggerListingProvider.class, MethodHandles.lookup());
|
||||
private static final String KEY_DEBUGGER_COORDINATES = "DebuggerCoordinates";
|
||||
@ -314,6 +311,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
}
|
||||
}
|
||||
|
||||
private final LocationTrackingSpec defaultTrackingSpec =
|
||||
LocationTrackingSpec.fromConfigName(PCLocationTrackingSpec.CONFIG_NAME);
|
||||
private final AutoReadMemorySpec defaultReadMemorySpec =
|
||||
AutoReadMemorySpec.fromConfigName(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
|
||||
private final DebuggerListingPlugin plugin;
|
||||
|
||||
//@AutoServiceConsumed via method
|
||||
@ -356,7 +358,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
protected final DebuggerGoToDialog goToDialog;
|
||||
|
||||
@AutoConfigStateField(codec = TrackingSpecConfigFieldCodec.class)
|
||||
protected LocationTrackingSpec trackingSpec = DEFAULT_TRACKING_SPEC;
|
||||
protected LocationTrackingSpec trackingSpec = defaultTrackingSpec;
|
||||
@AutoConfigStateField
|
||||
protected boolean syncToStaticListing;
|
||||
@AutoConfigStateField
|
||||
@ -364,7 +366,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
@AutoConfigStateField
|
||||
protected boolean followsCurrentThread = true;
|
||||
@AutoConfigStateField(codec = AutoReadMemorySpecConfigFieldCodec.class)
|
||||
protected AutoReadMemorySpec autoReadMemorySpec = DEFAULT_READ_MEMORY_SPEC;
|
||||
protected AutoReadMemorySpec autoReadMemorySpec = defaultReadMemorySpec;
|
||||
// TODO: followsCurrentSnap
|
||||
|
||||
protected ForTrackingAndLabelingTraceListener forTrackingTraceListener =
|
||||
@ -698,11 +700,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
// TODO: Add "other" option, and present most-recent in menu, too
|
||||
// TODO: "other" as in arbitrary expression?
|
||||
// Only those applicable to the current thread's registers, though.
|
||||
actionTrackLocation = DebuggerListingTrackLocationAction.builder(plugin)
|
||||
actionTrackLocation = DebuggerTrackLocationAction.builder(plugin)
|
||||
.onAction(this::activatedLocationTracking)
|
||||
.onActionStateChanged(this::changedLocationTracking)
|
||||
.buildAndInstallLocal(this);
|
||||
actionTrackLocation.setCurrentActionStateByUserData(DEFAULT_TRACKING_SPEC);
|
||||
actionTrackLocation.setCurrentActionStateByUserData(defaultTrackingSpec);
|
||||
|
||||
actionGoTo = GoToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> current.getView() != null)
|
||||
@ -721,11 +723,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
actionFollowsCurrentThread = new FollowsCurrentThreadAction();
|
||||
}
|
||||
actionCaptureSelectedMemory = new CaptureSelectedMemoryAction();
|
||||
actionAutoReadMemory = DebuggerListingAutoReadMemoryAction.builder(plugin)
|
||||
actionAutoReadMemory = DebuggerAutoReadMemoryAction.builder(plugin)
|
||||
.onAction(this::activatedAutoReadMemory)
|
||||
.onActionStateChanged(this::changedAutoReadMemory)
|
||||
.buildAndInstallLocal(this);
|
||||
actionAutoReadMemory.setCurrentActionStateByUserData(DEFAULT_READ_MEMORY_SPEC);
|
||||
actionAutoReadMemory.setCurrentActionStateByUserData(defaultReadMemorySpec);
|
||||
|
||||
actionExportView = ExportTraceViewAction.builder(plugin)
|
||||
.enabledWhen(ctx -> current.getView() != null)
|
||||
@ -1059,7 +1061,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
return null;
|
||||
}
|
||||
// NB: view's snap may be forked for emulation
|
||||
Address address = trackingSpec.computeTraceAddress(cur, current.getView().getSnap());
|
||||
Address address = trackingSpec.computeTraceAddress(tool, cur, current.getView().getSnap());
|
||||
return address == null ? null : new ProgramLocation(current.getView(), address);
|
||||
}
|
||||
|
||||
@ -1112,7 +1114,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
||||
}
|
||||
|
||||
protected void doAutoReadMemory() {
|
||||
autoReadMemorySpec.readMemory(current, visible).exceptionally(ex -> {
|
||||
autoReadMemorySpec.readMemory(tool, current, visible).exceptionally(ex -> {
|
||||
Msg.error(this, "Could not auto-read memory: " + ex);
|
||||
return null;
|
||||
});
|
||||
|
@ -1,302 +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.listing;
|
||||
|
||||
import docking.action.builder.MultiStateActionBuilder;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegisterSpace;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.stack.TraceStackFrame;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
|
||||
public interface DebuggerListingTrackLocationAction extends TrackLocationAction {
|
||||
public interface LocationTrackingSpec {
|
||||
LocationTrackingSpec TRACK_PC = new PCLocationTrackingSpec();
|
||||
LocationTrackingSpec TRACK_SP = new SPLocationTrackingSpec();
|
||||
LocationTrackingSpec TRACK_NONE = new NoneLocationTrackingSpec();
|
||||
|
||||
public static class TrackingSpecConfigFieldCodec
|
||||
implements ConfigFieldCodec<LocationTrackingSpec> {
|
||||
@Override
|
||||
public LocationTrackingSpec read(SaveState state, String name,
|
||||
LocationTrackingSpec current) {
|
||||
String specName = state.getString(name, null);
|
||||
return fromConfigName(specName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(SaveState state, String name, LocationTrackingSpec value) {
|
||||
state.putString(name, value.getConfigName());
|
||||
}
|
||||
}
|
||||
|
||||
static boolean changeIsCurrent(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||
DebuggerCoordinates current) {
|
||||
if (space == null || space.getThread() != current.getThread()) {
|
||||
return false;
|
||||
}
|
||||
if (space.getFrameLevel() != current.getFrame()) {
|
||||
return false;
|
||||
}
|
||||
if (!range.getLifespan().contains(current.getSnap())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static LocationTrackingSpec fromConfigName(String spec) {
|
||||
switch (spec) {
|
||||
default:
|
||||
case PCLocationTrackingSpec.CONFIG_NAME:
|
||||
return TRACK_PC;
|
||||
case SPLocationTrackingSpec.CONFIG_NAME:
|
||||
return TRACK_SP;
|
||||
case NoneLocationTrackingSpec.CONFIG_NAME:
|
||||
return TRACK_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
String getConfigName();
|
||||
|
||||
/**
|
||||
* Compute a title prefix to indicate this tracking specification
|
||||
*
|
||||
* @param thread the provider's current thread
|
||||
* @return a prefix, or {@code null} to use a default
|
||||
*/
|
||||
String computeTitle(DebuggerCoordinates coordinates);
|
||||
|
||||
Address computeTraceAddress(DebuggerCoordinates coordinates, long emuSnap);
|
||||
|
||||
// TODO: Is there a way to generalize these so that other dependencies need not
|
||||
// have their own bespoke methods?
|
||||
|
||||
boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates);
|
||||
|
||||
boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates);
|
||||
}
|
||||
|
||||
class NoneLocationTrackingSpec implements LocationTrackingSpec {
|
||||
static final String CONFIG_NAME = "TRACK_NONE";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String computeTitle(DebuggerCoordinates coordinates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address computeTraceAddress(DebuggerCoordinates coordinates, long emuSnap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use this, or allow arbitrary expressions
|
||||
interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||
Register computeRegister(DebuggerCoordinates coordinates);
|
||||
|
||||
AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates);
|
||||
|
||||
@Override
|
||||
default String computeTitle(DebuggerCoordinates coordinates) {
|
||||
Register register = computeRegister(coordinates);
|
||||
if (register == null) {
|
||||
return null;
|
||||
}
|
||||
return register.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default Address computeTraceAddress(DebuggerCoordinates coordinates, long emuSnap) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
TraceThread thread = coordinates.getThread();
|
||||
long snap = coordinates.getSnap();
|
||||
int frame = coordinates.getFrame();
|
||||
Register reg = computeRegister(coordinates);
|
||||
if (reg == null) {
|
||||
return null;
|
||||
}
|
||||
if (!thread.getLifespan().contains(snap)) {
|
||||
return null;
|
||||
}
|
||||
TraceMemoryRegisterSpace regs =
|
||||
trace.getMemoryManager().getMemoryRegisterSpace(thread, frame, false);
|
||||
if (regs == null) {
|
||||
return null;
|
||||
}
|
||||
RegisterValue value;
|
||||
if (regs.getState(emuSnap, reg) == TraceMemoryState.KNOWN) {
|
||||
value = regs.getValue(emuSnap, reg);
|
||||
}
|
||||
else {
|
||||
value = regs.getValue(snap, reg);
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
// TODO: Action to select the address space
|
||||
// Could use code unit, but that can't specify space, yet, either....
|
||||
return computeDefaultAddressSpace(coordinates)
|
||||
.getAddress(value.getUnsignedValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean affectedByRegisterChange(TraceAddressSpace space,
|
||||
TraceAddressSnapRange range, DebuggerCoordinates coordinates) {
|
||||
if (!LocationTrackingSpec.changeIsCurrent(space, range, coordinates)) {
|
||||
return false;
|
||||
}
|
||||
Register register = computeRegister(coordinates);
|
||||
AddressRange regRng = TraceRegisterUtils.rangeForRegister(register);
|
||||
return range.getRange().intersects(regRng);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class PCLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||
static final String CONFIG_NAME = "TRACK_PC";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
return trace.getBaseLanguage().getProgramCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
||||
return coordinates.getTrace().getBaseLanguage().getDefaultSpace();
|
||||
}
|
||||
|
||||
public Address computePCViaStack(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
TraceThread thread = coordinates.getThread();
|
||||
long snap = coordinates.getSnap();
|
||||
TraceStack stack = trace.getStackManager().getLatestStack(thread, snap);
|
||||
if (stack == null) {
|
||||
return null;
|
||||
}
|
||||
int level = coordinates.getFrame();
|
||||
TraceStackFrame frame = stack.getFrame(level, false);
|
||||
if (frame == null) {
|
||||
return null;
|
||||
}
|
||||
return frame.getProgramCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address computeTraceAddress(DebuggerCoordinates coordinates, long emuSnap) {
|
||||
if (coordinates.getTime().isSnapOnly()) {
|
||||
Address pc = computePCViaStack(coordinates);
|
||||
if (pc != null) {
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
return RegisterLocationTrackingSpec.super.computeTraceAddress(coordinates, emuSnap);
|
||||
}
|
||||
|
||||
// Note it does no good to override affectByRegChange. It must do what we'd avoid anyway.
|
||||
@Override
|
||||
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||
if (stack.getThread() != coordinates.getThread()) {
|
||||
return false;
|
||||
}
|
||||
if (!coordinates.getTime().isSnapOnly()) {
|
||||
return false;
|
||||
}
|
||||
// TODO: Would be nice to have stack lifespan...
|
||||
TraceStack curStack = coordinates.getTrace()
|
||||
.getStackManager()
|
||||
.getLatestStack(stack.getThread(), coordinates.getSnap());
|
||||
if (stack != curStack) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SPLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||
static final String CONFIG_NAME = "TRACK_SP";
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return CONFIG_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||
Trace trace = coordinates.getTrace();
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
return trace.getBaseCompilerSpec().getStackPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
||||
return coordinates.getTrace().getBaseLanguage().getDefaultDataSpace();
|
||||
}
|
||||
}
|
||||
|
||||
static MultiStateActionBuilder<LocationTrackingSpec> builder(Plugin owner) {
|
||||
MultiStateActionBuilder<LocationTrackingSpec> builder = TrackLocationAction.builder(owner);
|
||||
return builder
|
||||
.toolBarGroup(owner.getName())
|
||||
.performActionOnButtonClick(true)
|
||||
.addState(NAME_NONE, ICON_NONE, LocationTrackingSpec.TRACK_NONE)
|
||||
.addState(NAME_PC, ICON_PC, LocationTrackingSpec.TRACK_PC)
|
||||
.addState(NAME_SP, ICON_SP, LocationTrackingSpec.TRACK_SP);
|
||||
}
|
||||
}
|
@ -17,8 +17,13 @@ package ghidra.app.plugin.core.debug.utils;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.beans.PropertyEditor;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
|
||||
public enum MiscellaneousUtils {
|
||||
;
|
||||
@ -57,4 +62,21 @@ public enum MiscellaneousUtils {
|
||||
throw new IllegalStateException(
|
||||
"Ghidra does not know how to use PropertyEditor: " + editor.getClass().getName());
|
||||
}
|
||||
|
||||
public static <T> void collectUniqueInstances(Class<T> cls, Map<String, T> map,
|
||||
Function<T, String> keyFunc) {
|
||||
// This is wasteful. Existing instances will be re-instantiated and thrown away
|
||||
for (T t : ClassSearcher.getInstances(cls)) {
|
||||
String key = keyFunc.apply(t);
|
||||
T exists = map.get(key);
|
||||
if (exists != null) {
|
||||
if (exists.getClass().equals(t.getClass())) {
|
||||
continue;
|
||||
}
|
||||
Msg.error(LocationTrackingSpec.class,
|
||||
cls.getSimpleName() + " conflict over key: " + key);
|
||||
}
|
||||
map.put(key, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,8 @@
|
||||
*/
|
||||
package ghidra.app.services;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.*;
|
||||
import ghidra.framework.plugintool.ServiceInfo;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
|
@ -28,14 +28,13 @@ import generic.Unique;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest.TestDebuggerTargetTraceMapper;
|
||||
import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.dbg.model.TestDebuggerModelBuilder;
|
||||
import ghidra.dbg.target.TargetBreakpointSpecContainer;
|
||||
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
|
||||
import ghidra.dbg.target.TargetBreakpointSpecContainer;
|
||||
import ghidra.dbg.testutil.DebuggerModelTestUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@ -51,10 +50,6 @@ import help.screenshot.GhidraScreenShotGenerator;
|
||||
public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenerator
|
||||
implements DebuggerModelTestUtils {
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
TestDebuggerModelBuilder mb = new TestDebuggerModelBuilder();
|
||||
DebuggerModelServiceProxyPlugin modelService;
|
||||
DebuggerStaticMappingService mappingService;
|
||||
|
@ -21,7 +21,6 @@ import org.junit.Test;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest.TestDebuggerTargetTraceMapper;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.services.DebuggerTraceManagerService;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
@ -32,10 +31,6 @@ import help.screenshot.GhidraScreenShotGenerator;
|
||||
|
||||
public class DebuggerThreadsPluginScreenShots extends GhidraScreenShotGenerator {
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
// NOTE: Using model builder to capture "recording" icon in tabs
|
||||
TestDebuggerModelBuilder mb = new TestDebuggerModelBuilder();
|
||||
DebuggerModelServiceProxyPlugin modelService;
|
||||
|
@ -41,12 +41,11 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.services.LogicalBreakpoint.Enablement;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.dbg.target.TargetBreakpointSpecContainer;
|
||||
import ghidra.dbg.target.TargetBreakpointSpec.TargetBreakpointKind;
|
||||
import ghidra.dbg.target.TargetBreakpointSpecContainer;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.disassemble.Disassembler;
|
||||
import ghidra.program.model.address.Address;
|
||||
@ -74,10 +73,6 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
||||
protected static final Color DE_COLOR = new Color(255, 192, 128);
|
||||
protected static final Color ED_COLOR = new Color(255, 128, 192);
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
protected DebuggerBreakpointMarkerPlugin breakpointMarkerPlugin;
|
||||
protected DebuggerListingPlugin listingPlugin;
|
||||
protected CodeBrowserPlugin codeBrowserPlugin;
|
||||
|
@ -31,7 +31,6 @@ import generic.Unique;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import ghidra.app.plugin.core.debug.gui.breakpoint.DebuggerBreakpointsProvider.LogicalBreakpointTableModel;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.async.AsyncTestUtils;
|
||||
import ghidra.dbg.model.TestTargetProcess;
|
||||
@ -56,10 +55,6 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
||||
protected static final long TIMEOUT_MILLIS =
|
||||
SystemUtilities.isInTestingBatchMode() ? 5000 : Long.MAX_VALUE;
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
protected DebuggerBreakpointsPlugin breakpointsPlugin;
|
||||
protected DebuggerBreakpointsProvider breakpointsProvider;
|
||||
protected DebuggerStaticMappingService mappingService;
|
||||
|
@ -35,9 +35,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractFollowsCurrentThreadAction;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingAutoReadMemoryAction.AutoReadMemorySpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.async.SwingExecutorService;
|
||||
@ -59,16 +57,34 @@ import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||
static LocationTrackingSpec getLocationTrackingSpec(String name) {
|
||||
return /*waitForValue(() ->*/ LocationTrackingSpec.fromConfigName(name)/*)*/;
|
||||
}
|
||||
|
||||
static AutoReadMemorySpec getAutoReadMemorySpec(String name) {
|
||||
return AutoReadMemorySpec.fromConfigName(name);
|
||||
}
|
||||
|
||||
final LocationTrackingSpec trackNone =
|
||||
getLocationTrackingSpec(NoneLocationTrackingSpec.CONFIG_NAME);
|
||||
final LocationTrackingSpec trackPc =
|
||||
getLocationTrackingSpec(PCLocationTrackingSpec.CONFIG_NAME);
|
||||
final LocationTrackingSpec trackSp =
|
||||
getLocationTrackingSpec(SPLocationTrackingSpec.CONFIG_NAME);
|
||||
|
||||
final AutoReadMemorySpec readNone =
|
||||
getAutoReadMemorySpec(NoneAutoReadMemorySpec.CONFIG_NAME);
|
||||
final AutoReadMemorySpec readVisible =
|
||||
getAutoReadMemorySpec(VisibleAutoReadMemorySpec.CONFIG_NAME);
|
||||
final AutoReadMemorySpec readVisROOnce =
|
||||
getAutoReadMemorySpec(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
|
||||
protected DebuggerListingPlugin listingPlugin;
|
||||
protected DebuggerListingProvider listingProvider;
|
||||
|
||||
protected DebuggerStaticMappingService mappingService;
|
||||
protected CodeViewerService codeViewer;
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpListingProviderTest() throws Exception {
|
||||
listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
|
||||
@ -230,7 +246,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
TraceThread thread1;
|
||||
TraceThread thread2;
|
||||
DebuggerListingProvider extraListing = SwingExecutorService.INSTANCE.submit(
|
||||
() -> listingPlugin.createListingIfMissing(LocationTrackingSpec.TRACK_PC, true)).get();
|
||||
() -> listingPlugin.createListingIfMissing(trackPc, true)).get();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
DBTraceMemoryManager memory = tb.trace.getMemoryManager();
|
||||
memory.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
@ -288,7 +304,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
//Pre-check
|
||||
assertEquals(tb.addr(0x00400000), listingProvider.getLocation().getAddress());
|
||||
|
||||
listingProvider.setTrackingSpec(LocationTrackingSpec.TRACK_SP);
|
||||
listingProvider.setTrackingSpec(trackSp);
|
||||
waitForSwing();
|
||||
|
||||
ProgramLocation loc = listingProvider.getLocation();
|
||||
@ -299,7 +315,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
@Test
|
||||
public void testFollowsCurrentTraceOnTraceChangeWithoutRegisterTracking()
|
||||
throws Exception {
|
||||
listingProvider.setTrackingSpec(LocationTrackingSpec.TRACK_NONE);
|
||||
listingProvider.setTrackingSpec(trackNone);
|
||||
try ( //
|
||||
ToyDBTraceBuilder b1 =
|
||||
new ToyDBTraceBuilder(name.getMethodName() + "_1", LANGID_TOYBE64); //
|
||||
@ -356,7 +372,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
@Test
|
||||
public void testFollowsCurrentThreadOnThreadChangeWithoutRegisterTracking()
|
||||
throws Exception {
|
||||
listingProvider.setTrackingSpec(LocationTrackingSpec.TRACK_NONE);
|
||||
listingProvider.setTrackingSpec(trackNone);
|
||||
try ( //
|
||||
ToyDBTraceBuilder b1 =
|
||||
new ToyDBTraceBuilder(name.getMethodName() + "_1", LANGID_TOYBE64); //
|
||||
@ -635,8 +651,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
byte[] data = incBlock();
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertEquals(AutoReadMemorySpec.READ_VIS_RO_ONCE, listingProvider.getAutoReadMemorySpec());
|
||||
listingProvider.setAutoReadMemorySpec(AutoReadMemorySpec.READ_NONE);
|
||||
assertEquals(readVisROOnce, listingProvider.getAutoReadMemorySpec());
|
||||
listingProvider.setAutoReadMemorySpec(readNone);
|
||||
|
||||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
@ -678,7 +694,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
* NOTE: Should read immediately upon setting auto-read, but we're not focused on the
|
||||
* written block
|
||||
*/
|
||||
listingProvider.setAutoReadMemorySpec(AutoReadMemorySpec.READ_VIS_RO_ONCE);
|
||||
listingProvider.setAutoReadMemorySpec(readVisROOnce);
|
||||
waitForDomainObject(trace);
|
||||
buf.clear();
|
||||
assertEquals(data.length,
|
||||
@ -731,7 +747,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
listingProvider.locationLabel.getText());
|
||||
|
||||
DebuggerListingProvider extraProvider = runSwing(
|
||||
() -> listingPlugin.createListingIfMissing(LocationTrackingSpec.TRACK_NONE, false));
|
||||
() -> listingPlugin.createListingIfMissing(trackNone, false));
|
||||
waitForSwing();
|
||||
assertEquals(traceManager.getCurrentView(), extraProvider.getProgram());
|
||||
assertEquals("dynamic-testCloseCurrentTraceBlanksListings",
|
||||
@ -819,8 +835,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
waitForSwing();
|
||||
|
||||
// Check the default is track pc
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress());
|
||||
|
||||
runSwing(() -> goToDyn(tb.addr(0x00400000)));
|
||||
@ -831,15 +846,14 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
performAction(listingProvider.actionTrackLocation);
|
||||
assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress());
|
||||
|
||||
setActionStateWithTrigger(listingProvider.actionTrackLocation,
|
||||
LocationTrackingSpec.TRACK_SP, EventTrigger.GUI_ACTION);
|
||||
setActionStateWithTrigger(listingProvider.actionTrackLocation, trackSp,
|
||||
EventTrigger.GUI_ACTION);
|
||||
waitForSwing();
|
||||
assertEquals(tb.addr(0x1fff8765), listingProvider.getLocation().getAddress());
|
||||
|
||||
listingProvider.setTrackingSpec(LocationTrackingSpec.TRACK_NONE);
|
||||
listingProvider.setTrackingSpec(trackNone);
|
||||
waitForSwing();
|
||||
assertEquals(LocationTrackingSpec.TRACK_NONE,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackNone, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -922,7 +936,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
// NOTE: Action does not exist for main dynamic listing
|
||||
DebuggerListingProvider extraProvider = runSwing(
|
||||
() -> listingPlugin.createListingIfMissing(LocationTrackingSpec.TRACK_NONE, true));
|
||||
() -> listingPlugin.createListingIfMissing(trackNone, true));
|
||||
waitForSwing();
|
||||
assertTrue(extraProvider.actionFollowsCurrentThread.isEnabled());
|
||||
assertTrue(extraProvider.actionFollowsCurrentThread.isSelected());
|
||||
@ -950,7 +964,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
|
||||
listingProvider.setAutoReadMemorySpec(AutoReadMemorySpec.READ_NONE);
|
||||
listingProvider.setAutoReadMemorySpec(readNone);
|
||||
|
||||
// To verify enabled requires live target
|
||||
createAndOpenTrace();
|
||||
@ -1045,28 +1059,24 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
public void testActionAutoReadMemory() {
|
||||
assertTrue(listingProvider.actionAutoReadMemory.isEnabled());
|
||||
|
||||
assertEquals(AutoReadMemorySpec.READ_VIS_RO_ONCE, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(AutoReadMemorySpec.READ_VIS_RO_ONCE,
|
||||
listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
assertEquals(readVisROOnce, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(readVisROOnce, listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
|
||||
listingProvider.actionAutoReadMemory
|
||||
.setCurrentActionStateByUserData(AutoReadMemorySpec.READ_NONE);
|
||||
.setCurrentActionStateByUserData(readNone);
|
||||
waitForSwing();
|
||||
assertEquals(AutoReadMemorySpec.READ_NONE, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(AutoReadMemorySpec.READ_NONE,
|
||||
listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
assertEquals(readNone, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(readNone, listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
|
||||
listingProvider.setAutoReadMemorySpec(AutoReadMemorySpec.READ_VIS_RO_ONCE);
|
||||
listingProvider.setAutoReadMemorySpec(readVisROOnce);
|
||||
waitForSwing();
|
||||
assertEquals(AutoReadMemorySpec.READ_VIS_RO_ONCE, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(AutoReadMemorySpec.READ_VIS_RO_ONCE,
|
||||
listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
assertEquals(readVisROOnce, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(readVisROOnce, listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
|
||||
listingProvider.setAutoReadMemorySpec(AutoReadMemorySpec.READ_NONE);
|
||||
listingProvider.setAutoReadMemorySpec(readNone);
|
||||
waitForSwing();
|
||||
assertEquals(AutoReadMemorySpec.READ_NONE, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(AutoReadMemorySpec.READ_NONE,
|
||||
listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
assertEquals(readNone, listingProvider.getAutoReadMemorySpec());
|
||||
assertEquals(readNone, listingProvider.actionAutoReadMemory.getCurrentUserData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1154,8 +1164,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testActivateThreadTracks() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
Register pc = tb.language.getProgramCounter();
|
||||
@ -1186,8 +1195,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testActivateSnapTracks() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
Register pc = tb.language.getProgramCounter();
|
||||
@ -1215,8 +1223,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testActivateFrameTracks() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
TraceThread thread;
|
||||
@ -1244,8 +1251,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testRegsPCChangedTracks() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
DBTraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
@ -1275,8 +1281,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testRegsPCChangedTracksDespiteStackWithNoPC() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
DBTraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
@ -1310,8 +1315,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
@Test
|
||||
public void testStackPCChangedTracks() throws Exception {
|
||||
assertEquals(LocationTrackingSpec.TRACK_PC,
|
||||
listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData());
|
||||
|
||||
createAndOpenTrace();
|
||||
DBTraceStackManager sm = tb.trace.getStackManager();
|
||||
|
@ -35,7 +35,6 @@ import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerBlockChooserDialog.MemoryBlockRow;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModuleMapProposalDialog.ModuleMapTableColumns;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerSectionMapProposalDialog.SectionMapTableColumns;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.DebuggerListingService;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.ModuleMapEntry;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.SectionMapEntry;
|
||||
@ -76,10 +75,6 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
protected TraceSection secLibText;
|
||||
protected TraceSection secLibData;
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpModulesProviderTest() throws Exception {
|
||||
modulesPlugin = addPlugin(tool, DebuggerModulesPlugin.class);
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.register;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
import static ghidra.lifecycle.Unfinished.TODO;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@ -27,8 +27,9 @@ import org.junit.*;
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingTrackLocationAction.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.action.NoneLocationTrackingSpec;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.*;
|
||||
import ghidra.app.plugin.core.debug.gui.register.DebuggerRegistersProvider.RegisterTableColumns;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
@ -48,9 +49,6 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerGUITest
|
||||
implements AsyncTestUtils {
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
protected DebuggerRegistersPlugin registersPlugin;
|
||||
protected DebuggerRegistersProvider registersProvider;
|
||||
@ -701,7 +699,8 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
||||
addRegisterValues(thread);
|
||||
addRegisterTypes(thread);
|
||||
// Ensure cause is goto PC, not register tracking
|
||||
listingPlugin.setTrackingSpec(LocationTrackingSpec.TRACK_NONE);
|
||||
listingPlugin.setTrackingSpec(
|
||||
LocationTrackingSpec.fromConfigName(NoneLocationTrackingSpec.CONFIG_NAME));
|
||||
traceManager.activateThread(thread);
|
||||
waitForSwing();
|
||||
|
||||
|
@ -29,7 +29,6 @@ import com.google.common.collect.Range;
|
||||
|
||||
import docking.widgets.EventTrigger;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
@ -39,9 +38,6 @@ import ghidra.trace.model.time.TraceTimeManager;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
protected DebuggerThreadsPlugin threadsPlugin;
|
||||
protected DebuggerThreadsProvider threadsProvider;
|
||||
|
@ -26,7 +26,6 @@ import org.junit.*;
|
||||
import generic.Unique;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
||||
import ghidra.program.model.address.Address;
|
||||
@ -43,9 +42,6 @@ import ghidra.util.Msg;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
protected static void assertNoErr(WatchRow row) {
|
||||
Throwable error = row.getError();
|
||||
|
@ -24,7 +24,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetRegister;
|
||||
import ghidra.dbg.target.*;
|
||||
@ -34,9 +33,6 @@ import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class LargestSubDebuggerRegisterMapperTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
static class TestTargetMapper extends AbstractDebuggerTargetTraceMapper {
|
||||
public TestTargetMapper(TargetObject target)
|
||||
|
@ -26,7 +26,6 @@ import org.junit.*;
|
||||
|
||||
import generic.Unique;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.services.LogicalBreakpoint.Enablement;
|
||||
import ghidra.async.AsyncReference;
|
||||
@ -54,10 +53,6 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe
|
||||
protected static final long TIMEOUT_MILLIS =
|
||||
SystemUtilities.isInTestingBatchMode() ? 5000 : Long.MAX_VALUE;
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks the current set of logical breakpoints.
|
||||
*
|
||||
|
@ -34,8 +34,6 @@ import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.model.TestDebuggerObjectModel;
|
||||
import ghidra.dbg.model.TestLocalDebuggerModelFactory;
|
||||
import ghidra.dbg.testutil.DebuggerModelTestUtils;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.SystemUtilities;
|
||||
@ -54,58 +52,6 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
||||
protected static final long TIMEOUT_MILLIS =
|
||||
SystemUtilities.isInTestingBatchMode() ? 5000 : Long.MAX_VALUE;
|
||||
|
||||
public static final PathMatcher HARDCODED_MATCHER = new PathMatcher() {
|
||||
{
|
||||
// Paths for GDB
|
||||
addPattern(PathUtils.parse("Breakpoints[]."));
|
||||
addPattern(PathUtils.parse("Inferiors[].Memory[]"));
|
||||
addPattern(PathUtils.parse("Inferiors[].Modules[].Sections[]"));
|
||||
addPattern(PathUtils.parse("Inferiors[].Registers[]"));
|
||||
addPattern(PathUtils.parse("Inferiors[].Threads[]"));
|
||||
addPattern(PathUtils.parse("Inferiors[].Threads[].Stack[]"));
|
||||
|
||||
// Paths for dbgeng
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Memory[]"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Modules[]"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Registers[]"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Stack[]"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Debug.Breakpoints[]"));
|
||||
|
||||
// (Additional) paths for dbgmodel
|
||||
addPattern(PathUtils.parse("Sessions[].Attributes"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Stack.Frames[]"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].TTD.Position"));
|
||||
addPattern(PathUtils.parse("Sessions[].Processes[].Threads[].Registers.User."));
|
||||
|
||||
// Paths for JDI
|
||||
addPattern(PathUtils.parse("VirtualMachines[]"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Breakpoints"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Classes[]"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Classes[].Sections[]"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Threads[]"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Threads[].Registers[]"));
|
||||
addPattern(PathUtils.parse("VirtualMachines[].Threads[].Stack[]"));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public static void addTestModelPathPatterns() {
|
||||
PathMatcher m = HARDCODED_MATCHER;
|
||||
m.addPattern(PathUtils.parse("Processes[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Breakpoints[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Memory[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Modules[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Registers[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Threads[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Threads[].RegisterBank"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Threads[].Stack[]"));
|
||||
m.addPattern(PathUtils.parse("Processes[].Threads[].Stack[].RegisterBank"));
|
||||
}
|
||||
|
||||
static {
|
||||
addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exists just for mocking, because jmockit does Bad Things (TM) to
|
||||
* CollectionChangeListener.of() if I try to mock one of those or a subclass directly. I'm
|
||||
|
@ -40,16 +40,8 @@ import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
/**
|
||||
* NOTE: I'd like to avoid putting too much stuff in here until schemas are done, but I suppose
|
||||
* refactoring tests is all part of the refactoring game when it comes down to it.
|
||||
*/
|
||||
public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadsRecorded() throws Exception {
|
||||
createTestModel();
|
||||
|
@ -26,7 +26,6 @@ import org.junit.Test;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetStack;
|
||||
import ghidra.dbg.model.TestTargetStackFrameHasRegisterBank;
|
||||
@ -41,10 +40,6 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
||||
protected static final long TIMEOUT_MILLIS =
|
||||
SystemUtilities.isInTestingBatchMode() ? 5000 : Long.MAX_VALUE;
|
||||
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOpenTraces() throws Exception {
|
||||
assertEquals(Set.of(), traceManager.getOpenTraces());
|
||||
|
@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceTest;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
||||
@ -37,9 +36,6 @@ import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebuggerGUITest
|
||||
implements DebuggerModelTestUtils {
|
||||
static {
|
||||
DebuggerModelServiceTest.addTestModelPathPatterns();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutorEval() throws Throwable {
|
||||
|
Loading…
Reference in New Issue
Block a user