mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 08:30:11 +00:00
GP-38 additional register management API changes
This commit is contained in:
parent
af58f51519
commit
0386895578
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user