Refactoring based on HighSymbol

This commit is contained in:
caheckman 2019-12-06 12:12:58 -05:00
parent d552aa4b82
commit 76d0f12bd3
28 changed files with 631 additions and 470 deletions

View file

@ -393,7 +393,7 @@ void DynamicHash::uniqueHash(const Varnode *root,Funcdata *fd)
/// \param addr is the given address
/// \param h is the hash
/// \return the matching Varnode or NULL
Varnode *DynamicHash::findVarnode(Funcdata *fd,const Address &addr,uint8 h)
Varnode *DynamicHash::findVarnode(const Funcdata *fd,const Address &addr,uint8 h)
{
uint4 method = getMethodFromHash(h);
@ -423,7 +423,7 @@ Varnode *DynamicHash::findVarnode(Funcdata *fd,const Address &addr,uint8 h)
/// \param fd is the function holding the data-flow
/// \param addr is the given address
/// \param h is the given hash
void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,Funcdata *fd,const Address &addr,uint8 h)
void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h)
{
OpCode opc = getOpCodeFromHash(h);

View file

@ -79,11 +79,11 @@ public:
void clear(void); ///< Called for each additional hash (after the first)
void calcHash(const Varnode *root,uint4 method); ///< Calculate the hash for given Varnode and method
void uniqueHash(const Varnode *root,Funcdata *fd); ///< Select a unique hash for the given Varnode
Varnode *findVarnode(Funcdata *fd,const Address &addr,uint8 h);
Varnode *findVarnode(const Funcdata *fd,const Address &addr,uint8 h);
uint8 getHash(void) const { return hash; } ///< Get the (current) hash
const Address &getAddress(void) const { return addrresult; } ///< Get the (current) address
static void gatherFirstLevelVars(vector<Varnode *> &varlist,Funcdata *fd,const Address &addr,uint8 h);
static void gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h);
static int4 getSlotFromHash(uint8 h); ///< Retrieve the encoded slot from a hash
static uint4 getMethodFromHash(uint8 h); ///< Retrieve the encoded method from a hash
static OpCode getOpCodeFromHash(uint8 h); ///< Retrieve the encoded op-code from a hash

View file

@ -607,7 +607,6 @@ void Funcdata::saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,Varn
void Funcdata::saveXmlHigh(ostream &s) const
{
int4 j;
Varnode *vn;
HighVariable *high;
@ -620,32 +619,7 @@ void Funcdata::saveXmlHigh(ostream &s) const
high = vn->getHigh();
if (high->isMark()) continue;
high->setMark();
vn = high->getNameRepresentative(); // Get representative varnode
s << "<high ";
// a_v(s,"name",high->getName());
a_v_u(s,"repref",vn->getCreateIndex());
if (high->isSpacebase()||high->isImplied()) // This is a special variable
a_v(s,"class",string("other"));
else if (high->isPersist()&&high->isAddrTied()) // Global variable
a_v(s,"class",string("global"));
else if (high->isConstant())
a_v(s,"class",string("constant"));
else if (!high->isPersist())
a_v(s,"class",string("local"));
else
a_v(s,"class",string("other"));
if (high->isTypeLock())
a_v_b(s,"typelock",true);
if (high->getSymbol() != (Symbol *)0)
a_v_u(s,"symref",high->getSymbol()->getId());
s << '>';
high->getType()->saveXml(s);
for(j=0;j<high->numInstances();++j) {
s << "<addr ";
a_v_u(s,"ref",high->getInstance(j)->getCreateIndex());
s << "/>";
}
s << "</high>";
high->saveXml(s);
}
for(iter=beginLoc();iter!=endLoc();++iter) {
vn = *iter;

View file

@ -315,6 +315,14 @@ HighVariable *Funcdata::findHigh(const string &name) const
Symbol *sym = symList[0];
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
if (vn == (Varnode *)0 || vn->isAnnotation())
return (HighVariable *)0;
return vn->getHigh();
}
VarnodeLocSet::const_iterator iter,enditer;
HighVariable *high;

View file

@ -359,6 +359,46 @@ int4 HighVariable::instanceIndex(const Varnode *vn) const
return -1;
}
/// \param s is the output stream to write XML to
void HighVariable::saveXml(ostream &s) const
{
Varnode *vn = getNameRepresentative(); // Get representative varnode
s << "<high ";
// a_v(s,"name",high->getName());
a_v_u(s,"repref",vn->getCreateIndex());
if (isSpacebase()||isImplied()) // This is a special variable
a_v(s,"class",string("other"));
else if (isPersist()&&isAddrTied()) // Global variable
a_v(s,"class",string("global"));
else if (isConstant())
a_v(s,"class",string("constant"));
else if (!isPersist() && (symbol != (Symbol *)0)) {
if (symbol->getCategory() == 0)
a_v(s,"class",string("param"));
else
a_v(s,"class",string("local"));
}
else {
a_v(s,"class",string("other"));
}
if (isTypeLock())
a_v_b(s,"typelock",true);
if (symbol != (Symbol *)0) {
a_v_u(s,"symref",symbol->getId());
if (symboloffset >= 0)
a_v_i(s, "offset", symboloffset);
}
s << '>';
getType()->saveXml(s);
for(int4 j=0;j<inst.size();++j) {
s << "<addr ";
a_v_u(s,"ref",inst[j]->getCreateIndex());
s << "/>";
}
s << "</high>";
}
#ifdef MERGEMULTI_DEBUG
/// \brief Check that there are no internal Cover intersections within \b this
///

View file

@ -129,6 +129,7 @@ public:
bool isUnattached(void) const { return inst.empty(); } ///< Return \b true if \b this has no member Varnode
bool isTypeLock(void) const { updateType(); return ((flags & Varnode::typelock)!=0); } ///< Return \b true if \b this is \e typelocked
bool isNameLock(void) const { updateFlags(); return ((flags & Varnode::namelock)!=0); } ///< Return \b true if \b this is \e namelocked
void saveXml(ostream &s) const; ///< Save the variable to stream as an XML \<high\> tag
#ifdef MERGEMULTI_DEBUG
void verifyCover(void) const;
#endif

View file

@ -208,9 +208,10 @@ public class DecompilerParameterIdCmd extends BackgroundCommand {
boolean commitReturn = true;
if (!commitVoidReturn) {
DataType returnType = hfunc.getFunctionPrototype().getReturnType();
if (returnType instanceof VoidDataType)
if (returnType instanceof VoidDataType) {
commitReturn = false;
}
}
if (commitReturn) {
HighFunctionDBUtil.commitReturnToDatabase(hfunc, SourceType.ANALYSIS);
}
@ -274,7 +275,7 @@ public class DecompilerParameterIdCmd extends BackgroundCommand {
if (sym.getName().equals("in_FS_OFFSET")) {
continue;
}
if (!sym.getHighVariable().getStorage().isRegisterStorage()) {
if (!sym.getStorage().isRegisterStorage()) {
continue;
}

View file

@ -64,9 +64,5 @@ public class ClangVariableDecl extends ClangTokenGroup {
}
typevar = sym.getHighVariable();
datatype = sym.getDataType();
if (typevar == null) {
Msg.error(this, "High variable not found: " + sym.getName());
return;
}
}
}

View file

@ -130,7 +130,7 @@ public class FillOutStructureCmd extends BackgroundCommand {
}
}
if (var == null) {
if (var == null || var.getSymbol() == null || var.getOffset() >= 0) {
return false;
}
@ -232,7 +232,8 @@ public class FillOutStructureCmd extends BackgroundCommand {
private void commitVariable(HighVariable var, DataType newDt, boolean isThisParam) {
if (!isThisParam) {
try {
HighFunctionDBUtil.updateDBVariable(var, null, newDt, SourceType.USER_DEFINED);
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), null, newDt,
SourceType.USER_DEFINED);
}
catch (DuplicateNameException e) {
throw new AssertException("Unexpected exception", e);

View file

@ -151,6 +151,9 @@ public class RenameVariableAction extends AbstractDecompilerAction {
return false;
}
}
if (variable.getSymbol() == null) {
return false;
}
if (variable instanceof HighLocal) {
getPopupMenuData().setMenuItemName("Rename Variable");
return true;
@ -159,11 +162,6 @@ public class RenameVariableAction extends AbstractDecompilerAction {
getPopupMenuData().setMenuItemName("Rename Global");
return true;
}
//TODO: Constant equates do not work properly with decompiler
// else if (variable instanceof HighConstant) {
// getPopupMenuData().setMenuItemName("Rename Constant");
// return true;
// }
return false;
}
@ -179,20 +177,18 @@ public class RenameVariableAction extends AbstractDecompilerAction {
variable = forgeHighVariable(addr, controller);
}
}
//TODO: Constant equates do not work properly with decompiler
// if (variable instanceof HighConstant) {
// nameTask =
// new RenameConstantTask(tool, tokenAtCursor.getText(), (HighConstant) variable,
// controller.getProgram());
// }
// else
if (variable instanceof HighLocal) {
nameTask =
new RenameVariableTask(tool, variable.getName(), controller.getHighFunction(),
variable, tokenAtCursor.getVarnode(), SourceType.USER_DEFINED);
new RenameVariableTask(tool, variable.getSymbol().getName(),
controller.getHighFunction(), variable, tokenAtCursor.getVarnode(),
SourceType.USER_DEFINED);
}
else if (variable instanceof HighGlobal) {
Address addr = variable.getRepresentative().getAddress();
Address addr = null;
HighSymbol sym = variable.getSymbol();
if (sym instanceof HighCodeSymbol) {
addr = ((HighCodeSymbol) sym).getStorage().getMinAddress();
}
if (addr == null || !addr.isMemoryAddress()) {
Msg.showError(this, tool.getToolFrame(), "Rename Failed",
"Memory storage not found for global variable");

View file

@ -55,7 +55,7 @@ public class RenameVariableTask extends RenameTask {
HighFunctionDBUtil.commitReturnToDatabase(hfunction, signatureSrcType);
}
}
HighFunctionDBUtil.updateDBVariable(var, newName, null, srctype);
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), newName, null, srctype);
}
@Override
@ -80,6 +80,10 @@ public class RenameVariableTask extends RenameTask {
return false;
}
}
if (var.getSymbol() == null) {
errorMsg = "Rename Failed: No symbol";
return false;
}
return true;
}

View file

@ -129,13 +129,6 @@ public class RetypeVariableAction extends AbstractDecompilerAction {
boolean commitRequired = checkFullCommit(var, hfunction);
if (commitRequired) {
// int resp = OptionDialog.showOptionDialog(tool.getToolFrame(),
// "Parameter Commit Required",
// "Retyping a parameter requires all other parameters to be committed!\nContinue with retype?",
// "Continue");
// if (resp != OptionDialog.OPTION_ONE) {
// return;
// }
exactSpot = null; // Don't try to split out if commit is required
}
@ -176,7 +169,7 @@ public class RetypeVariableAction extends AbstractDecompilerAction {
Msg.showError(this, null, "Parameter Commit Failed", e.getMessage());
}
}
HighFunctionDBUtil.updateDBVariable(var, null, dt, SourceType.USER_DEFINED);
HighFunctionDBUtil.updateDBVariable(var.getSymbol(), null, dt, SourceType.USER_DEFINED);
successfulMod = true;
}
catch (DuplicateNameException e) {
@ -298,7 +291,7 @@ public class RetypeVariableAction extends AbstractDecompilerAction {
}
for (int i = 0; i < numParams; i++) {
HighParam param = localSymbolMap.getParam(i);
MappedSymbol param = localSymbolMap.getParamSymbol(i);
if (param.getSlot() != i) {
return true;
}
@ -350,11 +343,10 @@ public class RetypeVariableAction extends AbstractDecompilerAction {
return false;
}
}
if (variable instanceof HighConstant) {
// getPopupMenuData().setMenuItemName("Retype Constant");
// return true;
if (variable.getSymbol() == null) {
return false;
}
else if (variable instanceof HighLocal) {
if (variable instanceof HighLocal) {
getPopupMenuData().setMenuItemName("Retype Variable");
return true;
}
@ -412,7 +404,7 @@ public class RetypeVariableAction extends AbstractDecompilerAction {
return;
}
variable = RenameVariableAction.forgeHighVariable(addr, controller);
if (variable == null) {
if (variable == null || variable.getSymbol() == null || variable.getOffset() >= 0) {
return;
}
}

View file

@ -16,7 +16,12 @@
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;
@ -26,53 +31,25 @@ import ghidra.xml.XmlPullParser;
*
*/
public class DynamicSymbol extends HighSymbol {
public static class Entry {
public final Address pcaddr;
public final long hash;
public final int format;
protected long hash; // Hash encoding the specific Varnode
public Entry(Address addr,long h,int f) {
pcaddr = addr;
hash = h;
format = f;
}
}
private Entry[] refs;
public DynamicSymbol() { // For use with restoreXML
refs = new Entry[0];
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, int format) {
Address addr, long hash) {
super(uniqueId, nm, tp, size, addr, func);
refs = new Entry[1];
refs[0] = new Entry(addr,hash,format);
this.hash = hash;
}
public long getHash() {
return refs[0].hash;
}
public void addReference(Address addr,long hash,int format) {
Entry[] newrefs = new Entry[refs.length + 1];
for(int i=0;i<refs.length;++i) {
newrefs[i] = refs[i];
}
newrefs[refs.length] = new Entry(addr,hash,format);
refs = newrefs;
if (refs.length == 1)
{
pcaddr = addr; // Store first address as official pcaddr for symbol
}
return hash;
}
protected void buildHashXML(StringBuilder buf) {
for (Entry ref : refs) {
buf.append("<hash val=\"0x").append(Long.toHexString(ref.hash)).append("\"/>");
buildRangelistXML(buf, ref.pcaddr);
}
buf.append("<hash val=\"0x").append(Long.toHexString(hash)).append("\"/>");
buildRangelistXML(buf, pcaddr);
}
@Override
@ -88,25 +65,39 @@ public class DynamicSymbol extends HighSymbol {
}
@Override
public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException {
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement symel = parser.start("symbol");
restoreSymbolXML(symel, func);
type = func.getDataTypeManager().readXMLDataType(parser);
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()) {
long hash = 0;
int format = 0;
parser.discardSubTree();
}
}
@Override
protected void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement addrel = parser.start("hash");
hash = SpecXmlUtils.decodeLong(addrel.getAttribute("val"));
format = SpecXmlUtils.decodeInt(symel.getAttribute("format"));
parser.end(addrel);
Address addr = parseRangeList(parser);
addReference(addr,hash,format);
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);
}
}
@ -129,4 +120,23 @@ public class DynamicSymbol extends HighSymbol {
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);
}
}
}

View file

@ -33,19 +33,20 @@ public class EquateSymbol extends DynamicSymbol {
private long value; // Value of the equate
private int convert; // Non-zero if this is a conversion equate
public EquateSymbol() {
public EquateSymbol(HighFunction func) {
super(func);
}
public EquateSymbol(long uniqueId, String nm, long val, HighFunction func, Address addr,
long hash, int format) {
super(uniqueId, nm, DataType.DEFAULT, 1, func, addr, hash, format);
long hash) {
super(uniqueId, nm, DataType.DEFAULT, 1, func, addr, hash);
value = val;
convert = FORMAT_DEFAULT;
}
public EquateSymbol(long uniqueId, int conv, long val, HighFunction func, Address addr,
long hash, int format) {
super(uniqueId, "", DataType.DEFAULT, 1, func, addr, hash, format);
long hash) {
super(uniqueId, "", DataType.DEFAULT, 1, func, addr, hash);
value = val;
convert = conv;
}
@ -53,9 +54,9 @@ public class EquateSymbol extends DynamicSymbol {
public long getValue() { return value; }
@Override
public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException {
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement symel = parser.start("equatesymbol");
restoreSymbolXML(symel, func);
restoreSymbolXML(symel);
type = DataType.DEFAULT;
size = 1;
convert = FORMAT_DEFAULT;
@ -84,15 +85,9 @@ public class EquateSymbol extends DynamicSymbol {
if (size == 0) {
throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName());
}
restoreEntryXML(parser);
while(parser.peek().isStart()) {
long hash = 0;
int format = 0;
XmlElement addrel = parser.start("hash");
hash = SpecXmlUtils.decodeLong(addrel.getAttribute("val"));
format = SpecXmlUtils.decodeInt(addrel.getAttribute("format"));
parser.end(addrel);
Address addr = parseRangeList(parser);
addReference(addr,hash,format);
parser.discardSubTree();
}
}

View file

@ -210,9 +210,9 @@ public class FunctionPrototype {
* @return the i'th HighParam to this function prototype or null
* if this prototype is not backed by a LocalSymbolMap
*/
public HighParam getParam(int i) {
public HighSymbol getParam(int i) {
if (localsyms != null) {
return localsyms.getParam(i);
return localsyms.getParamSymbol(i);
}
return null;
}

View file

@ -99,6 +99,10 @@ public class GlobalSymbolMap {
* @return the new HighSymbol or null
*/
public HighCodeSymbol newSymbol(long id, Address addr, DataType dataType, int sz) {
if (dataType == null) {
dataType = DataType.DEFAULT;
sz = 1;
}
HighCodeSymbol symbol = new HighCodeSymbol(id, addr, dataType, sz, func);
insertSymbol(symbol, addr);
return symbol;

View file

@ -17,9 +17,13 @@ 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.Data;
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;
/**
@ -29,6 +33,7 @@ public class HighCodeSymbol extends HighSymbol {
private CodeSymbol symbol;
private Data data;
private VariableStorage storage;
public HighCodeSymbol(CodeSymbol sym, DataType dataType, int sz, HighFunction func) {
super(sym.getID(), sym.getName(), dataType, sz, null, func);
@ -43,6 +48,11 @@ public class HighCodeSymbol extends HighSymbol {
data = func.getFunction().getProgram().getListing().getDataAt(addr);
}
@Override
public boolean isGlobal() {
return true;
}
public CodeSymbol getCodeSymbol() {
return symbol;
}
@ -57,6 +67,26 @@ public class HighCodeSymbol extends HighSymbol {
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
@ -64,8 +94,37 @@ public class HighCodeSymbol extends HighSymbol {
}
@Override
public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException {
// TODO Auto-generated method stub
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();
}
}
@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);
}
}
}

View file

@ -18,7 +18,11 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.AbstractIntegerDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.scalar.Scalar;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
*
@ -30,6 +34,14 @@ public class HighConstant extends HighVariable {
private DynamicSymbol symbol;
private Address pcaddr; // null or Address of PcodeOp which defines the representative
/**
* Constructor for use with restoreXml
* @param func is the HighFunction this constant belongs to
*/
public HighConstant(HighFunction func) {
super(func);
}
/**
* Construct a constant NOT associated with a symbol
* @param name name of variable
@ -43,19 +55,6 @@ public class HighConstant extends HighVariable {
pcaddr = pc;
}
/**
* Construct constant associated with a dynamic symbol
* @param name name of variable
* @param type data type of variable
* @param vn constant varnode
* @param pc code unit address where constant is used
* @param sym associated dynamic symbol
*/
public HighConstant(String name, DataType type, Varnode vn, Address pc, DynamicSymbol sym) {
this(name, type, vn, pc, sym.getHighFunction());
symbol = sym;
}
@Override
public HighSymbol getSymbol() {
return symbol;
@ -88,4 +87,36 @@ public class HighConstant extends HighVariable {
return new Scalar(getSize() * 8, value, signed);
}
@Override
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("high");
long symref = SpecXmlUtils.decodeLong(el.getAttribute("symref"));
restoreInstances(parser, el);
pcaddr = function.getPCAddress(represent);
if (symref != 0) {
HighSymbol sym = function.getLocalSymbolMap().getSymbol(symref);
if (sym == null) {
sym = function.getGlobalSymbolMap().getSymbol(symref);
}
if (sym instanceof DynamicSymbol) {
symbol = (DynamicSymbol) sym;
name = sym.getName();
sym.setHighVariable(this);
}
else if (sym == null) {
GlobalSymbolMap globalMap = function.getGlobalSymbolMap();
Program program = function.getFunction().getProgram();
sym = globalMap.populateSymbol(symref, null, -1);
if (sym == null) {
PcodeOp op = ((VarnodeAST) represent).getLoneDescend();
Address addr = HighFunctionDBUtil.getSpacebaseReferenceAddress(program, op);
if (addr != null) {
sym = globalMap.newSymbol(symref, addr, DataType.DEFAULT, 1);
}
}
}
}
parser.end(el);
}
}

View file

@ -24,7 +24,6 @@ import org.xml.sax.*;
import ghidra.program.database.symbol.CodeSymbol;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*;
@ -209,41 +208,29 @@ public class HighFunction extends PcodeSyntaxTree {
}
private void readHighXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("high");
XmlElement el = parser.peek();
String classstring = el.getAttribute("class");
long symref = SpecXmlUtils.decodeLong(el.getAttribute("symref"));
int repref = SpecXmlUtils.decodeInt(el.getAttribute("repref"));
Varnode rep = getRef(repref);
if (rep == null) {
throw new PcodeXMLException("Undefined varnode reference");
HighVariable var;
switch (classstring.charAt(0)) {
case 'o':
var = new HighOther(this);
break;
case 'g':
var = new HighGlobal(this);
break;
case 'l':
var = new HighLocal(this);
break;
case 'p':
var = new HighParam(this);
break;
case 'c':
var = new HighConstant(this);
break;
default:
throw new PcodeXMLException("Unknown HighVariable class string: " + classstring);
}
DataType type = null;
ArrayList<Varnode> vnlist = new ArrayList<Varnode>();
int sz = -1;
if (parser.peek().isStart()) {
type = getDataTypeManager().readXMLDataType(parser);
}
if (type == null) {
throw new PcodeXMLException("Missing <type> for HighVariable");
}
// TODO: I'm not sure the decompiler's type size is preserved
// by the conversion to a GHIDRA type
sz = type.getLength();
while (parser.peek().isStart()) {
Varnode vn = Varnode.readXML(parser, this);
vnlist.add(vn);
}
Varnode[] vnarray = new Varnode[vnlist.size()];
vnlist.toArray(vnarray);
// VARDO: does rep varnode size differ from type length ?
newHigh(symref, type, sz, vnarray, rep, classstring);
parser.end(el);
var.restoreXml(parser);
}
private void readHighlistXML(XmlPullParser parser) throws PcodeXMLException {
@ -329,97 +316,7 @@ public class HighFunction extends PcodeSyntaxTree {
parser.end(el);
}
private HighVariable newHigh(long symref, DataType tp, int sz, Varnode[] inst, Varnode rep,
String classstring) throws PcodeXMLException {
HighVariable var = null;
if (classstring.equals("local")) {
HighSymbol sym = null;
if (symref != 0) {
sym = localSymbols.getSymbol(symref);
}
if (sym != null) {
var = sym.getHighVariable();
}
if (var == null) {
if (sym instanceof DynamicSymbol) {
// establish HighLocal for DynamicSymbol
var = new HighLocal(tp, rep, inst, sym.getPCAddress(), sym);
sym.setHighVariable(var);
}
else {
// The variable may be a partial, in which case
// we treat it as special
var = new HighOther(tp, rep, inst, getPCAddress(rep), this);
}
}
}
else if (classstring.equals("constant")) {
HighSymbol sym = null;
if (symref != 0) {
sym = localSymbols.getSymbol(symref);
if (sym == null) {
sym = globalSymbols.getSymbol(symref);
}
if (sym instanceof DynamicSymbol) {
var = sym.getHighVariable();
var = new HighConstant(sym.getName(), tp, rep, getPCAddress(rep),
(DynamicSymbol) sym);
sym.setHighVariable(var);
}
else if (sym == null) {
sym = globalSymbols.populateSymbol(symref, null, -1);
if (sym == null) {
PcodeOp op = ((VarnodeAST) rep).getLoneDescend();
Address addr =
HighFunctionDBUtil.getSpacebaseReferenceAddress(func.getProgram(), op);
if (addr != null) {
sym = globalSymbols.newSymbol(symref, addr, DataType.DEFAULT, 1);
}
}
}
}
if (var == null) {
var = new HighConstant(null, tp, rep, getPCAddress(rep), this);
}
}
else if (classstring.equals("global")) {
HighCodeSymbol sym = null;
if (symref != 0) {
sym = globalSymbols.getSymbol(symref);
}
if (sym == null) {
sym = globalSymbols.populateSymbol(symref, tp, sz);
if (sym == null) {
sym = globalSymbols.newSymbol(symref, rep.getAddress(), tp, sz);
if (sym == null) {
throw new PcodeXMLException(
"Bad global storage: " + rep.getAddress().toString());
}
}
}
var = new HighGlobal(sym, rep, inst);
sym.setHighVariable(var);
}
else if (classstring.equals("other")) {
// TODO: How do these compare with local ??
var = new HighOther(tp, rep, inst, getPCAddress(rep), this);
}
else {
throw new PcodeXMLException("Bad class string: " + classstring);
}
if (rep.getSize() == var.getSize()) {
var.attachInstances(inst, rep);
}
else { // Make sure varnodes are linked to HighVariable even if not formal instances, why do we do this???
for (Varnode element : inst) {
((VarnodeAST) element).setHigh(var);
}
}
var.setHighOnInstances();
return var;
}
private Address getPCAddress(Varnode rep) {
protected Address getPCAddress(Varnode rep) {
Address pcaddr = null;
if (!rep.isAddrTied()) {
pcaddr = rep.getPCAddress();

View file

@ -97,7 +97,7 @@ public class HighFunctionDBUtil {
List<Parameter> params = new ArrayList<Parameter>();
int paramCnt = symbolMap.getNumParams();
for (int i = 0; i < paramCnt; ++i) {
HighParam param = symbolMap.getParam(i);
HighSymbol param = symbolMap.getParamSymbol(i);
String name = param.getName();
DataType dataType;
if (useDataTypes) {
@ -201,23 +201,20 @@ public class HighFunctionDBUtil {
Iterator<HighSymbol> iter = highFunction.getLocalSymbolMap().getSymbols();
while (iter.hasNext()) {
HighSymbol sym = iter.next();
HighVariable high = sym.getHighVariable();
if ((high instanceof HighParam) || !(high instanceof HighLocal)) {
if (sym.isParameter() || sym.isGlobal()) {
continue;
}
HighLocal local = (HighLocal) high;
String name = local.getName();
String name = sym.getName();
try {
Variable var = clearConflictingLocalVariables(local);
Variable var = clearConflictingLocalVariables(sym);
if (var == null) {
var = createLocalVariable(local, null, null, source);
var = createLocalVariable(sym, null, null, source);
if (name != null) {
var.setName(name, source);
}
}
else {
var.setDataType(local.getDataType(), local.getStorage(), false, source);
var.setDataType(sym.getDataType(), sym.getStorage(), false, source);
var.setName(name, source);
}
}
@ -229,28 +226,29 @@ public class HighFunctionDBUtil {
}
/**
* Create a local DB variable with a default name
* @param local
* @param dt data type or null to use local data type defined by local high variable
* @param storage storage or null to use storage defined by local high variable
* @param source
* @return
* @throws InvalidInputException
* @throws DuplicateNameException
* Create a local DB variable with a default name. Storage and data-type for the variable
* can be provided explicitly, or they can be taken from a decompiler symbol.
* @param symbol is the decompiler symbol
* @param dt is the given data-type or null (to use the symbol's data-type)
* @param storage is the given storage or null (to use the symbol's storage)
* @param source is the desired SourceType of the new variable
* @return the new local variable
* @throws InvalidInputException is a valid variable can't be created
*/
private static Variable createLocalVariable(HighLocal local, DataType dt,
private static Variable createLocalVariable(HighSymbol symbol, DataType dt,
VariableStorage storage, SourceType source) throws InvalidInputException {
Function function = local.getHighFunction().getFunction();
Function function = symbol.getHighFunction().getFunction();
Program program = function.getProgram();
if (storage == null || storage.isUniqueStorage()) {
storage = local.getStorage();
storage = symbol.getStorage();
}
if (dt == null) {
dt = local.getDataType();
dt = symbol.getDataType();
}
Variable var = new LocalVariableImpl(null, local.getFirstUseOffset(), dt, storage, program);
Variable var =
new LocalVariableImpl(null, symbol.getFirstUseOffset(), dt, storage, program);
try {
var = function.addLocalVariable(var, SourceType.ANALYSIS);
var = function.addLocalVariable(var, source);
}
catch (DuplicateNameException e) {
throw new AssertException("Unexpected exception with default name", e);
@ -258,7 +256,7 @@ public class HighFunctionDBUtil {
Register reg = var.getRegister();
if (reg != null) {
program.getReferenceManager().addRegisterReference(local.getPCAddress(), -1, reg,
program.getReferenceManager().addRegisterReference(symbol.getPCAddress(), -1, reg,
RefType.WRITE, source);
}
@ -282,13 +280,15 @@ public class HighFunctionDBUtil {
long hash = var.getFirstStorageVarnode().getOffset();
Iterator<HighSymbol> symbols = highFunction.getLocalSymbolMap().getSymbols();
while (symbols.hasNext()) {
HighVariable high = symbols.next().getHighVariable();
if (!(high instanceof HighLocal)) {
HighSymbol symbol = symbols.next();
if (!(symbol instanceof DynamicSymbol)) {
continue;
}
// Note: assumes there is only one hash method used for unique locals
if (((HighLocal) high).buildDynamicHash() == hash) {
return true;
if (((DynamicSymbol) symbol).getHash() == hash) {
if (symbol.getHighVariable() != null) {
return true; // Hash successfully attached to a variable
}
}
}
return false;
@ -301,25 +301,22 @@ public class HighFunctionDBUtil {
* exists within the function at the same first-use-offset.
* @return existing variable with identical storage and first-use offset or null
*/
private static Variable clearConflictingLocalVariables(HighLocal local) {
private static Variable clearConflictingLocalVariables(HighSymbol local) {
if (local instanceof HighParam) {
if (local instanceof MappedSymbol) {
if (((MappedSymbol) local).getSlot() >= 0) { // Don't clear parameters
throw new IllegalArgumentException();
}
}
HighFunction highFunction = local.getHighFunction();
Function func = highFunction.getFunction();
HighSymbol symbol = local.getSymbol();
VariableStorage storage = local.getStorage();
int firstUseOffset = local.getFirstUseOffset();
if (symbol instanceof DynamicSymbol || storage.isUniqueStorage()) {
if (local instanceof DynamicSymbol) {
if (!(symbol instanceof DynamicSymbol)) {
return null;
}
DynamicSymbol dynamicSym = (DynamicSymbol) symbol;
DynamicSymbol dynamicSym = (DynamicSymbol) local;
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()) {
@ -352,15 +349,15 @@ public class HighFunctionDBUtil {
}
/**
* Get database parameter which corresponds to HighParam, where we anticipate that
* the parameter will be modified to match the HighParam. The entire prototype is
* Get database parameter which corresponds to the given symbol, where we anticipate that
* the parameter will be modified to match the symbol. The entire prototype is
* committed to the database if necessary. An exception is thrown if a modifiable parameter
* can't be found/created.
* @param param is the HighParam describing the desired function parameter
* @param param is the HighSymbol describing the desired function parameter
* @return the matching parameter that can be modified
* @throws InvalidInputException if the desired parameter cannot be modified
*/
private static Parameter getDatabaseParameter(HighParam param) throws InvalidInputException {
private static Parameter getDatabaseParameter(MappedSymbol param) throws InvalidInputException {
HighFunction highFunction = param.getHighFunction();
Function function = highFunction.getFunction();
@ -392,10 +389,9 @@ public class HighFunctionDBUtil {
}
/**
* Retype the specified variable in the database. All parameters may be flushed
* Rename and/or retype the specified variable in the database. All parameters may be flushed
* to the database if typed parameter inconsistency detected.
* Only variable types HighParam, HighLocal and HighGlobal are supported.
* @param variable
* @param variable is the symbol being updated
* @param name new variable name or null to use retain current variable name
* @param dataType newly assigned data type or null to retain current variable datatype.
* Only a fixed-length data type may be specified. If size varies from the current size,
@ -407,7 +403,7 @@ public class HighFunctionDBUtil {
* variable/label within the function's namespace
* @throws UnsupportedOperationException if unsupported variable type is specified
*/
public static void updateDBVariable(HighVariable variable, String name, DataType dataType,
public static void updateDBVariable(HighSymbol variable, String name, DataType dataType,
SourceType source) throws InvalidInputException, DuplicateNameException {
HighFunction highFunction = variable.getHighFunction();
@ -427,10 +423,11 @@ public class HighFunctionDBUtil {
boolean isRename = name != null;
if (variable instanceof HighParam) {
HighParam param = (HighParam) variable;
Parameter dbParam = getDatabaseParameter(param);
VariableStorage storage = param.getStorage();
if (variable.isParameter()) {
MappedSymbol mappedSymbol = (MappedSymbol) variable;
Parameter dbParam = getDatabaseParameter(mappedSymbol);
VariableStorage storage = mappedSymbol.getStorage();
if (dataType != null) {
if (resized && function.hasCustomVariableStorage()) {
VariableStorage newStorage =
@ -445,12 +442,20 @@ public class HighFunctionDBUtil {
dbParam.setName(name, source);
}
}
else if (variable instanceof HighLocal) {
HighLocal local = (HighLocal) variable;
VariableStorage storage = local.getStorage();
else if (!variable.isGlobal()) {
Variable var;
VariableStorage storage;
HighVariable tmpHigh = variable.getHighVariable();
if (tmpHigh != null && tmpHigh.getRepresentative().isUnique()) {
storage =
DynamicSymbol.buildDynamicStorage(tmpHigh.getRepresentative(), highFunction);
var = null;
}
else {
storage = variable.getStorage();
var = clearConflictingLocalVariables(variable);
}
boolean usesHashStorage = storage.isHashStorage();
Variable var = clearConflictingLocalVariables(local);
if (dataType == null) {
if (var != null) {
dataType = var.getDataType(); // Use preexisting datatype if it fits in desired storage
@ -463,21 +468,21 @@ public class HighFunctionDBUtil {
if (resized) {
if (usesHashStorage) {
throw new InvalidInputException(
"Variable size (" + local.getSize() + ") may not be changed: type '" +
"Variable size (" + variable.getSize() + ") may not be changed: type '" +
dataType.getName() + "' length is " + dataType.getLength());
}
storage = VariableUtilities.resizeStorage(storage, dataType, true, function);
}
if (var == null) {
var = createLocalVariable(local, dataType, storage, source);
var = createLocalVariable(variable, dataType, storage, source);
}
else {
// fixup reused variable
var.setDataType(dataType, storage, true, source);
if (name == null) {
name = local.getName(); // must update name if not specified
}
if (name == null) {
name = variable.getName(); // must update name if not specified
}
try {
// must set/correct name
@ -499,7 +504,7 @@ public class HighFunctionDBUtil {
}
}
}
else if (variable instanceof HighGlobal) {
else { // A global symbol
VariableStorage storage = variable.getStorage();
if (!storage.isMemoryStorage()) {
@ -507,21 +512,20 @@ public class HighFunctionDBUtil {
"Database supports global memory variables only");
}
HighGlobal global = (HighGlobal) variable;
if (name == null) {
name = global.getName();
name = variable.getName();
if (name != null && SymbolUtilities.isDynamicSymbolPattern(name, true)) {
name = null;
}
}
if (dataType != null) {
setGlobalDataType(global, dataType);
setGlobalDataType(variable, dataType);
}
if (name != null) {
try {
setGlobalName((HighGlobal) variable, variable.getName(), source);
setGlobalName(variable, variable.getName(), source);
}
catch (DuplicateNameException e) {
if (isRename) {
@ -530,13 +534,9 @@ public class HighFunctionDBUtil {
}
}
}
else {
throw new UnsupportedOperationException(
"Database support not provided for " + variable.getClass().getSimpleName());
}
}
private static void setGlobalName(HighGlobal global, String name, SourceType source)
private static void setGlobalName(HighSymbol global, String name, SourceType source)
throws DuplicateNameException, InvalidInputException {
Program program = global.getHighFunction().getFunction().getProgram();
VariableStorage storage = global.getStorage();
@ -554,7 +554,7 @@ public class HighFunctionDBUtil {
}
}
private static Data setGlobalDataType(HighGlobal global, DataType dt)
private static Data setGlobalDataType(HighSymbol global, DataType dt)
throws InvalidInputException {
Program program = global.getHighFunction().getFunction().getProgram();
VariableStorage storage = global.getStorage();

View file

@ -15,6 +15,12 @@
*/
package ghidra.program.model.pcode;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
*
*
@ -24,6 +30,14 @@ public class HighGlobal extends HighVariable {
private HighCodeSymbol symbol;
/**
* Constructor for use with restoreXml
* @param high is the HighFunction this global is accessed by
*/
public HighGlobal(HighFunction high) {
super(high);
}
public HighGlobal(HighCodeSymbol sym, Varnode vn, Varnode[] inst) {
super(sym.getName(), sym.getDataType(), vn, inst, sym.getHighFunction());
symbol = sym;
@ -33,4 +47,50 @@ public class HighGlobal extends HighVariable {
public HighSymbol getSymbol() {
return symbol;
}
@Override
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("high");
long symref = SpecXmlUtils.decodeLong(el.getAttribute("symref"));
String attrString = el.getAttribute("offset");
offset = -1;
if (attrString != null) {
offset = SpecXmlUtils.decodeInt(attrString);
}
restoreInstances(parser, el);
if (symref == 0) {
throw new PcodeXMLException("Missing symref attribute in <high> tag");
}
symbol = function.getGlobalSymbolMap().getSymbol(symref);
if (symbol == null) { // If we don't already have symbol, synthesize it
DataType symbolType;
int symbolSize;
if (offset < 0) { // Variable type and size matches symbol
symbolType = type;
symbolSize = getSize();
}
else {
symbolType = null;
symbolSize = -1;
}
GlobalSymbolMap globalMap = function.getGlobalSymbolMap();
symbol = globalMap.populateSymbol(symref, symbolType, symbolSize);
if (symbol == null) {
Address addr = represent.getAddress();
if (offset > 0) {
addr = addr.subtract(offset);
}
symbol = globalMap.newSymbol(symref, addr, symbolType, symbolSize);
if (symbol == null) {
throw new PcodeXMLException("Bad global storage: " + addr.toString());
}
}
}
if (offset < 0) {
name = symbol.getName();
}
symbol.setHighVariable(this);
parser.end(el);
}
}

View file

@ -16,18 +16,23 @@
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;
public class HighLocal extends HighVariable {
private Address pcaddr; // null or Address of PcodeOp which defines the representative
private HighSymbol symbol;
private long hash = 0; // 60-bit hash value, 0 indicates not-yet-computed or not-applicable
/**
* Constructor for use with restoreXml
* @param high is the HighFunction containing this local variable
*/
public HighLocal(HighFunction high) {
super(high);
}
public HighLocal(DataType type, Varnode vn, Varnode[] inst, Address pc, HighSymbol sym) {
super(sym.getName(), type, vn, inst, sym.getHighFunction());
@ -47,51 +52,30 @@ public class HighLocal extends HighVariable {
return pcaddr;
}
protected int getFirstUseOffset() {
if (pcaddr == null || getRepresentative().getAddress().isStackAddress()) {
return 0;
}
return (int) pcaddr.subtract(getHighFunction().getFunction().getEntryPoint());
}
@Override
public VariableStorage getStorage() {
Program program = getHighFunction().getFunction().getProgram();
Varnode represent = getRepresentative();
if (symbol instanceof DynamicSymbol || represent.isUnique()) {
long ourHash = buildDynamicHash();
try {
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(ourHash),
represent.getSize());
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("high");
long symref = SpecXmlUtils.decodeLong(el.getAttribute("symref"));
offset = -1;
String attrString = el.getAttribute("offset");
if (attrString != null) {
offset = SpecXmlUtils.decodeInt(attrString);
}
catch (InvalidInputException e) {
throw new AssertException("Unexpected exception", e);
restoreInstances(parser, el);
symbol = function.getLocalSymbolMap().getSymbol(symref);
if (symbol == null) {
throw new PcodeXMLException("HighLocal is missing symbol");
}
if (offset < 0) {
name = symbol.getName();
}
if (symbol instanceof MappedSymbol) {
return ((MappedSymbol) symbol).getStorage();
else {
name = "UNNAMED";
}
return super.getStorage();
}
public long buildDynamicHash() {
if (hash != 0) {
return hash;
}
if (symbol instanceof DynamicSymbol) {
hash = ((DynamicSymbol) symbol).getHash();
pcaddr = symbol.getPCAddress();
}
else if (getRepresentative().isUnique()) {
DynamicHash dynamicHash = new DynamicHash(getRepresentative(), getHighFunction());
hash = dynamicHash.getHash();
pcaddr = dynamicHash.getAddress();
}
return hash;
symbol.setHighVariable(this);
parser.end(el);
}
}

View file

@ -17,6 +17,9 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
*
@ -26,8 +29,16 @@ import ghidra.program.model.data.DataType;
*/
public class HighOther extends HighVariable {
private DynamicSymbol symbol;
private Address pcaddr; // Address of PcodeOp which defines the representative
private HighSymbol symbol; // Possibly a dynamic global symbol
/**
* Constructor for use with restoreXml
* @param high is the HighFunction containing the variable
*/
public HighOther(HighFunction high) {
super(high);
}
/**
* Construct a unique high NOT associated with a symbol
@ -42,14 +53,6 @@ public class HighOther extends HighVariable {
pcaddr = pc;
}
/**
* @return associated dynamic symbol or null
*/
@Override
public DynamicSymbol getSymbol() {
return symbol;
}
/**
* @return instruction address the variable comes into scope within the function
*/
@ -57,4 +60,31 @@ public class HighOther extends HighVariable {
return pcaddr;
}
@Override
public HighSymbol getSymbol() {
return symbol;
}
@Override
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
XmlElement el = parser.start("high");
long symref = SpecXmlUtils.decodeLong(el.getAttribute("symref"));
offset = -1;
String attrString = el.getAttribute("offset");
restoreInstances(parser, el);
name = "UNNAMED";
pcaddr = function.getPCAddress(represent);
if (symref != 0) {
offset = -1;
if (attrString != null) {
offset = SpecXmlUtils.decodeInt(attrString);
}
symbol = function.getLocalSymbolMap().getSymbol(symref);
if (symbol != null && offset < 0) {
name = symbol.getName();
}
}
parser.end(el);
}
}

View file

@ -17,6 +17,7 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.xml.XmlPullParser;
/**
*
@ -26,6 +27,14 @@ import ghidra.program.model.data.DataType;
public class HighParam extends HighLocal {
private int slot;
/**
* Constructor for use with restoreXml
* @param high is the HighFunction containing this parameter
*/
public HighParam(HighFunction high) {
super(high);
}
/**
* @param tp data type of variable
* @param rep is the representative input Varnode
@ -46,8 +55,13 @@ public class HighParam extends HighLocal {
}
@Override
protected int getFirstUseOffset() {
return 0;
public void restoreXml(XmlPullParser parser) throws PcodeXMLException {
super.restoreXml(parser);
slot = 0;
HighSymbol sym = getSymbol();
if (sym instanceof MappedSymbol) {
slot = ((MappedSymbol) sym).getSlot();
}
}
}

View file

@ -18,6 +18,7 @@ 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.VariableStorage;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
@ -37,7 +38,8 @@ public abstract class HighSymbol {
private HighVariable highVariable;
public HighSymbol() { // For use with restoreXML
public HighSymbol(HighFunction func) { // For use with restoreXML
function = func;
}
public HighSymbol(long uniqueId, String nm, DataType tp, int sz, Address pc,
@ -80,6 +82,13 @@ public abstract class HighSymbol {
return pcaddr;
}
protected int getFirstUseOffset() {
if (pcaddr == null) {
return 0;
}
return (int) pcaddr.subtract(getHighFunction().getFunction().getEntryPoint());
}
public HighFunction getHighFunction() {
return function;
}
@ -108,13 +117,32 @@ public abstract class HighSymbol {
return readonly;
}
/**
* Is this symbol a parameter for a function
* @return true if this is a parameter
*/
public boolean isParameter() {
return false;
}
/**
* Is this symbol in the global scope or some other global namespace
* @return true if this is global
*/
public boolean isGlobal() {
return false;
}
public abstract VariableStorage getStorage();
public abstract String buildXML();
public abstract void restoreXML(XmlPullParser parser, HighFunction func)
public abstract void restoreXML(XmlPullParser parser)
throws PcodeXMLException;
protected void restoreSymbolXML(XmlElement symel, HighFunction func) throws PcodeXMLException {
function = func;
protected abstract void restoreEntryXML(XmlPullParser parser) throws PcodeXMLException;
protected void restoreSymbolXML(XmlElement symel) throws PcodeXMLException {
id = SpecXmlUtils.decodeLong(symel.getAttribute("id"));
if (id == 0) {
throw new PcodeXMLException("missing unique symbol id");

View file

@ -15,11 +15,12 @@
*/
package ghidra.program.model.pcode;
import java.util.ArrayList;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableStorage;
import ghidra.util.Msg;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
/**
*
@ -29,11 +30,20 @@ import ghidra.util.exception.InvalidInputException;
*/
public abstract class HighVariable {
private String name;
private DataType type;
private Varnode represent; // A representative varnode
private Varnode[] instances; // Instances of this high-level variable
private HighFunction function; // associated function
protected String name;
protected DataType type;
protected Varnode represent; // A representative varnode
protected Varnode[] instances; // Instances of this high-level variable
protected int offset = -1; // Offset (in bytes) into containing symbol (-1 indicates whole match)
protected HighFunction function; // associated function
/**
* Constructor for use with restoreXml
* @param func is the HighFunction this variable belongs to
*/
protected HighVariable(HighFunction func) {
function = func;
}
protected HighVariable(String nm, DataType tp, Varnode rep, Varnode[] inst, HighFunction func) {
name = nm;
@ -104,6 +114,15 @@ public abstract class HighVariable {
*/
public abstract HighSymbol getSymbol();
/**
* Get the offset of this variable into its containing HighSymbol. If the value
* is -1, this indicates that this HighVariable matches the size and storage of the symbol.
* @return the offset
*/
public int getOffset() {
return offset;
}
/**
* Attach an instance or additional location the variable can be found in.
*
@ -121,16 +140,46 @@ public abstract class HighVariable {
}
}
public VariableStorage getStorage() {
Program program = getHighFunction().getFunction().getProgram();
try {
if (represent != null && (represent.isAddress() || represent.isRegister())) {
return new VariableStorage(program, represent);
/**
* Restore the data-type and the Varnode instances of this HighVariable.
* The "representative" Varnode is also populated.
* @param parser is the XML stream
* @param el is the root <high> tag
* @throws PcodeXMLException if the XML is not valid
*/
protected void restoreInstances(XmlPullParser parser, XmlElement el)
throws PcodeXMLException {
int repref = SpecXmlUtils.decodeInt(el.getAttribute("repref"));
Varnode rep = function.getRef(repref);
if (rep == null) {
throw new PcodeXMLException("Undefined varnode reference");
}
type = null;
ArrayList<Varnode> vnlist = new ArrayList<Varnode>();
if (parser.peek().isStart()) {
type = function.getDataTypeManager().readXMLDataType(parser);
}
catch (InvalidInputException e) {
Msg.error(this, "Failed to define variable storage: " + this, e);
if (type == null) {
throw new PcodeXMLException("Missing <type> for HighVariable");
}
return VariableStorage.UNASSIGNED_STORAGE;
while (parser.peek().isStart()) {
Varnode vn = Varnode.readXML(parser, function);
vnlist.add(vn);
}
Varnode[] vnarray = new Varnode[vnlist.size()];
vnlist.toArray(vnarray);
attachInstances(vnarray, rep);
setHighOnInstances();
}
/**
* Restore this HighVariable from a <high> XML tag
* @param parser is the XML stream
* @throws PcodeXMLException if the XML is not valid
*/
public abstract void restoreXml(XmlPullParser parser) throws PcodeXMLException;
}

View file

@ -101,7 +101,7 @@ public class LocalSymbolMap {
HighSymbol sym;
if (storage.isHashStorage()) {
sym = newDynamicSymbol(id, name, dt, sz, storage.getFirstVarnode().getOffset(),
defAddr, 0);
defAddr);
}
else {
sym = newMappedSymbol(id, name, dt, storage, defAddr, -1);
@ -167,16 +167,16 @@ public class LocalSymbolMap {
String typename = node.getAttribute("type");
HighSymbol res = null;
if (typename == null) {
res = new MappedSymbol();
res = new MappedSymbol(func);
}
else if (typename.equals("dynamic")) {
res = new DynamicSymbol();
res = new DynamicSymbol(func);
}
else if (typename.equals("equate")) {
res = new EquateSymbol();
res = new EquateSymbol(func);
}
res.restoreXML(parser, func);
res.restoreXML(parser);
parser.end(node);
insertSymbol(res);
return res;
@ -225,7 +225,7 @@ public class LocalSymbolMap {
ArrayList<MappedSymbol> parms = new ArrayList<MappedSymbol>();
while (parser.peek().isStart()) {
HighSymbol sym = parseSymbolXML(parser);
if (sym instanceof MappedSymbol && ((MappedSymbol) sym).isParameter()) {
if (sym.isParameter()) {
parms.add((MappedSymbol) sym);
}
}
@ -339,11 +339,11 @@ public class LocalSymbolMap {
}
public DynamicSymbol newDynamicSymbol(long id, String nm, DataType dt, int sz, long hash,
Address pcaddr, int format) {
Address pcaddr) {
if (id == 0) {
id = getNextId();
}
DynamicSymbol sym = new DynamicSymbol(id, nm, dt, sz, func, pcaddr, hash, format);
DynamicSymbol sym = new DynamicSymbol(id, nm, dt, sz, func, pcaddr, hash);
insertSymbol(sym);
return sym;
}
@ -365,23 +365,21 @@ public class LocalSymbolMap {
}
private void newEquateSymbol(long uniqueId, String nm, long val, long hash, Address addr,
int format,
TreeMap<String, DynamicSymbol> constantSymbolMap) {
DynamicSymbol eqSymbol = constantSymbolMap.get(nm);
if (eqSymbol != null) {
eqSymbol.addReference(addr, hash, format); // New reference to same symbol
return;
return; // New reference to same symbol
}
if (uniqueId == 0) {
uniqueId = getNextId();
}
int conv = EquateSymbol.convertName(nm, val);
if (conv < 0) {
eqSymbol = new EquateSymbol(uniqueId, nm, val, func, addr, hash, format);
eqSymbol = new EquateSymbol(uniqueId, nm, val, func, addr, hash);
eqSymbol.setNameLock(true);
}
else {
eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash, format);
eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash);
}
//Do NOT setTypeLock
constantSymbolMap.put(nm, eqSymbol);
@ -410,7 +408,7 @@ public class LocalSymbolMap {
if (constantSymbolMap == null) {
constantSymbolMap = new TreeMap<String, DynamicSymbol>();
}
newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr, 0,
newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr,
constantSymbolMap);
}
}

View file

@ -30,7 +30,8 @@ public class MappedSymbol extends HighSymbol {
private VariableStorage storage;
private int slot; // parameter slot, -1 for non-parameter
public MappedSymbol() { // For use with restoreXML
public MappedSymbol(HighFunction func) { // For use with restoreXML
super(func);
}
public MappedSymbol(long uniqueId, String name, DataType dt, VariableStorage store,
@ -44,22 +45,14 @@ public class MappedSymbol extends HighSymbol {
}
this.storage = store;
this.slot = slot;
Varnode rep = function.createFromStorage(null, storage, dt.getLength());
HighVariable var;
if (slot < 0) {
var = new HighLocal(type, rep, null, pcaddr, this);
}
else {
var = new HighParam(type, rep, pcaddr, slot, this);
}
setHighVariable(var);
var.setHighOnInstances();
}
@Override
public VariableStorage getStorage() {
return storage;
}
@Override
public boolean isParameter() {
return slot >= 0;
}
@ -88,9 +81,9 @@ public class MappedSymbol extends HighSymbol {
}
@Override
public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException {
public void restoreXML(XmlPullParser parser) throws PcodeXMLException {
XmlElement symel = parser.start("symbol");
restoreSymbolXML(symel, func);
restoreSymbolXML(symel);
slot = -1;
int cat = -1;
if (symel.hasAttribute("cat")) {
@ -99,7 +92,7 @@ public class MappedSymbol extends HighSymbol {
slot = SpecXmlUtils.decodeInt(symel.getAttribute("index"));
}
}
type = func.getDataTypeManager().readXMLDataType(parser);
type = function.getDataTypeManager().readXMLDataType(parser);
parser.end(symel);
if (slot >= 0 && name.startsWith("$$undef")) {
@ -107,10 +100,17 @@ public class MappedSymbol extends HighSymbol {
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();
Address addr = null;
XmlElement addrel = parser.start("addr");
int sz = type.getLength();
if (sz == 0) {
@ -123,8 +123,7 @@ public class MappedSymbol extends HighSymbol {
storage = new VariableStorage(program, varAddr, sz);
}
else {
addr = varAddr;
storage = func.readXMLVarnodePieces(addrel, varAddr);
storage = function.readXMLVarnodePieces(addrel, varAddr);
}
}
catch (InvalidInputException e) {
@ -134,16 +133,6 @@ public class MappedSymbol extends HighSymbol {
parser.end(addrel);
pcaddr = parseRangeList(parser);
Varnode rep = function.createFromStorage(addr, storage, sz);
HighVariable var;
if (slot < 0) {
var = new HighLocal(type, rep, null, pcaddr, this);
}
else {
var = new HighParam(type, rep, pcaddr, slot, this);
}
setHighVariable(var);
var.setHighOnInstances();
}
public static String buildSymbolXML(PcodeDataTypeManager dtmanage, long uniqueId, String nm,