diff --git a/Ghidra/Features/Base/ghidra_scripts/CreateRelocationBasedOperandReferences.java b/Ghidra/Features/Base/ghidra_scripts/CreateRelocationBasedOperandReferences.java new file mode 100644 index 0000000000..4c8654d403 --- /dev/null +++ b/Ghidra/Features/Base/ghidra_scripts/CreateRelocationBasedOperandReferences.java @@ -0,0 +1,161 @@ +/* ### + * 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. + */ +// This script creates references on scalar operands which can be directly +// correlated to a symbol or equate via a relocation table entry. Only symbols within +// byte-oriented address spaces will be considered. +//@category Analysis + +import java.util.Iterator; +import java.util.List; + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Instruction; +import ghidra.program.model.listing.Listing; +import ghidra.program.model.reloc.Relocation; +import ghidra.program.model.reloc.RelocationTable; +import ghidra.program.model.scalar.Scalar; +import ghidra.program.model.symbol.*; + +public class CreateRelocationBasedOperandReferences extends GhidraScript { + + @Override + public void run() throws Exception { + if (currentProgram == null) { + popup("No active Program to analyze"); + return; + } + + Listing listing = currentProgram.getListing(); + ReferenceManager refMgr = currentProgram.getReferenceManager(); + EquateTable equateTable = currentProgram.getEquateTable(); + SymbolTable symbolTable = currentProgram.getSymbolTable(); + + RelocationTable relocationTable = currentProgram.getRelocationTable(); + if (relocationTable.getSize() == 0) { + popup("Program does not have relocations"); + return; + } + + Iterator relocations = relocationTable.getRelocations(); + + monitor.initialize(relocationTable.getSize()); + int refCount = 0; + + while (relocations.hasNext()) { + monitor.checkCanceled(); + Relocation r = relocations.next(); + monitor.incrementProgress(1); + + Instruction instr = listing.getInstructionAt(r.getAddress()); + if (instr == null) { + continue; + } + + Equate equate = null; + Symbol symbol = null; + long value; + + List symbols = symbolTable.getLabelOrFunctionSymbols(r.getSymbolName(), null); + if (symbols.size() == 0) { + // check for possible equate definition + equate = equateTable.getEquate(r.getSymbolName()); + if (equate == null) { + continue; + } + value = equate.getValue(); + } + else if (symbols.size() == 1) { + symbol = symbols.get(0); + Address a = symbol.getAddress(); + if (a.getAddressSpace().getAddressableUnitSize() != 1) { + continue; + } + value = a.getOffset(); + } + else { + continue; + } + + Reference[] referencesFrom = null; + + int opCnt = instr.getNumOperands(); + for (int opIndex = 0; opIndex < opCnt; opIndex++) { + Scalar scalar = + getScalarOperand(instr.getDefaultOperandRepresentationList(opIndex)); + if (scalar == null || scalar.getUnsignedValue() != value) { + continue; + } + if (referencesFrom == null) { + referencesFrom = refMgr.getReferencesFrom(instr.getAddress()); + } + if (hasReference(referencesFrom, opIndex)) { + continue; // reference exists on operand + } + if (equateTable.getEquates(instr.getAddress(), opIndex).size() != 0) { + continue; // equate reference exists on operand + } + if (symbol != null) { + Reference ref = refMgr.addMemoryReference(instr.getAddress(), + symbol.getAddress(), RefType.DATA, SourceType.ANALYSIS, opIndex); + refMgr.setAssociation(symbol, ref); + } + else { + equate.addReference(instr.getAddress(), opIndex); + } + ++refCount; + break; + } + + } + + popup("Added " + refCount + " relocation-based references"); + } + + private Scalar getScalarOperand(List defaultOperandRepresentationList) { + Scalar s = null; + for (Object obj : defaultOperandRepresentationList) { + if (obj instanceof String) { + continue; + } + if (obj instanceof Character) { + continue; + } + if (obj instanceof Scalar) { + if (s != null) { + // more than one scalar found + return null; + } + s = (Scalar) obj; + } + else { + // non-scalar found + return null; + } + } + return s; + } + + private boolean hasReference(Reference[] referencesFrom, int opIndex) { + for (Reference r : referencesFrom) { + if (r.getOperandIndex() == opIndex) { + return true; + } + } + return false; + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg index d0c45fb169..beac886305 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg @@ -99,6 +99,9 @@ + + + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java index e86985a056..a049e5a600 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java @@ -768,6 +768,7 @@ public class SleighLanguage implements Language { XmlElement reg = parser.start(); String registerName = reg.getAttribute("name"); String registerRename = reg.getAttribute("rename"); + String registerAlias = reg.getAttribute("alias"); String groupName = reg.getAttribute("group"); boolean isHidden = SpecXmlUtils.decodeBoolean(reg.getAttribute("hidden")); if (registerRename != null) { @@ -784,6 +785,9 @@ public class SleighLanguage implements Language { Msg.error(this, "duplicate register " + registerName + ": " + description.getSpecFile()); } + if (registerAlias != null) { + registerBuilder.addAlias(registerName, registerAlias); + } if (groupName != null) { registerBuilder.setGroup(registerName, groupName); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterBuilder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterBuilder.java index 84ea905d69..eca3c69911 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterBuilder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterBuilder.java @@ -187,6 +187,25 @@ public class RegisterBuilder { return true; } + /** + * Add an alias to a previously defined register. + * @param registerName defined register + * @param alias alias to be added to defined register + * @return true if alias addition was successful, else false + */ + public boolean addAlias(String registerName, String alias) { + Register register = registerMap.get(registerName); + if (register == null) { + return false; + } + if (registerMap.containsKey(alias)) { + return false; + } + register.addAlias(alias); + addRegisterToNameMap(alias, register); + return true; + } + /** * Set the group name for the specified register * @param registerName register name diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/lang/RegisterManagerTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/lang/RegisterManagerTest.java index 5d613ecb79..6a467750bf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/lang/RegisterManagerTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/lang/RegisterManagerTest.java @@ -15,9 +15,11 @@ */ package ghidra.program.model.lang; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; -import org.junit.*; +import java.util.Iterator; + +import org.junit.Test; import generic.test.AbstractGenericTest; import ghidra.program.model.address.Address; @@ -25,8 +27,6 @@ import ghidra.program.model.address.AddressSpace; public class RegisterManagerTest extends AbstractGenericTest { - private RegisterManager registerManager; - public RegisterManagerTest() { super(); @@ -36,24 +36,6 @@ public class RegisterManagerTest extends AbstractGenericTest { return AddressSpace.DEFAULT_REGISTER_SPACE.getAddress(offset); } - @Before - public void setUp() throws Exception { - RegisterBuilder builder = new RegisterBuilder(); - builder.addRegister("L_0_8", "", addr(0), 8, false, 0); - builder.addRegister("L_0_4", "", addr(0), 4, false, 0); - builder.addRegister("L_4_4", "", addr(4), 4, false, 0); - builder.addRegister("L_0_2", "", addr(0), 2, false, 0); - builder.addRegister("L_2_2", "", addr(2), 2, false, 0); - - builder.addRegister("B_10_8", "", addr(0x10), 8, true, 0); - builder.addRegister("B_10_4", "", addr(0x10), 4, true, 0); - builder.addRegister("B_14_4", "", addr(0x14), 4, true, 0); - builder.addRegister("B_16_2", "", addr(0x16), 2, true, 0); - builder.addRegister("B_12_2", "", addr(0x12), 2, true, 0); - - registerManager = builder.getRegisterManager(); - } - @Test public void testLittle() { RegisterBuilder builder = new RegisterBuilder(); @@ -63,17 +45,17 @@ public class RegisterManagerTest extends AbstractGenericTest { builder.addRegister("L_0_2", "", addr(0), 2, false, 0); builder.addRegister("L_2_2", "", addr(2), 2, false, 0); - registerManager = builder.getRegisterManager(); + RegisterManager registerManager = builder.getRegisterManager(); - Assert.assertEquals("L_0_8", registerManager.getRegister(addr(0), 8).getName()); - Assert.assertEquals("L_0_8", registerManager.getRegister(addr(0), 7).getName()); - Assert.assertEquals("L_0_8", registerManager.getRegister(addr(0), 6).getName()); - Assert.assertEquals("L_0_8", registerManager.getRegister(addr(0), 5).getName()); - Assert.assertEquals("L_0_4", registerManager.getRegister(addr(0), 4).getName()); - Assert.assertEquals("L_0_4", registerManager.getRegister(addr(0), 3).getName()); - Assert.assertEquals("L_0_2", registerManager.getRegister(addr(0), 2).getName()); - Assert.assertEquals("L_0_2", registerManager.getRegister(addr(0), 1).getName()); - Assert.assertEquals("L_0_8", registerManager.getRegister(addr(0), 0).getName()); + assertEquals("L_0_8", registerManager.getRegister(addr(0), 8).getName()); + assertEquals("L_0_8", registerManager.getRegister(addr(0), 7).getName()); + assertEquals("L_0_8", registerManager.getRegister(addr(0), 6).getName()); + assertEquals("L_0_8", registerManager.getRegister(addr(0), 5).getName()); + assertEquals("L_0_4", registerManager.getRegister(addr(0), 4).getName()); + assertEquals("L_0_4", registerManager.getRegister(addr(0), 3).getName()); + assertEquals("L_0_2", registerManager.getRegister(addr(0), 2).getName()); + assertEquals("L_0_2", registerManager.getRegister(addr(0), 1).getName()); + assertEquals("L_0_8", registerManager.getRegister(addr(0), 0).getName()); assertNull(registerManager.getRegister(addr(1), 8)); assertNull(registerManager.getRegister(addr(1), 7)); @@ -91,9 +73,9 @@ public class RegisterManagerTest extends AbstractGenericTest { assertNull(registerManager.getRegister(addr(2), 5)); assertNull(registerManager.getRegister(addr(2), 4)); assertNull(registerManager.getRegister(addr(2), 3)); - Assert.assertEquals("L_2_2", registerManager.getRegister(addr(2), 2).getName()); - Assert.assertEquals("L_2_2", registerManager.getRegister(addr(2), 1).getName()); - Assert.assertEquals("L_2_2", registerManager.getRegister(addr(2), 0).getName()); + assertEquals("L_2_2", registerManager.getRegister(addr(2), 2).getName()); + assertEquals("L_2_2", registerManager.getRegister(addr(2), 1).getName()); + assertEquals("L_2_2", registerManager.getRegister(addr(2), 0).getName()); assertNull(registerManager.getRegister(addr(3), 8)); assertNull(registerManager.getRegister(addr(3), 7)); @@ -109,11 +91,11 @@ public class RegisterManagerTest extends AbstractGenericTest { assertNull(registerManager.getRegister(addr(4), 7)); assertNull(registerManager.getRegister(addr(4), 6)); assertNull(registerManager.getRegister(addr(4), 5)); - Assert.assertEquals("L_4_4", registerManager.getRegister(addr(4), 4).getName()); - Assert.assertEquals("L_4_4", registerManager.getRegister(addr(4), 3).getName()); - Assert.assertEquals("L_4_4", registerManager.getRegister(addr(4), 2).getName()); - Assert.assertEquals("L_4_4", registerManager.getRegister(addr(4), 1).getName()); - Assert.assertEquals("L_4_4", registerManager.getRegister(addr(4), 0).getName()); + assertEquals("L_4_4", registerManager.getRegister(addr(4), 4).getName()); + assertEquals("L_4_4", registerManager.getRegister(addr(4), 3).getName()); + assertEquals("L_4_4", registerManager.getRegister(addr(4), 2).getName()); + assertEquals("L_4_4", registerManager.getRegister(addr(4), 1).getName()); + assertEquals("L_4_4", registerManager.getRegister(addr(4), 0).getName()); } @@ -127,64 +109,64 @@ public class RegisterManagerTest extends AbstractGenericTest { builder.addRegister("B_6_2", "", addr(6), 2, true, 0); builder.addRegister("B_2_2", "", addr(2), 2, true, 0); - registerManager = builder.getRegisterManager(); + RegisterManager registerManager = builder.getRegisterManager(); - Assert.assertEquals("B_0_8", registerManager.getRegister(addr(0), 8).getName()); + assertEquals("B_0_8", registerManager.getRegister(addr(0), 8).getName()); assertNull(registerManager.getRegister(addr(0), 7)); assertNull(registerManager.getRegister(addr(0), 6)); assertNull(registerManager.getRegister(addr(0), 5)); - Assert.assertEquals("B_0_4", registerManager.getRegister(addr(0), 4).getName()); + assertEquals("B_0_4", registerManager.getRegister(addr(0), 4).getName()); assertNull(registerManager.getRegister(addr(0), 3)); assertNull(registerManager.getRegister(addr(0), 2)); assertNull(registerManager.getRegister(addr(0), 1)); - Assert.assertEquals("B_0_8", registerManager.getRegister(addr(0), 0).getName()); + assertEquals("B_0_8", registerManager.getRegister(addr(0), 0).getName()); assertNull(registerManager.getRegister(addr(1), 8)); - Assert.assertEquals("B_0_8", registerManager.getRegister(addr(1), 7).getName()); + assertEquals("B_0_8", registerManager.getRegister(addr(1), 7).getName()); assertNull(registerManager.getRegister(addr(1), 6)); assertNull(registerManager.getRegister(addr(1), 5)); assertNull(registerManager.getRegister(addr(1), 4)); - Assert.assertEquals("B_0_4", registerManager.getRegister(addr(1), 3).getName()); + assertEquals("B_0_4", registerManager.getRegister(addr(1), 3).getName()); assertNull(registerManager.getRegister(addr(1), 2)); assertNull(registerManager.getRegister(addr(1), 1)); assertNull(registerManager.getRegister(addr(1), 0)); assertNull(registerManager.getRegister(addr(2), 8)); assertNull(registerManager.getRegister(addr(2), 7)); - Assert.assertEquals("B_0_8", registerManager.getRegister(addr(2), 6).getName()); + assertEquals("B_0_8", registerManager.getRegister(addr(2), 6).getName()); assertNull(registerManager.getRegister(addr(2), 5)); assertNull(registerManager.getRegister(addr(2), 4)); assertNull(registerManager.getRegister(addr(2), 3)); - Assert.assertEquals("B_2_2", registerManager.getRegister(addr(2), 2).getName()); + assertEquals("B_2_2", registerManager.getRegister(addr(2), 2).getName()); assertNull(registerManager.getRegister(addr(2), 1)); - Assert.assertEquals("B_2_2", registerManager.getRegister(addr(2), 0).getName()); + assertEquals("B_2_2", registerManager.getRegister(addr(2), 0).getName()); assertNull(registerManager.getRegister(addr(3), 8)); assertNull(registerManager.getRegister(addr(3), 7)); assertNull(registerManager.getRegister(addr(3), 6)); - Assert.assertEquals("B_0_8", registerManager.getRegister(addr(3), 5).getName()); + assertEquals("B_0_8", registerManager.getRegister(addr(3), 5).getName()); assertNull(registerManager.getRegister(addr(3), 4)); assertNull(registerManager.getRegister(addr(3), 3)); assertNull(registerManager.getRegister(addr(3), 2)); - Assert.assertEquals("B_2_2", registerManager.getRegister(addr(3), 1).getName()); + assertEquals("B_2_2", registerManager.getRegister(addr(3), 1).getName()); assertNull(registerManager.getRegister(addr(3), 0)); assertNull(registerManager.getRegister(addr(4), 8)); assertNull(registerManager.getRegister(addr(4), 7)); assertNull(registerManager.getRegister(addr(4), 6)); assertNull(registerManager.getRegister(addr(4), 5)); - Assert.assertEquals("B_4_4", registerManager.getRegister(addr(4), 4).getName()); + assertEquals("B_4_4", registerManager.getRegister(addr(4), 4).getName()); assertNull(registerManager.getRegister(addr(4), 3)); assertNull(registerManager.getRegister(addr(4), 2)); assertNull(registerManager.getRegister(addr(4), 1)); - Assert.assertEquals("B_4_4", registerManager.getRegister(addr(4), 0).getName()); + assertEquals("B_4_4", registerManager.getRegister(addr(4), 0).getName()); assertNull(registerManager.getRegister(addr(5), 8)); assertNull(registerManager.getRegister(addr(5), 7)); assertNull(registerManager.getRegister(addr(5), 6)); assertNull(registerManager.getRegister(addr(5), 5)); assertNull(registerManager.getRegister(addr(5), 4)); - Assert.assertEquals("B_4_4", registerManager.getRegister(addr(5), 3).getName()); + assertEquals("B_4_4", registerManager.getRegister(addr(5), 3).getName()); assertNull(registerManager.getRegister(addr(5), 2)); assertNull(registerManager.getRegister(addr(5), 1)); assertNull(registerManager.getRegister(addr(5), 0)); @@ -195,9 +177,9 @@ public class RegisterManagerTest extends AbstractGenericTest { assertNull(registerManager.getRegister(addr(6), 5)); assertNull(registerManager.getRegister(addr(6), 4)); assertNull(registerManager.getRegister(addr(6), 3)); - Assert.assertEquals("B_6_2", registerManager.getRegister(addr(6), 2).getName()); + assertEquals("B_6_2", registerManager.getRegister(addr(6), 2).getName()); assertNull(registerManager.getRegister(addr(6), 1)); - Assert.assertEquals("B_6_2", registerManager.getRegister(addr(6), 0).getName()); + assertEquals("B_6_2", registerManager.getRegister(addr(6), 0).getName()); assertNull(registerManager.getRegister(addr(7), 8)); assertNull(registerManager.getRegister(addr(7), 7)); @@ -206,9 +188,55 @@ public class RegisterManagerTest extends AbstractGenericTest { assertNull(registerManager.getRegister(addr(7), 4)); assertNull(registerManager.getRegister(addr(7), 3)); assertNull(registerManager.getRegister(addr(7), 2)); - Assert.assertEquals("B_6_2", registerManager.getRegister(addr(7), 1).getName()); + assertEquals("B_6_2", registerManager.getRegister(addr(7), 1).getName()); assertNull(registerManager.getRegister(addr(7), 0)); } + @Test + public void testRenameAndAlias() { + RegisterBuilder builder = new RegisterBuilder(); + builder.addRegister("A", "", addr(0), 8, false, 0); + builder.addRegister("B", "", addr(0), 4, false, 0); + builder.addRegister("C", "", addr(4), 4, false, 0); + builder.addRegister("D", "", addr(0), 2, false, 0); + builder.addRegister("E", "", addr(2), 2, false, 0); + + builder.renameRegister("A", "L_0_8"); + builder.renameRegister("B", "L_0_4"); + builder.renameRegister("C", "L_4_4"); + builder.renameRegister("D", "L_0_2"); + builder.renameRegister("E", "L_2_2"); + + builder.addAlias("L_0_8", "L08"); + builder.addAlias("L_0_4", "L04"); + builder.addAlias("L_4_4", "L44"); + builder.addAlias("L_0_2", "L02"); + builder.addAlias("L_2_2", "L22"); + + RegisterManager registerManager = builder.getRegisterManager(); + + verifyRegisterNames(registerManager, "L_0_8", "L08"); + verifyRegisterNames(registerManager, "L_0_4", "L04"); + verifyRegisterNames(registerManager, "L_4_4", "L44"); + verifyRegisterNames(registerManager, "L_0_2", "L02"); + verifyRegisterNames(registerManager, "L_2_2", "L22"); + + } + + private void verifyRegisterNames(RegisterManager registerManager, String name, String alias) { + Register r = registerManager.getRegister(name); + assertNotNull(r); + assertEquals(name, r.getName()); + Iterator iterator = r.getAliases().iterator(); + assertEquals(alias, iterator.next()); + assertFalse(iterator.hasNext()); + + // same register instance should be provided for all name forms + assertTrue(r == registerManager.getRegister(name.toLowerCase())); + assertTrue(r == registerManager.getRegister(alias)); + assertTrue(r == registerManager.getRegister(alias.toLowerCase())); + + } + } diff --git a/Ghidra/Processors/PIC/data/languages/PIC24.pspec b/Ghidra/Processors/PIC/data/languages/PIC24.pspec index e08697bfc1..0357e6bb6a 100644 --- a/Ghidra/Processors/PIC/data/languages/PIC24.pspec +++ b/Ghidra/Processors/PIC/data/languages/PIC24.pspec @@ -8,4 +8,22 @@ + + + + + + + + + + + + + + + + + +