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 2a22ca800f..ce0e969af0 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 @@ -301,25 +301,11 @@ public class DisassemblerPlugin extends Plugin { return currentProgram.getMemory().contains(address); } - /** - * @see ghidra.app.plugin.contrib.disassembler.DisassemblyTaskListener#disassembleMessageReported(String) - */ - public void disassembleMessageReported(String msg) { - tool.setStatusInfo(msg); - } - - /** - * @see ghidra.app.plugin.contrib.disassembler.DisassemblyTaskListener#disassemblyDone(DisassemblyTask) - */ - public void disassemblyDone(Disassembler task) { - } - public void setDefaultContext(ListingActionContext context) { Program contextProgram = context.getProgram(); - ProgramContext programContext = contextProgram.getProgramContext(); - Register[] registers = programContext.getProcessorStateRegisters(); - if (registers.length == 0) { + Register baseContextReg = contextProgram.getLanguage().getContextBaseRegister(); + if (baseContextReg != null && baseContextReg.hasChildren()) { return; } @@ -328,8 +314,8 @@ public class DisassemblerPlugin extends Plugin { } public boolean hasContextRegisters(Program currentProgram) { - Register[] registers = currentProgram.getProgramContext().getProcessorStateRegisters(); - return registers.length > 0; + Register baseContextReg = currentProgram.getLanguage().getContextBaseRegister(); + return baseContextReg != null && baseContextReg.hasChildren(); } public void disassembleArmCallback(ListingActionContext context, boolean thumbMode) { diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg index faf6fd56da..8661541082 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/processor_spec.rxg @@ -99,11 +99,6 @@ - - - - - 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 5c514cd70b..251be0346c 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 @@ -265,6 +265,11 @@ public class SleighLanguage implements Language { return getRegisterManager().getContextBaseRegister(); } + @Override + public Register[] getContextRegisters() { + return getRegisterManager().getContextRegisters(); + } + @Override public MemoryBlockDefinition[] getDefaultMemoryBlocks() { return defaultMemoryBlocks; @@ -335,6 +340,11 @@ public class SleighLanguage implements Language { return getRegisterManager().getRegisters(); } + @Override + public String[] getRegisterNames() { + return getRegisterManager().getRegisterNames(); + } + @Override public String getSegmentedSpace() { return segmentedspace; @@ -743,11 +753,7 @@ public class SleighLanguage implements Language { String registerRename = reg.getAttribute("rename"); String groupName = reg.getAttribute("group"); boolean isHidden = SpecXmlUtils.decodeBoolean(reg.getAttribute("hidden")); - boolean isUnused = SpecXmlUtils.decodeBoolean(reg.getAttribute("unused")); - if (isUnused) { - registerBuilder.removeRegister(registerName); - } - else if (registerRename != null) { + if (registerRename != null) { if (!registerBuilder.renameRegister(registerName, registerRename)) { throw new SleighException( "error renaming " + registerName + " to " + registerRename); @@ -1584,4 +1590,5 @@ public class SleighLanguage implements Language { public Register[] getSortedVectorRegisters() { return registerManager.getSortedVectorRegisters(); } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java index 9c4ae7a895..3c9316ec4b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java @@ -67,7 +67,7 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple initializedCurrentValues(); if (upgrade) { - upgrade(addrMap, lang, monitor); + upgrade(addrMap, monitor); } if (openMode == DBConstants.UPGRADE && oldContextDataExists) { @@ -89,13 +89,13 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple return false; } - private void upgrade(AddressMap addressMapExt, Language language, TaskMonitor monitor) + private void upgrade(AddressMap addressMapExt, TaskMonitor monitor) throws CancelledException { OldProgramContextDB oldContext = new OldProgramContextDB(dbHandle, errorHandler, language, addressMapExt, lock); - for (Register register : registers) { + for (Register register : language.getRegisters()) { if (register.getBaseRegister() != register) { continue; } @@ -326,6 +326,7 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple // Sort the registers by size so that largest come first. // This prevents the remove call below from incorrectly clearing // smaller registers that are part of a larger register. + Register[] registers = language.getRegisters().clone(); Arrays.sort(registers, (r1, r2) -> r2.getBitLength() - r1.getBitLength()); // Map all register stores to new registers diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java index ffb60c99bd..ea4406aa8c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java @@ -1512,7 +1512,7 @@ public class Disassembler implements DisassemblerConflictHandler { private InstructionContext instructionContextCache = null; DisassemblerProgramContext() { - super(Disassembler.this.language); // getContextRegisters(Disassembler.this.baseContextRegister)); + super(Disassembler.this.language); if (realProgramContext != null) { setDefaultDisassemblyContext(realProgramContext.getDefaultDisassemblyContext()); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java index 85a7f921c4..9bc96c0192 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java @@ -121,6 +121,8 @@ public interface Language { /** * Return true if the instructions in this language support Pcode. + * + * @return true if language supports the use of pcode */ public boolean supportsPcode(); @@ -128,8 +130,8 @@ public interface Language { * Returns true if the language has defined the specified location as * volatile. * - * @param addr - * location address + * @param addr location address + * @return true if specified address is within a volatile range */ public boolean isVolatile(Address addr); @@ -161,6 +163,8 @@ public interface Language { * Get the total number of user defined pcode names. * * Note: only works for Pcode based languages + * + * @return number of user defined pcodeops */ public int getNumberOfUserDefinedOpNames(); @@ -170,6 +174,9 @@ public interface Language { * known. * * Note: only works for Pcode based languages + * + * @param index user defined pcodeop index + * @return pcodeop name or null if not defined */ public String getUserDefinedOpName(int index); @@ -199,12 +206,22 @@ public interface Language { public Register getRegister(AddressSpace addrspc, long offset, int size); /** - * get the array of Register objects that this language supports. + * Get the unsorted array of Register objects that this language supports + * (including context registers). * * @return the array of processor registers. */ public Register[] getRegisters(); + /** + * Get the unsorted array of register names that this language supports + * (including context registers). Names correspond to orignal register + * name and not aliases which may be defined. + * + * @return the array of processor register names. + */ + public String[] getRegisterNames(); + /** * Get a register given the name of the register * @@ -237,9 +254,18 @@ public interface Language { /** * Returns context base register or null if one has not been defined by the * language. + * @return base context register or null if not defined */ public Register getContextBaseRegister(); + /** + * Get the unsorted array of Context Register objects that this language defines + * (includes context base register and its context field registers). + * + * @return the array of processor registers. + */ + public Register[] getContextRegisters(); + /** * Returns the default memory blocks for this language. * @return the default memory blocks for this language @@ -277,16 +303,18 @@ public interface Language { public void applyContextSettings(DefaultProgramContext ctx); /** - * Refreshes the definition of this language if possible (statically defined - * languages can safely do nothing). + * Refreshes the definition of this language if possible. Use of this method is + * intended for development purpose only since stale references to prior + * language resources (e.g., registers) may persist. * @param taskMonitor monitor for progress back to the user - * @throws IOException + * @throws IOException if error occurs while reloading language spec file(s) */ public void reloadLanguage(TaskMonitor taskMonitor) throws IOException; /** * Returns a list of all compatible compiler spec descriptions. * The first item in the list is the default. + * @return list of all compatible compiler specifications descriptions */ public List getCompatibleCompilerSpecDescriptions(); 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 899eefa044..693b185a1c 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 @@ -23,7 +23,7 @@ import ghidra.util.Msg; public class RegisterBuilder { ArrayList registerList; - HashMap registerMap; + Map registerMap; // include aliases and case-variations Address contextAddress; public RegisterBuilder() { @@ -50,13 +50,14 @@ public class RegisterBuilder { Msg.error(this, "Duplicate register name: " + name); // TODO: should we throw exception - hopefully sleigh will prevent this condition } + // Use of register alias handles case where context field is defined with different names for (Register reg : registerList) { if (reg.getAddress().equals(register.getAddress()) && reg.getLeastSignificantBit() == register.getLeastSignificantBit() && reg.getBitLength() == register.getBitLength()) { // define as register alias reg.addAlias(name); - addRegisterToMap(register); + addRegisterToNameMap(name, register); return; } } @@ -64,16 +65,21 @@ public class RegisterBuilder { contextAddress = register.getAddress(); } registerList.add(register); - addRegisterToMap(register); + addRegisterToNameMap(name, register); } - private void addRegisterToMap(Register register) { - String name = register.getName(); + private void addRegisterToNameMap(String name, Register register) { registerMap.put(name, register); registerMap.put(name.toLowerCase(), register); registerMap.put(name.toUpperCase(), register); } + private void removeRegisterFromNameMap(String name) { + registerMap.remove(name); + registerMap.remove(name.toLowerCase()); + registerMap.remove(name.toUpperCase()); + } + /** * Returns the processor context address of the first * context register added to this builder. @@ -83,28 +89,8 @@ public class RegisterBuilder { return contextAddress; } - public void removeRegister(String name) { - Register register = registerMap.remove(name); - if (register != null) { - if (name.equals(register.getName())) { - // name is primary - check for alias - Iterator iter = register.getAliases().iterator(); - if (!iter.hasNext()) { - // no alias - remove register - registerList.remove(register); - } - else { - register.rename(iter.next()); - } - } - else { - register.removeAlias(name); - } - } - } - public RegisterManager getRegisterManager() { - return new RegisterManager(computeRegisters()); + return new RegisterManager(computeRegisters(), Collections.unmodifiableMap(registerMap)); } private Register[] computeRegisters() { @@ -171,6 +157,7 @@ public class RegisterBuilder { /** * Returns the register with the given name; * @param name the name of the register to retrieve + * @return register or null if not found */ public Register getRegister(String name) { return registerMap.get(name); @@ -192,8 +179,8 @@ public class RegisterBuilder { return false; } register.rename(newName); - registerMap.remove(oldName); - registerMap.put(newName, register); + removeRegisterFromNameMap(oldName); + addRegisterToNameMap(newName, register); return true; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterManager.java index 88ff382421..a91b868670 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/RegisterManager.java @@ -23,8 +23,12 @@ import ghidra.program.model.address.OldGenericNamespaceAddress; public class RegisterManager { Register[] registers; + Map registerNameMap = new HashMap(); // include aliases and case-variations + + String[] registerNames; // excludes aliases + Register[] contextRegisters; Register contextBaseRegister; - Map registerNameMap = new HashMap(); + Map sizeMap = new HashMap(); Map> registerAddressMap = new HashMap>(); @@ -74,21 +78,32 @@ public class RegisterManager { } }; - RegisterManager(Register[] cookedRegisters) { + /** + * Construct RegisterManager + * @param cookedRegisters all defined registers with appropriate parent-child relationships + * properly established. + * @param registerNameMap a complete name-to-register map including all register aliases + * and alternate spellings (e.g., case-variations) + */ + RegisterManager(Register[] cookedRegisters, Map registerNameMap) { registers = cookedRegisters; + this.registerNameMap = registerNameMap; initialize(); } private void initialize() { + List registerNameList = new ArrayList(); + List contextRegisterList = new ArrayList(); List registerList = new ArrayList(Arrays.asList(registers)); Collections.sort(registerList, registerSizeComparator); for (Register reg : registerList) { - registerNameMap.put(reg.getName(), reg); - for (String alias : reg.getAliases()) { - registerNameMap.put(alias, reg); - } - if (reg.isProcessorContext() && reg.isBaseRegister()) { - contextBaseRegister = reg; + String regName = reg.getName(); + registerNameList.add(regName); + if (reg.isProcessorContext()) { + contextRegisterList.add(reg); + if (reg.isBaseRegister()) { + contextBaseRegister = reg; + } } Address addr = reg.getAddress(); @@ -114,6 +129,8 @@ public class RegisterManager { for (Register register : registerList) { sizeMap.put(new RegisterSizeKey(register.getAddress(), 0), register); } + contextRegisters = contextRegisterList.toArray(new Register[contextRegisterList.size()]); + registerNames = registerNameList.toArray(new String[registerNameList.size()]); } private void populateSizeMapBigEndian(Register reg) { @@ -139,6 +156,22 @@ public class RegisterManager { return contextBaseRegister; } + /** + * Get unsorted array of all processor context registers (include base context register and children) + * @return all processor context registers + */ + public Register[] getContextRegisters() { + return contextRegisters; + } + + /** + * Get unsorted array of all original register names (exludes aliases) + * @return all register names + */ + public String[] getRegisterNames() { + return registerNames; + } + /** * Returns the largest register located at the specified address * @param addr register address diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractProgramContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractProgramContext.java index 220fba61ee..fd96114e20 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractProgramContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractProgramContext.java @@ -15,7 +15,7 @@ */ package ghidra.program.util; -import java.util.*; +import java.util.Arrays; import ghidra.program.model.address.Address; import ghidra.program.model.lang.*; @@ -25,7 +25,7 @@ import ghidra.program.model.listing.ProgramContext; abstract public class AbstractProgramContext implements ProgramContext, DefaultProgramContext { protected Language language; - protected Register[] registers; + protected Register baseContextRegister; private boolean hasNonFlowingContext = false; @@ -38,6 +38,14 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP init(language); } + /** + * Get underlying language associated with this context and its registers + * @return language + */ + public Language getLanguage() { + return language; + } + /** * Set those bits in the nonFlowingContextRegisterMask which should not * flow with context. @@ -75,7 +83,7 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP /** * Modify register value to eliminate non-flowing bits - * @param value + * @param value context register value to be modified * @return value suitable for flowing */ @Override @@ -88,8 +96,9 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP /** * Modify register value to only include non-flowing bits - * @param value - * @return new value or null + * @param value context register value to be modified + * @return new value or null if value does not correspond to a context register or + * non-flowing context fields have not been defined */ @Override public final RegisterValue getNonFlowValue(RegisterValue value) { @@ -99,33 +108,28 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP return value.clearBitValues(flowingContextRegisterMask); } - protected void init(Language language) { - this.language = language; - this.registers = language.getRegisters(); - baseContextRegister = language.getContextBaseRegister(); + /** + * Initialize context for the specified language + * @param lang processor language for which this context applies + */ + protected void init(Language lang) { + this.language = lang; + baseContextRegister = lang.getContextBaseRegister(); if (baseContextRegister == null) { baseContextRegister = new Register("DEFAULT_CONTEXT", "DEFAULT_CONTEXT", Address.NO_ADDRESS, 4, true, 0); } defaultDisassemblyContext = new RegisterValue(baseContextRegister); - - if (baseContextRegister != null) { - nonFlowingContextRegisterMask = baseContextRegister.getBaseMask().clone(); - Arrays.fill(nonFlowingContextRegisterMask, (byte) 0); - flowingContextRegisterMask = nonFlowingContextRegisterMask.clone(); - initContextBitMasks(baseContextRegister); - } + + nonFlowingContextRegisterMask = baseContextRegister.getBaseMask().clone(); + Arrays.fill(nonFlowingContextRegisterMask, (byte) 0); + flowingContextRegisterMask = nonFlowingContextRegisterMask.clone(); + initContextBitMasks(baseContextRegister); } @Override public final Register[] getProcessorStateRegisters() { - List list = new ArrayList(); - for (Register register : registers) { - if (register.isProcessorContext()) { - list.add(register); - } - } - return list.toArray(new Register[list.size()]); + return language.getContextRegisters(); } @Override @@ -135,16 +139,12 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP @Override public final String[] getRegisterNames() { - List list = new ArrayList(); - for (Register register : registers) { - list.add(register.getName()); - } - return list.toArray(new String[list.size()]); + return language.getRegisterNames(); } @Override public final Register[] getRegisters() { - return registers; + return language.getRegisters(); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractStoredProgramContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractStoredProgramContext.java index 929569cf4f..aa12eae564 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractStoredProgramContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AbstractStoredProgramContext.java @@ -205,7 +205,7 @@ abstract public class AbstractStoredProgramContext extends AbstractProgramContex public Register[] getRegistersWithValues() { if (registersWithValues == null) { registersWithValues = new HashSet<>(); - for (Register register : registers) { + for (Register register : language.getRegisters()) { RegisterValueStore store = registerValueMap.get(register.getBaseRegister()); if (store != null && !store.isEmpty()) { registersWithValues.add(register); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java index 394e960407..cb7ad24426 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java @@ -119,6 +119,11 @@ class OldLanguage implements Language { return registerMgr.getContextBaseRegister(); } + @Override + public Register[] getContextRegisters() { + return registerMgr.getContextRegisters(); + } + @Override public Register getRegister(Address addr, int size) { return registerMgr.getRegister(addr, size); @@ -139,6 +144,11 @@ class OldLanguage implements Language { return registerMgr.getRegisters(); } + @Override + public String[] getRegisterNames() { + return registerMgr.getRegisterNames(); + } + @Override public Register[] getRegisters(Address address) { return registerMgr.getRegisters(address);