From b51d423d4bcfd5297db4f28794199b13a11bad9d Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Fri, 24 Mar 2023 14:41:12 -0400 Subject: [PATCH] GP-1539: Polish the DebuggerGoToDialog. Allow labels and plain addresses. --- .../DebuggerListingPlugin.html | 26 +++- .../images/DebuggerGoToDialog.png | Bin 12862 -> 7183 bytes .../DebuggerMemoryBytesPlugin.html | 8 +- .../DebuggerWatchesPlugin.html | 4 + .../debug/gui/action/DebuggerGoToDialog.java | 115 +++++++++------ .../debug/gui/action/DebuggerGoToTrait.java | 59 ++++++-- .../action/DebuggerTrackLocationTrait.java | 7 + .../core/debug/gui/action/GoToInput.java | 36 +++++ .../debug/gui/action/LocationTracker.java | 12 ++ .../gui/action/NoneLocationTrackingSpec.java | 10 ++ .../action/PCByStackLocationTrackingSpec.java | 12 ++ .../gui/action/PCLocationTrackingSpec.java | 7 + .../action/RegisterLocationTrackingSpec.java | 8 ++ .../gui/action/WatchLocationTrackingSpec.java | 37 +++-- .../WatchLocationTrackingSpecFactory.java | 1 + .../gui/listing/DebuggerListingProvider.java | 8 ++ .../memory/DebuggerMemoryBytesProvider.java | 7 +- .../plugin/core/debug/gui/watch/WatchRow.java | 9 +- .../ghidra/pcode/exec/DebuggerPcodeUtils.java | 136 +++++++++++++++++- .../DebuggerListingPluginScreenShots.java | 2 +- .../listing/DebuggerListingProviderTest.java | 16 ++- .../DebuggerMemoryBytesProviderTest.java | 4 +- .../pcode/exec/SleighProgramCompiler.java | 131 +++++++++++++++-- .../java/ghidra/pcode/exec/SleighUtils.java | 63 ++++++++ .../pcode/exec/SleighProgramCompilerTest.java | 104 ++++++++++++++ .../ghidra/pcode/exec/SleighUtilsTest.java | 38 ++++- .../program/model/lang/PcodeParser.java | 2 +- 27 files changed, 759 insertions(+), 103 deletions(-) create mode 100644 Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/GoToInput.java create mode 100644 Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html index 032f904f74..3fa2c7bdd5 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html @@ -134,10 +134,12 @@

Go To (G)

This action is available whenever a trace is active in the listing. It prompts the user for - an address, which can be expressed in Sleigh, then attempts to navigate to it. The expression - is evaluated in the context of the current thread, frame, and point in time. If the current - trace is live and at the present, the target may be queried to retrieve any machine state - required to evaluate the expression.

+ an address, which can be expressed in simple notation or Sleigh, then attempts to + navigate to it. The expression is evaluated in the context of the current thread, frame, and + point in time. If the current trace is live and at the present, the target may be queried to + retrieve any machine state required to evaluate the expression. The expression may be in terms + of labels, registers, and constants. Labels may come from the current trace or a program mapped + into the trace. Ambiguities are resolved arbitrarily.

@@ -147,6 +149,22 @@
+

Some examples:

+ + +

Auto-Sync Cursor with Static Listing

This action is always available, but only on the primary dynamic listing. It configures diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/images/DebuggerGoToDialog.png index bdbc14fccae3d440ae74edb4f0a0fca87e628dca..bfc2dca48c4d2567185624695ea7f0a9020f470a 100644 GIT binary patch literal 7183 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 y72U;UB<+n>{_h9Ifw~yz7Go To (G) -

This action is available whenever a trace is active in the window. It prompts the user for - an address, which can be expressed in Sleigh, then attempts to navigate to it. The expression - is evaluated in the context of the current thread, frame, and point in time. If the current - trace is live and at the present, the target may be queried to retrieve any machine state - required to evaluate the expression.

+

This action is equivalent to the same action in the Dynamic Listing + window.

diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html index fe19e146a1..6ad0c355f7 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html @@ -42,6 +42,10 @@ constant 0x7fff0004 is a known issue. Just use the target's pointer size in bytes — 8 in the example. +
  • *:4 my_global: Display 4 bytes starting at the label "my_global", e.g., to + read the int value there. The label may be in the trace or in a program mapped + to the trace. Ambiguities are resolved arbitrarily.
  • +
  • *:8 RSP: Display 8 bytes of [ram] starting at the offset given by register RSP, e.g., to read a long on the stack.
  • diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToDialog.java index ad93816bca..83907f0092 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToDialog.java @@ -16,65 +16,69 @@ package ghidra.app.plugin.core.debug.gui.action; import java.awt.BorderLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.*; -import javax.swing.border.EmptyBorder; -import docking.DialogComponentProvider; +import ghidra.app.plugin.core.debug.gui.DebuggerResources; +import ghidra.app.plugin.core.debug.gui.action.DebuggerGoToTrait.GoToResult; +import ghidra.app.plugin.core.debug.gui.breakpoint.AbstractDebuggerSleighInputDialog; +import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.async.AsyncUtils; -import ghidra.program.model.address.AddressFactory; -import ghidra.program.model.address.AddressSpace; -import ghidra.util.MessageType; -import ghidra.util.Msg; +import ghidra.framework.plugintool.util.PluginUtils; +import ghidra.pcode.exec.SleighUtils; +import ghidra.program.model.address.*; +import ghidra.trace.model.guest.TracePlatform; +import ghidra.util.*; -public class DebuggerGoToDialog extends DialogComponentProvider { +public class DebuggerGoToDialog extends AbstractDebuggerSleighInputDialog { + private static final String TEXT = """ + + +

    + Enter an address or Sleigh expression. Press F1 for help and examples. +

    + + + """; private final DebuggerGoToTrait trait; private final DefaultComboBoxModel modelSpaces; - final JTextField textExpression; final JComboBox comboSpaces; public DebuggerGoToDialog(DebuggerGoToTrait trait) { - super("Go To", true, true, true, false); + super("Go To", TEXT); + setHelpLocation(new HelpLocation( + PluginUtils.getPluginNameFromClass(DebuggerListingPlugin.class), + DebuggerResources.GoToAction.HELP_ANCHOR)); this.trait = trait; - textExpression = new JTextField(); modelSpaces = new DefaultComboBoxModel<>(); comboSpaces = new JComboBox<>(modelSpaces); - JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(new EmptyBorder(16, 16, 16, 16)); - JLabel help = new JLabel( - "Enter any sleigh expression to evaluate against the current thread.
    " + - "Note that constants and memory derefs must have a resolved size.
    " + - "Examples:
    " + - ""); - help.getMaximumSize().width = 400; - panel.add(help, BorderLayout.NORTH); - Box box = Box.createHorizontalBox(); - box.setBorder(new EmptyBorder(16, 0, 0, 0)); - panel.add(box); + Box hbox = Box.createHorizontalBox(); + hbox.add(comboSpaces); + hbox.add(new JLabel(":")); + panel.add(hbox, BorderLayout.WEST); - box.add(new JLabel("*[")); - box.add(comboSpaces); - box.add(new JLabel("]")); - box.add(textExpression); + setFocusComponent(textInput); - addWorkPanel(panel); - setFocusComponent(textExpression); - - addOKButton(); - addCancelButton(); + textInput.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + okCallback(); + e.consume(); + } + } + }); } protected void populateSpaces(SleighLanguage language) { @@ -94,19 +98,37 @@ public class DebuggerGoToDialog extends DialogComponentProvider { } } + @Override + protected void validate() { + TracePlatform platform = trait.current.getPlatform(); + if (platform == null) { + throw new AssertionError("No current trace platform"); + } + Address address = platform.getAddressFactory().getAddress(getInput()); + if (address != null) { + return; + } + SleighUtils.parseSleighExpression(getInput()); + } + @Override // public for tests public void okCallback() { - CompletableFuture future; + validateAndMarkup(); + if (!isValid) { + return; + } + + CompletableFuture future; try { - future = trait.goToSleigh((String) comboSpaces.getSelectedItem(), - textExpression.getText()); + future = trait.goTo((String) comboSpaces.getSelectedItem(), getInput()); } catch (Throwable t) { future = CompletableFuture.failedFuture(t); } - future.thenAccept(success -> { - if (!success) { - setStatusText("Address not in trace", MessageType.ERROR, true); + future.thenAccept(result -> { + if (!result.success()) { + setStatusText("Address " + result.address() + " not in trace", MessageType.ERROR, + true); } else { close(); @@ -124,12 +146,15 @@ public class DebuggerGoToDialog extends DialogComponentProvider { close(); } - public void show(SleighLanguage language) { + public void show(SleighLanguage language, GoToInput defaultInput) { populateSpaces(language); - trait.tool.showDialog(this); + if (language.getAddressFactory().getAddressSpace(defaultInput.space()) != null) { + comboSpaces.setSelectedItem(defaultInput.space()); + } + prompt(trait.tool, defaultInput.offset()); } - public void setExpression(String expression) { - textExpression.setText(expression); + public void setOffset(String offset) { + textInput.setText(offset); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java index 4cdea1eed0..bcf2f20b80 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerGoToTrait.java @@ -28,12 +28,17 @@ import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; import ghidra.pcode.exec.*; import ghidra.pcode.utils.Utils; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.*; import ghidra.program.model.lang.Language; import ghidra.trace.model.guest.TracePlatform; public abstract class DebuggerGoToTrait { + /** + * @see DebuggerGoToTrait#goTo(String, String) + */ + public record GoToResult(Address address, Boolean success) { + } + protected DockingAction action; protected final PluginTool tool; @@ -48,6 +53,8 @@ public abstract class DebuggerGoToTrait { this.provider = provider; } + protected abstract GoToInput getDefaultInput(); + protected abstract boolean goToAddress(Address address); public void goToCoordinates(DebuggerCoordinates coordinates) { @@ -66,25 +73,61 @@ public abstract class DebuggerGoToTrait { private void activatedGoTo(ActionContext context) { DebuggerGoToDialog goToDialog = new DebuggerGoToDialog(this); TracePlatform platform = current.getPlatform(); - goToDialog.show((SleighLanguage) platform.getLanguage()); + goToDialog.show((SleighLanguage) platform.getLanguage(), getDefaultInput()); } - public CompletableFuture goToSleigh(String spaceName, String expression) { + /** + * Go to the given address + * + *

    + * If parsing or evaluation fails, an exception is thrown, or the future completes + * exceptionally. If the address is successfully computed, then a result will be returned. The + * {@link GoToResult#address()} method gives the parsed or computed address. The + * {@link GoToResult#success()} method indicates whether the cursor was successfully set to that + * address. + * + * @param spaceName the name of the address space + * @param offset a simple offset or Sleigh expression + * @return the result + */ + public CompletableFuture goTo(String spaceName, String offset) { + TracePlatform platform = current.getPlatform(); + Language language = platform.getLanguage(); + AddressSpace space = language.getAddressFactory().getAddressSpace(spaceName); + if (space == null) { + throw new IllegalArgumentException("No such address space: " + spaceName); + } + try { + Address address = space.getAddress(offset); + if (address == null) { + address = language.getAddressFactory().getAddress(offset); + } + if (address != null) { + return CompletableFuture + .completedFuture(new GoToResult(address, goToAddress(address))); + } + } + catch (AddressFormatException e) { + // Fall-through to try Sleigh + } + return goToSleigh(spaceName, offset); + } + + protected CompletableFuture goToSleigh(String spaceName, String expression) { TracePlatform platform = current.getPlatform(); Language language = platform.getLanguage(); if (!(language instanceof SleighLanguage)) { throw new IllegalStateException("Current trace does not use Sleigh"); } - SleighLanguage slang = (SleighLanguage) language; AddressSpace space = language.getAddressFactory().getAddressSpace(spaceName); if (space == null) { throw new IllegalArgumentException("No such address space: " + spaceName); } - PcodeExpression expr = SleighProgramCompiler.compileExpression(slang, expression); + PcodeExpression expr = DebuggerPcodeUtils.compileExpression(tool, current, expression); return goToSleigh(platform, space, expr); } - public CompletableFuture goToSleigh(TracePlatform platform, AddressSpace space, + protected CompletableFuture goToSleigh(TracePlatform platform, AddressSpace space, PcodeExpression expression) { PcodeExecutor executor = DebuggerPcodeUtils.executorForCoordinates(tool, current); CompletableFuture result = @@ -92,7 +135,7 @@ public abstract class DebuggerGoToTrait { return result.thenApplyAsync(offset -> { Address address = space.getAddress( Utils.bytesToLong(offset, offset.length, expression.getLanguage().isBigEndian())); - return goToAddress(platform.mapGuestToHost(address)); + return new GoToResult(address, goToAddress(platform.mapGuestToHost(address))); }, AsyncUtils.SWING_EXECUTOR); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java index e9fcef819f..843d49f8ed 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java @@ -315,6 +315,13 @@ public class DebuggerTrackLocationTrait { action.setCurrentActionStateByUserData(spec); } + public GoToInput getDefaultGoToInput(ProgramLocation loc) { + if (tracker == null) { + return NoneLocationTrackingSpec.INSTANCE.getDefaultGoToInput(tool, current, loc); + } + return tracker.getDefaultGoToInput(tool, current, loc); + } + protected void locationTracked() { // Listener method } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/GoToInput.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/GoToInput.java new file mode 100644 index 0000000000..deede24f7d --- /dev/null +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/GoToInput.java @@ -0,0 +1,36 @@ +/* ### + * 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.program.model.address.Address; + +public record GoToInput(String space, String offset) { + public static GoToInput fromString(String string) { + if (string.contains(":")) { + String[] parts = string.split(":", 2); + return new GoToInput(parts[0], parts[1]); + } + return new GoToInput(null, string); + } + + public static GoToInput fromAddress(Address address) { + return new GoToInput(address.getAddressSpace().getName(), address.toString(false)); + } + + public static GoToInput offsetOnly(String offset) { + return new GoToInput(null, offset); + } +} diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LocationTracker.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LocationTracker.java index 6fa2bb3acc..b2750c8ca9 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LocationTracker.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/LocationTracker.java @@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; +import ghidra.program.util.ProgramLocation; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.stack.TraceStack; @@ -53,6 +54,17 @@ public interface LocationTracker { CompletableFuture

    computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates); + /** + * Get the suggested input if the user activates "Go To" while this tracker is active + * + * @param tool the tool containing the provider + * @param coordinates the user's current coordinates + * @param location the user's current location + * @return the suggested address or Sleigh expression + */ + GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location); + // TODO: Is there a way to generalize these so that other dependencies need not // have their own bespoke methods? diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneLocationTrackingSpec.java index f41121d0e8..443cb5896a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneLocationTrackingSpec.java @@ -24,6 +24,7 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction; import ghidra.async.AsyncUtils; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; +import ghidra.program.util.ProgramLocation; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.stack.TraceStack; import ghidra.trace.util.TraceAddressSpace; @@ -69,6 +70,15 @@ public enum NoneLocationTrackingSpec implements LocationTrackingSpec, LocationTr return AsyncUtils.nil(); } + @Override + public GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location) { + if (location == null) { + return GoToInput.fromString("00000000"); + } + return GoToInput.fromAddress(location.getAddress()); + } + @Override public boolean affectedByBytesChange(TraceAddressSpace space, TraceAddressSnapRange range, DebuggerCoordinates coordinates) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java index 996552df13..dee6cd3193 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java @@ -23,6 +23,7 @@ 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.util.ProgramLocation; import ghidra.trace.model.Trace; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.stack.TraceStack; @@ -87,6 +88,17 @@ public enum PCByStackLocationTrackingSpec implements LocationTrackingSpec, Locat return CompletableFuture.supplyAsync(() -> doComputeTraceAddress(tool, coordinates)); } + @Override + public GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location) { + Address address = doComputeTraceAddress(tool, coordinates); + if (address == null) { + return NoneLocationTrackingSpec.INSTANCE.getDefaultGoToInput(tool, coordinates, + location); + } + return GoToInput.fromAddress(address); + } + // Note it does no good to override affectByRegChange. It must do what we'd avoid anyway. @Override public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCLocationTrackingSpec.java index c2b69303cb..511800da22 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCLocationTrackingSpec.java @@ -23,6 +23,7 @@ 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.util.ProgramLocation; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.stack.TraceStack; import ghidra.trace.util.TraceAddressSpace; @@ -81,6 +82,12 @@ public enum PCLocationTrackingSpec implements LocationTrackingSpec, LocationTrac }); } + @Override + public GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location) { + return BY_REG.getDefaultGoToInput(tool, coordinates, location); + } + // Note it does no good to override affectByRegChange. It must do what we'd avoid anyway. @Override public boolean affectedByStackChange(TraceStack stack, DebuggerCoordinates coordinates) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java index 8af97f5b7c..7087147a73 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java @@ -22,6 +22,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; +import ghidra.program.util.ProgramLocation; import ghidra.trace.model.Trace; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.guest.TracePlatform; @@ -91,6 +92,13 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec, Loca return CompletableFuture.supplyAsync(() -> doComputeTraceAddress(tool, coordinates)); } + @Override + default GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location) { + Register register = computeRegister(coordinates); + return GoToInput.offsetOnly(register.getName()); + } + @Override default boolean affectedByBytesChange(TraceAddressSpace space, TraceAddressSnapRange range, DebuggerCoordinates coordinates) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpec.java index 527b200a63..62afdfc624 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpec.java @@ -24,15 +24,16 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.gui.DebuggerResources; import ghidra.app.plugin.core.debug.gui.DebuggerResources.TrackLocationAction; import ghidra.app.plugin.core.debug.gui.watch.WatchRow; -import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.async.AsyncUtils; import ghidra.framework.plugintool.PluginTool; import ghidra.pcode.exec.*; import ghidra.pcode.exec.DebuggerPcodeUtils.WatchValue; +import ghidra.pcode.exec.SleighUtils.AddressOf; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.lang.Language; +import ghidra.program.util.ProgramLocation; import ghidra.trace.model.TraceAddressSnapRange; +import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.stack.TraceStack; import ghidra.trace.util.TraceAddressSpace; @@ -44,6 +45,11 @@ public class WatchLocationTrackingSpec implements LocationTrackingSpec { public static final String CONFIG_PREFIX = "TRACK_WATCH_"; private final String expression; + private final String label; + + public static boolean isTrackable(WatchRow watch) { + return SleighUtils.recoverAddressOf(null, watch.getExpression()) != null; + } /** * Derive a tracking specification from the given watch @@ -62,6 +68,8 @@ public class WatchLocationTrackingSpec implements LocationTrackingSpec { */ public WatchLocationTrackingSpec(String expression) { this.expression = expression; + AddressOf addrOf = SleighUtils.recoverAddressOf(null, expression); + this.label = SleighUtils.generateSleighExpression(addrOf.offset()); } @Override @@ -97,7 +105,7 @@ public class WatchLocationTrackingSpec implements LocationTrackingSpec { @Override public String getLocationLabel() { - return "&watch"; + return label; } /** @@ -124,18 +132,27 @@ public class WatchLocationTrackingSpec implements LocationTrackingSpec { return AsyncUtils.nil(); } return CompletableFuture.supplyAsync(() -> { - Language language = current.getPlatform().getLanguage(); - if (!(language instanceof SleighLanguage slang)) { - return null; - } - if (compiled == null || compiled.getLanguage() != language) { - compiled = SleighProgramCompiler.compileExpression(slang, expression); - } + compiled = DebuggerPcodeUtils.compileExpression(tool, current, expression); WatchValue value = compiled.evaluate(asyncExec); return value == null ? null : value.address(); }); } + @Override + public GoToInput getDefaultGoToInput(PluginTool tool, DebuggerCoordinates coordinates, + ProgramLocation location) { + TracePlatform platform = current.getPlatform(); + String defaultSpace = + platform == null ? "ram" : platform.getLanguage().getDefaultSpace().getName(); + AddressOf addrOf = SleighUtils.recoverAddressOf(defaultSpace, expression); + if (addrOf == null) { + return NoneLocationTrackingSpec.INSTANCE.getDefaultGoToInput(tool, coordinates, + location); + } + return new GoToInput(addrOf.space(), + SleighUtils.generateSleighExpression(addrOf.offset())); + } + @Override public boolean affectedByBytesChange(TraceAddressSpace space, TraceAddressSnapRange range, DebuggerCoordinates coordinates) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpecFactory.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpecFactory.java index c5f4c7ad50..874afb0b82 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpecFactory.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/WatchLocationTrackingSpecFactory.java @@ -38,6 +38,7 @@ public class WatchLocationTrackingSpecFactory implements LocationTrackingSpecFac } return watchesService.getWatches() .stream() + .filter(WatchLocationTrackingSpec::isTrackable) .map(WatchLocationTrackingSpec::fromWatch) .collect(Collectors.toList()); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java index 148a749354..516e2393cd 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java @@ -184,8 +184,16 @@ public class DebuggerListingProvider extends CodeViewerProvider { DebuggerListingProvider.this); } + @Override + protected GoToInput getDefaultInput() { + return trackingTrait.getDefaultGoToInput(getLocation()); + } + @Override protected boolean goToAddress(Address address) { + if (syncTrait.isAutoSyncCursorWithStaticListing()) { + syncTrait.doAutoSyncCursorIntoStatic(new ProgramLocation(getProgram(), address)); + } return getListingPanel().goTo(address); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProvider.java index 4774bb093a..8f20f1dc9a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProvider.java @@ -103,13 +103,18 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi DebuggerMemoryBytesProvider.this); } + @Override + protected GoToInput getDefaultInput() { + return trackingTrait.getDefaultGoToInput(currentLocation); + } + @Override protected boolean goToAddress(Address address) { TraceProgramView view = current.getView(); if (view == null) { return false; } - return goTo(view, new ProgramLocation(view, address)); + return DebuggerMemoryBytesProvider.this.goTo(view, new ProgramLocation(view, address)); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java index 06184ea615..436536ff30 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/WatchRow.java @@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture; import db.Transaction; import ghidra.app.plugin.core.debug.DebuggerCoordinates; -import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DebuggerControlService; import ghidra.app.services.DebuggerControlService.StateEditor; @@ -96,7 +95,8 @@ public class WatchRow { return; } try { - compiled = SleighProgramCompiler.compileExpression(provider.language, expression); + compiled = DebuggerPcodeUtils.compileExpression(provider.getTool(), provider.current, + expression); } catch (Exception e) { error = e; @@ -106,7 +106,6 @@ public class WatchRow { protected void reevaluate() { blank(); - SleighLanguage language = provider.language; PcodeExecutor executor = provider.asyncWatchExecutor; PcodeExecutor prevExec = provider.prevValueExecutor; if (executor == null) { @@ -114,9 +113,7 @@ public class WatchRow { return; } CompletableFuture.runAsync(() -> { - if (compiled == null || compiled.getLanguage() != language) { - recompile(); - } + recompile(); if (compiled == null) { provider.contextChanged(); return; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java index b8948a7873..177857ed5f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java @@ -22,21 +22,34 @@ import java.util.Map.Entry; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.service.emulation.*; import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerAccess; +import ghidra.app.plugin.processors.sleigh.SleighException; import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.app.services.DebuggerStaticMappingService; import ghidra.framework.plugintool.PluginTool; import ghidra.pcode.emu.ThreadPcodeExecutorState; import ghidra.pcode.exec.PcodeArithmetic.Purpose; import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason; +import ghidra.pcode.exec.SleighProgramCompiler.ErrorCollectingPcodeParser; import ghidra.pcode.exec.trace.*; import ghidra.pcode.exec.trace.data.DefaultPcodeTraceAccess; import ghidra.pcode.exec.trace.data.PcodeTraceDataAccess; import ghidra.pcode.utils.Utils; +import ghidra.pcodeCPort.slghsymbol.SleighSymbol; +import ghidra.pcodeCPort.slghsymbol.VarnodeSymbol; import ghidra.program.model.address.*; import ghidra.program.model.lang.*; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolType; +import ghidra.program.util.ProgramLocation; +import ghidra.sleigh.grammar.Location; import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceLocation; import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.memory.TraceMemoryState; +import ghidra.trace.model.symbol.TraceSymbol; +import ghidra.trace.model.symbol.TraceSymbolWithLifespan; import ghidra.util.NumericUtilities; /** @@ -45,6 +58,120 @@ import ghidra.util.NumericUtilities; public enum DebuggerPcodeUtils { ; + /** + * A p-code parser that can resolve labels from a trace or its mapped programs. + */ + public static class LabelBoundPcodeParser extends ErrorCollectingPcodeParser { + record ProgSym(String sourceName, String nm, Address address) { + } + + private final DebuggerStaticMappingService mappings; + private final DebuggerCoordinates coordinates; + + /** + * Construct a parser bound to the given coordinates + * + * @param tool the tool for the mapping service + * @param coordinates the current coordinates for context + */ + public LabelBoundPcodeParser(PluginTool tool, DebuggerCoordinates coordinates) { + super((SleighLanguage) coordinates.getPlatform().getLanguage()); + this.mappings = tool.getService(DebuggerStaticMappingService.class); + this.coordinates = coordinates; + } + + protected SleighSymbol createSleighConstant(String sourceName, String nm, Address address) { + return new VarnodeSymbol(new Location(sourceName, 0), nm, getConstantSpace(), + address.getOffset(), address.getAddressSpace().getPointerSize()); + } + + @Override + public SleighSymbol findSymbol(String nm) { + SleighSymbol symbol = null; + try { + symbol = super.findSymbol(nm); + } + catch (SleighException e) { + // leave null + } + if (symbol == null) { + symbol = findUserSymbol(nm); + } + if (symbol == null) { + throw new SleighException("Unknown register or label: '" + nm + "'"); + } + return symbol; + } + + protected SleighSymbol findUserSymbol(String nm) { + Trace trace = coordinates.getTrace(); + long snap = coordinates.getSnap(); + for (TraceSymbol symbol : trace.getSymbolManager() + .labelsAndFunctions() + .getNamed(nm)) { + if (symbol instanceof TraceSymbolWithLifespan lifeSym && + !lifeSym.getLifespan().contains(snap)) { + continue; + } + return createSleighConstant(trace.getName(), nm, symbol.getAddress()); + } + for (Program program : mappings.getOpenMappedProgramsAtSnap(trace, snap)) { + for (Symbol symbol : program.getSymbolTable().getSymbols(nm)) { + if (symbol.isDynamic() || symbol.isExternal()) { + continue; + } + if (symbol.getSymbolType() != SymbolType.FUNCTION && + symbol.getSymbolType() != SymbolType.LABEL) { + continue; + } + TraceLocation tloc = mappings.getOpenMappedLocation(trace, + new ProgramLocation(program, symbol.getAddress()), snap); + if (tloc == null) { + return null; + } + return createSleighConstant(program.getName(), nm, tloc.getAddress()); + } + } + return null; + } + } + + /** + * Compile the given Sleigh source into a p-code program, resolving user labels + * + *

    + * The resulting program must only be used with a state bound to the same coordinates. Any + * symbols which are resolved to labels in the trace or its mapped programs are effectively + * substituted for their offsets. If a label moves, the program should be recompiled in order to + * update those substitutions. + * + * @param tool the tool for context + * @param coordinates the coordinates for the trace (and programs) from which labels can be + * resolved + * @see SleighProgramCompiler#compileProgram(PcodeParser, SleighLanguage, String, String, + * PcodeUseropLibrary) + */ + public static PcodeProgram compileProgram(PluginTool tool, DebuggerCoordinates coordinates, + String sourceName, String source, PcodeUseropLibrary library) { + return SleighProgramCompiler.compileProgram(new LabelBoundPcodeParser(tool, coordinates), + (SleighLanguage) coordinates.getPlatform().getLanguage(), sourceName, source, library); + } + + /** + * Compile the given Sleigh expression into a p-code program, resolving user labels + * + *

    + * This has the same limitations as + * {@link #compileProgram(PluginTool, DebuggerCoordinates, String, String, PcodeUseropLibrary)} + * + * @see SleighProgramCompiler#compileExpression(PcodeParser, SleighLanguage, String) + */ + public static PcodeExpression compileExpression(PluginTool tool, + DebuggerCoordinates coordinates, String source) { + return SleighProgramCompiler.compileExpression(new LabelBoundPcodeParser(tool, coordinates), + (SleighLanguage) coordinates.getPlatform().getLanguage(), source); + } + /** * Get a p-code executor state for the given coordinates * @@ -76,7 +203,8 @@ public enum DebuggerPcodeUtils { return shared; } PcodeExecutorState local = new RWTargetRegistersPcodeExecutorState( - access.getDataForLocalState(coordinates.getThread(), coordinates.getFrame()), Mode.RW); + access.getDataForLocalState(coordinates.getThread(), coordinates.getFrame()), + Mode.RW); return new ThreadPcodeExecutorState<>(shared, local) { @Override public void clear() { @@ -319,7 +447,8 @@ public enum DebuggerPcodeUtils { bytes.binaryOp(opcode, sizeout, sizein1, in1.bytes.bytes, sizein2, in2.bytes.bytes)), STATE.binaryOp(opcode, sizeout, sizein1, in1.state, sizein2, in2.state), - location.binaryOp(opcode, sizeout, sizein1, in1.location, sizein2, in2.location), + location.binaryOp(opcode, sizeout, sizein1, in1.location, sizein2, + in2.location), READS.binaryOp(opcode, sizeout, sizein1, in1.reads, sizein2, in2.reads)); } @@ -495,7 +624,8 @@ public enum DebuggerPcodeUtils { } @Override - public WatchValue getVar(AddressSpace space, WatchValue offset, int size, boolean quantize, + public WatchValue getVar(AddressSpace space, WatchValue offset, int size, + boolean quantize, Reason reason) { return piece.getVar(space, offset.bytes.bytes, size, quantize, reason); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java index eaeda76b88..841be8a71c 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingPluginScreenShots.java @@ -135,7 +135,7 @@ public class DebuggerListingPluginScreenShots extends GhidraScreenShotGenerator performAction(listingProvider.actionGoTo, false); DebuggerGoToDialog dialog = waitForDialogComponent(DebuggerGoToDialog.class); - dialog.setExpression("RAX"); + dialog.setOffset("RAX"); captureDialog(dialog); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index 0aed8791e5..4366be04a0 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -844,23 +844,31 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI waitForSwing(); assertTrue(listingProvider.actionGoTo.isEnabled()); + performAction(listingProvider.actionGoTo, false); DebuggerGoToDialog dialog1 = waitForDialogComponent(DebuggerGoToDialog.class); runSwing(() -> { - dialog1.setExpression("r0"); + dialog1.setOffset("00400123"); dialog1.okCallback(); }); - waitForPass( - () -> assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress())); + () -> assertEquals(tb.addr(0x00400123), listingProvider.getLocation().getAddress())); performAction(listingProvider.actionGoTo, false); DebuggerGoToDialog dialog2 = waitForDialogComponent(DebuggerGoToDialog.class); runSwing(() -> { - dialog2.setExpression("*:4 r0"); + dialog2.setOffset("r0"); dialog2.okCallback(); }); + waitForPass( + () -> assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress())); + performAction(listingProvider.actionGoTo, false); + DebuggerGoToDialog dialog3 = waitForDialogComponent(DebuggerGoToDialog.class); + runSwing(() -> { + dialog3.setOffset("*:4 r0"); + dialog3.okCallback(); + }); waitForPass( () -> assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress())); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java index 724f7888ad..233d8f73d0 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java @@ -629,7 +629,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge performAction(memBytesProvider.actionGoTo, false); DebuggerGoToDialog dialog1 = waitForDialogComponent(DebuggerGoToDialog.class); runSwing(() -> { - dialog1.setExpression("r0"); + dialog1.setOffset("r0"); dialog1.okCallback(); }); @@ -642,7 +642,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge performAction(memBytesProvider.actionGoTo, false); DebuggerGoToDialog dialog2 = waitForDialogComponent(DebuggerGoToDialog.class); runSwing(() -> { - dialog2.setExpression("*:4 r0"); + dialog2.setOffset("*:4 r0"); dialog2.okCallback(); }); diff --git a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighProgramCompiler.java b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighProgramCompiler.java index 54e80fe237..ae623db85a 100644 --- a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighProgramCompiler.java +++ b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighProgramCompiler.java @@ -16,11 +16,12 @@ package ghidra.pcode.exec; import java.io.IOException; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.template.ConstructTpl; +import ghidra.pcode.utils.MessageFormattingUtils; import ghidra.pcodeCPort.pcoderaw.VarnodeData; import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghsymbol.*; @@ -47,6 +48,94 @@ public enum SleighProgramCompiler { private static final String EXPRESSION_SOURCE_NAME = "expression"; public static final String NIL_SYMBOL_NAME = "__nil"; + public interface PcodeLogEntry { + public static String formatList(List list) { + return list.stream().map(e -> e.format()).collect(Collectors.joining("\n")); + } + + Location loc(); + + String msg(); + + String type(); + + default String format() { + return "%s: %s".formatted(type(), MessageFormattingUtils.format(loc(), msg())); + } + } + + record PcodeError(Location loc, String msg) implements PcodeLogEntry { + @Override + public String type() { + return "ERROR"; + } + } + + record PcodeWarning(Location loc, String msg) implements PcodeLogEntry { + @Override + public String type() { + return "WARNING"; + } + } + + public static class DetailedSleighException extends SleighException { + private final List details; + + public DetailedSleighException(List details) { + super(PcodeLogEntry.formatList(details)); + this.details = List.copyOf(details); + } + + public List getDetails() { + return details; + } + } + + /** + * A p-code parser that provides programmatic access to error diagnostics. + */ + public static class ErrorCollectingPcodeParser extends PcodeParser { + private final List entries = new ArrayList<>(); + + public ErrorCollectingPcodeParser(SleighLanguage language) { + super(language, UniqueLayout.INJECT.getOffset(language)); + } + + @Override + public void reportError(Location location, String msg) { + entries.add(new PcodeError(location, msg)); + super.reportError(location, msg); + } + + @Override + public void reportWarning(Location location, String msg) { + entries.add(new PcodeWarning(location, msg)); + super.reportWarning(location, msg); + } + + @Override + public ConstructTpl compilePcode(String pcodeStatements, String srcFile, int srcLine) + throws SleighException { + try { + return super.compilePcode(pcodeStatements, srcFile, srcLine); + } + finally { + if (getErrors() != 0) { + throw new DetailedSleighException(entries); + } + } + } + + @Override + public SleighSymbol findSymbol(String nm) { + SleighSymbol symbol = super.findSymbol(nm); + if (symbol == null) { + throw new SleighException("Unknown register: '" + nm + "'"); + } + return symbol; + } + } + /** * Create a p-code parser for the given language * @@ -54,7 +143,7 @@ public enum SleighProgramCompiler { * @return a parser */ public static PcodeParser createParser(SleighLanguage language) { - return new PcodeParser(language, UniqueLayout.INJECT.getOffset(language)); + return new ErrorCollectingPcodeParser(language); } /** @@ -69,7 +158,7 @@ public enum SleighProgramCompiler { */ public static ConstructTpl compileTemplate(Language language, PcodeParser parser, String sourceName, String source) { - return parser.compilePcode(source, EXPRESSION_SOURCE_NAME, 1); + return parser.compilePcode(source, sourceName, 1); } /** @@ -162,22 +251,22 @@ public enum SleighProgramCompiler { } /** - * Compile the given Sleigh source into a simple p-code program + * Compile the given Sleigh source into a simple p-code program with the given parser * *

    * This is suitable for modifying program state using Sleigh statements. Most likely, in * scripting, or perhaps in a Sleigh repl. The library given during compilation must match the * library given for execution, at least in its binding of userop IDs to symbols. * + * @param the parser to use * @param language the language of the target p-code machine * @param sourceName a diagnostic name for the Sleigh source * @param source the Sleigh source * @param library the userop library or stub library for binding userop symbols * @return the compiled p-code program */ - public static PcodeProgram compileProgram(SleighLanguage language, String sourceName, - String source, PcodeUseropLibrary library) { - PcodeParser parser = createParser(language); + public static PcodeProgram compileProgram(PcodeParser parser, SleighLanguage language, + String sourceName, String source, PcodeUseropLibrary library) { Map symbols = library.getSymbols(language); addParserSymbols(parser, symbols); @@ -186,7 +275,18 @@ public enum SleighProgramCompiler { } /** - * Compile the given Sleigh expression into a p-code program that can evaluate it + * Compile the given Sleigh source into a simple p-code program + * + * @see #compileProgram(PcodeParser, SleighLanguage, String, String, PcodeUseropLibrary) + */ + public static PcodeProgram compileProgram(SleighLanguage language, String sourceName, + String source, PcodeUseropLibrary library) { + return compileProgram(createParser(language), language, sourceName, source, library); + } + + /** + * Compile the given Sleigh expression into a p-code program that can evaluate it, using the + * given parser * *

    * TODO: Currently, expressions cannot be compiled for a user-supplied userop library. The @@ -198,8 +298,8 @@ public enum SleighProgramCompiler { * @return a p-code program whose {@link PcodeExpression#evaluate(PcodeExecutor)} method will * evaluate the expression on the given executor and its state. */ - public static PcodeExpression compileExpression(SleighLanguage language, String expression) { - PcodeParser parser = createParser(language); + public static PcodeExpression compileExpression(PcodeParser parser, SleighLanguage language, + String expression) { Map symbols = PcodeExpression.CAPTURING.getSymbols(language); addParserSymbols(parser, symbols); @@ -208,6 +308,15 @@ public enum SleighProgramCompiler { return constructProgram(PcodeExpression::new, language, template, symbols); } + /** + * Compile the given Sleigh expression into a p-code program that can evaluate it + * + * @see #compileExpression(PcodeParser, SleighLanguage, String) + */ + public static PcodeExpression compileExpression(SleighLanguage language, String expression) { + return compileExpression(createParser(language), language, expression); + } + /** * Generate a Sleigh symbol for context when compiling a userop definition * diff --git a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighUtils.java b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighUtils.java index 52332022fc..b0c0251289 100644 --- a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighUtils.java +++ b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighUtils.java @@ -290,6 +290,39 @@ public enum SleighUtils { }); } + public static void matchDereference(Tree tree, Consumer onSpace, Consumer onSize, + Consumer onOffset) { + switch (tree.getChildCount()) { + case 3: + match(tree, SleighParser.OP_DEREFERENCE, onSpace, onSize, onOffset); + return; + case 2: + Tree child0 = tree.getChild(0); + switch (child0.getType()) { + case SleighParser.OP_IDENTIFIER: + match(tree, SleighParser.OP_DEREFERENCE, onSpace, onOffset); + return; + case SleighParser.OP_BIN_CONSTANT: + case SleighParser.OP_DEC_CONSTANT: + case SleighParser.OP_HEX_CONSTANT: + match(tree, SleighParser.OP_DEREFERENCE, onSize, onOffset); + return; + default: + throw new AssertionError( + "OP_DEREFERENCE with 2 children where child[0] is " + + SleighParser.tokenNames[child0.getType()]); + } + case 1: + match(tree, SleighParser.OP_DEREFERENCE, onOffset); + return; + default: + // Likely, the op is mismatched. Ensure the error message says so. + match(tree, SleighParser.OP_DEREFERENCE); + throw new AssertionError( + "OP_DEREFERENCE with " + tree.getChildCount() + " children"); + } + } + /** * Check if the given tree represents an unconditional breakpoint in the emulator * @@ -390,6 +423,36 @@ public enum SleighUtils { } } + public record AddressOf(String space, Tree offset) { + } + + public static AddressOf recoverAddressOf(String defaultSpace, Tree tree) { + var l = new Object() { + String space = defaultSpace; + Tree offset; + }; + matchDereference(tree, wantSpaceId -> { + match(wantSpaceId, SleighParser.OP_IDENTIFIER, id -> { + l.space = getIdentifier(id); + }); + }, wantSize -> { + // I don't care about size + }, wantOffset -> { + l.offset = wantOffset; + }); + return new AddressOf(l.space, removeParenthesisTree(Objects.requireNonNull(l.offset))); + } + + public static AddressOf recoverAddressOf(String defaultSpace, String expression) { + try { + Tree tree = parseSleighExpression(expression); + return recoverAddressOf(defaultSpace, tree); + } + catch (SleighParseError | MismatchException e) { + return null; + } + } + /** * Synthesize a tree (node) * diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java new file mode 100644 index 0000000000..a0c9b6124d --- /dev/null +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java @@ -0,0 +1,104 @@ +/* ### + * 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.pcode.exec; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import generic.Unique; +import generic.test.AbstractGTest; +import ghidra.GhidraTestApplicationLayout; +import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.app.plugin.processors.sleigh.SleighLanguageHelper; +import ghidra.framework.Application; +import ghidra.framework.ApplicationConfiguration; +import ghidra.pcode.exec.SleighProgramCompiler.DetailedSleighException; +import ghidra.pcode.exec.SleighProgramCompiler.PcodeLogEntry; +import ghidra.sleigh.grammar.Location; +import utility.function.ExceptionalCallback; + +public class SleighProgramCompilerTest extends AbstractGTest { + protected T rfail(String message) { + fail(message); + throw new AssertionError(); + } + + protected E expect(Class cls, ExceptionalCallback cb) { + try { + cb.call(); + } + catch (Throwable e) { + if (!cls.isInstance(e)) { + e.printStackTrace(); + return rfail("Expected " + cls + ". Got " + e.getClass()); + } + return cls.cast(e); + } + return rfail("Expected " + cls + ". Got success"); + } + + @Before + public void setUp() throws IOException { + if (!Application.isInitialized()) { + Application.initializeApplication( + new GhidraTestApplicationLayout(new File(getTestDirectoryPath())), + new ApplicationConfiguration()); + } + } + + @Test + public void testCompileProgramErrLocations() throws Throwable { + SleighLanguage language = SleighLanguageHelper.getMockBE64Language(); + DetailedSleighException exc = expect(DetailedSleighException.class, () -> { + PcodeProgram program = + SleighProgramCompiler.compileProgram(language, "test", "noreg = noreg;", + PcodeUseropLibrary.NIL); + // Shouldn't get here, but if we do, I'd like to see the program: + System.err.println(program); + }); + PcodeLogEntry entry = Unique.assertOne(exc.getDetails()); + Location loc = entry.loc(); + assertEquals("test", loc.filename); + assertEquals(1, loc.lineno); + assertEquals( + "unknown start, end, next2, operand, epsilon, or varnode 'noreg' in varnode reference", + entry.msg()); + } + + @Test + public void testCompileExpressionErrLocations() throws Throwable { + SleighLanguage language = SleighLanguageHelper.getMockBE64Language(); + DetailedSleighException exc = expect(DetailedSleighException.class, () -> { + PcodeProgram program = SleighProgramCompiler.compileExpression(language, "noreg"); + // Shouldn't get here, but if we do, I'd like to see the program: + System.err.println(program); + }); + PcodeLogEntry entry = Unique.assertOne(exc.getDetails()); + // TODO: It'd be nice if loc included a column number and token length + Location loc = entry.loc(); + assertEquals("expression", loc.filename); + assertEquals(1, loc.lineno); + assertEquals( + "unknown start, end, next2, operand, epsilon, or varnode 'noreg' in varnode reference", + entry.msg()); + } +} diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighUtilsTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighUtilsTest.java index 38c90810ef..43fb5a60cd 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighUtilsTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighUtilsTest.java @@ -15,13 +15,13 @@ */ package ghidra.pcode.exec; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.tree.Tree; import org.junit.Test; +import ghidra.pcode.exec.SleighUtils.AddressOf; import ghidra.pcode.exec.SleighUtils.SleighParseError; public class SleighUtilsTest { @@ -63,6 +63,40 @@ public class SleighUtilsTest { } } + @Test + public void testRecoverAddressOfMismatchErr() { + AddressOf addrOf = SleighUtils.recoverAddressOf(null, "ptr + 8"); + assertNull(addrOf); + } + + @Test + public void testRecoverAddressOfForm1() { + AddressOf addrOf = SleighUtils.recoverAddressOf(null, "*ptr"); + assertEquals(null, addrOf.space()); + assertEquals("ptr", SleighUtils.generateSleighExpression(addrOf.offset())); + } + + @Test + public void testRecoverAddressOfForm2a() { + AddressOf addrOf = SleighUtils.recoverAddressOf(null, "*:8 ptr"); + assertEquals(null, addrOf.space()); + assertEquals("ptr", SleighUtils.generateSleighExpression(addrOf.offset())); + } + + @Test + public void testRecoverAddressOfForm2b() { + AddressOf addrOf = SleighUtils.recoverAddressOf(null, "*[ram] ptr"); + assertEquals("ram", addrOf.space()); + assertEquals("ptr", SleighUtils.generateSleighExpression(addrOf.offset())); + } + + @Test + public void testRecoverAddressOfForm3() { + AddressOf addrOf = SleighUtils.recoverAddressOf(null, "*[ram]:8 ptr"); + assertEquals("ram", addrOf.space()); + assertEquals("ptr", SleighUtils.generateSleighExpression(addrOf.offset())); + } + @Test public void testRecoverConditionEqDec() { assertEquals("RAX == 0", diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java index 8e64c318a8..19d8622dd6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java @@ -155,7 +155,7 @@ public class PcodeParser extends PcodeCompile { if (sym != null) { return sym; } - return PcodeParser.this.sleigh.findSymbol(nm); + return sleigh.findSymbol(nm); } public SleighBase getSleigh() {