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 fcda0299da..876ff130fc 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 @@ -17,7 +17,9 @@ package ghidra.app.plugin.core.assembler; import java.awt.*; import java.awt.event.*; +import java.math.BigInteger; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; import javax.swing.*; @@ -37,11 +39,14 @@ import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParseErrorResult; import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParseResult; import ghidra.app.plugin.assembler.sleigh.sem.*; import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.util.viewer.field.ListingColors; import ghidra.framework.Application; import ghidra.framework.ApplicationConfiguration; import ghidra.program.model.address.Address; -import ghidra.program.model.lang.LanguageID; -import ghidra.program.model.listing.Instruction; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.ByteMemBufferImpl; +import ghidra.util.Msg; import ghidra.util.NumericUtilities; /** @@ -62,11 +67,11 @@ import ghidra.util.NumericUtilities; */ public class AssemblyDualTextField { private static final String FONT_ID = "font.plugin.assembly.dual.text.field"; - private static Color FG_PREFERENCE_MOST = + private static final Color FG_PREFERENCE_MOST = new GColor("color.fg.plugin.assembler.completion.most"); - private static Color FG_PREFERENCE_MIDDLE = + private static final Color FG_PREFERENCE_MIDDLE = new GColor("color.fg.plugin.assembler.completion.middle"); - private static Color FG_PREFERENCE_LEAST = + private static final Color FG_PREFERENCE_LEAST = new GColor("color.fg.plugin.assembler.completion.least"); protected final TextFieldLinker linker = new TextFieldLinker(); @@ -175,6 +180,34 @@ public class AssemblyDualTextField { } } + static class ContextChanges implements DisassemblerContextAdapter { + private final RegisterValue contextIn; + private final Map
contextsOut = new TreeMap<>(); + + public ContextChanges(RegisterValue contextIn) { + this.contextIn = contextIn; + } + + @Override + public RegisterValue getRegisterValue(Register register) { + if (register.getBaseRegister() == contextIn.getRegister()) { + return contextIn.getRegisterValue(register); + } + return null; + } + + @Override + public void setFutureRegisterValue(Address address, RegisterValue value) { + RegisterValue current = contextsOut.get(address); + RegisterValue combined = current == null ? value : current.combineValues(value); + contextsOut.put(address, combined); + } + + public void addFlow(ProgramContext progCtx, Address after) { + contextsOut.put(after, progCtx.getFlowValue(contextIn)); + } + } + /** * Represents an encoding for a complete assembly instruction * @@ -183,15 +216,50 @@ public class AssemblyDualTextField { * listener. */ static class AssemblyInstruction extends AssemblyCompletion { - private byte[] data; + private final byte[] data; + private final ContextChanges contextChanges; - public AssemblyInstruction(String text, byte[] data, int preference) { + public AssemblyInstruction(Program program, Language language, Address at, String text, + byte[] data, RegisterValue ctxVal, int preference) { // TODO?: Description to display constructor tree information super("", NumericUtilities.convertBytesToString(data, " "), preference == 10000 ? FG_PREFERENCE_MOST : preference == 5000 ? FG_PREFERENCE_MIDDLE : FG_PREFERENCE_LEAST, -preference); this.data = data; + this.contextChanges = new ContextChanges(ctxVal); + + try { + if (program != null) { + // Handle flow context first + contextChanges.addFlow(program.getProgramContext(), at.addWrap(data.length)); + // drop prototype, just want context changes (globalsets) + language.parse(new ByteMemBufferImpl(at, data, language.isBigEndian()), + contextChanges, false); + } + } + catch (InsufficientBytesException | UnknownInstructionException e) { + Msg.error(this, "Cannot disassembly just-assembled instruction?: " + + NumericUtilities.convertBytesToString(data)); + } + adjustOrderByContextChanges(program); + } + + private void adjustOrderByContextChanges(Program program) { + if (program == null) { + return; + } + ProgramContext ctx = program.getProgramContext(); + Register ctxReg = ctx.getBaseContextRegister(); + for (Entry ent : contextChanges.contextsOut.entrySet()) { + RegisterValue defVal = ctx.getDefaultDisassemblyContext(); + RegisterValue newVal = defVal.combineValues(ent.getValue()); + RegisterValue curVal = + defVal.combineValues(ctx.getRegisterValue(ctxReg, ent.getKey())); + BigInteger changed = + newVal.getUnsignedValueIgnoreMask().xor(curVal.getUnsignedValueIgnoreMask()); + order += changed.bitCount(); + } } /** @@ -257,7 +325,8 @@ public class AssemblyDualTextField { * the linked text boxes when retrieving the prefix. It also delegates the item styling to the * item instances. */ - class AssemblyAutocompleter extends TextFieldAutocompleter
+ * This means the user has highlighted an item, but has not activated that item.
+ *
+ * @param ev the event describing the selection
+ */
+ default public void completionSelected(AutocompletionEvent
* This means the user has explicitly activate the item, i.e., pressed enter on or clicked the
* item.
+ *
* @param e the event describing the activation
*/
public void completionActivated(AutocompletionEvent