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);