From d7934eaafc849dc1e795a561cfc19cf08595dbfb Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Tue, 13 Aug 2019 07:49:38 -0400 Subject: [PATCH] Added XGate/HCS12 Disassemble Action command. --- .../disassemble/Hcs12DisassembleCommand.java | 141 ++++++++++++++++++ .../core/disassembler/DisassemblerPlugin.java | 30 ++++ .../disassembler/Hcs12DisassembleAction.java | 84 +++++++++++ 3 files changed, 255 insertions(+) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/cmd/disassemble/Hcs12DisassembleCommand.java create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/Hcs12DisassembleAction.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/disassemble/Hcs12DisassembleCommand.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/disassemble/Hcs12DisassembleCommand.java new file mode 100644 index 0000000000..9aacf50db6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/disassemble/Hcs12DisassembleCommand.java @@ -0,0 +1,141 @@ +/* ### + * 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.cmd.disassemble; + +import ghidra.framework.model.DomainObject; +import ghidra.program.disassemble.DisassemblerContextImpl; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; +import ghidra.program.model.listing.Program; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +import java.math.BigInteger; + +/** + * Command object for performing HCS12/XGate disassembly + */ +public class Hcs12DisassembleCommand extends DisassembleCommand { + + private boolean xgMode; + + /** + * Constructor for Hcs12DisassembleCommand. + * @param startSet set of addresses to be the start of a disassembly. The + * Command object will attempt to start a disassembly at each address in this set. + * @param restrictedSet addresses that can be disassembled. + * a null set implies no restrictions + * @param xgMode pass true if the disassembling in XGATE Mode + */ + public Hcs12DisassembleCommand(AddressSetView startSet, AddressSetView restrictedSet, + boolean xgMode) { + super("Disassemble " + (xgMode ? "XGate" : "HCS12"), startSet, restrictedSet, true); + this.xgMode = xgMode; + } + + /** + * Constructor for DisassembleCommand. + * @param startSet set of addresses to be the start of a disassembly. The + * Command object will attempt to start a disassembly at each address in this set. + * @param restrictedSet addresses that can be disassembled. + * a null set implies no restrictions + * @param xgMode pass true if the disassembling in XGATE Mode + */ + public Hcs12DisassembleCommand(Address start, AddressSetView restrictedSet, boolean xgMode) { + this(new AddressSet(start, start), restrictedSet, xgMode); + useDefaultRepeatPatternBehavior = true; + } + + @Override + public void setSeedContext(DisassemblerContextImpl seedContext) { + throw new UnsupportedOperationException(); + } + + @Override + public void setInitialContext(RegisterValue initialContextValue) { + throw new UnsupportedOperationException(); + } + + /** + * + * @see ghidra.framework.cmd.BackgroundCommand#applyTo(ghidra.framework.model.DomainObject, ghidra.util.task.TaskMonitor) + */ + @Override + synchronized public boolean applyTo(DomainObject obj, TaskMonitor monitor) { + Program program = (Program) obj; + + disassemblyPerformed = false; + unalignedStart = false; + + // get the XGATE mode register and set accordingly + Register xgmodeReg = program.getProgramContext().getRegister("XGATE"); + RegisterValue xgmodeValue = null; + + // if doing xgate, and have no XGmode reg, no way to do disassemble in xgate + if (xgmodeReg == null) { + if (xgMode) { + return false; + } + } + else { + xgmodeValue = new RegisterValue(xgmodeReg, BigInteger.valueOf(xgMode ? 0x1 : 0x0)); + super.setInitialContext(xgmodeValue); + } + + int alignment = 1; + + // Set XGate Mode context on undefined code units only + try { + if (startSet != null) { + + // Align startSet so that context only affected at possible instruction starts + + AddressSet alignedSet = new AddressSet(); + for (AddressRange range : startSet) { + Address min = range.getMinAddress(); + long minOfffset = min.getOffset(); + if (minOfffset != min.getOffset()) { + min = min.getNewAddress(minOfffset); + } + Address max = range.getMaxAddress(); + long maxOffset = max.getOffset(); + if (maxOffset < minOfffset) { + // skip short unaligned range + continue; + } + if (maxOffset != max.getOffset()) { + max = max.getNewAddress(maxOffset); + } + alignedSet.addRange(min, max); + } + if (alignedSet.isEmpty()) { + unalignedStart = true; + return false; // alignedSet does not contain any aligned starts + } + startSet = program.getListing().getUndefinedRanges(alignedSet, true, monitor); + if (startSet.isEmpty()) { + return true; // startSet does not contain any aligned undefined starts + } + } + } + catch (CancelledException e) { + return true; + } + + return doDisassembly(monitor, program, alignment); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassemblerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassemblerPlugin.java index 9f4fac5d3e..2a22ca800f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassemblerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassemblerPlugin.java @@ -83,6 +83,8 @@ public class DisassemblerPlugin extends Plugin { private DockingAction contextAction; private DockingAction armDisassembleAction; private DockingAction armThumbDisassembleAction; + private DockingAction hcs12DisassembleAction; + private DockingAction xgateDisassembleAction; private DockingAction mipsDisassembleAction; private DockingAction mips16DisassembleAction; private DockingAction ppcDisassembleAction; @@ -172,6 +174,8 @@ public class DisassemblerPlugin extends Plugin { contextAction = new ContextAction(this, GROUP_NAME); armDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, false); armThumbDisassembleAction = new ArmDisassembleAction(this, GROUP_NAME, true); + hcs12DisassembleAction = new Hcs12DisassembleAction(this, GROUP_NAME, false); + xgateDisassembleAction = new Hcs12DisassembleAction(this, GROUP_NAME, true); mipsDisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, false); mips16DisassembleAction = new MipsDisassembleAction(this, GROUP_NAME, true); ppcDisassembleAction = new PowerPCDisassembleAction(this, GROUP_NAME, false); @@ -183,6 +187,8 @@ public class DisassemblerPlugin extends Plugin { tool.addAction(disassembleStaticAction); tool.addAction(armDisassembleAction); tool.addAction(armThumbDisassembleAction); + tool.addAction(hcs12DisassembleAction); + tool.addAction(xgateDisassembleAction); tool.addAction(mipsDisassembleAction); tool.addAction(mips16DisassembleAction); tool.addAction(ppcDisassembleAction); @@ -350,6 +356,30 @@ public class DisassemblerPlugin extends Plugin { } } + public void disassembleHcs12Callback(ListingActionContext context, boolean xgMode) { + ProgramSelection currentSelection = context.getSelection(); + ProgramLocation currentLocation = context.getLocation(); + Program currentProgram = context.getProgram(); + Hcs12DisassembleCommand cmd = null; + + if ((currentSelection != null) && (!currentSelection.isEmpty())) { + cmd = new Hcs12DisassembleCommand(currentSelection, null, xgMode); + } + else { + Address addr = currentLocation.getAddress(); + try { + currentProgram.getMemory().getByte(addr); + cmd = new Hcs12DisassembleCommand(addr, null, xgMode); + } + catch (MemoryAccessException e) { + tool.setStatusInfo("Can't disassemble unitialized memory!", true); + } + } + if (cmd != null) { + tool.executeBackgroundCommand(cmd, currentProgram); + } + } + public void disassembleMipsCallback(ListingActionContext context, boolean mips16) { ProgramSelection currentSelection = context.getSelection(); ProgramLocation currentLocation = context.getLocation(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/Hcs12DisassembleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/Hcs12DisassembleAction.java new file mode 100644 index 0000000000..23f6c893aa --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/Hcs12DisassembleAction.java @@ -0,0 +1,84 @@ +/* ### + * 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.disassembler; + +import java.awt.event.KeyEvent; + +import docking.action.KeyBindingData; +import docking.action.MenuData; +import ghidra.app.context.ListingActionContext; +import ghidra.app.context.ListingContextAction; +import ghidra.program.model.address.Address; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.Program; + + +/** + * Action for HCS12 mode disassembly + */ + +class Hcs12DisassembleAction extends ListingContextAction { + private DisassemblerPlugin plugin; + private boolean disassembleXgate = false; + + public Hcs12DisassembleAction(DisassemblerPlugin plugin, String groupName, boolean disassembleXgate) { + super("Disassemble " + (disassembleXgate ? "HCS12" : "XGate"), plugin.getName()); + + this.plugin = plugin; + this.disassembleXgate = disassembleXgate; + + setPopupMenuData( new MenuData( + new String[]{"Disassemble - "+ (disassembleXgate ? "XGate" : "HCS12") }, + null, + groupName ) ); + + int keyEvent = (disassembleXgate ? KeyEvent.VK_F12 : KeyEvent.VK_F11); + setKeyBindingData( new KeyBindingData( keyEvent, 0 ) ); + } + + @Override + public void actionPerformed(ListingActionContext context) { + plugin.disassembleHcs12Callback(context, disassembleXgate); + } + + @Override + public boolean isEnabledForContext(ListingActionContext context) { + + // Action only intended for use where Xgate instructions are available. + // The presence of the XGATE context register can be used for this + // determination. + + Address address = context.getAddress(); + if ( address == null ) { + return false; + } + + Program program = context.getProgram(); + Language lang = program.getLanguage(); + Processor proc = lang.getProcessor(); + + if (!"HCS12".equals(proc.toString())) { + return false; + } + + Register register = context.getProgram().getProgramContext().getRegister("XGATE"); + if (register == null) { + return false; + } + + return plugin.checkDisassemblyEnabled(context, address, true); + } +}