Program specific, user-defined, cspec extensions

Documentation for spec extensions

Handle extensions with parse errors
Export button for spec extensions
Pop-up dialog for parse errors in user-defined specification extensions
GP-653 corrected some minor issues and established new ProgramDB version
make incremental initialization constructor for AddressSized private
Make AddressSized fields private
More adjustments to AddressSized
Review fixes for BasicCompilerSpec
Take restoreXml out of DataOrganization interface
Remove restoreXml from BitFieldPacking interface
More review fixes
Prevent callotherfixup extension with non-existent target
Suggested export name
More documentation for SpecExtension
Support for undo/redo with spec extensions
Documentation for ConstructTpl
Split out ProgramCompilerSpec and other changes for review
Changes after next round of reviews
This commit is contained in:
caheckman 2021-02-02 13:07:54 -05:00 committed by ghidra1
parent 27fbe7278d
commit a5d4ca3cab
108 changed files with 7997 additions and 1997 deletions

View file

@ -1218,6 +1218,26 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
else if (elname == "inferptrbounds")
parseInferPtrBounds(*iter);
}
el = store.getTag("specextensions"); // Look for any user-defined configuration document
if (el != (const Element *)0) {
const List &userlist(el->getChildren());
for(iter=userlist.begin();iter!=userlist.end();++iter) {
const string &elname( (*iter)->getName() );
if (elname == "prototype")
parseProto(*iter);
else if (elname == "callfixup") {
pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"),
InjectPayload::CALLFIXUP_TYPE, *iter);
}
else if (elname == "callotherfixup") {
userops.parseCallOtherFixup(*iter,this);
}
else if (elname == "global")
globaltags.push_back(*iter);
}
}
// <global> tags instantiate the base symbol table
// They need to know about all spaces, so it must come
// after parsing of <stackpointer> and <spacebase>

View file

@ -314,7 +314,7 @@ public:
enum {
unaffected = 1, ///< The sub-function does not change the value at all
killedbycall = 2, ///< The memory is changed and is completely unrelated to its original value
return_address = 3, ///< The memory is being used to pass back a return value from the sub-function
return_address = 3, ///< The memory is being used to store the return address
unknown_effect = 4 ///< An unknown effect (indicates the absence of an EffectRecord)
};
private:

View file

@ -284,7 +284,7 @@ void ArchitectureGhidra::buildSpecFile(DocumentStorage &store)
istringstream cstream(cspecxml);
doc = store.parseDocument(cstream);
store.registerTag(doc->getRoot());
istringstream tstream(tspecxml);
doc = store.parseDocument(tstream);
store.registerTag(doc->getRoot());
@ -293,10 +293,10 @@ void ArchitectureGhidra::buildSpecFile(DocumentStorage &store)
doc = store.parseDocument(corestream);
store.registerTag(doc->getRoot());
pspecxml = ""; // Strings aren't used again free memory
cspecxml = "";
tspecxml = "";
corespecxml = "";
pspecxml.clear(); // Strings aren't used again free memory
cspecxml.clear();
tspecxml.clear();
corespecxml.clear();
}
void ArchitectureGhidra::postSpecFile(void)

View file

@ -82,7 +82,8 @@ class ArchitectureGhidra : public Architecture {
virtual void postSpecFile(void);
virtual void resolveArchitecture(void);
public:
ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec,istream &i,ostream &o);
ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,const string &corespec,
istream &i,ostream &o);
const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation
void clearWarnings(void) { warnings.clear(); } ///< Clear warnings
Document *getRegister(const string &regname); ///< Retrieve a register description given a name

View file

@ -174,6 +174,10 @@ void RegisterProgram::rawAction(void)
}
}
ghidra = new ArchitectureGhidra(pspec,cspec,tspec,corespec,sin,sout);
pspec.clear();
cspec.clear();
tspec.clear();
corespec.clear();
DocumentStorage store; // temp storage of initialization xml docs
ghidra->init(store);

View file

@ -293,6 +293,23 @@ int4 PcodeInjectLibrarySleigh::registerDynamicInject(InjectPayload *payload)
return id;
}
/// \brief Force a payload to be dynamic for debug purposes
///
/// Debug information may include inject information for payloads that aren't dynamic.
/// We substitute a dynamic payload so that analysis uses the debug info to inject, rather
/// than the hard-coded payload information.
/// \param injectid is the id of the payload to treat dynamic
/// \return the new dynamic payload object
InjectPayloadDynamic *PcodeInjectLibrarySleigh::forceDebugDynamic(int4 injectid)
{
InjectPayload *oldPayload = injection[injectid];
InjectPayloadDynamic *newPayload = new InjectPayloadDynamic(glb,oldPayload->getName(),oldPayload->getType());
delete oldPayload;
injection[injectid] = newPayload;
return newPayload;
}
void PcodeInjectLibrarySleigh::parseInject(InjectPayload *payload)
{
@ -399,9 +416,10 @@ void PcodeInjectLibrarySleigh::restoreDebug(const Element *el)
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> type;
int4 id = getPayloadId(type,name);
InjectPayloadDynamic *payload = (InjectPayloadDynamic *)getPayload(id);
if (payload->getSource() != "dynamic")
throw LowlevelError("Mismatch with debug inject XML");
InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id));
if (payload == (InjectPayloadDynamic *)0) {
payload = forceDebugDynamic(id);
}
payload->restoreEntry(subel);
}
}

View file

@ -91,6 +91,7 @@ class PcodeInjectLibrarySleigh : public PcodeInjectLibrary {
vector<OpBehavior *> inst;
InjectContextSleigh contextCache;
int4 registerDynamicInject(InjectPayload *payload);
InjectPayloadDynamic *forceDebugDynamic(int4 injectid);
void parseInject(InjectPayload *payload);
protected:
virtual int4 allocateInject(const string &sourceName,const string &name,int4 type);

View file

@ -216,10 +216,10 @@ void SegmentOp::restoreXml(const Element *el)
throw LowlevelError("Bad segment pattern tag: "+subel->getName());
}
if (injectId < 0)
throw LowlevelError("Missing <execute> child in <segmentop> tag");
throw LowlevelError("Missing <pcode> child in <segmentop> tag");
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
if (payload->sizeOutput() != 1)
throw LowlevelError("<execute> child of <segmentop> tag must declare one <output>");
throw LowlevelError("<pcode> child of <segmentop> tag must declare one <output>");
if (payload->sizeInput() == 1) {
innerinsize = payload->getInput(0).getSize();
}
@ -228,7 +228,7 @@ void SegmentOp::restoreXml(const Element *el)
innerinsize = payload->getInput(1).getSize();
}
else
throw LowlevelError("<execute> child of <segmentop> tag must declare one or two <input> tags");
throw LowlevelError("<pcode> child of <segmentop> tag must declare one or two <input> tags");
}
/// \param g is the Architecture owning this set of jump assist scripts

View file

@ -127,6 +127,12 @@ void XmlArchitecture::restoreXml(DocumentStorage &store)
++iter;
}
}
if (iter != list.end()) {
if ((*iter)->getName() == "specextensions") {
store.registerTag(*iter);
++iter;
}
}
if (iter!=list.end()) {
if ((*iter)->getName() == "coretypes") {
store.registerTag(*iter);