GP-38 additional register management API changes

This commit is contained in:
ghidra1 2020-07-21 15:34:07 -04:00
parent af58f51519
commit 0386895578
11 changed files with 151 additions and 104 deletions

View File

@ -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) {

View File

@ -99,11 +99,6 @@
<ref name="boolean_type"/>
</attribute>
</optional>
<optional>
<attribute name="unused">
<ref name="boolean_type"/>
</attribute>
</optional>
<optional>
<attribute name="vector_lane_sizes"/>
</optional>

View File

@ -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();
}
}

View File

@ -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

View File

@ -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());
}

View File

@ -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<CompilerSpecDescription> getCompatibleCompilerSpecDescriptions();

View File

@ -23,7 +23,7 @@ import ghidra.util.Msg;
public class RegisterBuilder {
ArrayList<Register> registerList;
HashMap<String, Register> registerMap;
Map<String, Register> 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<String> 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;
}

View File

@ -23,8 +23,12 @@ import ghidra.program.model.address.OldGenericNamespaceAddress;
public class RegisterManager {
Register[] registers;
Map<String, Register> registerNameMap = new HashMap<String, Register>(); // include aliases and case-variations
String[] registerNames; // excludes aliases
Register[] contextRegisters;
Register contextBaseRegister;
Map<String, Register> registerNameMap = new HashMap<String, Register>();
Map<RegisterSizeKey, Register> sizeMap = new HashMap<RegisterSizeKey, Register>();
Map<Address, List<Register>> registerAddressMap = new HashMap<Address, List<Register>>();
@ -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<String, Register> registerNameMap) {
registers = cookedRegisters;
this.registerNameMap = registerNameMap;
initialize();
}
private void initialize() {
List<String> registerNameList = new ArrayList<String>();
List<Register> contextRegisterList = new ArrayList<Register>();
List<Register> registerList = new ArrayList<Register>(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

View File

@ -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<Register> list = new ArrayList<Register>();
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<String> list = new ArrayList<String>();
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

View File

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

View File

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