GP-2830 Parsing pspec symbols

This commit is contained in:
caheckman 2022-11-10 18:27:51 -05:00
parent 3cf13c2533
commit 8f2450e625
13 changed files with 274 additions and 82 deletions

View file

@ -29,6 +29,7 @@ vector<ArchitectureCapability *> ArchitectureCapability::thelist;
const uint4 ArchitectureCapability::majorversion = 5;
const uint4 ArchitectureCapability::minorversion = 0;
AttributeId ATTRIB_ADDRESS = AttributeId("address",148);
AttributeId ATTRIB_ADJUSTVMA = AttributeId("adjustvma",103);
AttributeId ATTRIB_ENABLE = AttributeId("enable",104);
AttributeId ATTRIB_GROUP = AttributeId("group",105);
@ -583,15 +584,6 @@ void Architecture::buildAction(DocumentStorage &store)
allacts.resetDefaults();
}
/// This builds the database which holds the status registers setings and other
/// information that can affect disassembly depending on context.
/// \param store may hold configuration information
void Architecture::buildContext(DocumentStorage &store)
{
context = new ContextInternal();
}
/// Create the database object, which currently doesn't not depend on any configuration
/// data. Then create the root (global) scope and attach it to the database.
/// \param store is the storage for any configuration data
@ -605,72 +597,6 @@ Scope *Architecture::buildDatabase(DocumentStorage &store)
return globscope;
}
/// This builds the TypeFactory object specific to this architecture and
/// prepopulates it with the \e core types. Core types may be pulled
/// from the configuration information, or default core types are used.
/// \param store contains possible configuration information
void Architecture::buildTypegrp(DocumentStorage &store)
{
const Element *el = store.getTag("coretypes");
types = new TypeFactory(this); // Initialize the object
if (el != (const Element *)0) {
XmlDecode decoder(this,el);
types->decodeCoreTypes(decoder);
}
else {
// Put in the core types
types->setCoreType("void",1,TYPE_VOID,false);
types->setCoreType("bool",1,TYPE_BOOL,false);
types->setCoreType("uint1",1,TYPE_UINT,false);
types->setCoreType("uint2",2,TYPE_UINT,false);
types->setCoreType("uint4",4,TYPE_UINT,false);
types->setCoreType("uint8",8,TYPE_UINT,false);
types->setCoreType("int1",1,TYPE_INT,false);
types->setCoreType("int2",2,TYPE_INT,false);
types->setCoreType("int4",4,TYPE_INT,false);
types->setCoreType("int8",8,TYPE_INT,false);
types->setCoreType("float4",4,TYPE_FLOAT,false);
types->setCoreType("float8",8,TYPE_FLOAT,false);
types->setCoreType("float10",10,TYPE_FLOAT,false);
types->setCoreType("float16",16,TYPE_FLOAT,false);
types->setCoreType("xunknown1",1,TYPE_UNKNOWN,false);
types->setCoreType("xunknown2",2,TYPE_UNKNOWN,false);
types->setCoreType("xunknown4",4,TYPE_UNKNOWN,false);
types->setCoreType("xunknown8",8,TYPE_UNKNOWN,false);
types->setCoreType("code",1,TYPE_CODE,false);
types->setCoreType("char",1,TYPE_INT,true);
types->setCoreType("wchar2",2,TYPE_INT,true);
types->setCoreType("wchar4",4,TYPE_INT,true);
types->cacheCoreTypes();
}
}
/// Build the container that holds comments for executable in this Architecture.
/// \param store may hold configuration information
void Architecture::buildCommentDB(DocumentStorage &store)
{
commentdb = new CommentDatabaseInternal();
}
/// Build container that holds decoded strings
/// \param store may hold configuration information
void Architecture::buildStringManager(DocumentStorage &store)
{
stringManager = new StringManagerUnicode(this,2048);
}
/// Some processor models (Java byte-code) need a database of constants.
/// The database is always built, but may remain empty.
/// \param store may hold configuration information
void Architecture::buildConstantPool(DocumentStorage &store)
{
cpool = new ConstantPoolInternal();
}
/// This registers the OpBehavior objects for all known p-code OpCodes.
/// The Translate and TypeFactory object should already be built.
/// \param store may hold configuration information
@ -1257,6 +1183,7 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
}
else if (subId == ELEM_DEFAULT_SYMBOLS) {
decoder.openElement();
store.registerTag(decoder.getCurrentXmlElement());
decoder.closeElementSkipping(subId);
}
else if (subId == ELEM_DEFAULT_MEMORY_BLOCKS) {
@ -1449,6 +1376,7 @@ void Architecture::init(DocumentStorage &store)
restoreFromSpec(store);
print->initializeFromArchitecture();
symboltab->adjustCaches(); // In case the specs created additional address spaces
buildSymbols(store);
postSpecFile(); // Let subclasses do things after translate is ready
buildInstructions(store); // Must be called after translate is built

View file

@ -61,6 +61,7 @@ public:
class Architecture;
extern AttributeId ATTRIB_ADDRESS; ///< Marshaling attribute "address"
extern AttributeId ATTRIB_ADJUSTVMA; ///< Marshaling attribute "adjustvma"
extern AttributeId ATTRIB_ENABLE; ///< Marshaling attribute "enable"
extern AttributeId ATTRIB_GROUP; ///< Marshaling attribute "group"
@ -273,13 +274,48 @@ protected:
/// \return the PcodeInjectLibrary object
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void)=0;
virtual void buildTypegrp(DocumentStorage &store); ///< Build the data-type factory/container
virtual void buildCommentDB(DocumentStorage &store); ///< Build the comment database
virtual void buildStringManager(DocumentStorage &store); ///< Build the string manager
virtual void buildConstantPool(DocumentStorage &store); ///< Build the constant pool
/// \brief Build the data-type factory/container
///
/// Build the TypeFactory object specific to \b this Architecture and
/// prepopulate it with the \e core types. Core types may be pulled
/// from the configuration information, or default core types are used.
/// \param store contains possible configuration information
virtual void buildTypegrp(DocumentStorage &store)=0;
/// \brief Build the comment database
///
/// Build the container that holds comments in \b this Architecture.
/// \param store may hold configuration information
virtual void buildCommentDB(DocumentStorage &store)=0;
/// \brief Build the string manager
///
/// Build container that holds decoded strings for \b this Architecture.
/// \param store may hold configuration information
virtual void buildStringManager(DocumentStorage &store)=0;
/// \brief Build the constant pool
///
/// Some processor models (Java byte-code) need a database of constants.
/// The database is always built, but may remain empty.
/// \param store may hold configuration information
virtual void buildConstantPool(DocumentStorage &store)=0;
virtual void buildInstructions(DocumentStorage &store); ///< Register the p-code operations
virtual void buildAction(DocumentStorage &store); ///< Build the Action framework
virtual void buildContext(DocumentStorage &store); ///< Build the Context database
/// \brief Build the Context database
///
/// Build the database which holds status register settings and other
/// information that can affect disassembly depending on context.
/// \param store may hold configuration information
virtual void buildContext(DocumentStorage &store)=0;
/// \brief Build any symbols from spec files
///
/// Formal symbols described in a spec file are added to the global scope.
/// \param store may hold symbol elements
virtual void buildSymbols(DocumentStorage &store)=0;
/// \brief Load any relevant specification files
///

View file

@ -3224,6 +3224,32 @@ void Database::setPropertyRange(uint4 flags,const Range &range)
}
}
/// The non-zero bits in the \b flags parameter indicate the boolean properties to be cleared.
/// No other properties are altered.
/// \param flags is the set of properties to clear
/// \param range is the memory range to clear
void Database::clearPropertyRange(uint4 flags,const Range &range)
{
Address addr1 = range.getFirstAddr();
Address addr2 = range.getLastAddrOpen(glb);
flagbase.split(addr1);
partmap<Address,uint4>::iterator aiter,biter;
aiter = flagbase.begin(addr1);
if (!addr2.isInvalid()) {
flagbase.split(addr2);
biter = flagbase.begin(addr2);
}
else
biter = flagbase.end();
flags = ~flags;
while(aiter != biter) { // Update bits across whole range
(*aiter).second &= flags;
++aiter;
}
}
/// Encode a single \<db> element to the stream, which contains child elements
/// for each Scope (which contain Symbol children in turn).
/// \param encoder is the stream encoder

View file

@ -925,6 +925,7 @@ public:
Scope *mapScope(Scope *qpoint,const Address &addr,const Address &usepoint);
uint4 getProperty(const Address &addr) const { return flagbase.getValue(addr); } ///< Get boolean properties at the given address
void setPropertyRange(uint4 flags,const Range &range); ///< Set boolean properties over a given memory range
void clearPropertyRange(uint4 flags,const Range &range); ///< Clear boolean properties over a given memory range
void setProperties(const partmap<Address,uint4> &newflags) { flagbase = newflags; } ///< Replace the property map
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
void encode(Encoder &encoder) const; ///< Encode the whole Database to a stream

View file

@ -372,6 +372,55 @@ void ArchitectureGhidra::buildContext(DocumentStorage &store)
context = new ContextGhidra(this);
}
void ArchitectureGhidra::buildSymbols(DocumentStorage &store)
{
const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName());
if (symtag == (const Element *)0) return;
XmlDecode decoder(this,symtag);
uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS);
while(decoder.peekElement() != 0) {
uint4 subel = decoder.openElement(ELEM_SYMBOL);
string addrString;
string name;
int4 size = 0;
int4 volatileState = -1;
for(;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_NAME)
name = decoder.readString();
else if (attribId == ATTRIB_ADDRESS) {
addrString = decoder.readString();
}
else if (attribId == ATTRIB_VOLATILE) {
volatileState = decoder.readBool() ? 1 : 0;
}
else if (attribId == ATTRIB_SIZE)
size = decoder.readSignedInteger();
}
decoder.closeElement(subel);
if (name.size() == 0)
throw LowlevelError("Missing name attribute in <symbol> element");
if (addrString.size() == 0)
throw LowlevelError("Missing address attribute in <symbol> element");
// Currently we only use the volatile attribute on pspec symbols and let Ghidra
// feed the global symbol to the decompiler on a per function basic.
if (volatileState < 0)
continue;
Address addr = parseAddressSimple(addrString);
if (size == 0)
size = addr.getSpace()->getWordSize();
Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1));
if (volatileState == 0)
symboltab->clearPropertyRange(Varnode::volatil, range);
else
symboltab->setPropertyRange(Varnode::volatil, range);
}
decoder.closeElement(el);
}
void ArchitectureGhidra::resolveArchitecture(void)
{

View file

@ -97,6 +97,7 @@ class ArchitectureGhidra : public Architecture {
virtual void buildStringManager(DocumentStorage &store);
virtual void buildConstantPool(DocumentStorage &store);
virtual void buildContext(DocumentStorage &store);
virtual void buildSymbols(DocumentStorage &store);
virtual void buildSpecFile(DocumentStorage &store);
virtual void modifySpaces(Translate *trans) {} // This is handled directly by GhidraTranslate::initialize
virtual void postSpecFile(void);

View file

@ -1036,7 +1036,7 @@ AttributeId ATTRIB_VAL = AttributeId("val",24);
AttributeId ATTRIB_VALUE = AttributeId("value",25);
AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26);
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",148); // Number serves as next open index
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",149); // Number serves as next open index
ElementId ELEM_DATA = ElementId("data",1);
ElementId ELEM_INPUT = ElementId("input",2);

View file

@ -323,6 +323,7 @@ public:
document = (Document *)0; rootElement = root; attributeIndex = -1; } ///< Constructor with preparsed root
XmlDecode(const AddrSpaceManager *spc) : Decoder(spc) {
document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream
const Element *getCurrentXmlElement(void) const { return elStack.back(); } ///< Get pointer to underlying XML element object
virtual ~XmlDecode(void);
virtual void ingestStream(istream &s);
virtual uint4 peekElement(void);

View file

@ -194,6 +194,115 @@ PcodeInjectLibrary *SleighArchitecture::buildPcodeInjectLibrary(void)
return res;
}
void SleighArchitecture::buildTypegrp(DocumentStorage &store)
{
const Element *el = store.getTag("coretypes");
types = new TypeFactory(this); // Initialize the object
if (el != (const Element *)0) {
XmlDecode decoder(this,el);
types->decodeCoreTypes(decoder);
}
else {
// Put in the core types
types->setCoreType("void",1,TYPE_VOID,false);
types->setCoreType("bool",1,TYPE_BOOL,false);
types->setCoreType("uint1",1,TYPE_UINT,false);
types->setCoreType("uint2",2,TYPE_UINT,false);
types->setCoreType("uint4",4,TYPE_UINT,false);
types->setCoreType("uint8",8,TYPE_UINT,false);
types->setCoreType("int1",1,TYPE_INT,false);
types->setCoreType("int2",2,TYPE_INT,false);
types->setCoreType("int4",4,TYPE_INT,false);
types->setCoreType("int8",8,TYPE_INT,false);
types->setCoreType("float4",4,TYPE_FLOAT,false);
types->setCoreType("float8",8,TYPE_FLOAT,false);
types->setCoreType("float10",10,TYPE_FLOAT,false);
types->setCoreType("float16",16,TYPE_FLOAT,false);
types->setCoreType("xunknown1",1,TYPE_UNKNOWN,false);
types->setCoreType("xunknown2",2,TYPE_UNKNOWN,false);
types->setCoreType("xunknown4",4,TYPE_UNKNOWN,false);
types->setCoreType("xunknown8",8,TYPE_UNKNOWN,false);
types->setCoreType("code",1,TYPE_CODE,false);
types->setCoreType("char",1,TYPE_INT,true);
types->setCoreType("wchar2",2,TYPE_INT,true);
types->setCoreType("wchar4",4,TYPE_INT,true);
types->cacheCoreTypes();
}
}
void SleighArchitecture::buildCommentDB(DocumentStorage &store)
{
commentdb = new CommentDatabaseInternal();
}
void SleighArchitecture::buildStringManager(DocumentStorage &store)
{
stringManager = new StringManagerUnicode(this,2048);
}
void SleighArchitecture::buildConstantPool(DocumentStorage &store)
{
cpool = new ConstantPoolInternal();
}
void SleighArchitecture::buildContext(DocumentStorage &store)
{
context = new ContextInternal();
}
void SleighArchitecture::buildSymbols(DocumentStorage &store)
{
const Element *symtag = store.getTag(ELEM_DEFAULT_SYMBOLS.getName());
if (symtag == (const Element *)0) return;
XmlDecode decoder(this,symtag);
uint4 el = decoder.openElement(ELEM_DEFAULT_SYMBOLS);
while(decoder.peekElement() != 0) {
uint4 subel = decoder.openElement(ELEM_SYMBOL);
Address addr;
string name;
int4 size = 0;
int4 volatileState = -1;
for(;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_NAME)
name = decoder.readString();
else if (attribId == ATTRIB_ADDRESS) {
addr = parseAddressSimple(decoder.readString());
}
else if (attribId == ATTRIB_VOLATILE) {
volatileState = decoder.readBool() ? 1 : 0;
}
else if (attribId == ATTRIB_SIZE)
size = decoder.readSignedInteger();
}
decoder.closeElement(subel);
if (name.size() == 0)
throw LowlevelError("Missing name attribute in <symbol> element");
if (addr.isInvalid())
throw LowlevelError("Missing address attribute in <symbol> element");
if (size == 0)
size = addr.getSpace()->getWordSize();
if (volatileState >= 0) {
Range range(addr.getSpace(),addr.getOffset(),addr.getOffset() + (size-1));
if (volatileState == 0)
symboltab->clearPropertyRange(Varnode::volatil, range);
else
symboltab->setPropertyRange(Varnode::volatil, range);
}
Datatype *ct = types->getBase(size, TYPE_UNKNOWN);
Address usepoint;
symboltab->getGlobalScope()->addSymbol(name, ct, addr, usepoint);
}
decoder.closeElement(el);
}
void SleighArchitecture::resolveArchitecture(void)
{ // Find best architecture

View file

@ -117,6 +117,12 @@ protected:
static void collectSpecFiles(ostream &errs); ///< Gather specification files in normal locations
virtual Translate *buildTranslator(DocumentStorage &store);
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
virtual void buildTypegrp(DocumentStorage &store);
virtual void buildCommentDB(DocumentStorage &store);
virtual void buildStringManager(DocumentStorage &store);
virtual void buildConstantPool(DocumentStorage &store);
virtual void buildContext(DocumentStorage &store);
virtual void buildSymbols(DocumentStorage &store);
virtual void buildSpecFile(DocumentStorage &store);
virtual void modifySpaces(Translate *trans);
virtual void resolveArchitecture(void);

View file

@ -864,6 +864,37 @@ void AddrSpaceManager::renormalizeJoinAddress(Address &addr,int4 size)
addr = Address(newJoinRecord->unified.space,newJoinRecord->unified.offset);
}
/// The string \e must contain a hexadecimal offset. The offset may be optionally prepended with "0x".
/// The string may optionally start with the name of the address space to associate with the offset, followed
/// by ':' to separate it from the offset. If the name is not present, the default data space is assumed.
/// \param val is the string to parse
/// \return the parsed address
Address AddrSpaceManager::parseAddressSimple(const string &val)
{
string::size_type col = val.find(':');
AddrSpace *spc;
if (col==string::npos) {
spc = getDefaultDataSpace();
col = 0;
}
else {
string spcName = val.substr(0,col);
spc = getSpaceByName(spcName);
if (spc == (AddrSpace *)0)
throw LowlevelError("Unknown address space: " + spcName);
col += 1;
}
if (col + 2 <= val.size()) {
if (val[col] == '0' && val[col+1] == 'x')
col += 2;
}
istringstream s(val.substr(col));
uintb off;
s >> hex >> off;
return Address(spc,AddrSpace::addressToByte(off, spc->getWordSize()));
}
/// This constructs only a shell for the Translate object. It
/// won't be usable until it is initialized for a specific processor
/// The main entry point for this is the Translate::initialize method,

View file

@ -278,6 +278,9 @@ public:
/// \brief Make sure a possibly offset \e join address has a proper JoinRecord
void renormalizeJoinAddress(Address &addr,int4 size);
/// \brief Parse a string with just an \e address \e space name and a hex offset
Address parseAddressSimple(const string &val);
};
/// \brief The interface to a translation engine for a processor.

View file

@ -243,5 +243,6 @@ public record AttributeId(String name, int id) {
// public static final AttributeId ATTRIB_VARIANT = new AttributeId("variant", 143);
// public static final AttributeId ATTRIB_VERSION = new AttributeId("version", 144);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 148);
// public static final AttributeId ATTRIB_ADDRESS = new AttributeId("address", 148);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 149);
}