mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Refactor of HighSymbol to use SymbolEntry
This commit is contained in:
parent
7fa8245f90
commit
97b43b9470
22 changed files with 1422 additions and 679 deletions
|
@ -0,0 +1,127 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* A HighSymbol mapping based on local hashing of the symbol's Varnode within a
|
||||
* function's syntax tree. The storage address of a temporary Varnode (a Varnode in
|
||||
* the "unique" address space) is too ephemeral to use as a permanent way to identify it.
|
||||
* This symbol stores a hash (generated by DynamicHash) that is better suited to
|
||||
* identifying the Varnode.
|
||||
*/
|
||||
public class DynamicEntry extends SymbolEntry {
|
||||
private long hash; // Hash encoding the specific Varnode
|
||||
|
||||
/**
|
||||
* Constructor for use with restoreXML
|
||||
* @param sym is the owning HighSymbol
|
||||
*/
|
||||
public DynamicEntry(HighSymbol sym) {
|
||||
super(sym);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct given the underlying symbol, defining Address of the Varnode, and the hash value
|
||||
* @param sym is the given symbol
|
||||
* @param addr is the defining Address
|
||||
* @param h is the hash value
|
||||
*/
|
||||
public DynamicEntry(HighSymbol sym, Address addr, long h) {
|
||||
super(sym);
|
||||
pcaddr = addr;
|
||||
hash = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hash value
|
||||
*/
|
||||
public long getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement addrel = parser.start("hash");
|
||||
hash = SpecXmlUtils.decodeLong(addrel.getAttribute("val"));
|
||||
parser.end(addrel);
|
||||
parseRangeList(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXml(StringBuilder buf) {
|
||||
buf.append("<hash val=\"0x").append(Long.toHexString(hash)).append("\"/>");
|
||||
buildRangelistXML(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getStorage() {
|
||||
Program program = symbol.getProgram();
|
||||
try {
|
||||
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(getHash()),
|
||||
getSize());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the dynamic storage object for a new DynamicEntry, given the underlying temporary
|
||||
* Varnode and its function model. The hash is created from local information in the
|
||||
* syntax tree near the Varnode.
|
||||
* @param vn is the underlying Varnode
|
||||
* @param high is the function model
|
||||
* @return the dynamic storage object
|
||||
*/
|
||||
public static VariableStorage buildDynamicStorage(Varnode vn, HighFunction high) {
|
||||
DynamicHash dynamicHash = new DynamicHash(vn, high);
|
||||
Program program = high.getFunction().getProgram();
|
||||
long ourHash = dynamicHash.getHash();
|
||||
try {
|
||||
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(ourHash),
|
||||
vn.getSize());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return symbol.type.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVolatile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* Decompiler symbol whose references are encoded as dynamic hashes into the PcodeSyntaxTree
|
||||
*
|
||||
*/
|
||||
public class DynamicSymbol extends HighSymbol {
|
||||
protected long hash; // Hash encoding the specific Varnode
|
||||
|
||||
public DynamicSymbol(HighFunction func) { // For use with restoreXML
|
||||
super(func);
|
||||
}
|
||||
|
||||
public DynamicSymbol(long uniqueId, String nm, DataType tp, int size, HighFunction func,
|
||||
Address addr, long hash) {
|
||||
super(uniqueId, nm, tp, size, addr, func);
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public long getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
protected void buildHashXML(StringBuilder buf) {
|
||||
buf.append("<hash val=\"0x").append(Long.toHexString(hash)).append("\"/>");
|
||||
buildRangelistXML(buf, pcaddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXML() {
|
||||
String sym = buildSymbolXML(function.getDataTypeManager(), name, type, size,
|
||||
isTypeLocked(), isNameLocked(), isReadOnly(), false, 0);
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<mapsym type=\"dynamic\">\n");
|
||||
res.append(sym);
|
||||
buildHashXML(res);
|
||||
res.append("</mapsym>\n");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("symbol");
|
||||
restoreSymbolXML(symel);
|
||||
type = function.getDataTypeManager().readXMLDataType(parser);
|
||||
size = type.getLength();
|
||||
parser.end(symel);
|
||||
|
||||
if (size == 0) {
|
||||
throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName());
|
||||
}
|
||||
restoreEntryXML(parser);
|
||||
while(parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement addrel = parser.start("hash");
|
||||
hash = SpecXmlUtils.decodeLong(addrel.getAttribute("val"));
|
||||
parser.end(addrel);
|
||||
pcaddr = parseRangeList(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getStorage() {
|
||||
Program program = function.getFunction().getProgram();
|
||||
try {
|
||||
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(getHash()),
|
||||
getSize());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String buildSymbolXML(PcodeDataTypeManager dtmanage, String nm,
|
||||
DataType dt, int length, boolean tl, boolean nl, boolean ro, boolean isVolatile,
|
||||
int format) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<symbol");
|
||||
if (nm != null) {
|
||||
SpecXmlUtils.xmlEscapeAttribute(res, "name", nm);
|
||||
}
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", tl);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "namelock", nl);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "readonly", ro);
|
||||
if (isVolatile) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "volatile", true);
|
||||
}
|
||||
res.append(">\n");
|
||||
res.append(dtmanage.buildTypeRef(dt, length));
|
||||
res.append("</symbol>\n");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build dynamic VariableStorage for a unique variable
|
||||
* @param vn is the variable in the unique space
|
||||
* @param high is the HighFunction containing the variable
|
||||
* @return the dynamic VariableStorage
|
||||
*/
|
||||
public static VariableStorage buildDynamicStorage(Varnode vn, HighFunction high) {
|
||||
DynamicHash dynamicHash = new DynamicHash(vn, high);
|
||||
Program program = high.getFunction().getProgram();
|
||||
long ourHash = dynamicHash.getHash();
|
||||
try {
|
||||
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(ourHash),
|
||||
vn.getSize());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertException("Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ import ghidra.util.xml.SpecXmlUtils;
|
|||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
public class EquateSymbol extends DynamicSymbol {
|
||||
public class EquateSymbol extends HighSymbol {
|
||||
|
||||
public static final int FORMAT_DEFAULT = 0;
|
||||
public static final int FORMAT_HEX = 1;
|
||||
|
@ -39,16 +39,22 @@ public class EquateSymbol extends DynamicSymbol {
|
|||
|
||||
public EquateSymbol(long uniqueId, String nm, long val, HighFunction func, Address addr,
|
||||
long hash) {
|
||||
super(uniqueId, nm, DataType.DEFAULT, 1, func, addr, hash);
|
||||
super(uniqueId, nm, DataType.DEFAULT, func);
|
||||
category = 1;
|
||||
value = val;
|
||||
convert = FORMAT_DEFAULT;
|
||||
DynamicEntry entry = new DynamicEntry(this, addr, hash);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
public EquateSymbol(long uniqueId, int conv, long val, HighFunction func, Address addr,
|
||||
long hash) {
|
||||
super(uniqueId, "", DataType.DEFAULT, 1, func, addr, hash);
|
||||
super(uniqueId, "", DataType.DEFAULT, func);
|
||||
category = 1;
|
||||
value = val;
|
||||
convert = conv;
|
||||
DynamicEntry entry = new DynamicEntry(this, addr, hash);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
public long getValue() { return value; }
|
||||
|
@ -56,9 +62,8 @@ public class EquateSymbol extends DynamicSymbol {
|
|||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("equatesymbol");
|
||||
restoreSymbolXML(symel);
|
||||
restoreXMLHeader(symel);
|
||||
type = DataType.DEFAULT;
|
||||
size = 1;
|
||||
convert = FORMAT_DEFAULT;
|
||||
String formString = symel.getAttribute("format");
|
||||
if (formString != null) {
|
||||
|
@ -81,40 +86,12 @@ public class EquateSymbol extends DynamicSymbol {
|
|||
parser.start("value");
|
||||
value = SpecXmlUtils.decodeLong(parser.end().getText()); // End <value> tag
|
||||
parser.end(symel);
|
||||
|
||||
if (size == 0) {
|
||||
throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName());
|
||||
}
|
||||
restoreEntryXML(parser);
|
||||
while(parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXML() {
|
||||
String sym = buildSymbolXML(function.getDataTypeManager(), name, value, isNameLocked(), false, convert);
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<mapsym type=\"equate\">\n");
|
||||
res.append(sym);
|
||||
buildHashXML(res);
|
||||
res.append("</mapsym>\n");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public static String buildSymbolXML(PcodeDataTypeManager dtmanage, String nm,long value,
|
||||
boolean nl, boolean isVolatile,int convert) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<equatesymbol");
|
||||
if (nm != null) {
|
||||
SpecXmlUtils.xmlEscapeAttribute(res, "name", nm);
|
||||
}
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", true);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "namelock", nl);
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "cat", 1); // Specify category 1 for the equate
|
||||
if (isVolatile) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "volatile", true);
|
||||
}
|
||||
public void saveXML(StringBuilder buf) {
|
||||
buf.append("<equatesymbol");
|
||||
saveXMLHeader(buf);
|
||||
if (convert != 0) {
|
||||
String formString = "hex";
|
||||
if (convert == FORMAT_HEX) {
|
||||
|
@ -132,14 +109,13 @@ public class EquateSymbol extends DynamicSymbol {
|
|||
else if (convert == FORMAT_CHAR) {
|
||||
formString = "char";
|
||||
}
|
||||
SpecXmlUtils.encodeStringAttribute(res, "format", formString);
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "format", formString);
|
||||
}
|
||||
res.append(">\n");
|
||||
res.append(" <value>0x");
|
||||
res.append(Long.toHexString(value));
|
||||
res.append("</value>\n");
|
||||
res.append("</equatesymbol>\n");
|
||||
return res.toString();
|
||||
buf.append(">\n");
|
||||
buf.append(" <value>0x");
|
||||
buf.append(Long.toHexString(value));
|
||||
buf.append("</value>\n");
|
||||
buf.append("</equatesymbol>\n");
|
||||
}
|
||||
|
||||
public static int convertName(String nm,long val) {
|
||||
|
|
|
@ -26,14 +26,26 @@ import ghidra.program.model.listing.Program;
|
|||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
|
||||
/**
|
||||
* A container for global symbols in the decompiler's model of a function. It contains
|
||||
* HighSymbol objects for any symbol accessed by the particular function that is in either
|
||||
* the global scope or some other global namespace. Currently the container is populated
|
||||
* indirectly from the HighGlobal objects marshaled back from the decompiler, using either
|
||||
* the populateSymbol() or newSymbol() methods. HighSymbols are stored by Address and by id,
|
||||
* which matches the formal SymbolDB id when it exists.
|
||||
*/
|
||||
public class GlobalSymbolMap {
|
||||
private Program program;
|
||||
private HighFunction func;
|
||||
private SymbolTable symbolTable;
|
||||
private HashMap<Address, HighCodeSymbol> addrMappedSymbols; // Hashed by addr
|
||||
private HashMap<Long, HighCodeSymbol> symbolMap; // Hashed by unique key
|
||||
private HighFunction func; // Is the full decompiler model of the function to which this belongs
|
||||
private SymbolTable symbolTable; // Used for cross-referencing with Ghidra's database backed Symbols
|
||||
private HashMap<Address, HighCodeSymbol> addrMappedSymbols; // Look up symbols by address
|
||||
private HashMap<Long, HighCodeSymbol> symbolMap; // Look up symbol by id
|
||||
private long uniqueSymbolId; // Next available symbol id
|
||||
|
||||
/**
|
||||
* Construct a global symbol map attached to a particular function model.
|
||||
* @param f is the decompiler function model
|
||||
*/
|
||||
public GlobalSymbolMap(HighFunction f) {
|
||||
program = f.getFunction().getProgram();
|
||||
func = f;
|
||||
|
@ -108,14 +120,28 @@ public class GlobalSymbolMap {
|
|||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a HighSymbol based on an id
|
||||
* @param id is the id
|
||||
* @return the matching HighSymbol or null
|
||||
*/
|
||||
public HighCodeSymbol getSymbol(long id) {
|
||||
return symbolMap.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a HighSymbol based on an Address
|
||||
* @param addr is the given Address
|
||||
* @return the matching HighSymbol or null
|
||||
*/
|
||||
public HighCodeSymbol getSymbol(Address addr) {
|
||||
return addrMappedSymbols.get(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an iterator over all HighSymbols in this container
|
||||
* @return the iterator
|
||||
*/
|
||||
public Iterator<HighCodeSymbol> getSymbols() {
|
||||
return symbolMap.values().iterator();
|
||||
}
|
||||
|
|
|
@ -17,35 +17,110 @@ package ghidra.program.model.pcode;
|
|||
|
||||
import ghidra.program.database.symbol.CodeSymbol;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* Symbol returned by the decompiler that wraps a CodeSymbol
|
||||
* A global symbol as part of the decompiler's model of a function. This symbol can
|
||||
* be backed by a formal CodeSymbol, obtained using getCodeSymbol(). This symbol can be backed
|
||||
* by a formal Data object, obtained using getData(). If there is a backing CodeSymbol, this takes its name,
|
||||
* otherwise the name is dynamically generated using SymbolUtilities. The data-type attached to this does
|
||||
* not necessarily match the backing CodeSymbol or Data object.
|
||||
*/
|
||||
public class HighCodeSymbol extends HighSymbol {
|
||||
|
||||
private CodeSymbol symbol;
|
||||
private Data data;
|
||||
private VariableStorage storage;
|
||||
|
||||
/**
|
||||
* Construct with a backing CodeSymbol. An attempt is made to also find a backing Data object.
|
||||
* @param sym is the backing CodeSymbol
|
||||
* @param dataType is the (possibly distinct) data-type associated with the new HighSymbol
|
||||
* @param sz is the storage size, in bytes, of the symbol
|
||||
* @param func is the decompiler function model owning the new HighSymbol
|
||||
*/
|
||||
public HighCodeSymbol(CodeSymbol sym, DataType dataType, int sz, HighFunction func) {
|
||||
super(sym.getID(), sym.getName(), dataType, sz, null, func);
|
||||
super(sym.getID(), sym.getName(), dataType, func);
|
||||
symbol = sym;
|
||||
data = null;
|
||||
setNameLock(true);
|
||||
setTypeLock(true);
|
||||
Data data = null;
|
||||
Object dataObj = symbol.getObject();
|
||||
if (dataObj instanceof Data) {
|
||||
data = (Data) dataObj;
|
||||
}
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(symbol.getProgram(), symbol.getAddress(), sz);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
SymbolEntry entry;
|
||||
if (data != null) {
|
||||
entry = new MappedDataEntry(this, store, data);
|
||||
}
|
||||
else {
|
||||
entry = new MappedEntry(this, store, null);
|
||||
}
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with just a (global) storage address and size. There will be no backing CodeSymbol.
|
||||
* An attempt is made to find a backing Data object.
|
||||
* @param id is the id to associate with the new HighSymbol
|
||||
* @param addr is the starting Address of the symbol storage
|
||||
* @param dataType is the data-type associated with the new symbol
|
||||
* @param sz is the size of the symbol storage in bytes
|
||||
* @param func is the decompiler function model owning the new symbol
|
||||
*/
|
||||
public HighCodeSymbol(long id, Address addr, DataType dataType, int sz, HighFunction func) {
|
||||
super(id, SymbolUtilities.getDynamicName(func.getFunction().getProgram(), addr), dataType,
|
||||
sz, null, func);
|
||||
func);
|
||||
symbol = null;
|
||||
data = func.getFunction().getProgram().getListing().getDataAt(addr);
|
||||
setNameLock(true);
|
||||
setTypeLock(true);
|
||||
Program program = func.getFunction().getProgram();
|
||||
Data data = program.getListing().getDataAt(addr);
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(program, addr, sz);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
SymbolEntry entry;
|
||||
if (data != null) {
|
||||
entry = new MappedDataEntry(this, store, data);
|
||||
}
|
||||
else {
|
||||
entry = new MappedEntry(this, store, null);
|
||||
}
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for HighSymbol which is unattached to a HighFunction
|
||||
* @param id is the unique id to assign
|
||||
* @param nm is the name of the symbol
|
||||
* @param data is an underlying Data object defining the storage and data-type
|
||||
* @param dtmanage is the data-type manager for XML reference
|
||||
*/
|
||||
public HighCodeSymbol(long id, String nm, Data data, PcodeDataTypeManager dtmanage) {
|
||||
super(id, nm, data.getDataType(), true, true, dtmanage);
|
||||
Program program = dtmanage.getProgram();
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(program, data.getMinAddress(), data.getLength());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
SymbolEntry entry = new MappedDataEntry(this, store, data);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,78 +128,30 @@ public class HighCodeSymbol extends HighSymbol {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CodeSymbol backing this, if it exists
|
||||
* @return the CodeSymbol or null
|
||||
*/
|
||||
public CodeSymbol getCodeSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Data object backing this, if it exists
|
||||
* @return the Data object or null
|
||||
*/
|
||||
public Data getData() {
|
||||
if (data == null) {
|
||||
Object dataObj = symbol.getObject();
|
||||
if (dataObj instanceof Data) {
|
||||
data = (Data) dataObj;
|
||||
}
|
||||
SymbolEntry entry = entryList[0];
|
||||
if (entry instanceof MappedDataEntry) {
|
||||
return ((MappedDataEntry) entry).getData();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getStorage() {
|
||||
if (storage == null) {
|
||||
Data dataObj = getData();
|
||||
if (dataObj != null) {
|
||||
try {
|
||||
storage = new VariableStorage(function.getFunction().getProgram(),
|
||||
dataObj.getAddress(), dataObj.getLength());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
storage = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
storage = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
}
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXML() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("symbol");
|
||||
restoreSymbolXML(symel);
|
||||
Symbol tmpSymbol = function.getFunction().getProgram().getSymbolTable().getSymbol(getId());
|
||||
if (tmpSymbol instanceof CodeSymbol) {
|
||||
symbol = (CodeSymbol) tmpSymbol;
|
||||
}
|
||||
type = function.getDataTypeManager().readXMLDataType(parser);
|
||||
size = type.getLength();
|
||||
parser.end(symel);
|
||||
restoreEntryXML(parser);
|
||||
while (parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
super.restoreXML(parser);
|
||||
symbol = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
AddressFactory addrFactory = function.getAddressFactory();
|
||||
|
||||
XmlElement addrel = parser.start("addr");
|
||||
int sz = type.getLength();
|
||||
if (sz == 0) {
|
||||
throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName());
|
||||
}
|
||||
Address varAddr = Varnode.readXMLAddress(addrel, addrFactory);
|
||||
parser.end(addrel);
|
||||
pcaddr = parseRangeList(parser);
|
||||
if (symbol == null) {
|
||||
Program program = function.getFunction().getProgram();
|
||||
data = program.getListing().getDataAt(varAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,11 +98,7 @@ public class HighConstant extends HighVariable {
|
|||
if (symbol == null) {
|
||||
symbol = function.getGlobalSymbolMap().getSymbol(symref);
|
||||
}
|
||||
if (symbol instanceof DynamicSymbol) {
|
||||
name = symbol.getName();
|
||||
symbol.setHighVariable(this);
|
||||
}
|
||||
else if (symbol == null) {
|
||||
if (symbol == null) {
|
||||
GlobalSymbolMap globalMap = function.getGlobalSymbolMap();
|
||||
Program program = function.getFunction().getProgram();
|
||||
symbol = globalMap.populateSymbol(symref, null, -1);
|
||||
|
@ -114,6 +110,10 @@ public class HighConstant extends HighVariable {
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (symbol.getFirstWholeMap() instanceof DynamicEntry) {
|
||||
name = symbol.getName();
|
||||
symbol.setHighVariable(this);
|
||||
}
|
||||
}
|
||||
parser.end(el);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
||||
/**
|
||||
* A symbol, within a decompiler model, for a function without a body in the current Program.
|
||||
* The Address of this symbol corresponds to the code location that CALL instructions refer to.
|
||||
* In anticipation of a (not fully resolved) thunking mechanism, this symbol also has a separate
|
||||
* resolve Address, which is where the decompiler expects to retrieve the detailed Function object.
|
||||
*/
|
||||
public class HighExternalSymbol extends HighSymbol {
|
||||
|
||||
private Address resolveAddress; // The location of the Function object
|
||||
|
||||
/**
|
||||
* Construct the external reference symbol given a name, the symbol Address, and a
|
||||
* resolving Address.
|
||||
* @param nm is the given name
|
||||
* @param addr is the symbol Address
|
||||
* @param resolveAddr is the resolve Address
|
||||
* @param dtmanage is a PcodeDataTypeManager for facilitating XML marshaling
|
||||
*/
|
||||
public HighExternalSymbol(String nm, Address addr, Address resolveAddr,
|
||||
PcodeDataTypeManager dtmanage) {
|
||||
super(0, nm, DataType.DEFAULT, true, true, dtmanage);
|
||||
resolveAddress = resolveAddr;
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(getProgram(), addr, 1);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
MappedEntry entry = new MappedEntry(this, store, null);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXML(StringBuilder buf) {
|
||||
buf.append("<externrefsymbol");
|
||||
if ((name != null) && (name.length() > 0)) { // Give the symbol a name if we can
|
||||
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name + "_exref");
|
||||
}
|
||||
buf.append(">\n");
|
||||
buf.append(Varnode.buildXMLAddress(resolveAddress));
|
||||
buf.append("</externrefsymbol>\n");
|
||||
}
|
||||
}
|
|
@ -482,26 +482,6 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
return resBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the XML representation of only the shell function info not including everything known
|
||||
* about the function.
|
||||
*
|
||||
* @param name name of the function
|
||||
* @param addr address the function is located at
|
||||
*
|
||||
* @return the XML string
|
||||
*/
|
||||
static public String buildFunctionShellXML(String name, Address addr) {
|
||||
StringBuilder resBuf = new StringBuilder();
|
||||
resBuf.append("<function");
|
||||
SpecXmlUtils.xmlEscapeAttribute(resBuf, "name", name);
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "size", 1);
|
||||
resBuf.append(">\n");
|
||||
resBuf.append(Varnode.buildXMLAddress(addr));
|
||||
resBuf.append("</function>\n");
|
||||
return resBuf.toString();
|
||||
}
|
||||
|
||||
public static ErrorHandler getErrorHandler(final Object errOriginator,
|
||||
final String targetName) {
|
||||
return new ErrorHandler() {
|
||||
|
|
|
@ -40,8 +40,10 @@ public class HighFunctionDBUtil {
|
|||
public static final String AUTO_CAT = "/auto_proto"; // Category for auto generated prototypes
|
||||
|
||||
/**
|
||||
* Commit function return to the underlying database.
|
||||
* @param highFunction
|
||||
* Commit the decompiler's version of the function return data-type to the database.
|
||||
* The decompiler's version of the prototype model is committed as well
|
||||
* @param highFunction is the decompiler's model of the function
|
||||
* @param source is the desired SourceType for the commit
|
||||
*/
|
||||
public static void commitReturnToDatabase(HighFunction highFunction, SourceType source) {
|
||||
try {
|
||||
|
@ -84,7 +86,9 @@ public class HighFunctionDBUtil {
|
|||
|
||||
List<Parameter> params = getParameters(highFunction, useDataTypes);
|
||||
|
||||
commitParamsToDatabase(function, highFunction.getFunctionPrototype(), params,
|
||||
FunctionPrototype functionPrototype = highFunction.getFunctionPrototype();
|
||||
String modelName = (functionPrototype != null) ? functionPrototype.getModelName() : null;
|
||||
commitParamsToDatabase(function, modelName, params,
|
||||
highFunction.getFunctionPrototype().isVarArg(), true, source);
|
||||
}
|
||||
|
||||
|
@ -113,22 +117,26 @@ public class HighFunctionDBUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Commit the specified parameter list to the specified function.
|
||||
* @param function
|
||||
* @param params
|
||||
* Commit a specified set of parameters for the given function to the database.
|
||||
* The name, data-type, and storage is committed for each parameter. The parameters are
|
||||
* provided along with a formal PrototypeModel. If the parameters fit the model, they are
|
||||
* committed using "dynamic" storage. Otherwise, they are committed using "custom" storage.
|
||||
* @param function is the Function being modified
|
||||
* @param modelName is the name of the underlying PrototypeModel
|
||||
* @param params is the formal list of parameter objects
|
||||
* @param hasVarArgs is true if the prototype can take variable arguments
|
||||
* @param renameConflicts if true any name conflicts will be resolved
|
||||
* by renaming the conflicting local variable/label
|
||||
* @param source source type
|
||||
* @throws DuplicateNameException if commit of parameters caused conflict with other
|
||||
* local variable/label. Should not occur if renameConflicts is true.
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException for invalid variable names or for parameter data-types that aren't fixed length
|
||||
* @throws DuplicateNameException is there are collisions between variable names in the function's scope
|
||||
*/
|
||||
public static void commitParamsToDatabase(Function function, FunctionPrototype prototype,
|
||||
public static void commitParamsToDatabase(Function function, String modelName,
|
||||
List<Parameter> params, boolean hasVarArgs, boolean renameConflicts, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
String modelName = prototype != null ? prototype.getModelName() : null;
|
||||
|
||||
try {
|
||||
function.updateFunction(modelName, null, params,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, source);
|
||||
|
@ -180,6 +188,7 @@ public class HighFunctionDBUtil {
|
|||
break;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// Continue looping until we get a unique symbol name
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
break;
|
||||
|
@ -188,9 +197,10 @@ public class HighFunctionDBUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Commit all local variables to the underlying database.
|
||||
* @param highFunction
|
||||
* @param source source type
|
||||
* Commit local variables from the decompiler's model of the function to the database.
|
||||
* This does NOT include formal function parameters.
|
||||
* @param highFunction is the decompiler's model of the function
|
||||
* @param source is the desired SourceType for the commit
|
||||
*/
|
||||
public static void commitLocalsToDatabase(HighFunction highFunction, SourceType source) {
|
||||
|
||||
|
@ -281,11 +291,12 @@ public class HighFunctionDBUtil {
|
|||
Iterator<HighSymbol> symbols = highFunction.getLocalSymbolMap().getSymbols();
|
||||
while (symbols.hasNext()) {
|
||||
HighSymbol symbol = symbols.next();
|
||||
if (!(symbol instanceof DynamicSymbol)) {
|
||||
SymbolEntry entry = symbol.getFirstWholeMap();
|
||||
if (!(entry instanceof DynamicEntry)) {
|
||||
continue;
|
||||
}
|
||||
// Note: assumes there is only one hash method used for unique locals
|
||||
if (((DynamicSymbol) symbol).getHash() == hash) {
|
||||
if (((DynamicEntry) entry).getHash() == hash) {
|
||||
if (symbol.getHighVariable() != null) {
|
||||
return true; // Hash successfully attached to a variable
|
||||
}
|
||||
|
@ -303,8 +314,9 @@ public class HighFunctionDBUtil {
|
|||
*/
|
||||
private static Variable clearConflictingLocalVariables(HighSymbol local) {
|
||||
|
||||
if (local instanceof MappedSymbol) {
|
||||
if (((MappedSymbol) local).getSlot() >= 0) { // Don't clear parameters
|
||||
SymbolEntry entry = local.getFirstWholeMap();
|
||||
if (entry instanceof MappedEntry) {
|
||||
if (local.isParameter()) { // Don't clear parameters
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
@ -314,12 +326,12 @@ public class HighFunctionDBUtil {
|
|||
|
||||
VariableStorage storage = local.getStorage();
|
||||
int firstUseOffset = local.getFirstUseOffset();
|
||||
if (local instanceof DynamicSymbol) {
|
||||
if (entry instanceof DynamicEntry) {
|
||||
|
||||
DynamicSymbol dynamicSym = (DynamicSymbol) local;
|
||||
DynamicEntry dynamicEntry = (DynamicEntry) entry;
|
||||
for (Variable ul : func.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER)) {
|
||||
// Note: assumes there is only one hash method used for unique locals
|
||||
if (ul.getFirstStorageVarnode().getOffset() == dynamicSym.getHash()) {
|
||||
if (ul.getFirstStorageVarnode().getOffset() == dynamicEntry.getHash()) {
|
||||
return ul;
|
||||
}
|
||||
}
|
||||
|
@ -357,12 +369,12 @@ public class HighFunctionDBUtil {
|
|||
* @return the matching parameter that can be modified
|
||||
* @throws InvalidInputException if the desired parameter cannot be modified
|
||||
*/
|
||||
private static Parameter getDatabaseParameter(MappedSymbol param) throws InvalidInputException {
|
||||
private static Parameter getDatabaseParameter(HighSymbol param) throws InvalidInputException {
|
||||
|
||||
HighFunction highFunction = param.getHighFunction();
|
||||
Function function = highFunction.getFunction();
|
||||
|
||||
int slot = param.getSlot();
|
||||
int slot = param.getCategoryIndex();
|
||||
Parameter[] parameters = function.getParameters();
|
||||
if (slot < parameters.length) {
|
||||
if (parameters[slot].isAutoParameter()) {
|
||||
|
@ -424,10 +436,8 @@ public class HighFunctionDBUtil {
|
|||
boolean isRename = name != null;
|
||||
|
||||
if (variable.isParameter()) {
|
||||
MappedSymbol mappedSymbol = (MappedSymbol) variable;
|
||||
|
||||
Parameter dbParam = getDatabaseParameter(mappedSymbol);
|
||||
VariableStorage storage = mappedSymbol.getStorage();
|
||||
Parameter dbParam = getDatabaseParameter(variable);
|
||||
VariableStorage storage = variable.getStorage();
|
||||
if (dataType != null) {
|
||||
if (resized && function.hasCustomVariableStorage()) {
|
||||
VariableStorage newStorage =
|
||||
|
@ -448,7 +458,7 @@ public class HighFunctionDBUtil {
|
|||
HighVariable tmpHigh = variable.getHighVariable();
|
||||
if (tmpHigh != null && tmpHigh.getRepresentative().isUnique()) {
|
||||
storage =
|
||||
DynamicSymbol.buildDynamicStorage(tmpHigh.getRepresentative(), highFunction);
|
||||
DynamicEntry.buildDynamicStorage(tmpHigh.getRepresentative(), highFunction);
|
||||
var = null;
|
||||
}
|
||||
else {
|
||||
|
@ -591,26 +601,26 @@ public class HighFunctionDBUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Commit an override of a calls prototype to the database
|
||||
* @param function is the Function whose call is being overriden
|
||||
* @param callsite is the address of the call
|
||||
* @param sig signature override
|
||||
* @throws InvalidInputException
|
||||
* @throws DuplicateNameException
|
||||
* Commit an overriding prototype for a particular call site to the database. The override
|
||||
* only applies to the function(s) containing the actual call site. Calls to the same function from
|
||||
* other sites are unaffected. This is used typically either for indirect calls are for calls to
|
||||
* a function with a variable number of parameters.
|
||||
* @param function is the Function whose call site is being overridden
|
||||
* @param callsite is the address of the calling instruction (the call site)
|
||||
* @param sig is the overriding function signature
|
||||
* @throws InvalidInputException if there are problems committing the override symbol
|
||||
*/
|
||||
public static void writeOverride(Function function, Address callsite, FunctionSignature sig)
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
throws InvalidInputException {
|
||||
|
||||
ParameterDefinition[] params = sig.getArguments();
|
||||
FunctionSignatureImpl fsig = new FunctionSignatureImpl("tmpname"); // Empty datatype, will get renamed later
|
||||
FunctionDefinitionDataType fsig = new FunctionDefinitionDataType("tmpname"); // Empty datatype, will get renamed later
|
||||
fsig.setGenericCallingConvention(sig.getGenericCallingConvention());
|
||||
fsig.setArguments(params);
|
||||
fsig.setReturnType(sig.getReturnType());
|
||||
fsig.setVarArgs(sig.hasVarArgs());
|
||||
|
||||
FunctionDefinitionDataType dt = new FunctionDefinitionDataType(fsig);
|
||||
|
||||
DataTypeSymbol datsym = new DataTypeSymbol(dt, "prt", AUTO_CAT);
|
||||
DataTypeSymbol datsym = new DataTypeSymbol(fsig, "prt", AUTO_CAT);
|
||||
Program program = function.getProgram();
|
||||
SymbolTable symtab = program.getSymbolTable();
|
||||
DataTypeManager dtmanage = program.getDataTypeManager();
|
||||
|
@ -623,9 +633,9 @@ public class HighFunctionDBUtil {
|
|||
|
||||
/**
|
||||
* Read a call prototype override which corresponds to the specified override code symbol
|
||||
* @param sym special call override code symbol whose address corresponds to a callsite
|
||||
* @param sym special call override code symbol whose address corresponds to a call site
|
||||
* @return call prototype override DataTypeSymbol or null if associated function signature
|
||||
* datatype could not be found
|
||||
* data-type could not be found
|
||||
*/
|
||||
public static DataTypeSymbol readOverride(Symbol sym) {
|
||||
DataTypeSymbol datsym = DataTypeSymbol.readSymbol(AUTO_CAT, sym);
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
|
||||
/**
|
||||
* A function symbol that represents only a shell of (the name and address) the function,
|
||||
* when no other information is available.
|
||||
*/
|
||||
public class HighFunctionShellSymbol extends HighSymbol {
|
||||
|
||||
/**
|
||||
* Construct the function shell given a name and address
|
||||
* @param nm is the given name
|
||||
* @param addr is the given address
|
||||
* @param manage is PcodeDataTypeManager to facilitate XML marshaling
|
||||
*/
|
||||
public HighFunctionShellSymbol(String nm, Address addr, PcodeDataTypeManager manage) {
|
||||
super(0, nm, DataType.DEFAULT, true, true, manage);
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(getProgram(), addr, 1);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
MappedEntry entry = new MappedEntry(this, store, null);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXML(StringBuilder buf) {
|
||||
buf.append("<function");
|
||||
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "size", 1);
|
||||
buf.append(">\n");
|
||||
buf.append(Varnode.buildXMLAddress(getStorage().getMinAddress()));
|
||||
buf.append("</function>\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* A function symbol that encapsulates detailed information about a particular function
|
||||
* for the purposes of decompilation. The detailed model is provided by a backing HighFunction object.
|
||||
*/
|
||||
public class HighFunctionSymbol extends HighSymbol {
|
||||
|
||||
/**
|
||||
* Construct given an Address, size, and decompiler function model for the symbol.
|
||||
* The Address is typically the entry point of the function but may be different
|
||||
* if the function is getting mapped from elsewhere (i.e. the EXTERNAL space). The size
|
||||
* is given in bytes but generally isn't the true size of the function. The size needs to
|
||||
* make the symbol just big enough to absorb any off-cut Address queries.
|
||||
* @param addr is the starting Address of the symbol
|
||||
* @param size is the pseudo-size of the function
|
||||
* @param function is the decompiler model of the function
|
||||
*/
|
||||
public HighFunctionSymbol(Address addr, int size, HighFunction function) {
|
||||
super(0, "", DataType.DEFAULT, function);
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(getProgram(), addr, size);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
MappedEntry entry = new MappedEntry(this, store, null);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXML(StringBuilder buf) {
|
||||
MappedEntry entry = (MappedEntry) getFirstWholeMap();
|
||||
String funcString =
|
||||
function.buildFunctionXML(entry.getStorage().getMinAddress(), entry.getSize());
|
||||
buf.append(funcString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* A symbol with no underlying data-type. A label within code. This is used to
|
||||
* model named jump targets within a function to the decompiler.
|
||||
*/
|
||||
public class HighLabelSymbol extends HighSymbol {
|
||||
|
||||
/**
|
||||
* Construct the label given a name and address
|
||||
* @param nm is the given name
|
||||
* @param addr is the given Address
|
||||
* @param dtmanage is a PcodeDataManager to facilitate XML marshaling
|
||||
*/
|
||||
public HighLabelSymbol(String nm, Address addr, PcodeDataTypeManager dtmanage) {
|
||||
super(0, nm, DataType.DEFAULT, true, true, dtmanage);
|
||||
VariableStorage store;
|
||||
try {
|
||||
store = new VariableStorage(getProgram(), addr, 1);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
store = VariableStorage.UNASSIGNED_STORAGE;
|
||||
}
|
||||
MappedEntry entry = new MappedEntry(this, store, null);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXML(StringBuilder buf) {
|
||||
buf.append("<labelsym");
|
||||
saveXMLHeader(buf);
|
||||
buf.append("/>\n");
|
||||
}
|
||||
}
|
|
@ -57,11 +57,8 @@ public class HighParam extends HighLocal {
|
|||
@Override
|
||||
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
|
||||
super.restoreXml(parser);
|
||||
slot = 0;
|
||||
HighSymbol sym = getSymbol();
|
||||
if (sym instanceof MappedSymbol) {
|
||||
slot = ((MappedSymbol) sym).getSlot();
|
||||
}
|
||||
slot = sym.getCategoryIndex();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,105 +16,245 @@
|
|||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
public abstract class HighSymbol {
|
||||
/**
|
||||
* A symbol within the decompiler's model of a particular function. The symbol has a name and a data-type
|
||||
* along with other properties. The symbol is mapped to one or more storage locations by attaching a
|
||||
* SymbolEntry for each mapping.
|
||||
*/
|
||||
public class HighSymbol {
|
||||
|
||||
public static final long ID_BASE = 0x4000000000000000L; // Put keys in the dynamic symbol portion of the key space
|
||||
protected String name;
|
||||
protected DataType type;
|
||||
protected int size; // Size of this variable
|
||||
protected Address pcaddr; // first-use address
|
||||
protected HighFunction function; // associated function
|
||||
protected int category; // Sub-class of symbol -1=none 0=parameter 1=equate
|
||||
protected int categoryIndex; // Numbering within the sub-class
|
||||
private boolean namelock; // Is this variable's name locked
|
||||
private boolean typelock; // Is this variable's datatype locked
|
||||
private boolean readonly;
|
||||
private long id; // Unique id of this symbol
|
||||
protected SymbolEntry[] entryList; // List of mappings for this symbol
|
||||
|
||||
private HighVariable highVariable;
|
||||
private PcodeDataTypeManager dtmanage; // Datatype manager for XML generation
|
||||
|
||||
public HighSymbol(HighFunction func) { // For use with restoreXML
|
||||
/**
|
||||
* Constructor for use with restoreXML
|
||||
* @param func is the HighFunction using the symbol
|
||||
*/
|
||||
protected HighSymbol(HighFunction func) {
|
||||
function = func;
|
||||
dtmanage = function.getDataTypeManager();
|
||||
}
|
||||
|
||||
public HighSymbol(long uniqueId, String nm, DataType tp, int sz, Address pc,
|
||||
HighFunction func) {
|
||||
/**
|
||||
* Construct a base symbol, given a name and data-type. Mappings must be attached separately.
|
||||
* @param uniqueId is the id to associate with the new symbol
|
||||
* @param nm is the given name
|
||||
* @param tp is the given data-type
|
||||
* @param func is the function model owning the new symbol
|
||||
*/
|
||||
protected HighSymbol(long uniqueId, String nm, DataType tp, HighFunction func) {
|
||||
function = func;
|
||||
dtmanage = function.getDataTypeManager();
|
||||
name = nm;
|
||||
type = tp;
|
||||
size = sz;
|
||||
pcaddr = pc;
|
||||
namelock = false;
|
||||
typelock = false;
|
||||
function = func;
|
||||
id = uniqueId;
|
||||
category = -1;
|
||||
categoryIndex = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a symbol that is not attached to a function model. The symbol is given
|
||||
* a name, data-type, and other basic attributes. Mappings must be attached separately.
|
||||
* @param uniqueId is the id to associate with the new symbol
|
||||
* @param nm is the given name
|
||||
* @param tp is the given data-type
|
||||
* @param tlock is true if the symbol is type locked
|
||||
* @param nlock is true if the symbol is name locked
|
||||
* @param manage is a PcodeDataTypeManager to facilitate XML marshaling
|
||||
*/
|
||||
protected HighSymbol(long uniqueId, String nm, DataType tp, boolean tlock, boolean nlock,
|
||||
PcodeDataTypeManager manage) {
|
||||
function = null;
|
||||
dtmanage = manage;
|
||||
name = nm;
|
||||
type = tp;
|
||||
namelock = nlock;
|
||||
typelock = tlock;
|
||||
id = uniqueId;
|
||||
category = -1;
|
||||
categoryIndex = -1;
|
||||
}
|
||||
|
||||
protected void addMapEntry(SymbolEntry entry) {
|
||||
if (entryList == null) {
|
||||
entryList = new SymbolEntry[1];
|
||||
entryList[0] = entry;
|
||||
}
|
||||
else {
|
||||
SymbolEntry[] newList = new SymbolEntry[entryList.length + 1];
|
||||
for (int i = 0; i < entryList.length; ++i) {
|
||||
newList[i] = entryList[i];
|
||||
}
|
||||
newList[entryList.length] = entry;
|
||||
entryList = newList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id associated with this symbol.
|
||||
* @return the id
|
||||
*/
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param high is the associated HighVariable
|
||||
*/
|
||||
public void setHighVariable(HighVariable high) {
|
||||
this.highVariable = high;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HighVariable associate with this symbol if any. This allows the user to go straight
|
||||
* into the decompiler's function to see how the symbol gets manipulated.
|
||||
* @return the associated HighVariable or null
|
||||
*/
|
||||
public HighVariable getHighVariable() {
|
||||
return highVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base name of this symbol
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Program object containing the function being modeled.
|
||||
* @return the Program
|
||||
*/
|
||||
public Program getProgram() {
|
||||
return dtmanage.getProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data-type associate with this symbol
|
||||
*/
|
||||
public DataType getDataType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of bytes consumed by the storage for this symbol
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
return entryList[0].getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first code Address, within the function, where this symbol's storage actually
|
||||
* holds the value of the symbol. If there is more than one mapping for the symbol, this
|
||||
* returns the code Address for the first mapping. A null value indicates that the storage
|
||||
* is valid over the whole function (at least). If the value is non-null, the symbol storage
|
||||
* may be used for other purposes at prior locations.
|
||||
* @return the first use code Address or null
|
||||
*/
|
||||
public Address getPCAddress() {
|
||||
return pcaddr;
|
||||
return entryList[0].pcaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first code Address (expressed as a different in bytes from the starting address of the
|
||||
* function) where this symbol's storage actually holds the value of the symbol. A value of 0 indicates
|
||||
* that the storage is valid across the entire function. A negative value indicates the storage is
|
||||
* an input to the function.
|
||||
* @return the first-use offset of this symbol's storage
|
||||
*/
|
||||
protected int getFirstUseOffset() {
|
||||
Address pcaddr = entryList[0].pcaddr;
|
||||
if (pcaddr == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) pcaddr.subtract(getHighFunction().getFunction().getEntryPoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function model of which this symbol is a part.
|
||||
* @return the HighFunction owning this symbol
|
||||
*/
|
||||
public HighFunction getHighFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the category and associated index for this symbol. The category indicates a specific sub-class
|
||||
* of symbols. Currently -1=none, 0=parameter, 1=equate
|
||||
* @param cat is the category
|
||||
* @param index is the category index ("slot" for parameters)
|
||||
*/
|
||||
protected void setCategory(int cat, int index) {
|
||||
category = cat;
|
||||
categoryIndex = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this symbol's data-type is considered "locked". If it is "locked",
|
||||
* this symbol's data-type is considered unchangeable during decompilation. The data-type
|
||||
* will be forced into the decompiler's model of the function to the extent possible.
|
||||
* @param typelock is true if the data-type should be considered "locked".
|
||||
*/
|
||||
public void setTypeLock(boolean typelock) {
|
||||
this.typelock = typelock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this symbol's name is considered "locked". If it is "locked", the decompiler
|
||||
* will use the name when labeling the storage described by this symbol.
|
||||
* @param namelock is true if the name should be considered "locked".
|
||||
*/
|
||||
public void setNameLock(boolean namelock) {
|
||||
this.namelock = namelock;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readonly = readOnly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If this returns true, this symbol's data-type is "locked", meaning
|
||||
* it is considered unchangeable during decompilation. The data-type
|
||||
* will be forced into the decompiler's model of the function to the extent possible.
|
||||
* @return true if the data-type is considered "locked".
|
||||
*/
|
||||
public boolean isTypeLocked() {
|
||||
return typelock;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this returns true, this symbol's name is "locked". meaning the decompiler
|
||||
* is forced to use the name when labeling the storage described by this symbol.
|
||||
* @return true if the name is considered "locked".
|
||||
*/
|
||||
public boolean isNameLocked() {
|
||||
return namelock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the symbol's value is considered read-only (by the decompiler)
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
return readonly;
|
||||
return entryList[0].isReadOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +262,15 @@ public abstract class HighSymbol {
|
|||
* @return true if this is a parameter
|
||||
*/
|
||||
public boolean isParameter() {
|
||||
return false;
|
||||
return (category == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* For parameters (category=0), this method returns the position of the parameter within the function prototype.
|
||||
* @return the category index for this symbol
|
||||
*/
|
||||
public int getCategoryIndex() {
|
||||
return categoryIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,16 +281,55 @@ public abstract class HighSymbol {
|
|||
return false;
|
||||
}
|
||||
|
||||
public abstract VariableStorage getStorage();
|
||||
/**
|
||||
* @return the first mapping object attached to this symbol
|
||||
*/
|
||||
public SymbolEntry getFirstWholeMap() {
|
||||
return entryList[0];
|
||||
}
|
||||
|
||||
public abstract String buildXML();
|
||||
|
||||
public abstract void restoreXML(XmlPullParser parser)
|
||||
throws PcodeXMLException;
|
||||
/**
|
||||
* @return the storage associated with this symbol (associated with the first mapping)
|
||||
*/
|
||||
public VariableStorage getStorage() {
|
||||
return entryList[0].getStorage();
|
||||
}
|
||||
|
||||
protected abstract void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException;
|
||||
/**
|
||||
* Write out attributes for the base XML tag
|
||||
* @param buf is the XML output stream
|
||||
*/
|
||||
protected void saveXMLHeader(StringBuilder buf) {
|
||||
if ((id >> 56) != (ID_BASE >> 56)) { // Don't send down internal ids
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "id", id);
|
||||
}
|
||||
SpecXmlUtils.xmlEscapeAttribute(buf, "name", name);
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "typelock", typelock);
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "namelock", namelock);
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "readonly", isReadOnly());
|
||||
boolean isVolatile = entryList[0].isVolatile();
|
||||
if (isVolatile) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "volatile", true);
|
||||
}
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "cat", category);
|
||||
if (categoryIndex >= 0) {
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "index", categoryIndex);
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreSymbolXML(XmlElement symel) throws PcodeXMLException {
|
||||
/**
|
||||
* Save the symbol description as a tag to the XML stream. This does NOT save the mappings.
|
||||
* @param buf is the XML stream
|
||||
*/
|
||||
public void saveXML(StringBuilder buf) {
|
||||
buf.append("<symbol");
|
||||
saveXMLHeader(buf);
|
||||
buf.append(">\n");
|
||||
buf.append(dtmanage.buildTypeRef(type, getSize()));
|
||||
buf.append("</symbol>\n");
|
||||
}
|
||||
|
||||
protected void restoreXMLHeader(XmlElement symel) throws PcodeXMLException {
|
||||
id = SpecXmlUtils.decodeLong(symel.getAttribute("id"));
|
||||
if (id == 0) {
|
||||
throw new PcodeXMLException("missing unique symbol id");
|
||||
|
@ -158,53 +345,102 @@ public abstract class HighSymbol {
|
|||
namelock = true;
|
||||
}
|
||||
name = symel.getAttribute("name");
|
||||
categoryIndex = -1;
|
||||
category = -1;
|
||||
if (symel.hasAttribute("cat")) {
|
||||
category = SpecXmlUtils.decodeInt(symel.getAttribute("cat"));
|
||||
if (category == 0) {
|
||||
categoryIndex = SpecXmlUtils.decodeInt(symel.getAttribute("index"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Address parseRangeList(XmlPullParser parser) {
|
||||
Address addr = null;
|
||||
XmlElement rangelistel = parser.start("rangelist");
|
||||
if (parser.peek().isStart()) {
|
||||
// we only use this to establish first-use
|
||||
XmlElement rangeel = parser.start("range");
|
||||
String spc = rangeel.getAttribute("space");
|
||||
long offset = SpecXmlUtils.decodeLong(rangeel.getAttribute("first"));
|
||||
addr = function.getAddressFactory().getAddressSpace(spc).getAddress(offset);
|
||||
addr = function.getFunction().getEntryPoint().getAddressSpace().getOverlayAddress(addr);
|
||||
parser.end(rangeel);
|
||||
/**
|
||||
* Restore this symbol object and its associated mappings from an XML description
|
||||
* in the given stream.
|
||||
* @param parser is the given XML stream
|
||||
* @throws PcodeXMLException if the XML description is invalid
|
||||
*/
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("symbol");
|
||||
restoreXMLHeader(symel);
|
||||
type = dtmanage.readXMLDataType(parser);
|
||||
parser.end(symel);
|
||||
|
||||
if (categoryIndex >= 0 && name.startsWith("$$undef")) {
|
||||
// use default parameter name
|
||||
name = "param_" + Integer.toString(categoryIndex + 1);
|
||||
}
|
||||
|
||||
parser.end(rangelistel);
|
||||
return addr;
|
||||
while (parser.peek().isStart()) {
|
||||
XmlElement el = parser.peek();
|
||||
SymbolEntry entry;
|
||||
if (el.getName().equals("hash")) {
|
||||
entry = new DynamicEntry(this);
|
||||
}
|
||||
else if (this instanceof HighCodeSymbol) {
|
||||
entry = new MappedDataEntry(this);
|
||||
}
|
||||
else {
|
||||
entry = new MappedEntry(this);
|
||||
}
|
||||
entry.restoreXML(parser);
|
||||
addMapEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static void buildMapSymXML(StringBuilder res, String addrHashRes, Address pc, String sym) {
|
||||
res.append("<mapsym>\n");
|
||||
res.append(sym);
|
||||
res.append(addrHashRes);
|
||||
if (pc == null || pc.isExternalAddress()) {
|
||||
res.append("<rangelist/>");
|
||||
/**
|
||||
* Restore a full HighSymbol from the next <mapsym> tag in the given XML stream.
|
||||
* This method acts as an XML based HighSymbol factory, instantiating the correct class
|
||||
* based on the particular tags.
|
||||
* @param parser is the given XML stream
|
||||
* @param isGlobal is true if this symbol is being read into a global scope
|
||||
* @param high is the function model that will own the new symbol
|
||||
* @return the new symbol
|
||||
* @throws PcodeXMLException if the XML description is invalid
|
||||
*/
|
||||
public static HighSymbol restoreMapSymXML(XmlPullParser parser, boolean isGlobal,
|
||||
HighFunction high) throws PcodeXMLException {
|
||||
HighSymbol res = null;
|
||||
parser.start("mapsym");
|
||||
XmlElement symel = parser.peek();
|
||||
if (symel.getName().equals("equatesymbol")) {
|
||||
res = new EquateSymbol(high);
|
||||
}
|
||||
else if (isGlobal) {
|
||||
// res = new HighCodeSymbol(high);
|
||||
// Currently the decompiler does not send back global symbols. They are inferred from the HighVariables
|
||||
}
|
||||
else {
|
||||
buildRangelistXML(res, pc);
|
||||
res = new HighSymbol(high);
|
||||
}
|
||||
res.restoreXML(parser);
|
||||
while (parser.peek().isStart()) {
|
||||
SymbolEntry entry;
|
||||
if (parser.peek().getName().equals("hash")) {
|
||||
entry = new DynamicEntry(res);
|
||||
}
|
||||
else {
|
||||
entry = new MappedEntry(res);
|
||||
}
|
||||
entry.restoreXML(parser);
|
||||
res.addMapEntry(entry);
|
||||
}
|
||||
parser.end();
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the given symbol with all its mapping as a <mapsym> tag to the given XML stream.
|
||||
* @param res is the given XML stream
|
||||
* @param sym is the given symbol
|
||||
*/
|
||||
public static void buildMapSymXML(StringBuilder res, HighSymbol sym) {
|
||||
res.append("<mapsym>\n");
|
||||
sym.saveXML(res);
|
||||
for (SymbolEntry entry : sym.entryList) {
|
||||
entry.saveXml(res);
|
||||
}
|
||||
res.append("</mapsym>\n");
|
||||
}
|
||||
|
||||
public static void buildRangelistXML(StringBuilder res, Address pc) {
|
||||
res.append("<rangelist>");
|
||||
if (pc != null) {
|
||||
AddressSpace space = pc.getAddressSpace();
|
||||
if (space.isOverlaySpace()) {
|
||||
space = space.getPhysicalSpace();
|
||||
pc = space.getAddress(pc.getOffset());
|
||||
}
|
||||
res.append("<range");
|
||||
SpecXmlUtils.encodeStringAttribute(res, "space", space.getName());
|
||||
long off = pc.getUnsignedOffset();
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "first", off);
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "last", off);
|
||||
res.append("/>");
|
||||
}
|
||||
res.append("</rangelist>\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,18 +29,19 @@ import ghidra.xml.XmlElement;
|
|||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Local variables visible to a function. This includes mapped (on the stack) and
|
||||
* unmapped (only stored in a register).
|
||||
*
|
||||
* A container for local symbols within the decompiler's model of a function. It contains HighSymbol
|
||||
* objects for any symbol within the scope of the function, including parameters. The container is populated
|
||||
* either from the underlying Function object (when sending information to the decompiler) or read in from
|
||||
* an XML description (when receiving a function model from the decompiler). HighSymbols can be obtained
|
||||
* via Address using findLocal() or by id using getSymbol(). Parameters can be accessed specifically
|
||||
* using getParamSymbol().
|
||||
*/
|
||||
public class LocalSymbolMap {
|
||||
private HighFunction func; // Function to which these variables are local
|
||||
private String spacename;
|
||||
private HashMap<MappedVarKey, HighSymbol> addrMappedSymbols; // Hashed by addr and pcaddr
|
||||
private HashMap<Long, HighSymbol> symbolMap; // Hashed by unique key
|
||||
private MappedSymbol[] paramSymbols;
|
||||
private HighSymbol[] paramSymbols;
|
||||
private long uniqueSymbolId; // Next available symbol id
|
||||
|
||||
/**
|
||||
|
@ -52,10 +53,14 @@ public class LocalSymbolMap {
|
|||
spacename = spcname;
|
||||
addrMappedSymbols = new HashMap<MappedVarKey, HighSymbol>();
|
||||
symbolMap = new HashMap<Long, HighSymbol>();
|
||||
paramSymbols = new MappedSymbol[0];
|
||||
paramSymbols = new HighSymbol[0];
|
||||
uniqueSymbolId = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the decompiler's function model owning this container
|
||||
* @return the owning HighFunction
|
||||
*/
|
||||
public HighFunction getHighFunction() {
|
||||
return func;
|
||||
}
|
||||
|
@ -89,7 +94,6 @@ public class LocalSymbolMap {
|
|||
if (Undefined.isUndefined(dt)) {
|
||||
istypelock = false;
|
||||
}
|
||||
int sz = var.getLength();
|
||||
String name = var.getName();
|
||||
|
||||
VariableStorage storage = var.getVariableStorage();
|
||||
|
@ -100,8 +104,8 @@ public class LocalSymbolMap {
|
|||
}
|
||||
HighSymbol sym;
|
||||
if (storage.isHashStorage()) {
|
||||
sym = newDynamicSymbol(id, name, dt, sz, storage.getFirstVarnode().getOffset(),
|
||||
defAddr);
|
||||
sym =
|
||||
newDynamicSymbol(id, name, dt, storage.getFirstVarnode().getOffset(), defAddr);
|
||||
}
|
||||
else {
|
||||
sym = newMappedSymbol(id, name, dt, storage, defAddr, -1);
|
||||
|
@ -116,7 +120,7 @@ public class LocalSymbolMap {
|
|||
Address pcaddr = dbFunction.getEntryPoint();
|
||||
pcaddr = pcaddr.subtractWrap(1);
|
||||
|
||||
List<MappedSymbol> paramList = new ArrayList<MappedSymbol>();
|
||||
List<HighSymbol> paramList = new ArrayList<HighSymbol>();
|
||||
for (int i = 0; i < p.length; ++i) {
|
||||
Parameter var = p[i];
|
||||
if (!var.isValid()) {
|
||||
|
@ -128,8 +132,7 @@ public class LocalSymbolMap {
|
|||
VariableStorage storage = var.getVariableStorage();
|
||||
Address resAddr = storage.isStackStorage() ? null : pcaddr;
|
||||
long id = getNextId();
|
||||
MappedSymbol paramSymbol =
|
||||
newMappedSymbol(id, name, dt, storage, resAddr, i);
|
||||
HighSymbol paramSymbol = newMappedSymbol(id, name, dt, storage, resAddr, i);
|
||||
paramList.add(paramSymbol);
|
||||
boolean namelock = true;
|
||||
if (!includeDefaultNames) {
|
||||
|
@ -139,7 +142,7 @@ public class LocalSymbolMap {
|
|||
paramSymbol.setTypeLock(lock);
|
||||
}
|
||||
|
||||
paramSymbols = new MappedSymbol[paramList.size()];
|
||||
paramSymbols = new HighSymbol[paramList.size()];
|
||||
paramList.toArray(paramSymbols);
|
||||
Arrays.sort(paramSymbols, PARAM_SYMBOL_SLOT_COMPARATOR);
|
||||
|
||||
|
@ -163,21 +166,7 @@ public class LocalSymbolMap {
|
|||
* @throws PcodeXMLException for problems sub tags
|
||||
*/
|
||||
private HighSymbol parseSymbolXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement node = parser.start("mapsym");
|
||||
String typename = node.getAttribute("type");
|
||||
HighSymbol res = null;
|
||||
if (typename == null) {
|
||||
res = new MappedSymbol(func);
|
||||
}
|
||||
else if (typename.equals("dynamic")) {
|
||||
res = new DynamicSymbol(func);
|
||||
}
|
||||
else if (typename.equals("equate")) {
|
||||
res = new EquateSymbol(func);
|
||||
}
|
||||
|
||||
res.restoreXML(parser);
|
||||
parser.end(node);
|
||||
HighSymbol res = HighSymbol.restoreMapSymXML(parser, false, func);
|
||||
insertSymbol(res);
|
||||
return res;
|
||||
}
|
||||
|
@ -207,11 +196,11 @@ public class LocalSymbolMap {
|
|||
parser.end(el);
|
||||
}
|
||||
|
||||
private static final Comparator<MappedSymbol> PARAM_SYMBOL_SLOT_COMPARATOR =
|
||||
new Comparator<MappedSymbol>() {
|
||||
private static final Comparator<HighSymbol> PARAM_SYMBOL_SLOT_COMPARATOR =
|
||||
new Comparator<HighSymbol>() {
|
||||
@Override
|
||||
public int compare(MappedSymbol sym1, MappedSymbol sym2) {
|
||||
return sym1.getSlot() - sym2.getSlot();
|
||||
public int compare(HighSymbol sym1, HighSymbol sym2) {
|
||||
return sym1.getCategoryIndex() - sym2.getCategoryIndex();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -222,14 +211,14 @@ public class LocalSymbolMap {
|
|||
*/
|
||||
public void parseSymbolList(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement el = parser.start("symbollist");
|
||||
ArrayList<MappedSymbol> parms = new ArrayList<MappedSymbol>();
|
||||
ArrayList<HighSymbol> parms = new ArrayList<HighSymbol>();
|
||||
while (parser.peek().isStart()) {
|
||||
HighSymbol sym = parseSymbolXML(parser);
|
||||
if (sym.isParameter()) {
|
||||
parms.add((MappedSymbol) sym);
|
||||
parms.add(sym);
|
||||
}
|
||||
}
|
||||
paramSymbols = new MappedSymbol[parms.size()];
|
||||
paramSymbols = new HighSymbol[parms.size()];
|
||||
parms.toArray(paramSymbols);
|
||||
Arrays.sort(paramSymbols, PARAM_SYMBOL_SLOT_COMPARATOR);
|
||||
parser.end(el);
|
||||
|
@ -255,7 +244,7 @@ public class LocalSymbolMap {
|
|||
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
HighSymbol sym = iter.next();
|
||||
res.append(sym.buildXML());
|
||||
HighSymbol.buildMapSymXML(res, sym);
|
||||
}
|
||||
res.append("</symbollist>\n");
|
||||
res.append("</scope>\n");
|
||||
|
@ -306,14 +295,26 @@ public class LocalSymbolMap {
|
|||
return symbolMap.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of parameter symbols in this scope
|
||||
* @return the number of parameters
|
||||
*/
|
||||
public int getNumParams() {
|
||||
return paramSymbols.length;
|
||||
}
|
||||
|
||||
public MappedSymbol getParamSymbol(int i) {
|
||||
/**
|
||||
* @param i is the desired parameter position
|
||||
* @return the i-th parameter HighSymbol
|
||||
*/
|
||||
public HighSymbol getParamSymbol(int i) {
|
||||
return paramSymbols[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i is the desired parameter position
|
||||
* @return the i-th parameter variable
|
||||
*/
|
||||
public HighParam getParam(int i) {
|
||||
return (HighParam) paramSymbols[i].getHighVariable();
|
||||
}
|
||||
|
@ -328,22 +329,29 @@ public class LocalSymbolMap {
|
|||
return false;
|
||||
}
|
||||
|
||||
public MappedSymbol newMappedSymbol(long id, String nm, DataType dt, VariableStorage store,
|
||||
protected HighSymbol newMappedSymbol(long id, String nm, DataType dt, VariableStorage store,
|
||||
Address pcaddr, int slot) {
|
||||
if (id == 0) {
|
||||
id = getNextId();
|
||||
}
|
||||
MappedSymbol sym = new MappedSymbol(id, nm, dt, store, pcaddr, func, slot);
|
||||
HighSymbol sym = new HighSymbol(id, nm, dt, func);
|
||||
if (slot >= 0) {
|
||||
sym.setCategory(0, slot);
|
||||
}
|
||||
MappedEntry entry = new MappedEntry(sym, store, pcaddr);
|
||||
sym.addMapEntry(entry);
|
||||
insertSymbol(sym);
|
||||
return sym;
|
||||
}
|
||||
|
||||
public DynamicSymbol newDynamicSymbol(long id, String nm, DataType dt, int sz, long hash,
|
||||
protected HighSymbol newDynamicSymbol(long id, String nm, DataType dt, long hash,
|
||||
Address pcaddr) {
|
||||
if (id == 0) {
|
||||
id = getNextId();
|
||||
}
|
||||
DynamicSymbol sym = new DynamicSymbol(id, nm, dt, sz, func, pcaddr, hash);
|
||||
HighSymbol sym = new HighSymbol(id, nm, dt, func);
|
||||
DynamicEntry entry = new DynamicEntry(sym, pcaddr, hash);
|
||||
sym.addMapEntry(entry);
|
||||
insertSymbol(sym);
|
||||
return sym;
|
||||
}
|
||||
|
@ -356,17 +364,16 @@ public class LocalSymbolMap {
|
|||
uniqueSymbolId = val;
|
||||
}
|
||||
}
|
||||
if (sym instanceof MappedSymbol) {
|
||||
MappedSymbol mapSym = (MappedSymbol)sym;
|
||||
MappedVarKey key = new MappedVarKey(mapSym.getStorage(),mapSym.getPCAddress());
|
||||
if (sym.entryList[0] instanceof MappedEntry) {
|
||||
MappedVarKey key = new MappedVarKey(sym.getStorage(), sym.getPCAddress());
|
||||
addrMappedSymbols.put(key, sym);
|
||||
}
|
||||
symbolMap.put(uniqueId, sym);
|
||||
}
|
||||
|
||||
private void newEquateSymbol(long uniqueId, String nm, long val, long hash, Address addr,
|
||||
TreeMap<String, DynamicSymbol> constantSymbolMap) {
|
||||
DynamicSymbol eqSymbol = constantSymbolMap.get(nm);
|
||||
TreeMap<String, HighSymbol> constantSymbolMap) {
|
||||
HighSymbol eqSymbol = constantSymbolMap.get(nm);
|
||||
if (eqSymbol != null) {
|
||||
return; // New reference to same symbol
|
||||
}
|
||||
|
@ -390,7 +397,7 @@ public class LocalSymbolMap {
|
|||
* @param dbFunction is the function to pull equates for
|
||||
*/
|
||||
private void grabEquates(Function dbFunction) {
|
||||
TreeMap<String, DynamicSymbol> constantSymbolMap = null;
|
||||
TreeMap<String, HighSymbol> constantSymbolMap = null;
|
||||
// Find named constants via Equates
|
||||
Program program = dbFunction.getProgram();
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
|
@ -406,7 +413,7 @@ public class LocalSymbolMap {
|
|||
long hash[] = DynamicHash.calcConstantHash(instr, eq.getValue());
|
||||
for (long element : hash) {
|
||||
if (constantSymbolMap == null) {
|
||||
constantSymbolMap = new TreeMap<String, DynamicSymbol>();
|
||||
constantSymbolMap = new TreeMap<String, HighSymbol>();
|
||||
}
|
||||
newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr,
|
||||
constantSymbolMap);
|
||||
|
@ -429,7 +436,7 @@ public class LocalSymbolMap {
|
|||
|
||||
// Add constant dynamic symbols to map
|
||||
if (constantSymbolMap != null) {
|
||||
for (DynamicSymbol sym : constantSymbolMap.values()) {
|
||||
for (HighSymbol sym : constantSymbolMap.values()) {
|
||||
long id = getNextId();
|
||||
symbolMap.put(id, sym);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* A normal address based HighSymbol mapping with an associated Data object
|
||||
*/
|
||||
public class MappedDataEntry extends MappedEntry {
|
||||
private Data data; // Backing data object
|
||||
|
||||
/**
|
||||
* Constructor for use with restoreXML
|
||||
* @param sym is the owning HighSymbol
|
||||
*/
|
||||
public MappedDataEntry(HighSymbol sym) {
|
||||
super(sym);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct given a symbol, storage, and a backing Data object
|
||||
* @param sym the given symbol
|
||||
* @param store the given storage
|
||||
* @param d the backing Data object
|
||||
*/
|
||||
public MappedDataEntry(HighSymbol sym, VariableStorage store, Data d) {
|
||||
super(sym, store, null);
|
||||
data = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the backing Data object
|
||||
*/
|
||||
public Data getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
super.restoreXML(parser);
|
||||
data = symbol.getProgram().getListing().getDataAt(storage.getMinAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
if (data.isConstant()) {
|
||||
return true;
|
||||
}
|
||||
return super.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVolatile() {
|
||||
if (data.isVolatile()) {
|
||||
return true;
|
||||
}
|
||||
return super.isVolatile();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceIterator;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* A normal mapping of a HighSymbol to a particular Address, consuming a set number of bytes
|
||||
*/
|
||||
public class MappedEntry extends SymbolEntry {
|
||||
protected VariableStorage storage;
|
||||
|
||||
/**
|
||||
* For use with restoreXML
|
||||
* @param sym is the owning symbol
|
||||
*/
|
||||
public MappedEntry(HighSymbol sym) {
|
||||
super(sym);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct given a symbol, storage, and first-use Address
|
||||
* @param sym is the given symbol
|
||||
* @param store is the given storage
|
||||
* @param addr is the first-use Address (or null)
|
||||
*/
|
||||
public MappedEntry(HighSymbol sym, VariableStorage store, Address addr) {
|
||||
super(sym);
|
||||
storage = store;
|
||||
pcaddr = addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
HighFunction function = symbol.function;
|
||||
Program program = function.getFunction().getProgram();
|
||||
AddressFactory addrFactory = function.getAddressFactory();
|
||||
|
||||
XmlElement addrel = parser.start("addr");
|
||||
int sz = symbol.type.getLength();
|
||||
if (sz == 0) {
|
||||
throw new PcodeXMLException(
|
||||
"Invalid symbol 0-sized data-type: " + symbol.type.getName());
|
||||
}
|
||||
try {
|
||||
Address varAddr = Varnode.readXMLAddress(addrel, addrFactory);
|
||||
AddressSpace spc = varAddr.getAddressSpace();
|
||||
if ((spc == null) || (spc.getType() != AddressSpace.TYPE_VARIABLE)) {
|
||||
storage = new VariableStorage(program, varAddr, sz);
|
||||
}
|
||||
else {
|
||||
storage = function.readXMLVarnodePieces(addrel, varAddr);
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Invalid storage: " + e.getMessage());
|
||||
}
|
||||
parser.end(addrel);
|
||||
|
||||
parseRangeList(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveXml(StringBuilder buf) {
|
||||
int logicalsize = 0; // Assume datatype size and storage size are the same
|
||||
int typeLength = symbol.type.getLength();
|
||||
if (typeLength != storage.size() && typeLength > 0) {
|
||||
logicalsize = typeLength; // Force a logicalsize
|
||||
}
|
||||
String addrRes = Varnode.buildXMLAddress(storage.getVarnodes(), logicalsize);
|
||||
buf.append(addrRes);
|
||||
buildRangelistXML(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return storage.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
Address addr = storage.getMinAddress();
|
||||
if (addr == null) {
|
||||
return false;
|
||||
}
|
||||
boolean readonly = false;
|
||||
Program program = symbol.getProgram();
|
||||
MemoryBlock block = program.getMemory().getBlock(addr);
|
||||
if (block != null) {
|
||||
readonly = !block.isWrite();
|
||||
// if the block says read-only, check the refs to the variable
|
||||
// if the block says read-only, check the refs to the variable
|
||||
if (readonly) {
|
||||
ReferenceIterator refIter = program.getReferenceManager().getReferencesTo(addr);
|
||||
int count = 0;
|
||||
// boolean foundRead = false;
|
||||
while (refIter.hasNext() && count < 100) {
|
||||
Reference ref = refIter.next();
|
||||
if (ref.getReferenceType().isWrite()) {
|
||||
readonly = false;
|
||||
break;
|
||||
}
|
||||
if (ref.getReferenceType().isRead()) {
|
||||
// foundRead = true;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
// TODO: Don't do override if no read reference found
|
||||
//
|
||||
// if we only have indirect refs to it, don't assume readonly!
|
||||
//if (!foundRead && readonly && count > 1) {
|
||||
// readonly = false;
|
||||
//}
|
||||
// they must be reading it multiple times for some reason
|
||||
// if (readonly && count > 1) {
|
||||
// readonly = false;
|
||||
// }
|
||||
}
|
||||
}
|
||||
return readonly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVolatile() {
|
||||
Address addr = storage.getMinAddress();
|
||||
if (addr == null) {
|
||||
return false;
|
||||
}
|
||||
Program program = symbol.getProgram();
|
||||
if (program.getLanguage().isVolatile(addr)) {
|
||||
return true;
|
||||
}
|
||||
MemoryBlock block = program.getMemory().getBlock(addr);
|
||||
return (block != null && block.isVolatile());
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.ParamEntry;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
public class MappedSymbol extends HighSymbol {
|
||||
|
||||
private VariableStorage storage;
|
||||
private int slot; // parameter slot, -1 for non-parameter
|
||||
|
||||
public MappedSymbol(HighFunction func) { // For use with restoreXML
|
||||
super(func);
|
||||
}
|
||||
|
||||
public MappedSymbol(long uniqueId, String name, DataType dt, VariableStorage store,
|
||||
Address pcaddr,
|
||||
HighFunction func, int slot) {
|
||||
super(uniqueId, name, dt, store.size(), pcaddr, func);
|
||||
if (store.size() != dt.getLength()) {
|
||||
if (ParamEntry.getMetatype(dt) != ParamEntry.TYPE_FLOAT) {
|
||||
throw new IllegalArgumentException("Specified size does not match storage size");
|
||||
}
|
||||
}
|
||||
this.storage = store;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParameter() {
|
||||
return slot >= 0;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildXML() {
|
||||
if (storage.getMinAddress() == null) {
|
||||
return ""; // skip unassigned/bad variable
|
||||
}
|
||||
StringBuilder res = new StringBuilder();
|
||||
int cat = isParameter() ? 0 : -1;
|
||||
String sym = buildSymbolXML(function.getDataTypeManager(), getId(), name, type, size,
|
||||
isTypeLocked(), isNameLocked(), false, false, cat, slot);
|
||||
int logicalsize = 0; // Assume datatype size and storage size are the same
|
||||
if ((type != null) && (type.getLength() != storage.size()))
|
||||
{
|
||||
logicalsize = type.getLength(); // Force a logicalsize
|
||||
}
|
||||
String addrRes = Varnode.buildXMLAddress(storage.getVarnodes(), logicalsize);
|
||||
buildMapSymXML(res, addrRes, getPCAddress(), sym);
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
XmlElement symel = parser.start("symbol");
|
||||
restoreSymbolXML(symel);
|
||||
slot = -1;
|
||||
int cat = -1;
|
||||
if (symel.hasAttribute("cat")) {
|
||||
cat = SpecXmlUtils.decodeInt(symel.getAttribute("cat"));
|
||||
if (cat == 0) {
|
||||
slot = SpecXmlUtils.decodeInt(symel.getAttribute("index"));
|
||||
}
|
||||
}
|
||||
type = function.getDataTypeManager().readXMLDataType(parser);
|
||||
parser.end(symel);
|
||||
|
||||
if (slot >= 0 && name.startsWith("$$undef")) {
|
||||
// use default parameter name
|
||||
name = "param_" + Integer.toString(slot + 1);
|
||||
}
|
||||
|
||||
restoreEntryXML(parser);
|
||||
while (parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException {
|
||||
Program program = function.getFunction().getProgram();
|
||||
AddressFactory addrFactory = function.getAddressFactory();
|
||||
|
||||
XmlElement addrel = parser.start("addr");
|
||||
int sz = type.getLength();
|
||||
if (sz == 0) {
|
||||
throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName());
|
||||
}
|
||||
try {
|
||||
Address varAddr = Varnode.readXMLAddress(addrel, addrFactory);
|
||||
AddressSpace spc = varAddr.getAddressSpace();
|
||||
if ((spc == null) || (spc.getType() != AddressSpace.TYPE_VARIABLE)) {
|
||||
storage = new VariableStorage(program, varAddr, sz);
|
||||
}
|
||||
else {
|
||||
storage = function.readXMLVarnodePieces(addrel, varAddr);
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new PcodeXMLException("Invalid storage: " + e.getMessage());
|
||||
}
|
||||
size = storage.size();
|
||||
parser.end(addrel);
|
||||
|
||||
pcaddr = parseRangeList(parser);
|
||||
}
|
||||
|
||||
public static String buildSymbolXML(PcodeDataTypeManager dtmanage, long uniqueId, String nm,
|
||||
DataType dt, int length, boolean tl, boolean nl, boolean ro,
|
||||
boolean isVolatile, int cat, int slot) {
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append("<symbol");
|
||||
if ((uniqueId >> 56) == (ID_BASE >> 56)) {
|
||||
uniqueId = 0; // Don't send down internal ids
|
||||
}
|
||||
if (uniqueId != 0) {
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "id", uniqueId);
|
||||
}
|
||||
SpecXmlUtils.xmlEscapeAttribute(res, "name", nm);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "typelock", tl);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "namelock", nl);
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "readonly", ro);
|
||||
if (isVolatile) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "volatile", true);
|
||||
}
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "cat", cat);
|
||||
if (slot >= 0) {
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(res, "index", slot);
|
||||
}
|
||||
res.append(">\n");
|
||||
res.append(dtmanage.buildTypeRef(dt, length));
|
||||
res.append("</symbol>\n");
|
||||
return res.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.pcode;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
/**
|
||||
* A mapping from a HighSymbol object to the storage that holds the symbol's value.
|
||||
*
|
||||
*/
|
||||
public abstract class SymbolEntry {
|
||||
protected HighSymbol symbol; // The Symbol owning this entry
|
||||
protected Address pcaddr; // Start of code range where this SymbolEntry applies
|
||||
|
||||
/**
|
||||
* Constructor for use with restoreXML
|
||||
* @param sym is the symbol owning this entry
|
||||
*/
|
||||
public SymbolEntry(HighSymbol sym) {
|
||||
symbol = sym;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore this entry from the given XML stream. Typically more than one tag is consumed
|
||||
* @param parser is the given XML stream
|
||||
* @throws PcodeXMLException if the XML is invalid
|
||||
*/
|
||||
public abstract void restoreXML(XmlPullParser parser)
|
||||
throws PcodeXMLException;
|
||||
|
||||
/**
|
||||
* Save this entry as (a set of) XML tags to the given stream
|
||||
* @param buf is the given stream
|
||||
*/
|
||||
public abstract void saveXml(StringBuilder buf);
|
||||
|
||||
/**
|
||||
* Get the storage associated with this particular mapping of the Symbol
|
||||
* @return the storage object
|
||||
*/
|
||||
public abstract VariableStorage getStorage();
|
||||
|
||||
/**
|
||||
* Get the number of bytes consumed by the symbol when using this storage
|
||||
* @return the size of this entry
|
||||
*/
|
||||
public abstract int getSize();
|
||||
|
||||
/**
|
||||
* @return true if the mapped storage is read-only
|
||||
*/
|
||||
public abstract boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* @return true if the mapped storage is volatile
|
||||
*/
|
||||
public abstract boolean isVolatile();
|
||||
|
||||
/**
|
||||
* The storage used to hold this Symbol may be used for other purposes at different points in
|
||||
* the code. This returns the earliest address in the code where this storage is used for this symbol
|
||||
* @return the starting address where the Symbol uses this storage
|
||||
*/
|
||||
public Address getPCAdress() {
|
||||
return pcaddr;
|
||||
}
|
||||
|
||||
protected void parseRangeList(XmlPullParser parser) {
|
||||
XmlElement rangelistel = parser.start("rangelist");
|
||||
if (parser.peek().isStart()) {
|
||||
// we only use this to establish first-use
|
||||
XmlElement rangeel = parser.start("range");
|
||||
String spc = rangeel.getAttribute("space");
|
||||
long offset = SpecXmlUtils.decodeLong(rangeel.getAttribute("first"));
|
||||
pcaddr = symbol.function.getAddressFactory().getAddressSpace(spc).getAddress(offset);
|
||||
pcaddr =
|
||||
symbol.function.getFunction().getEntryPoint().getAddressSpace().getOverlayAddress(
|
||||
pcaddr);
|
||||
parser.end(rangeel);
|
||||
}
|
||||
|
||||
parser.end(rangelistel);
|
||||
}
|
||||
|
||||
protected void buildRangelistXML(StringBuilder res) {
|
||||
if (pcaddr == null || pcaddr.isExternalAddress()) {
|
||||
res.append("<rangelist/>");
|
||||
return;
|
||||
}
|
||||
res.append("<rangelist>");
|
||||
AddressSpace space = pcaddr.getAddressSpace();
|
||||
long off;
|
||||
if (space.isOverlaySpace()) {
|
||||
space = space.getPhysicalSpace();
|
||||
off = space.getAddress(pcaddr.getOffset()).getUnsignedOffset();
|
||||
}
|
||||
else {
|
||||
off = pcaddr.getUnsignedOffset();
|
||||
}
|
||||
res.append("<range");
|
||||
SpecXmlUtils.encodeStringAttribute(res, "space", space.getName());
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "first", off);
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(res, "last", off);
|
||||
res.append("/>");
|
||||
res.append("</rangelist>\n");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue