Merge remote-tracking branch 'origin/GP-4742_emteere_PSPECImprovements--SQUASHED'

This commit is contained in:
ghidra1 2024-07-29 18:05:41 -04:00
commit 47b08753e5
8 changed files with 319 additions and 81 deletions

View File

@ -32,8 +32,7 @@ import ghidra.program.database.ProgramDB;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.InvalidAddressException;
import ghidra.program.model.mem.MemoryConflictException;
import ghidra.program.model.symbol.*;
@ -487,7 +486,7 @@ public abstract class AbstractProgramLoader implements Loader {
for (Register reg : lang.getRegisters()) {
Address addr = reg.getAddress();
if (addr.isMemoryAddress()) {
createSymbol(program, reg.getName(), addr, false, true, true);
createSymbol(program, reg.getName(), addr, null, false, true, true);
}
}
// optionally create default symbols defined by pspec
@ -495,7 +494,7 @@ public abstract class AbstractProgramLoader implements Loader {
boolean anchorSymbols = shouldAnchorSymbols(options);
List<AddressLabelInfo> labels = lang.getDefaultSymbols();
for (AddressLabelInfo info : labels) {
createSymbol(program, info.getLabel(), info.getAddress(), info.isEntry(),
createSymbol(program, info.getLabel(), info.getAddress(), info.getDescription(), info.isEntry(),
info.isPrimary(), anchorSymbols);
}
}
@ -507,13 +506,16 @@ public abstract class AbstractProgramLoader implements Loader {
}
private static void createSymbol(Program program, String labelname, Address address,
boolean isEntry, boolean isPrimary, boolean anchorSymbols) {
String comment, boolean isEntry, boolean isPrimary, boolean anchorSymbols) {
SymbolTable symTable = program.getSymbolTable();
Address addr = address;
Symbol s = symTable.getPrimarySymbol(addr);
try {
Namespace namespace = program.getGlobalNamespace();
s = symTable.createLabel(addr, labelname, namespace, SourceType.IMPORTED);
if (comment != null) {
program.getListing().setComment(address, CodeUnit.EOL_COMMENT, comment);
}
if (isEntry) {
symTable.addExternalEntryPoint(addr);
}

View File

@ -145,25 +145,7 @@ public class SymbolicPropogator {
this.evaluator = eval;
AddressSpace defaultDataSpace = program.getLanguage().getDefaultDataSpace();
AddressSpace defaultSpace = program.getLanguage().getDefaultSpace();
defaultSpacesAreTheSame = defaultSpace.equals(defaultDataSpace);
AddressSpace defaultAddrSpace = program.getAddressFactory().getDefaultAddressSpace();
// Only make reference if other reference or symbol exists
memorySpaces = new ArrayList<>();
for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) {
if (!space.isLoadedMemorySpace()) {
continue;
}
if (space == defaultAddrSpace) {
memorySpaces.add(0, space); // default space is always at index 0
}
else {
memorySpaces.add(space);
}
}
initValidAddressSpaces();
// if assuming, make a copy of programContext
savedProgramContext = programContext;
@ -206,6 +188,44 @@ public class SymbolicPropogator {
return bodyDone;
}
/**
* Initialize address spaces to be used for a potential reference with an unknown space.
*/
private void initValidAddressSpaces() {
AddressSpace defaultDataSpace = program.getLanguage().getDefaultDataSpace();
AddressSpace defaultSpace = program.getLanguage().getDefaultSpace();
defaultSpacesAreTheSame = defaultSpace.equals(defaultDataSpace);
AddressSpace defaultAddrSpace = program.getAddressFactory().getDefaultAddressSpace();
// Only make reference if other reference or symbol exists
memorySpaces = new ArrayList<>();
for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) {
if (!space.isLoadedMemorySpace()) {
continue;
}
// only default or defaultData based overlay spaces added
if (space.isOverlaySpace()) {
OverlayAddressSpace ovSpace = (OverlayAddressSpace) space;
AddressSpace baseSpace = ovSpace.getPhysicalSpace();
if (!( baseSpace.equals(defaultDataSpace) || baseSpace.equals(defaultSpace) ) ) {
continue;
}
}
else if (!( space.equals(defaultDataSpace) || space.equals(defaultSpace) ) ) {
continue;
}
if (space.equals(defaultAddrSpace)) {
memorySpaces.add(0, space); // default space is always at index 0
}
else {
memorySpaces.add(space);
}
}
}
/**
* Save off the current context and set the current context to a copy
* This is done so that the values in the context are not changed, but can be used for computation.
@ -2307,7 +2327,8 @@ public class SymbolicPropogator {
AddressSpace instrSpace = instruction.getMinAddress().getAddressSpace();
// Find likely preferred target space
// 1. only non-overlay space is default space, or
// 1. only non-overlay spaces are defaultSpace of defaultDataSpace,
// or overlay spaces with base space of defaultSpace or defaultDataSpace
// 2. presence of destination symbol/reference at only one of many possible targets
// if this instruction is in an overlay space overlaying the default space, change the default space

View File

@ -24,16 +24,19 @@ import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.analysis.ConstantPropagationAnalyzer;
import ghidra.app.plugin.core.analysis.ConstantPropagationContextEvaluator;
import ghidra.framework.store.LockException;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryConflictException;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.util.SymbolicPropogator.Value;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor;
@ -307,6 +310,167 @@ public class ConstantPropogationReferenceTest extends AbstractGenericTest {
assertOperandReferenceTo(1, instr, addr("0x00040100"));
}
@Test
public void testOverlayReferences_AARCH64() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64);
// Copy and use PasteCopiedListingsBytesScript
// 00400000 fd 7b bf a9 stp x29,x30,[sp, #local_10]!
// 00400004 fd 03 00 91 mov x29,sp
// 00400008 60 00 00 d0 adrp x0,0x40e000
// 0040000c 01 00 24 91 add x1,x0,#0x900
// 00400010 60 00 00 d0 adrp x0,0x40e000
// 00400014 00 40 24 91 add x0=>data:DWORD_0040e910,x0,#0x910
// 00400018 e2 03 01 aa mov x2=>data:DWORD_0040e900,x1
// 0040001c e1 15 80 52 mov w1,#0xaf
// 00400020 05 00 00 94 bl FUN_00400034
// 00400024 21 00 80 d2 mov x1,#0x1
// 00400028 40 00 80 d2 mov x0,#0x2
// 0040002c 02 00 00 94 bl FUN_00400034
// 00400030 c0 03 5f d6 ret
//
// 00400034 c0 03 5f d6 ret
// 00400038 00 00 00 00 ddw 0h
// 0040003c 00 00 00 00 ddw 0h
//
// 0040e900 53 74 72 69 ddw 53747269h
// 0040e904 6e 67 50 61 ddw 6E675061h
// 0040e908 72 61 6d 31 ddw 72616D31h
// 0040e90c 00 00 00 00 ddw 0h
//
// 0040e910 53 74 72 69 ddw 53747269h
// 0040e914 6e 67 50 61 ddw 6E675061h
// 0040e918 72 61 6d 32 ddw 72616D32h
// 0040e91c 00 00 00 00 ddw 0h
String ovBlockName = "textov";
MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x10000);
builder.setBytes(textBlock.getStart().toString(),
"fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6");
builder.setBytes(ovBlockName+":"+"0x0040e900",
"53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00");
builder.disassemble(textBlock.getStart().toString(), 16*4);
analyzer = new ConstantPropagationAnalyzer();
program = builder.getProgram();
program.startTransaction("Test");
Address codeStart = addr(ovBlockName+":"+"0x00400000");
Listing listing = program.getListing();
assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart));
AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4));
analyze(addressSet);
Instruction instr;
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910"));
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900"));
}
@Test
public void testOverlayReferencesToBase_AARCH64() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64);
String ovBlockName = "textov";
// Same as above test
MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000);
builder.setBytes(textBlock.getStart().toString(),
"fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6");
builder.setBytes("0x0040e900",
"53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00");
builder.disassemble(textBlock.getStart().toString(), 16*4);
analyzer = new ConstantPropagationAnalyzer();
program = builder.getProgram();
program.startTransaction("Test");
Address codeStart = addr(ovBlockName+":"+"0x00400000");
Listing listing = program.getListing();
assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart));
AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4));
analyze(addressSet);
Instruction instr;
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr("0x0040e910"));
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr("0x0040e900"));
}
@Test
public void testOverlayReferencesToSplit_AARCH64() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._AARCH64);
String ovBlockName = "textov";
// Same as above test
MemoryBlock textBlock = builder.createOverlayMemory(ovBlockName,"0x400000",0x1000);
builder.setBytes(textBlock.getStart().toString(),
"fd 7b bf a9 fd 03 00 91 60 00 00 d0 01 00 24 91 60 00 00 d0 00 40 24 91 e2 03 01 aa e1 15 80 52 05 00 00 94 21 00 80 d2 40 00 80 d2 02 00 00 94 c0 03 5f d6 c0 03 5f d6");
builder.withTransaction(() -> {
try {
MemoryBlock dataBlock = builder.getProgram().getMemory().createInitializedBlock(ovBlockName, textBlock.getStart().getAddressSpace().getAddressInThisSpaceOnly(0x0040e900), 0x100L, (byte) 0, TaskMonitor.DUMMY,
false);
builder.setBytes(dataBlock.getStart().toString(),
"53 74 72 69 6e 67 50 61 72 61 6d 31 00 00 00 00 53 74 72 69 6e 67 50 61 72 61 6d 32 00 00 00 00");
}
catch (Exception e) {
e.printStackTrace();
}
});
builder.disassemble(textBlock.getStart().toString(), 16*4);
analyzer = new ConstantPropagationAnalyzer();
program = builder.getProgram();
program.startTransaction("Test");
Address codeStart = addr(ovBlockName+":"+"0x00400000");
Listing listing = program.getListing();
assertNotNull("Bad instruction disassembly", listing.getInstructionAt(codeStart));
AddressSet addressSet = new AddressSet(codeStart, codeStart.add(16*4));
analyze(addressSet);
Instruction instr;
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(20));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e910"));
instr = listing.getInstructionAt(addr(ovBlockName+":"+"0x00400000").add(24));
assertNoOperandReference(1, instr);
assertOperandReferenceTo(0, instr, addr(ovBlockName+":"+"0x0040e900"));
}
@Test
public void testPIC_Call_X86_64() throws Exception {

View File

@ -384,27 +384,29 @@ void ArchitectureGhidra::buildSymbols(DocumentStorage &store)
{
const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName());
if (symtag == (const Element *)0) return;
XmlDecode decoder(this,symtag);
if (symtag == (const Element*) 0)
return;
XmlDecode decoder(this, symtag);
uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS);
while(decoder.peekElement() != 0) {
Address lastAddr(Address::m_minimal);
int4 lastSize = -1;
while (decoder.peekElement() != 0) {
uint4 subel = decoder.openElement(ELEM_SYMBOL);
string addrString;
string name;
int4 size = 0;
int4 volatileState = -1;
for(;;) {
for (;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == 0)
break;
if (attribId == ATTRIB_NAME)
name = decoder.readString();
else if (attribId == ATTRIB_ADDRESS) {
addrString = decoder.readString();
}
else if (attribId == ATTRIB_VOLATILE) {
} else if (attribId == ATTRIB_VOLATILE) {
volatileState = decoder.readBool() ? 1 : 0;
}
else if (attribId == ATTRIB_SIZE)
} else if (attribId == ATTRIB_SIZE)
size = decoder.readSignedInteger();
}
decoder.closeElement(subel);
@ -417,14 +419,21 @@ void ArchitectureGhidra::buildSymbols(DocumentStorage &store)
// feed the global symbol to the decompiler on a per function basic.
if (volatileState < 0)
continue;
Address addr = parseAddressSimple(addrString);
Address addr;
if (addrString == "next" && lastSize != -1) {
addr = lastAddr + lastSize;
} else {
addr = parseAddressSimple(addrString);
}
if (size == 0)
size = addr.getSpace()->getWordSize();
Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1));
Range range(addr.getSpace(), addr.getOffset(), addr.getOffset() + (size - 1));
if (volatileState == 0)
symboltab->clearPropertyRange(Varnode::volatil, range);
else
symboltab->setPropertyRange(Varnode::volatil, range);
lastAddr = addr;
lastSize = size;
}
decoder.closeElement(el);
}

View File

@ -267,27 +267,35 @@ void SleighArchitecture::buildSymbols(DocumentStorage &store)
{
const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName());
if (symtag == (const Element *)0) return;
XmlDecode decoder(this,symtag);
if (symtag == (const Element*) 0)
return;
XmlDecode decoder(this, symtag);
uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS);
while(decoder.peekElement() != 0) {
Address lastAddr(Address::m_minimal);
int4 lastSize = -1;
while (decoder.peekElement() != 0) {
uint4 subel = decoder.openElement(ELEM_SYMBOL);
Address addr;
string name;
string description;
int4 size = 0;
int4 volatileState = -1;
for(;;) {
for (;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == 0)
break;
if (attribId == ATTRIB_NAME)
name = decoder.readString();
else if (attribId == ATTRIB_ADDRESS) {
addr = parseAddressSimple(decoder.readString());
string addrStr = decoder.readString();
if (addrStr == "next" && lastSize != -1) {
addr = lastAddr + lastSize;
} else {
addr = parseAddressSimple(addrStr);
}
else if (attribId == ATTRIB_VOLATILE) {
} else if (attribId == ATTRIB_VOLATILE) {
volatileState = decoder.readBool() ? 1 : 0;
}
else if (attribId == ATTRIB_SIZE)
} else if (attribId == ATTRIB_SIZE)
size = decoder.readSignedInteger();
}
decoder.closeElement(subel);
@ -298,7 +306,7 @@ void SleighArchitecture::buildSymbols(DocumentStorage &store)
if (size == 0)
size = addr.getSpace()->getWordSize();
if (volatileState >= 0) {
Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1));
Range range(addr.getSpace(), addr.getOffset(), addr.getOffset() + (size - 1));
if (volatileState == 0)
symboltab->clearPropertyRange(Varnode::volatil, range);
else
@ -307,6 +315,8 @@ void SleighArchitecture::buildSymbols(DocumentStorage &store)
Datatype *ct = types->getBase(size, TYPE_UNKNOWN);
Address usepoint;
symboltab->getGlobalScope()->addSymbol(name, ct, addr, usepoint);
lastAddr = addr;
lastSize = size;
}
decoder.closeElement(el);
}

View File

@ -146,6 +146,9 @@
<ref name="symbol_type"/>
</attribute>
</optional>
<optional>
<attribute name="description"/>
</optional>
</element>
</oneOrMore>

View File

@ -756,14 +756,28 @@ public class SleighLanguage implements Language {
}
else if (elName.equals("default_symbols")) {
XmlElement subel = parser.start();
Address previousAddr = null;
int previousSize = 1;
while (parser.peek().getName().equals("symbol")) {
XmlElement symbol = parser.start();
String labelName = symbol.getAttribute("name");
String addressString = symbol.getAttribute("address");
String typeString = symbol.getAttribute("type");
String comment = symbol.getAttribute("description");
ProcessorSymbolType type = ProcessorSymbolType.getType(typeString);
boolean isEntry = SpecXmlUtils.decodeBoolean(symbol.getAttribute("entry"));
Address startAddress = addressFactory.getAddress(addressString);
Address startAddress = null;
if (addressString.equalsIgnoreCase("next")) {
if (previousAddr == null) {
Msg.error(this, "use of addr=\"next\" tag with no previous address for " +
labelName + " : " + description.getSpecFile());
} else {
startAddress = previousAddr.add(previousSize);
}
}
else {
startAddress = addressFactory.getAddress(addressString);
}
int rangeSize = SpecXmlUtils.decodeInt(symbol.getAttribute("size"));
Boolean isVolatile =
SpecXmlUtils.decodeNullableBoolean(symbol.getAttribute("volatile"));
@ -774,7 +788,7 @@ public class SleighLanguage implements Language {
else {
AddressLabelInfo info;
try {
info = new AddressLabelInfo(startAddress, rangeSize, labelName, false,
info = new AddressLabelInfo(startAddress, rangeSize, labelName, comment, false,
isEntry, type, isVolatile);
}
catch (AddressOverflowException e) {
@ -801,6 +815,8 @@ public class SleighLanguage implements Language {
}
// skip the end tag
parser.end(symbol);
previousAddr = startAddress;
previousSize = rangeSize;
}
parser.end(subel);
}

View File

@ -29,6 +29,7 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
private Address addr;
private Address endAddr;
private String label;
private String description;
private boolean isPrimary;
private boolean isEntry;
private ProcessorSymbolType processorSymbolType;
@ -41,12 +42,13 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
* @param addr Address object that describes the memory address
* @param sizeInBytes Integer describing the Size in bytes that the label applies to.
* @param label String label or alias for the Address
* @param description Label description
* @param isPrimary boolean describes if this object is the primary label for the Address 'addr'
* @param isEntry boolean describes if this object is an entry label for the Address 'addr'
* @param type ProcessorSymbolType the type of symbol
* @param isVolatile Boolean describes if the memory at this address is volatile
*/
public AddressLabelInfo(Address addr, Integer sizeInBytes, String label, boolean isPrimary,
public AddressLabelInfo(Address addr, Integer sizeInBytes, String label, String description, boolean isPrimary,
boolean isEntry, ProcessorSymbolType type, Boolean isVolatile) throws AddressOverflowException {
this.addr = addr;
if ( sizeInBytes == null || sizeInBytes <= 0 ) {
@ -57,6 +59,7 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
}
this.endAddr = this.addr.addNoWrap(this.sizeInBytes-1);
this.label = label;
this.description = description;
this.isPrimary = isPrimary;
this.isEntry = isEntry;
this.processorSymbolType = type;
@ -64,28 +67,35 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
}
/**
* Returns the object's address.
* @return object's address.
*/
public final Address getAddress() {
return addr;
}
/**
* Returns the object's end address.
* @return the object's end address.
*/
public final Address getEndAddress() {
return endAddr;
}
/**
* Returns the object's label or alias.
* @return the object's label or alias.
*/
public final String getLabel() {
return label;
}
/**
* Returns the object's size in bytes. Always non-zero positive value and defaults to
* @return the object's description if it has one, null otherwise
*/
public final String getDescription() {
return description;
}
/**
* @return the object's size in bytes. Always non-zero positive value and defaults to
* addressable unit size of associated address space.
*/
public final int getByteSize() {
@ -93,14 +103,14 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
}
/**
* Returns whether the object is the primary label at the address.
* @return whether the object is the primary label at the address.
*/
public final boolean isPrimary() {
return isPrimary;
}
/**
* Returns whether the object is volatile.
* @return whether the object is volatile.
* Boolean.False when the address is explicitly not volatile.
* Boolean.True when the address is volatile.
* NULL when the volatility is not defined at this address.
@ -164,6 +174,9 @@ public class AddressLabelInfo implements Comparable<AddressLabelInfo> {
buf.append("isEntry = " + isEntry);
buf.append(", ");
buf.append("type = " + processorSymbolType);
if (description != null) {
buf.append("description = " + description);
}
return buf.toString();
}
}