mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-38 add semi-case-insensitive register get-by-name to Language and
construct various register context implementations with language instead of register array to avoid need to build name loopup maps.
This commit is contained in:
parent
58157a1175
commit
af58f51519
12 changed files with 88 additions and 102 deletions
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,14 +15,12 @@
|
|||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.util.ProgramContextImpl;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import java.lang.UnsupportedOperationException;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.util.ProgramContextImpl;
|
||||
|
||||
public class EmulateDisassemblerContext implements DisassemblerContext {
|
||||
|
||||
|
@ -72,7 +69,7 @@ public class EmulateDisassemblerContext implements DisassemblerContext {
|
|||
contextRegValue = null;
|
||||
}
|
||||
if (contextRegValue == null) {
|
||||
ProgramContextImpl defaultContext = new ProgramContextImpl(language.getRegisters());
|
||||
ProgramContextImpl defaultContext = new ProgramContextImpl(language);
|
||||
language.applyContextSettings(defaultContext);
|
||||
contextRegValue = defaultContext.getDefaultValue(contextReg, addr);
|
||||
if (contextRegValue == null) {
|
||||
|
|
|
@ -49,8 +49,7 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
public ProgramRegisterContextDB(DBHandle dbHandle, ErrorHandler errHandler, Language lang,
|
||||
CompilerSpec compilerSpec, AddressMap addrMap, Lock lock, int openMode,
|
||||
CodeManager codeMgr, TaskMonitor monitor) throws VersionException, CancelledException {
|
||||
|
||||
super(lang.getRegisters());
|
||||
super(lang);
|
||||
this.addrMap = addrMap;
|
||||
this.dbHandle = dbHandle;
|
||||
this.errorHandler = errHandler;
|
||||
|
@ -194,6 +193,9 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
@Override
|
||||
public void setProgram(ProgramDB program) {
|
||||
this.program = program;
|
||||
if (program.getLanguage() != language) {
|
||||
throw new IllegalArgumentException("Program does not correspond to current language");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -306,16 +308,16 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
AddressSetView programMemory, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (translator == null) {
|
||||
Language lang = program.getLanguage();
|
||||
// Language instance unchanged
|
||||
boolean clearContext = Boolean.valueOf(
|
||||
lang.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE));
|
||||
language.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE));
|
||||
if (clearContext) {
|
||||
RegisterValueStore store = registerValueMap.get(baseContextRegister);
|
||||
if (store != null) {
|
||||
store.clearAll();
|
||||
}
|
||||
}
|
||||
initializeDefaultValues(lang, newCompilerSpec);
|
||||
initializeDefaultValues(language, newCompilerSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -350,11 +352,9 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
|
|||
registerValueMap.remove(register);
|
||||
}
|
||||
|
||||
initializeDefaultValues(newLanguage, newCompilerSpec);
|
||||
init(newLanguage);
|
||||
|
||||
registers = newLanguage.getRegisters();
|
||||
baseContextRegister = newLanguage.getContextBaseRegister();
|
||||
init();
|
||||
initializeDefaultValues(newLanguage, newCompilerSpec);
|
||||
|
||||
registerValueMap.clear();
|
||||
initializedCurrentValues();
|
||||
|
|
|
@ -284,7 +284,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||
bmMgr = program.getBookmarkManager();
|
||||
}
|
||||
else {
|
||||
defaultLanguageContext = new ProgramContextImpl(language.getRegisters());
|
||||
defaultLanguageContext = new ProgramContextImpl(language);
|
||||
language.applyContextSettings(defaultLanguageContext);
|
||||
}
|
||||
|
||||
|
@ -1496,11 +1496,6 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private static Register[] getContextRegisters(Register baseContextRegister) {
|
||||
return baseContextRegister != null ? new Register[] { baseContextRegister }
|
||||
: new Register[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>DisassemblerProgramContext</code> is used as a proxy program context due to the
|
||||
* delayed nature of laying down instructions and their associated context state.
|
||||
|
@ -1517,7 +1512,7 @@ public class Disassembler implements DisassemblerConflictHandler {
|
|||
private InstructionContext instructionContextCache = null;
|
||||
|
||||
DisassemblerProgramContext() {
|
||||
super(getContextRegisters(Disassembler.this.baseContextRegister));
|
||||
super(Disassembler.this.language); // getContextRegisters(Disassembler.this.baseContextRegister));
|
||||
if (realProgramContext != null) {
|
||||
setDefaultDisassemblyContext(realProgramContext.getDefaultDisassemblyContext());
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.model.lang;
|
|||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class RegisterBuilder {
|
||||
|
||||
|
@ -44,14 +45,18 @@ public class RegisterBuilder {
|
|||
}
|
||||
|
||||
public void addRegister(Register register) {
|
||||
Register aliasedReg = null;
|
||||
String name = register.getName();
|
||||
if (registerMap.get(name) != null) {
|
||||
Msg.error(this, "Duplicate register name: " + name);
|
||||
// TODO: should we throw exception - hopefully sleigh will prevent this condition
|
||||
}
|
||||
for (Register reg : registerList) {
|
||||
if (reg.getAddress().equals(register.getAddress()) &&
|
||||
reg.getLeastSignificantBit() == register.getLeastSignificantBit() &&
|
||||
reg.getBitLength() == register.getBitLength()) {
|
||||
// define as register alias
|
||||
reg.addAlias(register.getName());
|
||||
registerMap.put(register.getName(), reg);
|
||||
reg.addAlias(name);
|
||||
addRegisterToMap(register);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +64,14 @@ public class RegisterBuilder {
|
|||
contextAddress = register.getAddress();
|
||||
}
|
||||
registerList.add(register);
|
||||
registerMap.put(register.getName(), register);
|
||||
addRegisterToMap(register);
|
||||
}
|
||||
|
||||
private void addRegisterToMap(Register register) {
|
||||
String name = register.getName();
|
||||
registerMap.put(name, register);
|
||||
registerMap.put(name.toLowerCase(), register);
|
||||
registerMap.put(name.toUpperCase(), register);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -132,7 +132,8 @@ public class RegisterManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns context base register or null if one has not been defined by the language.
|
||||
* Get context base-register
|
||||
* @return context base register or null if one has not been defined by the language.
|
||||
*/
|
||||
public Register getContextBaseRegister() {
|
||||
return contextBaseRegister;
|
||||
|
@ -140,9 +141,8 @@ public class RegisterManager {
|
|||
|
||||
/**
|
||||
* Returns the largest register located at the specified address
|
||||
*
|
||||
* @param addr
|
||||
* @return largest register
|
||||
* @param addr register address
|
||||
* @return register or null if not found
|
||||
*/
|
||||
public Register getRegister(Address addr) {
|
||||
if (!addr.isRegisterAddress() && !addr.getAddressSpace().hasMappedRegisters()) {
|
||||
|
@ -154,8 +154,8 @@ public class RegisterManager {
|
|||
/**
|
||||
* Returns all registers located at the specified address
|
||||
*
|
||||
* @param addr
|
||||
* @return largest register
|
||||
* @param addr register address
|
||||
* @return array of registers found (may be empty)
|
||||
*/
|
||||
public Register[] getRegisters(Address addr) {
|
||||
if (addr.isRegisterAddress() || addr.getAddressSpace().hasMappedRegisters()) {
|
||||
|
@ -177,12 +177,10 @@ public class RegisterManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest register at the specified address whose size is
|
||||
* greater than or equal the specified size.
|
||||
* Get register by address and size
|
||||
* @param addr register address
|
||||
* @param size the size of the register (in bytes). A value of 0 will return the
|
||||
* largest register at the specified addr
|
||||
* @return register
|
||||
* @param size register size
|
||||
* @return register or null if not found
|
||||
*/
|
||||
public Register getRegister(Address addr, int size) {
|
||||
if (!addr.isRegisterAddress() && !addr.getAddressSpace().hasMappedRegisters()) {
|
||||
|
@ -192,24 +190,29 @@ public class RegisterManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the register with the given name;
|
||||
* @param name the name of the register to retrieve
|
||||
* Get register by name. A semi-case-insensitive lookup is performed.
|
||||
* The specified name must match either the case-sensitive name or
|
||||
* be entirely lowercase or uppercase.
|
||||
* @param name register name
|
||||
* @return register or null if not found
|
||||
*/
|
||||
public Register getRegister(String name) {
|
||||
return registerNameMap.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of all registers.
|
||||
* @return all registers
|
||||
* Get all registers. Array returned is not protected and must not be modified
|
||||
* by caller.
|
||||
* @return array of all registers defined
|
||||
*/
|
||||
public Register[] getRegisters() {
|
||||
return registers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of vector registers, sorted first by size and then by offset
|
||||
* @return sorted vector registers
|
||||
* Get all vector registers indentified by processor specification
|
||||
* in sorted order based upon address and size.
|
||||
* @return all vector registers
|
||||
*/
|
||||
public Register[] getSortedVectorRegisters() {
|
||||
if (sortedVectorRegisters == null) {
|
||||
|
|
|
@ -561,6 +561,12 @@ public class SymbolUtilities {
|
|||
* @param name the dynamic label name to parse into an address.
|
||||
*/
|
||||
public static Address parseDynamicName(AddressFactory factory, String name) {
|
||||
|
||||
// strip leading underscores
|
||||
while (name.startsWith(UNDERSCORE)) {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
String[] pieces = name.split(UNDERSCORE);
|
||||
if (pieces.length < 2) { // if we have less than two pieces, then this is not a dynamic name.
|
||||
return null;
|
||||
|
|
|
@ -18,16 +18,15 @@ package ghidra.program.util;
|
|||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.DefaultProgramContext;
|
||||
import ghidra.program.model.listing.ProgramContext;
|
||||
|
||||
abstract public class AbstractProgramContext implements ProgramContext, DefaultProgramContext {
|
||||
|
||||
protected Language language;
|
||||
protected Register[] registers;
|
||||
protected Register baseContextRegister;
|
||||
private Map<String, Register> registerNameMap; // lazy initialized only when getRegister(name) called
|
||||
|
||||
private boolean hasNonFlowingContext = false;
|
||||
private byte[] nonFlowingContextRegisterMask;
|
||||
|
@ -35,17 +34,8 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP
|
|||
|
||||
protected RegisterValue defaultDisassemblyContext;
|
||||
|
||||
protected AbstractProgramContext(Register[] registers) {
|
||||
this.registers = registers;
|
||||
|
||||
init();
|
||||
|
||||
if (baseContextRegister != null) {
|
||||
nonFlowingContextRegisterMask = baseContextRegister.getBaseMask().clone();
|
||||
Arrays.fill(nonFlowingContextRegisterMask, (byte) 0);
|
||||
flowingContextRegisterMask = nonFlowingContextRegisterMask.clone();
|
||||
initContextBitMasks(baseContextRegister);
|
||||
}
|
||||
protected AbstractProgramContext(Language language) {
|
||||
init(language);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,37 +99,22 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP
|
|||
return value.clearBitValues(flowingContextRegisterMask);
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
registerNameMap = null;
|
||||
baseContextRegister = null;
|
||||
for (Register register : registers) {
|
||||
if (register.isProcessorContext()) {
|
||||
baseContextRegister = register.getBaseRegister();
|
||||
break; // should only be one
|
||||
}
|
||||
}
|
||||
protected void init(Language language) {
|
||||
this.language = language;
|
||||
this.registers = language.getRegisters();
|
||||
baseContextRegister = language.getContextBaseRegister();
|
||||
if (baseContextRegister == null) {
|
||||
baseContextRegister =
|
||||
new Register("DEFAULT_CONTEXT", "DEFAULT_CONTEXT", Address.NO_ADDRESS, 4, true, 0);
|
||||
}
|
||||
defaultDisassemblyContext = new RegisterValue(baseContextRegister);
|
||||
}
|
||||
|
||||
private Map<String, Register> getRegisterNameMap() {
|
||||
if (registerNameMap != null) {
|
||||
return registerNameMap;
|
||||
}
|
||||
// if register map hasn't been initialized, initialize it
|
||||
registerNameMap = new HashMap<String, Register>();
|
||||
|
||||
// NOTE: if you want upper case names recognized, override this method and add them
|
||||
for (Register register : registers) {
|
||||
registerNameMap.put(register.getName(), register);
|
||||
for (String alias : register.getAliases()) {
|
||||
registerNameMap.put(alias, register);
|
||||
}
|
||||
if (baseContextRegister != null) {
|
||||
nonFlowingContextRegisterMask = baseContextRegister.getBaseMask().clone();
|
||||
Arrays.fill(nonFlowingContextRegisterMask, (byte) 0);
|
||||
flowingContextRegisterMask = nonFlowingContextRegisterMask.clone();
|
||||
initContextBitMasks(baseContextRegister);
|
||||
}
|
||||
return registerNameMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -155,7 +130,7 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP
|
|||
|
||||
@Override
|
||||
public final Register getRegister(String name) {
|
||||
return getRegisterNameMap().get(name);
|
||||
return language.getRegister(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,8 +20,7 @@ import java.util.*;
|
|||
|
||||
import ghidra.program.database.register.InMemoryRangeMapAdapter;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.ContextChangeException;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -34,8 +33,8 @@ abstract public class AbstractStoredProgramContext extends AbstractProgramContex
|
|||
|
||||
private Set<Register> registersWithValues; // cached set, recomputed whenever null
|
||||
|
||||
protected AbstractStoredProgramContext(Register[] registers) {
|
||||
super(registers);
|
||||
protected AbstractStoredProgramContext(Language language) {
|
||||
super(language);
|
||||
registerValueMap = new HashMap<>();
|
||||
defaultRegisterValueMap = new HashMap<>();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,6 +16,7 @@
|
|||
package ghidra.program.util;
|
||||
|
||||
import ghidra.program.database.register.InMemoryRangeMapAdapter;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
||||
/**
|
||||
|
@ -24,11 +24,11 @@ import ghidra.program.model.lang.Register;
|
|||
*/
|
||||
public class ProgramContextImpl extends AbstractStoredProgramContext {
|
||||
/**
|
||||
* Construct a new program context with the indicated registers.
|
||||
* @param regs array of handles to registers
|
||||
* Construct a new program context
|
||||
* @param language program language
|
||||
*/
|
||||
public ProgramContextImpl(Register[] regs) {
|
||||
super(regs);
|
||||
public ProgramContextImpl(Language language) {
|
||||
super(language);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue