From 8ab6690dff9616dcb9bcead848323b70c5bce681 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Mon, 27 Jun 2022 14:32:19 -0400 Subject: [PATCH] GP-0: Fixed various Debugger and Assembler test issues --- .../AbstractTracePatchInstructionAction.java | 7 +++-- .../DebuggerDisassemblerPluginTestHelper.java | 27 +++++++++++++++++++ .../disassemble/DebuggerDisassemblyTest.java | 20 ++++++-------- ...ggerStateEditingPluginIntegrationTest.java | 17 +++++++++--- .../core/assembler/AssemblyDualTextField.java | 6 ++--- .../core/assembler/PatchDataAction.java | 3 +-- .../assembler/AssemblerPluginTestHelper.java | 2 +- .../autocomplete/TextFieldAutocompleter.java | 7 +++++ .../sleigh/AbstractAssemblyTest.java | 14 +++++----- .../assembler/sleigh/AssemblyTestCase.java | 11 ++++---- 10 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPluginTestHelper.java diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/AbstractTracePatchInstructionAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/AbstractTracePatchInstructionAction.java index e0a00e2cee..316ecca896 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/AbstractTracePatchInstructionAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/AbstractTracePatchInstructionAction.java @@ -63,7 +63,8 @@ public abstract class AbstractTracePatchInstructionAction extends PatchInstructi public void setAddress(Address address) { super.setAddress(address); RegisterValue rv = getContextValue(getCodeUnit()); - ctx = AssemblyPatternBlock.fromRegisterValue(rv).fillMask(); + ctx = rv == null ? AssemblyPatternBlock.nop() + : AssemblyPatternBlock.fromRegisterValue(rv).fillMask(); } }; } @@ -126,7 +127,9 @@ public abstract class AbstractTracePatchInstructionAction extends PatchInstructi view.getMemory().setBytes(address, data); // This invalidates cu AddressSetView set = new AddressSet(address, address.add(data.length - 1)); TraceDisassembleCommand dis = new TraceDisassembleCommand(platform, address, set); - dis.setInitialContext(contextValue); + if (contextValue != null) { + dis.setInitialContext(contextValue); + } dis.run(tool, view); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPluginTestHelper.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPluginTestHelper.java new file mode 100644 index 0000000000..bf3a77d024 --- /dev/null +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPluginTestHelper.java @@ -0,0 +1,27 @@ +/* ### + * 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.disassemble; + +import ghidra.app.plugin.core.assembler.AssemblerPluginTestHelper; +import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; +import ghidra.program.model.listing.Program; + +public class DebuggerDisassemblerPluginTestHelper extends AssemblerPluginTestHelper { + public DebuggerDisassemblerPluginTestHelper(DebuggerDisassemblerPlugin disassemblerPlugin, + CodeViewerProvider provider, Program program) { + super(disassemblerPlugin.actionPatchInstruction, null, provider, program); + } +} diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java index e7a6ed91db..26743059c7 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java @@ -428,9 +428,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerGUITest new ProgramSelection(start, start.addWrap(1)), null); assertTrue(disassemblerPlugin.actionPatchInstruction.isEnabledForContext(actionContext)); - AssemblerPluginTestHelper helper = - new AssemblerPluginTestHelper(disassemblerPlugin.actionPatchInstruction, null, - listingProvider, tb.trace.getProgramView()); + DebuggerDisassemblerPluginTestHelper helper = new DebuggerDisassemblerPluginTestHelper( + disassemblerPlugin, listingProvider, tb.trace.getProgramView()); Instruction result = helper.patchInstructionAt(start, "andeq r0,r0,r0", "bx lr"); assertArrayEquals(tb.arr(0x1e, 0xff, 0x2f, 0xe1), result.getBytes()); @@ -466,9 +465,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerGUITest new ProgramSelection(start, start.addWrap(1)), null); assertTrue(disassemblerPlugin.actionPatchInstruction.isEnabledForContext(actionContext)); - AssemblerPluginTestHelper helper = - new AssemblerPluginTestHelper(disassemblerPlugin.actionPatchInstruction, null, - listingProvider, tb.trace.getProgramView()); + DebuggerDisassemblerPluginTestHelper helper = new DebuggerDisassemblerPluginTestHelper( + disassemblerPlugin, listingProvider, tb.trace.getProgramView()); Instruction result = helper.patchInstructionAt(start, "movs r0,r0", "bx lr"); assertArrayEquals(tb.arr(0x70, 0x47), result.getBytes()); @@ -502,9 +500,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerGUITest new ProgramSelection(start, start.addWrap(1)), null); assertTrue(disassemblerPlugin.actionPatchInstruction.isEnabledForContext(actionContext)); - AssemblerPluginTestHelper helper = - new AssemblerPluginTestHelper(disassemblerPlugin.actionPatchInstruction, null, - listingProvider, tb.trace.getProgramView()); + DebuggerDisassemblerPluginTestHelper helper = new DebuggerDisassemblerPluginTestHelper( + disassemblerPlugin, listingProvider, tb.trace.getProgramView()); Instruction result = helper.patchInstructionAt(start, "andeq r0,r0,r0", "bx lr"); assertArrayEquals(tb.arr(0x1e, 0xff, 0x2f, 0xe1), result.getBytes()); @@ -543,9 +540,8 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerGUITest new ProgramSelection(start, start.addWrap(1)), null); assertTrue(disassemblerPlugin.actionPatchInstruction.isEnabledForContext(actionContext)); - AssemblerPluginTestHelper helper = - new AssemblerPluginTestHelper(disassemblerPlugin.actionPatchInstruction, null, - listingProvider, tb.trace.getProgramView()); + DebuggerDisassemblerPluginTestHelper helper = new DebuggerDisassemblerPluginTestHelper( + disassemblerPlugin, listingProvider, tb.trace.getProgramView()); Instruction result = helper.patchInstructionAt(start, "movs r0,r0", "bx lr"); assertArrayEquals(tb.arr(0x70, 0x47), result.getBytes()); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/editing/DebuggerStateEditingPluginIntegrationTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/editing/DebuggerStateEditingPluginIntegrationTest.java index 9587ca6d52..d4be04f87d 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/editing/DebuggerStateEditingPluginIntegrationTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/editing/DebuggerStateEditingPluginIntegrationTest.java @@ -33,6 +33,8 @@ import ghidra.app.plugin.core.assembler.AssemblerPlugin; import ghidra.app.plugin.core.assembler.AssemblerPluginTestHelper; import ghidra.app.plugin.core.clipboard.ClipboardPlugin; import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; +import ghidra.app.plugin.core.debug.disassemble.DebuggerDisassemblerPlugin; +import ghidra.app.plugin.core.debug.disassemble.DebuggerDisassemblerPluginTestHelper; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin; import ghidra.app.services.DebuggerStateEditingService; @@ -43,6 +45,7 @@ import ghidra.program.util.ProgramLocation; import ghidra.trace.database.DBTraceUtils; import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.program.TraceVariableSnapProgramView; +import ghidra.util.Swing; import ghidra.util.database.UndoableTransaction; /** @@ -58,7 +61,8 @@ public class DebuggerStateEditingPluginIntegrationTest extends AbstractGhidraHea @Test public void testPatchInstructionActionInDynamicListingEmu() throws Throwable { DebuggerListingPlugin listingPlugin = addPlugin(tool, DebuggerListingPlugin.class); - AssemblerPlugin assemblerPlugin = addPlugin(tool, AssemblerPlugin.class); + DebuggerDisassemblerPlugin disassemblerPlugin = + addPlugin(tool, DebuggerDisassemblerPlugin.class); DebuggerStateEditingPlugin editingPlugin = addPlugin(tool, DebuggerStateEditingPlugin.class); DebuggerStateEditingService editingService = @@ -73,13 +77,17 @@ public class DebuggerStateEditingPluginIntegrationTest extends AbstractGhidraHea tb.trace.getMemoryManager() .createRegion("Memory[bin:.text]", 0, tb.range(0x00400000, 0x00401000), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)); + // Dynamic Patch Instruction requires existing code unit for context + tb.addInstruction(0, tb.addr(0x00400123), tb.host); } CodeViewerProvider listingProvider = listingPlugin.getProvider(); - AssemblerPluginTestHelper helper = - new AssemblerPluginTestHelper(assemblerPlugin, listingProvider, view); + DebuggerDisassemblerPluginTestHelper helper = + new DebuggerDisassemblerPluginTestHelper(disassemblerPlugin, listingProvider, view); traceManager.activateTrace(tb.trace); + Swing.runNow( + () -> listingProvider.goTo(view, new ProgramLocation(view, tb.addr(0x00400123)))); waitForSwing(); assertTrue(editingPlugin.actionEditMode.isEnabled()); @@ -96,7 +104,8 @@ public class DebuggerStateEditingPluginIntegrationTest extends AbstractGhidraHea assertTrue( helper.patchInstructionAction.isAddToPopup(listingProvider.getActionContext(null))); - Instruction ins = helper.patchInstructionAt(tb.addr(0x00400123), "", "imm r0,#1234"); + Instruction ins = + helper.patchInstructionAt(tb.addr(0x00400123), "imm r0,#0x0", "imm r0,#1234"); assertEquals(2, ins.getLength()); long snap = traceManager.getCurrent().getViewSnap(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java index ee226a3149..9d5e8792f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java @@ -719,14 +719,14 @@ public class AssemblyDualTextField { * If text parses and assembles, then the completion set will include assembled instruction-byte * entries. Note that there may still be valid textual completions to continue the instruction. * The suggestions yielded by all syntax errors are used to create textual completions. If the - * suggestion is prefixed by the buffer where the syntax error ocurred, then, the tail of that + * suggestion is prefixed by the buffer where the syntax error occurred, then, the tail of that * suggestion is made into a completion entry. * * @param text the prefix * @return the collection of completion items */ protected Collection computeCompletions(String text) { - final AssemblyPatternBlock ctx = getContext(); + final AssemblyPatternBlock ctx = Objects.requireNonNull(getContext()); Set result = new TreeSet<>(); Collection parses = assembler.parseLine(text); @@ -748,7 +748,7 @@ public class AssemblyDualTextField { for (AssemblyParseResult parse : parses) { if (!parse.isError()) { AssemblyResolutionResults sems = - assembler.resolveTree(parse, address, getContext()); + assembler.resolveTree(parse, address, ctx); for (AssemblyResolution ar : sems) { if (ar.isError()) { //result.add(new AssemblyError("", ar.toString())); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java index c4b5e8286d..4951dbb01b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java @@ -45,8 +45,6 @@ public class PatchDataAction extends AbstractPatchAction { /*test*/ final JTextField input = new JTextField(); - private Data data; - public PatchDataAction(Plugin owner) { this(owner, "Patch Data"); } @@ -119,6 +117,7 @@ public class PatchDataAction extends AbstractPatchAction { public void accept() { Program program = getProgram(); Address address = getAddress(); + Data data = getData(); DataType dt = data.getBaseDataType(); /** * Do as much outside the transaction as possible. The tool tends to steal focus away upon diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/assembler/AssemblerPluginTestHelper.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/assembler/AssemblerPluginTestHelper.java index 9e81d81812..2466345229 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/assembler/AssemblerPluginTestHelper.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/assembler/AssemblerPluginTestHelper.java @@ -82,7 +82,7 @@ public class AssemblerPluginTestHelper { AbstractGenericTest.runSwing(() -> { instructionInput.setText(text); instructionInput.auto.startCompletion(instructionInput.getOperandsField()); - instructionInput.auto.flushUpdates(); + instructionInput.auto.updateNow(); }); return AbstractGenericTest.waitForValue(() -> AbstractGenericTest.runSwing(() -> { List suggestions = instructionInput.auto.getSuggestions(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java index d1a153a307..4188b2abda 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java @@ -755,6 +755,13 @@ public class TextFieldAutocompleter { updateManager.flush(); } + /** + * Update the completion list immediately + */ + public void updateNow() { + updateManager.updateNow(); + } + /** * Cause the suggestion at the given index to be selected * diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AbstractAssemblyTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AbstractAssemblyTest.java index 67902fa3bd..ced28f6272 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AbstractAssemblyTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AbstractAssemblyTest.java @@ -200,7 +200,8 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest { */ protected void checkAllExact(AssemblyResolutionResults rr, Collection disassembly, long addr, String ctxstr) { - final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefault() + Address address = lang.getDefaultSpace().getAddress(addr); + final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address) : AssemblyPatternBlock.fromString(ctxstr)).fillMask(); dbg.println("Checking each: " + disassembly + " ctx:" + ctx); boolean gotOne = false; @@ -316,6 +317,7 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest { protected void runTest(String assembly, String instr, Collection disassembly, long addr, String ctxstr, boolean checkOneCompat, boolean checkAllExact, boolean checkAllSyntaxErrs, boolean checkAllSemanticErrs) { + Address address = lang.getDefaultSpace().getAddress(addr); // A sanity check, first if (instr != null) { @@ -323,9 +325,8 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest { if (!ins.isFullMask()) { throw new RuntimeException("Desired instruction bytes should be fully-defined"); } - final AssemblyPatternBlock ctx = - (ctxstr == null ? context.getDefault() : AssemblyPatternBlock.fromString(ctxstr)) - .fillMask(); + final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address) + : AssemblyPatternBlock.fromString(ctxstr)).fillMask(); try { String disstr; PseudoInstruction psins = disassemble(addr, ins.getVals(), ctx.getVals()); @@ -374,12 +375,11 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest { try { if (ctxstr == null) { - assembler.assembleLine(lang.getDefaultSpace().getAddress(addr), assembly); + assembler.assembleLine(address, assembly); } else { SleighAssembler sas = (SleighAssembler) assembler; - sas.assembleLine(lang.getDefaultSpace().getAddress(addr), assembly, - AssemblyPatternBlock.fromString(ctxstr)); + sas.assembleLine(address, assembly, AssemblyPatternBlock.fromString(ctxstr)); } } catch (AssemblySemanticException e) { diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AssemblyTestCase.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AssemblyTestCase.java index ffd56c9349..67d688601f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AssemblyTestCase.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/AssemblyTestCase.java @@ -207,7 +207,8 @@ public abstract class AssemblyTestCase extends AbstractGenericTest { */ protected void checkAllExact(AssemblyResolutionResults rr, Collection disassembly, long addr, String ctxstr) { - final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefault() + Address address = lang.getDefaultSpace().getAddress(addr); + final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address) : AssemblyPatternBlock.fromString(ctxstr)).fillMask(); dbg.println("Checking each: " + disassembly + " ctx:" + ctx); boolean gotOne = false; @@ -323,6 +324,7 @@ public abstract class AssemblyTestCase extends AbstractGenericTest { protected void runTest(String assembly, String instr, Collection disassembly, long addr, String ctxstr, boolean checkOneCompat, boolean checkAllExact, boolean checkAllSyntaxErrs, boolean checkAllSemanticErrs) { + Address address = lang.getDefaultSpace().getAddress(addr); // A sanity check, first if (instr != null) { @@ -330,7 +332,7 @@ public abstract class AssemblyTestCase extends AbstractGenericTest { if (!ins.isFullMask()) { throw new RuntimeException("Desired instruction bytes should be fully-defined"); } - final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefault() + final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address) : AssemblyPatternBlock.fromString(ctxstr)).fillMask(); try { String disstr; @@ -380,12 +382,11 @@ public abstract class AssemblyTestCase extends AbstractGenericTest { try { if (ctxstr == null) { - assembler.assembleLine(lang.getDefaultSpace().getAddress(addr), assembly); + assembler.assembleLine(address, assembly); } else { SleighAssembler sas = (SleighAssembler) assembler; - sas.assembleLine(lang.getDefaultSpace().getAddress(addr), assembly, - AssemblyPatternBlock.fromString(ctxstr)); + sas.assembleLine(address, assembly, AssemblyPatternBlock.fromString(ctxstr)); } } catch (AssemblySemanticException e) {