GP-848: Refactored LocationTrackingSpec and AutoReadMemorySpec to be ExtensionPoints

This commit is contained in:
Dan 2021-04-13 08:59:07 -04:00
parent ee2f01b53a
commit 3b058380a3
33 changed files with 980 additions and 686 deletions

View File

@ -1,5 +1,6 @@
AutoReadMemorySpec
DebuggerBot
DebuggerMappingOpinion
DebuggerModelFactory
DisassemblyInject
LocationTrackingSpec

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -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;
});

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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.
*

View File

@ -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

View File

@ -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();

View File

@ -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());

View File

@ -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 {