Merge remote-tracking branch 'origin/GP-38_ghidra1_CaseInsensitiveRegisterLookup'

This commit is contained in:
ghidra1
2020-07-24 16:16:08 -04:00
54 changed files with 577 additions and 605 deletions
@@ -219,8 +219,7 @@ public class BuildResultState extends GhidraScript {
// }
// }
//
Register[] regs = currentProgram.getLanguage().getRegisters();
List<Register> registers = Arrays.asList(regs);
List<Register> registers = currentProgram.getLanguage().getRegisters();
try {
Register reg = askChoice("Results Query", "Select Register:", registers, null);
while (reg != null) {
@@ -309,8 +309,7 @@ public class ApplyFunctionSignatureCmd extends BackgroundCommand {
Program program = function.getProgram();
Address entryPoint = function.getEntryPoint();
SymbolUtilities.validateName(name, entryPoint, SymbolType.FUNCTION,
program.getAddressMap().getAddressFactory());
SymbolUtilities.validateName(name);
SymbolTable symbolTable = program.getSymbolTable();
Symbol sym = symbolTable.getPrimarySymbol(entryPoint);
@@ -31,7 +31,6 @@ import ghidra.program.util.SymbolicPropogator.Value;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
/**
* CallDepthChangeInfo.java
@@ -89,7 +88,7 @@ public class CallDepthChangeInfo {
this.program = func.getProgram();
frameReg = program.getCompilerSpec().getStackPointer();
try {
initialize(func, func.getBody(), frameReg, TaskMonitorAdapter.DUMMY_MONITOR);
initialize(func, func.getBody(), frameReg, TaskMonitor.DUMMY);
}
catch (CancelledException e) {
throw new RuntimeException("Unexpected Exception", e);
@@ -532,7 +531,7 @@ public class CallDepthChangeInfo {
st.push(func.getEntryPoint());
st.push(new Integer(0));
st.push(Boolean.TRUE);
ProcessorContextImpl procContext = new ProcessorContextImpl(trans.getRegisters());
ProcessorContextImpl procContext = new ProcessorContextImpl(program.getLanguage());
AddressSet undone = new AddressSet(func.getBody());
AddressSet badStackSet = new AddressSet(undone);
@@ -903,9 +902,9 @@ public class CallDepthChangeInfo {
Stack<Object> st = new Stack<Object>();
st.push(func.getEntryPoint());
st.push(new Integer(0));
st.push(Integer.valueOf(0));
st.push(Boolean.TRUE);
ProcessorContextImpl procContext = new ProcessorContextImpl(trans.getRegisters());
ProcessorContextImpl procContext = new ProcessorContextImpl(program.getLanguage());
AddressSet undone = new AddressSet(func.getBody());
AddressSet badStackSet = new AddressSet(undone);
@@ -955,7 +954,7 @@ public class CallDepthChangeInfo {
Address[] flows = instr.getFlows();
for (Address flow2 : flows) {
st.push(flow2);
st.push(new Integer(stackPointerDepth));
st.push(Integer.valueOf(stackPointerDepth));
st.push(stackOK);
}
}
@@ -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,6 +15,8 @@
*/
package ghidra.app.merge.listing;
import java.util.*;
import ghidra.app.merge.MergeResolver;
import ghidra.app.merge.ProgramMultiUserMergeManager;
import ghidra.app.merge.tool.ListingMergePanel;
@@ -27,9 +28,6 @@ import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.util.Arrays;
import java.util.Comparator;
/**
* <code>ProgramContextMergeManager</code> merges register value changes
* for multi-user program versions. It merges changes for each named register
@@ -70,7 +68,7 @@ public class ProgramContextMergeManager implements MergeResolver, ListingMergeCo
ProgramContext latestContext;
ProgramContext myContext;
ProgramContext resultContext;
Register[] registers;
List<Register> registers;
/** Used to determine differences between the original program and latest program. */
ProgramDiff diffOriginalLatest;
@@ -187,21 +185,19 @@ public class ProgramContextMergeManager implements MergeResolver, ListingMergeCo
mergePanel.setTopComponent(conflictInfoPanel);
}
try {
String[] latestNames = latestContext.getRegisterNames();
String[] myNames = myContext.getRegisterNames();
Arrays.sort(latestNames);
Arrays.sort(myNames);
if (!Arrays.equals(latestNames, myNames)) {
List<String> latestNames = latestContext.getRegisterNames();
List<String> myNames = myContext.getRegisterNames();
if (!latestNames.equals(myNames)) {
mergeManager.setStatusText("Program Context Registers don't match between the programs.");
cancel();
return;
}
Register[] regs = latestContext.getRegisters();
ArrayList<Register> regs = new ArrayList<>(latestContext.getRegisters());
// 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.
Arrays.sort(regs, new Comparator<Register>() {
Collections.sort(regs, new Comparator<Register>() {
@Override
public int compare(Register r1, Register r2) {
return r2.getBitLength() - r1.getBitLength();
@@ -211,15 +207,16 @@ public class ProgramContextMergeManager implements MergeResolver, ListingMergeCo
int transactionID = resultPgm.startTransaction(getDescription());
boolean commit = false;
try {
int numRegs = regs.length;
int numRegs = regs.size();
monitor.initialize(numRegs);
// Get the conflicts for each register
for (int i = 0; i < numRegs; i++) {
if (regs[i].isProcessorContext()) {
Register reg = regs.get(i);
if (reg.isProcessorContext()) {
continue; // context register handle by code unit merge
}
String regName = regs[i].getName();
String regName = reg.getName();
int currentProgressPercentage = (int) (((float) 100 / numRegs) * i);
mergeManager.updateProgress(currentProgressPercentage,
"Merging register values for " + regName);
@@ -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) {
@@ -47,9 +47,9 @@ public class ProcessorStateDialog extends DialogComponentProvider {
public ProcessorStateDialog(ProgramContext programContext) {
super(TITLE, true, false, true, false);
this.programContext = programContext;
Register[] contextRegisters = programContext.getProcessorStateRegisters();
registerList = new ArrayList<>();
for (Register register : contextRegisters) {
for (Register register : programContext.getContextRegisters()) {
if (!register.isBaseRegister()) {
registerList.add(register);
}
@@ -172,8 +172,8 @@ class VarnodeLocationCellEditor extends AbstractCellEditor implements TableCellE
private Component createRegisterCombo(VarnodeInfo varnode) {
ProgramContext programContext = program.getProgramContext();
Register[] contextRegisters = programContext.getRegisters();
List<Register> validItems = new ArrayList<>(Arrays.asList(contextRegisters));
List<Register> validItems = new ArrayList<>(programContext.getRegisters());
for (Iterator<Register> iter = validItems.iterator(); iter.hasNext();) {
Register register = iter.next();
@@ -186,7 +186,7 @@ public class RegisterFieldFactory extends FieldFactory {
private List<Register> getSetRegisters(Function function) {
Program program = function.getProgram();
ProgramContext programContext = program.getProgramContext();
Register[] registers = programContext.getRegisters();
Register[] registers = programContext.getRegistersWithValues();
Address address = function.getEntryPoint();
List<Register> setRegisters = new ArrayList<>();
for (Register register : registers) {
@@ -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,21 +15,23 @@
*/
package ghidra.app.util.xml;
import ghidra.app.util.importer.*;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.util.*;
import ghidra.util.exception.*;
import ghidra.util.task.*;
import ghidra.util.xml.*;
import ghidra.xml.*;
import java.io.*;
import java.math.*;
import java.io.IOException;
import java.math.BigInteger;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.SAXParseException;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import ghidra.util.XmlProgramUtilities;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.xml.*;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
* XML manager for register values.
@@ -87,10 +88,11 @@ class RegisterValuesXmlMgr {
* Returns list of unique registers which do not overlap any smaller
* registers.
*/
private Register[] getUniqueRegisters() {
private List<Register> getUniqueRegisters() {
Register[] regs = context.getRegisters();
Arrays.sort(regs, new Comparator<Register>() {
ArrayList<Register> regs = new ArrayList<>(context.getRegisters());
Collections.sort(regs, new Comparator<Register>() {
@Override
public int compare(Register r1, Register r2) {
int size1 = r1.getMinimumByteSize();
int size2 = r2.getMinimumByteSize();
@@ -101,30 +103,6 @@ class RegisterValuesXmlMgr {
}
});
// ArrayList list = new ArrayList();
// for (int i = 0; i < regs.length; i++) {
//
// Register reg = regs[i];
// int minOffset = reg.getOffset();
// int maxOffset = minOffset + reg.getSize() - 1;
//
// // Skip if reg is broken into smaller registers
// boolean overlap = false;
// for (int n = 0; n < i; n++) {
// int off = regs[n].getOffset();
// if (off >= minOffset && off <= maxOffset) {
// overlap = true;
// break;
// }
// }
// if (!overlap) {
// list.add(reg);
// }
// }
//
// regs = new Register[list.size()];
// list.toArray(regs);
return regs;
}
@@ -140,11 +118,7 @@ class RegisterValuesXmlMgr {
writer.startElement("REGISTER_VALUES");
Register[] regs = getUniqueRegisters();
//for (int i = 0; i < regs.length; i++) {
//Register reg = regs[i];
//}
List<Register> regs = getUniqueRegisters();
if (set == null) {
set = program.getMemory();
}
@@ -156,8 +130,7 @@ class RegisterValuesXmlMgr {
AddressRange range = rangeIter.next();
for (int i = 0; i < regs.length; i++) {
Register reg = regs[i];
for (Register reg : regs) {
AddressRangeIterator it = context.getRegisterValueAddressRanges(reg, range.getMinAddress(), range.getMaxAddress());
while(it.hasNext()) {
monitor.checkCanceled();
@@ -1156,13 +1156,8 @@ public class ProgramDiff {
private AddressSet getProgramContextDifferences(AddressSetView addressSet, TaskMonitor monitor)
throws ProgramConflictException, CancelledException {
AddressSet differences = new AddressSet();
ProgramContext pc1 = program1.getProgramContext();
ProgramContext pc2 = program2.getProgramContext();
String[] names1 = pc1.getRegisterNames();
String[] names2 = pc2.getRegisterNames();
Arrays.sort(names1);
Arrays.sort(names2);
if (!Arrays.equals(names1, names2)) {
if (!ProgramMemoryComparator.sameProgramContextRegisterNames(program1, program2)) {
throw new ProgramConflictException(
"Program Context Registers don't match between the programs.");
}
@@ -1171,7 +1166,10 @@ public class ProgramDiff {
AddressSet inCommon = pgmMemComp.getAddressesInCommon();
addressSet = (addressSet != null) ? inCommon.intersect(addressSet) : inCommon;
for (String element : names1) {
ProgramContext pc1 = program1.getProgramContext();
ProgramContext pc2 = program2.getProgramContext();
for (String element : pc1.getRegisterNames()) {
monitor.checkCanceled();
Register rb1 = pc1.getRegister(element);
Register rb2 = pc2.getRegister(element);
@@ -383,9 +383,8 @@ public class ProgramDiffDetails {
l1 = p1.getListing();
l2 = p2.getListing();
Register[] descs1 = p1.getProgramContext().getRegisters();
maxRegisterName = "Register".length(); // default name length.
for (Register element : descs1) {
for (Register element : p1.getProgramContext().getRegisters()) {
maxRegisterName = Math.max(maxRegisterName, element.getName().length());
}
}
@@ -1285,13 +1284,8 @@ public class ProgramDiffDetails {
* @throws ConcurrentModificationException if analysis is modifying the program context.
*/
private void addProgramContextDetails() throws ConcurrentModificationException {
ProgramContext pc1 = p1.getProgramContext();
ProgramContext pc2 = p2.getProgramContext();
String[] names1 = pc1.getRegisterNames();
String[] names2 = pc2.getRegisterNames();
Arrays.sort(names1);
Arrays.sort(names2);
if (!Arrays.equals(names1, names2)) {
if (!ProgramMemoryComparator.sameProgramContextRegisterNames(p1, p2)) {
addDiffHeader("Program Context");
addText(
indent1 + "Program Context Registers don't match between the programs." + newLine);
@@ -1299,8 +1293,9 @@ public class ProgramDiffDetails {
}
// Check all the register's values and output any differences.
Register[] descs1 = pc1.getRegisters();
for (Register reg1 : descs1) {
ProgramContext pc1 = p1.getProgramContext();
ProgramContext pc2 = p2.getProgramContext();
for (Register reg1 : pc1.getRegisters()) {
addRegisterDiffDetails(pc1, pc2, reg1);
}
}
@@ -15,12 +15,13 @@
*/
package ghidra.program.util;
import java.util.Arrays;
import java.util.List;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import java.util.Arrays;
/**
* <CODE>ProgramMemoryComparator</CODE> is a class for comparing two programs and
* determining the address differences between them.
@@ -120,15 +121,17 @@ public class ProgramMemoryComparator {
* @return true if the programs are alike (their language name or address spaces are the same).
*/
public static boolean similarPrograms(Program p1, Program p2) {
if (p1 == null || p2 == null)
if (p1 == null || p2 == null) {
return false;
}
if (p1.getLanguageID().equals(p2.getLanguageID())) {
return true;
}
AddressSpace[] spaces1 = p1.getLanguage().getAddressFactory().getAddressSpaces();
AddressSpace[] spaces2 = p2.getLanguage().getAddressFactory().getAddressSpaces();
if (spaces1.length != spaces2.length)
if (spaces1.length != spaces2.length) {
return false;
}
Arrays.sort(spaces1);
Arrays.sort(spaces2);
for (int i=0; i<spaces1.length; i++) {
@@ -279,14 +282,9 @@ public class ProgramMemoryComparator {
static public boolean sameProgramContextRegisterNames(Program program1, Program program2) {
ProgramContext pc1 = program1.getProgramContext();
ProgramContext pc2 = program2.getProgramContext();
String[] names1 = pc1.getRegisterNames();
String[] names2 = pc2.getRegisterNames();
Arrays.sort(names1);
Arrays.sort(names2);
if (!Arrays.equals(names1, names2)) {
return false;
}
return true;
List<String> names1 = pc1.getRegisterNames();
List<String> names2 = pc2.getRegisterNames();
return names1.equals(names2);
}
}
@@ -239,11 +239,11 @@ public class ProgramMerge implements PropertyVisitor {
ProgramContext resultContext = resultProgram.getProgramContext();
ProgramContext originContext = originProgram.getProgramContext();
Register[] originRegs = originContext.getRegisters();
ArrayList<Register> originRegs = new ArrayList<>(originContext.getRegisters());
// 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.
Arrays.sort(originRegs, (r1, r2) -> r2.getBitLength() - r1.getBitLength());
Collections.sort(originRegs, (r1, r2) -> r2.getBitLength() - r1.getBitLength());
AddressRangeIterator originRangeIter = originAddressSet.getAddressRanges();
while (originRangeIter.hasNext() && !monitor.isCancelled()) {
AddressRange originRange = originRangeIter.next();
@@ -81,9 +81,9 @@ public class SymbolicPropogator {
public SymbolicPropogator(Program program) {
this.program = program;
Register regs[] = program.getLanguage().getRegisters();
programContext = new ProgramContextImpl(regs);
spaceContext = new ProgramContextImpl(regs);
Language language = program.getLanguage();
programContext = new ProgramContextImpl(language);
spaceContext = new ProgramContextImpl(language);
setPointerMask(program);
setExternalRange(program);
@@ -208,8 +208,9 @@ public class SymbolicPropogator {
* @return
*/
protected VarnodeContext saveOffCurrentContext(Address startAddr) {
ProgramContext newValueContext = new ProgramContextImpl(programContext.getRegisters());
ProgramContext newSpaceContext = new ProgramContextImpl(programContext.getRegisters());
Language language = program.getLanguage();
ProgramContext newValueContext = new ProgramContextImpl(language);
ProgramContext newSpaceContext = new ProgramContextImpl(language);
VarnodeContext newContext = new VarnodeContext(program, newValueContext, newSpaceContext);
newContext.setDebug(debug);
int constantSpaceID = program.getAddressFactory().getConstantSpace().getSpaceID();
@@ -1389,7 +1389,7 @@ public class VarnodeContext implements ProcessorContext {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return offsetContext.getRegisters();
}
@@ -15,8 +15,7 @@
*/
package ghidra.app.cmd.disassemble;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.*;
import java.math.BigInteger;
@@ -338,8 +337,7 @@ public class DisassembleContextTest extends AbstractGhidraHeadedIntegrationTest
public void testFlowWithNoSaveIntoContextImpl() {
// Simple context does not contain default values
ProgramContext retainedContext =
new ProgramContextImpl(program.getLanguage().getRegisters());
ProgramContext retainedContext = new ProgramContextImpl(program.getLanguage());
Address addr = space.getAddress(0x0);
@@ -15,8 +15,7 @@
*/
package ghidra.app.util.viewer.field;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.math.BigInteger;
import java.util.*;
@@ -106,11 +105,10 @@ public class RegisterFieldFactoryTest extends AbstractGhidraHeadedIntegrationTes
}
private List<Register> getNonContextRegisters(ProgramContext pc) {
Register[] regs = pc.getRegisters();
List<Register> nonContextRegs = new ArrayList<Register>();
for (int i = 0; i < regs.length; i++) {
if (!regs[i].isProcessorContext()) {
nonContextRegs.add(regs[i]);
for (Register reg : pc.getRegisters()) {
if (!reg.isProcessorContext()) {
nonContextRegs.add(reg);
}
}
return nonContextRegs;
@@ -58,6 +58,21 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
mem = program.getMemory();
}
@Test
public void testRegisterNameLookup() {
ProgramContext programContext = program.getProgramContext();
boolean didSomething = false;
for (String regName : programContext.getRegisterNames()) {
Register reg = programContext.getRegister(regName);
assertNotNull(reg);
assertEquals(regName, reg.getName());
assertTrue(reg == programContext.getRegister(regName.toLowerCase()));
assertTrue(reg == programContext.getRegister(regName.toUpperCase()));
didSomething = true;
}
assertTrue(didSomething);
}
@Test
public void testAll() {
int id = program.startTransaction("Test");
@@ -73,10 +88,7 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
}
ProgramContext programContext = program.getProgramContext();
Register[] registers = null;
if (programContext != null) {
registers = programContext.getRegisters();
}
boolean didSomething = false;
Address startAddress = start;
Address endAddress = getAddress(0x30);
@@ -84,7 +96,7 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
// stick a value into each one!
BigInteger value = BigInteger.valueOf(255);
for (Register register : registers) {
for (Register register : programContext.getRegisters()) {
Register reg = register;
if (!reg.isBaseRegister() && reg.isProcessorContext()) {
continue;
@@ -136,7 +148,9 @@ public class ProgramContextTest extends AbstractGhidraHeadedIntegrationTest {
endAddress.getAddressSpace().getMaxAddress()),
programContext.getRegisterValueRangeContaining(reg, badAddress));
didSomething = true;
}
assertTrue(didSomething);
}
finally {
program.endTransaction(id, false);
@@ -132,7 +132,7 @@ public class ContextStateTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testStoreConstantWithEntryContext() {
ProgramContextImpl ctx = new ProgramContextImpl(lang.getRegisters());
ProgramContextImpl ctx = new ProgramContextImpl(lang);
ctx.setDefaultValue(
new RegisterValue(lang.getRegister("EAX"), new BigInteger("fedcba98", 16)), addr(1000),
addr(1000));
@@ -839,16 +839,13 @@ public class DecompileCallback {
return null;
}
ProgramContext context = program.getProgramContext();
Register[] regs = context.getRegisters();
if (regs == null || regs.length == 0) {
return null;
}
StringBuilder stringBuf = new StringBuilder();
stringBuf.append("<tracked_pointset");
Varnode.appendSpaceOffset(stringBuf, addr);
stringBuf.append(">\n");
for (Register reg : regs) {
for (Register reg : context.getRegisters()) {
if (reg.isProcessorContext()) {
continue;
}
@@ -29,7 +29,6 @@ src/main/java/ghidra/program/database/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/address/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/block/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/data/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/graph/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/lang/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/listing/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/mem/package.html||GHIDRA||||END|
@@ -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>
@@ -16,6 +16,7 @@
package ghidra.app.plugin.assembler.sleigh.sem;
import java.math.BigInteger;
import java.util.List;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
@@ -117,7 +118,7 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return lang.getRegisters();
}
@@ -1276,7 +1276,7 @@ public class SleighDebugLogger {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
if (originalContext != null) {
return originalContext.getRegisters();
}
@@ -140,7 +140,6 @@ public class SleighLanguage implements Language {
loadRegisters(registerBuilder);
readRemainingSpecification();
// registerManager = registerBuilder.getRegisterManager();
xrefRegisters();
instructProtoMap = new LinkedHashMap<>();
@@ -265,6 +264,11 @@ public class SleighLanguage implements Language {
return getRegisterManager().getContextBaseRegister();
}
@Override
public List<Register> getContextRegisters() {
return getRegisterManager().getContextRegisters();
}
@Override
public MemoryBlockDefinition[] getDefaultMemoryBlocks() {
return defaultMemoryBlocks;
@@ -331,10 +335,15 @@ public class SleighLanguage implements Language {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return getRegisterManager().getRegisters();
}
@Override
public List<String> getRegisterNames() {
return getRegisterManager().getRegisterNames();
}
@Override
public String getSegmentedSpace() {
return segmentedspace;
@@ -743,11 +752,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);
@@ -1074,11 +1079,8 @@ public class SleighLanguage implements Language {
}
private void xrefRegisters() {
Register[] regs = getRegisterManager().getRegisters();
for (Register register : regs) {
if (register.isProcessorContext()) {
contextcache.registerVariable(register);
}
for (Register register : getRegisterManager().getContextRegisters()) {
contextcache.registerVariable(register);
}
}
@@ -1581,7 +1583,8 @@ public class SleighLanguage implements Language {
}
@Override
public Register[] getSortedVectorRegisters() {
public List<Register> getSortedVectorRegisters() {
return registerManager.getSortedVectorRegisters();
}
}
@@ -16,6 +16,7 @@
package ghidra.app.util;
import java.math.BigInteger;
import java.util.List;
import ghidra.program.disassemble.DisassemblerContextImpl;
import ghidra.program.model.address.Address;
@@ -56,7 +57,7 @@ public class PseudoDisassemblerContext implements DisassemblerContext {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return disContext.getRegisters();
}
@@ -548,7 +548,7 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return procContext.getRegisters();
}
@@ -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) {
@@ -157,7 +154,7 @@ public class EmulateDisassemblerContext implements DisassemblerContext {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
throw new UnsupportedOperationException();
}
@@ -17,8 +17,7 @@ package ghidra.program.database.code;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
@@ -753,7 +752,7 @@ abstract class CodeUnitDB extends DatabaseObject implements CodeUnit, ProcessorC
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return programContext.getRegisters();
}
@@ -17,6 +17,7 @@ package ghidra.program.database.code;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.StringTokenizer;
import db.*;
@@ -130,8 +131,9 @@ class PrototypeManager {
RecordIterator it = contextTable.iterator();
while (it.hasNext()) {
monitor.setProgress(++count);
if (monitor.isCancelled())
if (monitor.isCancelled()) {
throw new IOException("Upgrade Cancelled");
}
Record rec = it.next();
String oldValue = rec.getString(0);
rec.setString(0, convertString(oldValue));
@@ -143,8 +145,9 @@ class PrototypeManager {
it = tempTable.iterator();
while (it.hasNext()) {
monitor.setProgress(++count);
if (monitor.isCancelled())
if (monitor.isCancelled()) {
throw new IOException("Upgrade Cancelled");
}
Record rec = it.next();
contextTable.putRecord(rec);
}
@@ -187,8 +190,9 @@ class PrototypeManager {
RecordIterator it = protoAdapter.getRecords();
while (it.hasNext()) {
monitor.setProgress(++count);
if (monitor.isCancelled())
if (monitor.isCancelled()) {
throw new IOException("Upgrade Cancelled");
}
Record rec = it.next();
tempAdapter.createRecord((int) rec.getKey(), rec.getLongValue(ADDR_COL),
rec.getBinaryData(BYTES_COL), rec.getBooleanValue(DELAY_COL));
@@ -201,8 +205,9 @@ class PrototypeManager {
it = tempAdapter.getRecords();
while (it.hasNext()) {
monitor.setProgress(++count);
if (monitor.isCancelled())
if (monitor.isCancelled()) {
throw new IOException("Upgrade Cancelled");
}
Record rec = it.next();
protoAdapter.createRecord((int) rec.getKey(), rec.getLongValue(ADDR_COL),
rec.getBinaryData(BYTES_COL), rec.getBooleanValue(DELAY_COL));
@@ -287,19 +292,10 @@ class PrototypeManager {
return 0;
}
// private boolean shouldSave(BigInteger value, BigInteger defaultValue) {
// if (value == null) {
// return false;
// }
// if (defaultValue == null) {
// return true;
// }
// return !value.equals(defaultValue);
//
// }
/**
* Get the prototype with the given ID.
* @param protoID prototype ID
* @return instruction prototype or null if not found
*/
InstructionPrototype getPrototype(int protoID) {
if (protoID < 0) {
@@ -449,25 +445,16 @@ class PrototypeManager {
this.address = address;
}
/**
* @see ghidra.program.model.lang.ProcessorContext#getRegister(java.lang.String)
*/
@Override
public Register getRegister(String name) {
return programContext.getRegister(name);
}
/**
* @see ghidra.program.model.lang.ProcessorContext#getRegisters()
*/
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return programContext.getRegisters();
}
/**
* @see ghidra.program.model.lang.ProcessorContext#hasValue(ghidra.program.model.lang.Register)
*/
@Override
public boolean hasValue(Register register) {
return false;
@@ -49,16 +49,14 @@ public class OldProgramContextDB implements ProgramContext, DefaultProgramContex
private DBHandle dbHandle;
private ErrorHandler errHandler;
private Register[] registers;
private Language language;
private AddressMap addrMap;
private int registerSpaceSize;
private Lock lock;
/**
* maintain values stored in registers for specified addresses and
* address ranges using the PropertyMap utilities.
*/
private HashMap<String, Register> registersMap;
private Map<Integer, AddressRangeMapDB> valueMaps;
private Register baseContextRegister;
protected Map<Register, RegisterValueStore> defaultRegisterValueMap;
@@ -82,28 +80,12 @@ public class OldProgramContextDB implements ProgramContext, DefaultProgramContex
this.errHandler = errHandler;
this.lock = lock;
this.addrMap = addrMap.getOldAddressMap();
this.registers = language.getRegisters();
this.language = language;
defaultRegisterValueMap = new HashMap<Register, RegisterValueStore>();
registersMap = new HashMap<String, Register>();
valueMaps = new HashMap<>();
registerSpaceSize = 0;
for (Register register : registers) {
String registerName = register.getName();
registersMap.put(registerName.toUpperCase(), register);
int offset = (register.getOffset() & 0xffff);
if (offset + register.getMinimumByteSize() > registerSpaceSize) {
registerSpaceSize = offset + register.getMinimumByteSize();
}
}
for (Register register : registers) {
if (register.isProcessorContext()) {
baseContextRegister = register.getBaseRegister();
break;
}
}
baseContextRegister = language.getContextBaseRegister();
if (baseContextRegister == null) {
baseContextRegister =
new Register("DEFAULT_CONTEXT", "DEFAULT_CONTEXT",
@@ -186,28 +168,18 @@ public class OldProgramContextDB implements ProgramContext, DefaultProgramContex
}
@Override
public 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()]);
public List<Register> getContextRegisters() {
return language.getContextRegisters();
}
@Override
public Register getRegister(String name) {
return registersMap.get(name.toUpperCase());
return language.getRegister(name);
}
@Override
public String[] getRegisterNames() {
List<String> list = new ArrayList<String>();
for (Register register : registers) {
list.add(register.getName());
}
return list.toArray(new String[list.size()]);
public List<String> getRegisterNames() {
return language.getRegisterNames();
}
@Override
@@ -273,8 +245,8 @@ public class OldProgramContextDB implements ProgramContext, DefaultProgramContex
}
@Override
public Register[] getRegisters() {
return registers;
public List<Register> getRegisters() {
return language.getRegisters();
}
public long getSigned(Address addr, Register reg) throws UnsupportedOperationException {
@@ -446,7 +418,7 @@ public class OldProgramContextDB implements ProgramContext, DefaultProgramContex
public Register[] getRegistersWithValues() {
if (registersWithValues == null) {
List<Register> tmp = new ArrayList<Register>();
for (Register register : registers) {
for (Register register : getRegisters()) {
AddressRangeIterator it = getRegisterValueAddressRanges(register);
if (it.hasNext()) {
tmp.add(register);
@@ -17,8 +17,7 @@ package ghidra.program.database.register;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.*;
import db.*;
import db.util.ErrorHandler;
@@ -49,8 +48,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;
@@ -68,7 +66,7 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple
initializedCurrentValues();
if (upgrade) {
upgrade(addrMap, lang, monitor);
upgrade(addrMap, monitor);
}
if (openMode == DBConstants.UPGRADE && oldContextDataExists) {
@@ -90,13 +88,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;
}
@@ -306,16 +304,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;
}
@@ -324,7 +322,8 @@ 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.
Arrays.sort(registers, (r1, r2) -> r2.getBitLength() - r1.getBitLength());
List<Register> registers = new ArrayList<Register>(language.getRegisters());
Collections.sort(registers, (r1, r2) -> r2.getBitLength() - r1.getBitLength());
// Map all register stores to new registers
for (Register register : registers) {
@@ -350,11 +349,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();
@@ -558,8 +558,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
newName = "";
}
else {
SymbolUtilities.validateName(newName, address, getSymbolType(),
symbolMgr.getAddressMap().getAddressFactory());
SymbolUtilities.validateName(newName);
nameChange = !oldName.equals(newName);
if (!namespaceChange && !nameChange) {
return;
@@ -2305,7 +2305,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try {
parent = validateNamespace(parent, addr, symbolType);
source = validateSource(source, name, addr, symbolType);
name = validateName(name, addr, symbolType, source);
name = validateName(name, source);
checkDuplicateSymbolName(addr, name, parent, symbolType);
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
@@ -2356,7 +2356,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try {
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
source = validateSource(source, name, addr, SymbolType.LABEL);
name = validateName(name, addr, SymbolType.LABEL, source);
name = validateName(name, source);
Symbol symbol = getSymbol(name, addr, namespace);
if (symbol != null) {
@@ -2400,7 +2400,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
source = validateSource(source, name, addr, SymbolType.FUNCTION);
name = validateName(name, addr, SymbolType.FUNCTION, source);
name = validateName(name, source);
Symbol[] symbols = getSymbols(addr);
@@ -2510,12 +2510,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return null;
}
private String validateName(String name, Address addr, SymbolType type, SourceType source)
private String validateName(String name, SourceType source)
throws InvalidInputException {
if (source == SourceType.DEFAULT) {
return "";
}
SymbolUtilities.validateName(name, addr, type, addrMap.getAddressFactory());
SymbolUtilities.validateName(name);
return name;
}
@@ -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);
if (realProgramContext != null) {
setDefaultDisassemblyContext(realProgramContext.getDefaultDisassemblyContext());
}
@@ -1732,7 +1727,7 @@ public class Disassembler implements DisassemblerConflictHandler {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return langauge.getRegisters();
}
@@ -566,7 +566,7 @@ public class DisassemblerContextImpl implements DisassemblerContext {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return programContext.getRegisters();
}
@@ -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,11 +206,21 @@ public interface Language {
public Register getRegister(AddressSpace addrspc, long offset, int size);
/**
* get the array of Register objects that this language supports.
* Get an unsorted unmodifiable list of Register objects that this language defines
* (including context registers).
*
* @return the array of processor registers.
* @return unmodifiable list of processor registers.
*/
public Register[] getRegisters();
public List<Register> getRegisters();
/**
* Get an alphabetical sorted unmodifiable list of original register names
* (including context registers). Names correspond to orignal register
* name and not aliases which may be defined.
*
* @return alphabetical sorted unmodifiable list of original register names.
*/
public List<String> getRegisterNames();
/**
* Get a register given the name of the register
@@ -235,11 +252,20 @@ public interface Language {
public Register getProgramCounter();
/**
* Returns context base register or null if one has not been defined by the
* Returns processor 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 an unsorted unmodifiable list of processor context registers that this language defines
* (includes context base register and its context field registers).
*
* @return unmodifiable list of processor registers.
*/
public List<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();
@@ -384,9 +412,9 @@ public interface Language {
public Exception getManualException();
/**
* Returns the array of vector registers, sorted first by size and then by name.
* @return sorted array of vector registers.
* Returns an unmodifiable list of vector registers, sorted first by size and then by name.
* @return unmodifiable list of vector registers.
*/
public Register[] getSortedVectorRegisters();
public List<Register> getSortedVectorRegisters();
}
@@ -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,8 +16,7 @@
package ghidra.program.model.lang;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* An implementation of processor context which contains the state of all
@@ -29,47 +27,41 @@ import java.util.Map;
*/
public final class ProcessorContextImpl implements ProcessorContext {
Map<Register, byte[]> values = new HashMap<Register, byte[]>();
Register[] registers;
Register baseContextRegister;
Language language;
public ProcessorContextImpl(ProcessorContext context) {
this(context.getRegisters());
for (Register register : registers) {
if (!register.isBaseRegister()) {
continue;
}
if (register.isProcessorContext()) {
baseContextRegister = register;
}
RegisterValue value = context.getRegisterValue(register);
if (value != null) {
setRegisterValue(value);
}
}
}
// public ProcessorContextImpl(ProcessorContext context) {
// this(context.getRegisters());
// for (Register register : registers) {
// if (!register.isBaseRegister()) {
// continue;
// }
// if (register.isProcessorContext()) {
// baseContextRegister = register;
// }
// RegisterValue value = context.getRegisterValue(register);
// if (value != null) {
// setRegisterValue(value);
// }
// }
// }
public ProcessorContextImpl(Register[] registers) {
this.registers = registers;
public ProcessorContextImpl(Language language) {
this.language = language;
}
@Override
public Register getBaseContextRegister() {
return baseContextRegister;
return language.getContextBaseRegister();
}
@Override
public Register getRegister(String name) {
for (Register register : registers) {
if (register.getName().equals(name)) {
return register;
}
}
return null;
return language.getRegister(name);
}
@Override
public Register[] getRegisters() {
return registers;
public List<Register> getRegisters() {
return language.getRegisters();
}
@Override
@@ -16,6 +16,7 @@
package ghidra.program.model.lang;
import java.math.BigInteger;
import java.util.List;
/**
* Defines the interface for an object containing the state
@@ -30,10 +31,10 @@ public interface ProcessorContextView {
public Register getBaseContextRegister();
/**
* Returns all the Registers for the processor
* Returns all the Registers for the processor as an unmodifiable list
* @return all the Registers for the processor
*/
public Register[] getRegisters();
public List<Register> getRegisters();
/**
* Get a Register given the name of a register
@@ -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,12 +15,13 @@
*/
package ghidra.program.model.lang;
import java.math.BigInteger;
import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.ContextChangeException;
import ghidra.program.model.listing.ProgramContext;
import java.math.BigInteger;
/**
* Implementation for the program processor context interface
*/
@@ -45,17 +45,11 @@ public class ProgramProcessorContext implements ProcessorContext {
return context.getBaseContextRegister();
}
/**
* @see ghidra.program.model.lang.ProcessorContext#getRegisters()
*/
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return context.getRegisters();
}
/**
* @see ghidra.program.model.lang.ProcessorContext#getRegister(java.lang.String)
*/
@Override
public Register getRegister(String name) {
return context.getRegister(name);
@@ -71,10 +65,6 @@ public class ProgramProcessorContext implements ProcessorContext {
return context.getRegisterValue(register, addr);
}
/**
* @throws ContextChangeException
* @see ghidra.program.model.lang.ProcessorContext#setValue(ghidra.program.model.lang.Register, java.math.BigInteger)
*/
@Override
public void setValue(Register register, BigInteger value) throws ContextChangeException {
context.setValue(register, addr, addr, value);
@@ -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.
@@ -22,6 +21,7 @@ package ghidra.program.model.lang;
*/
import java.math.BigInteger;
import java.util.List;
public class ReadOnlyProcessorContext implements ProcessorContext {
@@ -42,7 +42,7 @@ public class ReadOnlyProcessorContext implements ProcessorContext {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
return context.getRegisters();
}
@@ -18,11 +18,12 @@ package ghidra.program.model.lang;
import java.util.*;
import ghidra.program.model.address.Address;
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() {
@@ -44,14 +45,19 @@ 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
}
// 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(register.getName());
registerMap.put(register.getName(), reg);
reg.addAlias(name);
addRegisterToNameMap(name, register);
return;
}
}
@@ -59,7 +65,19 @@ public class RegisterBuilder {
contextAddress = register.getAddress();
}
registerList.add(register);
registerMap.put(register.getName(), register);
addRegisterToNameMap(name, register);
}
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());
}
/**
@@ -71,31 +89,15 @@ 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);
}
}
}
/**
* Compute current register collection and instantiate a {@link RegisterManager}
* @return new register manager instance
*/
public RegisterManager getRegisterManager() {
return new RegisterManager(computeRegisters());
return new RegisterManager(computeRegisters(), registerMap);
}
private Register[] computeRegisters() {
private List<Register> computeRegisters() {
List<Register> regList = new LinkedList<>();
List<Register> unprocessed = new LinkedList<>(registerList);
@@ -117,8 +119,7 @@ public class RegisterBuilder {
}
bitSize = nextLargerSize;
}
return registerList.toArray(new Register[registerList.size()]);
return registerList;
}
private Register[] getChildren(Register parent, List<Register> regList) {
@@ -159,6 +160,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);
@@ -180,8 +182,8 @@ public class RegisterBuilder {
return false;
}
register.rename(newName);
registerMap.remove(oldName);
registerMap.put(newName, register);
removeRegisterFromNameMap(oldName);
addRegisterToNameMap(newName, register);
return true;
}
@@ -17,19 +17,23 @@ package ghidra.program.model.lang;
import java.util.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.OldGenericNamespaceAddress;
import ghidra.program.model.address.*;
public class RegisterManager {
Register[] registers;
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>>();
private List<Register> registers;
private Map<String, Register> registerNameMap = new HashMap<String, Register>(); // include aliases and case-variations
private List<String> registerNames; // alphabetical sorted list, excludes aliases
private List<Register> contextRegisters;
private Register contextBaseRegister;
private Map<RegisterSizeKey, Register> sizeMap = new HashMap<RegisterSizeKey, Register>();
private Map<Address, List<Register>> registerAddressMap =
new HashMap<Address, List<Register>>();
/**Collection of vector registers, sorted first by size and then by offset**/
private TreeSet<Register> sortedVectorRegisters;
/**List of vector registers, sorted first by size and then by offset**/
private List<Register> sortedVectorRegisters;
class RegisterSizeKey {
Address address;
@@ -74,21 +78,32 @@ public class RegisterManager {
}
};
RegisterManager(Register[] cookedRegisters) {
registers = cookedRegisters;
/**
* Construct RegisterManager
* @param registers 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(List<Register> registers, Map<String, Register> registerNameMap) {
this.registers = Collections.unmodifiableList(registers);
this.registerNameMap = Collections.unmodifiableMap(registerNameMap);
initialize();
}
private void initialize() {
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;
List<String> registerNameList = new ArrayList<String>();
List<Register> contextRegisterList = new ArrayList<Register>();
ArrayList<Register> registerListSortedBySize = new ArrayList<>(registers); // copy for sorting
Collections.sort(registerListSortedBySize, registerSizeComparator);
for (Register reg : registerListSortedBySize) {
String regName = reg.getName();
registerNameList.add(regName);
if (reg.isProcessorContext()) {
contextRegisterList.add(reg);
if (reg.isBaseRegister()) {
contextBaseRegister = reg;
}
}
Address addr = reg.getAddress();
@@ -110,10 +125,13 @@ public class RegisterManager {
}
}
// handle the register size 0 case;
Collections.reverse(registerList);
for (Register register : registerList) {
Collections.reverse(registerListSortedBySize);
for (Register register : registerListSortedBySize) {
sizeMap.put(new RegisterSizeKey(register.getAddress(), 0), register);
}
contextRegisters = Collections.unmodifiableList(contextRegisterList);
Collections.sort(registerNameList);
registerNames = Collections.unmodifiableList(registerNameList);
}
private void populateSizeMapBigEndian(Register reg) {
@@ -132,33 +150,54 @@ 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;
}
/**
* Returns the largest register located at the specified address
* Get unsorted unmodifiable list of all processor context registers (include base context register and children)
* @return all processor context registers
*/
public List<Register> getContextRegisters() {
return contextRegisters;
}
/**
* Get an alphabetical sorted unmodifiable list of original register names
* (including context registers). Names correspond to orignal register
* name and not aliases which may be defined.
*
* @param addr
* @return largest register
* @return alphabetical sorted unmodifiable list of original register names.
*/
public List<String> getRegisterNames() {
return registerNames;
}
/**
* Returns the largest register located at the specified address
* @param addr register address
* @return register or null if not found
*/
public Register getRegister(Address addr) {
if (!addr.isRegisterAddress() && !addr.getAddressSpace().hasMappedRegisters()) {
return null;
AddressSpace space = addr.getAddressSpace();
if (space.isRegisterSpace() || space.hasMappedRegisters()) {
return sizeMap.get(new RegisterSizeKey(addr, 0));
}
return sizeMap.get(new RegisterSizeKey(addr, 0));
return null;
}
/**
* 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()) {
AddressSpace space = addr.getAddressSpace();
if (space.isRegisterSpace() || space.hasMappedRegisters()) {
List<Register> list = registerAddressMap.get(getGlobalAddress(addr));
if (list != null) {
Register[] regs = new Register[list.size()];
@@ -177,50 +216,55 @@ 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()) {
return null;
AddressSpace space = addr.getAddressSpace();
if (space.isRegisterSpace() || space.hasMappedRegisters()) {
return sizeMap.get(new RegisterSizeKey(addr, size));
}
return sizeMap.get(new RegisterSizeKey(addr, size));
return null;
}
/**
* 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 as an unsorted unmodifiable list.
* @return unmodifiable list of all registers defined
*/
public Register[] getRegisters() {
public List<Register> getRegisters() {
return registers;
}
/**
* Returns the array of vector registers, sorted first by size and then by offset
* @return sorted vector registers
* Get an unmodifiable list of all vector registers indentified by the processor specification
* in sorted order based upon address and size.
* @return all vector registers as unmodifiable list
*/
public Register[] getSortedVectorRegisters() {
public List<Register> getSortedVectorRegisters() {
if (sortedVectorRegisters == null) {
sortedVectorRegisters = new TreeSet<Register>(RegisterManager::compareVectorRegisters);
for (Register reg : getRegisters()) {
ArrayList<Register> list = new ArrayList<Register>();
for (Register reg : registers) {
if (reg.isVectorRegister()) {
sortedVectorRegisters.add(reg);
list.add(reg);
}
}
Collections.sort(list, RegisterManager::compareVectorRegisters);
sortedVectorRegisters = Collections.unmodifiableList(list);
}
return sortedVectorRegisters.toArray(new Register[0]);
return sortedVectorRegisters;
}
/**
@@ -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,36 +15,33 @@
*/
package ghidra.program.model.lang;
import ghidra.program.model.address.Address;
import java.util.*;
import ghidra.program.model.address.Address;
public class RegisterTranslator {
private static Comparator<Register> registerSizeComparator = new Comparator<Register>() {
@Override
public int compare(Register r1, Register r2) {
// Used for sorting largest to smallest
return r2.getBitLength() - r1.getBitLength();
}
};
private Register[] oldRegs;
private Register[] newRegs;
private Language oldLang;
private Language newLang;
private HashMap<Integer, List<Register>> oldRegisterMap;
private HashMap<Integer, List<Register>> newRegisterMap;
private HashMap<String, Register> oldRegisterNameMap;
private HashMap<String, Register> newRegisterNameMap;
public RegisterTranslator(Language oldLang, Language newLang) {
oldRegs = oldLang.getRegisters();
newRegs = newLang.getRegisters();
this.oldRegisterMap = buildOffsetMap(oldRegs);
this.newRegisterMap = buildOffsetMap(newRegs);
oldRegisterNameMap = buildNameMap(oldRegs);
newRegisterNameMap = buildNameMap(newRegs);
this.oldLang = oldLang;
this.newLang = newLang;
this.oldRegisterMap = buildOffsetMap(oldLang.getRegisters());
this.newRegisterMap = buildOffsetMap(newLang.getRegisters());
}
private HashMap<Integer, List<Register>> buildOffsetMap(Register[] registers) {
private HashMap<Integer, List<Register>> buildOffsetMap(List<Register> registers) {
HashMap<Integer, List<Register>> offsetMap = new HashMap<Integer, List<Register>>();
for (Register register : registers) {
Address addr = register.getAddress();
@@ -69,14 +65,6 @@ public class RegisterTranslator {
return offsetMap;
}
private HashMap<String, Register> buildNameMap(Register[] regs) {
HashMap<String, Register> map = new HashMap<String, Register>();
for (Register r : regs) {
map.put(r.getName().toUpperCase(), r);
}
return map;
}
public Register getOldRegister(int offset, int size) {
List<Register> list = oldRegisterMap.get(offset);
if (list != null) {
@@ -110,15 +98,15 @@ public class RegisterTranslator {
}
public Register getNewRegister(Register oldReg) {
return newRegisterNameMap.get(oldReg.getName().toUpperCase());
return newLang.getRegister(oldReg.getName());
}
public Register getOldRegister(Register newReg) {
return oldRegisterNameMap.get(newReg.getName().toUpperCase());
return oldLang.getRegister(newReg.getName());
}
public Register[] getNewRegisters() {
return newRegs;
public List<Register> getNewRegisters() {
return newLang.getRegisters();
}
}
@@ -340,7 +340,7 @@ public class InstructionStub implements Instruction {
}
@Override
public Register[] getRegisters() {
public List<Register> getRegisters() {
throw new UnsupportedOperationException();
}
@@ -15,12 +15,13 @@
*/
package ghidra.program.model.listing;
import java.math.BigInteger;
import java.util.List;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import java.math.BigInteger;
/**
* Interface to define a processor register context over the address space.
*/
@@ -34,14 +35,14 @@ public interface ProgramContext {
/**
* Modify register value to eliminate non-flowing bits
* @param value
* @param value register value to be modified
* @return value suitable for flowing
*/
public RegisterValue getFlowValue(RegisterValue value);
/**
* Modify register value to only include non-flowing bits
* @param value
* @param value register value to be modified
* @return new value or null
*/
public RegisterValue getNonFlowValue(RegisterValue value);
@@ -57,9 +58,9 @@ public interface ProgramContext {
/**
* Get all the register descriptions defined for this program context.
*
* @return array of defined register descriptions
* @return unmodifiable list of defined register descriptions
*/
public Register[] getRegisters();
public List<Register> getRegisters();
/**
* Returns an array of all registers that at least one value associated with an address.
@@ -92,6 +93,8 @@ public interface ProgramContext {
* @param start the start address to set values
* @param end the end address to set values
* @param value the actual values to store at address
* @throws ContextChangeException if failed to modifiy context across specified range
* (e.g., instruction exists).
*/
public void setRegisterValue(Address start, Address end, RegisterValue value)
throws ContextChangeException;
@@ -112,6 +115,8 @@ public interface ProgramContext {
* @param start the start address.
* @param end the end address (inclusive).
* @param value the value to assign. A value of null will effective clear any existing values.
* @throws ContextChangeException if failed to modifiy context across specified range
* (e.g., instruction exists).
*/
public void setValue(Register register, Address start, Address end, BigInteger value)
throws ContextChangeException;
@@ -130,6 +135,8 @@ public interface ProgramContext {
* given range for the given register. Each range returned will have the same value
* associated with the register for all addresses in that range.
* @param register the register for which to get set value ranges.
* @param start start of address range to search
* @param end end of address range to search
* @return An AddressRangeIterator over all address within the given range that have values
* for the given register.
*/
@@ -139,8 +146,8 @@ public interface ProgramContext {
/**
* Returns the bounding address-range containing addr and the the same RegisterValue throughout.
* The range returned may be limited by other value changes associated with register's base-register.
* @param register
* @param addr
* @param register program register
* @param addr program address
* @return single register-value address-range containing addr
*/
public AddressRange getRegisterValueRangeContaining(Register register, Address addr);
@@ -159,6 +166,8 @@ public interface ProgramContext {
* given range for the given register. Each range returned will have the same default value
* associated with the register for all addresses in that range.
* @param register the register for which to get default value ranges.
* @param start start of address range to search
* @param end end of address range to search
* @return An AddressRangeIterator over all address within the given range that have default values
* for the given register.
*/
@@ -169,20 +178,26 @@ public interface ProgramContext {
* Gets the registers for this context that are used for processor context states.
* @return all processor context registers
*/
public Register[] getProcessorStateRegisters();
public List<Register> getContextRegisters();
/**
* Remove (unset) the register values for a given address range.
* @param start starting address.
* @param end ending adddress.
* @param register handle to the register to be set.
* @throws ContextChangeException thrown if context change not permitted over specified
* range (e.g., instructions exist)
*/
public void remove(Address start, Address end, Register register) throws ContextChangeException;
/**
* Returns the list of register names
* Get an alphabetical sorted unmodifiable list of original register names
* (including context registers). Names correspond to orignal register
* name and not aliases which may be defined.
*
* @return alphabetical sorted unmodifiable list of original register names.
*/
public String[] getRegisterNames();
public List<String> getRegisterNames();
/**
* Returns true if the given register has the value over the addressSet
@@ -224,7 +239,7 @@ public interface ProgramContext {
* from the default disassembly context and the context register value stored
* at the specified address. Those bits specified by the stored context value
* take precedence.
* @param address
* @param address program address
* @return disassembly context register value
*/
public RegisterValue getDisassemblyContext(Address address);
@@ -20,6 +20,8 @@
*/
package ghidra.program.model.pcode;
import java.util.List;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
@@ -50,8 +52,9 @@ public class VarnodeTranslator {
* @return Register or null if node is not a register
*/
public Register getRegister(Varnode node) {
if (node == null)
if (node == null) {
return null;
}
return language.getRegister(node.getAddress(), node.getSize());
}
@@ -72,9 +75,9 @@ public class VarnodeTranslator {
* Get all defined registers for the program this translator was created
* with.
*
* @return all defined registers
* @return all defined registers as unmodifiable list
*/
public Register[] getRegisters() {
public List<Register> getRegisters() {
return language.getRegisters();
}
}
@@ -219,11 +219,10 @@ public class SymbolUtilities {
/**
* Validate the given symbol name: cannot be null, cannot be an empty string, cannot contain blank
* characters, cannot be a reserved name.
* NOTE: This is not infallible since default data labels can start with any data-type name
* @param name symbol name to be validated
* @throws InvalidInputException invalid or reserved name has been specified
*/
public static void validateName(String name, Address address, SymbolType symbolType,
AddressFactory addrFactory) throws InvalidInputException {
public static void validateName(String name) throws InvalidInputException {
if (name == null) {
throw new InvalidInputException("Symbol name can't be null");
@@ -243,6 +242,7 @@ public class SymbolUtilities {
/**
* Returns true if the given name starts with a possible default symbol prefix.
* @param name the name string to test.
* @return true if name starts with a know dynamic prefix
*/
public static boolean startsWithDefaultDynamicPrefix(String name) {
for (String element : DYNAMIC_PREFIX_ARRAY) {
@@ -279,9 +279,11 @@ public class SymbolUtilities {
/**
* Tests if the given name is a possible dynamic symbol name.
* WARNING! This method should be used carefully since it will return true for
* any name which ends with an '_' followed by a valid hex value
* any name which starts with a known dynamic label prefix or ends with an '_'
* followed by a valid hex value.
* @param name the name to test
* @param caseSensitive true if case matters.
* @return true if name is a possible dynamic symbol name, else false
*/
public static boolean isDynamicSymbolPattern(String name, boolean caseSensitive) {
@@ -330,6 +332,7 @@ public class SymbolUtilities {
* Returns true if the specified char
* is not valid for use in a symbol name
* @param c the character to be tested as a valid symbol character.
* @return return true if c is an invalid char within a symbol name, else false
*/
public static boolean isInvalidChar(char c) {
if (c < ' ') { // non-printable ASCII
@@ -354,6 +357,7 @@ public class SymbolUtilities {
* @param str the string to have invalid chars converted to underscores or removed.
* @param replaceWithUnderscore - true means replace the invalid
* chars with underscore. if false, then just drop the invalid chars
* @return modified string
*/
public static String replaceInvalidChars(String str, boolean replaceWithUnderscore) {
if (str == null) {
@@ -376,8 +380,9 @@ public class SymbolUtilities {
}
/**
* Create a name for an offcut reference.
* Create a dynamic label name for an offcut reference.
* @param addr the address at which to create an offcut reference name.
* @return dynamic offcut label name
*/
public static String getDynamicOffcutName(Address addr) {
if (addr != null) {
@@ -387,9 +392,13 @@ public class SymbolUtilities {
}
/**
* Create a name for a dynamic symbol
* Create a name for a dynamic symbol with a 3-letter prefix based upon reference level
* and an address. Acceptable referenceLevel's are:
* {@link #UNK_LEVEL}, {@link #DAT_LEVEL}, {@link #LAB_LEVEL}, {@link #SUB_LEVEL},
* {@link #EXT_LEVEL}, {@link #FUN_LEVEL}.
* @param referenceLevel the type of reference for which to create a dynamic name.
* @param addr the address at which to create a dynamic name.
* @return dynamic symbol name
*/
public static String getDynamicName(int referenceLevel, Address addr) {
if (addr != null) {
@@ -558,9 +567,18 @@ public class SymbolUtilities {
/**
* Parse a dynamic name and return its address or null if unable to parse.
* @param factory address factory
* @param name the dynamic label name to parse into an address.
* @return address corresponding to symbol name if it satisfies possible dynamic naming
* or null if unable to parse address fro name
*/
public static Address parseDynamicName(AddressFactory factory, String name) {
// assume dynamic names will naver start with an underscore
if (name.startsWith(UNDERSCORE)) {
return null;
}
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;
@@ -913,6 +931,7 @@ public class SymbolUtilities {
* @param program the program to search.
* @param symbolName the name of the global label or function symbol to search.
* @param errorConsumer the object to use for reporting errors via it's accept() method.
* @return symbol if a unique label/function symbol with name is found or null
*/
public static Symbol getExpectedLabelOrFunctionSymbol(Program program, String symbolName,
Consumer<String> errorConsumer) {
@@ -938,6 +957,7 @@ public class SymbolUtilities {
* @param program the program to search.
* @param symbolName the name of the global label or function symbol to search.
* @param errorConsumer the object to use for reporting errors via it's accept() method.
* @return symbol if a unique label/function symbol with name is found or null
*/
public static Symbol getLabelOrFunctionSymbol(Program program, String symbolName,
Consumer<String> errorConsumer) {
@@ -15,19 +15,19 @@
*/
package ghidra.program.util;
import java.util.*;
import java.util.Arrays;
import java.util.List;
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 Register[] registers;
protected Language language;
protected Register baseContextRegister;
private Map<String, Register> registerNameMap; // lazy initialized only when getRegister(name) called
private boolean hasNonFlowingContext = false;
private byte[] nonFlowingContextRegisterMask;
@@ -35,17 +35,16 @@ abstract public class AbstractProgramContext implements ProgramContext, DefaultP
protected RegisterValue defaultDisassemblyContext;
protected AbstractProgramContext(Register[] registers) {
this.registers = registers;
protected AbstractProgramContext(Language language) {
init(language);
}
init();
if (baseContextRegister != null) {
nonFlowingContextRegisterMask = baseContextRegister.getBaseMask().clone();
Arrays.fill(nonFlowingContextRegisterMask, (byte) 0);
flowingContextRegisterMask = nonFlowingContextRegisterMask.clone();
initContextBitMasks(baseContextRegister);
}
/**
* Get underlying language associated with this context and its registers
* @return language
*/
public Language getLanguage() {
return language;
}
/**
@@ -85,7 +84,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
@@ -98,8 +97,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) {
@@ -109,67 +109,43 @@ 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
}
}
/**
* 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);
}
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);
}
}
return registerNameMap;
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()]);
public final List<Register> getContextRegisters() {
return language.getContextRegisters();
}
@Override
public final Register getRegister(String name) {
return getRegisterNameMap().get(name);
return language.getRegister(name);
}
@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()]);
public final List<String> getRegisterNames() {
return language.getRegisterNames();
}
@Override
public final Register[] getRegisters() {
return registers;
public final List<Register> getRegisters() {
return language.getRegisters();
}
@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<>();
}
@@ -206,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);

Some files were not shown because too many files have changed in this diff Show More