mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-2459: Refactor platform into LocationTracking. Add PC-by-reg, PC-by-stack
This commit is contained in:
parent
45165ea167
commit
8247ff6d43
14 changed files with 304 additions and 84 deletions
|
@ -108,6 +108,19 @@
|
||||||
meaning may vary among platforms. While there may be some nuances to the register value, the
|
meaning may vary among platforms. While there may be some nuances to the register value, the
|
||||||
value recorded in the stack should indicate the next instruction to be executed.</LI>
|
value recorded in the stack should indicate the next instruction to be executed.</LI>
|
||||||
|
|
||||||
|
<LI>Track Program Counter (by stack) - navigates this listing to the current program counter
|
||||||
|
as recorded from the debugger's stack trace. This option is not recommended for regular use,
|
||||||
|
especially for emulation, since the emulator does not provide stack trace records. It is
|
||||||
|
recommended for debugger connection developers to verify the stack records are being property
|
||||||
|
interpreted by the GUI.</LI>
|
||||||
|
|
||||||
|
<LI>Track Program Counter (by register) - navigates this listing to the current program
|
||||||
|
counter as recorded from the registers. While suitable for regular use, the default "Track
|
||||||
|
Program Counter" option is recommended, since the stack may record the program counter in
|
||||||
|
some cases where the registers do not. For example, when unwinding a stack frame, the
|
||||||
|
debugger may report the frame's program counter without reporting the frame's registers. This
|
||||||
|
option may be desired if/when stack frames are recorded incorrectly.</LI>
|
||||||
|
|
||||||
<LI>Track Stack Pointer - navigates this listing to the current stack pointer. Again,
|
<LI>Track Stack Pointer - navigates this listing to the current stack pointer. Again,
|
||||||
platforms may vary in how they define the stack pointer.</LI>
|
platforms may vary in how they define the stack pointer.</LI>
|
||||||
</UL>
|
</UL>
|
||||||
|
|
|
@ -83,13 +83,26 @@
|
||||||
<UL>
|
<UL>
|
||||||
<LI>Do Not Track - disables automatic navigation.</LI>
|
<LI>Do Not Track - disables automatic navigation.</LI>
|
||||||
|
|
||||||
<LI>Track Program Counter - (default) navigates this window to the current program counter.
|
<LI>Track Program Counter - (default) navigates this listing to the current program counter.
|
||||||
If the stack contains a record of the program counter, it is preferred to the recorded
|
If the stack contains a record of the program counter, it is preferred to the recorded
|
||||||
register value. Note that debuggers may vary in how they report the program counter, and its
|
register value. Note that debuggers may vary in how they report the program counter, and its
|
||||||
meaning may vary among platforms. While there may be some nuances to the register value, the
|
meaning may vary among platforms. While there may be some nuances to the register value, the
|
||||||
value recorded in the stack should indicate the next instruction to be executed.</LI>
|
value recorded in the stack should indicate the next instruction to be executed.</LI>
|
||||||
|
|
||||||
<LI>Track Stack Pointer - navigates this window to the current stack pointer. Again,
|
<LI>Track Program Counter (by stack) - navigates this listing to the current program counter
|
||||||
|
as recorded from the debugger's stack trace. This option is not recommended for regular use,
|
||||||
|
especially for emulation, since the emulator does not provide stack trace records. It is
|
||||||
|
recommended for debugger connection developers to verify the stack records are being property
|
||||||
|
interpreted by the GUI.</LI>
|
||||||
|
|
||||||
|
<LI>Track Program Counter (by register) - navigates this listing to the current program
|
||||||
|
counter as recorded from the registers. While suitable for regular use, the default "Track
|
||||||
|
Program Counter" option is recommended, since the stack may record the program counter in
|
||||||
|
some cases where the registers do not. For example, when unwinding a stack frame, the
|
||||||
|
debugger may report the frame's program counter without reporting the frame's registers. This
|
||||||
|
option may be desired if/when stack frames are recorded incorrectly.</LI>
|
||||||
|
|
||||||
|
<LI>Track Stack Pointer - navigates this listing to the current stack pointer. Again,
|
||||||
platforms may vary in how they define the stack pointer.</LI>
|
platforms may vary in how they define the stack pointer.</LI>
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
|
|
|
@ -859,11 +859,15 @@ public interface DebuggerResources {
|
||||||
String HELP_ANCHOR = "track_location";
|
String HELP_ANCHOR = "track_location";
|
||||||
|
|
||||||
String NAME_PC = "Track Program Counter";
|
String NAME_PC = "Track Program Counter";
|
||||||
|
String NAME_PC_BY_REGISTER = "Track Program Counter (by Register)";
|
||||||
|
String NAME_PC_BY_STACK = "Track Program Counter (by Stack)";
|
||||||
String NAME_SP = "Track Stack Pointer";
|
String NAME_SP = "Track Stack Pointer";
|
||||||
String NAME_NONE = "Do Not Track";
|
String NAME_NONE = "Do Not Track";
|
||||||
|
|
||||||
// TODO: Separate icons for Program Counter and Stack Pointer
|
// TODO: Separate icons for Program Counter and Stack Pointer
|
||||||
Icon ICON_PC = ICON_REGISTER_MARKER;
|
Icon ICON_PC = ICON_REGISTER_MARKER;
|
||||||
|
Icon ICON_PC_BY_REGISTER = ICON_REGISTER_MARKER;
|
||||||
|
Icon ICON_PC_BY_STACK = ICON_REGISTER_MARKER;
|
||||||
Icon ICON_SP = ICON_REGISTER_MARKER;
|
Icon ICON_SP = ICON_REGISTER_MARKER;
|
||||||
// TODO: Consider sync_disabled icon
|
// TODO: Consider sync_disabled icon
|
||||||
Icon ICON_NONE = ICON_DELETE;
|
Icon ICON_NONE = ICON_DELETE;
|
||||||
|
|
|
@ -25,6 +25,7 @@ public interface DebuggerTrackLocationAction extends TrackLocationAction {
|
||||||
static MultiStateActionBuilder<LocationTrackingSpec> builder(Plugin owner) {
|
static MultiStateActionBuilder<LocationTrackingSpec> builder(Plugin owner) {
|
||||||
MultiStateActionBuilder<LocationTrackingSpec> builder = TrackLocationAction.builder(owner);
|
MultiStateActionBuilder<LocationTrackingSpec> builder = TrackLocationAction.builder(owner);
|
||||||
builder.toolBarGroup(owner.getName());
|
builder.toolBarGroup(owner.getName());
|
||||||
|
builder.useCheckboxForIcons(true);
|
||||||
for (LocationTrackingSpec spec : LocationTrackingSpec.allSpecs().values()) {
|
for (LocationTrackingSpec spec : LocationTrackingSpec.allSpecs().values()) {
|
||||||
builder.addState(spec.getMenuName(), spec.getMenuIcon(), spec);
|
builder.addState(spec.getMenuName(), spec.getMenuIcon(), spec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,8 +251,8 @@ public class DebuggerTrackLocationTrait {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// NB: view's snap may be forked for emulation
|
// NB: view's snap may be forked for emulation
|
||||||
Address address = spec.computeTraceAddress(tool, cur, current.getView().getSnap());
|
Address address = spec.computeTraceAddress(tool, cur);
|
||||||
return address == null ? null : new ProgramLocation(current.getView(), address);
|
return address == null ? null : new ProgramLocation(cur.getView(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doTrack() {
|
protected void doTrack() {
|
||||||
|
|
|
@ -29,21 +29,26 @@ import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.trace.model.TraceAddressSnapRange;
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
|
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||||
import ghidra.trace.model.stack.TraceStack;
|
import ghidra.trace.model.stack.TraceStack;
|
||||||
import ghidra.trace.util.TraceAddressSpace;
|
import ghidra.trace.util.TraceAddressSpace;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.classfinder.ExtensionPoint;
|
import ghidra.util.classfinder.ExtensionPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "specification" for automatic navigation of the dynamic listing
|
* A specification for automatic navigation of the dynamic listing
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* TODO: Some of these should be configurable, and permit multiple instances, so that common
|
* 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
|
* 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.
|
* want 3 different common expressions readily available in the drop-down list. It might make sense
|
||||||
|
* to generate a tracking specification from each Watch.
|
||||||
*/
|
*/
|
||||||
public interface LocationTrackingSpec extends ExtensionPoint {
|
public interface LocationTrackingSpec extends ExtensionPoint {
|
||||||
class Private {
|
enum Private {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
private final Map<String, LocationTrackingSpec> specsByName = new TreeMap<>();
|
private final Map<String, LocationTrackingSpec> specsByName = new TreeMap<>();
|
||||||
private final ChangeListener classListener = this::classesChanged;
|
private final ChangeListener classListener = this::classesChanged;
|
||||||
|
|
||||||
|
@ -57,7 +62,7 @@ public interface LocationTrackingSpec extends ExtensionPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Private PRIVATE = new Private();
|
Private PRIVATE = Private.INSTANCE;
|
||||||
|
|
||||||
public static class TrackingSpecConfigFieldCodec
|
public static class TrackingSpecConfigFieldCodec
|
||||||
implements ConfigFieldCodec<LocationTrackingSpec> {
|
implements ConfigFieldCodec<LocationTrackingSpec> {
|
||||||
|
@ -74,36 +79,87 @@ public interface LocationTrackingSpec extends ExtensionPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given trace-space and range refer to memory or the current frame
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If the space models memory, the thread and frame are not considered, in case, e.g., the
|
||||||
|
* tracked register is memory-mapped. If the space models registers, the thread and frame are
|
||||||
|
* considered and must match those given in the coordinates. Whatever the case, the span must
|
||||||
|
* include the snap of the coordinates. Otherwise, the change is not considered current.
|
||||||
|
*
|
||||||
|
* @param space the trace-space, giving thread, frame, and address space
|
||||||
|
* @param range the address range and time span of the change
|
||||||
|
* @param current the current coordinates
|
||||||
|
* @return true if the change affects the tracked address for the given coordinates
|
||||||
|
*/
|
||||||
static boolean changeIsCurrent(TraceAddressSpace space, TraceAddressSnapRange range,
|
static boolean changeIsCurrent(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
DebuggerCoordinates current) {
|
DebuggerCoordinates current) {
|
||||||
if (space == null || space.getThread() != current.getThread()) {
|
if (space == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (space.getFrameLevel() != current.getFrame()) {
|
if (!space.getAddressSpace().isMemorySpace()) {
|
||||||
|
TraceMemorySpace memSpace = current.getTrace()
|
||||||
|
.getMemoryManager()
|
||||||
|
.getMemoryRegisterSpace(current.getThread(), current.getFrame(), false);
|
||||||
|
if (memSpace == null || memSpace.getAddressSpace() != space.getAddressSpace()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!range.getLifespan().contains(current.getSnap())) {
|
if (!range.getLifespan().contains(current.getSnap())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the specification for the given configuration name
|
||||||
|
*
|
||||||
|
* @param name the name
|
||||||
|
* @return the spec, or null
|
||||||
|
*/
|
||||||
static LocationTrackingSpec fromConfigName(String name) {
|
static LocationTrackingSpec fromConfigName(String name) {
|
||||||
synchronized (PRIVATE) {
|
synchronized (PRIVATE) {
|
||||||
return PRIVATE.specsByName.get(name);
|
return PRIVATE.specsByName.get(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a copy of all the known specifications
|
||||||
|
*
|
||||||
|
* @return the specifications by configuration name
|
||||||
|
*/
|
||||||
static Map<String, LocationTrackingSpec> allSpecs() {
|
static Map<String, LocationTrackingSpec> allSpecs() {
|
||||||
synchronized (PRIVATE) {
|
synchronized (PRIVATE) {
|
||||||
return Map.copyOf(PRIVATE.specsByName);
|
return new TreeMap<>(PRIVATE.specsByName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configuration name
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This is the value stored in configuration files to identify this specification
|
||||||
|
*
|
||||||
|
* @return the configuration name
|
||||||
|
*/
|
||||||
String getConfigName();
|
String getConfigName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A human-readable name for this specification
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This is the text displayed in menus
|
||||||
|
*
|
||||||
|
* @return the menu name
|
||||||
|
*/
|
||||||
String getMenuName();
|
String getMenuName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the icon for this specification
|
||||||
|
*
|
||||||
|
* @return the icon
|
||||||
|
*/
|
||||||
Icon getMenuIcon();
|
Icon getMenuIcon();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,15 +176,16 @@ public interface LocationTrackingSpec extends ExtensionPoint {
|
||||||
* <p>
|
* <p>
|
||||||
* If the coordinates indicate emulation, i.e., the schedule is non-empty, the trace manager
|
* 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
|
* 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
|
* general, the location should be computed using that snap, i.e.,
|
||||||
* indicated in {@code coordinates}.
|
* {@link DebuggerCoordinates#getViewSnap()} rather than {@link DebuggerCoordinates#getSnap()}.
|
||||||
|
* The address returned must be in the host platform's language, i.e., please use
|
||||||
|
* {@link TracePlatform#mapGuestToHost(Address)}.
|
||||||
*
|
*
|
||||||
* @param tool the tool containing the provider
|
* @param tool the tool containing the provider
|
||||||
* @param coordinates the trace, thread, snap, etc., of the tool
|
* @param coordinates the trace, thread, snap, etc., of the tool
|
||||||
* @param emuSnap the "scratch" snap storing emulated state
|
|
||||||
* @return the address to navigate to
|
* @return the address to navigate to
|
||||||
*/
|
*/
|
||||||
Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates, long emuSnap);
|
Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates);
|
||||||
|
|
||||||
// TODO: Is there a way to generalize these so that other dependencies need not
|
// TODO: Is there a way to generalize these so that other dependencies need not
|
||||||
// have their own bespoke methods?
|
// have their own bespoke methods?
|
||||||
|
|
|
@ -49,8 +49,7 @@ public class NoneLocationTrackingSpec implements LocationTrackingSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
public Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates) {
|
||||||
long emuSnap) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.guest.TracePlatform;
|
||||||
|
|
||||||
|
public class PCByRegisterLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||||
|
public static final String CONFIG_NAME = "TRACK_PC_BY_REGISTER";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfigName() {
|
||||||
|
return CONFIG_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMenuName() {
|
||||||
|
return TrackLocationAction.NAME_PC_BY_REGISTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Icon getMenuIcon() {
|
||||||
|
return TrackLocationAction.ICON_PC_BY_REGISTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||||
|
TracePlatform platform = coordinates.getPlatform();
|
||||||
|
if (platform == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return platform.getLanguage().getProgramCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
||||||
|
return coordinates.getPlatform().getLanguage().getDefaultSpace();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* ###
|
||||||
|
* 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.Trace;
|
||||||
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
|
import ghidra.trace.model.stack.TraceStack;
|
||||||
|
import ghidra.trace.model.stack.TraceStackFrame;
|
||||||
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
|
import ghidra.trace.util.TraceAddressSpace;
|
||||||
|
|
||||||
|
public class PCByStackLocationTrackingSpec implements LocationTrackingSpec {
|
||||||
|
public static final String CONFIG_NAME = "TRACK_PC_BY_STACK";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfigName() {
|
||||||
|
return CONFIG_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMenuName() {
|
||||||
|
return TrackLocationAction.NAME_PC_BY_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Icon getMenuIcon() {
|
||||||
|
return TrackLocationAction.ICON_PC_BY_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String computeTitle(DebuggerCoordinates coordinates) {
|
||||||
|
return "Stack's PC";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address computeTraceAddress(PluginTool tool, 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(snap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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...
|
||||||
|
// TODO: It does in objects mode. Leave until old code is removed.
|
||||||
|
TraceStack curStack = coordinates.getTrace()
|
||||||
|
.getStackManager()
|
||||||
|
.getLatestStack(stack.getThread(), coordinates.getSnap());
|
||||||
|
if (stack != curStack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean affectedByRegisterChange(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
|
DebuggerCoordinates coordinates) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,16 +21,18 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
import ghidra.program.model.lang.Register;
|
|
||||||
import ghidra.trace.model.Trace;
|
|
||||||
import ghidra.trace.model.stack.TraceStack;
|
import ghidra.trace.model.stack.TraceStack;
|
||||||
import ghidra.trace.model.stack.TraceStackFrame;
|
import ghidra.trace.util.TraceAddressSpace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
|
||||||
|
|
||||||
public class PCLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
public class PCLocationTrackingSpec implements LocationTrackingSpec {
|
||||||
public static final String CONFIG_NAME = "TRACK_PC";
|
public static final String CONFIG_NAME = "TRACK_PC";
|
||||||
|
|
||||||
|
private static final PCByRegisterLocationTrackingSpec BY_REG =
|
||||||
|
new PCByRegisterLocationTrackingSpec();
|
||||||
|
private static final PCByStackLocationTrackingSpec BY_STACK =
|
||||||
|
new PCByStackLocationTrackingSpec();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getConfigName() {
|
public String getConfigName() {
|
||||||
return CONFIG_NAME;
|
return CONFIG_NAME;
|
||||||
|
@ -47,63 +49,30 @@ public class PCLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
public String computeTitle(DebuggerCoordinates coordinates) {
|
||||||
Trace trace = coordinates.getTrace();
|
return "Auto PC";
|
||||||
if (trace == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return trace.getBaseLanguage().getProgramCounter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSpace computeDefaultAddressSpace(DebuggerCoordinates coordinates) {
|
public Address computeTraceAddress(PluginTool tool, 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(snap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
|
||||||
long emuSnap) {
|
|
||||||
if (coordinates.getTime().isSnapOnly()) {
|
if (coordinates.getTime().isSnapOnly()) {
|
||||||
Address pc = computePCViaStack(coordinates);
|
Address pc = BY_STACK.computeTraceAddress(tool, coordinates);
|
||||||
if (pc != null) {
|
if (pc != null) {
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RegisterLocationTrackingSpec.super.computeTraceAddress(tool, coordinates, emuSnap);
|
return BY_REG.computeTraceAddress(tool, coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note it does no good to override affectByRegChange. It must do what we'd avoid anyway.
|
// Note it does no good to override affectByRegChange. It must do what we'd avoid anyway.
|
||||||
@Override
|
@Override
|
||||||
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) {
|
||||||
if (stack.getThread() != coordinates.getThread()) {
|
return BY_STACK.affectedByStackChange(stack, coordinates);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!coordinates.getTime().isSnapOnly()) {
|
|
||||||
return false;
|
@Override
|
||||||
}
|
public boolean affectedByRegisterChange(TraceAddressSpace space, TraceAddressSnapRange range,
|
||||||
// TODO: Would be nice to have stack lifespan...
|
DebuggerCoordinates coordinates) {
|
||||||
TraceStack curStack = coordinates.getTrace()
|
return BY_REG.affectedByRegisterChange(space, range, coordinates);
|
||||||
.getStackManager()
|
|
||||||
.getLatestStack(stack.getThread(), coordinates.getSnap());
|
|
||||||
if (stack != curStack) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@ import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.lang.RegisterValue;
|
import ghidra.program.model.lang.RegisterValue;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.TraceAddressSnapRange;
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.memory.TraceMemorySpace;
|
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||||
import ghidra.trace.model.memory.TraceMemoryState;
|
import ghidra.trace.model.memory.TraceMemoryState;
|
||||||
import ghidra.trace.model.stack.TraceStack;
|
import ghidra.trace.model.stack.TraceStack;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.util.TraceAddressSpace;
|
import ghidra.trace.util.TraceAddressSpace;
|
||||||
import ghidra.trace.util.TraceRegisterUtils;
|
|
||||||
|
|
||||||
// TODO: Use this, or allow arbitrary expressions
|
// TODO: Use this, or allow arbitrary expressions
|
||||||
public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||||
|
@ -45,10 +45,11 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates,
|
default Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates) {
|
||||||
long emuSnap) {
|
|
||||||
Trace trace = coordinates.getTrace();
|
Trace trace = coordinates.getTrace();
|
||||||
|
TracePlatform platform = coordinates.getPlatform();
|
||||||
TraceThread thread = coordinates.getThread();
|
TraceThread thread = coordinates.getThread();
|
||||||
|
long viewSnap = coordinates.getViewSnap();
|
||||||
long snap = coordinates.getSnap();
|
long snap = coordinates.getSnap();
|
||||||
int frame = coordinates.getFrame();
|
int frame = coordinates.getFrame();
|
||||||
Register reg = computeRegister(coordinates);
|
Register reg = computeRegister(coordinates);
|
||||||
|
@ -64,19 +65,19 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
RegisterValue value;
|
RegisterValue value;
|
||||||
if (regs.getState(emuSnap, reg) == TraceMemoryState.KNOWN) {
|
if (regs.getState(platform, viewSnap, reg) == TraceMemoryState.KNOWN) {
|
||||||
value = regs.getValue(emuSnap, reg);
|
value = regs.getValue(platform, viewSnap, reg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value = regs.getValue(snap, reg);
|
value = regs.getValue(platform, snap, reg);
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO: Action to select the address space
|
// TODO: Action to select the address space
|
||||||
// Could use code unit, but that can't specify space, yet, either....
|
// Could use code unit, but that can't specify space, yet, either....
|
||||||
return computeDefaultAddressSpace(coordinates)
|
return platform.mapGuestToHost(computeDefaultAddressSpace(coordinates)
|
||||||
.getAddress(value.getUnsignedValue().longValue(), true);
|
.getAddress(value.getUnsignedValue().longValue(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,7 +90,9 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec {
|
||||||
if (register == null) {
|
if (register == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AddressRange regRng = TraceRegisterUtils.rangeForRegister(register);
|
AddressSpace as = space.getAddressSpace();
|
||||||
|
AddressRange regRng = coordinates.getPlatform()
|
||||||
|
.getConventionalRegisterRange(as.isRegisterSpace() ? as : null, register);
|
||||||
return range.getRange().intersects(regRng);
|
return range.getRange().intersects(regRng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
|
|
||||||
public class SPLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
public class SPLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||||
public static final String CONFIG_NAME = "TRACK_SP";
|
public static final String CONFIG_NAME = "TRACK_SP";
|
||||||
|
@ -43,11 +43,11 @@ public class SPLocationTrackingSpec implements RegisterLocationTrackingSpec {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Register computeRegister(DebuggerCoordinates coordinates) {
|
public Register computeRegister(DebuggerCoordinates coordinates) {
|
||||||
Trace trace = coordinates.getTrace();
|
TracePlatform platform = coordinates.getPlatform();
|
||||||
if (trace == null) {
|
if (platform == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return trace.getBaseCompilerSpec().getStackPointer();
|
return platform.getCompilerSpec().getStackPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -201,6 +201,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void specChanged(LocationTrackingSpec spec) {
|
protected void specChanged(LocationTrackingSpec spec) {
|
||||||
|
updateTitle();
|
||||||
trackingSpecChangeListeners.fire.locationTrackingSpecChanged(spec);
|
trackingSpecChangeListeners.fire.locationTrackingSpecChanged(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,6 +1058,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
trackingTrait.goToCoordinates(coordinates);
|
trackingTrait.goToCoordinates(coordinates);
|
||||||
readsMemTrait.goToCoordinates(coordinates);
|
readsMemTrait.goToCoordinates(coordinates);
|
||||||
locationLabel.goToCoordinates(coordinates);
|
locationLabel.goToCoordinates(coordinates);
|
||||||
|
updateTitle();
|
||||||
contextChanged();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,11 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
protected void locationTracked() {
|
protected void locationTracked() {
|
||||||
doGoToTracked();
|
doGoToTracked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void specChanged(LocationTrackingSpec spec) {
|
||||||
|
updateTitle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ForMemoryBytesReadsMemoryTrait extends DebuggerReadsMemoryTrait {
|
protected class ForMemoryBytesReadsMemoryTrait extends DebuggerReadsMemoryTrait {
|
||||||
|
@ -324,6 +329,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
trackingTrait.goToCoordinates(coordinates);
|
trackingTrait.goToCoordinates(coordinates);
|
||||||
readsMemTrait.goToCoordinates(coordinates);
|
readsMemTrait.goToCoordinates(coordinates);
|
||||||
locationLabel.goToCoordinates(coordinates);
|
locationLabel.goToCoordinates(coordinates);
|
||||||
|
updateTitle();
|
||||||
contextChanged();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue