Merge remote-tracking branch 'origin/caheckman_EquateDeindirect'

This commit is contained in:
ghidra1 2020-07-01 14:04:12 -04:00
commit 0d2df489ce
43 changed files with 1050 additions and 396 deletions

View file

@ -51,22 +51,19 @@ public class HighFunction extends PcodeSyntaxTree {
private GlobalSymbolMap globalSymbols;
private List<JumpTable> jumpTables;
private List<DataTypeSymbol> protoOverrides;
private boolean showNamespace = true;
/**
* @param function function associated with the higher level function abstraction.
* @param language description of the processor language of the function
* @param compilerSpec description of the compiler that produced the function
* @param dtManager data type manager
* @param showNamespace true signals to print function names with their namespace
*/
public HighFunction(Function function, Language language, CompilerSpec compilerSpec,
PcodeDataTypeManager dtManager, boolean showNamespace) {
PcodeDataTypeManager dtManager) {
super(function.getProgram().getAddressFactory(), dtManager);
func = function;
this.language = language;
this.compilerSpec = compilerSpec;
this.showNamespace = showNamespace;
localSymbols = new LocalSymbolMap(this, "stack");
globalSymbols = new GlobalSymbolMap(this);
proto = new FunctionPrototype(localSymbols, function);
@ -260,9 +257,9 @@ public class HighFunction extends PcodeSyntaxTree {
public void readXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement start = parser.start("function");
String name = start.getAttribute("name");
if (!func.getName(showNamespace).equals(name)) {
if (!func.getName().equals(name)) {
throw new PcodeXMLException(
"Function name mismatch: " + func.getName(showNamespace) + " + " + name);
"Function name mismatch: " + func.getName() + " + " + name);
}
while (!parser.peek().isEnd()) {
XmlElement subel = parser.peek();
@ -436,11 +433,12 @@ public class HighFunction extends PcodeSyntaxTree {
* addresses near its entry point.
*
* @param id is the id associated with the function symbol
* @param namespace is the namespace containing the function symbol
* @param entryPoint pass null to use the function entryPoint, pass an address to force an entry point
* @param size describes how many bytes the function occupies as code
* @return the XML string
*/
public String buildFunctionXML(long id, Address entryPoint, int size) {
public String buildFunctionXML(long id, Namespace namespace, Address entryPoint, int size) {
// Functions aren't necessarily contiguous with the smallest address being the entry point
// So size needs to be smaller than size of the contiguous chunk containing the entry point
StringBuilder resBuf = new StringBuilder();
@ -448,7 +446,7 @@ public class HighFunction extends PcodeSyntaxTree {
if (id != 0) {
SpecXmlUtils.encodeUnsignedIntegerAttribute(resBuf, "id", id);
}
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getName(showNamespace));
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getName());
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", size);
if (func.isInline()) {
SpecXmlUtils.encodeBooleanAttribute(resBuf, "inline", true);
@ -463,12 +461,12 @@ public class HighFunction extends PcodeSyntaxTree {
else {
resBuf.append(Varnode.buildXMLAddress(entryPoint)); // Address is forced on XML
}
resBuf.append(localSymbols.buildLocalDbXML());
localSymbols.buildLocalDbXML(resBuf, namespace);
proto.buildPrototypeXML(resBuf, getDataTypeManager());
if ((jumpTables != null) && (jumpTables.size() > 0)) {
resBuf.append("<jumptablelist>\n");
for (int i = 0; i < jumpTables.size(); ++i) {
jumpTables.get(i).buildXml(resBuf);
for (JumpTable jumpTable : jumpTables) {
jumpTable.buildXml(resBuf);
}
resBuf.append("</jumptablelist>\n");
}
@ -478,8 +476,7 @@ public class HighFunction extends PcodeSyntaxTree {
}
if ((protoOverrides != null) && (protoOverrides.size() > 0)) {
PcodeDataTypeManager dtmanage = getDataTypeManager();
for (int i = 0; i < protoOverrides.size(); ++i) {
DataTypeSymbol sym = protoOverrides.get(i);
for (DataTypeSymbol sym : protoOverrides) {
Address addr = sym.getAddress();
FunctionPrototype fproto = new FunctionPrototype(
(FunctionSignature) sym.getDataType(), compilerSpec, false);
@ -618,22 +615,39 @@ public class HighFunction extends PcodeSyntaxTree {
}
}
static public void createNamespaceTag(StringBuilder buf, Namespace namespc) {
if (namespc == null) {
return;
}
ArrayList<String> arr = new ArrayList<String>();
Namespace curspc = namespc;
while (curspc != null) {
arr.add(0, curspc.getName());
curspc = curspc.getParentNamespace();
}
buf.append("<val/>\n"); // Force global scope to have empty name
for (int i = 1; i < arr.size(); ++i) {
buf.append("<val>");
SpecXmlUtils.xmlEscape(buf, arr.get(i));
buf.append("</val>\n");
/**
* Append an XML &lt;parent&gt; tag to the buffer describing the formal path elements
* from the root (global) namespace up to the given namespace
* @param buf is the buffer to write to
* @param namespace is the namespace being described
* @param includeId is true if the XML tag should include namespace ids
*/
static public void createNamespaceTag(StringBuilder buf, Namespace namespace,
boolean includeId) {
buf.append("<parent>\n");
if (namespace != null) {
ArrayList<Namespace> arr = new ArrayList<Namespace>();
Namespace curspc = namespace;
while (curspc != null) {
arr.add(0, curspc);
if (curspc instanceof Library) {
break; // Treat library namespace as root
}
curspc = curspc.getParentNamespace();
}
buf.append("<val/>\n"); // Force global scope to have empty name
for (int i = 1; i < arr.size(); ++i) {
Namespace curScope = arr.get(i);
buf.append("<val");
if (includeId) {
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", curScope.getID());
}
buf.append('>');
SpecXmlUtils.xmlEscape(buf, curScope.getName());
buf.append("</val>\n");
}
}
buf.append("</parent>\n");
}
/**

View file

@ -17,7 +17,9 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.symbol.Namespace;
import ghidra.util.exception.InvalidInputException;
/**
@ -54,11 +56,25 @@ public class HighFunctionSymbol extends HighSymbol {
return true;
}
@Override
public Namespace getNamespace() {
Function func = function.getFunction();
Namespace namespc = func.getParentNamespace();
while (func.isThunk() && namespc.getID() == Namespace.GLOBAL_NAMESPACE_ID) {
// Thunks can be in a different namespace than the thunked function.
// We choose the thunk's namespace unless it is the global namespace
func = func.getThunkedFunction(false);
namespc = func.getParentNamespace();
}
return namespc;
}
@Override
public void saveXML(StringBuilder buf) {
MappedEntry entry = (MappedEntry) getFirstWholeMap();
String funcString =
function.buildFunctionXML(getId(), entry.getStorage().getMinAddress(), entry.getSize());
function.buildFunctionXML(getId(), getNamespace(), entry.getStorage().getMinAddress(),
entry.getSize());
buf.append(funcString);
}
}

View file

@ -48,23 +48,20 @@ public class HighParamID extends PcodeSyntaxTree {
private Integer protoextrapop;
private List<ParamMeasure> inputlist = new ArrayList<ParamMeasure>();
private List<ParamMeasure> outputlist = new ArrayList<ParamMeasure>();
private boolean showNamespace = true;
/**
* @param function function associated with the higher level function abstraction.
* @param language language parser used to disassemble/get info on the language.
* @param compilerSpec the compiler spec.
* @param dtManager data type manager.
* @param showNamespace true to show the parameters namespace.
*/
public HighParamID(Function function, Language language, CompilerSpec compilerSpec,
PcodeDataTypeManager dtManager, boolean showNamespace) {
PcodeDataTypeManager dtManager) {
super(function.getProgram().getAddressFactory(), dtManager);
func = function;
modelname = null;
protoextrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
this.showNamespace = showNamespace;
}
/**
@ -137,8 +134,8 @@ public class HighParamID extends PcodeSyntaxTree {
public void readXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement start = parser.start("parammeasures");
functionname = start.getAttribute("name");
if (!func.getName(showNamespace).equals(functionname)) {
throw new PcodeXMLException("Function name mismatch: " + func.getName(showNamespace) +
if (!func.getName().equals(functionname)) {
throw new PcodeXMLException("Function name mismatch: " + func.getName() +
" + " + functionname);
}
while (!parser.peek().isEnd()) {
@ -157,10 +154,12 @@ public class HighParamID extends PcodeSyntaxTree {
subel = parser.start("proto");
modelname = subel.getAttribute("model");
String val = subel.getAttribute("extrapop");
if (val.equals("unknown"))
if (val.equals("unknown")) {
protoextrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
else
}
else {
protoextrapop = SpecXmlUtils.decodeInt(val);
}
parser.end(subel);
}
else if (subel.getName().equals("input")) {
@ -243,23 +242,28 @@ public class HighParamID extends PcodeSyntaxTree {
try {
//TODO: Currently, only storing one output, so looking for the best to report. When possible, change this to report all
int best_index = 0;
if (getNumOutputs() > 1)
for (int i = 1; i < getNumOutputs(); i++)
if (getNumOutputs() > 1) {
for (int i = 1; i < getNumOutputs(); i++) {
if (getOutput(i).getRank() < getOutput(best_index).getRank()) {//TODO: create mirror of ranks on high side (instead of using numbers?)
best_index = i;
}
}
}
if (getNumOutputs() != 0) {
ParamMeasure pm = getOutput(best_index);
pm.getRank(); //TODO (maybe): this value is not used or stored on the java side at this point
Varnode vn = pm.getVarnode();
DataType dataType;
if (storeDataTypes)
if (storeDataTypes) {
dataType = pm.getDataType();
else
}
else {
dataType = dtManage.findUndefined(vn.getSize());
}
//Msg.debug(this, "func: " + func.getName() + " -- type: " + dataType.getName());
if (!(dataType == null || dataType instanceof VoidDataType))
if (!(dataType == null || dataType instanceof VoidDataType)) {
func.setReturn(dataType, buildStorage(vn), SourceType.ANALYSIS);
}
}
}
catch (InvalidInputException e) {
@ -282,10 +286,12 @@ public class HighParamID extends PcodeSyntaxTree {
DataType dataType;
//Msg.debug(this, "function(" + func.getName() + ")--param size: " + vn.getSize() +
// "--type before store: " + pm.getDataType().getName());
if (storeDataTypes)
if (storeDataTypes) {
dataType = pm.getDataType();
else
}
else {
dataType = dtManage.findUndefined(vn.getSize());
}
Variable v =
new ParameterImpl(null, dataType, buildStorage(vn),
func.getProgram());

View file

@ -19,6 +19,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
@ -130,6 +131,18 @@ public class HighSymbol {
return null;
}
/**
* Fetch the namespace owning this symbol, if it exists.
* @return the Namespace object or null
*/
public Namespace getNamespace() {
Symbol sym = getSymbol();
if (sym != null) {
return sym.getParentNamespace();
}
return null;
}
/**
* Associate a particular HighVariable with this symbol. This is used to link the symbol
* into the decompiler's description of how a function manipulates a particular symbol.

View file

@ -17,8 +17,7 @@ package ghidra.program.model.pcode;
import java.util.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressIterator;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.listing.*;
@ -184,16 +183,18 @@ public class LocalSymbolMap {
if (symbol != null) {
id = symbol.getID();
}
Address defAddr = null;
if (!storage.isStackStorage()) {
defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset());
}
HighSymbol sym;
if (storage.isHashStorage()) {
Address defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset());
sym =
newDynamicSymbol(id, name, dt, storage.getFirstVarnode().getOffset(), defAddr);
}
else {
Address defAddr = null;
int addrType = storage.getFirstVarnode().getAddress().getAddressSpace().getType();
if (addrType != AddressSpace.TYPE_STACK && addrType != AddressSpace.TYPE_RAM) {
defAddr = dbFunction.getEntryPoint().addWrap(local.getFirstUseOffset());
}
sym = newMappedSymbol(id, name, dt, storage, defAddr, -1);
}
sym.setTypeLock(istypelock);
@ -325,31 +326,29 @@ public class LocalSymbolMap {
}
/**
* @return an XML document string representing this local variable map.
* Output an XML document representing this local variable map.
* @param resBuf is the buffer to write to
* @param namespace if the namespace of the function
*/
public String buildLocalDbXML() { // Get memory mapped local variables
StringBuilder res = new StringBuilder();
res.append("<localdb");
SpecXmlUtils.encodeBooleanAttribute(res, "lock", false);
SpecXmlUtils.encodeStringAttribute(res, "main", spacename);
res.append(">\n");
res.append("<scope");
SpecXmlUtils.xmlEscapeAttribute(res, "name", func.getFunction().getName());
res.append(">\n");
res.append("<parent>\n");
HighFunction.createNamespaceTag(res, func.getFunction().getParentNamespace());
res.append("</parent>\n");
res.append("<rangelist/>\n"); // Empty address range
res.append("<symbollist>\n");
public void buildLocalDbXML(StringBuilder resBuf, Namespace namespace) { // Get memory mapped local variables
resBuf.append("<localdb");
SpecXmlUtils.encodeBooleanAttribute(resBuf, "lock", false);
SpecXmlUtils.encodeStringAttribute(resBuf, "main", spacename);
resBuf.append(">\n");
resBuf.append("<scope");
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", func.getFunction().getName());
resBuf.append(">\n");
HighFunction.createNamespaceTag(resBuf, namespace, false);
resBuf.append("<rangelist/>\n"); // Empty address range
resBuf.append("<symbollist>\n");
Iterator<HighSymbol> iter = symbolMap.values().iterator();
while (iter.hasNext()) {
HighSymbol sym = iter.next();
HighSymbol.buildMapSymXML(res, sym);
HighSymbol.buildMapSymXML(resBuf, sym);
}
res.append("</symbollist>\n");
res.append("</scope>\n");
res.append("</localdb>\n");
return res.toString();
resBuf.append("</symbollist>\n");
resBuf.append("</scope>\n");
resBuf.append("</localdb>\n");
}
/**