diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index 09d9e60de0..1fc34f407b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -17,6 +17,8 @@ #include "funcdata.hh" #include +uint8 Symbol::ID_BASE = 0x4000000000000000L; + /// This SymbolEntry is unintegrated. An address or hash must be provided /// either directly or via restoreXml(). /// \param sym is the Symbol \b this will be a map for @@ -338,50 +340,79 @@ void Symbol::restoreXmlHeader(const Element *el) { name.clear(); category = -1; + symbolId = 0; for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i)=="name") - name = el->getAttributeValue(i); - else if (el->getAttributeName(i)=="cat") { - istringstream s(el->getAttributeValue("cat")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> category; - } - else if (el->getAttributeName(i)=="namelock") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::namelock; - } - else if (el->getAttributeName(i)=="typelock") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::typelock; - } - else if (el->getAttributeName(i)=="readonly") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::readonly; - } - else if (el->getAttributeName(i)=="volatile") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::volatil; - } - else if (el->getAttributeName(i)=="indirectstorage") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::indirectstorage; - } - else if (el->getAttributeName(i)=="hiddenretparm") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::hiddenretparm; - } - else if (el->getAttributeName(i)=="format") { - const string &formString( el->getAttributeValue(i)); - if (formString == "hex") - dispflags |= Symbol::force_hex; - else if (formString == "dec") - dispflags |= Symbol::force_dec; - else if (formString == "char") - dispflags |= Symbol::force_char; - else if (formString == "oct") - dispflags |= Symbol::force_oct; - else if (formString == "bin") - dispflags |= Symbol::force_bin; + const string &attName(el->getAttributeName(i)); + switch (attName[0]) { + case 'c': + if (attName == "cat") { + istringstream s(el->getAttributeValue(i)); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> category; + } + break; + case 'f': + if (attName == "format") { + const string &formString(el->getAttributeValue(i)); + if (formString == "hex") + dispflags |= Symbol::force_hex; + else if (formString == "dec") + dispflags |= Symbol::force_dec; + else if (formString == "char") + dispflags |= Symbol::force_char; + else if (formString == "oct") + dispflags |= Symbol::force_oct; + else if (formString == "bin") + dispflags |= Symbol::force_bin; + } + break; + case 'h': + if (attName == "hiddenretparm") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::hiddenretparm; + } + break; + case 'i': + if (attName == "id") { + istringstream s(el->getAttributeValue(i)); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> symbolId; + if ((symbolId >> 56) == (ID_BASE >> 56)) + symbolId = 0; // Don't keep old internal id's + } + else if (attName == "indirectstorage") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::indirectstorage; + } + break; + case 'n': + if (attName == "name") + name = el->getAttributeValue(i); + else if (attName == "namelock") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::namelock; + } + break; + case 'r': + if (attName == "readonly") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::readonly; + } + break; + case 't': + if (attName == "typelock") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::typelock; + } + break; + case 'v': + if (attName == "volatile") { + if (xml_readbool(el->getAttributeValue(i))) + flags |= Varnode::volatil; + } + break; + default: + break; } } if (category == 0) { @@ -716,7 +747,7 @@ void Scope::attachScope(Scope *child) { child->parent = this; - pair value(ScopeKey(child->name,child->dedupId),child); + pair value(ScopeKey(child->name,child->uniqueId),child); pair res; if (child->name.size()==0) throw LowlevelError("Non-global scope has empty name"); @@ -1574,6 +1605,10 @@ bool Scope::isReadOnly(const Address &addr,int4 size,const Address &usepoint) co void ScopeInternal::addSymbolInternal(Symbol *sym) { + if (sym->symbolId == 0) { + sym->symbolId = Symbol::ID_BASE + (((uint8)uniqueId & 0xffff) << 40) + nextUniqueId; + nextUniqueId += 1; + } try { if (sym->name.size() == 0) sym->name = buildUndefinedName(); @@ -1695,6 +1730,7 @@ list::iterator ScopeInternal::endDynamic(void) ScopeInternal::ScopeInternal(const string &nm,Architecture *g) : Scope(nm,g) { + nextUniqueId = 0; int4 numspaces = g->numSpaces(); for(int4 i=0;iname.size() != 0) throw LowlevelError("Global scope does not have empty name"); + newscope->assignId(0); globalscope = newscope; return; } + newscope->assignId(nextScopeId); + nextScopeId += 1; parent->attachScope(newscope); } @@ -2635,7 +2675,7 @@ void Database::deleteScope(Scope *scope) delete scope; } else { - ScopeKey key(scope->name,scope->dedupId); + ScopeKey key(scope->name,scope->uniqueId); ScopeMap::iterator iter = scope->parent->children.find(key); if (iter == scope->parent->children.end()) throw LowlevelError("Could not remove parent reference to: "+scope->name); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index 9f08675cdb..9686a36013 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -157,17 +157,19 @@ class Symbol { protected: Scope *scope; ///< The scope that owns this symbol string name; ///< The local name of the symbol - uint4 nameDedup; ///< id to distinguish symbols with the same name Datatype *type; ///< The symbol's data-type + uint4 nameDedup; ///< id to distinguish symbols with the same name uint4 flags; ///< Varnode-like properties of the symbol // only typelock,namelock,readonly,externref // addrtied, persist inherited from scope uint4 dispflags; ///< Flags affecting the display of this symbol int2 category; ///< Special category (-1==none 0=parameter 1=equate) uint2 catindex; ///< Index within category + uint8 symbolId; ///< Unique id, 0=unassigned vector::iterator> mapentry; ///< List of storage locations labeled with \b this Symbol virtual ~Symbol(void) {} ///< Destructor void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol + void setSymbolId(uint8 val) { symbolId = val; } ///< Assign a unique id to the symbol void checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on public: /// \brief Possible display (dispflag) properties for a Symbol @@ -181,14 +183,14 @@ public: }; /// \brief Construct given a name and data-type Symbol(Scope *sc,const string &nm,Datatype *ct) - { scope=sc; name=nm; nameDedup=0; type=ct; flags=0; dispflags=0; category=-1; } + { scope=sc; name=nm; nameDedup=0; type=ct; flags=0; dispflags=0; category=-1; symbolId = 0; } /// \brief Construct for use with restoreXml() - Symbol(Scope *sc) { scope=sc; nameDedup=0; flags=0; dispflags=0; category=-1; } + Symbol(Scope *sc) { scope=sc; nameDedup=0; flags=0; dispflags=0; category=-1; symbolId = 0; } const string &getName(void) const { return name; } ///< Get the local name of the symbol Datatype *getType(void) const { return type; } ///< Get the data-type - uint4 getId(void) const { return (uint4)(uintp)this; } ///< Get a unique id for the symbol + uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol uint4 getFlags(void) const { return flags; } ///< Get the boolean properties of the Symbol uint4 getDisplayFormat(void) const { return (dispflags & 7); } ///< Get the format to display the Symbol in int2 getCategory(void) const { return category; } ///< Get the Symbol category @@ -210,6 +212,7 @@ public: virtual void saveXml(ostream &s) const; ///< Save \b this Symbol to an XML stream virtual void restoreXml(const Element *el); ///< Restore \b this Symbol from an XML stream virtual int4 getBytesConsumed(void) const; ///< Get number of bytes consumed within the address->symbol map + static uint8 ID_BASE; ///< Base of internal ID's }; /// Force a specific display format for constant symbols @@ -405,12 +408,13 @@ class Scope { ScopeMap children; ///< Sorted list of child scopes void attachScope(Scope *child); ///< Attach a new child Scope to \b this void detachScope(ScopeMap::iterator iter); ///< Detach a child Scope from \b this + void assignId(uint4 val) { uniqueId = val; } ///< Let the database assign a unique id to \b this scope protected: Architecture *glb; ///< Architecture of \b this scope string name; ///< Name of \b this scope Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for - uint4 dedupId; ///< Id to dedup scopes with same name (when allowed) + uint4 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids static const Scope *stackAddr(const Scope *scope1, const Scope *scope2, const Address &addr, @@ -488,7 +492,7 @@ public: #endif /// \brief Construct an empty scope, given a name and Architecture Scope(const string &nm,Architecture *g) { - name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; dedupId = 0; + name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; uniqueId = 0; #ifdef OPACTION_DEBUG debugon = false; #endif @@ -714,6 +718,7 @@ protected: vector maptable; ///< Rangemaps of SymbolEntry, one map for each address space vector > category; ///< References to Symbol objects organized by category list dynamicentry; ///< Dynamic symbol entries + uint8 nextUniqueId; ///< Next available symbol id public: ScopeInternal(const string &nm,Architecture *g); ///< Construct the Scope virtual void clear(void); @@ -817,12 +822,13 @@ class Database { Scope *globalscope; ///< A quick reference to the \e global Scope ScopeResolve resolvemap; ///< The Address to \e namespace map partmap flagbase; ///< Map of global properties + uint4 nextScopeId; ///< Id for next attached scope (0 reserved for global scope) void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope void clearResolveRecursive(Scope *scope); ///< Clear the \e ownership ranges of a given Scope and its children void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map static void parseParentTag(const Element *el,string &name,vector &parnames); public: - Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue() = 0; } ///< Constructor + Database(Architecture *g) { glb=g; globalscope=(Scope *)0; flagbase.defaultValue()=0; nextScopeId=1; } ///< Constructor ~Database(void); ///< Destructor Architecture *getArch(void) const { return glb; } ///< Get the Architecture associate with \b this void attachScope(Scope *newscope,Scope *parent); ///< Register a new Scope diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc index d1ba9e89ce..edbda7b274 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc @@ -305,7 +305,6 @@ ScopeLocal::ScopeLocal(AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInter rangeLocked = false; stackGrowsNegative = true; restrictScope(fd); - dedupId = fd->getAddress().getOffset(); // Allow multiple scopes with same name } /// Turn any symbols that are \e name \e locked but not \e type \e locked into name recommendations diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableDecl.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableDecl.java index cc009cca5c..aceb3d414a 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableDecl.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableDecl.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +56,7 @@ public class ClangVariableDecl extends ClangTokenGroup { public void restoreFromXML(XmlPullParser parser,PcodeFactory pfactory) { XmlElement node = parser.peek(); super.restoreFromXML(parser,pfactory); - int symref = SpecXmlUtils.decodeInt(node.getAttribute(ClangXML.SYMREF)); + long symref = SpecXmlUtils.decodeLong(node.getAttribute(ClangXML.SYMREF)); HighSymbol sym = pfactory.getSymbol(symref); if (sym == null) { Msg.error(this, "Invalid symbol reference: " + symref); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index 5696212774..612f7224ca 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -831,12 +831,20 @@ public class DecompileCallback { if ((data.getDataType() == DataType.DEFAULT) && (sym == null) && !isVolatile && !readonly) { return null; } - - String name = sym != null ? sym.getName() : SymbolUtilities.getDynamicName(program, addr); + long uniqueId; + String name; + if (sym != null) { + name = sym.getName(); + uniqueId = sym.getID(); + } + else { + name = SymbolUtilities.getDynamicName(program, addr); + uniqueId = 0; + } int sz = data.getLength(); - String symstring = MappedSymbol.buildSymbolXML(dtmanage, name, data.getDataType(), sz, true, - true, readonly, isVolatile, -1, -1); + String symstring = MappedSymbol.buildSymbolXML(dtmanage, uniqueId, name, data.getDataType(), + sz, true, true, readonly, isVolatile, -1, -1); if (debug != null) { debug.getType(data.getDataType()); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicSymbol.java index d577f52e3c..e50dca0592 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicSymbol.java @@ -44,8 +44,9 @@ public class DynamicSymbol extends HighSymbol { refs = new Entry[0]; } - public DynamicSymbol(String nm,DataType tp,int size,HighFunction func,Address addr,long hash,int format) { - super(nm,tp,size,addr,func); + public DynamicSymbol(long uniqueId, String nm, DataType tp, int size, HighFunction func, + Address addr, long hash, int format) { + super(uniqueId, nm, tp, size, addr, func); refs = new Entry[1]; refs[0] = new Entry(addr,hash,format); } @@ -56,18 +57,21 @@ public class DynamicSymbol extends HighSymbol { public void addReference(Address addr,long hash,int format) { Entry[] newrefs = new Entry[refs.length + 1]; - for(int i=0;i"); - buildRangelistXML(buf, refs[i].pcaddr); + for (Entry ref : refs) { + buf.append(""); + buildRangelistXML(buf, ref.pcaddr); } } @@ -84,15 +88,16 @@ public class DynamicSymbol extends HighSymbol { } @Override - public int restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException { + public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException { XmlElement symel = parser.start("symbol"); - int symbolId = restoreSymbolXML(symel, func); + restoreSymbolXML(symel, func); type = func.getDataTypeManager().readXMLDataType(parser); size = type.getLength(); parser.end(symel); - if (size == 0) + if (size == 0) { throw new PcodeXMLException("Invalid symbol 0-sized data-type: " + type.getName()); + } while(parser.peek().isStart()) { long hash = 0; int format = 0; @@ -103,7 +108,6 @@ public class DynamicSymbol extends HighSymbol { Address addr = parseRangeList(parser); addReference(addr,hash,format); } - return symbolId; } public static String buildSymbolXML(PcodeDataTypeManager dtmanage, String nm, @@ -117,8 +121,9 @@ public class DynamicSymbol extends HighSymbol { SpecXmlUtils.encodeBooleanAttribute(res, "typelock", tl); SpecXmlUtils.encodeBooleanAttribute(res, "namelock", nl); SpecXmlUtils.encodeBooleanAttribute(res, "readonly", ro); - if (isVolatile) + if (isVolatile) { SpecXmlUtils.encodeBooleanAttribute(res, "volatile", true); + } res.append(">\n"); res.append(dtmanage.buildTypeRef(dt, length)); res.append("\n"); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/EquateSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/EquateSymbol.java index 12f89b276b..5599483906 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/EquateSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/EquateSymbol.java @@ -36,14 +36,16 @@ public class EquateSymbol extends DynamicSymbol { public EquateSymbol() { } - public EquateSymbol(String nm,long val,HighFunction func,Address addr,long hash,int format) { - super(nm, DataType.DEFAULT, 1, func, addr, hash, format); + 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); value = val; convert = FORMAT_DEFAULT; } - public EquateSymbol(int conv,long val,HighFunction func,Address addr,long hash,int format) { - super("", DataType.DEFAULT, 1, func, addr, hash, format); + 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); value = val; convert = conv; } @@ -51,9 +53,9 @@ public class EquateSymbol extends DynamicSymbol { public long getValue() { return value; } @Override - public int restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException { + public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException { XmlElement symel = parser.start("equatesymbol"); - int symbolId = restoreSymbolXML(symel, func); + restoreSymbolXML(symel, func); type = DataType.DEFAULT; size = 1; convert = FORMAT_DEFAULT; @@ -92,7 +94,6 @@ public class EquateSymbol extends DynamicSymbol { Address addr = parseRangeList(parser); addReference(addr,hash,format); } - return symbolId; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunction.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunction.java index 6aba92aa4a..a52ab82305 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunction.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighFunction.java @@ -120,7 +120,7 @@ public class HighFunction extends PcodeSyntaxTree { } @Override - public HighSymbol getSymbol(int symbolId) { + public HighSymbol getSymbol(long symbolId) { return localSymbols.getSymbol(symbolId); } @@ -469,9 +469,8 @@ public class HighFunction extends PcodeSyntaxTree { // Note that we don't need to distinguish between unique,register,ram etc. and don't // need to separate out first use versus mapped use. When the high local is written // to database, these issues will be resolved at that point. - sym = localSymbols.newMappedSymbol(highloc.getName(), highloc.getDataType(), - new VariableStorage(func.getProgram(), vn), vn.getPCAddress(), -1, - vn.hashCode()); + sym = localSymbols.newMappedSymbol(0, highloc.getName(), highloc.getDataType(), + new VariableStorage(func.getProgram(), vn), vn.getPCAddress(), -1); reslocal = new HighLocal(highloc.getDataType(), vn, null, vn.getPCAddress(), sym); resremain = highloc; // Keep remaining varnodes in old high diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java index e8a0d3cdc5..f051b5087f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/HighSymbol.java @@ -24,6 +24,7 @@ import ghidra.xml.XmlPullParser; public abstract 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 @@ -32,13 +33,15 @@ public abstract class HighSymbol { 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 private HighVariable highVariable; public HighSymbol() { // For use with restoreXML } - public HighSymbol(String nm,DataType tp,int sz,Address pc,HighFunction func) { + public HighSymbol(long uniqueId, String nm, DataType tp, int sz, Address pc, + HighFunction func) { name = nm; type = tp; size = sz; @@ -46,8 +49,13 @@ public abstract class HighSymbol { namelock = false; typelock = false; function = func; + id = uniqueId; } - + + public long getId() { + return id; + } + public void setHighVariable(HighVariable high) { this.highVariable = high; } @@ -102,25 +110,26 @@ public abstract class HighSymbol { public abstract String buildXML(); - public abstract int restoreXML(XmlPullParser parser,HighFunction func) throws PcodeXMLException; + public abstract void restoreXML(XmlPullParser parser, HighFunction func) + throws PcodeXMLException; - protected int restoreSymbolXML(XmlElement symel,HighFunction func) throws PcodeXMLException { + protected void restoreSymbolXML(XmlElement symel, HighFunction func) throws PcodeXMLException { function = func; - int symbolId = SpecXmlUtils.decodeInt(symel.getAttribute("id")); - if (symbolId == 0) { + id = SpecXmlUtils.decodeLong(symel.getAttribute("id")); + if (id == 0) { throw new PcodeXMLException("missing unique symbol id"); } typelock = false; String typelockstr = symel.getAttribute("typelock"); - if ((typelockstr != null) && (SpecXmlUtils.decodeBoolean(typelockstr))) + if ((typelockstr != null) && (SpecXmlUtils.decodeBoolean(typelockstr))) { typelock = true; + } namelock = false; String namelockstr = symel.getAttribute("namelock"); - if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) + if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) { namelock = true; + } name = symel.getAttribute("name"); - - return symbolId; } protected Address parseRangeList(XmlPullParser parser) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java index d1a81e3d9f..111b97292a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LocalSymbolMap.java @@ -39,8 +39,9 @@ public class LocalSymbolMap { private HighFunction func; // Function to which these variables are local private String spacename; private HashMap addrMappedSymbols; // Hashed by addr and pcaddr - private HashMap symbolMap; // Hashed by unique key + private HashMap symbolMap; // Hashed by unique key private MappedSymbol[] paramSymbols; + private long uniqueSymbolId; // Next available symbol id /** * @param highFunc HighFunction the local variables are defined within. @@ -50,21 +51,31 @@ public class LocalSymbolMap { func = highFunc; spacename = spcname; addrMappedSymbols = new HashMap(); - symbolMap = new HashMap(); + symbolMap = new HashMap(); paramSymbols = new MappedSymbol[0]; + uniqueSymbolId = 0; } public HighFunction getHighFunction() { return func; } + /** + * Assign a unique id to a new symbol being put in this container. + * @return the unique id + */ + private long getNextId() { + long key = HighSymbol.ID_BASE + uniqueSymbolId; + uniqueSymbolId += 1; + return key; + } + /** * Populate the local variable map from information attached to the Program DB's function. * @param includeDefaultNames is true if default symbol names should be considered locked */ public void grabFromFunction(boolean includeDefaultNames) { Function dbFunction = func.getFunction(); - int uniqueSymbolId = 0; Variable locals[] = dbFunction.getLocalVariables(); for (Variable local : locals) { Variable var = local; @@ -82,18 +93,18 @@ public class LocalSymbolMap { String name = var.getName(); VariableStorage storage = var.getVariableStorage(); + long id = getNextId(); Address defAddr = null; if (!storage.isStackStorage()) { defAddr = dbFunction.getEntryPoint().addWrap(var.getFirstUseOffset()); } HighSymbol sym; if (storage.isHashStorage()) { - sym = - newDynamicSymbol(name, dt, sz, storage.getFirstVarnode().getOffset(), defAddr, - 0, ++uniqueSymbolId); + sym = newDynamicSymbol(id, name, dt, sz, storage.getFirstVarnode().getOffset(), + defAddr, 0); } else { - sym = newMappedSymbol(name, dt, storage, defAddr, -1, ++uniqueSymbolId); + sym = newMappedSymbol(id, name, dt, storage, defAddr, -1); } sym.setTypeLock(istypelock); sym.setNameLock(isnamelock); @@ -116,8 +127,9 @@ public class LocalSymbolMap { String name = var.getName(); VariableStorage storage = var.getVariableStorage(); Address resAddr = storage.isStackStorage() ? null : pcaddr; + long id = getNextId(); MappedSymbol paramSymbol = - newMappedSymbol(name, dt, storage, resAddr, i, ++uniqueSymbolId); + newMappedSymbol(id, name, dt, storage, resAddr, i); paramList.add(paramSymbol); boolean namelock = true; if (!includeDefaultNames) { @@ -131,7 +143,7 @@ public class LocalSymbolMap { paramList.toArray(paramSymbols); Arrays.sort(paramSymbols, PARAM_SYMBOL_SLOT_COMPARATOR); - uniqueSymbolId = grabEquates(dbFunction, uniqueSymbolId); + grabEquates(dbFunction); } private boolean isUserDefinedName(String name) { @@ -164,9 +176,9 @@ public class LocalSymbolMap { res = new EquateSymbol(); } - int symbolId = res.restoreXML(parser, func); + res.restoreXML(parser, func); parser.end(node); - insertSymbol(res,symbolId); + insertSymbol(res); return res; } @@ -290,7 +302,7 @@ public class LocalSymbolMap { * @param id symbol-id * @return variable or null if not found */ - public HighSymbol getSymbol(int id) { + public HighSymbol getSymbol(long id) { return symbolMap.get(id); } @@ -316,43 +328,60 @@ public class LocalSymbolMap { return false; } - public MappedSymbol newMappedSymbol(String nm, DataType dt, VariableStorage store, - Address pcaddr, int slot, int id) { - MappedSymbol sym = new MappedSymbol(nm, dt, store, pcaddr, func, slot); - insertSymbol(sym,id); + public MappedSymbol 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); + insertSymbol(sym); return sym; } - public DynamicSymbol newDynamicSymbol(String nm, DataType dt, int sz, long hash, - Address pcaddr, int format, int id) { - DynamicSymbol sym = new DynamicSymbol(nm, dt, sz, func, pcaddr, hash, format); - insertSymbol(sym,id); + public DynamicSymbol newDynamicSymbol(long id, String nm, DataType dt, int sz, long hash, + Address pcaddr, int format) { + if (id == 0) { + id = getNextId(); + } + DynamicSymbol sym = new DynamicSymbol(id, nm, dt, sz, func, pcaddr, hash, format); + insertSymbol(sym); return sym; } - private void insertSymbol(HighSymbol sym,int id) { + private void insertSymbol(HighSymbol sym) { + long uniqueId = sym.getId(); + if ((uniqueId >> 56) == (HighSymbol.ID_BASE >> 56)) { + long val = uniqueId & 0x7fffffff; + if (val > uniqueSymbolId) { + uniqueSymbolId = val; + } + } if (sym instanceof MappedSymbol) { MappedSymbol mapSym = (MappedSymbol)sym; MappedVarKey key = new MappedVarKey(mapSym.getStorage(),mapSym.getPCAddress()); addrMappedSymbols.put(key, sym); } - symbolMap.put(id, sym); + symbolMap.put(uniqueId, sym); } - private void newEquateSymbol(String nm, long val, long hash, Address addr, int format, + private void newEquateSymbol(long uniqueId, String nm, long val, long hash, Address addr, + int format, TreeMap constantSymbolMap) { DynamicSymbol eqSymbol = constantSymbolMap.get(nm); if (eqSymbol != null) { eqSymbol.addReference(addr, hash, format); // New reference to same symbol return; } + if (uniqueId == 0) { + uniqueId = getNextId(); + } int conv = EquateSymbol.convertName(nm, val); if (conv < 0) { - eqSymbol = new EquateSymbol(nm, val, func, addr, hash, format); + eqSymbol = new EquateSymbol(uniqueId, nm, val, func, addr, hash, format); eqSymbol.setNameLock(true); } else { - eqSymbol = new EquateSymbol(conv, val, func, addr, hash, format); + eqSymbol = new EquateSymbol(uniqueId, conv, val, func, addr, hash, format); } //Do NOT setTypeLock constantSymbolMap.put(nm, eqSymbol); @@ -361,10 +390,8 @@ public class LocalSymbolMap { /** * Build dynamic symbols based on equates * @param dbFunction is the function to pull equates for - * @param uniqueSymbolId is the next available symbol id - * @return the next available symbol id */ - private int grabEquates(Function dbFunction, int uniqueSymbolId) { + private void grabEquates(Function dbFunction) { TreeMap constantSymbolMap = null; // Find named constants via Equates Program program = dbFunction.getProgram(); @@ -383,7 +410,7 @@ public class LocalSymbolMap { if (constantSymbolMap == null) { constantSymbolMap = new TreeMap(); } - newEquateSymbol(eq.getDisplayName(), eq.getValue(), element, defAddr, 0, + newEquateSymbol(0, eq.getDisplayName(), eq.getValue(), element, defAddr, 0, constantSymbolMap); } } @@ -405,10 +432,10 @@ public class LocalSymbolMap { // Add constant dynamic symbols to map if (constantSymbolMap != null) { for (DynamicSymbol sym : constantSymbolMap.values()) { - symbolMap.put(++uniqueSymbolId, sym); + long id = getNextId(); + symbolMap.put(id, sym); } } - return uniqueSymbolId; } /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedSymbol.java index 2740c37fbf..45f7f1c872 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/MappedSymbol.java @@ -33,21 +33,25 @@ public class MappedSymbol extends HighSymbol { public MappedSymbol() { // For use with restoreXML } - public MappedSymbol(String name, DataType dt, VariableStorage store, Address pcaddr, + public MappedSymbol(long uniqueId, String name, DataType dt, VariableStorage store, + Address pcaddr, HighFunction func, int slot) { - super(name, dt, store.size(), pcaddr, func); + super(uniqueId, name, dt, store.size(), pcaddr, func); if (store.size() != dt.getLength()) { - if (ParamEntry.getMetatype(dt) != ParamEntry.TYPE_FLOAT) + if (ParamEntry.getMetatype(dt) != ParamEntry.TYPE_FLOAT) { throw new IllegalArgumentException("Specified size does not match storage size"); + } } this.storage = store; this.slot = slot; Varnode rep = function.createFromStorage(null, storage, dt.getLength()); HighVariable var; - if (slot < 0) + if (slot < 0) { var = new HighLocal(type, rep, null, pcaddr, this); - else + } + else { var = new HighParam(type, rep, pcaddr, slot, this); + } setHighVariable(var); var.setHighOnInstances(); } @@ -71,26 +75,29 @@ public class MappedSymbol extends HighSymbol { } StringBuilder res = new StringBuilder(); int cat = isParameter() ? 0 : -1; - String sym = buildSymbolXML(function.getDataTypeManager(),name, type, size, + 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())) // If sizesdiffer + 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 int restoreXML(XmlPullParser parser,HighFunction func) throws PcodeXMLException { + public void restoreXML(XmlPullParser parser, HighFunction func) throws PcodeXMLException { XmlElement symel = parser.start("symbol"); - int symbolId = restoreSymbolXML(symel, func); + restoreSymbolXML(symel, func); slot = -1; int cat = -1; if (symel.hasAttribute("cat")) { cat = SpecXmlUtils.decodeInt(symel.getAttribute("cat")); - if (cat == 0) + if (cat == 0) { slot = SpecXmlUtils.decodeInt(symel.getAttribute("index")); + } } type = func.getDataTypeManager().readXMLDataType(parser); parser.end(symel); @@ -129,26 +136,34 @@ public class MappedSymbol extends HighSymbol { pcaddr = parseRangeList(parser); Varnode rep = function.createFromStorage(addr, storage, sz); HighVariable var; - if (slot < 0) + if (slot < 0) { var = new HighLocal(type, rep, null, pcaddr, this); - else + } + else { var = new HighParam(type, rep, pcaddr, slot, this); + } setHighVariable(var); var.setHighOnInstances(); - return symbolId; } - public static String buildSymbolXML(PcodeDataTypeManager dtmanage, String nm, + 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("> 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) + if (isVolatile) { SpecXmlUtils.encodeBooleanAttribute(res, "volatile", true); + } SpecXmlUtils.encodeSignedIntegerAttribute(res, "cat", cat); if (slot >= 0) { SpecXmlUtils.encodeSignedIntegerAttribute(res, "index", slot); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeFactory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeFactory.java index 554262c22b..11e248eec2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeFactory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeFactory.java @@ -57,7 +57,8 @@ public interface PcodeFactory { public VariableStorage buildStorage(Varnode vn) throws InvalidInputException; public Varnode getRef(int refid); public PcodeOp getOpRef(int refid); - public HighSymbol getSymbol(int symbolId); + + public HighSymbol getSymbol(long symbolId); public Varnode setInput(Varnode vn,boolean val); public void setAddrTied(Varnode vn,boolean val); public void setPersistant(Varnode vn,boolean val); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeSyntaxTree.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeSyntaxTree.java index 0a2bb0a003..48cd3429a6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeSyntaxTree.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeSyntaxTree.java @@ -142,8 +142,9 @@ public class PcodeSyntaxTree implements PcodeFactory { // bad prototypes causing the decompiler to produce weird stuff // TODO: We should emit some kind of warning int sz = 0; - for (Varnode piece : pieces) + for (Varnode piece : pieces) { sz += piece.getSize(); + } Address uniqaddr = addrFactory.getUniqueSpace().getAddress(0x20000000); storage = new VariableStorage(datatypeManager.getProgram(),uniqaddr,sz); } @@ -156,26 +157,30 @@ public class PcodeSyntaxTree implements PcodeFactory { else { offObject = new Integer((int)offset); offset += roundsize; - if (offset > joinAllocate) + if (offset > joinAllocate) { joinAllocate = (int)offset; + } } - if (joinmap == null) + if (joinmap == null) { joinmap = new HashMap(); + } joinmap.put(offObject, storage); return storage; } private VariableStorage findJoinStorage(long offset) { - if (joinmap == null) + if (joinmap == null) { return null; + } return joinmap.get(new Integer((int)offset)); } @Override public VariableStorage buildStorage(Varnode vn) throws InvalidInputException { Address addr = vn.getAddress(); - if (addr.getAddressSpace().getType() == AddressSpace.TYPE_VARIABLE) + if (addr.getAddressSpace().getType() == AddressSpace.TYPE_VARIABLE) { return findJoinStorage(addr.getOffset()); + } return new VariableStorage(datatypeManager.getProgram(),vn); } @@ -306,10 +311,12 @@ public class PcodeSyntaxTree implements PcodeFactory { @Override public Varnode newVarnode(int sz, Address addr, int id) { Varnode vn = vbank.create(sz, addr, id); - if (uniqId <= id) + if (uniqId <= id) { uniqId = id + 1; - if (refmap != null) + } + if (refmap != null) { refmap.put(id, vn); + } return vn; } @@ -342,10 +349,12 @@ public class PcodeSyntaxTree implements PcodeFactory { @Override public Varnode setInput(Varnode vn, boolean val) { - if ((!vn.isInput()) && val) + if ((!vn.isInput()) && val) { return vbank.setInput(vn); - if (vn.isInput() && (!val)) + } + if (vn.isInput() && (!val)) { vbank.makeFree(vn); + } return vn; } @@ -360,13 +369,14 @@ public class PcodeSyntaxTree implements PcodeFactory { @Override public Varnode getRef(int id) { - if (refmap == null) + if (refmap == null) { return null; + } return refmap.get(id); } @Override - public HighSymbol getSymbol(int symbolId) { + public HighSymbol getSymbol(long symbolId) { return null; } @@ -410,8 +420,9 @@ public class PcodeSyntaxTree implements PcodeFactory { @Override public PcodeOp getOpRef(int id) { - if (oprefmap == null) + if (oprefmap == null) { buildOpRefs(); + } return oprefmap.get(id); } @@ -437,12 +448,16 @@ public class PcodeSyntaxTree implements PcodeFactory { public void setOutput(PcodeOp op, Varnode vn) { if (vn == op.getOutput()) + { return; // Output already set to this - if (op.getOutput() != null) + } + if (op.getOutput() != null) { unSetOutput(op); + } - if (vn.getDef() != null) // Varnode is already an output + if (vn.getDef() != null) { unSetOutput(vn.getDef()); + } vn = vbank.setDef(vn, op); op.setOutput(vn); } @@ -450,16 +465,21 @@ public class PcodeSyntaxTree implements PcodeFactory { public void unSetOutput(PcodeOp op) { Varnode vn = op.getOutput(); if (vn == null) + { return; // Nothing to do + } op.setOutput(null); vbank.makeFree(vn); } public void setInput(PcodeOp op, Varnode vn, int slot) { if (slot >= op.getNumInputs()) + { op.setInput(null, slot); // Expand number of inputs as necessary - if (op.getInput(slot) != null) + } + if (op.getInput(slot) != null) { unSetInput(op, slot); + } if (vn != null) { VarnodeAST vnast = (VarnodeAST) vn; vnast.addDescendant(op); @@ -484,29 +504,35 @@ public class PcodeSyntaxTree implements PcodeFactory { public void unlink(PcodeOpAST op) { unSetOutput(op); - for (int i = 0; i < op.getNumInputs(); ++i) + for (int i = 0; i < op.getNumInputs(); ++i) { unSetInput(op, i); - if (op.getParent() != null) + } + if (op.getParent() != null) { unInsert(op); + } } @Override public PcodeOp newOp(SequenceNumber sq, int opc, ArrayList inputs, Varnode output) throws UnknownInstructionException { PcodeOp op = opbank.create(opc, inputs.size(), sq); - if (output != null) + if (output != null) { setOutput(op, output); - for (int i = 0; i < inputs.size(); ++i) + } + for (int i = 0; i < inputs.size(); ++i) { setInput(op, inputs.get(i), i); - if (oprefmap != null) + } + if (oprefmap != null) { oprefmap.put(sq.getTime(), op); + } return op; } private void readVarnodeXML(XmlPullParser parser) throws PcodeXMLException { XmlElement el = parser.start("varnodes"); - while (parser.peek().isStart()) + while (parser.peek().isStart()) { Varnode.readXML(parser, this); + } parser.end(el); } @@ -524,8 +550,9 @@ public class PcodeSyntaxTree implements PcodeFactory { bl.insertEnd(op); } int index = bl.getIndex(); - while (bblocks.size() <= index) + while (bblocks.size() <= index) { bblocks.add(null); + } bblocks.set(index, bl); parser.end(el); } @@ -542,17 +569,20 @@ public class PcodeSyntaxTree implements PcodeFactory { public void readXML(XmlPullParser parser) throws PcodeXMLException { XmlElement el = parser.start("ast"); - if (!vbank.isEmpty()) + if (!vbank.isEmpty()) { clear(); + } readVarnodeXML(parser); buildVarnodeRefs(); // Build the HashMap BlockMap blockMap = new BlockMap(addrFactory); while (parser.peek().isStart()) { XmlElement subel = parser.peek(); - if (subel.getName().equals("block")) + if (subel.getName().equals("block")) { readBasicBlockXML(parser, blockMap); // Read a basic block and all its PcodeOps - else // Read block edges + } + else { readBlockEdgeXML(parser); + } } parser.end(el); }